Example #1
0
def test_mag_ab_redshift_dependence():

    from astropy import units

    from skypy.galaxy.spectrum import mag_ab

    # make a wide tophat bandpass
    bp_lam = np.logspace(-10, 10, 3) * units.AA
    bp_tx = np.ones(3) * units.dimensionless_unscaled
    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)

    # create a narrow gaussian source
    lam = np.logspace(0, 3, 1000) * units.AA
    flam = np.exp(-((lam - 100 * units.AA) /
                    (10 * units.AA))**2) * units.Unit('erg s-1 cm-2 AA-1')
    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)

    # array of redshifts
    z = np.linspace(0, 1, 11)

    # compute the AB magnitude at different redshifts
    m = mag_ab(spec, bp, z)

    # compare with expected redshift dependence
    np.testing.assert_allclose(m, m[0] - 2.5 * np.log10(1 + z))
Example #2
0
def test_mag_ab_multi():

    from astropy import units
    from skypy.galaxy.spectrum import mag_ab

    # 5 redshifts
    z = np.linspace(0, 1, 5)

    # 2 Gaussian bandpasses
    bp_lam = np.logspace(0, 4, 1000) * units.AA
    bp_mean = np.array([[1000], [2000]]) * units.AA
    bp_width = np.array([[100], [10]]) * units.AA
    bp_tx = np.exp(-(
        (bp_lam - bp_mean) / bp_width)**2) * units.dimensionless_unscaled
    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)

    # 3 Flat Spectra
    lam = np.logspace(0, 4, 1000) * units.AA
    A = np.array([[2], [3], [4]])
    flam = A * 0.10884806248538730623 * units.Unit('erg s-1 cm-2 AA') / lam**2
    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)

    # Compare calculated magnitudes with truth
    magnitudes = mag_ab(spec, bp, z)
    truth = -2.5 * np.log10(A * (1 + z)).T[:, np.newaxis, :]
    assert magnitudes.shape == (5, 2, 3)
    np.testing.assert_allclose(*np.broadcast_arrays(magnitudes, truth))
Example #3
0
def test_template_spectra():

    from astropy import units
    from skypy.galaxy.spectrum import mag_ab, magnitudes_from_templates
    from astropy.cosmology import Planck15

    # 3 Flat Templates
    lam = np.logspace(0, 4, 1000) * units.AA
    A = np.array([[2], [3], [4]])
    flam = A * 0.10884806248538730623 * units.Unit('erg s-1 cm-2 AA') / lam**2
    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)

    # Gaussian bandpass
    bp_lam = np.logspace(0, 4, 1000) * units.AA
    bp_tx = np.exp(-((bp_lam - 1000 * units.AA) /
                     (100 * units.AA))**2) * units.dimensionless_unscaled
    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)

    # Each test galaxy is exactly one of the templates
    coefficients = np.diag(np.ones(3))
    mt = magnitudes_from_templates(coefficients, spec, bp)
    m = mag_ab(spec, bp)
    np.testing.assert_allclose(mt, m)

    # Test distance modulus
    redshift = np.array([0, 1, 2])
    dm = Planck15.distmod(redshift).value
    mt = magnitudes_from_templates(coefficients, spec, bp, distance_modulus=dm)
    np.testing.assert_allclose(mt, m + dm)

    # Test stellar mass
    sm = np.array([1, 2, 3])
    mt = magnitudes_from_templates(coefficients, spec, bp, stellar_mass=sm)
    np.testing.assert_allclose(mt, m - 2.5 * np.log10(sm))

    # Redshift interpolation test; linear interpolation sufficient over a small
    # redshift range at low relative tolerance
    z = np.linspace(0, 0.1, 3)
    m_true = magnitudes_from_templates(coefficients,
                                       spec,
                                       bp,
                                       redshift=z,
                                       resolution=4)
    m_interp = magnitudes_from_templates(coefficients,
                                         spec,
                                         bp,
                                         redshift=z,
                                         resolution=2)
    np.testing.assert_allclose(m_true, m_interp, rtol=1e-2)
    with pytest.raises(AssertionError):
        np.testing.assert_allclose(m_true, m_interp, rtol=1e-5)
Example #4
0
def skypy_data_loader(module, name, *tags):
    '''load data from the skypy data package'''

    # result is spectrum or list of spectra
    spectra = None

    # load each tag separately
    for tag in tags:

        # get resource filename from module, name, and tag
        filename = resource_filename(f'skypy-data.{module}',
                                     f'{name}_{tag}.ecsv')

        # load the data file
        data = astropy.table.Table.read(filename, format='ascii.ecsv')

        # get the spectral axis
        spectral_axis = data['spectral_axis'].quantity

        # load all templates
        flux_unit = data['flux_0'].unit
        fluxes = []
        while 'flux_%d' % len(fluxes) in data.colnames:
            fluxes.append(data['flux_%d' %
                               len(fluxes)].quantity.to_value(flux_unit))
        fluxes = np.squeeze(fluxes) * flux_unit

        # construct the Spectrum1D
        spectrum = specutils.Spectrum1D(spectral_axis=spectral_axis,
                                        flux=fluxes)

        # combine with existing
        spectra = combine_spectra(spectra, spectrum)

    return spectra
Example #5
0
def snth_spectrum_1000(NGC4945_continuum_rest_frame):

    real_spectrum = NGC4945_continuum_rest_frame
    freq_axis = real_spectrum.frequency_axis
    sinthetic_model = nd.normalized_blackbody(1000)
    sinthetic_flux = sinthetic_model(freq_axis.value)

    mu, sigma = 0, 0.1
    nd_random = np.random.RandomState(50)
    gaussian_noise = nd_random.normal(mu, sigma, len(freq_axis))
    noisy_model = sinthetic_flux * (1 * u.adu + gaussian_noise * u.adu)

    dispersion = 3.51714285129581
    first_wave = 18940.578099674
    dispersion_type = "LINEAR  "

    spectrum_length = len(real_spectrum.flux)
    spectral_axis = (first_wave +
                     dispersion * np.arange(0, spectrum_length)) * u.AA
    spec1d = su.Spectrum1D(flux=noisy_model, spectral_axis=spectral_axis)
    frequency_axis = spec1d.spectral_axis.to(u.Hz)

    snth_spectrum = NirdustSpectrum(
        header=None,
        z=0,
        spectrum_length=spectrum_length,
        dispersion_key=None,
        first_wavelength=None,
        dispersion_type=dispersion_type,
        spec1d=spec1d,
        frequency_axis=frequency_axis,
    )
    return snth_spectrum
Example #6
0
def decam_loader(*bands):
    '''load DECam bandpass filters'''

    # download DECam filter data
    filename = download_file(
        'http://www.ctio.noao.edu/noao/sites/default/files/DECam/STD_BANDPASSES_DR1.fits'
    )

    # load the data file
    data = astropy.table.Table.read(filename, format='fits')

    # set units
    data['LAMBDA'].unit = units.angstrom

    # get the spectral axis
    spectral_axis = data['LAMBDA'].quantity

    # load requested bands
    throughput = []
    for band in bands:
        throughput.append(data[band])
    throughput = np.squeeze(throughput) * units.dimensionless_unscaled

    # return the bandpasses as Spectrum1D
    return specutils.Spectrum1D(spectral_axis=spectral_axis, flux=throughput)
Example #7
0
def test_fit_blackbody(NGC4945_continuum_rest_frame):
    real_spectrum = NGC4945_continuum_rest_frame
    freq_axis = real_spectrum.frequency_axis
    sinthetic_model = BlackBody(1000 * u.K)
    sinthetic_flux = sinthetic_model(freq_axis)

    dispersion = 3.51714285129581
    first_wave = 18940.578099674
    dispersion_type = "LINEAR  "

    spectrum_length = len(real_spectrum.flux)
    spectral_axis = (first_wave +
                     dispersion * np.arange(0, spectrum_length)) * u.AA
    spec1d = su.Spectrum1D(flux=sinthetic_flux, spectral_axis=spectral_axis)
    frequency_axis = spec1d.spectral_axis.to(u.Hz)

    snth_blackbody = NirdustSpectrum(
        header=None,
        z=0,
        spectrum_length=spectrum_length,
        dispersion_key=None,
        first_wavelength=None,
        dispersion_type=dispersion_type,
        spec1d=spec1d,
        frequency_axis=frequency_axis,
    )

    snth_bb_temp = (snth_blackbody.normalize().convert_to_frequency().
                    fit_blackbody(1200).temperature)

    np.testing.assert_almost_equal(snth_bb_temp.value, 1000, decimal=7)
Example #8
0
def test_mag_ab_standard_source():

    from astropy import units

    from skypy.galaxy.spectrum import mag_ab

    # create a bandpass
    bp_lam = np.logspace(0, 4, 1000) * units.AA
    bp_tx = np.exp(-((bp_lam - 1000 * units.AA) /
                     (100 * units.AA))**2) * units.dimensionless_unscaled
    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)

    # test that the AB standard source has zero magnitude
    lam = np.logspace(0, 4, 1000) * units.AA
    flam = 0.10884806248538730623 * units.Unit('erg s-1 cm-2 AA') / lam**2
    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)

    m = mag_ab(spec, bp)

    assert np.isclose(m, 0)
    def test_from_spectrum1d_Empirical1D_bandpass_masked(self):
        import specutils

        lamb = [1000, 5000, 10000] * u.AA
        thru = [0, 1, -1] * units.THROUGHPUT
        mask = np.array([False, False, True])
        spec = specutils.Spectrum1D(spectral_axis=lamb, flux=thru, mask=mask)
        bp = SpectralElement.from_spectrum1d(spec, keep_neg=False)

        w = bp.waveset
        assert isinstance(bp.model, Empirical1D)
        assert_quantity_allclose(w, [1000, 5000] * u.AA)
        assert_quantity_allclose(bp(w), [0, 1])
    def test_from_spectrum1d_Empirical1D_source_masked(self):
        import specutils

        lamb = [1000, 5000, 10000] * u.AA
        flux = [0, -0.5e-17, 5.6e-17] * units.FLAM
        mask = np.array([False, True, False])
        spec = specutils.Spectrum1D(spectral_axis=lamb, flux=flux, mask=mask)
        sp = SourceSpectrum.from_spectrum1d(spec, keep_neg=False)

        w = sp.waveset
        y = sp(w, flux_unit=units.FLAM)
        assert_quantity_allclose(w, [1000, 10000] * u.AA)
        assert_quantity_allclose(y, [0, 5.6e-17] * units.FLAM)
Example #11
0
    def normalize(self):
        """Normalize the spectrum to the unity using the mean value.

        Returns
        -------
        out: NirsdustSpectrum object
            New instance of the NirdustSpectrun class with the flux normalized
            to unity.
        """
        normalized_flux = self.spec1d.flux / np.mean(self.spec1d.flux)
        new_spec1d = su.Spectrum1D(normalized_flux, self.spec1d.spectral_axis)
        kwargs = attr.asdict(self)
        kwargs.update(spec1d=new_spec1d)
        return NirdustSpectrum(**kwargs)
    def test_from_spectrum1d_Empirical1D_bandpass(self):
        import specutils

        lamb = [1000, 5000, 10000] * u.AA
        thru = [0, 1, -1] * units.THROUGHPUT
        spec = specutils.Spectrum1D(spectral_axis=lamb, flux=thru)
        with pytest.warns(AstropyUserWarning,
                          match=r'contained negative flux or throughput'):
            bp = SpectralElement.from_spectrum1d(spec, keep_neg=False)

        w = bp.waveset
        assert isinstance(bp.model, Empirical1D)
        assert_quantity_allclose(w, lamb)
        assert_quantity_allclose(bp(w), [0, 1, 0])
Example #13
0
def test_combine_spectra():

    from skypy.galaxy._spectrum_loaders import combine_spectra
    from astropy import units

    a = specutils.Spectrum1D(spectral_axis=[1., 2., 3.] * units.AA,
                             flux=[1., 2., 3.] * units.Jy)
    b = specutils.Spectrum1D(spectral_axis=[1e-10, 2e-10, 3e-10] * units.m,
                             flux=[4e-23, 5e-23, 6e-23] *
                             units.Unit('erg s-1 cm-2 Hz-1'))

    assert np.allclose(a.spectral_axis, b.spectral_axis, atol=0, rtol=1e-10)

    assert a == combine_spectra(a, None)
    assert a == combine_spectra(None, a)

    ab = combine_spectra(a, b)
    assert isinstance(ab, specutils.Spectrum1D)
    assert ab.shape == (2, 3)
    assert ab.flux.unit == units.Jy
    assert np.allclose([[1, 2, 3], [4, 5, 6]], ab.flux.value)

    abb = combine_spectra(ab, b)
    assert isinstance(ab, specutils.Spectrum1D)
    assert abb.shape == (3, 3)
    assert abb.flux.unit == units.Jy
    assert np.allclose([[1, 2, 3], [4, 5, 6], [4, 5, 6]], abb.flux.value)

    c = specutils.Spectrum1D(spectral_axis=[1., 2., 3., 4.] * units.AA,
                             flux=[1., 2., 3., 4.] * units.Jy)

    ac = combine_spectra(a, c)
    assert isinstance(ac, specutils.SpectrumList)

    aca = combine_spectra(ac, a)
    assert isinstance(aca, specutils.SpectrumList)
Example #14
0
def test_stellar_mass_from_reference_band():

    from astropy import units
    from skypy.galaxy.spectrum import mag_ab, stellar_mass_from_reference_band

    # Gaussian bandpass
    bp_lam = np.logspace(0, 4, 1000) * units.AA
    bp_mean = 1000 * units.AA
    bp_width = 100 * units.AA
    bp_tx = np.exp(-(
        (bp_lam - bp_mean) / bp_width)**2) * units.dimensionless_unscaled
    band = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)

    # 3 Flat template spectra
    lam = np.logspace(0, 4, 1000) * units.AA
    A = np.array([[2], [3], [4]])
    flam = A * 0.10884806248538730623 * units.Unit('erg s-1 cm-2 AA') / lam**2
    templates = specutils.Spectrum1D(spectral_axis=lam, flux=flam)

    # Absolute magnitudes for each template
    Mt = mag_ab(templates, band)

    # Using the identity matrix for the coefficients yields trivial test cases
    coeff = np.diag(np.ones(3))

    # Using the absolute magnitudes of the templates as reference magnitudes
    # should return one solar mass for each template.
    stellar_mass = stellar_mass_from_reference_band(coeff, templates, Mt, band)
    truth = 1
    np.testing.assert_allclose(stellar_mass, truth)

    # Solution for given magnitudes without template mixing
    Mb = np.array([10, 20, 30])
    stellar_mass = stellar_mass_from_reference_band(coeff, templates, Mb, band)
    truth = np.power(10, -0.4 * (Mb - Mt))
    np.testing.assert_allclose(stellar_mass, truth)
Example #15
0
def combine_spectra(a, b):
    '''combine two spectra'''
    if a is None or b is None:
        return a or b

    if isinstance(a, specutils.SpectrumList) or isinstance(b, specutils.SpectrumList):
        a = a if isinstance(a, specutils.SpectrumList) else specutils.SpectrumList([a])
        b = b if isinstance(b, specutils.SpectrumList) else specutils.SpectrumList([b])
        return specutils.SpectrumList(a + b)

    if (len(a.spectral_axis) == len(b.spectral_axis)
            and np.allclose(a.spectral_axis, b.spectral_axis, atol=0, rtol=1e-10)
            and a.flux.unit.is_equivalent(b.flux.unit)):
        flux_a = np.atleast_2d(a.flux.value)
        flux_b = np.atleast_2d(b.flux.to_value(a.flux.unit))
        if flux_a.shape[1:] == flux_b.shape[1:]:
            return specutils.Spectrum1D(spectral_axis=a.spectral_axis,
                                        flux=np.concatenate([flux_a, flux_b])*a.flux.unit)

    return specutils.SpectrumList([a, b])
Example #16
0
def skypy_data_loader(module, name, *tags):
    '''load data from the skypy data package'''

    # result is spectrum or list of spectra
    spectra = None

    # load each tag separately
    for tag in tags:

        # get resource filename from module, name, and tag
        try:
            filename = resource_filename(f'skypy-data.{module}',
                                         f'{name}_{tag}.ecsv')
        except ModuleNotFoundError as exc:
            message = str("No module named 'skypy-data'. To install:\n"
                          "pip install skypy-data@https://github.com/"
                          "skypyproject/skypy-data/archive/master.tar.gz")
            raise ModuleNotFoundError(message) from exc

        # load the data file
        data = astropy.table.Table.read(filename, format='ascii.ecsv')

        # get the spectral axis
        spectral_axis = data['spectral_axis'].quantity

        # load all templates
        flux_unit = data['flux_0'].unit
        fluxes = []
        while 'flux_%d' % len(fluxes) in data.colnames:
            fluxes.append(data['flux_%d' %
                               len(fluxes)].quantity.to_value(flux_unit))
        fluxes = np.squeeze(fluxes) * flux_unit

        # construct the Spectrum1D
        spectrum = specutils.Spectrum1D(spectral_axis=spectral_axis,
                                        flux=fluxes)

        # combine with existing
        spectra = combine_spectra(spectra, spectrum)

    return spectra
    def test_from_spectrum1d_Empirical1D_source(self):
        import specutils

        lamb = [1000, 5000, 10000] * u.AA
        flux = [0, -0.5e-17, 5.6e-17] * units.FLAM
        spec = specutils.Spectrum1D(spectral_axis=lamb, flux=flux)
        spec.meta['source'] = [1, 2, 3]
        with pytest.warns(AstropyUserWarning,
                          match=r'contained negative flux or throughput'):
            sp = SourceSpectrum.from_spectrum1d(spec, keep_neg=False)

        w = sp.waveset
        y = sp(w, flux_unit=units.FLAM)
        assert isinstance(sp.model, Empirical1D)
        assert sp.meta['header']['source'] == spec.meta['source']
        assert_quantity_allclose(w, lamb)
        assert_quantity_allclose(y, [0, 0, 5.6e-17] * units.FLAM)

        # Ensure metadata is copied, not referenced
        spec.meta['source'][1] = 99
        assert sp.meta['header']['source'] == [1, 2, 3]
        sp.meta['header']['source'][0] = 100
        assert spec.meta['source'] == [1, 99, 3]
Example #18
0
def measure_EW_simple(waves,
                      fluxes,
                      unc,
                      line,
                      wave_range,
                      feat_type,
                      line_width=[0., 0.],
                      plot=False,
                      file=None,
                      verbose=False,
                      name='Unknown Line',
                      diag_path=None):

    feat_type = feat_type.lower()

    #check to see if there's flux
    if np.all(np.abs(fluxes) <= 2 * unc):
        print('Warning! No flux in region for {}!'.format(name))

        res = 'No Flux'

        return res, res

    feature_waves = waves * u.AA

    feature_flux = fluxes * u.erg / (u.AA * u.s * (u.cm)**2)

    uncertainties = unc

    feature_unc = astropy.nddata.StdDevUncertainty(unc * u.erg / (u.AA * u.s *
                                                                  (u.cm)**2))

    feature_spec = specutils.Spectrum1D(spectral_axis=feature_waves,
                                        flux=feature_flux,
                                        uncertainty=feature_unc)

    continuum_fit = specutils.fitting.fit_generic_continuum(feature_spec)(
        feature_spec.spectral_axis)

    #looping to refine the continuum fit

    #initial mask around the feature
    mask = np.ones(len(feature_flux), dtype='bool')
    mask[(feature_waves.value > line_width[0])
         & (feature_waves.value < line_width[1])] = False

    subtr_spec = feature_spec - continuum_fit

    for i in range(5):

        masked_spec = specutils.Spectrum1D(spectral_axis=feature_waves[mask],
                                           flux=feature_flux[mask],
                                           uncertainty=feature_unc[mask])

        continuum_model = specutils.fitting.fit_generic_continuum(masked_spec)
        continuum_fit = continuum_model(feature_spec.spectral_axis)

        subtr_spec = feature_spec - continuum_fit

        mask = np.abs(subtr_spec.flux.value) < 3 * uncertainties

        if verbose:
            plt.plot(feature_waves, continuum_fit)
            plt.plot(feature_waves, feature_spec.flux)
            plt.title('refine {}'.format(i))
            plt.show()

    continuum_fit = continuum_model(feature_spec.spectral_axis)

    subtr_spec = feature_spec - continuum_fit

    if plot or (diag_path is not None):

        plt.figure(figsize=[12, 7])

        plt.plot(feature_spec.wavelength, feature_spec.flux)
        plt.plot(feature_spec.wavelength, continuum_fit)

        #plt.xlabel('Wavelength')
        #plt.ylabel('Flux Density')

        plt.title('Continuum fit of {}'.format(name))

        if isinstance(file, str):

            plt.savefig('kastclassify_EW_continuum_' + file)

        if diag_path is not None:

            plt.savefig(diag_path + '{}_EW_continuum_fit.png'.format(name))

        if plot:

            plt.show()

        plt.close()

    #finding line center

    near_line_waves = feature_waves[(feature_waves.value >= (line - 10))
                                    & (feature_waves.value <= (line + 10))]
    near_line_fluxes = subtr_spec.flux.value[
        (feature_waves.value >= (line - 10))
        & (feature_waves.value <= (line + 10))]

    if feat_type == 'absorption':

        line = near_line_waves.value[near_line_fluxes == np.amin(
            near_line_fluxes)]

    elif feat_type == 'emission':

        line == near_line_waves.value[near_line_fluxes == np.amax(
            near_line_fluxes)]

    else:
        print('WARNING! Feature type {} is unknown'.format(feat_type))

        res = 'Unknown Feature Type'

        return res, res

    #create continuum normalized spectrum and continuum subtracted spectrum
    norm_spec = feature_spec / continuum_fit

    #re-centering using subtracted spectrum

    #find all features in this spectrum
    line_info = specutils.fitting.find_lines_threshold(subtr_spec)

    if len(line_info) == 0:
        print('Warning! No features detected for {}!'.format(name))

        res = 'No Feature Detected'

        return res, res

    try:
        #the actual line center is the closest feature to our expected center
        nearest = np.argmin(
            np.abs(line_info[line_info['line_type'] == feat_type]
                   ['line_center'].value - line))

    except:
        print('Warning! No features detected for {}!'.format(name))

        res = 'No Feature Detected'

        return res, res

    line_center = line_info[line_info['line_type'] ==
                            feat_type][nearest]['line_center'].value

    #if the line width is not defined, calculate it
    #calculated as 1.5 * FWHM
    if line_width[0] == 0.:

        near_line_waves = feature_waves[(feature_waves.value >= (line - 15))
                                        & (feature_waves.value <=
                                           (line + 15))].value
        near_line_fluxes = subtr_spec.flux.value[
            (feature_waves.value >= (line - 15))
            & (feature_waves.value <= (line + 15))]

        if feat_type == 'absorption':

            near_line_fluxes = np.abs(near_line_fluxes)

        elif feat_type == 'emission':

            pass

        else:
            print('WARNING! Feature type {} is unknown'.format(feat_type))

            res = 'Unknown Feature Type'

            return res, res

        max_flx = np.amax(near_line_fluxes)

        half_max = max_flx / 2

        outside = near_line_fluxes < half_max

        try:
            lower_bound = max(near_line_waves[(near_line_waves < line_center)
                                              & outside])
            upper_bound = min(near_line_waves[(near_line_waves > line_center)
                                              & outside])
        except:
            print('Warning! No features detected for {}!'.format(name))

            res = 'No Feature Detected'

            return res, res

        FWHM = upper_bound - lower_bound

        line_width[0] = 1.5 * FWHM
        line_width[1] = 1.5 * FWHM

    #pick out the region containing the feature
    region = specutils.SpectralRegion((line_center - line_width[0]) * u.AA,
                                      (line_center + line_width[1]) * u.AA)

    #calculate the width
    EW = specutils.analysis.equivalent_width(norm_spec, regions=region)

    if plot or (diag_path is not None):

        fig, ax = plt.subplots(1, figsize=[12, 7])

        ax.plot(norm_spec.wavelength, norm_spec.flux, label=EW)

        ax.axvline(line_center - line_width[0])
        ax.axvline(line_center + line_width[1])

        rect = matplotlib.patches.Rectangle((line_center - EW.value / 2, 0),
                                            EW.value,
                                            1,
                                            hatch='x',
                                            fill=False)

        ax.add_patch(rect)

        ax.set_xlabel('Wavelength ({})'.format(u.AA))
        ax.set_ylabel('Normalized Flux Density')

        ax.set_title('Equivalent Width of {}'.format(name))

        fig.legend()

        if isinstance(file, str):

            fig.savefig('kastclassify_EW_width_' + file)

        if diag_path is not None:

            fig.savefig(diag_path + '{}_EW_measurement.png'.format(name))

        if plot:

            fig.show()

        plt.close(fig)

    return EW, line_center
Example #19
0
def sp_correction(nuclear_spectrum, external_spectrum):
    """Stellar Population substraction.

    The spectral continuum of Type 2 Seyfert galaxies in the K band
    (19.-2.5 $mu$m) is composed by the stellar population component and the
    hot dust component. The first one is the sum of the Planck functions of
    all the stars in the host galaxy and can be represented by a spectrum
    extracted at a prudential distance from the nucleus, where the emission
    is expected to be dominated by the stellar population. In sp_correction
    this is introduced in the parameter "external spectrum". The stellar
    population dominated spectrum must be substracted from the nuclear
    spectrum in order to obtain the hot dust component in the nuclear
    spectrum. The excess obtained from the substraction is expected to have
    blackbody-shape.

    The operations applied to prepare the nuclear spectrum for fitting are:

    1) normalization using the mean value of the flux for both spectra
    2) substraction of the external spectrum flux from the nuclear spectrum
       flux.

    Parameters
    ----------
    nuclear_spectrum: NirdustSpectrum object
        Instance of NirdusSpectrum containing the nuclear spectrum.

    external_spectrum: NirdustSpectrum object
        Instance of NirdusSpectrum containing the external spectrum.

    Returns
    -------
    out: NirsdustSpectrum object
        Returns a new instance of the class NirdustSpectrum containing the
        nuclear spectrum ready for blackbody fitting.
    """
    normalized_nuc = nuclear_spectrum.normalize()
    normalized_ext = external_spectrum.normalize()

    dif = len(normalized_nuc.spec1d.spectral_axis) - len(
        normalized_ext.spec1d.spectral_axis)

    if dif == 0:

        flux_resta = (normalized_nuc.spec1d.flux -
                      normalized_ext.spec1d.flux) + 1

        new_spectral_axis = nuclear_spectrum.spectral_axis

    elif dif < 0:

        new_ext = normalized_ext[-dif:]
        flux_resta = (normalized_nuc.spec1d.flux - new_ext.spec1d.flux) + 1

        new_spectral_axis = external_spectrum.spectral_axis[-dif:]

    elif dif > 0:

        new_nuc = normalized_nuc[dif:]
        flux_resta = (new_nuc.spec1d.flux - normalized_ext.spec1d.flux) + 1
        new_spectral_axis = nuclear_spectrum.spectral_axis[dif:]

    substracted_1d_spectrum = su.Spectrum1D(flux_resta, new_spectral_axis)

    new_freq_axis = substracted_1d_spectrum.spectral_axis.to(u.Hz)

    kwargs = attr.asdict(normalized_nuc)
    kwargs.update(spec1d=substracted_1d_spectrum, frequency_axis=new_freq_axis)

    return NirdustSpectrum(**kwargs)
Example #20
0
def spectrum(
    flux,
    header,
    z=0,
    dispersion_key="CD1_1",
    first_wavelength="CRVAL1",
    dispersion_type="CTYPE1",
    **kwargs,
):
    """Instantiate a NirdustSpectrum object from FITS parameters.

    Parameters
    ----------
    flux: Quantity
        Intensity for each pixel in arbitrary units.

    header: FITS header
        Header of the spectrum.

    z: float
    Redshif of the galaxy.

    dispersion_key: str
        Header keyword that gives dispersion in Å/pix. Default is 'CD1_1'

    first_wavelength: str
        Header keyword that contains the wavelength of the first pixel. Default
        is ``CRVAL1``.

    dispersion_type: str
        Header keyword that contains the dispersion function type. Default is
        ``CTYPE1``.

    Return
    ------
    spectrum: ``NirsdustSpectrum``
        Return a instance of the class NirdustSpectrum with the entered
        parameters.
    """
    if header[dispersion_key] <= 0:
        raise ValueError("dispersion must be positive")

    spectrum_length = len(flux)
    spectral_axis = ((header[first_wavelength] +
                      header[dispersion_key] * np.arange(0, spectrum_length)) /
                     (1 + z) * u.AA)
    spec1d = su.Spectrum1D(flux=flux * u.adu,
                           spectral_axis=spectral_axis,
                           **kwargs)
    frequency_axis = spec1d.spectral_axis.to(u.Hz)

    return NirdustSpectrum(
        header=header,
        z=z,
        spectrum_length=spectrum_length,
        dispersion_key=dispersion_key,
        first_wavelength=first_wavelength,
        dispersion_type=dispersion_type,
        spec1d=spec1d,
        frequency_axis=frequency_axis,
    )