示例#1
0
    def __call__(self, img, trace_object):
        self.last_trace = trace_object
        self.last_img = img

        if self.apwidth < 1:
            raise ValueError('apwidth must be >= 1')
        if self.skysep < 1:
            raise ValueError('skysep must be >= 1')
        if self.skywidth < 1:
            raise ValueError('skywidth must be >= 1')

        trace_line = trace_object.line

        onedspec = np.zeros_like(trace_line)
        skysubflux = np.zeros_like(trace_line)
        fluxerr = np.zeros_like(trace_line)

        for i in range(0, len(trace_line)):
            # first do the aperture flux
            # juuuust in case the trace gets too close to an edge
            widthup = self.apwidth / 2
            widthdn = self.apwidth / 2
            if (trace_line[i] + widthup > img.shape[0]):
                widthup = img.shape[0] - trace_line[i] - 1
            if (trace_line[i] - widthdn < 0):
                widthdn = trace_line[i] - 1

            # simply add up the total flux around the trace_line +/- width
            onedspec[i] = np.nansum(
                img[int(trace_line[i] - widthdn):int(trace_line[i] + widthup + 1), i]
            )

            # now do the sky fit
            itrace_line = int(trace_line[i])
            sky_y = np.append(
                np.arange(
                    itrace_line - self.apwidth - self.skysep - self.skywidth,
                    itrace_line - self.apwidth - self.skysep
                ),
                np.arange(
                    itrace_line + self.apwidth + self.skysep + 1,
                    itrace_line + self.apwidth + self.skysep + self.skywidth + 1
                )
            )

            sky_flux = img[sky_y, i]
            if (self.skydeg > 0):
                # fit a polynomial to the sky in this column
                pfit = np.polyfit(sky_y, sky_flux, self.skydeg)
                # define the aperture in this column
                ap = np.arange(
                    trace_line[i] - self.apwidth,
                    trace_line[i] + self.apwidth + 1
                )
                # evaluate the polynomial across the aperture, and sum
                skysubflux[i] = np.nansum(np.polyval(pfit, ap))
            elif (self.skydeg == 0):
                skysubflux[i] = np.nanmean(sky_flux) * (self.apwidth * 2.0 + 1)

            # finally, compute the error in this pixel
            sigma_bkg = np.nanstd(sky_flux)  # stddev in the background data
            n_bkg = np.float(len(sky_y))  # number of bkgd pixels
            n_ap = self.apwidth * 2. + 1  # number of aperture pixels

            # based on aperture phot err description by F. Masci, Caltech:
            # http://wise2.ipac.caltech.edu/staff/fmasci/ApPhotUncert.pdf
            fluxerr[i] = np.sqrt(
                np.nansum(onedspec[i] - skysubflux[i]) + (n_ap + n_ap**22 / n_bkg) * (sigma_bkg**2)
            )

        spec = Spectrum1D(
            spectral_axis=np.arange(len(onedspec)) * u.pixel,
            flux=onedspec * img.unit,
            uncertainty=StdDevUncertainty(fluxerr)
        )
        skyspec = Spectrum1D(
            spectral_axis=np.arange(len(onedspec)) * u.pixel,
            flux=skysubflux * img.unit
        )

        return spec, skyspec
示例#2
0
 def wrapper(data, spectral_axis, *args, **kwargs):
     spec = Spectrum1D(flux=u.Quantity(data),
                       spectral_axis=spectral_axis)
     return func(spec, *args, **kwargs).flux.value
        # The spectrum is in the second HDU of this file.
        f = fits.open(filename)
        specdata = f[1].data  # doctest: +REMOTE_DATA
        z = cz.loc[gal][0] / 3e5
        #z = f[2].data.Z[0]
        print(z)

        f.close()

        lamb_full = 10**specdata['loglam'] * u.AA  # doctest: +REMOTE_DATA
        lamb = lamb_full[lamb_full < 6900 * u.AA]

        flux = specdata['flux'] * 10**-17 * u.Unit(
            'erg cm-2 s-1 AA-1')  # doctest: +REMOTE_DATA
        flux = flux[lamb_full < 6900 * u.AA]
        spec = Spectrum1D(spectral_axis=lamb,
                          flux=flux)  # doctest: +REMOTE_DATA
        cont_norm_spec = spec / fit_generic_continuum(spec)(
            spec.spectral_axis)  # doctest: +REMOTE_DATA

        wave = np.array(cont_norm_spec.wavelength)
        flux = np.array(cont_norm_spec.flux)
        new_wave = wave / (1 + z)  #/3e5))
        new_flux = flux * (1 + z)  #/3e5))#rebin_spec(new_wave,flux,wave)
        new_spec = Spectrum1D(
            spectral_axis=new_wave * u.AA,
            flux=new_flux *
            u.Unit('erg cm-2 s-1 AA-1'))  # doctest: +REMOTE_DATA

        heii_wave = new_wave[(new_wave > 4665) & (new_wave < 4705)]
        heii_flux = new_flux[(new_wave > 4665) & (new_wave < 4705)]
        heii_spec = Spectrum1D(
示例#4
0
snsp.generate_spectra(save_as=pickle_name, use_template_star=use_template_star)
# print(snsp._preprocessed_snap.s['smooth'])
# print(snsp._preprocessed_snap.s['mass'])
# snsp.generate_spectra_from_pickle(pickle_name)

# Do noise:
# We defined the contamination range (the dispersion ) in a way that the residuals
# between the constructed spectrum and the original spectrum of
# the library to be less than ~ 0.073.

print('Computing noise')
sigma = 0.07
noise = np.random.normal(
    loc=0.0, scale=sigma * snsp.spectrum.flux) * snsp.spectrum.flux.unit
print('Adding noise to signal')
new_spectrum = Spectrum1D(spectral_axis=snsp.spectrum.wavelength,
                          flux=snsp.spectrum.flux + noise)
old_spectrum = copy.deepcopy(snsp.spectrum)
snsp.spectrum = new_spectrum

cg = CubeGenerator(snsp, bins=bins)
cg.sum_on_line_of_sigth()
cube = cg.create_spectral_cube()
cube.write(out_name + 'pix{}_sum.fits'.format(bins), overwrite=True)

im = cg.sph_projection_direct(num_threads=num_threads)
cube_sph = cg.create_spectral_cube()

if do_spectral_rebinning:
    muse_cube = muse_rebin(snsp.last_valid_freq, cube_sph)
else:
    muse_cube = cube_sph
def get_toi837_li_equivalent_width():

    spectrum_path = '../data/spectra/TOI-837_FEROS.fits'
    plotpath = '../results/TOI_837/feros_spectrum_get_li_equivalent_width.png'

    #
    # fit out the continuum to get the continuum normalized flux, over the
    # window of 6670 angstrom to 6713 angstrom.
    #
    xlim = [6670, 6713]

    hdul = fits.open(spectrum_path)
    d = hdul[0].data
    wav = d[0, 0]
    flx = d[3, 0]

    if isinstance(xlim, list):
        xmin = xlim[0]
        xmax = xlim[1]
        sel = (wav > xmin) & (wav < xmax)

        wav = wav[sel]
        flx = flx[sel]

    spec = Spectrum1D(spectral_axis=wav * u.AA,
                      flux=flx * u.dimensionless_unscaled)

    if isinstance(xlim, list):
        exclude_regions = []
        if xmin < 6709.2 and xmax > 6710.2:
            exclude_regions.append(SpectralRegion(6709.2 * u.AA,
                                                  6710.2 * u.AA))
        if xmin < 6679 and xmax > 6681:
            exclude_regions.append(SpectralRegion(6679 * u.AA, 6681 * u.AA))

    cont_flx = (fit_generic_continuum(spec, exclude_regions=exclude_regions)(
        spec.spectral_axis))

    cont_norm_spec = spec / cont_flx

    #
    # to fit gaussians, look at 1-flux.
    #
    full_spec = Spectrum1D(spectral_axis=cont_norm_spec.wavelength,
                           flux=(1 - cont_norm_spec.flux))

    #
    # get the Li EW
    #
    region = SpectralRegion(6708.5 * u.AA, 6711.5 * u.AA)
    li_equiv_width = equivalent_width(cont_norm_spec, regions=region)
    li_centroid = centroid(full_spec, region)

    #
    # fit a gaussian too, and get ITS equiv width
    # https://specutils.readthedocs.io/en/stable/fitting.html
    #
    g_init = models.Gaussian1D(amplitude=0.2 * u.dimensionless_unscaled,
                               mean=6709.7 * u.AA,
                               stddev=0.5 * u.AA)
    g_fit = fit_lines(full_spec, g_init, window=(region.lower, region.upper))
    y_fit = g_fit(full_spec.wavelength)

    fitted_spec = Spectrum1D(spectral_axis=full_spec.wavelength,
                             flux=(1 - y_fit) * u.dimensionless_unscaled)
    fitted_li_equiv_width = equivalent_width(fitted_spec, regions=region)

    #
    # print bestfit params
    #
    print(42 * '=')
    print('got Li equiv width of {}'.format(li_equiv_width))
    print('got fitted Li equiv width of {}'.format(fitted_li_equiv_width))
    print('got Li centroid of {}'.format(li_centroid))
    print('fit gaussian1d params are\n{}'.format(repr(g_fit)))
    print(42 * '=')

    #
    # plot the results
    #
    f, axs = plt.subplots(nrows=4, ncols=1, figsize=(6, 8))

    axs[0].plot(wav, flx, c='k', zorder=3)
    axs[0].plot(wav, cont_flx, c='r', zorder=2)

    axs[1].plot(cont_norm_spec.wavelength, cont_norm_spec.flux, c='k')

    axs[2].plot(cont_norm_spec.wavelength, cont_norm_spec.flux, c='k')

    axs[3].plot(full_spec.wavelength, full_spec.flux, c='k')
    axs[3].plot(full_spec.wavelength, y_fit, c='g')

    txt = ('gaussian1d\namplitude:{:.3f}\nmean:{:.3f}\nstd:{:.3f}\nEW:{:.3f}'.
           format(g_fit.amplitude.value, g_fit.mean.value, g_fit.stddev.value,
                  fitted_li_equiv_width))
    axs[3].text(0.95,
                0.95,
                txt,
                ha='right',
                va='top',
                transform=axs[3].transAxes,
                fontsize='xx-small')

    axs[0].set_ylabel('flux')
    axs[1].set_ylabel('contnorm flux')
    axs[2].set_ylabel('contnorm flux [zoom]')
    axs[3].set_ylabel('1 - (contnorm flux)')

    if isinstance(xlim, list):
        for ax in axs:
            ax.set_xlim(xlim)

    axs[2].set_xlim([6708.5, 6711.5])
    axs[3].set_xlim([6708.5, 6711.5])
    axs[-1].set_xlabel('wavelength [angstrom]')

    for ax in axs:
        format_ax(ax)
    outpath = '../results/TOI_837/toi837_li_equivalent_width_routine.png'
    savefig(f, outpath)
def test_spectrum1d_2d_data():

    # This test makes sure that 2D spectra represented as Spectrum1D round-trip
    # Note that Spectrum1D will typically have a 1D spectral WCS even if the
    # data is N-dimensional, so we need to pad the WCS before passing it to
    # glue and un-pad it when translating back.

    # We test both the case where the WCS is 2D and the case where it is 1D

    wcs = WCS(naxis=1)
    wcs.wcs.ctype = ['FREQ']
    wcs.wcs.cdelt = [10]
    wcs.wcs.set()

    flux = np.ones((3, 2)) * u.Unit('Jy')

    spec = Spectrum1D(flux, wcs=wcs, meta={'instrument': 'spamcam'})

    assert spec.data.ndim == 2
    assert spec.wcs.naxis == 1

    data_collection = DataCollection()

    data_collection['spectrum'] = spec

    data = data_collection['spectrum']

    assert isinstance(data, Data)
    assert len(data.main_components) == 1
    assert data.main_components[0].label == 'flux'
    assert_allclose(data['flux'], flux.value)

    assert data.coords.pixel_n_dim == 2
    assert data.coords.world_n_dim == 2
    assert len(data.pixel_component_ids) == 2
    assert len(data.world_component_ids) == 2

    assert data.coordinate_components[0].label == 'Pixel Axis 0 [y]'
    assert data.coordinate_components[1].label == 'Pixel Axis 1 [x]'
    assert data.coordinate_components[2].label == 'Offset'
    assert data.coordinate_components[3].label == 'Frequency'

    assert_equal(data['Offset'], [[0, 0], [1, 1], [2, 2]])
    assert_equal(data['Frequency'], [[10, 20], [10, 20], [10, 20]])

    s, o = data.coords.pixel_to_world(1, 2)
    assert isinstance(s, SpectralCoord)

    # Check round-tripping of coordinates
    with pytest.warns(AstropyUserWarning, match='No observer defined on WCS'):
        px, py = data.coords.world_to_pixel(s, o)
    assert_allclose(px, 1)
    assert_allclose(py, 2)

    # Check round-tripping of translation
    spec_new = data.get_object(statistic=None)
    assert isinstance(spec_new, Spectrum1D)

    # The WCS object should be the same
    assert spec_new.wcs.pixel_n_dim == 1
    assert spec_new.wcs.world_n_dim == 1
    assert spec_new.wcs is spec.wcs

    # The metadata should still be present
    assert spec_new.meta['instrument'] == 'spamcam'
示例#7
0
文件: loaders.py 项目: einshoe/ssv-py
def add_single_spectra_to_map(
    spectra_map,
    *,
    header,
    data,
    spec_info=None,
    wcs_info=None,
    units_info=None,
    purpose_prefix=None,
    all_standard_units,
    all_keywords,
    valid_wcs,
    index=None,
):
    spec_wcs_info = {}
    spec_units_info = {}
    if wcs_info is not None:
        spec_wcs_info.update(wcs_info)
    if units_info is not None:
        spec_units_info.update(units_info)

    if spec_info is not None:
        spec_wcs_info.update(spec_info.get("wcs", {}))
        spec_units_info.update(spec_info.get("units", {}))
        purpose = spec_info.get("purpose")
    else:
        purpose = None

    purpose = get_purpose(
        header,
        purpose=purpose,
        purpose_prefix=purpose_prefix,
        all_keywords=all_keywords,
        index=index,
    )

    if purpose == Purpose.SKIP:
        return None

    if valid_wcs or not spec_wcs_info:
        wcs = WCS(header)
    else:
        wcs = compute_wcs_from_keys_and_values(header, **spec_wcs_info)

    if all_standard_units:
        spec_units_info = {"flux_unit_keyword": "BUNIT"}
    flux_unit = get_flux_units_from_keys_and_values(header, **spec_units_info)
    flux = data * flux_unit

    meta = {"header": header, "purpose": PURPOSE_SPECTRA_MAP[purpose]}

    if purpose in CREATE_SPECTRA:
        spectrum = Spectrum1D(wcs=wcs, flux=flux, meta=meta)
        spectra_map[PURPOSE_SPECTRA_MAP[purpose]].append(spectrum)
    elif purpose in ERROR_PURPOSES:
        try:
            spectrum = spectra_map[PURPOSE_SPECTRA_MAP[purpose]][-1]
        except IndexError:
            raise ValueError(f"No spectra to associate with {purpose}")
        aligned_flux = pixel_to_pixel(wcs, spectrum.wcs, flux)
        spectrum.uncertainty = UNCERTAINTY_MAP[purpose](aligned_flux)
        spectrum.meta["uncertainty_header"] = header

    # We never actually want to return something, this just flags it to pylint
    # that we know we're breaking out of the function when skip is selected
    return None
def test_pre_full(data_path, template_path, z_lit, z_bound, spec_type):
    """Returns the full spectrum best-fit redshift and min chi2. 
    Tests the redshift array on the entire spectrum to ensure bounds are appropriate.
    
    Parameters
    ----------
    data_path : str
        Path to data spectrum file
    template_path : str
        Path to template spectrum file
    z_lit : float
        Literature redshift for target object
    z_bound : float
        Amount to add and subtract from z_lit for redshifts to test
    spec_type : str
        Indicates if looking at coadded spectrum or single 1D spectrum
        
    Returns
    -------
    tm_result[0] : float
        Best-fit redshift
    tm_result[1] : float
        Minimum chi-squared
    """
    
    #Import data
    data_wave_full, data_cut_wave, data_flux_full, data_cut_flux, data_noise_full, data_cut_noise = prep_data(data_path, 
                                                                                                              spec_type)

    #Import smoothed template
    template_wave, smoothed_template_flux, smoothed_template_noise = prep_template(template_path)

    #Continuum normalize over whole wavelength range
    norm_data_wave, norm_data_flux, norm_data_noise = continuum_normalize(np.min(data_cut_wave), np.max(data_cut_wave), 
                                                                          data_cut_flux, data_cut_wave, data_cut_noise)
    norm_template_wave, norm_template_flux, norm_template_noise = continuum_normalize(np.min(template_wave), 
                                                                                      np.max(template_wave),
                                                                                      smoothed_template_flux, template_wave, 
                                                                                      smoothed_template_noise)

    #Put spectra into Spectrum1D objects
    data_spec = Spectrum1D(spectral_axis=norm_data_wave*u.Angstrom, flux=norm_data_flux*(u.erg/u.s/u.cm**2/u.Angstrom),
                           uncertainty=StdDevUncertainty(norm_data_noise))
    template_spec = Spectrum1D(spectral_axis=norm_template_wave*u.Angstrom, flux=norm_template_flux*(u.Lsun/u.micron))

    #Plot before
    plt.figure(figsize=(12,4))
    plt.plot(data_spec.spectral_axis, data_spec.flux, label='observed')
    plt.plot(template_spec.spectral_axis, template_spec.flux, label='template')
    plt.legend()
    plt.show()

    #Fit redshifts
    redshifts = np.linspace(z_lit-z_bound, z_lit+z_bound, 1000)
    tm_result = template_redshift(observed_spectrum=data_spec, template_spectrum=template_spec, redshift=redshifts)

    #Plot after
    plt.figure(figsize=(12,4))
    plt.plot(data_spec.spectral_axis, data_spec.flux, label='observed')
    plt.plot(tm_result[2].spectral_axis, tm_result[2].flux, label='redshifted template')
    plt.legend()
    plt.show()

    plt.figure(figsize=(12,4))
    plt.plot(template_spec.spectral_axis, template_spec.flux, label='template')
    plt.plot(tm_result[2].spectral_axis, tm_result[2].flux, label='redshifted template')
    plt.legend()
    plt.show()
    return tm_result[0], tm_result[1]
def chunk_redshift(data_wave, data_flux, data_noise, template_path, z_lit, targ_delta, overhang, z_test, z_bound, position):
    """Returns the bestfit redshift of each chunk.
    
    Parameters
    ----------
    data_wave : tuple
        Data wavelength array
    data_flux : tuple
        Data flux array
    data_noise : tuple
        Data noise array
    template_path : str
        Path to template spectrum file
    z_lit : float
        Literature redshift of target object
    targ_delta : float
        Wavelength chunk size in Angstroms
    overhang : float
        Amount of wavelength overhang template chunks should have in Angstroms
    z_test : float
        Starting redshift for chunks (measured by eye in 1 chunk)
    z_bound : float
        Amount to add and subtract from z_lit for redshifts to test
    position : str
        'before' or 'after' to indicate if pre- or post-flexure correction
        
    Results
    -------
    bestfit_redshift : tuple
        Best fitting redshift for each chunk
    best_chi2 : tuple
        Minimum chi squared for each chunk
    redshifted_spectra : tuple
        Redshifted chunks
    chi2 : tuple
        All chi2
    """
    
    #Get data chunks
    data_wave_chunks, data_flux_chunks, data_noise_chunks = data_chunks(data_wave, data_flux, data_noise, targ_delta)

    #Get template_chunks 
    temp_wave_chunks, temp_flux_chunks, temp_noise_chunks, temp_central_wavelengths, central_waves = template_chunks(data_wave, 
                                                                                                                     data_flux,
                                                                                                      data_noise, template_path,
                                                                                                      z_lit, targ_delta,
                                                                                                      overhang, position)

    #Find redshifts of each chunk
    observed_chunks = []
    temp_chunks = []
    for i in range(len(data_wave_chunks)):
        observed_chunks.append(Spectrum1D(spectral_axis=data_wave_chunks[i]*u.Angstrom, 
                                          flux=data_flux_chunks[i]*(u.erg/u.s/u.cm**2/u.Angstrom), 
                                          uncertainty=InverseVariance(data_noise_chunks[i])))
        temp_chunks.append(Spectrum1D(spectral_axis=temp_wave_chunks[i]*u.Angstrom, 
                                 flux=temp_flux_chunks[i]*(u.Lsun/u.micron),
                                 uncertainty=StdDevUncertainty(temp_noise_chunks[i])))

    redshifts_chunks = np.linspace(z_test-z_bound, z_test+z_bound, 1000)
    fitted_redshift_results = []
    bestfit_redshift = np.zeros(len(data_wave_chunks))
    best_chi2 = np.zeros(len(data_wave_chunks))
    redshifted_spectra = []
    chi2 = []
    for i in range(len(data_wave_chunks)):
        fitted_redshift_results.append(template_redshift(observed_spectrum=observed_chunks[i], 
                                                            template_spectrum=temp_chunks[i],
                                                            redshift=redshifts_chunks))
        bestfit_redshift[i] = fitted_redshift_results[i][0]
        best_chi2[i] = fitted_redshift_results[i][1]
        redshifted_spectra.append(fitted_redshift_results[i][2])
        chi2.append(fitted_redshift_results[i][3])
        
    return bestfit_redshift, best_chi2, redshifted_spectra, chi2
示例#10
0
    def __call__(self,
                 image,
                 trace_object,
                 disp_axis=1,
                 crossdisp_axis=0,
                 bkgrd_prof=models.Polynomial1D(2),
                 variance=None,
                 mask=None,
                 unit=None):
        """
        Run the Horne calculation on a region of an image and extract a
        1D spectrum.

        Parameters
        ----------

        image : `~astropy.nddata.NDData` or array-like, required
            The input 2D spectrum from which to extract a source. An
            NDData object must specify uncertainty and a mask. An array
            requires use of the `variance`, `mask`, & `unit` arguments.

        trace_object : `~specreduce.tracing.Trace`, required
            The associated 1D trace object created for the 2D image.

        disp_axis : int, optional
            The index of the image's dispersion axis. [default: 1]

        crossdisp_axis : int, optional
            The index of the image's cross-dispersion axis. [default: 0]

        bkgrd_prof : `~astropy.modeling.Model`, optional
            A model for the image's background flux.
            [default: models.Polynomial1D(2)]

        variance : `~numpy.ndarray`, optional
            (Only used if `image` is not an NDData object.)
            The associated variances for each pixel in the image. Must
            have the same dimensions as `image`. [default: None]

        mask : `~numpy.ndarray`, optional
            (Only used if `image` is not an NDData object.)
            Whether to mask each pixel in the image. Must have the same
            dimensions as `image`. If blank, all non-NaN pixels are
            unmasked. [default: None]

        unit : `~astropy.units.core.Unit` or str, optional
            (Only used if `image` is not an NDData object.)
            The associated unit for the data in `image`. If blank,
            fluxes are interpreted as unitless. [default: None]


        Returns
        -------
        spec_1d : `~specutils.Spectrum1D`
            The final, Horne extracted 1D spectrum.
        """
        # handle image and associated data based on image's type
        if isinstance(image, NDData):
            img = np.ma.array(image.data, mask=image.mask)
            unit = image.unit if image.unit is not None else u.Unit()

            if image.uncertainty is not None:
                # prioritize NDData's uncertainty over variance argument
                if image.uncertainty.uncertainty_type == 'var':
                    variance = image.uncertainty.array
                elif image.uncertainty.uncertainty_type == 'std':
                    # NOTE: CCDData defaults uncertainties given as pure arrays
                    # to std and logs a warning saying so upon object creation.
                    # should we remind users again here?
                    warnings.warn("image NDData object's uncertainty "
                                  "interpreted as standard deviation. if "
                                  "incorrect, use VarianceUncertainty when "
                                  "assigning image object's uncertainty.")
                    variance = image.uncertainty.array**2
                elif image.uncertainty.uncertainty_type == 'ivar':
                    variance = 1 / image.uncertainty.array
                else:
                    # other options are InverseVariance and UnknownVariance
                    raise ValueError(
                        "image NDData object has unexpected "
                        "uncertainty type. instead, try "
                        "VarianceUncertainty or StdDevUncertainty.")
            else:
                # ignore variance arg to focus on updating NDData object
                raise ValueError('image NDData object lacks uncertainty')

        else:
            if any(arg is None for arg in (variance, mask, unit)):
                raise ValueError('if image is a numpy array, the variance, '
                                 'mask, and unit arguments must be specified. '
                                 'consider wrapping that information into one '
                                 'object by instead passing an NDData image.')
            if image.shape != variance.shape:
                raise ValueError('image and variance shapes must match')
            if image.shape != mask.shape:
                raise ValueError('image and mask shapes must match')

            # fill in non-required arguments if empty
            if mask is None:
                mask = np.ma.masked_invalid(image)
            if isinstance(unit, str):
                unit = u.Unit(unit)
            else:
                unit = unit if unit is not None else u.Unit()

            # create image
            img = np.ma.array(image, mask=mask)

        # co-add signal in each image column
        ncols = img.shape[crossdisp_axis]
        xd_pixels = np.arange(ncols)  # y plot dir / x spec dir
        coadd = img.sum(axis=disp_axis) / ncols

        # fit source profile, using Gaussian model as a template
        # NOTE: could add argument for users to provide their own model
        gauss_prof = models.Gaussian1D(amplitude=coadd.max(),
                                       mean=coadd.argmax(),
                                       stddev=2)

        # Fit extraction kernel to column with combined gaussian/bkgrd model
        ext_prof = gauss_prof + bkgrd_prof
        fitter = fitting.LevMarLSQFitter()
        fit_ext_kernel = fitter(ext_prof, xd_pixels, coadd)

        # use compound model to fit a kernel to each image column
        # NOTE: infers Gaussian1D source profile; needs generalization for others
        kernel_vals = []
        norms = []
        for col_pix in range(img.shape[disp_axis]):
            # set gaussian model's mean as column's corresponding trace value
            fit_ext_kernel.mean_0 = trace_object.trace[col_pix]
            # NOTE: support for variable FWHMs forthcoming and would be here

            # fit compound model to column
            fitted_col = fit_ext_kernel(xd_pixels)

            # save result and normalization
            kernel_vals.append(fitted_col)
            norms.append(fit_ext_kernel.amplitude_0 * fit_ext_kernel.stddev_0 *
                         np.sqrt(2 * np.pi))

        # transform fit-specific information
        kernel_vals = np.array(kernel_vals).T
        norms = np.array(norms)

        # calculate kernel normalization, masking NaNs
        g_x = np.ma.sum(kernel_vals**2 / variance, axis=crossdisp_axis)

        # sum by column weights
        weighted_img = np.ma.divide(img * kernel_vals, variance)
        result = np.ma.sum(weighted_img, axis=crossdisp_axis) / g_x

        # multiply kernel normalization into the extracted signal
        extraction = result * norms

        # convert the extraction to a Spectrum1D object
        pixels = np.arange(img.shape[disp_axis]) * u.pix
        spec_1d = Spectrum1D(spectral_axis=pixels, flux=extraction * unit)

        return spec_1d
def centroid_offsets(targ_bounds, data_wave, data_flux, sky_cents):
    """Returns amount by which extracted skylines are offset from model and the nearest wavelength value to each.
    
    Parameters
    ----------
    targ_bounds : tuple
        List of tuples defining bounds of region around each skyline to examine
    data_wave : tuple
        Wavelength array
    data_flux : tuple
        Flux array
    sky_cents : tuple
        Skymodel centroids
        
    Returns
    -------
    nearest_waves : tuple
        Nearest wavelength value to centroid
    offsets : tuple
        Offset between data and skymodel
    """
    
    regions = SpectralRegion(targ_bounds[0][0]*u.Angstrom,targ_bounds[0][-1]*u.Angstrom)
    for i in range(1, len(targ_bounds)):
        regions += SpectralRegion(targ_bounds[i][0]*u.Angstrom, targ_bounds[i][-1]*u.Angstrom)

    #Normalize data
    targ_norm_wave, targ_norm_flux, targ_norm_noise = continuum_normalize(np.min(data_wave), np.max(data_wave), data_flux, 
                                                                          data_wave, np.zeros(len(data_flux)))
    
    
    #Find offsets
    target = Spectrum1D(spectral_axis=targ_norm_wave*u.Angstrom, flux=targ_norm_flux*u.ct)
    sub_spec = extract_region(target, regions)
    offsets = np.zeros(len(sky_cents))
    nearest_waves = np.zeros(len(sky_cents))
    for i, sub in enumerate(sub_spec):
        an_disp = sub.flux.max()
        an_ampl = sub.flux.min()
        an_mean = sub.spectral_axis[sub.flux.argmax()]
        nearest_waves[i] = an_mean.value
        an_stdv = np.sqrt(np.sum((sub.spectral_axis - an_mean)**2) / (len(sub.spectral_axis) - 1))

        plt.figure()
        plt.scatter(an_mean.value, an_disp.value, marker='o', color='#e41a1c', s=100, label='data')
        plt.scatter(sky_cents[i], an_disp.value, marker='o', color='k', s=100, label='archive')
        plt.vlines([an_mean.value - an_stdv.value, an_mean.value + an_stdv.value],
                    sub.flux.min().value, sub.flux.max().value,
                    color='#377eb8', ls='--', lw=2)
        g_init = ( models.Const1D(an_disp) +
                  models.Gaussian1D(amplitude=(an_ampl - an_disp),
                                mean=an_mean, stddev=an_stdv) )
        g_fit = fit_lines(sub, g_init)
        line_fit = g_fit(sub.spectral_axis)
        plt.plot(sub.spectral_axis, sub.flux, color='#e41a1c', lw=2)
        plt.plot(sub.spectral_axis, line_fit, color='#377eb8', lw=2)

        plt.axvline(an_mean.value, color='#e41a1c', ls='--', lw=2)
        plt.legend()
        offsets[i] = an_mean.value - sky_cents[i].value
        
    return nearest_waves, offsets
示例#12
0
from astropy.convolution import Gaussian1DKernel, convolve

INPUT_spec = 'CS31_CNO_0n.spec'

fwhm = 0.20
#SIGMA=8

SIGMA = fwhm / 2.35482 * 100

wl, fl = np.genfromtxt(INPUT_spec, skip_header=2, unpack=True)

wl2, fl2 = np.genfromtxt('fluxCS31_0.norm.nulbad.0.200',
                         skip_header=2,
                         unpack=True)

spec1 = Spectrum1D(spectral_axis=wl * u.A, flux=fl * u.Jy)

#spec1_tsmooth = trapezoid_smooth(spec1, width=3)
#spec1_bsmooth = box_smooth(spec1, width=3)
#spec1_msmooth = median_smooth(spec1, width=3)

spec1_gsmooth = gaussian_smooth(spec1, stddev=SIGMA)

g = Gaussian1DKernel(stddev=SIGMA)
# Convolve data
z = convolve(fl, g)

#plt.plot(spec1.spectral_axis, spec1.flux)

plt.plot(wl2, fl2)
plt.plot(wl, z)
示例#13
0
def line_fit(spec,
             spec_err,
             wave_obj,
             dwave=10. * u.AA,
             dwave_cont=100. * u.AA,
             sigmamax=14. * u.AA):
    '''
    Function to fit a 1D gaussian to a HETDEX spectrum from get_spec.py

    Parameters
    ----------
    spec
        1D spectrum from a row in the table provided by get_spec.py.
        Will assume unit of 10**-17*u.Unit('erg cm-2 s-1 AA-1') if no units
        are provided.
    spec_err
        1D spectral uncertainty from table provided by get_spec.py.
        Will assume unit of 10**-17*u.Unit('erg cm-2 s-1 AA-1') if no units
        are provided.
    wave_obj
        wavelength you want to fit, an astropy quantity
    dwave
        spectral region above and below wave_obj to fit a line, an astropy quantity.
        Default is 10.*u.AA
    dwave_cont
        spectral region to fit continuum. Default is +/- 100.*u.AA
    sigmamax
        Maximum linewidth (this is sigma/stdev of the gaussian fit) to allow
        for a fit. Assumes unit of u.AA if not given

    Returns
    -------

    '''

    try:
        spectrum = Spectrum1D(flux=spec,
                              spectral_axis=(2.0 * np.arange(1036) + 3470.) *
                              u.AA,
                              uncertainty=StdDevUncertainty(spec_err),
                              velocity_convention=None)
    except ValueError:
        spectrum = Spectrum1D(
            flux=spec * 10**-17 * u.Unit('erg cm-2 s-1 AA-1'),
            spectral_axis=(2.0 * np.arange(1036) + 3470.) * u.AA,
            uncertainty=StdDevUncertainty(spec_err * 10**-17 *
                                          u.Unit('erg cm-2 s-1 AA-1')),
            velocity_convention=None)

    # measure continuum over 2*dwave_cont wide window first:
    cont_region = SpectralRegion((wave_obj - dwave_cont),
                                 (wave_obj + dwave_cont))
    cont_spectrum = extract_region(spectrum, cont_region)
    cont = np.median(cont_spectrum.flux)

    if np.isnan(cont):
        #set continuum if its NaN
        print('Continuum fit is NaN. Setting to 0.0')
        cont = 0.0 * cont_spectrum.unit

    # now get region to fit the continuum subtracted line

    sub_region = SpectralRegion((wave_obj - dwave), (wave_obj + dwave))
    sub_spectrum = extract_region(spectrum, sub_region)

    try:
        line_param = estimate_line_parameters(sub_spectrum - cont,
                                              models.Gaussian1D())
    except:
        return None

    if np.isnan(line_param.amplitude.value):
        print('Line fit yields NaN result. Exiting.')
        return None

    try:
        sigma = np.minimum(line_param.stddev, sigmamax)
    except ValueError:
        sigma = np.minimum(line_param.stddev, sigmamax * u.AA)

    if np.isnan(sigma):
        sigma = sigmamax

    g_init = models.Gaussian1D(amplitude=line_param.amplitude,
                               mean=line_param.mean,
                               stddev=sigma)

    #    lineregion = SpectralRegion((wave_obj-2*sigma), (wave_obj+2*sigma))
    #    cont = fit_generic_continuum(sub_spectrum, exclude_regions=lineregion,
    #                                 model=models.Linear1D(slope=0))

    #r1 = SpectralRegion((wave_obj-dwave), (wave_obj-2*sigma))
    #r2 = SpectralRegion((wave_obj+2*sigma), (wave_obj+dwave))
    #fitcontregion = r1 + r2

    #fit_cont_spectrum = extract_region(sub_spectrum, fitcontregion)
    #cont = np.mean(np.hstack([fit_cont_spectrum[0].flux, fit_cont_spectrum[1].flux]))

    #contspec = cont(sub_spectrum.spectral_axis)

    g_fit = fit_lines(sub_spectrum - cont, g_init)

    x = np.arange(wave_obj.value - dwave.value, wave_obj.value + dwave.value,
                  0.5) * u.AA
    y_fit = g_fit(x)

    line_flux_model = np.sum(y_fit * 0.5 * u.AA)

    chi2 = calc_chi2(sub_spectrum - cont, g_fit)

    sn = np.sum(np.array(sub_spectrum.flux)) / np.sqrt(
        np.sum(sub_spectrum.uncertainty.array**2))

    line_flux_data = line_flux(sub_spectrum - cont).to(u.erg * u.cm**-2 *
                                                       u.s**-1)

    line_flux_data_err = np.sqrt(np.sum(sub_spectrum.uncertainty.array**2))

    #fitted_region = SpectralRegion((line_param.mean - 2*sigma),
    #                               (line_param.mean + 2*sigma))

    #fitted_spectrum = extract_region(spectrum, fitted_region)

    #line_param = estimate_line_parameters(fitted_spectrum, models.Gaussian1D())

    #sn = np.sum(np.array(fitted_spectrum.flux)) / np.sqrt(np.sum(
    #    fitted_spectrum.uncertainty.array**2))

    #line_flux_data = line_flux(fitted_spectrum).to(u.erg * u.cm**-2 * u.s**-1)

    #line_flux_data_err = np.sqrt(np.sum(fitted_spectrum.uncertainty.array**2))

    return line_param, sn, chi2, sigma, line_flux_data, line_flux_model, line_flux_data_err, g_fit, cont
示例#14
0
                             max(mplot2.y[right:]),
                             num=len(mplot2.x))
        y_model = mplot2.y
        y_cn = y_model / y_cont
        dcontplot = DataPlot()
        dcont = Data1D("normalized", mplot.x, y_cn)
        dcontplot.prepare(dcont)
        dcontplot.plot()
        os.chdir(r"/home/dtyler/Desktop/DocumentsDT/outputs/standard_" +
                 fits_image_filename)
        plt.savefig(fits_image_filename[:-4] + "norm_continuum.png")
        os.chdir(r"/home/dtyler/Desktop/DocumentsDT/Programs")

        ###################################
        ###  calculate equivalent width
        spectrum = Spectrum1D(flux=y_cn * u.dimensionless_unscaled,
                              spectral_axis=mplot.x * u.AA)
        eqw = equivalent_width(spectrum)
        """print("EW", eqw.value) 
		print('norm factor', norm_factor)
		for par in bmdl.pars:
			print(par.fullname, par.val)"""

        ### print output to file

        os.chdir(
            r"/home/dtyler/Desktop/DocumentsDT/Analysis/standard_eq_widths")

        fil = open(fits_image_filename[:-4] + ".txt", 'w')
        fil.write('eqw' + '\t' + str(eqw.value) + '\n')
        fil.write('norm' + '\t' + str(norm_factor) + '\n')
        for par in bmdl.pars:
示例#15
0
def load_aaomega_file(filename, *args, **kwargs):
    with read_fileobj_or_hdulist(filename, *args, **kwargs) as fits_file:
        fits_header = fits_file[AAOMEGA_SCIENCE_INDEX].header

        # fits_file is the hdulist
        var_idx = None
        rwss_idx = None
        for idx, extn in enumerate(fits_file):
            if extn.name == "VARIANCE":
                var_idx = idx
            if extn.name == "RWSS":
                rwss_idx = idx
        # science data
        fits_data = fits_file[AAOMEGA_SCIENCE_INDEX].data

        # read in Fibre table data....
        ftable = Table(fits_file[AAOMEGA_FIBRE_INDEX].data)

        # A SpectrumList to hold all the Spectrum1D objects
        sl = SpectrumList()

        # the row var contains the pixel data from the science frame
        for i, row in enumerate(fits_data):
            # Definitely need deepcopy here, otherwise it does *NOT* work!
            fib_header = deepcopy(fits_header)
            # Adjusting some values from primary header so individual fibre
            # spectra have meaningful headers
            fib_header["FLDNAME"] = (fits_header["OBJECT"],
                                     "Name of 2dF .fld file")
            fib_header["FLDRA"] = (
                fits_header["MEANRA"],
                "Right Ascension of 2dF field",
            )
            fib_header["FLDDEC"] = (fits_header["MEANDEC"],
                                    "Declination of 2dF field")
            # Now for the fibre specific information from the Fibre Table
            # (extension 2)
            # Caution: RA and DEC are stored in RADIANS in the FIBRE TABLE!
            fib_header["RA"] = (
                ftable["RA"][i] * 180.0 / np.pi,
                "Right Ascension of fibre from configure .fld file",
            )
            fib_header["DEC"] = (
                ftable["DEC"][i] * 180.0 / np.pi,
                "Declination of fibre from configure .fld file",
            )
            fib_header["OBJECT"] = (
                ftable["NAME"][i],
                "Name of target observed by fibre",
            )
            fib_header["OBJCOM"] = (
                ftable["COMMENT"][i],
                "Comment from configure .fld file for target",
            )
            fib_header["OBJMAG"] = (
                ftable["MAGNITUDE"][i],
                "Magnitude of target observed by fibre",
            )
            fib_header["OBJTYPE"] = (
                ftable["TYPE"][i],
                "Type of target observed by fibre",
            )
            fib_header["OBJPIV"] = (
                ftable["PIVOT"][i],
                "Pivot number used to observe target",
            )
            fib_header["OBJPID"] = (
                ftable["PID"][i],
                "Program ID from configure .fld file",
            )
            fib_header["OBJX"] = (
                ftable["X"][i],
                "X coord of target observed by fibre (microns)",
            )
            fib_header["OBJY"] = (
                ftable["Y"][i],
                "Y coord of target observed by fibre (microns)",
            )
            fib_header["OBJXERR"] = (
                ftable["XERR"][i],
                "X coord error of target observed by fibre (microns)",
            )
            fib_header["OBJYERR"] = (
                ftable["YERR"][i],
                "Y coord error of target observed by fibre (microns)",
            )
            fib_header["OBJTHETA"] = (
                ftable["THETA"][i],
                "Angle of fibre used to observe target",
            )
            fib_header["OBJRETR"] = (
                ftable["RETRACTOR"][i],
                "Retractor number used to observe target",
            )
            # WLEN added around 2005 according to AAOmega obs manual...
            # so not always available
            if "WLEN" in ftable.colnames:
                fib_header["OBJWLEN"] = (
                    ftable["WLEN"][i],
                    "Retractor of target observed by fibre",
                )

            # ftable['TYPE'][i]:
            #   P == program (science)
            #   S == sky
            #   U == unallocated or unused
            #   F == fiducial (guide) fibre
            #   N == broken, dead or no fibre
            meta = {"header": fib_header}

            if ftable["TYPE"][i] == "P":
                meta["purpose"] = "reduced"
            elif ftable["TYPE"][i] == "S":
                meta["purpose"] = "sky"
            else:
                # Don't include other fibres that are not science or sky
                continue

            wcs = compute_wcs_from_keys_and_values(fib_header,
                                                   **AAOMEGA_2DF_WCS_SETTINGS)
            flux = row * AAOMEGA_2DF_FLUX_UNIT
            meta["fibre_index"] = i

            # Our science spectrum
            spectrum = Spectrum1D(wcs=wcs, flux=flux, meta=meta)
            # If the VARIANCE spectrum exists, add it as an additional spectrum
            # in the meta dict with key 'variance'
            if var_idx is not None:
                var_data = fits_file[var_idx].data
                var_flux = var_data[i] * AAOMEGA_2DF_FLUX_UNIT**2
                spectrum.uncertainty = VarianceUncertainty(var_flux)
            # If the RWSS spectrum exists, add it as an additional spectrum in
            # the meta dict with key 'science_sky'
            # This is an optional extension produced by 2dfdr on request: all
            # spectra without the average/median sky subtraction
            # Useful in case users want to do their own sky subtraction.
            if rwss_idx is not None:
                rwss_data = fits_file[rwss_idx].data
                rwss_flux = rwss_data[i] * AAOMEGA_2DF_FLUX_UNIT
                rwss_meta = {"header": fib_header, "purpose": "science_sky"}
                spectrum.meta["science_sky"] = Spectrum1D(wcs=wcs,
                                                          flux=rwss_flux,
                                                          meta=rwss_meta)

            # Add our spectrum to the list.
            # The additional spectra are accessed using
            # spectrum.meta['variance'] and spectrum.meta['science_sky']
            sl.append(spectrum)

    add_labels(sl)

    return sl
def dered_corr(data_path, template_path, wave_corr, z_lit, z_bound, spec_type):
    """Function to check remaining flexure after flexure correction has been applied.
    
    Parameters
    ----------
    data_path : str
        Path to data spectrum file
    template_path : str
        Path to template spectrum file
    wave_corr : tuple
        Flexure-corrected wavelength array
    z_lit : float
        Literature redshift for target object
    z_bound : float
        Amount to add and subtract from z_lit for redshifts to test
    spec_type : str
        Indicates if looking at coadded spectrum or single 1D spectrum
        
    Returns
    -------
    tm_result_corr : float
        Best-fitting redshift post flexure-correction
    dered_wave : tuple
        De-redshifted wavelength array
    """
    
    #Get data
    data_wave_full, data_cut_wave, data_flux_full, data_cut_flux, data_noise_full, data_cut_noise = prep_data(data_path,
                                                                                                             spec_type)

    #Get template
    template_wave, smoothed_template_flux, smoothed_template_noise = prep_template(template_path)

    #Find redshift of new, corrected spectrum and de-redshift it to match the template
    #Continuum-norm over whole blue range
    norm_wave_corr, norm_corr_flux, norm_corr_noise = continuum_normalize(np.min(wave_corr), np.max(wave_corr), data_cut_flux, 
                                                                          wave_corr, data_cut_noise)
    norm_template_wave, norm_template_flux, norm_template_noise = continuum_normalize(np.min(template_wave), 
                                                                                      np.max(template_wave), 
                                                                                      smoothed_template_flux, template_wave, 
                                                                                      smoothed_template_noise)

    #Plot before
    plt.figure(figsize=(12,4))
    plt.plot(norm_wave_corr, norm_corr_flux, label='observed')
    plt.plot(norm_template_wave, norm_template_flux, label='template')
    plt.legend()

    #Find new redshift of whole spectrum
    corr_spec = Spectrum1D(spectral_axis=norm_wave_corr*u.Angstrom, flux=norm_corr_flux*(u.erg/u.s/u.cm**2/u.Angstrom),
                           uncertainty=StdDevUncertainty(norm_corr_noise))
    template_spec = Spectrum1D(spectral_axis=norm_template_wave*u.Angstrom, flux=norm_template_flux*(u.Lsun/u.micron))

    pre_redshifts = np.linspace(z_lit-z_bound, z_lit+z_bound, 1000)
    tm_result_corr = template_redshift(observed_spectrum=corr_spec, template_spectrum=template_spec, redshift=pre_redshifts)

    #Plot after
    plt.figure(figsize=(12,4))
    plt.plot(corr_spec.spectral_axis, corr_spec.flux, label='observed')
    plt.plot(tm_result_corr[2].spectral_axis, tm_result_corr[2].flux, label='redshifted template')
    plt.legend()

    plt.figure(figsize=(12,4))
    plt.plot(template_spec.spectral_axis, template_spec.flux, label='template')
    plt.plot(tm_result_corr[2].spectral_axis, tm_result_corr[2].flux, label='redshifted template')
    plt.legend()

    #De-redshift data
    dered_wave = norm_wave_corr/(1+z_lit)

    plt.figure(figsize=(12,4))
    plt.plot(dered_wave, norm_corr_flux, label='de-redshifted data')
    plt.plot(norm_template_wave, norm_template_flux, label='template')
    plt.legend()
    
    return tm_result_corr, dered_wave
示例#17
0
def test_from_spectrum1d(mode):

    if mode == 'wcs3d':
        # This test is intended to be run with the version of Spectrum1D based
        # on NDCube 2.0
        pytest.importorskip("ndcube", minversion="1.99")

        # Set up simple spatial+spectral WCS
        wcs = WCS(naxis=3)
        wcs.wcs.ctype = ['RA---TAN', 'DEC--TAN', 'FREQ']
        wcs.wcs.set()
        flux = np.ones((4, 4, 5))*u.Unit('Jy')
        uncertainty = VarianceUncertainty(np.square(flux*0.1))
        mask = np.zeros((4, 4, 5))
        kwargs = {'wcs': wcs, 'uncertainty': uncertainty, 'mask': mask}
    else:
        flux = [2, 3, 4, 5] * u.Jy
        uncertainty = VarianceUncertainty([0.1, 0.1, 0.1, 0.1] * u.Jy**2)
        mask = [False, False, False, False]
        if mode == 'wcs1d':
            wcs = WCS(naxis=1)
            wcs.wcs.ctype = ['FREQ']
            wcs.wcs.set()
            kwargs = {'wcs': wcs, 'uncertainty': uncertainty, 'mask': mask}
        else:
            kwargs = {'spectral_axis': [1, 2, 3, 4] * u.Hz,
                      'uncertainty': uncertainty, 'mask': mask}

    spec = Spectrum1D(flux, **kwargs)

    data_collection = DataCollection()

    data_collection['spectrum'] = spec

    data = data_collection['spectrum']

    assert isinstance(data, Data)
    assert len(data.main_components) == 3
    assert data.main_components[0].label == 'flux'
    assert_allclose(data['flux'], flux.value)
    component = data.get_component('flux')
    assert component.units == 'Jy'

    # Check uncertainty parsing within glue data object
    assert data.main_components[1].label == 'uncertainty'
    assert_allclose(data['uncertainty'], uncertainty.array)
    component = data.get_component('uncertainty')
    assert component.units == 'Jy2'

    # Check round-tripping via single attribute reference
    spec_new = data.get_object(attribute='flux', statistic=None)
    assert isinstance(spec_new, Spectrum1D)
    assert_quantity_allclose(spec_new.spectral_axis, [1, 2, 3, 4] * u.Hz)
    if mode == 'wcs3d':
        assert_quantity_allclose(spec_new.flux, np.ones((5, 4, 4))*u.Unit('Jy'))
    else:
        assert_quantity_allclose(spec_new.flux, [2, 3, 4, 5] * u.Jy)
    assert spec_new.uncertainty is None

    # Check complete round-tripping, including uncertainties
    spec_new = data.get_object(statistic=None)
    assert isinstance(spec_new, Spectrum1D)
    assert_quantity_allclose(spec_new.spectral_axis, [1, 2, 3, 4] * u.Hz)
    if mode == 'wcs3d':
        assert_quantity_allclose(spec_new.flux, np.ones((5, 4, 4))*u.Unit('Jy'))
        assert spec_new.uncertainty is not None
        print(spec_new.uncertainty)
        print(uncertainty)
        assert_quantity_allclose(spec_new.uncertainty.quantity,
                                 np.ones((5, 4, 4))*0.01*u.Jy**2)
    else:
        assert_quantity_allclose(spec_new.flux, [2, 3, 4, 5] * u.Jy)
        assert spec_new.uncertainty is not None
        assert_quantity_allclose(spec_new.uncertainty.quantity, [0.1, 0.1, 0.1, 0.1] * u.Jy**2)
示例#18
0
def mos_niriss_parser(app, data_dir, obs_label=""):
    """
    Attempts to parse all data for a NIRISS dataset in the specified
    directory, which should include:
    - *_direct_*_cal.fits : Direct 2D image
    - *_direct_*_cat.ecsv : Source catalog
    - *_WFSSR_*_cal.fits : 2D spectra in first orientation
    - *_WFSSC_*_cal.fits : 2D spectra in second orientation
    - *_WFSSR_*_x1d.fits : 1D spectra in first orientatiom
    - *_WFSSC_*_x1d.fits : 1D spectra in second orientatiom
    The spectra from the "C" files (horizontal orientation) are showed
    in the viewers by default.
    """

    p = Path(data_dir)
    if not p.is_dir():
        raise ValueError("{} is not a valid directory path".format(data_dir))
    source_cat = sorted(list(p.glob("{}*_direct_*_cat.ecsv".format(obs_label))))
    direct_image = sorted(list(p.glob("{}*_direct_dit1*_i2d.fits".format(obs_label))))
    spec2d_r = sorted(list(p.glob("{}*_WFSSR_*_cal.fits".format(obs_label))))
    spec2d_c = sorted(list(p.glob("{}*_WFSSC_*_cal.fits".format(obs_label))))
    spec1d_r = sorted(list(p.glob("{}*_WFSSR_*_x1d.fits".format(obs_label))))
    spec1d_c = sorted(list(p.glob("{}*_WFSSC_*_x1d.fits".format(obs_label))))

    file_lists = {
                  "Source Catalog": source_cat,
                  "Direct Image": direct_image,
                  "2D Spectra C": spec2d_c,
                  "2D Spectra R": spec2d_r,
                  "1D Spectra C": spec1d_c,
                  "1D Spectra R": spec1d_r
                 }

    # Convert from pathlib Paths back to strings
    for key in file_lists:
        file_lists[key] = [str(x) for x in file_lists[key]]
    _warn_if_not_found(app, file_lists)

    # Parse relevant information from source catalog
    cat_fields = ["id", "sky_centroid.ra", "sky_centroid.dec"]
    source_ids = []
    ras = []
    decs = []
    image_add = []

    pupil_id_dict = {}

    # Retrieve source information
    for source_catalog_num in range(0, len(file_lists["Source Catalog"])):
        cat_file = file_lists["Source Catalog"][source_catalog_num]
        parsed_cat_fields = _fields_from_ecsv(cat_file, cat_fields, delimiter=" ")
        pupil = [x
                 for x in cat_file.split("/")[-1].split("_")
                 if x[0] == "F" or x[0] == "f"][0]

        pupil_id_dict[pupil] = {}

        for row in parsed_cat_fields:
            pupil_id_dict[pupil][int(row[0])] = (row[1], row[2])

    # Read in direct image filters
    image_dict = {}
    filter_wcs = {}

    # Set up a dictionary of datasets to add to glue
    add_to_glue = {}

    print("Loading: Images")

    for image_file in file_lists["Direct Image"]:
        im_split = image_file.split("/")[-1].split("_")
        pupil = [x
                 for x in image_file.split("/")[-1].split("_")
                 if x[0] == "F" or x[0] == "f"][0]

        image_label = "Image {} {}".format(im_split[0], pupil)

        with fits.open(image_file) as file_obj:
            data_iter = get_image_data_iterator(app, file_obj, "Image", ext=None)
            data_obj = [d[0] for d in data_iter]  # We do not use the generated labels
            image_data = data_obj[0]  # Grab the first one. TODO: Error if multiple found?

        with fits.open(image_file) as temp:
            filter_wcs[pupil] = temp[1].header

        image_data.label = image_label
        add_to_glue[image_label] = image_data

        image_dict[pupil] = image_label

    # Parse 2D spectra
    spec_labels_2d = []
    for f in ["2D Spectra C", "2D Spectra R"]:

        for fname in file_lists[f]:
            print(f"Loading: {f} sources")

            orientation = f[-1]
            filter_name = [x
                           for x in fname.split("/")[-1].split("_")
                           if x[0] == "F" or x[0] == "f"][0]

            with fits.open(fname, memmap=False) as temp:
                sci_hdus = []
                wav_hdus = {}
                for i in range(len(temp)):
                    if "EXTNAME" in temp[i].header:
                        if temp[i].header["EXTNAME"] == "SCI":
                            sci_hdus.append(i)
                            wav_hdus[i] = ('WAVELENGTH', temp[i].header['EXTVER'])

                # Now get a Spectrum1D object for each SCI HDU
                for sci in sci_hdus:

                    if temp[sci].header["SPORDER"] == 1:

                        data = temp[sci].data
                        meta = temp[sci].header

                        # The wavelength is stored in a WAVELENGTH HDU. This is
                        # a 2D array, but in order to be able to use Spectrum1D
                        # we use the average wavelength for all image rows
                        wav = temp[wav_hdus[sci]].data.mean(axis=0) * u.micron

                        spec2d = Spectrum1D(data * u.one, spectral_axis=wav, meta=meta)

                        spec2d.meta['INSTRUME'] = 'NIRISS'

                        label = "{} Source {} spec2d {}".format(filter_name,
                                                                temp[sci].header["SOURCEID"],
                                                                orientation
                                                                )
                        ra, dec = pupil_id_dict[filter_name][temp[sci].header["SOURCEID"]]
                        source_ids.append("Source Catalog: {} Source ID: {}".
                                          format(filter_name, temp[sci].header["SOURCEID"]))
                        ras.append(ra)
                        decs.append(dec)
                        image_add.append(image_dict[filter_name])
                        spec_labels_2d.append(label)

                        add_to_glue[label] = spec2d

    spec_labels_1d = []
    for f in ["1D Spectra C", "1D Spectra R"]:

        for fname in file_lists[f]:
            print(f"Loading: {f} sources")

            with fits.open(fname, memmap=False) as temp:
                # TODO: Remove this once valid SRCTYPE values are present in all headers
                for hdu in temp:
                    if "SRCTYPE" in hdu.header and\
                            (hdu.header["SRCTYPE"] in ["POINT", "EXTENDED"]):
                        pass
                    else:
                        hdu.header["SRCTYPE"] = "EXTENDED"

                specs = SpectrumList.read(temp, format="JWST x1d multi")
                filter_name = [x
                               for x in fname.split("/")[-1].split("_")
                               if x[0] == "F" or x[0] == "f"][0]

                # Orientation denoted by "C" or "R"
                orientation = f[-1]

                for spec in specs:
                    if spec.meta['header']['SPORDER'] == 1 and\
                            spec.meta['header']['EXTNAME'] == "EXTRACT1D":

                        label = "{} Source {} spec1d {}".format(filter_name,
                                                                spec.meta['header']['SOURCEID'],
                                                                orientation
                                                                )
                        spec_labels_1d.append(label)
                        add_to_glue[label] = spec

    # Add the datasets to glue - we do this in one step so that we can easily
    # optimize by avoiding recomputing the full link graph at every add

    with app.data_collection.delay_link_manager_update():

        for label, data in add_to_glue.items():
            app.add_data(data, label, notify_done=False)

        # We then populate the table inside this context manager as _add_to_table
        # does operations that also trigger link manager updates.
        _add_to_table(app, source_ids, "Source ID")
        _add_to_table(app, ras, "Right Ascension")
        _add_to_table(app, decs, "Declination")
        _add_to_table(app, image_add, "Images")
        _add_to_table(app, spec_labels_1d, "1D Spectra")
        _add_to_table(app, spec_labels_2d, "2D Spectra")

    app.get_viewer('table-viewer')._shared_image = True
示例#19
0
def EW(specname,name):

    lamb, flux= np.genfromtxt(specname, skip_header=1, unpack=True)

    flux = flux * u.Unit('J cm-2 s-1 AA-1') 
    #flux = flux * u.Unit('erg cm-2 s-1 AA-1') 
    lamb= lamb * u.AA 
    spec = Spectrum1D(spectral_axis=lamb, flux=flux) 
    # normalization is not so good 
    cont_norm_spec = spec / fit_generic_continuum(spec)(spec.spectral_axis) 

    print('-----------'+name+'------------')
#line A
    EWa = equivalent_width(cont_norm_spec, regions=SpectralRegion(8493*u.AA, 8502*u.AA))
    #FWHMa = fwhm(cont_norm_spec, regions=SpectralRegion(8493*u.AA, 8502*u.AA))
    print('EW A line: '+str(EWa))
#line B
    EWb = equivalent_width(cont_norm_spec, regions=SpectralRegion(8533*u.AA, 8551*u.AA))
    print('EW B line: '+str(EWb))
#line C
    EWc = equivalent_width(cont_norm_spec, regions=SpectralRegion(8655*u.AA, 8670*u.AA))
    print('EW C line: '+str(EWc))
#open log file 
    
    #nonlinear to metal-poor
    V_VHB = -2.0
    
    EWbc= (EWb+EWc)
    EWbc= float(EWbc/(1. * u.AA))
    
    EWp = (EWbc)**(-1.5) 
    
    #nonlinear to metal-poor
    #Wl = float(EWb / (1. * u.AA)) + float(EWc / (1. * u.AA)) + (0.64 * V_VHB)
    #FeH= -2.81 + 0.44*Wl
    # FeH constants to V-VHB
    
    a=-2.87
    b=0.195
    c=0.458
    d=-0.913
    e=0.0155
    
    #float all
    
    FeH = a + b * V_VHB + c * EWbc + d * EWp + e * EWbc * V_VHB 
    
    
    
    print('[Fe/H]: '+str(FeH))

    #change relampled spectrum to noise spectrum 
    LOG = open('./EWs/EWfile-'+name+'.txt', 'w')
    #LOG = open('./EWs/EWfileRE-'+name+'.txt', 'w')
    LOG.write('Log file of '+ name +' \n \n')
    LOG.write('Input Spectrum:   '+ specname +' \n \n')
    LOG.write('EW A line:             '+ str(EWa) +' \n') 
    LOG.write('EW B line:             '+ str(EWb) +' \n') 
    LOG.write('EW C line:             '+ str(EWc) +' \n') 
    LOG.write('[Fe/H]_CaT:             '+ str(FeH) +' \n') 

    
    f1 = plt.figure(figsize=(16,9))

    ax = f1.add_subplot(111)
    ax.plot(cont_norm_spec.spectral_axis, cont_norm_spec.flux)
    ax.set_xlim([8480,8690])
    ax.set_ylabel('Flux (J cm-2 s-1 AA-1)')
    ax.set_xlabel('Wavelength ( $\AA$ )')
    ax.axvspan(8498-float(EWa / (2. * u.AA))  , 8498+float(EWa / (2. * u.AA))   , alpha=0.2, color='red')
    ax.axvspan(8542-float(EWb / (2. * u.AA))  , 8542+float(EWb / (2. * u.AA))   , alpha=0.2, color='red')
    ax.axvspan(8662-float(EWc / (2. * u.AA))  , 8662+float(EWc / (2. * u.AA))   , alpha=0.2, color='red')
    
    #change relampled spectrum to noise spectrum 
    plt.savefig('./EWs/EW-figs/EW'+name+'.pdf')
示例#20
0
    def vue_fit_model_to_cube(self, *args, **kwargs):

        if self._warn_if_no_equation():
            return
        data = self.app.data_collection[self._selected_data_label]

        # First, ensure that the selected data is cube-like. It is possible
        # that the user has selected a pre-existing 1d data object.
        if data.ndim != 3:
            snackbar_message = SnackbarMessage(
                f"Selected data {self._selected_data_label} is not cube-like",
                color='error',
                sender=self)
            self.hub.broadcast(snackbar_message)
            return

        # Get the primary data component
        attribute = data.main_components[0]
        component = data.get_component(attribute)
        temp_values = data.get_data(attribute)

        # Transpose the axis order
        values = np.moveaxis(temp_values, 0, -1) * u.Unit(component.units)

        # We manually create a Spectrum1D object from the flux information
        #  in the cube we select
        wcs = data.coords.sub([WCSSUB_SPECTRAL])
        spec = Spectrum1D(flux=values, wcs=wcs)

        # TODO: in vuetify >2.3, timeout should be set to -1 to keep open
        #  indefinitely
        snackbar_message = SnackbarMessage("Fitting model to cube...",
                                           loading=True,
                                           timeout=0,
                                           sender=self)
        self.hub.broadcast(snackbar_message)

        # Retrieve copy of the models with proper "fixed" dictionaries
        # TODO: figure out why this was causing the parallel fitting to fail
        #models_to_fit = self._reinitialize_with_fixed()
        models_to_fit = self._initialized_models.values()

        fitted_model, fitted_spectrum = fit_model_to_spectrum(
            spec, models_to_fit, self.model_equation, run_fitter=True)

        # Save fitted 3D model in a way that the cubeviz
        # helper can access it.
        self.app._fitted_3d_model = fitted_model

        # Transpose the axis order back
        values = np.moveaxis(fitted_spectrum.flux.value, -1, 0)

        count = max(
            map(lambda s: int(next(iter(re.findall("\d$", s)), 0)),
                self.data_collection.labels)) + 1

        label = f"{self.model_label} [Cube] {count}"

        # Create new glue data object
        output_cube = Data(label=label, coords=data.coords)
        output_cube['flux'] = values
        output_cube.get_component('flux').units = \
            fitted_spectrum.flux.unit.to_string()

        # Add to data collection
        self.app.data_collection.append(output_cube)

        snackbar_message = SnackbarMessage("Finished cube fitting",
                                           color='success',
                                           loading=False,
                                           sender=self)
        self.hub.broadcast(snackbar_message)
示例#21
0
文件: VERNE.py 项目: drheitor/VERNE
    xn=[]
    yn=[]
    n=0
    for i in point:
        xn.append(point[n][0])
        yn.append(point[n][1])
        n=n+1
      
#--------------------------------      
#Creating spectrums to fit 


y=-y+1.0
y = y * u.Unit('J cm-2 s-1 AA-1') 
# reading spec
spec = Spectrum1D(spectral_axis=x*u.AA, flux=y)


#--------------------------------
#LINES LIMITS
if interactive_mode == False:
    lines = find_lines_derivative(spec, flux_threshold= 1 - _flux_threshold_)

    if len(lines)>3:
        print('Check _flux_threshold_' )
    
    try:
        lineAcentre=lines[0][0]
        lineBcentre=lines[1][0]
        lineCcentre=lines[2][0]
    # if the code was only able to find the CaT-b line    
示例#22
0
    def vue_fit_model_to_cube(self, *args, **kwargs):

        if self._warn_if_no_equation():
            return

        if self.selected_data in self.app.data_collection.labels:
            data = self.app.data_collection[self.selected_data]
        else:  # User selected some subset from spectrum viewer, just use original cube
            data = self.app.data_collection[0]

        # First, ensure that the selected data is cube-like. It is possible
        # that the user has selected a pre-existing 1d data object.
        if data.ndim != 3:
            snackbar_message = SnackbarMessage(
                f"Selected data {self.selected_data} is not cube-like",
                color='error',
                sender=self)
            self.hub.broadcast(snackbar_message)
            return

        # Get the primary data component
        attribute = data.main_components[0]
        component = data.get_component(attribute)
        temp_values = data.get_data(attribute)

        # Transpose the axis order
        values = np.moveaxis(temp_values, 0, -1) * u.Unit(component.units)

        # We manually create a Spectrum1D object from the flux information
        #  in the cube we select
        wcs = data.coords.sub([WCSSUB_SPECTRAL])
        spec = Spectrum1D(flux=values, wcs=wcs)

        # TODO: in vuetify >2.3, timeout should be set to -1 to keep open
        #  indefinitely
        snackbar_message = SnackbarMessage("Fitting model to cube...",
                                           loading=True,
                                           timeout=0,
                                           sender=self)
        self.hub.broadcast(snackbar_message)

        # Retrieve copy of the models with proper "fixed" dictionaries
        models_to_fit = self._reinitialize_with_fixed()

        try:
            fitted_model, fitted_spectrum = fit_model_to_spectrum(
                spec,
                models_to_fit,
                self.model_equation,
                run_fitter=True,
                window=self._window)
        except ValueError:
            snackbar_message = SnackbarMessage("Cube fitting failed",
                                               color='error',
                                               loading=False,
                                               sender=self)
            self.hub.broadcast(snackbar_message)
            raise

        # Save fitted 3D model in a way that the cubeviz
        # helper can access it.
        for m in fitted_model:
            temp_label = "{} ({}, {})".format(self.model_label, m["x"], m["y"])
            self.app.fitted_models[temp_label] = m["model"]

        # Transpose the axis order back
        values = np.moveaxis(fitted_spectrum.flux.value, -1, 0)

        count = max(
            map(lambda s: int(next(iter(re.findall(r"\d$", s)), 0)),
                self.data_collection.labels)) + 1

        label = f"{self.model_label} [Cube] {count}"

        # Create new glue data object
        output_cube = Data(label=label, coords=data.coords)
        output_cube['flux'] = values
        output_cube.get_component('flux').units = \
            fitted_spectrum.flux.unit.to_string()

        # Add to data collection
        self.app.add_data(output_cube, label)
        if self.selected_viewer != 'None':
            # replace the contents in the selected viewer with the results from this plugin
            self.app.add_data_to_viewer(self.viewer_to_id.get(
                self.selected_viewer),
                                        label,
                                        clear_other_data=True)

        snackbar_message = SnackbarMessage("Finished cube fitting",
                                           color='success',
                                           loading=False,
                                           sender=self)
        self.hub.broadcast(snackbar_message)
示例#23
0
def load_MAST_calspec(filename, remote=True, cache=True, show_progress=False):
    """
    Load a standard star spectrum from the `calspec` database at MAST. These spectra are provided in
    FITS format and are described in detail at:

    https://www.stsci.edu/hst/instrumentation/reference-data-for-calibration-and-tools/astronomical-catalogs/calspec  # noqa

    If `remote` is True, the spectrum will be downloaded from MAST. Set `remote` to False to load
    a local file.

    Parameters
    ----------
    filename : str
        FITS filename of the standard star spectrum, e.g. g191b2b_005.fits.

    remote : bool (default = True)
        If True, download the spectrum from MAST. If False, check if `filename` exists and load
        it.
    cache : bool (default = True)
        Toggle whether downloaded data is cached or not.
    show_progress : bool (default = True)
        Toggle whether download progress bar is shown.

    Returns
    -------
    spectrum : None or `~specutils.Spectrum1D`
        If the spectrum can be loaded, return it as a `~specutils.Spectrum1D`.
        Otherwise return None. The spectral_axis units are Å (`~astropy.units.angstrom`) and
        the flux units are milli-Janskys (`~astropy.units.mJy`).
    """
    if remote:
        url = f"https://archive.stsci.edu/hlsps/reference-atlases/cdbs/calspec/{filename}"
        try:
            file_path = download_file(
                url,
                cache=cache,
                show_progress=show_progress,
                pkgname='specreduce'
            )
        except Exception as e:
            msg = f"Downloading of {filename} failed: {e}"
            warnings.warn(msg, AstropyUserWarning)
            file_path = None
    else:
        if os.path.isfile(filename):
            file_path = filename
        else:
            msg = f"Provided filename, {filename}, does not exist or is not a valid file."
            warnings.warn(msg, AstropyUserWarning)
            file_path = None

    if file_path is None:
        return None
    else:
        hdr, wave, flux = synphot.specio.read_fits_spec(file_path)

        # the calspec data stores flux in synphot's FLAM units. convert to flux units
        # supported directly by astropy.units. mJy is chosen since it's the JWST
        # standard and can easily be converted to/from AB magnitudes.
        flux_mjy = synphot.units.convert_flux(wave, flux, u.mJy)
        spectrum = Spectrum1D(spectral_axis=wave, flux=flux_mjy)
        return spectrum
示例#24
0
sne_name = folder_path.split('/')[-1]

#input command for redshift
redshift = float(input('Input Redshift of SNe:'))
z = 1 + redshift

#turn each file name into array
#apply obs to rest wavelength and flux conversion
#create list of spectrum files, and continuum files
cont_list = []
data = []
for epoch in file_list:
    file = np.genfromtxt(fname= epoch)
    lamb = (file[:, 0] / z) * u.AA
    flux = file[:, 1] * 10 ** -15 * u.Unit('erg cm-2 s-1 AA-1')
    spec = Spectrum1D(spectral_axis=lamb, flux=flux)
    data.append(spec)
    cont_list.append((spec /spec) * fit_generic_continuum(spec)(spec.spectral_axis))


#plot to find the lines to calculate EW
spcplt = data[0]
cntplt = cont_list[0]
f, ax = plt.subplots()
ax.step(spcplt.wavelength, spcplt.flux)
ax.step(cntplt.wavelength, cntplt.flux)
ax.set_xlim(6000*u.AA, 7500*u.AA)
ax.grid(True)
wave = [6563, 6678, 7065, 7155]
for line in wave:
    plt.axvline(x = line)
示例#25
0
        q += 1

slice = int(0.3 * (right - left))  #weird koefficient
line = np.zeros(len(data))
for i in range(len(data)):
    line[i] = lines[i][slice]  #result 1d line
not_real_lambda = range(len(line))

slice_light = left - 10  #slice of stray light -- continuum
line_light = np.zeros(len(data))
for i in range(len(data)):
    line_light[i] = data[i][slice]
line -= line_light

#finding emissions and absorptions lines
spectrum = Spectrum1D(flux=line * u.Jy, spectral_axis=not_real_lambda *
                      u.um)  #units only for work
lines1 = find_lines_derivative(spectrum, flux_threshold=100)

lam = []  #wavelenghts of lines
max_flux = []  #amplitudes of lines
num = len(lines1)
for i in range(num):
    max_flux.append(line[int(lines1['line_center'].value[i])])
    lam.append(lines1['line_center'].value[i])

std_hands = 1
compound_model = models.Gaussian1D(max_flux[0], lam[0], std_hands)
for i in range(1, num):
    compound_model += models.Gaussian1D(max_flux[i], lam[i], std_hands)
fitter = fitting.LevMarLSQFitter()
compound_fit = fitter(compound_model, not_real_lambda[0:1000], line[0:1000])
示例#26
0
    def to_object(self, data_or_subset, attribute=None, statistic='mean'):
        """
        Convert a glue Data object to a Spectrum1D object.

        Parameters
        ----------
        data_or_subset : `glue.core.data.Data` or `glue.core.subset.Subset`
            The data to convert to a Spectrum1D object
        attribute : `glue.core.component_id.ComponentID`
            The attribute to use for the Spectrum1D data
        statistic : {'minimum', 'maximum', 'mean', 'median', 'sum', 'percentile'}
            The statistic to use to collapse the dataset
        """

        if isinstance(data_or_subset, Subset):
            data = data_or_subset.data
            subset_state = data_or_subset.subset_state
        else:
            data = data_or_subset
            subset_state = None

        if isinstance(data.coords, WCSCoordinates):

            # Find spectral axis
            spec_axis = data.coords.wcs.naxis - 1 - data.coords.wcs.wcs.spec

            # Find non-spectral axes
            axes = tuple(i for i in range(data.ndim) if i != spec_axis)

            kwargs = {'wcs': data.coords.wcs.sub([WCSSUB_SPECTRAL])}

        elif isinstance(data.coords, SpectralCoordinates):

            kwargs = {'spectral_axis': data.coords.spectral_axis}

        else:

            raise TypeError(
                'data.coords should be an instance of WCSCoordinates or SpectralCoordinates'
            )

        if isinstance(attribute, str):
            attribute = data.id[attribute]
        elif len(data.main_components) == 0:
            raise ValueError('Data object has no attributes.')
        elif attribute is None:
            if len(data.main_components) == 1:
                attribute = data.main_components[0]
            else:
                raise ValueError(
                    "Data object has more than one attribute, so "
                    "you will need to specify which one to use as "
                    "the flux for the spectrum using the "
                    "attribute= keyword argument.")

        component = data.get_component(attribute)

        # Collapse values to profile
        if data.ndim > 1:
            # Get units and attach to value
            values = data.compute_statistic(statistic,
                                            attribute,
                                            axis=axes,
                                            subset_state=subset_state)
            mask = None
        else:
            values = data.get_data(attribute)
            if subset_state is None:
                mask = None
            else:
                mask = data.get_mask(subset_state=subset_state)
                values = values.copy()
                values[~mask] = np.nan

        values = values * u.Unit(component.units)

        return Spectrum1D(values, mask=mask, **kwargs)
示例#27
0
    def vue_spatial_convolution(self, *args):
        """
        Use astropy convolution machinery to smooth the spatial dimensions of
        the data cube.
        """

        size = float(self.stddev)

        label = f"Smoothed {self._selected_data.label} spatial stddev {size}"

        if label in self.data_collection:
            # immediately cancel before smoothing
            snackbar_message = SnackbarMessage(
                "Data with selected stddev already exists, canceling operation.",
                color="error",
                sender=self)
            self.hub.broadcast(snackbar_message)

            return

        # Get information from the flux component
        attribute = self._selected_data.main_components[0]

        cube = self._selected_data.get_object(cls=Spectrum1D,
                                              attribute=attribute,
                                              statistic=None)
        flux_unit = cube.flux.unit

        # Extend the 2D kernel to have a length 1 spectral dimension, so that
        # we can do "3d" convolution to the whole cube
        kernel = np.expand_dims(Gaussian2DKernel(size), 2)

        # TODO: in vuetify >2.3, timeout should be set to -1 to keep open
        #  indefinitely
        snackbar_message = SnackbarMessage(
            "Smoothing spatial slices of cube...",
            loading=True,
            timeout=0,
            sender=self)
        self.hub.broadcast(snackbar_message)

        convolved_data = convolve(cube, kernel)

        # Create a new cube with the old metadata. Note that astropy
        # convolution generates values for masked (NaN) data.
        newcube = Spectrum1D(flux=convolved_data * flux_unit, wcs=cube.wcs)

        # add data to the collection
        self.app.add_data(newcube, label)
        if self.selected_viewer != 'None':
            # replace the contents in the selected viewer with the results from this plugin
            self.app.add_data_to_viewer(self.viewer_to_id.get(
                self.selected_viewer),
                                        label,
                                        clear_other_data=True)

        snackbar_message = SnackbarMessage(
            f"Data set '{self._selected_data.label}' smoothed successfully.",
            color="success",
            sender=self)
        self.hub.broadcast(snackbar_message)
示例#28
0

if __name__ == "__main__":
    wline = [185.999]
    band = 'R1'
    order = int(band[1])
    np.random.seed(0)
    x = np.linspace(180., 190., 100)
    y = 3 * np.exp(-0.5 * (x - 185.999)**2 / 0.1**2)
    y += np.random.normal(0., 0.2, x.shape)

    y_continuum = 3.2 * np.exp(-0.5 * (x - 5.6)**2 / 4.8**2)
    y += y_continuum

    #create spectrum to fit
    spectrum = Spectrum1D(flux=y * u.Jy, spectral_axis=x * u.um)
    noise_region = SpectralRegion(180. * u.um, 184. * u.um)
    spectrum = noise_region_uncertainty(spectrum, noise_region)

    #line_region = [(185.52059807*u.um, 186.47740193*u.um)]
    g1_fit = fit_generic_continuum(spectrum, model=models.Polynomial1D(1))
    y_continuum_fitted = g1_fit(x * u.um)

    plt.plot(x, y, label='spectrum')
    plt.errorbar(x, y, yerr=spectrum.uncertainty.array, color='b')
    plt.plot(x, y_continuum_fitted, label='cont_0')
    plt.title('Continuum+line Fitting')
    plt.grid(True)

    line = LineFitterMult(spectrum,
                          wline,
示例#29
0
def create_spectrum1d(xmin, xmax, uncertainty=None):
    flux = np.ones(xmax - xmin) * u.Jy
    wavelength = np.arange(xmin, xmax) * 0.1 * u.nm
    uncertainty = StdDevUncertainty(np.ones(xmax - xmin) * u.Jy) if uncertainty is not None else None
    return Spectrum1D(spectral_axis=wavelength, flux=flux,
                      uncertainty=uncertainty)
示例#30
0
def specviz_spectrum1d_parser(app,
                              data,
                              data_label=None,
                              format=None,
                              show_in_viewer=True):
    """
    Loads a data file or `~specutils.Spectrum1D` object into Specviz.

    Parameters
    ----------
    data : str, `~specutils.Spectrum1D`, or `~specutils.SpectrumList`
        Spectrum1D, SpectrumList, or path to compatible data file.
    data_label : str
        The Glue data label found in the ``DataCollection``.
    format : str
        Loader format specification used to indicate data format in
        `~specutils.Spectrum1D.read` io method.
    """

    # If no data label is assigned, give it a unique identifier
    if not data_label:
        data_label = "specviz_data|" + str(
            base64.b85encode(uuid.uuid4().bytes), "utf-8")

    if isinstance(data, SpectrumCollection):
        raise TypeError("SpectrumCollection detected."
                        " Please provide a Spectrum1D or SpectrumList")
    elif isinstance(data, Spectrum1D):
        data = [data]
        data_label = [data_label]
    elif isinstance(data, SpectrumList):
        pass
    else:
        path = pathlib.Path(data)

        if path.is_file():
            try:
                data = [Spectrum1D.read(str(path), format=format)]
                data_label = [data_label]
            except IORegistryError:
                # Multi-extension files may throw a registry error
                data = SpectrumList.read(str(path), format=format)
        else:
            raise FileNotFoundError("No such file: " + str(path))

    if isinstance(data, SpectrumList):
        if not isinstance(data_label, (list, tuple)):
            temp_labels = []
            for i in range(len(data)):
                temp_labels.append(f"{data_label} {i}")
            data_label = temp_labels
        elif len(data_label) != len(data):
            raise ValueError(
                f"Length of data labels list ({len(data_label)}) is different"
                f" than length of list of data ({len(data)})")

    # If there's already data in the viewer, convert units if needed
    current_unit = None
    current_spec = app.get_data_from_viewer("spectrum-viewer")
    if current_spec != {} and current_spec is not None:
        spec_key = list(current_spec.keys())[0]
        current_unit = current_spec[spec_key].spectral_axis.unit
    with app.data_collection.delay_link_manager_update():
        for i in range(len(data)):
            spec = data[i]
            if current_unit is not None and spec.spectral_axis.unit != current_unit:
                spec = Spectrum1D(
                    flux=spec.flux,
                    spectral_axis=spec.spectral_axis.to(current_unit))

            app.add_data(spec, data_label[i])

            # Only auto-show the first spectrum in a list
            if i == 0 and show_in_viewer:
                app.add_data_to_viewer("spectrum-viewer", data_label[i])