Exemple #1
0
def poly_sub(cfg_par, x, y, deg):
    '''
        Continuum subtraction on spectrum through polynomial fitting    
        
        INPUT:
            parameter file
            x-axis of the spectrum  
            y-axis of the spectrum
            degre of polynomial to fit
        OUTPUT:
            continuum subtracted y-axis of spectrum 
        '''

    if cfg_par['abs_ex'].get('zunit') == 'm/s':
        unit_z = u.m / u.s
    else:
        unit_z = u.Hz

    step = (x[-1] - x[0]) / len(x)
    wave_for_spec = WaveCoord(cdelt=step, crval=x[0], cunit=unit_z)
    spe = Spectrum(wave=wave_for_spec, data=y)
    cont = spe.poly_spec(deg)

    cont_sub = y - cont.data

    return cont_sub
Exemple #2
0
def test_spectrum_methods(spec_var, spec_novar):
    """Spectrum class: testing sum/mean/abs/sqrt methods"""
    wave = WaveCoord(crpix=2.0, cdelt=3.0, crval=0.5, cunit=u.nm, shape=10)
    spectrum1 = Spectrum(data=np.array([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
                         wave=wave)
    sum1 = spectrum1.sum()
    assert_almost_equal(sum1[0], spectrum1.data.sum())
    spectrum2 = spectrum1[1:-2]
    sum1 = spectrum1.sum(lmin=spectrum1.wave.coord(1),
                         lmax=spectrum1.wave.coord(10 - 3),
                         unit=u.nm)
    sum2 = spectrum2.sum()
    assert_almost_equal(sum1, sum2)
    mean1 = spectrum1.mean(lmin=spectrum1.wave.coord(1),
                           lmax=spectrum1.wave.coord(10 - 3),
                           unit=u.nm)
    mean2 = spectrum2.mean()
    assert_almost_equal(mean1, mean2)

    spvar2 = spec_var.abs()
    assert spvar2[23] == np.abs(spec_var[23])
    spvar2 = spec_var.abs().sqrt()
    assert spvar2[8] == np.sqrt(np.abs(spec_var[8]))
    assert_almost_equal(spec_var.mean()[0], 11.526, 2)
    assert_almost_equal(spec_novar.mean()[0], 11.101, 2)
    spvarsum = spvar2 + 4 * spvar2 - 56 / spvar2

    assert_almost_equal(spvarsum[10],
                        spvar2[10] + 4 * spvar2[10] - 56 / spvar2[10], 2)
    assert_almost_equal(spec_var.get_step(), 0.630, 2)
    assert_almost_equal(spec_var.get_start(), 4602.604, 2)
    assert_almost_equal(spec_var.get_end(), 7184.289, 2)
    assert_almost_equal(spec_var.get_range()[0], 4602.604, 2)
    assert_almost_equal(spec_var.get_range()[1], 7184.289, 2)
Exemple #3
0
def test_rebin(spec_var, spec_novar):
    """Spectrum class: testing rebin function"""
    wave = WaveCoord(crpix=2.0, cdelt=3.0, crval=0.5, shape=10)
    spectrum1 = Spectrum(data=np.array([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9]) * 2.3,
                         wave=wave)
    unit = spectrum1.wave.unit
    factor = 3
    s = slice(0, factor * (spectrum1.shape[0] // factor))  # The rebinned slice
    flux1 = spectrum1[s].sum()[0] * spectrum1[s].wave.get_step(unit=unit)
    spectrum2 = spectrum1.rebin(factor, margin='left')
    flux2 = spectrum2.sum()[0] * spectrum2.wave.get_step(unit=unit)
    assert_almost_equal(flux1, flux2, 2)

    unit = spec_novar.wave.unit
    factor = 4
    s = slice(0, factor * (spec_novar.shape[0] // factor))
    flux1 = spec_novar[s].sum()[0] * spec_novar[s].wave.get_step(unit=unit)
    spnovar2 = spec_novar.rebin(factor, margin='left')
    flux2 = spnovar2.sum()[0] * spnovar2.wave.get_step(unit=unit)
    assert_almost_equal(flux1, flux2, 2)

    unit = spec_var.wave.unit
    factor = 4
    s = slice(0, factor * (spec_var.shape[0] // factor))
    flux1 = spec_var[s].sum(weight=False)[0] * \
        spec_var[s].wave.get_step(unit=unit)
    spvar2 = spec_var.rebin(factor, margin='left')
    flux2 = spvar2.sum(weight=False)[0] * spvar2.wave.get_step(unit=unit)
    assert_almost_equal(flux1, flux2, 2)
Exemple #4
0
def test_resample2():
    """Spectrum class: testing resampling function
    with a spectrum of integers and resampling to a smaller pixel size"""
    wave = WaveCoord(crpix=2.0, cdelt=3.0, crval=0.5, cunit=u.nm)
    spectrum1 = Spectrum(data=np.array([0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]),
                         wave=wave)
    flux1 = spectrum1.sum()[0] * spectrum1.wave.get_step()
    spectrum2 = spectrum1.resample(0.3)
    flux2 = spectrum2.sum()[0] * spectrum2.wave.get_step()
    assert_almost_equal(flux1, flux2, 2)
Exemple #5
0
def residual(p,
             datacube=datacube,
             pos=None,
             specwidth=spectralpixel,
             galcen=galcen,
             galPA=galPA):
    par = p.valuesdict()
    incli = par['incli']
    col_denst = par['col_dens']
    h = par['height']
    bes = par['dop_param']
    v_max = par['vel_max']
    h_vt = par['h_v']

    csize = par['csize']
    r_0t = par['r_0']

    print(par)
    h_v = 10**h_vt
    col_dens = 10**col_denst
    r_0 = 10**r_0t
    coord_sky = datacube.wcs.pix2sky([int(pos[0]), int(pos[1])], unit=u.deg)
    dec = coord_sky[0][0]
    ra = coord_sky[0][1]
    c1 = SkyCoord(ra * u.degree, dec * u.degree, frame='icrs')

    flux = datacube[:, int(pos[0]), int(pos[1])]
    abso = flux.data[specwidth[0]:specwidth[1] + 1]
    sigma = np.sqrt(flux.var[specwidth[0]:specwidth[1] + 1])

    scale = 7.28  # z=0.73379  # plat scale (kpc/") for Planck
    c1 = SkyCoord(ra * u.degree, dec * u.degree, frame='icrs')
    #D = scale * galcen.separation(c1).arcsec
    #pa = galcen.position_angle(c1).to(u.deg)
    #alpha = galPA - pa.value

    alpha = csu.get_alpha(c1, galcen, galPA)
    D = csu.get_impactparam(c1, galcen, scale)
    lam2 = np.arange(4825.12, 4886.37 + 1.5, 0.1)
    wave1 = WaveCoord(cdelt=0.1, crval=4825.12, cunit=u.angstrom)

    model = Disco(h, incli, Rcore=0.1)
    spec = model.averagelos(D, alpha, lam2, 100, 12, z, csize, col_dens, bes,
                            r_0, v_max, h_v, 0)
    spe = Spectrum(wave=wave1, data=spec)
    rspe = spe.resample(1.25)
    fluxmodel = rspe.data
    absomodel = fluxmodel[specwidth[0]:specwidth[1] + 1]

    #ymodelt = np.concatenate((ymodel[0][14:36],ymodel[1][16:36],ymodel[2][16:36]))
    rest = ((abso - absomodel) / sigma)**2
    dif = abso - absomodel
    return (fluxmodel, rest, datacube[:, int(pos[0]),
                                      int(pos[1])].data, sigma, dif)
Exemple #6
0
    def __init__(self, source=None, **kwargs) :
        """Initialisation of the opening of spectra
        """
        self.verbose = kwargs.pop('verbose', False)
        # Arguments for the plots
        self.title = kwargs.pop('title', "Spectrum")
        self.add_sky_lines = kwargs.pop("add_sky_lines", False)
        if self.add_sky_lines :
            self.color_sky = kwargs.pop("color_sky", "red")
            self.linestyle_sky = kwargs.pop("linestyle_sky", "--")
            self.alpha_sky = kwargs.pop("alpha_sky", 0.3)

        if source is not None:
            self.__dict__.update(source.__dict__)
        else :
            Spectrum.__init__(self, **kwargs)
Exemple #7
0
def load_spectra(filename):
    spectra = OrderedDict()
    with fits.open(filename) as hdul:
        for i in range(1, len(hdul), 2):
            spec_id = int(hdul[i].name[4:])
            spectra[spec_id] = Spectrum(hdulist=hdul, ext=(i, i + 1))
    return spectra
Exemple #8
0
def test_get_Spectrum(spec_var):
    """Spectrum class: testing getters"""
    wave = WaveCoord(crpix=2.0, cdelt=3.0, crval=0.5, cunit=u.nm)
    spectrum1 = Spectrum(data=np.array([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9]) * 2.3,
                         wave=wave)
    a = spectrum1[1:7]
    assert a.shape[0] == 6
    a = spectrum1.subspec(1.2, 15.6, unit=u.nm)
    assert a.shape[0] == 6

    unit = spec_var.wave.unit
    spvarcut = spec_var.subspec(5560, 5590, unit=unit)
    assert spvarcut.shape[0] == 48
    assert_almost_equal(spvarcut.get_start(unit=unit), 5560.25, 2)
    assert_almost_equal(spvarcut.get_end(unit=unit), 5589.89, 2)
    assert_almost_equal(spvarcut.get_step(unit=unit), 0.63, 2)
Exemple #9
0
def get_sky_spectrum(filename) :
    """Read sky spectrum from MUSE data reduction
    """
    sky = pyfits.getdata(filename)
    crval = sky['lambda'][0]
    cdelt = sky['lambda'][1] - crval
    wavein = WaveCoord(cdelt=cdelt, crval=crval, cunit= units.angstrom)
    spec = Spectrum(wave=wavein, data=sky['data'], var=sky['stat'])
    return spec
Exemple #10
0
    def getsp(self):
        """
        Get estimated spectra as a dict (with the HST ids as keys) of mpdaf Spectra
        """
        cat = {}
        for k, key in enumerate(self.listHST_ID):
            cat[key] = Spectrum(data=self.sources[k],
                                var=self.varSources[k],
                                wave=self.src.spectra['MUSE_TOT'].wave)

        return cat
Exemple #11
0
def test_arithmetric():
    """Spectrum class: testing arithmetic functions"""
    wave = WaveCoord(crpix=2.0, cdelt=3.0, crval=0.5, cunit=u.nm)
    spectrum1 = Spectrum(data=np.array([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
                         wave=wave)
    spectrum2 = spectrum1 > 6  # [-,-,-,-,-,-,-,7,8,9]
    # +
    spectrum3 = spectrum1 + spectrum2
    assert spectrum3.data.data[3] == 3
    assert spectrum3.data.data[8] == 16
    spectrum3 = 4.2 + spectrum1
    assert spectrum3.data.data[3] == 3 + 4.2
    # -
    spectrum3 = spectrum1 - spectrum2
    assert spectrum3.data.data[3] == 3
    assert spectrum3.data.data[8] == 0
    spectrum3 = spectrum1 - 4.2
    assert spectrum3.data.data[8] == 8 - 4.2
    # *
    spectrum3 = spectrum1 * spectrum2
    assert spectrum3.data.data[8] == 64
    spectrum3 = 4.2 * spectrum1
    assert spectrum3.data.data[9] == 9 * 4.2
    # /
    spectrum3 = spectrum1 / spectrum2
    # divide functions that have a validity domain returns the masked constant
    # whenever the input is masked or falls outside the validity domain.
    assert spectrum3.data.data[8] == 1
    spectrum3 = 1.0 / (4.2 / spectrum1)
    assert spectrum3.data.data[5] == 5 / 4.2

    # with cube
    wcs = WCS()
    cube1 = Cube(data=np.ones(shape=(10, 6, 5)), wave=wave, wcs=wcs)
    cube2 = spectrum1 + cube1
    sp1data = spectrum1.data[:, np.newaxis, np.newaxis]
    assert_array_almost_equal(cube2.data, sp1data + cube1.data)

    cube2 = spectrum1 - cube1
    assert_array_almost_equal(cube2.data, sp1data - cube1.data)

    cube2 = spectrum1 * cube1
    assert_array_almost_equal(cube2.data, sp1data * cube1.data)

    cube2 = spectrum1 / cube1
    assert_array_almost_equal(cube2.data, sp1data / cube1.data)

    # spectrum * image
    data = np.ones(shape=(6, 5)) * 2
    image1 = Image(data=data, wcs=wcs)
    cube2 = spectrum1 * image1
    assert_array_almost_equal(cube2.data,
                              sp1data * image1.data[np.newaxis, :, :])
Exemple #12
0
def get_sky_spectrum(specname):
    """Read sky spectrum from MUSE data reduction
    """
    if not os.path.isfile(specname):
        upipe.print_error("{0} not found".format(specname))
        return None

    sky = pyfits.getdata(specname)
    crval = sky['lambda'][0]
    cdelt = sky['lambda'][1] - crval
    wavein = WaveCoord(cdelt=cdelt, crval=crval, cunit=u.angstrom)
    spec = Spectrum(wave=wavein, data=sky['data'], var=sky['stat'])
    return spec
Exemple #13
0
    def run(self, orig, grid_dxy=0, spectrum_size_fwhm=6):
        self.Cat2, line_est, line_var = estimation_line(
            orig.Cat1,
            orig.cube_raw,
            orig.var,
            orig.PSF,
            orig.wfields,
            orig.wcs,
            orig.wave,
            size_grid=grid_dxy,
            criteria='flux',
            order_dct=30,
            horiz_psf=1,
            horiz=5,
        )
        _format_cat(self.Cat2)

        self._loginfo('Save the updated catalog in self.Cat2 (%d lines)',
                      len(self.Cat2))

        # Radius for spectrum trimming
        radius = np.ceil(np.array(orig.FWHM_profiles) * spectrum_size_fwhm / 2)
        radius = radius.astype(int)

        self.spectra = OrderedDict()
        for row, data, vari in zip(self.Cat2, line_est, line_var):
            profile, z, num_line = row['profile', 'z', 'num_line']
            z_min = z - radius[profile]
            z_max = z + radius[profile]
            if len(data) > 1:  # RB test for bug in GridAnalysis
                sp = Spectrum(data=data,
                              var=vari,
                              wave=orig.wave,
                              mask=np.ma.nomask,
                              copy=False)
                self.spectra[num_line] = sp.subspec(z_min, z_max, unit=None)

        self._loginfo('Save estimated spectrum of each line in self.spectra')
Exemple #14
0
    def to_mpdaf(self, row=1, scale=True):
        """
        Creates a mpdaf.obj.Spectrum object from FADO 1D files.

        The spectrum can be specified as a row or as a name.
        Allowed names are the following

        1: 'Observed'         spectrum de-redshifted and rebinned'
        2: 'Error'
        3: 'Mask'
        4: 'Best'
        5: 'Average'            of individual solutions
        6: 'Median'
        7: 'Stdev'
        8: 'Stellar'            using best fit'
        9: 'Nebular'            using best fit'
        10: 'AGN'               using best fit'
        11: 'M/L'
        12: 'LSF'  Line spread function

        The best-fits for individual solution can only be specified as a number 13-XX
        see self.max_rows

        Parameters
        ----------
        row: str, int
            Allowed names: 'observed', 'error', 'mask', 'best', 'average', 'median', 'stdev', 'stellar', 'nebular'
                'agn', 'm/l', 'lsf'
            The row number where the spectra is extracted, default=1 (0 in python notation)

        scale: bool, whether to scale the spectra or not, default True

        Returns
        -------
        a mpdaf.obj.Spectrum object
        """
        try:
            from mpdaf.obj import Spectrum, WaveCoord
        except ImportError as e:
            print(e, "MPDAF not installed, cannot continue")
            raise
        sp = self.spectrum(row, scale)
        wave_coord = WaveCoord(cdelt=self.header["CDELT1"],
                               crval=self.header["CRVAL1"],
                               cunit=self.fado_load.wave_unit)

        sp_mpdaf = Spectrum(wave=wave_coord, data=sp.flux)

        return sp_mpdaf
Exemple #15
0
 def read(self):
     """Read sky continuum spectrum from MUSE data reduction
     """
     if not os.path.isfile(self.filename):
         upipe.print_error("{0} not found".format(self.filename))
         crval = 0.0
         data = np.zeros(0)
         cdelt = 1.0
     else:
         sky = pyfits.getdata(self.filename)
         crval = sky['lambda'][0]
         cdelt = sky['lambda'][1] - crval
         data = sky['flux']
     wavein = WaveCoord(cdelt=cdelt, crval=crval, cunit=u.angstrom)
     self.spec = Spectrum(wave=wavein, data=data)
Exemple #16
0
def test_mag():
    """Spectrum class: testing magnitude computations."""
    Vega = Spectrum(get_data_file('obj', 'Vega.fits'))
    Vega.unit = u.Unit('2E-17 erg / (Angstrom cm2 s)')
    Vega.wave.wcs.wcs.cunit[0] = u.angstrom
    assert_almost_equal(Vega.abmag_filter_name('V')[0], 0, 1)
    mag = Vega.abmag_filter_name('Ic')[0]
    assert mag > 0.4 and mag < 0.5
    mag = Vega.abmag_band(22500, 2500)[0]
    assert mag > 1.9 and mag < 2.0
Exemple #17
0
def test_write(tmpdir):
    """Spectrum class: testing write."""
    testfile = str(tmpdir.join('spec.fits'))
    sp = Spectrum(data=np.arange(10), wave=WaveCoord(cunit=u.nm))
    sp.write(testfile)

    with fits.open(testfile) as hdu:
        assert_array_equal(hdu[1].data.shape, sp.shape)

    hdr = hdu[1].header
    assert hdr['EXTNAME'] == 'DATA'
    assert hdr['NAXIS'] == 1
    assert u.Unit(hdr['CUNIT1']) == u.nm
    assert hdr['NAXIS1'] == sp.shape[0]

    # Same with Angstrom
    sp = Spectrum(data=np.arange(10), wave=WaveCoord(cunit=u.angstrom))
    sp.write(testfile)

    with fits.open(testfile) as hdu:
        assert u.Unit(hdu[1].header['CUNIT1']) == u.angstrom
Exemple #18
0
def test_gauss_fit(capsys, cont):
    """Spectrum class: testing Gaussian fit"""
    contval = cont or 0
    wave = WaveCoord(crpix=1, cdelt=0.3, crval=400, cunit=u.nm)
    spem = Spectrum(data=np.zeros(600) + contval, wave=wave)
    spem.add_gaussian(5000, 1200, 20, unit=u.angstrom)

    setup_logging()
    gauss = spem.gauss_fit(lmin=(4500, 4800),
                           lmax=(5200, 6000),
                           lpeak=5000,
                           cont=cont,
                           unit=u.angstrom)
    gauss.print_param()
    out, err = capsys.readouterr()
    assert '[INFO] Gaussian center = 5000 ' in err

    assert_almost_equal(gauss.lpeak, 5000, 2)
    assert_almost_equal(gauss.flux, 1200, 2)
    assert_almost_equal(gauss.fwhm, 20, 2)
    assert_allclose(spem.fwhm(gauss.lpeak, cont=contval), 20, atol=0.2)
Exemple #19
0
            ra = coord_sky[0][1]
            scale = 7.28  # z=0.73379  # plat scale (kpc/") for Planck
            c1 = SkyCoord(ra * u.degree, dec * u.degree, frame='icrs')
            alpha = csu.get_alpha(c1, galcen, galPA)
            D = csu.get_impactparam(c1, galcen, scale)

            flux = datacube[:, i, j]
            abso = flux.data[specwidth[0]:specwidth[1] + 1]
            sigma = np.sqrt(flux.var[specwidth[0]:specwidth[1] + 1])
            lam2 = np.arange(4825.12, 4886.37 + 1.5, 0.1)
            wave1 = WaveCoord(cdelt=0.1, crval=4825.12, cunit=u.angstrom)

            model = Disco(h, incli, Rcore=0.1)
            spec = model.averagelos(D, alpha, lam2, 100, 12, z, csize,
                                    col_dens, bes, r_0, v_max, h_v, 0)
            spe = Spectrum(wave=wave1, data=spec)
            rspe = spe.resample(1.25)
            fluxmodel = rspe.data
            absomodel = fluxmodel[specwidth[0]:specwidth[1] + 1]

            #ymodelt = np.concatenate((ymodel[0][14:36],ymodel[1][16:36],ymodel[2][16:36]))
            dif = np.sum(((abso - absomodel) / sigma)**2)
            ima.data[i, j] = dif
            ima.mask[i, j] = False

        else:
            ima.data[i, j] = 0
            ima.mask[i, j] = True

ima.plot(colorbar='v')
plt.show()
Exemple #20
0
def spec_var():
    return Spectrum(get_data_file('obj', 'Spectrum_Variance.fits'), ext=[0, 1])
Exemple #21
0
def spec_novar():
    return Spectrum(get_data_file('obj', 'Spectrum_Novariance.fits'))
Exemple #22
0
    def __init__(self):
        self.img = None
        self.cube = None
        self.spec = None
        if os.path.exists(SKYREF):
            self.sky = Spectrum(SKYREF)
            self.sky.data /= self.sky.data.max()
        else:
            print('Sky file missing')
            self.sky = None

        pg.mkQApp()

        self.win = win = QtGui.QWidget()
        win.setWindowTitle('MUSE Cube Viewer')
        # layout = QtGui.QGridLayout()
        layout = QtGui.QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        win.setLayout(layout)

        self.splitter = QtGui.QSplitter()
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        layout.addWidget(self.splitter)

        self.tree = ParameterTree(showHeader=False)
        self.splitter.addWidget(self.tree)
        self.params = Parameter.create(name='params',
                                       type='group',
                                       children=PARAMS)
        self.tree.setParameters(self.params, showTop=False)
        self.tree.setWindowTitle('pyqtgraph example: Parameter Tree')

        self.connect(('Median filter', ), self.update_spec_plot)
        self.connect(('Sky', ), self.update_spec_plot)
        self.connect(('Spectrum', 'Lambda Max'), self.show_image)
        self.connect(('Spectrum', 'Lambda Min'), self.show_image)
        self.connect(('Spectrum', 'Line color'), self.update_spec_plot)
        self.connect(('Spectrum', 'Selection color'), self.update_spec_plot)
        self.connect(('Spectrum', 'Show Zoom'), self.add_zoom_window)

        self.win_inner = win = pg.GraphicsLayoutWidget()
        self.splitter2 = QtGui.QSplitter()
        self.splitter2.setOrientation(QtCore.Qt.Vertical)
        self.splitter.addWidget(self.win_inner)

        # self.img_label = win.addLabel('Hello !', justify='right')

        # A plot area (ViewBox + axes) for displaying the  white-light image
        win.nextRow()
        self.white_plot = win.addPlot(title='White-light Image')
        self.white_plot.setAspectLocked(lock=True, ratio=1)
        self.white_item = pg.ImageItem()
        self.white_plot.addItem(self.white_item)

        # A plot area (ViewBox + axes) for displaying the image
        win.nextColumn()
        self.img_plot = win.addPlot(title='Band Image')
        self.img_plot.setAspectLocked(lock=True, ratio=1)
        self.img_item = pg.ImageItem()
        self.img_plot.addItem(self.img_item)

        # pg.SignalProxy(self.img_plot.scene().sigMouseMoved, rateLimit=60,
        #                slot=self.on_mouse_moved)

        # Contrast/color control
        self.hist = hist = pg.HistogramLUTItem()
        hist.setImageItem(self.img_item)
        win.addItem(hist)

        # self.specplot = win.addPlot(row=2, col=0, colspan=2)
        win.nextRow()
        self.specplot = win.addPlot(title='Spectrum', colspan=3)
        self.zoomplot = None
        self.zoomplot_visible = False

        # self.lbdareg = region = pg.LinearRegionItem(movable=False)
        # self.specplot.addItem(region)
        # region.setZValue(10)
        self.zoomreg = region = pg.LinearRegionItem()
        region.setZValue(10)
        self.specplot.addItem(self.zoomreg, ignoreBounds=True)
        region.sigRegionChanged.connect(self.update_zoom_spec_from_region)

        p = self.params
        lmin = p['Spectrum', 'Lambda Min']
        lmax = p['Spectrum', 'Lambda Max']
        region.setRegion([lmin, lmax])

        self.win.resize(1000, 800)
        self.win.show()
Exemple #23
0
def test_integrate():
    """Spectrum class: testing integration"""
    wave = WaveCoord(crpix=2.0, cdelt=3.0, crval=0.5, cunit=u.nm)
    spectrum1 = Spectrum(data=np.array([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
                         wave=wave,
                         unit=u.Unit('ct/Angstrom'))

    # Integrate the whole spectrum, by not specifying starting or ending
    # wavelengths. This should be the sum of the pixel values multiplied
    # by cdelt in angstroms (because the flux units are per angstrom).
    result, err = spectrum1.integrate()
    expected = spectrum1.get_step(unit=u.angstrom) * spectrum1.sum()[0]
    assert_almost_equal(result.value, expected)
    assert result.unit == u.ct
    assert np.isinf(err)

    # The result should not change if we change the wavelength units of
    # the wavelength limits to nanometers.
    result = spectrum1.integrate(unit=u.nm)[0]
    expected = spectrum1.get_step(unit=u.angstrom) * spectrum1.sum()[0]
    assert_almost_equal(result.value, expected)
    assert result.unit == u.ct

    # new spectrum with variance
    spectrum1 = Spectrum(data=np.array([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
                         var=np.ones(10),
                         wave=wave,
                         unit=u.Unit('ct/Angstrom'))

    # Integrate over a wavelength range 3.5 to 6.5 nm. The WCS
    # conversion equation from wavelength to pixel index is,
    #
    #  index = crpix-1 + (lambda-crval)/cdelt
    #  index = 1 + (lambda - 0.5) / 3.0
    #
    # So wavelengths 3.5 and 6.5nm, correspond to pixel indexes
    # of 2.0 and 3.0. These are the centers of pixels 2 and 3.
    # Thus the integration should be the value of pixel 2 times
    # half of cdelt, plus the value of pixel 3 times half of cdelt.
    # This comes to 2*3.0/2 + 3*3.0/2 = 7.5 ct/Angstrom*nm, which
    # should be rescaled to 75 ct, since nm/Angstrom is 10.0.
    result, err = spectrum1.integrate(lmin=3.5, lmax=6.5, unit=u.nm)
    assert_almost_equal(result.value, 75)
    assert result.unit == u.ct

    datasum, var = spectrum1.sum(lmin=3.5, lmax=6.5, unit=u.nm)
    assert_almost_equal(result.value, datasum * 15)
    assert_almost_equal(err.value, var * 15)

    # Do the same test, but specify the wavelength limits in angstroms.
    # The result should be the same as before.
    result = spectrum1.integrate(lmin=35.0, lmax=65.0, unit=u.angstrom)[0]
    assert_almost_equal(result.value, 75)
    assert result.unit == u.ct

    assert_almost_equal(result.value, datasum * 15)
    assert_almost_equal(err.value, var * 15)

    # Do the same experiment yet again, but this time after changing
    # the flux units of the spectrum to simple counts, without any per
    # wavelength units. Since there are no wavelength units in the
    # flux units, the result should not be rescaled from the native
    # value of 7.5, and because we specified a wavelength range in
    # angstroms, the resulting units should be counts * nm.
    spectrum1.unit = u.ct
    result = spectrum1.integrate(lmin=3.5, lmax=6.5, unit=u.nm)[0]
    assert_almost_equal(result.value, 7.5)
    assert result.unit == u.ct * u.nm
Exemple #24
0
wavep = 4855

for i in range(datacube.shape[1]):
    for j in range(datacube.shape[2]):
        spe = datacube[:, i, j]
        var = spe.var
        sigma = np.sqrt(var)
        #arrays
        flux = spe.data
        sigma = sigma.data
        wave = spe.wave.coord()
        #vel = (wave/(wave0*(1+zabs))-1)*299792.458
        #mask pixels for continuum definition
        p1 = np.int(spe.wave.pixel(wavep - 60 * 1.25))
        p2 = np.int(spe.wave.pixel(wavep - 30 * 1.25))
        p3 = np.int(spe.wave.pixel(wavep + 30 * 1.25))
        p4 = np.int(spe.wave.pixel(wavep + 100 * 1.25))
        flux1 = flux[np.r_[p1:p2, p3:p4]]
        wave1 = wave[np.r_[p1:p2, p3:p4]]
        #continuum
        z = np.polyfit(wave1, flux1, 2)
        p = np.poly1d(z)
        cont = p(wave)
        nflux = flux / cont
        stdev = sigma / cont  #for displaying
        #mpdaf normalized continuum
        wave_aux = WaveCoord(cdelt=1.25, crval=wave[0], cunit=u.angstrom)
        nspe = Spectrum(wave=wave_aux, data=nflux, var=(stdev**2))
        norcube[:, i, j] = nspe
        #co[:] = sp-ai
Exemple #25
0
def test_resample():
    """Spectrum class: Test resampling"""

    # Choose the dimensions of the spectrum, choosing a large number that is
    # *not* a convenient power of 2.
    oldshape = 4000

    # Choose the wavelength pixel size and the default wavelength units.
    oldstep = 1.0
    oldunit = u.angstrom

    # Create the wavelength axis coordinates.
    wave = WaveCoord(crpix=2.0,
                     cdelt=oldstep,
                     crval=0.5,
                     cunit=oldunit,
                     shape=oldshape)

    # Specify the desired increase in pixel size, and the resulting pixel size.
    factor = 6.5
    newstep = ((factor * oldstep) * oldunit).to(u.nm).value

    # Specify the wavelength at which the peak of the resampled spectrum should
    # be expected.
    expected_peak_wave = 3000.0

    # Create the array in which the test spectrum will be composed.
    data = np.zeros(oldshape)

    # Get the wavelength coordinates of each pixel in the spectrum.
    w = wave.coord()

    # Add the following list gaussians to the spectrum, where each
    # gaussian is specified as: (amplitude, sigma_in_pixels,
    # center_wavelength). Given that narrow gaussians are reduced in
    # amplitude by resampling more than wide gaussians, we arrange
    # that the peak gaussian before and after correctly resampling are
    # different.
    gaussians = [
        (0.5, 12.0, 800.0),
        (0.7, 5.0, 1200.0),
        (0.4, 700.0, 1600.0),
        (1.5, 2.6, 1980.0),  # Peak before resampling
        (1.2, 2.6, 2000.0),
        (1.3, 15.0, expected_peak_wave),  # Peak if resampled correctly
        (1.0, 2.0, 3200.0)
    ]
    for amp, sigma, center in gaussians:
        sigma *= oldstep
        data += amp * np.exp(-0.5 * ((center - w) / sigma)**2)

    # Fill the variance array with a simple window function.
    var = np.hamming(oldshape)

    # Add gaussian random noise to the spectrum, but leave 3 output
    # pixel widths zero at each end of the spectrum so that the PSF of
    # the output grid doesn't spread flux from the edges off the edge
    # of the output grid. It takes about 3 pixel widths for the gaussian
    # PSF to drop to about 0.01 of its peak.
    margin = np.ceil(3 * factor).astype(int)
    data[margin:-margin] += np.random.normal(scale=0.1,
                                             size=data.shape - 2 * margin)

    # Install the spectral data in a Spectrum container.
    oldsp = Spectrum(data=data, var=var, wave=wave)

    # Mask a few pixels.
    masked_slice = slice(900, 910)
    oldsp.mask[masked_slice] = True

    # Create a down-sampled version of the input spectrum.
    newsp = oldsp.resample(newstep, unit=u.nm)

    # Check that the integral flux in the resampled spectrum matches that of
    # the original spectrum.
    expected_flux = oldsp.sum(weight=False)[0] * oldsp.wave.get_step(
        unit=oldunit)
    actual_flux = newsp.sum(weight=False)[0] * newsp.wave.get_step(
        unit=oldunit)
    assert_allclose(actual_flux, expected_flux, 1e-2)

    # Do the same test, but with fluxes weighted by the inverse of the variances.
    expected_flux = oldsp.sum(weight=True)[0] * oldsp.wave.get_step(
        unit=oldunit)
    actual_flux = newsp.sum(weight=True)[0] * newsp.wave.get_step(unit=oldunit)
    assert_allclose(actual_flux, expected_flux, 1e-2)

    # Check that the peak of the resampled spectrum is at the wavelength
    # where the strongest gaussian was centered in the input spectrum.
    assert_allclose(np.argmax(newsp.data),
                    newsp.wave.pixel(expected_peak_wave, nearest=True))

    # Now upsample the downsampled spectrum to the original pixel size.
    # This won't recover the same spectrum, since higher spatial frequencies
    # are lost when downsampling, but the total flux should be about the
    # same, and the peak should be at the same wavelength as the peak in
    # original spectrum within one pixel width of the downsampled spectrum.
    newsp2 = newsp.resample(oldstep, unit=oldunit)

    # Check that the doubly resampled spectrum has the same integrated flux
    # as the original.
    expected_flux = oldsp.sum(weight=False)[0] * oldsp.wave.get_step(
        unit=oldunit)
    actual_flux = newsp2.sum(weight=False)[0] * newsp2.wave.get_step(
        unit=oldunit)
    assert_allclose(actual_flux, expected_flux, 1e-2)

    # Check that the peak of the up-sampled spectrum is at the wavelength
    # of the peak of the down-sampled spectrum to within the pixel resolution
    # of the downsampled spectrum.
    assert_allclose(
        newsp.wave.pixel(newsp2.wave.coord(np.argmax(newsp2.data)),
                         nearest=True),
        newsp.wave.pixel(expected_peak_wave, nearest=True))

    # Check that pixels that were masked in the input spectrum are still
    # masked in the final spectrum.
    np.testing.assert_equal(newsp2.mask[masked_slice],
                            oldsp.mask[masked_slice])
Exemple #26
0
def create_source(
    source_id,
    source_table,
    source_lines,
    origin_params,
    cube_cor_filename,
    cube_std_filename,
    mask_filename,
    skymask_filename,
    spectra_fits_filename,
    segmaps,
    version,
    source_ts,
    profile_fwhm,
    *,
    author="",
    nb_fwhm=2,
    expmap_filename=None,
    save_to=None,
):
    """Create a MPDAF source.

    This function create a MPDAF source object for the ORIGIN source.

    Parameters
    ----------
    source_id : int
        Identifier for the source in the source and line tables.
    source_table : astropy.table.Table
        Catalogue of sources like the Cat3_sources one.
    source_lines : astropy.table.Table
        Catalogue of lines like the Cat3_lines one.
    origin_params : dict
        Dictionary of the parameters for the ORIGIN run.
    cube_cor_filename : str
        Name of the file containing the correlation cube of the ORIGIN run.
    cube_std_filename : str
        Name of the file containing the std cube of the ORIGIN run.
    mask_filenam e: str
        Name of the file containing the mask of the source.
    skymask_filename : str
        Name of the file containing the sky mask of the source.
    spectra_fits_filename : str
        Name of the FITS file containing the spectra of the lines.
    segmaps : dict(str: str)
        Dictionnary associating to a segmap type the associated FITS file name.
    version : str
        Version number stored in the source.
    source_ts : str
        Time stamp for when the source was created.
    profile_fwhm : list of int
        List of line profile FWHM in pixel. The index in the list is the
        profile number.
    author : str
        Name of the author.
    nb_fwhm : float
        Factor multiplying the FWHM of the line to compute the width of the
        narrow band image.
    expmap_filename : str
        Name of the file containing the exposure map.  If not None, a cut-out
        of the exposure map will be added to the source file.
    save_to : str
        If not None, the source will be saved to the given file.

    Returns
    -------
    mpdaf.sdetect.Source or None
        If save_to is used, the function returns None.

    """
    logger = logging.getLogger(__name__)

    # [0] is to get a Row not a table.
    source_table = source_table.filled()
    source_info = source_table[source_table["ID"] == source_id][0]

    # The mask size is used for the cut-out size.
    mask = Image(mask_filename)
    mask_size = mask.shape[0]

    data_cube = Cube(origin_params["cubename"], convert_float64=False)

    origin = (
        "ORIGIN",
        origin_version,
        os.path.basename(origin_params["cubename"]),
        data_cube.primary_header.get("CUBE_V", ""),
    )
    source = Source.from_data(
        source_info["ID"], source_info["ra"], source_info["dec"], origin
    )

    # Information about the source in the headers
    source.header["SRC_V"] = version, "Source version"
    source.header["SRC_TS"] = source_ts, "Timestamp of the source creation"
    source.header["CAT3_TS"] = (
        source_table.meta["CAT3_TS"],
        "Timestamp of the catalog creation",
    )
    source.add_history("Source created with ORIGIN", author)

    source.header["OR_X"] = source_info["x"], "x position in pixels"
    source.header["OR_Y"] = source_info["y"], "y position in pixels"
    source.header["OR_SEG"] = (
        source_info["seg_label"],
        "Label in the segmentation map",
    )
    source.header["OR_V"] = origin_version, "ORIGIN version"
    source.header["OR_FLUX"] = source_info["flux"], "flux maximum in all lines"
    source.header["OR_PMAX"] = (source_info["purity"], "maximum purity in all lines")

    if not np.isnan(source_info["STD"]):
        source.header["OR_STD"] = (source_info["STD"], "STD max value in all lines")

    if not np.isnan(source_info["nsigSTD"]):
        source.header["OR_nSTD"] = (
            source_info["nsigSTD"],
            "max of STD/std(STD) in all lines",
        )

    if not np.isnan(source_info["T_GLR"]):
        source.header["OR_TGLR"] = (
            source_info["T_GLR"],
            "T_GLR max value in all lines",
        )
    if not np.isnan(source_info["nsigTGLR"]):
        source.header["OR_nTGLR"] = (
            source_info["nsigTGLR"],
            "max of T_GLR/std(T_GLR) in all lines",
        )

    # source_header_keyword: (key_in_origin_param, description)
    parameters_to_add = {
        "OR_PROF": ("profiles", "OR input, spectral profiles"),
        "OR_FSF": ("PSF", "OR input, FSF cube"),
        "OR_THL%02d": ("threshold_list", "OR input threshold per area"),
        "OR_NA": ("nbareas", "OR number of areas"),
        "preprocessing": {"OR_DCT": ("dct_order", "OR input, DCT order")},
        "areas": {
            "OR_PFAA": ("pfa", "OR input, PFA used to create the area map"),
            "OR_SIZA": ("maxsize", "OR input, maximum area size in pixels"),
            "OR_MSIZA": ("minsize", "OR input, minimum area size in pixels"),
        },
        "compute_PCA_threshold": {"OR_PFAT": ("pfa_test", "OR input, PFA test")},
        "compute_greedy_PCA": {
            "OR_FBG": ("Noise_population", "OR input: fraction of spectra estimated"),
            "OR_ITMAX": ("itermax", "OR input, maximum number of iterations"),
        },
        "compute_TGLR": {"OR_NG": ("size", "OR input, connectivity size")},
        "detection": {
            "OR_DXY": ("tol_spat", "OR input, spatial tolerance for merging (pix)"),
            "OR_DZ": ("tol_spec", "OR input, spectral tolerance for merging (pix)"),
        },
        "compute_spectra": {"OR_NXZ": ("grid_dxy", "OR input, grid Nxy")},
    }

    def add_keyword(keyword, param, description, params):
        if param == "threshold_list" and param in params:
            for idx, threshold in enumerate(params["threshold_list"]):
                source.header[keyword % idx] = (float("%0.2f" % threshold), description)
        elif param in params:
            if params[param] is None:
                source.header[keyword] = "", description
            else:
                source.header[keyword] = params[param], description
        else:
            logger.debug("Parameter %s absent of the parameter list.", param)

    for keyword, val in parameters_to_add.items():
        if isinstance(val, dict) and keyword in origin_params:
            for key, val2 in val.items():
                add_keyword(key, *val2, origin_params[keyword]["params"])
        else:
            add_keyword(keyword, *val, origin_params)

    source.header["COMP_CAT"] = (
        source_info["comp"],
        "1/0 (1=Pre-detected in STD, 0=detected in CORREL)",
    )

    if source.COMP_CAT:
        threshold_keyword, purity_keyword = "threshold_std", "purity_std"
    else:
        threshold_keyword, purity_keyword = "threshold", "purity"
    source.header["OR_TH"] = (
        float("%0.2f" % origin_params[threshold_keyword]),
        "OR input, threshold",
    )
    source.header["OR_PURI"] = (
        float("%0.2f" % origin_params[purity_keyword]),
        "OR input, purity",
    )

    # Mini-cubes
    source.add_cube(
        data_cube, "MUSE_CUBE", size=mask_size, unit_size=None, add_white=True
    )
    # Add FSF with the full cube, to have the same shape as fieldmap, then we
    # can work directly with the subcube
    has_fsf = True
    try:
        source.add_FSF(data_cube, fieldmap=origin_params["fieldmap"])
    except:
        logger.debug('No FSF information found in the cube')
        has_fsf = False
    data_cube = source.cubes["MUSE_CUBE"]

    if source.COMP_CAT:
        cube_ori = Cube(cube_std_filename, convert_float64=False)
        source.add_cube(cube_ori, "ORI_SNCUBE", size=mask_size, unit_size=None)
        cube_ori = source.cubes["ORI_SNCUBE"]
    else:
        cube_ori = Cube(cube_cor_filename, convert_float64=False)
        source.add_cube(cube_ori, "ORI_CORREL", size=mask_size, unit_size=None)
        cube_ori = source.cubes["ORI_CORREL"]

    # Table of sources around the exported sources.
    radius = mask_size / 2
    x_min, x_max = source_info["x"] - radius, source_info["x"] + radius
    y_min, y_max = source_info["y"] - radius, source_info["y"] + radius
    nearby_sources = (
        (source_table["x"] >= x_min)
        & (source_table["x"] <= x_max)
        & (source_table["y"] >= y_min)
        & (source_table["y"] <= y_max)
    )
    source.tables["ORI_CAT"] = source_table["ID", "ra", "dec"][nearby_sources]

    # Maps
    # The white map was added when adding the MUSE cube.
    source.images["ORI_MAXMAP"] = cube_ori.max(axis=0)
    # Using add_image, the image size is taken from the white map.
    source.add_image(mask, "ORI_MASK_OBJ")
    source.add_image(Image(skymask_filename), "ORI_MASK_SKY")
    for segmap_type, segmap_filename in segmaps.items():
        source.add_image(Image(segmap_filename), "ORI_SEGMAP_%s" % segmap_type)
    if expmap_filename is not None:
        source.add_image(Image(expmap_filename), "EXPMAP")

    # Full source spectra
    source.extract_spectra(
        data_cube, obj_mask="ORI_MASK_OBJ", sky_mask="ORI_MASK_SKY", skysub=True
    )
    source.extract_spectra(
        data_cube, obj_mask="ORI_MASK_OBJ", sky_mask="ORI_MASK_SKY", skysub=False
    )
    if source.COMP_CAT:
        source.spectra["ORI_CORR"] = (
            source.cubes["ORI_SNCUBE"] * source.images["ORI_MASK_OBJ"]
        ).mean(axis=(1, 2))
    else:
        source.spectra["ORI_CORR"] = (
            source.cubes["ORI_CORREL"] * source.images["ORI_MASK_OBJ"]
        ).mean(axis=(1, 2))

    # Add the FSF information to the source and use this information to compute
    # the PSF weighted spectra.
    if has_fsf:
        try:    
            fsfmodel = source.get_FSF()
            fwhm_fsf = fsfmodel.get_fwhm(data_cube.wave.coord()) 
            beta_fsf = fsfmodel.get_beta(data_cube.wave.coord()) 
            source.extract_spectra(
                data_cube,
                obj_mask="ORI_MASK_OBJ",
                sky_mask="ORI_MASK_SKY",
                skysub=True,
                psf=fwhm_fsf,
                beta=beta_fsf,
            )
            source.extract_spectra(
                data_cube,
                obj_mask="ORI_MASK_OBJ",
                sky_mask="ORI_MASK_SKY",
                skysub=False,
                psf=fwhm_fsf,
                beta=beta_fsf,
            )
        except:
            # WIP to work with the new FSF model
            has_fsf = False

    # Per line data: the line table, the spectrum of each line, the narrow band
    # map from the data and from the correlation cube.
    # Content of the line table in the source
    line_columns, line_units, line_fmt = zip(
        *[
            ("NUM_LINE", None, None),
            ("RA_LINE", u.deg, ".2f"),
            ("DEC_LINE", u.deg, ".2f"),
            ("LBDA_OBS", u.Angstrom, ".2f"),
            ("FWHM", u.Angstrom, ".2f"),
            ("FLUX", u.erg / (u.s * u.cm ** 2), ".1f"),
            ("GLR", None, ".1f"),
            ("nGLR", None, ".1f"),
            ("PROF", None, None),
            ("PURITY", None, ".2f"),
        ]
    )

    # If the line is a complementary one, the GLR column is replace by STD
    if source.COMP_CAT:
        line_columns = list(line_columns)
        line_columns[6] = "STD"
        line_columns[7] = "nSTD"

    # We put all the ORIGIN lines in an ORI_LINES tables but keep only the
    # unique lines in the LINES tables.
    source.add_table(source_lines, "ORI_LINES", select_in=None, col_dist=None)

    # Table containing the information on the narrow band images.
    nb_par_rows = []

    hdulist = fits.open(spectra_fits_filename)

    for line in source_lines[source_lines["merged_in"] == -9999]:
        num_line, lbda_ori, prof = line[["num_line", "lbda", "profile"]]
        fwhm_ori = profile_fwhm[prof] * data_cube.wave.get_step(unit=u.Angstrom)
        if source.COMP_CAT:
            glr_std = line["STD"]
            nglr_std = line["nsigSTD"]
        else:
            glr_std = line["T_GLR"]
            nglr_std = line["nsigTGLR"]

        source.add_line(
            cols=line_columns,
            values=[
                num_line,
                line["ra"],
                line["dec"],
                lbda_ori,
                fwhm_ori,
                line["flux"],
                glr_std,
                nglr_std,
                prof,
                line["purity"],
            ],
            units=line_units,
            fmt=line_fmt,
            desc=None,
        )

        if f"DATA{num_line}" in hdulist:  # RB add test
            source.spectra[f"ORI_SPEC_{num_line}"] = Spectrum(
                hdulist=hdulist,
                ext=(f"DATA{num_line}", f"STAT{num_line}"),
                convert_float64=False,
            )

        source.add_narrow_band_image_lbdaobs(
            data_cube,
            f"NB_LINE_{num_line}",
            lbda=lbda_ori,
            width=nb_fwhm * fwhm_ori,
            method="sum",
            subtract_off=True,
            margin=10.0,
            fband=3.0,
        )

        nb_par_rows.append(
            [f"NB_LINE_{num_line}", lbda_ori, nb_fwhm * fwhm_ori, 10.0, 3.0]
        )

        source.add_narrow_band_image_lbdaobs(
            cube_ori,
            f"ORI_CORR_{num_line}",
            lbda=lbda_ori,
            width=nb_fwhm * fwhm_ori,
            method="max",
            subtract_off=False,
        )

        # Compute the spectra weighted by the correlation map for the
        # current line
        tags = [f"ORI_CORR_{num_line}"]
        source.extract_spectra(
            data_cube,
            obj_mask="ORI_MASK_OBJ",
            sky_mask="ORI_MASK_SKY",
            skysub=True,
            tags_to_try=tags,
        )
        source.extract_spectra(
            data_cube,
            obj_mask="ORI_MASK_OBJ",
            sky_mask="ORI_MASK_SKY",
            skysub=False,
            tags_to_try=tags,
        )

    # set REFSPEC to the spectrum weighted by the correlation map of the
    # brightest line
    num_max = source.lines["NUM_LINE"][np.argmax(source.lines["FLUX"])]
    source.header["REFSPEC"] = f"ORI_CORR_{num_max}_SKYSUB"

    hdulist.close()

    nb_par = Table(
        names=["LINE", "LBDA", "WIDTH", "MARGIN", "FBAND"],
        dtype=["U20", float, float, float, float],
        rows=nb_par_rows,
    )
    source.add_table(nb_par, "NB_PAR", select_in=None, col_dist=None)

    if save_to is not None:
        source.write(save_to)
    else:
        return source