Пример #1
0
def emission_templates(velscale):
    """ Load files with stellar library used as templates. """
    current_dir = os.getcwd()
    # Template directory is also set in setyp.py
    os.chdir(template_dir)
    emission = [x for x in os.listdir(".") if x.startswith("emission") and x.endswith(".fits")]
    emission.sort()
    c = 299792.458
    FWHM_tem = 2.1  # MILES library spectra have a resolution FWHM of 2.54A.
    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pf.open(emission[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2["CRVAL1"] + np.array([0.0, h2["CDELT1"] * (h2["NAXIS1"] - 1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
    templates = np.empty((sspNew.size, len(emission)))
    for j in range(len(emission)):
        hdu = pf.open(emission[j])
        ssp = hdu[0].data
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
        templates[:, j] = sspNew
    # templates *= 1e5 # Normalize templates
    os.chdir(current_dir)
    return templates, logLam2, h2["CDELT1"], emission
Пример #2
0
def emission_templates(velscale):
    """ Load files with stellar library used as templates. """
    current_dir = os.getcwd()
    # Template directory is also set in setup.py
    os.chdir(templates_dir)
    emission = [x for x in os.listdir(".") if x.startswith("emission") and
             x.endswith(".fits") and x not in ["emission_FWHM_2.7.fits",
                                               "emission_FWHM_3.7.fits"]]
    emission.sort()
    c = 299792.458
    FWHM_tem = 2.5 # MILES library spectra have a resolution FWHM of 2.54A.
    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pf.open(emission[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array([0.,h2['CDELT1']*(h2['NAXIS1']-1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                               velscale=velscale)
    templates = np.empty((sspNew.size,len(emission)))
    for j in range(len(emission)):
        ssp = pf.getdata(emission[j])
        w = wavelength_array(emission[j])
        dsigma = np.sqrt((3.7**2 - 2.7**2))/2.335/(w[1]-w[0])
        ssp = gaussian_filter1d(ssp, dsigma)
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                                   velscale=velscale)
        templates[:,j] = sspNew
    templates *= 1e5 # Normalize templates
    os.chdir(current_dir)
    return templates, logLam2, h2['CDELT1'], emission
Пример #3
0
def emission_templates(velscale):
    """ Load files with stellar library used as templates. """
    current_dir = os.getcwd()
    # Template directory is also set in setyp.py
    os.chdir(template_dir)
    emission = [x for x in os.listdir(".") if x.startswith("emission") and
             x.endswith(".fits")]
    emission.sort()
    c = 299792.458
    FWHM_tem = 2.1 # MILES library spectra have a resolution FWHM of 2.54A.
    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pf.open(emission[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array([0.,h2['CDELT1']*(h2['NAXIS1']-1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                               velscale=velscale)
    templates = np.empty((sspNew.size,len(emission)))
    for j in range(len(emission)):
        hdu = pf.open(emission[j])
        ssp = hdu[0].data
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                                   velscale=velscale)
        templates[:,j] = sspNew
    # templates *= 1e5 # Normalize templates
    os.chdir(current_dir)
    return templates, logLam2, h2['CDELT1'], emission
Пример #4
0
def load_templates_regul(velscale):
    """ Load templates into 2D array for regularization"""
    # cd into template folder to make calculations
    current_dir = os.getcwd()
    os.chdir(os.path.join(home, "miles_models"))
    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    miles = [x for x in os.listdir(".") if x.endswith(".fits")]
    print miles
    raw_input()
    hdu = pf.open(miles[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array([0.,h2['CDELT1']*(h2['NAXIS1']-1)])

    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                               velscale=velscale)
    # Ordered array of metallicities
    Zs = set([x.split("Z")[1].split("T")[0] for x in miles])
    Zs = [float(x.replace("m", "-").replace("p", "")) for x in Zs]
    Zs.sort()
    Z2 = Zs[:]
    for i in range(len(Zs)):
        if Zs[i] < 0:
            Zs[i] = "{0:.2f}".format(Zs[i]).replace("-", "m")
        else:
            Zs[i] = "p{0:.2f}".format(Zs[i])
    # Ordered array of ages
    Ts = list(set([x.split("T")[1].split(".fits")[0] for x in miles]))
    Ts.sort()
    # Create a three dimensional array to store the
    # two dimensional grid of model spectra
    #
    nAges = len(Ts)
    nMetal = len(Zs)
    templates = np.empty((sspNew.size,nAges,nMetal))

    # Here we make sure the spectra are sorted in both [M/H]
    # and Age along the two axes of the rectangular grid of templates.
    # A simple alphabetical ordering of Vazdekis's naming convention
    # does not sort the files by [M/H], so we do it explicitly below
    miles = []
    for k in range(nMetal):
        for j in range(nAges):
            filename = "Mun1.30Z{0}T{1}.fits".format(Zs[k], Ts[j])
            ssp = pf.getdata(filename)
            sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                                       velscale=velscale)
            templates[:,j,k] = sspNew # Templates are *not* normalized here
            miles.append(filename)
    templates /= np.median(templates) # Normalizes templates by a scalar
    os.chdir(current_dir)
    return templates, logLam2, Ts, Z2, miles, h2['CDELT1']
Пример #5
0
def setup_bc03_library(wave,
                       velscale=None,
                       FWHM_gal=1,
                       version='N',
                       in_log=True):
    FWHM_tem = 1  # this number is crap as the spectra are synthetic in part...
    lam, full, full_data, logAge_grid, metal_grid = load_bc03_library(
        version=version)

    templates = np.zeros_like(full)

    new_ssp = np.interp(wave, lam, ssp, right=0, left=0)
    lamRange_temp = [wave[0], wave[-1]]
    delta = np.diff(lam)[0]
    if in_log:
        sspNew, logLam2, velscale = util.log_rebin(lamRange_temp,
                                                   ssp,
                                                   velscale=0.99999 * velscale)
    else:
        sspNew = ssp
        logLam2 = np.log(lam)
    #

    templates = np.empty((sspNew.size, nAges, nMetal))

    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    sigma = FWHM_dif / 2.355 / delta  # Sigma difference in pixels

    for i, d in enumerate(data):
        tmp = os.path.join(os.path.dirname(basefile), 'BasesDir',
                           d['specfile'])
        lam, ssp = np.loadtxt(tmp, unpack=True)
        full[:, i % nAges, int(i / nAges)] = ssp
        new_lam = wave
        #new_lam = np.arange(new_lam[0], new_lam[-1],1)
        new_ssp = np.interp(new_lam, lam, ssp, right=0, left=0)
        # new_lam = np.arange(lam[0], lam[-1],1)
        # new_ssp = np.interp(new_lam,lam, ssp, right=0, left=0)
        # mask = (new_lam > wave.min()-1) & (new_lam < wave.max()+2)
        lam = new_lam  #[mask]
        ssp = new_ssp  #[mask]
        ssp = ndimage.gaussian_filter1d(ssp, sigma)
        if in_log:
            sspNew, logLam2, velscale = util.log_rebin(lamRange_temp,
                                                       ssp,
                                                       velscale=velscale)
        else:
            sspNew = ssp
        templates[:, i % nAges, int(i / nAges)] = sspNew
        logAge_grid[i % nAges, int(i / nAges)] = np.log10(d['age'] / 1.e9)
        metal_grid[i % nAges, int(i / nAges)] = np.log10(d['Z'])

    return templates, lamRange_temp, logAge_grid, metal_grid  #, lam_full, full
Пример #6
0
def load_templates_regul(velscale):
    """ Load templates into 2D array for regularization"""
    # cd into template folder to make calculations
    current_dir = os.getcwd()
    os.chdir(os.path.join(home, "miles_models"))
    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    miles = [x for x in os.listdir(".") if x.endswith(".fits")]
    print miles
    raw_input()
    hdu = pf.open(miles[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2["CRVAL1"] + np.array([0.0, h2["CDELT1"] * (h2["NAXIS1"] - 1)])

    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
    # Ordered array of metallicities
    Zs = set([x.split("Z")[1].split("T")[0] for x in miles])
    Zs = [float(x.replace("m", "-").replace("p", "")) for x in Zs]
    Zs.sort()
    Z2 = Zs[:]
    for i in range(len(Zs)):
        if Zs[i] < 0:
            Zs[i] = "{0:.2f}".format(Zs[i]).replace("-", "m")
        else:
            Zs[i] = "p{0:.2f}".format(Zs[i])
    # Ordered array of ages
    Ts = list(set([x.split("T")[1].split(".fits")[0] for x in miles]))
    Ts.sort()
    # Create a three dimensional array to store the
    # two dimensional grid of model spectra
    #
    nAges = len(Ts)
    nMetal = len(Zs)
    templates = np.empty((sspNew.size, nAges, nMetal))

    # Here we make sure the spectra are sorted in both [M/H]
    # and Age along the two axes of the rectangular grid of templates.
    # A simple alphabetical ordering of Vazdekis's naming convention
    # does not sort the files by [M/H], so we do it explicitly below
    miles = []
    for k in range(nMetal):
        for j in range(nAges):
            filename = "Mun1.30Z{0}T{1}.fits".format(Zs[k], Ts[j])
            ssp = pf.getdata(filename)
            sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
            templates[:, j, k] = sspNew  # Templates are *not* normalized here
            miles.append(filename)
    templates /= np.median(templates)  # Normalizes templates by a scalar
    os.chdir(current_dir)
    return templates, logLam2, Ts, Z2, miles, h2["CDELT1"]
Пример #7
0
def load_sky(filenames, velscale, full_output=False):
    """ Load and rebin sky files. """
    skydata = fits_to_matrix(filenames)
    h1 = pf.getheader(filenames[0])
    lamRange1 = h1['CRVAL1'] + np.array([0.,h1['CDELT1']*(h1['NAXIS1']-1)])
    sky1, logLam1, velscale = util.log_rebin(lamRange1, skydata[:,0],
                                                   velscale=velscale)

    skylog = np.zeros((sky1.shape[0], len(filenames)))
    for i in range(len(filenames)):
        skylog[:,i], logLam1, velscale = util.log_rebin(lamRange1,
                                        skydata[:,i], velscale=velscale)
    if full_output:
        return skylog, logLam1
    return skylog
Пример #8
0
def smooth_and_rebin(bc03, bc03_lambda, gal_lambda, velscale, FWHM_gal=1, FWHM_tem=0):
    """
    Smooth and rebin the BC03 spectra based on the sampling 
    of the galaxy to be fitted.
    Input :
    - bc03 : the spectral templates
    - bc03_lambda : the template wavelength array
    - gal_lambda : the galaxy wavelength array, which the rebinning 
    is going to match. Note tha the galaxy must have already 
    been log-rebinned. 
    - velscale : velocity scale of the galaxy, for log rebinning
    - FWHM_gal : FWHM of the galaxy resolution
    - FWHM_tem : FWHM of the template resolution
    Output :
    - templates : the smoothed and rebinned version of the BC03 input
    """
    templates = np.empty(((gal_lambda.size,)+(bc03.shape[1],bc03.shape[2])))
    for i in range(bc03.shape[1]):
        for j in range(bc03.shape[2]):
            ssp = bc03[:,i,j]
            #resize the templates to the log-rebinned galaxy wavelengths
            new_ssp = np.interp(gal_lambda, bc03_lambda, ssp, right=0, left=0)
            #log-rebin the interpolated templates
            #the output velscape should be close to identical to the input
            #Likewise, logLam2 == np.log(gal_lambda) to about 1e-5 
            sspNew, logLam2, velscale = util.log_rebin([gal_lambda[0],gal_lambda[-1]], new_ssp, velscale=velscale)
            #smooth the log-rebinned templates
            FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
            sigma = FWHM_dif/2.355/np.diff(gal_lambda)[0]
            smoothed_ssp = ndimage.gaussian_filter1d(new_ssp, sigma)
            templates[:, i, j] = smoothed_ssp
    return templates
Пример #9
0
def stellar_templates(velscale):
    """ Load files with stellar library used as templates. """
    current_dir = os.getcwd()
    # Template directory is also set in config.py
    os.chdir(templates_dir)
    miles = [x for x in os.listdir(".") if x.startswith("Mun") and
             x.endswith(".fits")]
    # Ordered array of metallicities
    Zs = set([x.split("Z")[1].split("T")[0] for x in miles])
    Zs = [float(x.replace("m", "-").replace("p", "").replace("_", "."))
          for x in Zs]
    Zs.sort()
    for i in range(len(Zs)):
        if Zs[i] < 0:
            Zs[i] = "{0:.2f}".format(Zs[i]).replace("-", "m")
        else:
            Zs[i] = "p{0:.2f}".format(Zs[i])
    # Ordered array of ages
    Ts = list(set([x.split("T")[1][:7]
                   for x in miles]))
    Ts.sort()
    miles = []
    metal_ages = []
    for m in Zs:
        for t in Ts:
            filename = "Mun1.30Z{0}T{1}_linear_FWHM_2.7.fits".format(m, t)
            if os.path.exists(filename):
                miles.append(filename)
                metal_ages.append([m.replace("_", ".").replace("p",
                       "+").replace("m", "-"),t.replace("_", ".")])
    hdu = pf.open(miles[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array([0.,h2['CDELT1']*(h2['NAXIS1']-1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                               velscale=velscale)
    templates = np.empty((sspNew.size,len(miles)))
    for j in range(len(miles)):
        ssp = pf.getdata(miles[j])
        w = wavelength_array(miles[j])
        dsigma = np.sqrt((3.7**2 - 2.7**2))/2.335/(w[1]-w[0])
        ssp = gaussian_filter1d(ssp, dsigma)
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                                   velscale=velscale)
        templates[:,j] = sspNew
    os.chdir(current_dir)
    return templates, logLam2, h2['CDELT1'], miles
Пример #10
0
def stellar_templates(velscale):
    """ Load files with stellar library used as templates. """
    current_dir = os.getcwd()
    # Template directory is also set in config.py
    os.chdir(template_dir)
    miles = [x for x in os.listdir(".") if x.startswith("Mun") and
             x.endswith(".fits")]
    # Ordered array of metallicities
    Zs = set([x.split("Z")[1].split("T")[0] for x in miles])
    Zs = [float(x.replace("m", "-").replace("p", "").replace("_", "."))
          for x in Zs]
    Zs.sort()
    for i in range(len(Zs)):
        if Zs[i] < 0:
            Zs[i] = "{0:.2f}".format(Zs[i]).replace("-", "m")
        else:
            Zs[i] = "p{0:.2f}".format(Zs[i])
    Zs = [str(x).replace(".", "_") for x in Zs]
    # Ordered array of ages
    Ts = list(set([x.split("T")[1].split(".fits")[0].replace("_", ".")
                   for x in miles]))
    Ts.sort()
    Ts = [str(x).replace(".", "_") for x in Ts]
    miles = []
    metal_ages = []
    for m in Zs:
        for t in Ts:
            filename = "Mun1_30Z{0}T{1}.fits".format(m, t)
            if os.path.exists(filename):
                miles.append(filename)
                metal_ages.append([m.replace("_", ".").replace("p",
                       "+").replace("m", "-"),t.replace("_", ".")])
    hdu = pf.open(miles[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array([0.,h2['CDELT1']*(h2['NAXIS1']-1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                               velscale=velscale)
    templates = np.empty((sspNew.size,len(miles)))
    for j in range(len(miles)):
        hdu = pf.open(miles[j])
        ssp = hdu[0].data
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp,
                                                   velscale=velscale)
        templates[:,j] = sspNew
    os.chdir(current_dir)
    return templates, logLam2, h2['CDELT1'], miles
Пример #11
0
def build_templates(lam, ssp, wave, velscale, sigma):
        new_ssp = np.interp(wave, lam, ssp, right=0, left=0)
        lam=wave
        ssp=new_ssp
        ssp = ndimage.gaussian_filter1d(new_ssp,sigma)
        sspNew, logLam2, velscale = util.log_rebin([wave[0],wave[-1]], ssp, velscale=velscale)
 
        return sspNew
Пример #12
0
    def __init__(self, spec, velscale, pklfile=None):
        """ Load the pkl file from previous ppxf fit and define some atributes.
        """
        if pklfile == None:
            pklfile = spec.replace(".fits", ".pkl")
        with open(pklfile) as f:
            pp = pickle.load(f)
        self.__dict__ = pp.__dict__.copy()
        self.spec = spec
        if not os.path.exists(os.path.join(os.getcwd(), spec)):
            self.spec = os.path.join(data_dir, spec)
        self.velscale = velscale
        self.w = wavelength_array(os.path.join(data_dir, spec))
        self.flux = pf.getdata(self.spec)
        self.flux_log, self.logw, velscale = util.log_rebin(
            [self.w[0], self.w[-1]], self.flux, velscale=velscale)
        self.w_log = np.exp(self.logw)
        self.header = pf.getheader(os.path.join(data_dir, spec))
        self.lam = self.header['CRVAL1'] + np.array(
            [0., self.header['CDELT1'] * (self.header['NAXIS1'] - 1)])
        ######################################################################
        # # Read templates
        star_templates, self.logLam2, self.delta, miles = stellar_templates(
            velscale)
        ######################################################################
        # Convolve our spectra to match MILES resolution
        FWHM_tem = 2.51
        FWHM_spec = 2.1
        FWHM_dif = np.sqrt(FWHM_tem**2 - FWHM_spec**2)
        sigma = FWHM_dif / 2.355 / self.delta  # Sigma difference in pixels
        ######################################################################
        spec_lin = ndimage.gaussian_filter1d(self.flux, sigma)
        # Rebin to logarithm scale
        galaxy, self.logLam1, velscale = util.log_rebin(self.lam,
                                                        spec_lin,
                                                        velscale=velscale)
        self.dv = (self.logLam2[0] - self.logLam1[0]) * c
        # if self.sky != None:
        #     sky = self.weights[-1] * self.sky.T[0]
        #     self.bestfit -= sky
        #     self.galaxy -= sky
        #     skyspec = os.path.join(sky_data_dir, spec.replace("fin1", "sky1"))
        #     sky_lin = pf.getdata(skyspec)

        return
Пример #13
0
    def rebin(self):
        self.stellar_templates = get_stellar_templates(
            self.FWHM_gal, library=self.params.library)

        ## smooth spectrum to fit with templates resolution
        if self.FWHM_gal < self.stellar_templates.FWHM_tem:
            sigma = self.stellar_templates.FWHM_dif / 2.355 / self.CDELT  # Change in px
            self.bin_lin = ndimage.gaussian_filter1d(self.bin_lin, sigma)
            self.bin_lin_noise = np.sqrt(
                ndimage.gaussian_filter1d(self.bin_lin_noise**2, sigma))

        ## rebin spectrum logarthmically
        self.bin_log, self.logLam_bin, self.velscale = util.log_rebin(
            self.lamRange, self.bin_lin)
        bin_log_noise, logLam_bin, _ = util.log_rebin(self.lamRange,
                                                      self.bin_lin_noise**2)
        self.bin_log_noise = np.sqrt(bin_log_noise)
        self.lambdaq = np.exp(self.logLam_bin)
Пример #14
0
    def __init__(self, spec, velscale, pklfile=None):
        """ Load the pkl file from previous ppxf fit and define some atributes.
        """
        if pklfile == None:
            pklfile = spec.replace(".fits", ".pkl")
        with open(pklfile) as f:
            pp = pickle.load(f)
        self.__dict__ = pp.__dict__.copy()
        self.spec = spec
        if not os.path.exists(os.path.join(os.getcwd(), spec)):
            self.spec = os.path.join(data_dir, spec)
        self.velscale = velscale
        self.w = wavelength_array(os.path.join(data_dir, spec))
        self.flux = pf.getdata(self.spec)
        self.flux_log, self.logw, velscale = util.log_rebin(
                        [self.w[0], self.w[-1]], self.flux, velscale=velscale)
        self.w_log = np.exp(self.logw)
        self.header = pf.getheader(os.path.join(data_dir, spec))
        self.lam = self.header['CRVAL1'] + np.array([0.,
                              self.header['CDELT1']*(self.header['NAXIS1']-1)])
        ######################################################################
        # # Read templates
        star_templates, self.logLam2, self.delta, miles= stellar_templates(velscale)
        ######################################################################
        # Convolve our spectra to match MILES resolution
        FWHM_tem = 2.51
        FWHM_spec = 2.1
        FWHM_dif = np.sqrt(FWHM_tem**2 - FWHM_spec**2)
        sigma = FWHM_dif/2.355/self.delta # Sigma difference in pixels
        ######################################################################
        spec_lin = ndimage.gaussian_filter1d(self.flux,sigma)
        # Rebin to logarithm scale
        galaxy, self.logLam1, velscale = util.log_rebin(self.lam, spec_lin,
                                                   velscale=velscale)
        self.dv = (self.logLam2[0]-self.logLam1[0])*c
        # if self.sky != None:
        #     sky = self.weights[-1] * self.sky.T[0]
        #     self.bestfit -= sky
        #     self.galaxy -= sky
        #     skyspec = os.path.join(sky_data_dir, spec.replace("fin1", "sky1"))
        #     sky_lin = pf.getdata(skyspec)


        return
Пример #15
0
def setup_bc03_library(wave, velscale=None, FWHM_gal=1, version='N', in_log=True):
    FWHM_tem = 1 # this number is crap as the spectra are synthetic in part...
    lam, full, full_data, logAge_grid, metal_grid = load_bc03_library(version=version)

    templates = np.zeros_like(full)
    
    new_ssp = np.interp(wave,lam, ssp, right=0, left=0)
    lamRange_temp = [wave[0],wave[-1]]
    delta = np.diff(lam)[0]
    if in_log:
        sspNew, logLam2, velscale = util.log_rebin(lamRange_temp, ssp, velscale=0.99999*velscale)
    else:
        sspNew=ssp
        logLam2=np.log(lam)
    #

    templates = np.empty((sspNew.size, nAges, nMetal))

    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    sigma = FWHM_dif/2.355/delta # Sigma difference in pixels

    for i,d in enumerate(data):
        tmp=os.path.join(os.path.dirname(basefile),'BasesDir',d['specfile'])
        lam,ssp = np.loadtxt(tmp, unpack=True)
        full[:,i%nAges,int(i/nAges)] = ssp
        new_lam = wave
        #new_lam = np.arange(new_lam[0], new_lam[-1],1)
        new_ssp = np.interp(new_lam,lam, ssp, right=0, left=0)
        # new_lam = np.arange(lam[0], lam[-1],1)
        # new_ssp = np.interp(new_lam,lam, ssp, right=0, left=0)
        # mask = (new_lam > wave.min()-1) & (new_lam < wave.max()+2)
        lam=new_lam#[mask]
        ssp=new_ssp#[mask]
        ssp = ndimage.gaussian_filter1d(ssp,sigma)
        if in_log:
            sspNew, logLam2, velscale = util.log_rebin(lamRange_temp, ssp, velscale=velscale)
        else:
            sspNew=ssp
        templates[:,i%nAges,int(i/nAges)] = sspNew
        logAge_grid[i%nAges,int(i/nAges)] = np.log10(d['age']/1.e9)
        metal_grid[i%nAges,int(i/nAges)] = np.log10(d['Z'])
            
    return templates, lamRange_temp, logAge_grid, metal_grid#, lam_full, full
Пример #16
0
def build_templates(lam, ssp, wave, velscale, sigma):
    new_ssp = np.interp(wave, lam, ssp, right=0, left=0)
    lam = wave
    ssp = new_ssp
    ssp = ndimage.gaussian_filter1d(new_ssp, sigma)
    sspNew, logLam2, velscale = util.log_rebin([wave[0], wave[-1]],
                                               ssp,
                                               velscale=velscale)

    return sspNew
Пример #17
0
	def rebin(self):
		self.stellar_templates = get_stellar_templates(self.FWHM_gal, 
			library=self.params.library)
		
		## smooth spectrum to fit with templates resolution
		if self.FWHM_gal < self.stellar_templates.FWHM_tem:
			sigma = self.stellar_templates.FWHM_dif/2.355/self.CDELT # Change in px
			self.bin_lin = ndimage.gaussian_filter1d(self.bin_lin, sigma)
			self.bin_lin_noise = np.sqrt(ndimage.gaussian_filter1d(
				self.bin_lin_noise**2, sigma))
			self.FWHM_gal = self.stellar_templates.FWHM_tem
		
		## rebin spectrum logarthmically
		self.bin_log, self.logLam_bin, self.velscale = util.log_rebin(self.lamRange, 
			self.bin_lin)
		bin_log_noise, logLam_bin, _ = util.log_rebin(self.lamRange, 
			self.bin_lin_noise**2)
		self.bin_log_noise = np.sqrt(bin_log_noise)
		self.lambdaq = np.exp(self.logLam_bin)
Пример #18
0
def getdata_NEW(spec, wavelength, l1, l2):

    tmp = np.column_stack((wavelength, spec))
    mn = tmp[tmp[:, 0] > l1]
    mx = tmp[tmp[:, 0] < l2]

    lamRange = [mn[0, 0], mx[-1, 0]]

    galaxy, logLam1, velscale = util.log_rebin(lamRange, spec)

    return galaxy, logLam1, velscale
Пример #19
0
def stellar_templates(velscale):
    """ Load files with stellar library used as templates. """
    current_dir = os.getcwd()
    # Template directory is also set in config.py
    os.chdir(template_dir)
    miles = [x for x in os.listdir(".") if x.startswith("Mun") and x.endswith(".fits")]
    # Ordered array of metallicities
    Zs = set([x.split("Z")[1].split("T")[0] for x in miles])
    Zs = [float(x.replace("m", "-").replace("p", "").replace("_", ".")) for x in Zs]
    Zs.sort()
    for i in range(len(Zs)):
        if Zs[i] < 0:
            Zs[i] = "{0:.2f}".format(Zs[i]).replace("-", "m")
        else:
            Zs[i] = "p{0:.2f}".format(Zs[i])
    Zs = [str(x).replace(".", "_") for x in Zs]
    # Ordered array of ages
    Ts = list(set([x.split("T")[1].split(".fits")[0].replace("_", ".") for x in miles]))
    Ts.sort()
    Ts = [str(x).replace(".", "_") for x in Ts]
    miles = []
    metal_ages = []
    for m in Zs:
        for t in Ts:
            filename = "Mun1_30Z{0}T{1}.fits".format(m, t)
            if os.path.exists(filename):
                miles.append(filename)
                metal_ages.append([m.replace("_", ".").replace("p", "+").replace("m", "-"), t.replace("_", ".")])
    hdu = pf.open(miles[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2["CRVAL1"] + np.array([0.0, h2["CDELT1"] * (h2["NAXIS1"] - 1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
    templates = np.empty((sspNew.size, len(miles)))
    for j in range(len(miles)):
        hdu = pf.open(miles[j])
        ssp = hdu[0].data
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
        templates[:, j] = sspNew
    os.chdir(current_dir)
    return templates, logLam2, h2["CDELT1"], miles
def fit_spectra(bin_sci_j, ppxf_bestfit_j, plot=False):
    """
    """

    with fits.open(bin_sci_j) as hdu:
        odata = hdu[0].data
        ohdr = hdu[0].header

    bestfit = fits.getdata(ppxf_bestfit_j)

    lamRange = ohdr['CRVAL1'] + np.array([1. - ohdr['CRPIX1'], ohdr['NAXIS1'] - ohdr['CRPIX1']]) * ohdr['CD1_1']
    x = np.linspace(lamRange[0], lamRange[1], ohdr['NAXIS1'])

    # Log bin the spectra to match the best fit absorption template
    galaxy, logLam1, velscale = util.log_rebin(lamRange, odata)
    log_bins = np.exp(logLam1)
    emlns, lnames, lwave = util.emission_lines(logLam1, lamRange, 2.3)

    # Hgamma 4340.47, Hbeta 4861.33, OIII [4958.92, 5006.84]
    # lwave = [4340.47, 4861.33, 4958.92, 5006.84]

    # find the index of the emission lines
    iHg = (np.abs(log_bins - lwave[0])).argmin()
    iHb = (np.abs(log_bins - lwave[1])).argmin()
    iOIII = (np.abs(log_bins - lwave[2])).argmin()
    iOIIIb = (np.abs(log_bins - (lwave[2] - 47.92))).argmin()

    # There are BOTH absorption and emission features about the wavelength of Hgamma and Hbeta, so we need
    # to use a specialized fitting function (convolved Guassian and Lorentzian -> pVoight) to remove the
    # emission lines
    popt_Hg, pcov_Hg = fit_ems_pvoightcont(log_bins, galaxy, x, odata, iHg, bestfit)
    popt_Hb, pcov_Hb = fit_ems_pvoightcont(log_bins, galaxy, x, odata, iHb, bestfit)

    # There are only emission features about the OIII doublet so we only fit the emission line with a Gaussian
    popt_OIII, pcov_OIII = fit_ems_lincont(x, odata, iOIII, bestfit, x[954], [x[952], x[956]])
    popt_OIIIb, pcov_OIIIb = fit_ems_lincont(x, odata, iOIIIb, bestfit)

    em_fit = gauss_lorentz(x, popt_Hg[0], popt_Hg[1], popt_Hg[2], popt_Hg[3], popt_Hg[4], popt_Hg[5]) + \
             gauss_lorentz(x, popt_Hb[0], popt_Hb[1], popt_Hb[2], popt_Hb[3], popt_Hb[4], popt_Hb[5]) + \
             gauss_lorentz(x, popt_OIII[0], popt_OIII[1], popt_OIII[2], popt_OIII[3], popt_OIII[4], popt_OIII[5]) + \
             gauss_lorentz(x, popt_OIIIb[0], popt_OIIIb[1], popt_OIIIb[2], popt_OIIIb[3], popt_OIIIb[4], popt_OIIIb[5])

    abs_fit = odata - em_fit

    if plot:
        plt.plot(x, odata, '-k', label="spectra")
        # plt.plot(x, bestfit, '--r', label="bestfit absorption line")
        plt.plot(x, abs_fit, '-b', label="absorption spectra - gauss")
        plt.legend()
        plt.show()

    return abs_fit, em_fit
Пример #21
0
def get_templates(velscale, l1, l2):

    library = glob('/Volumes/VINCE/OAC/libraries/Valdes/clean_short/*')
    ssp = pd.read_table(library[0], header=None)[0].values

    FWHM_gal = 13.1
    FWHM_tem = 1.35
    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    scale = 0.4
    sigma = FWHM_dif / 2.355 / scale
    lamRange2 = [3465., 9469.]

    sspNew, logLam2, _ = util.log_rebin(lamRange2, ssp, velscale=velscale)
    library_size = sspNew.size
    templates = np.empty((library_size, len(library)))

    for j in range(len(library)):
        tmp = pd.read_table(library[j], sep=r'\s+', header=None)
        ssp = tmp[0].values
        ssp = ndimage.gaussian_filter1d(ssp, sigma)
        sspNew, logLam2, _ = util.log_rebin(lamRange2, ssp, velscale=velscale)
        templates[:, j] = sspNew / np.median(sspNew)

    return logLam2, templates
Пример #22
0
 def __init__(self, spec, velscale):
     """ Load the pkl file from previous ppxf fit and define some attributes.
     """
     with open(spec.replace(".fits", ".pkl")) as f:
         pp = pickle.load(f)
     self.__dict__ = pp.__dict__.copy()
     self.spec = os.path.join(data_dir, spec)
     self.vhelio = pf.getval(os.path.join(data_dir, self.spec), "VHELIO")
     self.velscale = velscale
     self.w = wavelength_array(os.path.join(data_dir, spec))
     self.flux = pf.getdata(self.spec)
     self.flux_log, self.logw, velscale = util.log_rebin(
                     [self.w[0], self.w[-1]], self.flux, velscale=velscale) 
     self.w_log = np.exp(self.logw)
     self.calc_sn()
     return
Пример #23
0
def check_ppxf(spec, velscale):
    """ Checking if velocity os star is zero"""
    templates, logLam2, delta, miles= stellar_templates(velscale)
    FWHM_dif = np.sqrt(FWHM_tem**2 - FWHM_spec**2)
    sigma = FWHM_dif/2.355/delta # Sigma difference in pixels
    star = pf.getdata(spec)
    star1 = ndimage.gaussian_filter1d(star, sigma)
    w = wavelength_array(spec)
    lamRange= np.array([w[0], w[-1]])
    galaxy, logLam1, velscale = util.log_rebin(lamRange, star1, \
                                               velscale=velscale)
    sn = snr(star1)
    noise = np.ones_like(galaxy) / sn
    dv = (logLam2[0]-logLam1[0])*c
    pp = ppxf(templates, galaxy, noise, velscale, [0,50],
        plot=True, moments=2, degree=5, mdegree=-1, vsyst=dv)
    plt.show()
    return
Пример #24
0
def w_temp(velscale):
    """ Make templates array"""
    current_dir = os.getcwd()
    os.chdir(template_dir)
    miles = [x for x in os.listdir(".") if x.endswith(".fits")]
    miles.sort()
    c = 299792.458
    FWHM_tem = 2.54  # MILES library spectra have a resolution FWHM of 2.54A.
    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pf.open(miles[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2["CRVAL1"] + np.array([0.0, h2["CDELT1"] * (h2["NAXIS1"] - 1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
    os.chdir(current_dir)
    return np.exp(logLam2)
Пример #25
0
def ppxf_gas_kinematics_parallel_loop(bin_sci_j, ppxf_bestfit_j, gal_hdr, templates, velscale, sigma, lamRange1,
                                      logLam2, start, plot, moments, regul_err, reg_dim, component, bias, quiet):
    gal_data = fits.getdata(bin_sci_j, 0)
    gal_data_new = ndimage.gaussian_filter1d(gal_data, sigma)

    galaxy, logLam1, velscale = util.log_rebin(lamRange1, gal_data_new, velscale=velscale)
    noise = galaxy * 0 + 1  # Assume constant noise per pixel here

    # The galaxy and the template spectra do not have the same starting wavelength.
    # For this reason an extra velocity shift DV has to be applied to the template
    # to fit the galaxy spectrum. We remove this artificial shift by using the
    # keyword VSYST in the call to PPXF below, so that all velocities are
    # measured with respect to DV. This assume the redshift is negligible.
    # In the case of a high-redshift galaxy one should de-redshift its
    # wavelength to the rest frame before using the line below as described
    # in PPXF_KINEMATICS_EXAMPLE_SAURON.
    #
    c = 299792.458
    dv = (logLam2[0] - logLam1[0]) * c  # km/s

    t = clock()

    pp = ppxf(templates, galaxy, noise, velscale, start, plot=plot, moments=moments, degree=-1, mdegree=10,
              vsyst=dv, clean=False, regul=1. / regul_err, reg_dim=reg_dim, component=component, bias=bias,
              quiet=quiet)

    print ('pPXF sol of bin {}: {}'.format(j, pp.sol))
    print ('pPXF error of bin {}: {}'.format(j, pp.error))

    hdu_best = fits.PrimaryHDU()
    hdu_best.data = pp.bestfit
    hdu_best.header['CD1_1'] = gal_hdr['CD1_1']
    hdu_best.header['CDELT1'] = gal_hdr['CD1_1']
    hdu_best.header['CRPIX1'] = gal_hdr['CRPIX1']
    hdu_best.header['CRVAL1'] = gal_hdr['CRVAL1']
    hdu_best.header['NAXIS1'] = pp.bestfit.size
    hdu_best.header['CTYPE1'] = 'LINEAR'  # corresponds to sampling of values above
    hdu_best.header['DC-FLAG'] = '1'  # 0 = linear, 1= log-linear sampling
    hdu_best.writeto(ppxf_bestfit_j, clobber=True)

    return pp
Пример #26
0
def emission_line_template(lines, velscale, res=2.54, intens=None, resamp=15, return_log=True):
    lines = np.atleast_1d(lines)
    if intens == None:
        intens = np.ones_like(lines) * 1e-5
    current_dir = os.getcwd()
    # Template directory is also set in setyp.py
    os.chdir(template_dir)
    refspec = [x for x in os.listdir(".") if x.endswith(".fits")][0]
    lamb = wavelength_array(refspec)
    delta = lamb[1] - lamb[0]
    lamb2 = np.linspace(lamb[0] - delta / 2.0, lamb[-1] + delta / 2.0, len(lamb + 1) * resamp)
    sigma = res / (2.0 * np.sqrt(2.0 * np.log(2.0)))
    spec = np.zeros_like(lamb2)
    for line, intensity in zip(lines, intens):
        spec += intensity * np.exp(-(lamb2 - line) ** 2 / (2 * sigma * sigma))
    spec = np.sum(spec.reshape(len(lamb), resamp), axis=1)
    if not return_log:
        return spec
    specNew, logLam2, velscale = util.log_rebin([lamb[0], lamb[-1]], spec, velscale=velscale)
    os.chdir(current_dir)
    return specNew
Пример #27
0
def run_ppxf(spectra, velscale):
    """ Run pPXF in a list of spectra"""
    print "Loading templates"
    templates, logLam2, delta = load_templates(velscale)
    for i, spec in enumerate(spectra):
        print "pPXF run of spectrum {0} ({1} of {2})".format(spec, i+1, 
              len(spectra))
        print "Preparing files..."
        # Read a galaxy spectrum and define the wavelength range
        hdu = pf.open(spec)
        spec_lin = hdu[0].data
        h1 = hdu[0].header
        lamRange1 = h1['CRVAL1'] + np.array([0.,h1['CDELT1']*(h1['NAXIS1']-1)])
        # Convolve our spectra to match MILES resolution
        FWHM_dif = np.sqrt(FWHM_tem**2 - FWHM_spec**2)
        sigma = FWHM_dif/2.355/delta # Sigma difference in pixels
        spec_lin = ndimage.gaussian_filter1d(spec_lin,sigma)
        # Rebin to logarithm scale
        galaxy, logLam1, velscale = util.log_rebin(lamRange1, spec_lin, 
                                                   velscale=velscale)
        noise = 0. * galaxy + 0.1
        dv = (logLam2[0]-logLam1[0])*c 
        start, goodPixels = read_setup_file(spec, logLam1)
        print "First interaction of pPXF.."
        pp0 = ppxf(templates, galaxy, noise, velscale, start,
                  goodpixels=goodPixels, plot=False, moments=4,
                  degree=6, mdegree=4, vsyst=dv)
        print "Calculating realistic noise for input..."
        rms0 = galaxy[goodPixels] - pp0.bestfit[goodPixels]
        noise0 = 1.4826 * np.median(np.abs(rms0 - np.median(rms0)))
        noise0 = 0. * galaxy + noise0
        print "Second run of pPXF..."
        pp = ppxf(templates, galaxy, noise0, velscale, pp0.sol,
                  goodpixels=goodPixels, plot=False, moments=4,
                  degree=6, mdegree=4, vsyst=dv, lam=lamRange1)
        print "Finished! Now saving results..."
        with open(spec.replace(".fits", ".pkl"), "w") as f:
            pickle.dump(pp, f)
    return
Пример #28
0
def w_temp(velscale):
    """ Make templates array"""
    current_dir = os.getcwd()
    os.chdir(template_dir)
    miles = [x for x in os.listdir(".") if x.endswith(".fits")]
    miles.sort()
    c = 299792.458
    FWHM_tem = 2.54  # MILES library spectra have a resolution FWHM of 2.54A.
    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pf.open(miles[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array(
        [0., h2['CDELT1'] * (h2['NAXIS1'] - 1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2,
                                               ssp,
                                               velscale=velscale)
    os.chdir(current_dir)
    return np.exp(logLam2)
Пример #29
0
def smooth_and_rebin(bc03,
                     bc03_lambda,
                     gal_lambda,
                     velscale,
                     FWHM_gal=1,
                     FWHM_tem=0):
    """
    Smooth and rebin the BC03 spectra based on the sampling 
    of the galaxy to be fitted.
    Input :
    - bc03 : the spectral templates
    - bc03_lambda : the template wavelength array
    - gal_lambda : the galaxy wavelength array, which the rebinning 
    is going to match. Note tha the galaxy must have already 
    been log-rebinned. 
    - velscale : velocity scale of the galaxy, for log rebinning
    - FWHM_gal : FWHM of the galaxy resolution
    - FWHM_tem : FWHM of the template resolution
    Output :
    - templates : the smoothed and rebinned version of the BC03 input
    """
    templates = np.empty(
        ((gal_lambda.size, ) + (bc03.shape[1], bc03.shape[2])))
    for i in range(bc03.shape[1]):
        for j in range(bc03.shape[2]):
            ssp = bc03[:, i, j]
            #resize the templates to the log-rebinned galaxy wavelengths
            new_ssp = np.interp(gal_lambda, bc03_lambda, ssp, right=0, left=0)
            #log-rebin the interpolated templates
            #the output velscape should be close to identical to the input
            #Likewise, logLam2 == np.log(gal_lambda) to about 1e-5
            sspNew, logLam2, velscale = util.log_rebin(
                [gal_lambda[0], gal_lambda[-1]], new_ssp, velscale=velscale)
            #smooth the log-rebinned templates
            FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
            sigma = FWHM_dif / 2.355 / np.diff(gal_lambda)[0]
            smoothed_ssp = ndimage.gaussian_filter1d(new_ssp, sigma)
            templates[:, i, j] = smoothed_ssp
    return templates
Пример #30
0
def emission_line_template(lines, velscale, res=2.54, intens=None, resamp=15,
                           return_log=True):
    lines = np.atleast_1d(lines)
    if intens == None:
        intens = np.ones_like(lines) * 1e-5
    current_dir = os.getcwd()
    # Template directory is also set in setyp.py
    os.chdir(template_dir)
    refspec = [x for x in os.listdir(".") if x.endswith(".fits")][0]
    lamb = wavelength_array(refspec)
    delta = lamb[1] - lamb[0]
    lamb2 = np.linspace(lamb[0]-delta/2., lamb[-1] + delta/2., len(lamb+1)*resamp)
    sigma = res / (2. * np.sqrt(2. * np.log(2.)))
    spec = np.zeros_like(lamb2)
    for line, intensity in zip(lines, intens):
        spec += intensity * np.exp(- (lamb2 - line)**2 / (2 * sigma * sigma))
    spec = np.sum(spec.reshape(len(lamb), resamp), axis=1)
    if not return_log:
        return spec
    specNew, logLam2, velscale = util.log_rebin([lamb[0], lamb[-1]], spec,
                                                   velscale=velscale)
    os.chdir(current_dir)
    return specNew
def subtract_besftfit(bin_sci, ppxf_bestfit, em_bin_sci):
    """
    """

    for j in range(len(glob.glob(bin_sci.format('*')))):
        if not os.path.exists(em_bin_sci.format(j)):

            with fits.open(bin_sci.format(j)) as hdu:
                odata = hdu[0].data
                ohdr = hdu[0].header

            bestfit = fits.getdata(ppxf_bestfit.format(j))

            lamRange = ohdr['CRVAL1'] + np.array([1. - ohdr['CRPIX1'], ohdr['NAXIS1'] - ohdr['CRPIX1']]) * ohdr['CD1_1']

            # Log bin the spectra to match the best fit absorption template
            galaxy, logLam, velscale = util.log_rebin(lamRange, odata)

            ems_fit = np.subtract(galaxy, bestfit)

            ems_hdu = fits.PrimaryHDU()
            ems_hdu.data = ems_fit
            ems_hdu.header = fits.getheader(bin_sci.format(j), 0)
            ems_hdu.writeto(em_bin_sci.format(j))
def setup_spectral_library(velscale, FWHM_gal):

    # Read the list of filenames from the Single Stellar Population library
    # by Vazdekis et al. (2010, MNRAS, 404, 1639) http://miles.iac.es/.
    #
    # For this example I downloaded from the above website a set of
    # model spectra with default linear sampling of 0.9A/pix and default
    # spectral resolution of FWHM=2.51A. I selected a Salpeter IMF
    # (slope 1.30) and a range of population parameters:
    #
    #     [M/H] = [-1.71, -1.31, -0.71, -0.40, 0.00, 0.22]
    #     Age = np.linspace(np.log10(1), np.log10(17.7828), 26)
    #
    # This leads to a set of 156 model spectra with the file names like
    #
    #     Mun1.30Zm0.40T03.9811.fits
    #
    # IMPORTANT: the selected models form a rectangular grid in [M/H]
    # and Age: for each Age the spectra sample the same set of [M/H].
    #
    # We assume below that the model spectra have been placed in the
    # directory "miles_models" under the current directory.
    #
    vazdekis = glob.glob('miles_models/Mun1.30*.fits')
    vazdekis.sort()
    FWHM_tem = 2.51  # Vazdekis+10 spectra have a resolution FWHM of 2.51A.

    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SDSS galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = fits.open(vazdekis[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange_temp = h2['CRVAL1'] + np.array(
        [0., h2['CDELT1'] * (h2['NAXIS1'] - 1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange_temp,
                                               ssp,
                                               velscale=velscale)

    # Create a three dimensional array to store the
    # two dimensional grid of model spectra
    #
    nAges = 26
    nMetal = 6
    templates = np.empty((sspNew.size, nAges, nMetal))

    # Convolve the whole Vazdekis library of spectral templates
    # with the quadratic difference between the SDSS and the
    # Vazdekis instrumental resolution. Logarithmically rebin
    # and store each template as a column in the array TEMPLATES.

    # Quadratic sigma difference in pixels Vazdekis --> SDSS
    # The formula below is rigorously valid if the shapes of the
    # instrumental spectral profiles are well approximated by Gaussians.
    #
    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    sigma = FWHM_dif / 2.355 / h2['CDELT1']  # Sigma difference in pixels

    # These are the array where we want to store
    # the characteristics of each SSP model
    #
    logAge_grid = np.empty((nAges, nMetal))
    metal_grid = np.empty((nAges, nMetal))

    # These are the characteristics of the adopted rectangular grid of SSP models
    #
    logAge = np.linspace(np.log10(1), np.log10(17.7828), nAges)
    metal = [-1.71, -1.31, -0.71, -0.40, 0.00, 0.22]

    # Here we make sure the spectra are sorted in both [M/H]
    # and Age along the two axes of the rectangular grid of templates.
    # A simple alphabetical ordering of Vazdekis's naming convention
    # does not sort the files by [M/H], so we do it explicitly below
    #
    metal_str = ['m1.71', 'm1.31', 'm0.71', 'm0.40', 'p0.00', 'p0.22']
    for k, mh in enumerate(metal_str):
        files = [s for s in vazdekis if mh in s]
        for j, filename in enumerate(files):
            hdu = fits.open(filename)
            ssp = hdu[0].data
            ssp = ndimage.gaussian_filter1d(ssp, sigma)
            sspNew, logLam2, velscale = util.log_rebin(lamRange_temp,
                                                       ssp,
                                                       velscale=velscale)
            templates[:, j, k] = sspNew  # Templates are *not* normalized here
            logAge_grid[j, k] = logAge[j]
            metal_grid[j, k] = metal[k]

    return templates, lamRange_temp, logAge_grid, metal_grid
Пример #33
0
    def get_templates(self, galaxy, velscale=None, use_all_temp=False):
        import glob  # for searching for files
        if self.library == 'vazdekis':
            templateFiles = glob.glob(
                '%s/libraries/python/ppxf/spectra/Rbi1.30z*.fits' %
                (cc.home_dir))

            f = fits.open(templateFiles[0])
            v2 = f[0].data
            self.wav = np.arange(f[0].header['NAXIS1'])*f[0].header['CDELT1'] + \
             f[0].header['CRVAL1']

            # Using same keywords as fits headers
            CRVAL_temp = f[0].header['CRVAL1']  # starting wavelength
            NAXIS_temp = f[0].header['NAXIS1']  # Number of entries
            # wavelength increments (resolution?)
            CDELT_temp = f[0].header['CDELT1']
            f.close()

            self.lamRange_template = CRVAL_temp + np.array(
                [0, CDELT_temp * (NAXIS_temp - 1)])

            log_temp_template, self.logLam_template, self.velscale = \
             util.log_rebin(self.lamRange_template, self.wav)#, velscale=velscale)

            self.ntemp = len(templateFiles)
            self.templatesToUse = np.arange(self.ntemp)

            self.templates = np.zeros((len(log_temp_template), self.ntemp))
            self.lin_templates = np.zeros(
                (len(f[0].header['NAXIS1']), self.ntemp))

            ## Reading the contents of the files into the array templates.
            ## Including rebinning them.
            for i in range(self.ntemp):
                f = fits.open(templateFiles[i])
                self.lin_templates[:, i] = f[0].data
                f.close()
                if self.FWHM_tem < self.FWHM_gal:
                    sigma = self.FWHM_dif / 2.355 / CDELT_temp  # Sigma difference (px)
                    conv_temp = ndimage.gaussian_filter1d(
                        self.lin_templates[:, i], sigma)
                else:
                    conv_temp = self.lin_templates[:, i]
                ## Rebinning templates logarthmically
                log_temp_template, self.logLam_template, _ = util.log_rebin(
                    self.lamRange_template,
                    conv_temp)  #, velscale=self.velscale)
                self.templates[:, i] = log_temp_template

        elif self.library == 'Miles':  # Miles stars
            # Finding the template files
            # There is some issue with the memory structure of the university macs
            # (HFS+), meaning these templates can only be loaded once if located on
            # the home directory, but more if on the Data partition...
            if cc.device != 'uni':
                templateFiles = glob.glob(
                    '%s/models/miles_library/m0[0-9][0-9][0-9]V' %
                    (cc.home_dir))
            else:
                templateFiles = glob.glob(
                    '%s/Data/' % (cc.base_dir) +
                    'idl_libraries/ppxf/MILES_library/m0[0-9][0-9][0-9]V')

            # self.wav is wavelength, v2 is spectrum
            self.wav, v2 = np.loadtxt(templateFiles[0], unpack='True')

            # Using same keywords as fits headers
            CRVAL_temp = self.wav[0]  # starting wavelength
            NAXIS_temp = np.shape(v2)[0]  # Number of entries
            # wavelength increments (resolution?)
            CDELT_temp = (self.wav[NAXIS_temp - 1] -
                          self.wav[0]) / (NAXIS_temp - 1)

            self.lamRange_template = CRVAL_temp + np.array(
                [0, CDELT_temp * (NAXIS_temp - 1)])

            log_temp_template, self.logLam_template, self.velscale = \
             util.log_rebin(self.lamRange_template, self.wav, velscale=velscale)

            if use_all_temp or galaxy is None:
                self.ntemp = len(templateFiles)
                self.templatesToUse = np.arange(self.ntemp)
            else:
                self.templatesToUse = use_templates(galaxy,
                                                    cc.device == 'glamdring')
                self.ntemp = len(self.templatesToUse)
            self.templates = np.zeros((len(log_temp_template), self.ntemp))
            self.lin_templates = np.zeros((len(v2), self.ntemp))

            ## Reading the contents of the files into the array templates.
            ## Including rebinning them.
            for i in range(self.ntemp):
                if use_all_temp:
                    _, self.lin_templates[:, i] = np.loadtxt(templateFiles[i],
                                                             unpack='True')
                else:
                    _, self.lin_templates[:, i] = np.loadtxt(
                        templateFiles[self.templatesToUse[i]], unpack='True')
                if self.FWHM_tem < self.FWHM_gal:
                    sigma = self.FWHM_dif / 2.355 / CDELT_temp  # Sigma difference (px)
                    conv_temp = ndimage.gaussian_filter1d(
                        self.lin_templates[:, i], sigma)
                else:
                    conv_temp = self.lin_templates[:, i]
                ## Rebinning templates logarthmically
                log_temp_template, self.logLam_template, _ = util.log_rebin(
                    self.lamRange_template, conv_temp, velscale=self.velscale)
                self.templates[:, i] = log_temp_template
def remove_emission_lines(bin_sci, ppxf_bestfit, abs_bin_sci, plot=True, bad_lines=[]):
    """
    Fit the absorption spectra with a pVoight function by parameterizing the bestfit template as output from pPXF,
    fit the emission lines over the absorption features with a sum of a gaussian and lorentz and subtract from the
    original spectra. Where the emission lines are isolated, just interpolate the continuum values from the best fit
    template and replace.
    This requires a very good fit between the galaxy spectra and the bestfit spectra. I recommend running this with
    plot=True to check for any residuals.
    """

    for j in range(len(glob.glob(bin_sci.format('*')))):

        bin_sci_j = bin_sci.format(j)
        ppxf_bestfit_j = ppxf_bestfit.format(j)

        if not os.path.exists(abs_bin_sci.format(j)):

            if plot:
                print('>>>>> Removing emission lines from spectra {}'.format(j))

            with fits.open(bin_sci_j) as hdu:
                odata = hdu[0].data
                ohdr = hdu[0].header

            bestfit = fits.getdata(ppxf_bestfit_j)

            lamRange = ohdr['CRVAL1'] + np.array([1. - ohdr['CRPIX1'], ohdr['NAXIS1'] - ohdr['CRPIX1']]) * ohdr['CD1_1']
            lin_bins = np.linspace(lamRange[0], lamRange[1], ohdr['NAXIS1'])

            # Log bin the spectra to match the best fit absorption template
            galaxy, logLam1, velscale = util.log_rebin(lamRange, odata)
            log_bins = np.exp(logLam1)
            emlns, lnames, lwave = util.emission_lines(logLam1, lamRange, 2.3)

            # Hgamma 4340.47, Hbeta 4861.33, OIII [4958.92, 5006.84]
            # lwave = [4340.47, 4861.33, 4958.92, 5006.84]

            # find the index of the emission lines
            iHg = (np.abs(log_bins - lwave[0])).argmin()
            iHb = (np.abs(log_bins - lwave[1])).argmin()
            iOIII = (np.abs(log_bins - lwave[2])).argmin()
            iOIIIb = (np.abs(log_bins - (lwave[2] - 47.92))).argmin()

            # There are BOTH absorption and emission features about the wavelength of Hgamma and Hbeta, so we need
            # to use a specialized fitting function (convolved Guassian and Lorentzian -> pVoight) to remove the
            # emission lines
            popt_Hg, pcov_Hg = remove_lines.fit_ems_pvoightcont(log_bins, galaxy, lin_bins, odata, iHg, bestfit)
            popt_Hb, pcov_Hb = remove_lines.fit_ems_pvoightcont(log_bins, galaxy, lin_bins, odata, iHb, bestfit)

            em_fit = remove_lines.gauss_lorentz(lin_bins, popt_Hg[0], popt_Hg[1], popt_Hg[2], popt_Hg[3], popt_Hg[4],
                                                popt_Hg[5]) + \
                     remove_lines.gauss_lorentz(lin_bins, popt_Hb[0], popt_Hb[1], popt_Hb[2], popt_Hb[3], popt_Hb[4],
                                                popt_Hb[5])

            abs_feat_fit = odata - em_fit

            abs_fit = remove_lines.em_chop(lin_bins, abs_feat_fit, iOIII, log_bins, bestfit)
            abs_fit = remove_lines.em_chop(lin_bins, abs_fit, iOIIIb, log_bins, bestfit)

            for lin in bad_lines:
                ibad = (np.abs(lin_bins - lin)).argmin()
                abs_fit = remove_lines.em_chop(lin_bins, abs_fit, ibad, log_bins, bestfit)

            if plot:
                plt.plot(lin_bins, odata, '-k', label="spectra")
                # plt.plot(lin_bins, bestfit, '--r', label="bestfit absorption line")
                plt.plot(lin_bins, abs_fit, '-b', label="absorption spectra")
                plt.legend()
                plt.show()

            abs_hdu = fits.PrimaryHDU()
            abs_hdu.data = abs_fit
            abs_hdu.header = fits.getheader(bin_sci.format(j), 0)
            abs_hdu.writeto(abs_bin_sci.format(j))
Пример #35
0
def ppxf_example_simulation():

    file_dir = path.dirname(path.realpath(__file__))  # path of this procedure

    hdu = fits.open(file_dir + '/veltemps/bd-013097_M2III_rebinflux_rest.fits'
                    )  # BUCKET: which star should I choose???
    # '/miles_models/Mun1.30Zp0.00T12.5893_iPp0.00_baseFe_linear_FWHM_2.51.fits')  # Solar metallicitly, Age=12.59 Gyr
    ssp = hdu[
        1].data  # hdu[1] is science header for us; hdu[0] is generic header
    h = hdu[1].header

    lamRange = h['CRVAL1'] + np.array([0., h['CD1_1'] * (h['NAXIS1'] - 1)])
    c = 299792.458  # speed of light in km/s
    velscale = c * h['CD1_1'] / max(
        lamRange)  # Do not degrade original velocity sampling
    star, logLam, velscale = util.log_rebin(lamRange, ssp, velscale=velscale)

    # The finite sampling of the observed spectrum is modeled in detail:
    # the galaxy spectrum is obtained by oversampling the actual observed spectrum
    # to a high resolution. This represent the true spectrum, which is later resampled
    # to lower resolution to simulate the observations on the CCD. Similarly, the
    # convolution with a well-sampled LOSVD is done on the high-resolution spectrum,
    # and later resampled to the observed resolution before fitting with PPXF.

    factor = 10  # Oversampling integer factor for an accurate convolution
    starNew = ndimage.interpolation.zoom(
        star, factor,
        order=3)  # This is the underlying spectrum, known at high resolution
    star = rebin(
        starNew, factor
    )  # Make sure that the observed spectrum is the integral over the pixels

    # find worst SNR, and worst h3, h4 (highest)
    h3 = 0.1  # Adopted G-H parameters of the LOSVD
    h4 = 0.04  # 0.1
    sn = 30.  # Adopted S/N of the Monte Carlo simulation
    m = 300  # Number of realizations of the simulation
    moments = 4
    velV = np.random.rand(
        m
    )  # velocity in *pixels* [=V(km/s)/velScale]  # (len m array of random on [0, 1)
    sigmaV = np.linspace(
        0.5, 4, m
    )  # Range of sigma in *pixels* [=sigma(km/s)/velScale]  # m evenly spaced [0.5,...,4]

    result = np.zeros((m, moments))  # This will store the results
    t = clock()

    for j, (vel, sigma) in enumerate(zip(velV, sigmaV)):

        dx = int(
            abs(vel) +
            5 * sigma)  # Sample the Gaussian and GH at least to vel+5*sigma
        x = np.linspace(
            -dx, dx, 2 * dx * factor +
            1)  # Evaluate the Gaussian using steps of 1/factor pixels.
        w = (x - vel) / sigma
        w2 = w**2
        gauss = np.exp(-0.5 * w2)
        gauss /= np.sum(gauss)  # Normalized total(gauss)=1
        h3poly = w * (2. * w2 - 3.) / np.sqrt(3.)  # H3(y)
        h4poly = (w2 * (4. * w2 - 12.) + 3.) / np.sqrt(24.)  # H4(y)
        losvd = gauss * (1. + h3 * h3poly + h4 * h4poly)

        galaxy = signal.fftconvolve(
            starNew, losvd, mode="same")  # Convolve the oversampled spectrum
        # FFT convolution: multiplication in the frequency domain corresponds to convolution in the time domain
        galaxy = rebin(
            galaxy, factor)  # Integrate spectrum into original spectral pixels
        noise = galaxy / sn  # 1sigma error spectrum
        galaxy = np.random.normal(galaxy,
                                  noise)  # Add noise to the galaxy spectrum
        start = np.array([
            vel + np.random.uniform(-1, 1),
            sigma * np.random.uniform(0.8, 1.2)
        ]) * velscale  # Convert to km/s

        pp = ppxf(star,
                  galaxy,
                  noise,
                  velscale,
                  start,
                  goodpixels=np.arange(dx, galaxy.size - dx),
                  plot=False,
                  moments=moments,
                  bias=0.4)  # 0.2
        result[j, :] = pp.sol

    print('Calculation time: %.2f s' % (clock() - t))

    # large scale kinematics to estimate dark matter fraction within effective radii, and stellar mass-light ratio
    # mass distribution discribed by GME and dark matter dstribution different
    # work with sarah to use JAM; figure out why we ever use schwarzschild model if JAM is faster (what assumptions are
    # we making/what regimes do we have to be in to use JAM?

    plt.clf()
    plt.subplot(221)
    plt.plot(sigmaV * velscale, result[:, 0] - velV * velscale,
             '+k')  # BUCKET: why is V multiplied by velscale?
    plt.axhline(0, color='r')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-20, 20)
    plt.xlabel(r'$\sigma_{\rm in}\ (km\ s^{-1})$')
    plt.ylabel(r'$V - V_{\rm in}\ (km\ s^{-1})$')
    plt.text(2.05 * velscale, -15, r'2$\times$velscale')

    plt.subplot(222)
    plt.plot(sigmaV * velscale, result[:, 1] - sigmaV * velscale,
             '+k')  # BUCKET: why is sigma multiplied by velscale?
    plt.axhline(0, color='r')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-20, 20)
    plt.xlabel(r'$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel(r'$\sigma - \sigma_{\rm in}\ (km\ s^{-1})$')
    plt.text(2.05 * velscale, -15, r'2$\times$velscale')

    plt.subplot(223)
    plt.plot(sigmaV * velscale, result[:, 2], '+k')
    plt.axhline(h3, color='r')
    plt.axhline(0, linestyle='dotted', color='limegreen')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-0.2 + h3, 0.2 + h3)
    plt.xlabel(r'$\sigma_{\rm in}\ (km\ s^{-1})$')
    plt.ylabel('$h_3$')
    plt.text(2.05 * velscale, h3 - 0.15, r'2$\times$velscale')

    plt.subplot(224)
    plt.plot(sigmaV * velscale, result[:, 3], '+k')
    plt.axhline(h4, color='r')
    plt.axhline(0, linestyle='dotted', color='limegreen')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-0.2 + h4, 0.2 + h4)
    plt.xlabel(r'$\sigma_{\rm in}\ (km\ s^{-1})$')
    plt.ylabel('$h_4$')
    plt.text(2.05 * velscale, h4 - 0.15, r'2$\times$velscale')

    plt.tight_layout()
    plt.show()  # pause(1)
def ppxf_example_two_components():

    file_dir = path.dirname(path.realpath(__file__))  # path of this procedure

    hdu = fits.open(file_dir + '/miles_models/Mun1.30Zp0.00T12.5893.fits'
                    )  # Solar metallicitly, Age=12.59 Gyr
    gal_lin = hdu[0].data
    h1 = hdu[0].header
    lamRange1 = h1['CRVAL1'] + np.array(
        [0., h1['CDELT1'] * (h1['NAXIS1'] - 1)])
    c = 299792.458  # speed of light in km/s
    velscale = c * h1['CDELT1'] / max(
        lamRange1)  # Do not degrade original velocity sampling
    model1, logLam1, velscale = util.log_rebin(lamRange1,
                                               gal_lin,
                                               velscale=velscale)
    model1 /= np.median(model1)

    hdu = fits.open(file_dir + '/miles_models/Mun1.30Zp0.00T01.0000.fits'
                    )  # Solar metallicitly, Age=1.00 Gyr
    gal_lin = hdu[0].data
    model2, logLam1, velscale = util.log_rebin(lamRange1,
                                               gal_lin,
                                               velscale=velscale)
    model2 /= np.median(model2)

    model = np.column_stack([model1, model2])
    galaxy = np.empty_like(model)

    # These are the input values in spectral pixels
    # for the (V,sigma) of the two kinematic components
    #
    vel = np.array([0., 250.]) / velscale
    sigma = np.array([200., 100.]) / velscale

    # The synthetic galaxy model consists of the sum of two
    # SSP spectra with age of 1Gyr and 13Gyr respectively
    # with different velocity and dispersion
    #
    for j in range(len(vel)):
        dx = int(abs(vel[j]) +
                 4. * sigma[j])  # Sample the Gaussian at least to vel+4*sigma
        v = np.linspace(-dx, dx, 2 * dx + 1)
        losvd = np.exp(-0.5 * ((v - vel[j]) / sigma[j])**2)  # Gaussian LOSVD
        losvd /= np.sum(losvd)  # normaize LOSVD
        galaxy[:, j] = signal.fftconvolve(model[:, j], losvd, mode="same")
        galaxy[:, j] /= np.median(model[:, j])
    galaxy = np.sum(galaxy, axis=1)
    sn = 100.
    noise = galaxy / sn
    galaxy = np.random.normal(galaxy, noise)  # add noise to galaxy

    # Adopts two templates per kinematic component
    #
    templates = np.column_stack([model1, model2, model1, model2])

    # Start both kinematic components from the same guess.
    # With multiple stellar kinematic components
    # a good starting guess is essential
    #
    start = [np.mean(vel) * velscale, np.mean(sigma) * velscale]
    start = [start, start]
    goodPixels = np.arange(20, 6000)

    t = clock()

    plt.clf()
    plt.subplot(211)
    plt.title("Two components pPXF fit")
    print("+++++++++++++++++++++++++++++++++++++++++++++")

    pp = ppxf(templates,
              galaxy,
              noise,
              velscale,
              start,
              goodpixels=goodPixels,
              plot=True,
              degree=4,
              moments=[2, 2],
              component=[0, 0, 1, 1])

    plt.subplot(212)
    plt.title("Single component pPXF fit")
    print("---------------------------------------------")

    start = start[0]
    pp = ppxf(templates,
              galaxy,
              noise,
              velscale,
              start,
              goodpixels=goodPixels,
              plot=True,
              degree=4,
              moments=2)

    print("=============================================")
    print("Total elapsed time %.2f s" % (clock() - t))

    plt.tight_layout()
    plt.pause(1)
Пример #37
0
def run_ppxf(spectra, velscale, ncomp=None, has_emission=True, mdegree=-1,
             degree=20, plot=False, sky=None, start=None, moments=None,
             log_dir=None, w1=4000., w2=7000.):
    """ Run pPXF in a list of spectra"""
    if isinstance(spectra, str):
        spectra = [spectra]
    ##########################################################################
    # Load templates for both stars and gas
    star_templates = pf.getdata(os.path.join(templates_dir,
                                             'miles_FWHM_3.7.fits'), 0)
    logLam2 = pf.getdata(os.path.join(templates_dir, 'miles_FWHM_3.7.fits'), 1)
    miles = np.loadtxt(os.path.join(templates_dir, 'miles_FWHM_3.7.txt'),
                       dtype=str).tolist()
    gas_templates = pf.getdata(os.path.join(templates_dir,
                                             'emission_FWHM_3.7.fits'), 0)
    logLam_gas = pf.getdata(os.path.join(templates_dir, 'emission_FWHM_3.7.fits'),
                            1)
    gas_files = np.loadtxt(os.path.join(templates_dir, 'emission_FWHM_3.7.txt'),
                       dtype=str).tolist()

    ngas = len(gas_files)
    ntemplates = len(miles)
    ##########################################################################
    # Join templates in case emission lines are used.
    if has_emission:
        templates = np.column_stack((star_templates, gas_templates))
        templates_names = np.hstack((miles, gas_files))
    else:
        templates = star_templates
        templates_names = miles
        ngas = 0
    ##########################################################################
    if sky == None:
        nsky = 0
    else:
        nsky = sky.shape[1]
    if ncomp == 1:
        components = 0
    elif ncomp == 2:
        components = np.hstack((np.zeros(len(star_templates[0])),
                                np.ones(len(gas_templates[0]))))
    if moments == None:
        moments = [4] if ncomp == 1 else [4,2]
    for i, spec in enumerate(spectra):
        print "pPXF run of spectrum {0} ({1} of {2})".format(spec, i+1,
              len(spectra))
        plt.clf()
        ######################################################################
        # Read galaxy spectrum and define the wavelength range
        hdu = pf.open(spec)
        spec_lin = hdu[0].data
        h1 = pf.getheader(spec)
        lamRange1 = h1['CRVAL1'] + np.array([0.,h1['CDELT1']*(h1['NAXIS1']-1)])
        ######################################################################
        # Rebin to log scale
        galaxy, logLam1, velscale = util.log_rebin(lamRange1, spec_lin, 
                                                   velscale=velscale)
        ######################################################################
        # First guess for the noise
        noise = np.ones_like(galaxy) * np.std(galaxy - medfilt(galaxy, 5))
        ######################################################################
        # Calculate difference of velocity between spectrum and templates
        # due to different initial wavelength
        dv = (logLam2[0]-logLam1[0])*c
        ######################################################################
        # Set first guess from setup files
        if start is None:
            start = [v0s[spec.split("_")[0]], 50]
            goodPixels = None
        ######################################################################
        # Expand start variable to include multiple components
        if ncomp > 1:
            start = [start, [start[0], 30]]
        ######################################################################
        # Select goodpixels
        w = np.exp(logLam1)
        goodpixels = np.argwhere((w>w1) & (w<w2)).T[0]
        # First pPXF interaction
        pp0 = ppxf(templates, galaxy, noise, velscale, start,
                   goodpixels=goodpixels, plot=False, moments=moments,
                   degree=degree, mdegree=mdegree, vsyst=dv, component=components,
                   sky=sky)
        rms0 = galaxy[goodpixels] - pp0.bestfit[goodpixels]
        noise0 = 1.4826 * np.median(np.abs(rms0 - np.median(rms0)))
        noise0 = np.zeros_like(galaxy) + noise0
        # Second pPXF interaction, realistic noise estimation
        pp = ppxf(templates, galaxy, noise0, velscale, start,
                  goodpixels=goodpixels, plot=False, moments=moments,
                  degree=degree, mdegree=mdegree, vsyst=dv,
                  component=components, sky=sky)
        plt.title(spec.replace("_", "-"))
        plt.show(block=False)
        plt.savefig("{1}/{0}".format(spec.replace(".fits", ".png"), log_dir))
        ######################################################################
        # Adding other things to the pp object
        pp.template_files = templates_names
        pp.has_emission = has_emission
        pp.dv = dv
        pp.w = w
        pp.velscale = velscale
        pp.spec = spec
        pp.ngas = ngas
        pp.ntemplates = ntemplates
        pp.nsky = nsky
        pp.templates = 0
        ######################################################################
        # Save fit to pickles file to keep session
        ppsave(pp, "{1}/{0}".format(spec.replace(".fits", ""), log_dir))
        pp = ppload("{1}/{0}".format(spec.replace(".fits", ""), log_dir))
        ######################################################################
        ppf = pPXF(spec, velscale, pp)
        ppf.plot("{1}/{0}".format(spec.replace(".fits", ".png"), log_dir))
        ######################################################################
        # # Save to output text file
        # if ncomp > 1:
        #     pp.sol = pp.sol[0]
        #     pp.error = pp.error[0]
        # sol = [val for pair in zip(pp.sol, pp.error) for val in pair]
        # sol = ["{0:12s}".format("{0:.3g}".format(x)) for x in sol]
        # sol.append("{0:12s}".format("{0:.3g}".format(pp0.chi2)))
        # sol = ["{0:30s}".format(spec)] + sol
    return
Пример #38
0
def interface_sets(nstart, nend):

    full_time = clock()

    ####### setting up some variables for magnitudes and indices calculation ########

    c = 299792.458

    filter_list = 'sdss_manga_pipeline.res'
    zero_point = 'AB'
    redshift = 0.0

    indices_list = 'MaNGA_range.def'

    print('     > gathering info')

    ######## setting up directories and files ########

    data_dir = '/mnt/lustre/smg/stellar_libraries/MaNGA/'
    output_dir = '/mnt/lustre/smg/stellar_libraries/MaNGA/parameters/she-ra/beta_tests/combo_test/'

    file_spectra = 'MaStar_spectra_ebv_gaia_rb_isopars'

    ##### templates information #####

    templates_dir = '/mnt/lustre/smg/stellar_libraries/atlas9marcs/'
    templates_parameters = 'templates_grid_parameters_R2000.fits'

    header = fits.open(templates_dir + templates_parameters)

    templ_id, templ_teff, templ_logg, templ_metal = header[1].data[
        'NAME'], header[1].data['TEFF'], header[1].data['LOGG'], header[
            1].data['METAL']
    templ_gmag, templa_rmag, templ_imag = header[1].data['Gmag'], header[
        1].data['Rmag'], header[1].data['Imag']

    tot_templ = len(templ_id)

    estimate_teff = interp1d(templ_gmag - templ_imag,
                             templ_teff,
                             bounds_error=False,
                             fill_value='extrapolate')

    ######## reading spectra file ########

    print('     > reading information from the spectra file')

    header = fits.open(data_dir + 'spectra/' + file_spectra + '.fits')

    mangaid, mastarid, starid = header[1].data['mangaid'], header[1].data[
        'mastarid'], header[1].data['id']
    plate, ifudesign, mjd = header[1].data['plate'], header[1].data[
        'ifudesign'], header[1].data['mjd']
    ra, dec = header[1].data['objra'], header[1].data['objdec']
    wave, flux = header[1].data['wave'], header[1].data['flux']

    minlogg = header[1].data['minlogg']
    bad_info = np.where(minlogg <= -8)
    minlogg[bad_info] = 'NaN'

    nspectra = int(header[1].header['naxis2'])

    naxis1 = int(np.shape(wave)[1])

    crval1 = min(wave[0, :])
    crval2 = max(wave[0, :])
    cdelt1 = abs(crval1 - crval2) / naxis1

    new_wave = np.linspace(start=crval1, stop=crval2, num=naxis1)

    ######## setting up arrays ########

    parameters = np.zeros((nspectra, 9))
    selected_parameters = np.zeros((nspectra, 3))
    ppxf_info = np.zeros((nspectra, 3))

    indices = np.zeros((nspectra, 42))
    mags = np.zeros((nspectra, 5))

    #############################################################################################################################################

    ######## running things for each spectrum ########

    print('     > working on each spectrum')

    for i in range(nstart, nend + 1):

        start_time = clock()

        new_flux = np.interp(new_wave, wave[i, :], flux[i, :])
        new_flux = new_flux * 1e-17  # to have 10^-17 erg/s/cm2/Angstrom as units

        ######## calculating the E(B-V) from Schlegel+98 as a function of coordinates ########

        print('          > calculating the E(B-V) from Schlegel+98')
        ebv = get_dust_radec(ra[i], dec[i], 'ebv')

        ######## calculating the reddening as a function of wavelength ########

        print('          > calculating the reddening')
        reddening = dust_allen_py(ebv, new_wave)

        ######## in order to correct, the flux needs to be divided by the reddening ########

        corrected_flux = new_flux / reddening

        bad_flux = np.isnan(corrected_flux) | np.isinf(corrected_flux) | (
            corrected_flux <= 0.0)
        corrected_flux[bad_flux] = 0.0

        ######## calculating the indices ########
        print(
            '          > calculating indices within the MaNGA wavelength range'
        )
        indices[i, :], err_indices = calculate_indices(new_wave,
                                                       corrected_flux,
                                                       indices_list,
                                                       mastarid[i],
                                                       ef=0,
                                                       rv=0,
                                                       plot=False,
                                                       sim=False)

        ######## calculating the magnitudes ########
        print('          > calculating SDSS magnitudes')
        mags[i, :] = calculate_magnitudes(new_wave, corrected_flux,
                                          filter_list, zero_point, redshift)

        ######## calculating the first guess for the stellar parameters ########

        print(
            '          > calculating the first set of teff, logg, and metallicity'
        )

        parameters[i, 0] = estimate_teff(
            mags[i, 1] - mags[i, 3])  # Teff as a function of (g-i)
        parameters[i, 1] = minlogg[i]  # from isoparsfit - isochrone fitting
        parameters[i, 2] = -1.0  # open metallicity

        bad_data = np.isnan(parameters[i, 0]) | np.isinf(
            parameters[i, 0]) | np.isnan(parameters[i, 1]) | np.isinf(
                parameters[i, 1]) | np.isnan(parameters[i, 2]) | np.isinf(
                    parameters[i, 2])
        if bad_data:
            parameters[i, :] = -999
            ppxf_info[i, :] = -999
            ##### making a preliminary output file #####
            print('          > making a preliminary output file')
            f = open(output_dir + 'prelim_output/' + mastarid[i] + '_she-ra',
                     'w')
            f.write('%r %r %r %i %i %i %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n' \
                    %(mangaid[i], mastarid[i], starid[i], \
                    plate[i], ifudesign[i], mjd[i], \
                    ra[i],dec[i], \
                    parameters[i,0],parameters[i,1],parameters[i,2], \
                    parameters[i,3],parameters[i,4],parameters[i,5], \
                    parameters[i,6],parameters[i,7],parameters[i,8], \
                    ppxf_info[i,0], ppxf_info[i,1], ppxf_info[i,2], \
                    mags[i,0], mags[i,1], mags[i,2], mags[i,3], mags[i,4], \
                    indices[i,0], indices[i,1], indices[i,2], indices[i,3], indices[i,4], \
                    indices[i,5], indices[i,6], indices[i,7], indices[i,8], indices[i,9], \
                    indices[i,10], indices[i,11], indices[i,12], indices[i,13], indices[i,14], \
                    indices[i,15], indices[i,16], indices[i,17], indices[i,18], indices[i,19], \
                    indices[i,20], indices[i,21], indices[i,22], indices[i,23], indices[i,24], \
                    indices[i,25], indices[i,26], indices[i,27], indices[i,28], indices[i,29], \
                    indices[i,30], indices[i,31], indices[i,32], indices[i,33], indices[i,34], \
                    indices[i,35], indices[i,36], indices[i,37], indices[i,38], indices[i,39], \
                    indices[i,40], indices[i,41]))
            f.close()
            print('     > spectrum ' + str(i) + ' done')
            continue

        print('               > Teff  = ' + str(parameters[i, 0]) + ' K')
        print('               > logg  = ' + str(parameters[i, 1]) + ' dex')
        print('               > metal = ' + str(parameters[i, 2]) +
              ' dex')  # not a real prior

        ######## calculating the second guess for the stellar parameters ########

        if (parameters[i, 0] >= 12000): teff_guess = 2000
        if (parameters[i, 0] < 12000): teff_guess = 1000

        logg_guess = 0.80  # fixed value
        metal_guess = 2.00  # open metallicity

        selected_parameters[i, 0] = parameters[i, 0]
        selected_parameters[i, 1] = parameters[i, 1]
        selected_parameters[i, 2] = parameters[i, 2]

        if (parameters[i, 0] <= min(templ_teff)):
            selected_parameters[i, 0] = min(templ_teff) + teff_guess
        if (parameters[i, 0] >= max(templ_teff)):
            selected_parameters[i, 0] = max(templ_teff) - teff_guess

        if ((parameters[i, 0] >= 12000) & (parameters[i, 1] <= 3.5)):
            selected_parameters[i, 1] = 3.5
        if ((parameters[i, 0] >= 8000) & (parameters[i, 0] <= 12000) &
            (parameters[i, 1] <= 2.0)):
            selected_parameters[i, 1] = 2.5
        if ((parameters[i, 0] >= 6000) & (parameters[i, 0] <= 8000) &
            (parameters[i, 1] <= 1.0)):
            selected_parameters[i, 1] = 1.5
        if ((parameters[i, 0] >= 2500) & (parameters[i, 0] <= 6000) &
            (parameters[i, 1] <= 0.0)):
            selected_parameters[i, 1] = 0.0
        if ((parameters[i, 0] >= 2500) & (parameters[i, 0] <= 12000) &
            (parameters[i, 1] >= 5.0)):
            selected_parameters[i, 1] = 5.0

        if (parameters[i, 2] <= min(templ_metal)):
            selected_parameters[i, 2] = min(templ_metal) + metal_guess
        if (parameters[i, 2] >= max(templ_metal)):
            selected_parameters[i, 2] = max(templ_metal) - metal_guess

        ok_set = np.where(
            (np.abs(templ_teff - selected_parameters[i, 0]) <= teff_guess)
            & (np.abs(templ_logg - selected_parameters[i, 1]) <= logg_guess)
            & (np.abs(templ_metal - selected_parameters[i, 2]) <= metal_guess))

        templ_set_id = templ_id[ok_set]
        templ_set_teff = templ_teff[ok_set]
        templ_set_logg = templ_logg[ok_set]
        templ_set_metal = templ_metal[ok_set]

        if not templ_set_id.size:
            parameters[i, 3] = -999
            parameters[i, 4] = -999
            parameters[i, 5] = -999
            parameters[i, 6] = -999
            parameters[i, 7] = -999
            parameters[i, 8] = -999
            ##### making a preliminary output file #####
            print('          > making a preliminary output file')
            f = open(output_dir + 'prelim_output/' + mastarid[i] + '_she-ra',
                     'w')
            f.write('%r %r %r %i %i %i %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n' \
                    %(mangaid[i], mastarid[i], starid[i], \
                    plate[i], ifudesign[i], mjd[i], \
                    ra[i],dec[i], \
                    parameters[i,0],parameters[i,1],parameters[i,2], \
                    parameters[i,3],parameters[i,4],parameters[i,5], \
                    parameters[i,6],parameters[i,7],parameters[i,8], \
                    ppxf_info[i,0], ppxf_info[i,1], ppxf_info[i,2], \
                    mags[i,0], mags[i,1], mags[i,2], mags[i,3], mags[i,4], \
                    indices[i,0], indices[i,1], indices[i,2], indices[i,3], indices[i,4], \
                    indices[i,5], indices[i,6], indices[i,7], indices[i,8], indices[i,9], \
                    indices[i,10], indices[i,11], indices[i,12], indices[i,13], indices[i,14], \
                    indices[i,15], indices[i,16], indices[i,17], indices[i,18], indices[i,19], \
                    indices[i,20], indices[i,21], indices[i,22], indices[i,23], indices[i,24], \
                    indices[i,25], indices[i,26], indices[i,27], indices[i,28], indices[i,29], \
                    indices[i,30], indices[i,31], indices[i,32], indices[i,33], indices[i,34], \
                    indices[i,35], indices[i,36], indices[i,37], indices[i,38], indices[i,39], \
                    indices[i,40], indices[i,41]))
            f.close()
            print('     > spectrum ' + str(i) + ' done')
            continue

        ##### setting up the MaStar for pPXF #####

        velscale = c * cdelt1 / max(
            new_wave)  # do not degrade original velocity sampling
        log_corrected_flux, log_new_wave, velscale = util.log_rebin(
            [min(new_wave), max(new_wave)], corrected_flux, velscale=velscale)

        ##### setting up the selected templates #####

        templ_set = len(templ_set_id)
        templates = np.zeros((len(log_corrected_flux), templ_set))

        for j in range(0, templ_set):
            hdu = fits.open(templates_dir + 'grid/' + templ_set_id[j] +
                            '.fits')
            template_wave = np.linspace(start=hdu[0].header['CRVAL1'],
                                        stop=hdu[0].header['CRVAL2'],
                                        num=hdu[0].header['NAXIS1'])
            template_flux = np.interp(new_wave, template_wave, hdu[0].data)

            bad_flux = np.isnan(template_flux) | np.isinf(template_flux) | (
                template_flux <= 0.0)
            template_flux[bad_flux] = 0.0

            log_template_flux, log_template_wave, velscale = util.log_rebin(
                [min(new_wave), max(new_wave)],
                template_flux,
                velscale=velscale)
            log_template_flux /= np.median(log_template_flux)

            templates[:, j] = log_template_flux

        ##### setting up the variables to run pPXF #####

        start = [0, 10]

        noise = np.ones_like(log_corrected_flux)

        sol = ppxf(templates,
                   log_corrected_flux,
                   noise,
                   velscale,
                   start,
                   lam=np.exp(log_new_wave),
                   degree=10,
                   moments=2,
                   quiet=True)

        sol.plot()
        plt.title(mastarid[i])
        #plt.show()
        plt.savefig(output_dir + 'fsf/' + mastarid[i] + '_bestfit.png')
        plt.close()

        ##### gathering the chi2, vel and sigma from the pPXF output #####

        print(
            '          > gathering the information from the full-spectrum fitting'
        )

        ppxf_info[i, 0] = sol.chi2
        ppxf_info[i, 1] = sol.sol[0]
        ppxf_info[i, 2] = sol.sol[1]

        print('               > chi2/dof  = ' + str(ppxf_info[i, 0]))
        print('               > vel       = ' + str(ppxf_info[i, 1]) +
              ' km s-1')
        print('               > sigma     = ' + str(ppxf_info[i, 2]) +
              ' km s-1')

        prelim_teff = []
        prelim_logg = []
        prelim_metal = []

        ppxf_weights = sol.weights[:]

        ##### calculating the weighted parameters #####

        for j in range(0, templ_set):
            prelim_teff.append(sol.weights[j] * templ_set_teff[j] /
                               np.sum(sol.weights[:]))
            prelim_logg.append(sol.weights[j] * templ_set_logg[j] /
                               np.sum(sol.weights[:]))
            prelim_metal.append(sol.weights[j] * templ_set_metal[j] /
                                np.sum(sol.weights[:]))

        parameters[i, 3] = np.sum(prelim_teff[:])
        parameters[i, 4] = np.sum(prelim_logg[:])
        parameters[i, 5] = np.sum(prelim_metal[:]) + 0.3

        bad_data = np.isnan(parameters[i, 3]) | np.isinf(
            parameters[i, 3]) | np.isnan(parameters[i, 4]) | np.isinf(
                parameters[i, 4]) | np.isnan(parameters[i, 5]) | np.isinf(
                    parameters[i, 5])
        if bad_data:
            parameters[i, 3] = -999
            parameters[i, 4] = -999
            parameters[i, 5] = -999
            parameters[i, 6] = -999
            parameters[i, 7] = -999
            parameters[i, 8] = -999
            ##### making a preliminary output file #####
            print('          > making a preliminary output file')
            f = open(output_dir + 'prelim_output/' + mastarid[i] + '_she-ra',
                     'w')
            f.write('%r %r %r %i %i %i %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n' \
                    %(mangaid[i], mastarid[i], starid[i], \
                    plate[i], ifudesign[i], mjd[i], \
                    ra[i],dec[i], \
                    parameters[i,0],parameters[i,1],parameters[i,2], \
                    parameters[i,3],parameters[i,4],parameters[i,5], \
                    parameters[i,6],parameters[i,7],parameters[i,8], \
                    ppxf_info[i,0], ppxf_info[i,1], ppxf_info[i,2], \
                    mags[i,0], mags[i,1], mags[i,2], mags[i,3], mags[i,4], \
                    indices[i,0], indices[i,1], indices[i,2], indices[i,3], indices[i,4], \
                    indices[i,5], indices[i,6], indices[i,7], indices[i,8], indices[i,9], \
                    indices[i,10], indices[i,11], indices[i,12], indices[i,13], indices[i,14], \
                    indices[i,15], indices[i,16], indices[i,17], indices[i,18], indices[i,19], \
                    indices[i,20], indices[i,21], indices[i,22], indices[i,23], indices[i,24], \
                    indices[i,25], indices[i,26], indices[i,27], indices[i,28], indices[i,29], \
                    indices[i,30], indices[i,31], indices[i,32], indices[i,33], indices[i,34], \
                    indices[i,35], indices[i,36], indices[i,37], indices[i,38], indices[i,39], \
                    indices[i,40], indices[i,41]))
            f.close()
            print('     > spectrum ' + str(i) + ' done')
            continue

        print(
            '          > calculating the second set of teff, logg, and metallicity'
        )

        print('               > Teff  = ' + str(parameters[i, 3]) + ' K')
        print('               > logg  = ' + str(parameters[i, 4]) + ' dex')
        print('               > metal = ' + str(parameters[i, 5]) + ' dex')

        ##### gathering the parameters of the template with the largest weight #####

        print(
            '          > calculating the third set of teff, logg, and metallicity'
        )

        ok_heavy = np.where(ppxf_weights == max(ppxf_weights))

        parameters[i, 6] = templ_set_teff[ok_heavy]
        parameters[i, 7] = templ_set_logg[ok_heavy]
        parameters[i, 8] = templ_set_metal[ok_heavy] + 0.3

        print('               > Teff  = ' + str(parameters[i, 6]) + ' K')
        print('               > logg  = ' + str(parameters[i, 7]) + ' dex')
        print('               > metal = ' + str(parameters[i, 8]) + ' dex')

        print('          > elapsed time for one MaStar %.2f s' %
              (clock() - start_time))

        ##### making a preliminary output file #####

        print('          > making a preliminary output file')
        f = open(output_dir + 'prelim_output/' + mastarid[i] + '_she-ra', 'w')
        f.write('%r %r %r %i %i %i %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n' \
                %(mangaid[i], mastarid[i], starid[i], \
                plate[i], ifudesign[i], mjd[i], \
                ra[i],dec[i], \
                parameters[i,0],parameters[i,1],parameters[i,2], \
                parameters[i,3],parameters[i,4],parameters[i,5], \
                parameters[i,6],parameters[i,7],parameters[i,8], \
                ppxf_info[i,0], ppxf_info[i,1], ppxf_info[i,2], \
                mags[i,0], mags[i,1], mags[i,2], mags[i,3], mags[i,4], \
                indices[i,0], indices[i,1], indices[i,2], indices[i,3], indices[i,4], \
                indices[i,5], indices[i,6], indices[i,7], indices[i,8], indices[i,9], \
                indices[i,10], indices[i,11], indices[i,12], indices[i,13], indices[i,14], \
                indices[i,15], indices[i,16], indices[i,17], indices[i,18], indices[i,19], \
                indices[i,20], indices[i,21], indices[i,22], indices[i,23], indices[i,24], \
                indices[i,25], indices[i,26], indices[i,27], indices[i,28], indices[i,29], \
                indices[i,30], indices[i,31], indices[i,32], indices[i,33], indices[i,34], \
                indices[i,35], indices[i,36], indices[i,37], indices[i,38], indices[i,39], \
                indices[i,40], indices[i,41]))
        f.close()

        print('     > spectrum ' + str(i) + ' done')
        #sys.stdout.write("     > spectrum = %d %s \r" % (i+1,'done'))
        #sys.stdout.flush()

    print('     > all spectra done')
    print('     > elapsed time for all MaStar %.2f s' % (clock() - full_time))
Пример #39
0
#redshift = 2472. #ngc772
#redshift = 1485.  #ngc1022
#redshift = 1032. #vcc784
#redshift = 674. #vcc1146
redshift = 401. #vcc1619
#redshift = 1359 #VCC0355

start = [redshift,10.] 				#(km/s), starting guess for [V,sigma]
specdir='/Users/nluetzge/Science/UCDs/'
#----------------------------------Read all files-----------------------------------------
# Read the combined spectrum
hdu = fits.open(name+'_spec.fits')
gal=hdu[0].data
hdr=hdu[0].header
lamRange1=hdr['CRVAL1'] + np.array([0.,hdr['CDELT1']*(hdr['NAXIS1']-1.)])
galaxy, logLam1, velscale = util.log_rebin(lamRange1, gal)

# Read the template
if make_temp:
	temp_files = glob(specdir+Z+'/nifstemp*fits')
	nfiles=len(temp_files)
	for i in range(nfiles):
		hdu = fits.open(temp_files[i])
		h_template=hdu[0].header
		temp_lin=hdu[0].data
		
		# the wavelength range calculated from the header data
		naxis=h_template['NAXIS1']
		lamRange2=h_template['CRVAL1'] + np.array([0.,h_template['CDELT1']*(h_template['NAXIS1']-1.)])
		
		tt, logLam2,velscale = util.log_rebin(lamRange2, temp_lin, velscale=velscale)
Пример #40
0
def ppxf_simulation_example():

    dir = 'spectra/'
    file = dir + 'Rbi1.30z+0.00t12.59.fits'
    hdu = pyfits.open(file)
    ssp = hdu[0].data
    h = hdu[0].header

    lamRange = h['CRVAL1'] + np.array([0., h['CDELT1'] * (h['NAXIS1'] - 1)])
    star, logLam, velscale = util.log_rebin(lamRange, ssp)

    # The finite sampling of the observed spectrum is modeled in detail:
    # the galaxy spectrum is obtained by oversampling the actual observed spectrum
    # to a high resolution. This represent the true spectrum, which is later resampled
    # to lower resolution to simulate the observations on the CCD. Similarly, the
    # convolution with a well-sampled LOSVD is done on the high-resolution spectrum,
    # and later resampled to the observed resolution before fitting with PPXF.

    factor = 10  # Oversampling integer factor for an accurate convolution
    starNew = ndimage.interpolation.zoom(
        star, factor,
        order=1)  # This is the underlying spectrum, known at high resolution
    star = rebin(
        starNew, factor
    )  # Make sure that the observed spectrum is the integral over the pixels

    vel = 0.3  # velocity in *pixels* [=V(km/s)/velScale]
    h3 = 0.1  # Adopted G-H parameters of the LOSVD
    h4 = -0.1
    sn = 60.  # Adopted S/N of the Monte Carlo simulation
    m = 300  # Number of realizations of the simulation
    sigmaV = np.linspace(
        0.8, 4, m)  # Range of sigma in *pixels* [=sigma(km/s)/velScale]

    result = np.zeros((m, 4))  # This will store the results
    t = clock()
    np.random.seed(123)  # for reproducible results

    for j in range(m):

        sigma = sigmaV[j]
        dx = int(
            abs(vel) +
            4.0 * sigma)  # Sample the Gaussian and GH at least to vel+4*sigma
        x = np.linspace(
            -dx, dx, 2 * dx * factor +
            1)  # Evaluate the Gaussian using steps of 1/factor pixels.
        w = (x - vel) / sigma
        w2 = w**2
        gauss = np.exp(-0.5 * w2) / (np.sqrt(2. * np.pi) * sigma * factor
                                     )  # Normalized total(gauss)=1
        h3poly = w * (2. * w2 - 3.) / np.sqrt(3.)  # H3(y)
        h4poly = (w2 * (4. * w2 - 12.) + 3.) / np.sqrt(24.)  # H4(y)
        losvd = gauss * (1. + h3 * h3poly + h4 * h4poly)

        galaxy = signal.fftconvolve(
            starNew, losvd, mode="same")  # Convolve the oversampled spectrum
        galaxy = rebin(
            galaxy, factor)  # Integrate spectrum into original spectral pixels
        noise = galaxy / sn  # 1sigma error spectrum
        galaxy = np.random.normal(galaxy,
                                  noise)  # Add noise to the galaxy spectrum
        start = np.array([
            vel + np.random.random(), sigma * np.random.uniform(0.85, 1.15)
        ]) * velscale  # Convert to km/s

        pp = ppxf(star,
                  galaxy,
                  noise,
                  velscale,
                  start,
                  goodpixels=np.arange(dx, galaxy.size - dx),
                  plot=False,
                  moments=4,
                  bias=0.5)
        result[j, :] = pp.sol

    print('Calculation time: %.2f s' % (clock() - t))

    plt.clf()
    plt.subplot(221)
    plt.plot(sigmaV * velscale, result[:, 0] - vel * velscale, '+k')
    plt.plot(sigmaV * velscale, sigmaV * velscale * 0, '-r')
    plt.ylim(-40, 40)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$V - V_{in}\ (km\ s^{-1}$)')

    plt.subplot(222)
    plt.plot(sigmaV * velscale, result[:, 1] - sigmaV * velscale, '+k')
    plt.plot(sigmaV * velscale, sigmaV * velscale * 0, '-r')
    plt.ylim(-40, 40)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$\sigma - \sigma_{in}\ (km\ s^{-1}$)')

    plt.subplot(223)
    plt.plot(sigmaV * velscale, result[:, 2], '+k')
    plt.plot(sigmaV * velscale, sigmaV * velscale * 0 + h3, '-r')
    plt.ylim(-0.2 + h3, 0.2 + h3)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$h_3$')

    plt.subplot(224)
    plt.plot(sigmaV * velscale, result[:, 3], '+k')
    plt.plot(sigmaV * velscale, sigmaV * velscale * 0 + h4, '-r')
    plt.ylim(-0.2 + h4, 0.2 + h4)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$h_4$')

    plt.tight_layout()
    plt.pause(0.01)
def ppxf_simulation_example():

    hdu = fits.open('miles_models/Mun1.30Zp0.00T12.5893.fits'
                    )  # Solar metallicitly, Age=12.59 Gyr
    ssp = hdu[0].data
    h = hdu[0].header

    lamRange = h['CRVAL1'] + np.array([0., h['CDELT1'] * (h['NAXIS1'] - 1)])
    c = 299792.458  # speed of light in km/s
    velscale = c * h['CDELT1'] / max(
        lamRange)  # Do not degrade original velocity sampling
    star, logLam, velscale = util.log_rebin(lamRange, ssp, velscale=velscale)

    # The finite sampling of the observed spectrum is modeled in detail:
    # the galaxy spectrum is obtained by oversampling the actual observed spectrum
    # to a high resolution. This represent the true spectrum, which is later resampled
    # to lower resolution to simulate the observations on the CCD. Similarly, the
    # convolution with a well-sampled LOSVD is done on the high-resolution spectrum,
    # and later resampled to the observed resolution before fitting with PPXF.

    factor = 10  # Oversampling integer factor for an accurate convolution
    starNew = ndimage.interpolation.zoom(
        star, factor,
        order=3)  # This is the underlying spectrum, known at high resolution
    star = rebin(
        starNew, factor
    )  # Make sure that the observed spectrum is the integral over the pixels

    np.random.seed(133)  # for reproducible results

    h3 = 0.1  # Adopted G-H parameters of the LOSVD
    h4 = -0.1
    sn = 30.  # Adopted S/N of the Monte Carlo simulation
    m = 300  # Number of realizations of the simulation
    moments = 4
    velV = np.random.rand(m)  # velocity in *pixels* [=V(km/s)/velScale]
    sigmaV = np.linspace(
        0.5, 4, m)  # Range of sigma in *pixels* [=sigma(km/s)/velScale]

    result = np.zeros((m, moments))  # This will store the results
    t = clock()

    for j, (vel, sigma) in enumerate(zip(velV, sigmaV)):

        dx = int(
            abs(vel) +
            4.0 * sigma)  # Sample the Gaussian and GH at least to vel+4*sigma
        x = np.linspace(
            -dx, dx, 2 * dx * factor +
            1)  # Evaluate the Gaussian using steps of 1/factor pixels.
        w = (x - vel) / sigma
        w2 = w**2
        gauss = np.exp(-0.5 * w2)
        gauss /= np.sum(gauss)  # Normalized total(gauss)=1
        h3poly = w * (2. * w2 - 3.) / np.sqrt(3.)  # H3(y)
        h4poly = (w2 * (4. * w2 - 12.) + 3.) / np.sqrt(24.)  # H4(y)
        losvd = gauss * (1. + h3 * h3poly + h4 * h4poly)

        galaxy = signal.fftconvolve(
            starNew, losvd, mode="same")  # Convolve the oversampled spectrum
        galaxy = rebin(
            galaxy, factor)  # Integrate spectrum into original spectral pixels
        noise = galaxy / sn  # 1sigma error spectrum
        galaxy = np.random.normal(galaxy,
                                  noise)  # Add noise to the galaxy spectrum
        start = np.array([
            vel + np.random.random(), sigma * np.random.uniform(0.85, 1.15), 0,
            0
        ]) * velscale  # Convert to km/s

        pp = ppxf(star,
                  galaxy,
                  noise,
                  velscale,
                  start,
                  goodpixels=np.arange(dx, galaxy.size - dx),
                  plot=False,
                  moments=moments,
                  bias=0.3,
                  oversample=None)
        result[j, :] = pp.sol

    print('Calculation time: %.2f s' % (clock() - t))

    plt.clf()
    plt.subplot(221)
    plt.plot(sigmaV * velscale, (result[:, 0] / velscale - velV) / sigmaV,
             '+k')
    plt.axhline(0, color='r')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-0.3, 0.3)
    plt.xlabel(r'$\sigma_{\rm in}\ (km\ s^{-1})$')
    plt.ylabel(r'$(V - V_{\rm in})/\sigma_{\rm in}$')
    plt.text(2.05 * velscale, -0.2, r'2$\times$velscale')

    plt.subplot(222)
    plt.plot(sigmaV * velscale, np.log10(result[:, 1] / (velscale * sigmaV)),
             '+k')
    plt.axhline(0, color='r')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-0.15, 0.15)
    plt.xlabel(r'$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel(r'$\log(\sigma/\sigma_{\rm in})$')
    plt.text(2.05 * velscale, -0.1, r'2$\times$velscale')

    plt.subplot(223)
    plt.plot(sigmaV * velscale, result[:, 2], '+k')
    plt.axhline(h3, color='r')
    plt.axhline(0, linestyle='dotted', color='limegreen')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-0.15 + h3, 0.15 + h3)
    plt.xlabel(r'$\sigma_{\rm in}\ (km\ s^{-1})$')
    plt.ylabel('$h_3$')
    plt.text(2.05 * velscale, h3 - 0.1, r'2$\times$velscale')

    plt.subplot(224)
    plt.plot(sigmaV * velscale, result[:, 3], '+k')
    plt.axhline(h4, color='r')
    plt.axhline(0, linestyle='dotted', color='limegreen')
    plt.axvline(velscale, linestyle='dashed')
    plt.axvline(2 * velscale, linestyle='dashed')
    plt.ylim(-0.15 + h4, 0.15 + h4)
    plt.xlabel(r'$\sigma_{\rm in}\ (km\ s^{-1})$')
    plt.ylabel('$h_4$')
    plt.text(2.05 * velscale, h4 - 0.1, r'2$\times$velscale')

    plt.tight_layout()
    plt.pause(0.01)
Пример #42
0
def ppxf_kinematics_example_sauron():

    # Read a galaxy spectrum and define the wavelength range
    #
    dir = 'spectra/'
    file = dir + 'NGC4550_SAURON.fits'

    hdu = pyfits.open(file)
    gal_lin = hdu[0].data
    h1 = hdu[0].header

    lamRange1 = h1['CRVAL1'] + np.array([0.,h1['CDELT1']*(h1['NAXIS1']-1)])
    FWHM_gal = 4.2 # SAURON has an instrumental resolution FWHM of 4.2A.

    # If the galaxy is at a significant redshift (z > 0.03), one would need to apply
    # a large velocity shift in PPXF to match the template to the galaxy spectrum.
    # This would require a large initial value for the velocity (V > 1e4 km/s)
    # in the input parameter START = [V,sig]. This can cause PPXF to stop!
    # The solution consists of bringing the galaxy spectrum roughly to the
    # rest-frame wavelength, before calling PPXF. In practice there is no
    # need to modify the spectrum before the usual LOG_REBIN, given that a
    # red shift corresponds to a linear shift of the log-rebinned spectrum.
    # One just needs to compute the wavelength range in the rest-frame
    # and adjust the instrumental resolution of the galaxy observations.
    # This is done with the following three commented lines:
    #
    # z = 1.23 # Initial estimate of the galaxy redshift
    # lamRange1 = lamRange1/(1+z) # Compute approximate restframe wavelength range
    # FWHM_gal = FWHM_gal/(1+z)   # Adjust resolution in Angstrom

    galaxy, logLam1, velscale = util.log_rebin(lamRange1, gal_lin)
    galaxy = galaxy/np.median(galaxy) # Normalize spectrum to avoid numerical issues
    noise = galaxy*0 + 0.0049           # Assume constant noise per pixel here

    # Read the list of filenames from the Single Stellar Population library
    # by Vazdekis (1999, ApJ, 513, 224). A subset of the library is included
    # for this example with permission. See http://purl.org/cappellari/software
    # for suggestions of more up-to-date stellar libraries.
    #
    vazdekis = glob.glob(dir + 'Rbi1.30z*.fits')
    vazdekis.sort()
    FWHM_tem = 1.8 # Vazdekis spectra have a resolution FWHM of 1.8A.

    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pyfits.open(vazdekis[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array([0.,h2['CDELT1']*(h2['NAXIS1']-1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
    templates = np.empty((sspNew.size,len(vazdekis)))

    # Convolve the whole Vazdekis library of spectral templates
    # with the quadratic difference between the SAURON and the
    # Vazdekis instrumental resolution. Logarithmically rebin
    # and store each template as a column in the array TEMPLATES.

    # Quadratic sigma difference in pixels Vazdekis --> SAURON
    # The formula below is rigorously valid if the shapes of the
    # instrumental spectral profiles are well approximated by Gaussians.
    #
    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    sigma = FWHM_dif/2.355/h2['CDELT1'] # Sigma difference in pixels

    for j in range(len(vazdekis)):
        hdu = pyfits.open(vazdekis[j])
        ssp = hdu[0].data
        ssp = ndimage.gaussian_filter1d(ssp,sigma)
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp, velscale=velscale)
        templates[:,j] = sspNew/np.median(sspNew) # Normalizes templates

    # The galaxy and the template spectra do not have the same starting wavelength.
    # For this reason an extra velocity shift DV has to be applied to the template
    # to fit the galaxy spectrum. We remove this artificial shift by using the
    # keyword VSYST in the call to PPXF below, so that all velocities are
    # measured with respect to DV. This assume the redshift is negligible.
    # In the case of a high-redshift galaxy one should de-redshift its
    # wavelength to the rest frame before using the line below (see above).
    #
    c = 299792.458
    dv = (logLam2[0]-logLam1[0])*c # km/s

    vel = 450. # Initial estimate of the galaxy velocity in km/s
    z = np.exp(vel/c) - 1   # Relation between velocity and redshift in pPXF
    goodPixels = util.determine_goodpixels(logLam1, lamRange2, z)

    # Here the actual fit starts. The best fit is plotted on the screen.
    # Gas emission lines are excluded from the pPXF fit using the GOODPIXELS keyword.
    #
    start = [vel, 180.] # (km/s), starting guess for [V,sigma]
    t = clock()

    pp = ppxf(templates, galaxy, noise, velscale, start,
              goodpixels=goodPixels, plot=True, moments=4,
              degree=4, vsyst=dv)

    print("Formal errors:")
    print("     dV    dsigma   dh3      dh4")
    print("".join("%8.2g" % f for f in pp.error*np.sqrt(pp.chi2)))

    print('Elapsed time in PPXF: %.2f s' % (clock() - t))
Пример #43
0
    def __init__(self,
                 pathname,
                 velscale,
                 FWHM_gal,
                 metal=None,
                 FWHM_tem=2.51,
                 normalize=False,
                 max_age=None):
        """
        Produces an array of logarithmically-binned templates by reading
        the spectra from the Single Stellar Population (SSP) library by
        Vazdekis et al. (2010, MNRAS, 404, 1639) http://miles.iac.es/.
        The code checks that the model specctra form a rectangular grid
        in age and metallicity and properly sorts them in both parameters.
        The code also returns the age and metallicity of each template
        by reading these parameters directly from the file names.
        The templates are broadened by a Gaussian with dispersion
        sigma_diff = np.sqrt(sigma_gal**2 - sigma_tem**2).

        Thie script relies on the files naming convention adopted by
        the MILES library, where SSP spectra have the form below

            Mun1.30Zm0.40T00.0794_iPp0.00_baseFe_linear_FWHM_2.51.fits

        This code can be easily adapted by the users to deal with other stellar
        libraries, different IMFs or different abundances.

        :param pathname: path with wildcards returning the list files to use
            (e.g. 'miles_models/Mun1.30*.fits'). The files must form a Cartesian grid
            in age and metallicity and the procedure returns an error if they do not.
        :param velscale: desired velocity scale for the output templates library in km/s
            (e.g. 60). This is generally the same or an integer fraction of the velscale
            of the galaxy spectrum.
        :param FWHM_gal: vector or scalar with the FWHM of the instrumental resolution
            of the galaxy spectrum in Angstrom.
        :param normalize: set to True to normalize each template to mean=1.
            This is useful to compute light-weighted stellar population quantities.
        :param max_age: optional maximum age in Gyr for the MILES models.
            This can be useful e.g. to limit the templates age to be younger
            than the age of the Universe at a given redshift.
        :param metal: optionally select a *single* metallicity [M/H]
            (e.g. metal = 0 to select only the spectra with Solar metallicity).
        :return: The following variables are stored as attributes of the miles class:
            .templates: array has dimensions templates[npixels, n_ages, n_metals];
            .log_lam_temp: natural np.log() wavelength of every pixel npixels;
            .age_grid: (Gyr) has dimensions age_grid[n_ages, n_metals];
            .metal_grid: [M/H] has dimensions metal_grid[n_ages, n_metals].
            .n_ages: number of different ages
            .n_metal: number of different metallicities

        """
        files = glob.glob(pathname)
        assert len(files) > 0, "Files not found %s" % pathname

        all = [age_metal(f) for f in files]
        all_ages, all_metals = np.array(all).T
        ages, metals = np.unique(all_ages), np.unique(all_metals)
        n_ages, n_metal = len(ages), len(metals)

        assert set(all) == set([(a, b) for a in ages for b in metals]), \
            'Ages and Metals do not form a Cartesian grid'

        # Extract the wavelength range and logarithmically rebin one spectrum
        # to the same velocity scale of the SDSS galaxy spectrum, to determine
        # the size needed for the array which will contain the template spectra.
        hdu = fits.open(files[0])
        ssp = hdu[0].data
        h2 = hdu[0].header
        lam_range_temp = h2['CRVAL1'] + np.array(
            [0, h2['CDELT1'] * (h2['NAXIS1'] - 1)])
        sspNew, log_lam_temp = util.log_rebin(lam_range_temp,
                                              ssp,
                                              velscale=velscale)[:2]

        templates = np.empty((sspNew.size, n_ages, n_metal))
        age_grid = np.empty((n_ages, n_metal))
        metal_grid = np.empty((n_ages, n_metal))

        # Convolve the whole Vazdekis library of spectral templates
        # with the quadratic difference between the galaxy and the
        # Vazdekis instrumental resolution. Logarithmically rebin
        # and store each template as a column in the array TEMPLATES.

        # Quadratic sigma difference in pixels Vazdekis --> galaxy
        # The formula below is rigorously valid if the shapes of the
        # instrumental spectral profiles are well approximated by Gaussians.
        FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
        sigma = FWHM_dif / 2.355 / h2['CDELT1']  # Sigma difference in pixels

        # Here we make sure the spectra are sorted in both [M/H] and Age
        # along the two axes of the rectangular grid of templates.
        for j, age in enumerate(ages):
            for k, met in enumerate(metals):
                p = all.index((age, met))
                hdu = fits.open(files[p])
                ssp = hdu[0].data
                if np.isscalar(FWHM_gal):
                    if sigma > 0.1:  # Skip convolution for nearly zero sigma
                        ssp = ndimage.gaussian_filter1d(ssp, sigma)
                else:
                    ssp = util.gaussian_filter1d(
                        ssp, sigma)  # convolution with variable sigma
                sspNew = util.log_rebin(lam_range_temp, ssp,
                                        velscale=velscale)[0]
                if normalize:
                    sspNew /= np.mean(sspNew)
                templates[:, j, k] = sspNew
                age_grid[j, k] = age
                metal_grid[j, k] = met

        if max_age is not None:
            w = age_grid[:, 0] <= max_age
            templates = templates[:, w, :]
            age_grid = age_grid[w, :]
            metal_grid = metal_grid[w, :]
            n_ages, n_metal = age_grid.shape

        if metal is not None:
            w = metal_grid[0, :] == metal
            templates = np.squeeze(templates[:, :, w])
            age_grid = np.squeeze(age_grid[:, w])
            metal_grid = np.squeeze(metal_grid[:, w])
            n_ages, n_metal = age_grid.size, 1
        self.norm = np.median(templates)
        self.templates = templates / self.norm  # Normalize by a scalar
        self.log_lam_temp = log_lam_temp
        self.age_grid = age_grid
        self.metal_grid = metal_grid
        self.n_ages = n_ages
        self.n_metal = n_metal
	def __init__(self, galaxy='ngc3557', slit_h=4.5, slit_w=2, slit_pa=30, 
		method='Rampazzo_aperture', r1=0, r2=None, debug=False):
		print galaxy
		if 'Rampazzo' in method:
			from Rampazzo import rampazzo
			# Default is nuclear region: 0<r<R_e/16
			if r2 is None:
				r2 = get_R_e(galaxy)/16
			data = rampazzo(galaxy, method='aperture', slit_h=slit_h, r1=r1, r2=r2, 
				debug=debug)

			if 'gradient' in method:
				if '2' in method: data.method = 'gradient2'
				else: data.method = 'gradient'

		elif method == 'Ogando':
			from Ogando import ogando
			data = ogando(galaxy, debug=debug, slit_h=slit_h, slit_w=slit_w, 
				slit_pa=slit_pa)

		elif method == 'Miles':
			from Miles import miles
			data = miles(galaxy)

		gal_spec, gal_noise = data.get_spec()

		gal_spec, lam, cut = apply_range(gal_spec, window=201, repeats=3, 
			lam=data.lam, set_range=np.array([4200,10000]), return_cuts=True)
		gal_noise = gal_noise[cut]
		lamRange = np.array([lam[0],lam[-1]])/(1+data.z)
## ----------================= Templates ====================---------
		FWHM_gal = 2.5 # VIMOS documentation (and fits header)
		FWHM_gal = FWHM_gal/(1+data.z) # Adjust resolution in Angstrom

		stellar_templates = get_stellar_templates(galaxy, FWHM_gal)
		velscale = stellar_templates.velscale

		e_templates = get_emission_templates(gas, lamRange, 
			stellar_templates.logLam_template, FWHM_gal)

		if gas:
			templates = np.column_stack((stellar_templates.templates, e_templates.templates))
		else:
			templates = stellar_templates.templates
		component = [0]*len(stellar_templates.templatesToUse) + e_templates.component
		templatesToUse = np.append(stellar_templates.templatesToUse, 
			e_templates.templatesToUse)
		element = ['stellar'] + e_templates.element

		start = [[data.vel, data.sig]] * (max(component) + 1)
		moments = [stellar_moments] + [gas_moments] * max(component)
## ----------============== Final calibrations ==============---------
		## smooth spectrum to fit with templates resolution
		if FWHM_gal < stellar_templates.FWHM_tem:
			sigma = stellar_templates.FWHM_dif/2.355/data.f[0].header['CDELT3']
			gal_spec = ndimage.gaussian_filter1d(gal_spec, sigma)
			gal_noise = np.sqrt(ndimage.gaussian_filter1d(gal_noise**2, sigma))
		
		## rebin spectrum logarthmically
		gal_spec_log, logLam_bin, _ = util.log_rebin(lamRange, gal_spec, velscale=velscale)
		gal_noise_log, logLam_bin, _ = util.log_rebin(lamRange, gal_noise**2, 
			velscale=velscale)
		gal_noise_log = np.sqrt(gal_noise_log)

		gal_noise_log = gal_noise_log + 0.0000000000001



		dv = (stellar_templates.logLam_template[0]-logLam_bin[0])*c # km/s
		# Find the pixels to ignore to avoid being distracted by gas emission
		#; lines or atmospheric absorbsion line.  
		goodPixels = determine_goodpixels(logLam_bin,stellar_templates.lamRange_template,
			data.vel, data.z, gas=gas!=0) 
		lambdaq = np.exp(logLam_bin)
## ----------=================== pPXF =======================---------
		pp = ppxf(templates, gal_spec_log, gal_noise_log, velscale, start, 
			goodpixels=goodPixels, moments=moments, degree=-1, vsyst=dv, 
			component=component, lam=lambdaq, plot=not quiet, quiet=quiet, mdegree=10)
		self.pp = pp

		# Only use stellar templates (Remove emission lines)
		stellar_spec = gal_spec_log - \
			pp.matrix[:, -e_templates.ntemp:].dot(pp.weights[-e_templates.ntemp:])
		conv_spec = pp.matrix[:, :-e_templates.ntemp].dot(pp.weights[:-e_templates.ntemp])

		# Generate the unconvolved spectra ('0 km/s' resolution)
		unc_lam = stellar_templates.wav
		unc_spec = stellar_templates.lin_templates.dot(pp.weights[:stellar_templates.ntemp])
		unc_spec *= np.polynomial.legendre.legval(np.linspace(-1,1,
			len(unc_spec)), np.append(1, pp.mpolyweights))
## ----------============== Absorption Line =================---------

		lines = ['G4300', 'Fe4383', 'Ca4455', 'Fe4531', 'H_beta', 'Fe5015', 'Mg_b']
		self.result = {}
		self.uncert = {}
		for line in lines:		
			ab, ab_uncert = absorption(line, lambdaq, stellar_spec, noise=gal_noise_log, 
				unc_lam=unc_lam, unc_spec=unc_spec,	conv_spec=conv_spec)#, 
				#lick=True)

			if method == 'Ogando':
				# Aperture correction
				ab_file = '%s/Documents/useful_files/ab_linelist.dat' % (cc.home_dir)
				i1, i2, b1, b2, r1, r2, units = np.genfromtxt(ab_file, unpack=True, 
					usecols=(1,2,3,4,5,6,7), skip_header=2, skip_footer=2)
				ls = np.genfromtxt(ab_file, unpack=True, dtype=str, usecols=(8), 
					skip_header=2, skip_footer=2)
				l = np.where(ls == line)[0][0]
				index = [i1[l], i2[l]]

				# Convert to mag
				ab = -2.5 * np.log(1 - ab/(index[1]-index[0]))

				# Aperture Correction: beta values taken from paper
				beta = {'H_beta':0.002, 'Fe5015':-0.012, 'Mg_b':-0.031} 
				# If line is not observed by Ogando
				if line not in beta.keys():
					self.result[line] = np.nan
					self.uncert[line] = np.nan
					continue
				H = 70.0 # value used by Bolonga group.
				r_ab = np.degrees(1.19/1000 * H/(c * data.z)) * 60 * 60 # 1.19 kpc -> arcsec
				# Correction is def in eq (9) with r_ab and r_norm def in eq (1) - not 
				#	100% sure if I've got them correct.
				ab = ab - beta[line] * np.log(1.025 * np.sqrt(slit_w*r_ab/np.pi)/slit_h)

				# Back to Angstroms
				ab = (index[1]-index[0]) * (1 - np.exp(ab/-2.5))

			elif 'Rampazzo' in method:
				self.r = data.r
			self.result[line] = ab
			self.uncert[line] = ab_uncert

		if debug:
			for line in lines:
				print '%s:	%.3f +/- %.3f' % (line, self.result[line], self.uncert[line])
def ppxf_two_components_example():

    hdu = fits.open('miles_models/Mun1.30Zp0.00T12.5893.fits')  # Solar metallicitly, Age=12.59 Gyr
    gal_lin = hdu[0].data
    h1 = hdu[0].header
    lamRange1 = h1['CRVAL1'] + np.array([0., h1['CDELT1']*(h1['NAXIS1']-1)])
    c = 299792.458 # speed of light in km/s
    velscale = c*h1['CDELT1']/max(lamRange1)   # Do not degrade original velocity sampling
    model1, logLam1, velscale = util.log_rebin(lamRange1, gal_lin, velscale=velscale)
    model1 /= np.median(model1)

    hdu = fits.open('miles_models/Mun1.30Zp0.00T01.0000.fits')  # Solar metallicitly, Age=1.00 Gyr
    gal_lin = hdu[0].data
    model2, logLam1, velscale = util.log_rebin(lamRange1, gal_lin, velscale=velscale)
    model2 /= np.median(model2)

    model = np.column_stack([model1, model2])
    galaxy = np.empty_like(model)

    # These are the input values in spectral pixels
    # for the (V,sigma) of the two kinematic components
    #
    vel = np.array([0., 250.])/velscale
    sigma = np.array([200., 100.])/velscale

    # The synthetic galaxy model consists of the sum of two
    # SSP spectra with age of 1Gyr and 13Gyr respectively
    # with different velocity and dispersion
    #
    for j in range(len(vel)):
        dx = int(abs(vel[j]) + 4.*sigma[j])   # Sample the Gaussian at least to vel+4*sigma
        v = np.linspace(-dx, dx, 2*dx + 1)
        losvd = np.exp(-0.5*((v - vel[j])/sigma[j])**2) # Gaussian LOSVD
        losvd /= np.sum(losvd) # normaize LOSVD
        galaxy[:, j] = signal.fftconvolve(model[:, j], losvd, mode="same")
        galaxy[:, j] /= np.median(model[:, j])
    galaxy = np.sum(galaxy, axis=1)
    sn = 100.
    np.random.seed(2) # Ensure reproducible results
    noise = galaxy/sn
    galaxy = np.random.normal(galaxy, noise) # add noise to galaxy

    # Adopts two templates per kinematic component
    #
    templates = np.column_stack([model1, model2, model1, model2])

    # Start both kinematic components from the same guess.
    # With multiple stellar kinematic components
    # a good starting guess is essential
    #
    start = [np.mean(vel)*velscale, np.mean(sigma)*velscale]
    start = [start, start]
    goodPixels = np.arange(20, 6000)

    t = clock()

    plt.clf()
    plt.subplot(211)
    plt.title("Two components pPXF fit")
    print("+++++++++++++++++++++++++++++++++++++++++++++")

    pp = ppxf(templates, galaxy, noise, velscale, start,
              goodpixels=goodPixels, plot=True, degree=4,
              moments=[2, 2], component=[0, 0, 1, 1])

    plt.subplot(212)
    plt.title("Single component pPXF fit")
    print("---------------------------------------------")

    start = start[0]
    pp = ppxf(templates, galaxy, noise, velscale, start,
              goodpixels=goodPixels, plot=True, degree=4, moments=2)

    plt.tight_layout()
    plt.pause(0.01)

    print("=============================================")
    print("Total elapsed time %.2f s" % (clock() - t))
for ii in numpy.arange(len(filenames)):
  print ii, "/", len(filenames)
  wave, gal_lin, variance_lin, pix = numpy.genfromtxt(filenames[ii], unpack = True, skiprows = 1) 
  Spaxel_coordinates = findCoords_from_string(filenames[ii])
  #
  text =  "Blue_Spec_"+str(int(Spaxel_coordinates[0]))+"_"+str(int(Spaxel_coordinates[1]))
  #
  noise_lin = numpy.sqrt(variance_lin)
  out_range = numpy.where(numpy.logical_or(wave< 4020., wave > 5550.))
  wave_sel = numpy.delete(wave, out_range)
  gal_lin_sel = numpy.delete(gal_lin, out_range)
  noise_lin_sel = numpy.delete(noise_lin, out_range)
  lamRange1 = numpy.array([wave_sel[0], wave_sel[-1]])
  #
  galaxy, logLam1, velscale = util.log_rebin(lamRange1, gal_lin_sel)
  fac = numpy.median(galaxy)
  galaxy = galaxy / fac# Normalize spectrum to avoid numerical issues
  error, logLam1, velscale = util.log_rebin(lamRange1, noise_lin_sel**2)
  noise = numpy.sqrt(error)
  noise = noise / fac
  #
  #
  logLam2, fl_temp = numpy.genfromtxt(directory + 'wise_template.dat', unpack = True, skiprows = 1)
  wave_temp = numpy.exp(logLam2)
  lamRange2 = numpy.array([logLam2[0], logLam2[-1]])
  #
  templates = fl_temp
  #
  c = 299792.458
  dv = (logLam2[0]-logLam1[0])*c # km/s
def ppxf_kinematics_example_sdss():

    # Read SDSS DR12 galaxy spectrum taken from here http://dr12.sdss3.org/
    # The spectrum is *already* log rebinned by the SDSS DR12
    # pipeline and log_rebin should not be used in this case.
    file = 'spectra/NGC4636_SDSS_DR12.fits'
    hdu = pyfits.open(file)
    t = hdu['COADD'].data
    z =  0.003129   # SDSS redshift estimate

    # Only use the wavelength range in common between galaxy and stellar library.
    mask = (t['loglam'] > np.log10(3540)) & (t['loglam'] < np.log10(7409))
    flux = t['flux'][mask]
    galaxy = flux/np.median(flux)   # Normalize spectrum to avoid numerical issues
    loglam_gal = t['loglam'][mask]
    lam_gal = 10**loglam_gal
    noise = galaxy*0 + 0.0166       # Assume constant noise per pixel here

    c = 299792.458                  # speed of light in km/s
    frac = lam_gal[1]/lam_gal[0]    # Constant lambda fraction per pixel
    dlam_gal = (frac - 1)*lam_gal   # Size of every pixel in Angstrom
    wdisp = t['wdisp'][mask]        # Intrinsic dispersion of every pixel, in pixels units
    fwhm_gal = 2.355*wdisp*dlam_gal # Resolution FWHM of every pixel, in Angstroms
    velscale = np.log(frac)*c       # Constant velocity scale in km/s per pixel

    # If the galaxy is at a significant redshift (z > 0.03), one would need to apply
    # a large velocity shift in PPXF to match the template to the galaxy spectrum.
    # This would require a large initial value for the velocity (V > 1e4 km/s)
    # in the input parameter START = [V,sig]. This can cause PPXF to stop!
    # The solution consists of bringing the galaxy spectrum roughly to the
    # rest-frame wavelength, before calling PPXF. In practice there is no
    # need to modify the spectrum in any way, given that a red shift
    # corresponds to a linear shift of the log-rebinned spectrum.
    # One just needs to compute the wavelength range in the rest-frame
    # and adjust the instrumental resolution of the galaxy observations.
    # This is done with the following three commented lines:
    #
    # lam_gal = lam_gal/(1+z)  # Compute approximate restframe wavelength
    # fwhm_gal = fwhm_gal/(1+z)   # Adjust resolution in Angstrom

    # Read the list of filenames from the Single Stellar Population library
    # by Vazdekis (2010, MNRAS, 404, 1639) http://miles.iac.es/. A subset
    # of the library is included for this example with permission
    vazdekis = glob.glob('miles_models/Mun1.30Z*.fits')
    vazdekis.sort()
    fwhm_tem = 2.51 # Vazdekis+10 spectra have a constant resolution FWHM of 2.51A.

    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SDSS galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pyfits.open(vazdekis[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lam_temp = h2['CRVAL1'] + h2['CDELT1']*np.arange(h2['NAXIS1'])
    lamRange_temp = [np.min(lam_temp), np.max(lam_temp)]
    sspNew, logLam2, velscale = util.log_rebin(lamRange_temp, ssp, velscale=velscale)
    templates = np.empty((sspNew.size, len(vazdekis)))

    # Interpolates the galaxy spectral resolution at the location of every pixel
    # of the templates. Outside the range of the galaxy spectrum the resolution
    # will be extrapolated, but this is irrelevant as those pixels cannot be
    # used in the fit anyway.
    fwhm_gal = np.interp(lam_temp, lam_gal, fwhm_gal)

    # Convolve the whole Vazdekis library of spectral templates
    # with the quadratic difference between the SDSS and the
    # Vazdekis instrumental resolution. Logarithmically rebin
    # and store each template as a column in the array TEMPLATES.

    # Quadratic sigma difference in pixels Vazdekis --> SDSS
    # The formula below is rigorously valid if the shapes of the
    # instrumental spectral profiles are well approximated by Gaussians.
    #
    # In the line below, the fwhm_dif is set to zero when fwhm_gal < fwhm_tem.
    # In principle it should never happen and a higher resolution template should be used.
    #
    fwhm_dif = np.sqrt((fwhm_gal**2 - fwhm_tem**2).clip(0))
    sigma = fwhm_dif/2.355/h2['CDELT1'] # Sigma difference in pixels

    for j, fname in enumerate(vazdekis):
        hdu = pyfits.open(fname)
        ssp = hdu[0].data
        ssp = util.gaussian_filter1d(ssp, sigma)  # perform convolution with variable sigma
        sspNew, logLam2, velscale = util.log_rebin(lamRange_temp, ssp, velscale=velscale)
        templates[:, j] = sspNew/np.median(sspNew) # Normalizes templates

    # The galaxy and the template spectra do not have the same starting wavelength.
    # For this reason an extra velocity shift DV has to be applied to the template
    # to fit the galaxy spectrum. We remove this artificial shift by using the
    # keyword VSYST in the call to PPXF below, so that all velocities are
    # measured with respect to DV. This assume the redshift is negligible.
    # In the case of a high-redshift galaxy one should de-redshift its
    # wavelength to the rest frame before using the line below (see above).
    #
    c = 299792.458
    dv = np.log(lam_temp[0]/lam_gal[0])*c    # km/s
    goodpixels = util.determine_goodpixels(np.log(lam_gal), lamRange_temp, z)

    # Here the actual fit starts. The best fit is plotted on the screen.
    # Gas emission lines are excluded from the pPXF fit using the GOODPIXELS keyword.
    #
    vel = c*np.log(1 + z)   # Initial estimate of the galaxy velocity in km/s
    start = [vel, 200.] # (km/s), starting guess for [V,sigma]
    t = clock()

    pp = ppxf(templates, galaxy, noise, velscale, start,
              goodpixels=goodpixels, plot=True, moments=4,
              degree=12, vsyst=dv, clean=False)

    print("Formal errors:")
    print("     dV    dsigma   dh3      dh4")
    print("".join("%8.2g" % f for f in pp.error*np.sqrt(pp.chi2)))

    print('Elapsed time in PPXF: %.2f s' % (clock() - t))
def ppxf_example_sky_and_symmetric_losvd():

    file_dir = path.dirname(path.realpath(__file__))  # path of this procedure

    # Solar metallicity, Age=12.59 Gyr
    hdu = fits.open(file_dir + '/miles_models/Mun1.30Zp0.00T12.5893.fits')
    ssp = hdu[0].data
    h = hdu[0].header

    lamRange = h['CRVAL1'] + np.array([0., h['CDELT1'] * (h['NAXIS1'] - 1)])
    velscale = 70.  # km/s
    star, logLam, velscale = util.log_rebin(lamRange, ssp, velscale=velscale)
    star /= np.mean(star)

    # Adopted input parameters =================================================

    vel = 200. / velscale  # Velocity of 1st spectrum in pixels (2nd has -vel)
    sigma = 300. / velscale  # Dispersion of both spectra in pixels
    h3 = 0.1  # h3 of 1st spectrum (2nd has -h3)
    h4 = 0.1
    sn = 40.
    moments = 4
    deg = 4
    vshift = 10  # Adopted systemic velocity in pixels
    vsyst = vshift * velscale  # Adopted systemic velocity in km/s

    # Generate input Sky =======================================================
    # For illustration, the sky is modelled as two Gaussian emission lines

    n = star.size
    x = np.arange(n)
    sky1 = np.exp(-0.5 * (x - 1000)**2 / 100)
    sky2 = np.exp(-0.5 * (x - 2000)**2 / 100)

    # Generate input LOSVD =====================================================

    dx = int(abs(vel) + 5 * sigma)
    v = np.linspace(-dx, dx, 2 * dx + 1)
    w = (v - vel) / sigma
    w2 = w**2
    gauss = np.exp(-0.5 * w2)
    gauss /= np.sum(gauss)
    h3poly = w * (2 * w2 - 3) / np.sqrt(3)
    h4poly = (w2 * (4 * w2 - 12) + 3) / np.sqrt(24)
    losvd = gauss * (1 + h3 * h3poly + h4 * h4poly)

    # Generate first synthetic spectrum ========================================
    # The template is convolved with the LOSVD

    x = np.linspace(-1, 1, n)
    galaxy1 = signal.fftconvolve(star, losvd, mode="same")
    galaxy1 = np.roll(galaxy1, vshift)  # Mimic nonzero systemic velocity
    galaxy1 *= legendre.legval(
        x, np.append(1,
                     np.random.uniform(-0.1, 0.1,
                                       deg - 1)))  # Multiplicative polynomials
    galaxy1 += legendre.legval(x,
                               np.random.uniform(-0.1, 0.1,
                                                 deg))  # Additive polynomials
    galaxy1 += sky1 + 2 * sky2  # Add two sky lines
    galaxy1 = np.random.normal(galaxy1, 1 / sn)  # Add noise

    # Generate symmetric synthetic spectrum ====================================
    # The same template is convolved with a reversed LOSVD
    # and different polynomials and sky lines are included

    galaxy2 = signal.fftconvolve(star, np.flip(losvd, 0), mode="same")
    galaxy2 = np.roll(galaxy2, vshift)  # Mimic nonzero systemic velocity
    galaxy2 *= legendre.legval(
        x, np.append(1,
                     np.random.uniform(-0.1, 0.1,
                                       deg - 1)))  # Multiplicative polynomials
    galaxy2 += legendre.legval(x,
                               np.random.uniform(-0.1, 0.1,
                                                 deg))  # Additive polynomials
    galaxy2 += 2 * sky1 + sky2  # Add two sky lines
    galaxy2 = np.random.normal(galaxy2, 1 / sn)  # Add noise

    # Load spectral templates ==================================================

    vazdekis = glob.glob(file_dir + '/miles_models/Mun1.30Z*.fits')
    templates = np.empty((n, len(vazdekis)))
    for j, file in enumerate(vazdekis):
        hdu = fits.open(file)
        ssp = hdu[0].data
        sspNew, logLam2, velscale = util.log_rebin(lamRange,
                                                   ssp,
                                                   velscale=velscale)
        templates[:, j] = sspNew / np.median(sspNew)  # Normalize templates

    # Do the fit ===============================================================

    # Input both galaxy spectra simultaneously to pPXF
    galaxy = np.column_stack([galaxy1, galaxy2])

    # Use two sky templates for each galaxy spectrum
    sky = np.column_stack([sky1, sky2])

    # Randomized starting guess
    vel0 = vel + np.random.uniform(-1, 1)
    sigma0 = sigma * np.random.uniform(0.8, 1.2)
    start = np.array([vel0, sigma0]) * velscale  # Convert to km/s
    goodpixels = np.arange(50, n - 50)

    print(
        "\nThe input values are: Vel=%0.0f, sigma=%0.0f, h3=%0.1f, h4=%0.1f\n"
        % (vel * velscale, sigma * velscale, h3, h4))

    t = clock()

    pp = ppxf(templates,
              galaxy,
              np.full_like(galaxy, 1 / sn),
              velscale,
              start,
              goodpixels=goodpixels,
              plot=1,
              moments=moments,
              vsyst=vsyst,
              mdegree=deg,
              degree=deg,
              sky=sky)

    print('Elapsed time in pPXF: %.2f s' % (clock() - t))
    plt.pause(1)
Пример #49
0
def ppxf_kinematics_example_sauron():

    # Read a galaxy spectrum and define the wavelength range
    #
    file = 'spectra/NGC4550_SAURON.fits'
    hdu = fits.open(file)
    gal_lin = hdu[0].data
    h1 = hdu[0].header

    lamRange1 = h1['CRVAL1'] + np.array(
        [0., h1['CDELT1'] * (h1['NAXIS1'] - 1)])
    FWHM_gal = 4.2  # SAURON has an instrumental resolution FWHM of 4.2A.

    # If the galaxy is at a significant redshift (z > 0.03), one would need to apply
    # a large velocity shift in PPXF to match the template to the galaxy spectrum.
    # This would require a large initial value for the velocity (V > 1e4 km/s)
    # in the input parameter START = [V,sig]. This can cause PPXF to stop!
    # The solution consists of bringing the galaxy spectrum roughly to the
    # rest-frame wavelength, before calling PPXF. In practice there is no
    # need to modify the spectrum before the usual LOG_REBIN, given that a
    # red shift corresponds to a linear shift of the log-rebinned spectrum.
    # One just needs to compute the wavelength range in the rest-frame
    # and adjust the instrumental resolution of the galaxy observations.
    # This is done with the following three commented lines:
    #
    # z = 1.23 # Initial estimate of the galaxy redshift
    # lamRange1 = lamRange1/(1+z) # Compute approximate restframe wavelength range
    # FWHM_gal = FWHM_gal/(1+z)   # Adjust resolution in Angstrom

    galaxy, logLam1, velscale = util.log_rebin(lamRange1, gal_lin)
    galaxy = galaxy / np.median(
        galaxy)  # Normalize spectrum to avoid numerical issues
    noise = galaxy * 0 + 0.0047  # Assume constant noise per pixel here

    # Read the list of filenames from the Single Stellar Population library
    # by Vazdekis (2010, MNRAS, 404, 1639) http://miles.iac.es/. A subset
    # of the library is included for this example with permission
    vazdekis = glob.glob('miles_models/Mun1.30Z*.fits')
    FWHM_tem = 2.51  # Vazdekis+10 spectra have a constant resolution FWHM of 2.51A.

    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = fits.open(vazdekis[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange2 = h2['CRVAL1'] + np.array(
        [0., h2['CDELT1'] * (h2['NAXIS1'] - 1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange2,
                                               ssp,
                                               velscale=velscale)
    templates = np.empty((sspNew.size, len(vazdekis)))

    # Convolve the whole Vazdekis library of spectral templates
    # with the quadratic difference between the SAURON and the
    # Vazdekis instrumental resolution. Logarithmically rebin
    # and store each template as a column in the array TEMPLATES.

    # Quadratic sigma difference in pixels Vazdekis --> SAURON
    # The formula below is rigorously valid if the shapes of the
    # instrumental spectral profiles are well approximated by Gaussians.
    #
    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    sigma = FWHM_dif / 2.355 / h2['CDELT1']  # Sigma difference in pixels

    for j, file in enumerate(vazdekis):
        hdu = fits.open(file)
        ssp = hdu[0].data
        ssp = ndimage.gaussian_filter1d(ssp, sigma)
        sspNew, logLam2, velscale = util.log_rebin(lamRange2,
                                                   ssp,
                                                   velscale=velscale)
        templates[:, j] = sspNew / np.median(sspNew)  # Normalizes templates

    # The galaxy and the template spectra do not have the same starting wavelength.
    # For this reason an extra velocity shift DV has to be applied to the template
    # to fit the galaxy spectrum. We remove this artificial shift by using the
    # keyword VSYST in the call to PPXF below, so that all velocities are
    # measured with respect to DV. This assume the redshift is negligible.
    # In the case of a high-redshift galaxy one should de-redshift its
    # wavelength to the rest frame before using the line below (see above).
    #
    c = 299792.458
    dv = (logLam2[0] - logLam1[0]) * c  # km/s

    vel = 450.  # Initial estimate of the galaxy velocity in km/s
    z = np.exp(vel / c) - 1  # Relation between velocity and redshift in pPXF
    goodPixels = util.determine_goodpixels(logLam1, lamRange2, z)

    # Here the actual fit starts. The best fit is plotted on the screen.
    # Gas emission lines are excluded from the pPXF fit using the GOODPIXELS keyword.
    #
    start = [vel, 180., 0, 0]  # (km/s), starting guess for [V,sigma]
    t = clock()

    pp = ppxf(templates,
              galaxy,
              noise,
              velscale,
              start,
              goodpixels=goodPixels,
              plot=True,
              moments=4,
              degree=4,
              vsyst=dv)

    print("Formal errors:")
    print("     dV    dsigma   dh3      dh4")
    print("".join("%8.2g" % f for f in pp.error * np.sqrt(pp.chi2)))

    print('Elapsed time in PPXF: %.2f s' % (clock() - t))
Пример #50
0
def run_ppxf(spectra,
             velscale,
             ncomp=2,
             has_emission=True,
             mdegree=-1,
             degree=20,
             pkls=None,
             plot=False,
             data_sky=None):
    """ Run pPXF in a list of spectra"""
    if isinstance(spectra, str):
        spectra = [spectra]
    if isinstance(pkls, str):
        pkls = [pkls]
    if pkls == None:
        pkls = [x.replace(".fits", ".pkl") for x in spectra]
    ##########################################################################
    # Load templates for both stars and gas
    star_templates, logLam2, delta, miles = stellar_templates(velscale)
    gas_templates, logLam_gas, delta_gas, gas_files = emission_templates(
        velscale)
    ##########################################################################
    # Join templates in case emission lines are used.
    if has_emission:
        templates = np.column_stack((star_templates, gas_templates))
    else:
        templates = star_templates
    ##########################################################################
    if ncomp == 1:
        components = 0
        moments = [4]
        templates_names = miles
    elif ncomp == 2:
        components = np.hstack(
            (np.zeros(len(star_templates[0])), np.ones(len(gas_templates[0]))))
        moments = [4, 2]
        templates_names = np.hstack((miles, gas_files))

    else:
        raise Exception("ncomp has to be 1 or 2.")
    for i, spec in enumerate(spectra):
        print "pPXF run of spectrum {0} ({1} of {2})".format(
            spec, i + 1, len(spectra))
        pkl = pkls[i]
        ######################################################################
        # Read one galaxy spectrum and define the wavelength range
        specfile = os.path.join(data_dir, spec)
        hdu = pf.open(specfile)
        spec_lin = hdu[0].data
        h1 = pf.getheader(specfile)
        lamRange1 = h1['CRVAL1'] + np.array(
            [0., h1['CDELT1'] * (h1['NAXIS1'] - 1)])
        ######################################################################
        # Degrade observed spectra to match template resolution
        FWHM_dif = np.sqrt(FWHM_tem**2 - FWHM_spec**2)
        sigma = FWHM_dif / 2.355 / delta  # Sigma difference in pixels
        spec_lin = ndimage.gaussian_filter1d(spec_lin, sigma)
        ######################################################################
        # Rebin to log scale
        galaxy, logLam1, velscale = util.log_rebin(lamRange1,
                                                   spec_lin,
                                                   velscale=velscale)
        ######################################################################
        # First guess for the noise
        noise = np.ones_like(galaxy) * np.std(galaxy - medfilt(galaxy, 5))
        ######################################################################
        # Calculate difference of velocity between spectrum and templates
        # due to different initial wavelength
        dv = (logLam2[0] - logLam1[0]) * c
        ######################################################################
        # Set first guess from setup files
        start, goodPixels = read_setup_file(spec, logLam1, mask_emline=False)
        ######################################################################
        # Expand start variable to include multiple components
        if ncomp > 1:
            start = [start, [start[0], 30]]
        ######################################################################
        # Read sky in needed
        if data_sky == None:
            sky = None
        else:
            sky_lin = pf.getdata(data_sky[i])
            sky_lin = ndimage.gaussian_filter1d(sky_lin, sigma)
            sky, logLam1, velscale = util.log_rebin(lamRange1,
                                                    sky_lin,
                                                    velscale=velscale)
            sky = sky.reshape(-1, 1)
        ######################################################################
        # First pPXF interaction
        if os.path.exists(spec.replace(".fits", ".pkl")):
            pp0 = pPXF(spec, velscale, pklfile=spec.replace(".fits", ".pkl"))
            noise0 = pp0.noise
        else:
            pp0 = ppxf(templates,
                       galaxy,
                       noise,
                       velscale,
                       start,
                       goodpixels=goodPixels,
                       plot=False,
                       moments=moments,
                       degree=12,
                       mdegree=-1,
                       vsyst=dv,
                       component=components,
                       sky=sky)
            rms0 = galaxy[goodPixels] - pp0.bestfit[goodPixels]
            noise0 = 1.4826 * np.median(np.abs(rms0 - np.median(rms0)))
            noise0 = np.zeros_like(galaxy) + noise0
        # Second pPXF interaction, realistic noise estimation
        pp = ppxf(templates,
                  galaxy,
                  noise0,
                  velscale,
                  start,
                  goodpixels=goodPixels,
                  plot=plot,
                  moments=moments,
                  degree=degree,
                  mdegree=mdegree,
                  vsyst=dv,
                  component=components,
                  sky=sky)
        # pp.template_files = templates_names
        # pp.has_emission = has_emission
        ######################################################################
        # Save to output file to keep session
        with open(pkl, "w") as f:
            pickle.dump(pp, f)
        ######################################################################
    return
Пример #51
0
def VIMOS_ppxf(l1, l2, start, plot=True, nsimulations=False):

    spec = getdata(result['ORIGINALFILE'].loc[0], 1)
    header = getheader(result['ORIGINALFILE'].loc[0], 1)

    quadrant = header['ESO OCS CON QUAD']

    lamRange = header['CRVAL1'] + np.array(
        [0., header['CD1_1'] * (header['NAXIS1'] - 1)])
    wavelength = np.linspace(lamRange[0], lamRange[1], header['NAXIS1'])

    ix_start = np.where(wavelength > l1)[0][0]
    ix_end = np.where(wavelength < l2)[0][-1]

    w_start = wavelength[ix_start]
    w_end = wavelength[ix_end]

    lamRange = [w_start, w_end]

    galaxy, logLam1, velscale = util.log_rebin(lamRange, spec)

    wavelength_log = np.exp(logLam1)

    logLam2, templates = utilities.get_templates(velscale, l1, l2)
    dv = (logLam2[0] - logLam1[0]) * c

    df_columns = [
        'slit_id', 'rv_ppxf', 'rv_ppxf_err', 'sigma_ppxf', 'sigma_ppxf_err',
        'seeing', 'vhelio'
    ]
    final_frame = pd.DataFrame(columns=df_columns)

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

    for i in tqdm(range(0, len(result))):

        single = result.iloc[i]

        hdu = fits.open(single['ORIGINALFILE'])

        header = hdu[0].header
        galaxy, _, _ = util.log_rebin(lamRange,
                                      hdu[1].data[ix_start:ix_end],
                                      velscale=velscale)
        noise, _, _ = util.log_rebin(lamRange,
                                     hdu[2].data[ix_start:ix_end],
                                     velscale=velscale)
        noise = noise + 0.001  # Some spectra have noise = 0
        twoD = hdu[3].data
        thumbnail = hdu[4].data

        hdu.close()

        seeing = header[
            'ESO TEL IA FWHMLINOBS']  # Delivered seeing on IA detector
        slit_id = single['ID']
        quadrant = slit_id[2]
        rv_fxcor = single['VREL']
        sg = header['SG_NORM']
        sn1 = header['SN1']
        sn2 = header['SN2']
        RA_g = single['RA_g']
        DEC_g = single['DEC_g']

        vhelio = utilities.get_vhelio(
            header)  # Calculate heliocentric velocity
        start = [rv_fxcor, 10]

        if (quadrant == '1') | (quadrant == '3'):
            pixelmask = pixelmask_Q1Q3
        else:
            pixelmask = pixelmask_normal

        goodpixels = utilities.make_goodpixels(pixelmask, logLam1, logLam2)

        rv, sigma, error_rv, error_sigma, chi2, bestfit, residuals, zp1, output_wavelengths = run_ppxf(
            wavelength_log, templates, galaxy, noise, velscale, start,
            goodpixels, dv)

        if plot:

            kwargs = {
                'output_wavelengths': output_wavelengths,
                'ix_start': ix_start,
                'ix_end': ix_end,
                'slit_id': slit_id,
                'rv': rv,
                'sigma': sigma,
                'chi2': chi2,
                'pixelmask': pixelmask,
                'zp1': zp1,
                'rv_fxcor': rv_fxcor,
                'sg': sg,
                'sn1': sn1,
                'sn2': sn2,
                'RA_g': RA_g,
                'DEC_g': DEC_g
            }

            figure = ppplot.ppxfplot(twoD, galaxy, noise, bestfit, residuals,
                                     thumbnail, **kwargs)
            figure.savefig(
                '/Volumes/VINCE/OAC/ppxf/figures/{}.png'.format(slit_id))
            plt.close(figure)

        df_tmp = pd.DataFrame(
            [[slit_id, rv, error_rv, sigma, error_sigma, seeing, vhelio]],
            columns=df_columns)
        final_frame = final_frame.append(df_tmp, ignore_index=True)

        final_frame.to_csv('ppxf_results.csv', index=False)

        if nsimulations:

            samples = []
            rv_mc = []

            for j in xrange(nsimulations):
                noise_mc = noise * np.random.normal(size=noise.size)
                galaxy_mc = bestfit + noise_mc

                samples.append((wavelength_log, templates, galaxy_mc, noise,
                                velscale, start, goodpixels, dv))
                rv, sigma, chi2, error_rv, error_sigma, bestfit, residuals, zp1, output_wavelengths = run_ppxf(
                    wavelength_log, templates, galaxy_mc, noise, velscale,
                    start, goodpixels, dv)
                rv_mc.append(rv)

                #workers = min(multiprocessing.cpu_count(), 2)
                #pool = multiprocessing.Pool(processes=workers)

                #print 'Using', workers, 'workers'

                #sample_results = pool.map(_boot_VIMOS_ppxf, samples)

                #print 'past sample_results'
    return final_frame
Пример #52
0
def ppxf_nifs_kinematics():

    file_dir = path.dirname(path.realpath(__file__))  # path of this procedure

    # Read a galaxy spectrum and define the wavelength range
    #
    file = file_dir + '/spectra/pgc12557_combined.fits'  # '/spectra/NGC4550_SAURON.fits'  # my current file location
    hdu = fits.open(file)
    gal_lin = hdu[1].data  # gal_lin = hdu[0].data
    # h1 = hdu[0].header
    h1 = hdu[
        1].header  # I need to use 1st extension header (0=general, 1=science, 2=variance, 3=data quality flags)
    '''
    print(h1)
    
    BITPIX  =                  -32 / array data type                                
    NAXIS   =                    3 / number of array dimensions                     
    NAXIS1  =                   71                                                  
    NAXIS2  =                   69                                                  
    NAXIS3  =                 2040                                 
    PCOUNT  =                    0 / number of parameters                           
    GCOUNT  =                    1 / number of groups                               
    EXTNAME = 'SCI     '           / Extension name                                 
    EXTVER  =                    1 / Extension version                              
    INHERIT =                    F / Inherits global header                         
    ORIGIN  = 'NOAO-IRAF FITS Image Kernel July 2003' / FITS file originator        
    OBJECT  = 'PGC12557'           / Name of the object observed                    
    DISPAXIS=                    3 / Dispersion axis                                
    PIXSCALE=                 0.05 / Pixel scale in arcsec/pixel                    
    CTYPE1  = 'LINEAR  '           / coordinate type for the dispersion axis        
    CTYPE2  = 'LINEAR  '           / coordinate type for the spatial axis           
    DC-FLAG =                    0 /                                                
    CD1_1   =                 0.05 /                                                
    CD2_2   =                 0.05 /                                                
    DCLOG1  = 'Transform'                                                           
    WCSDIM  =                    3 /                                                
    CRVAL1  =                2.987                                                  
    CRPIX1  =                  68.                                                  
    CRPIX2  =                   2.                                                  
    WAT1_001= 'wtype=linear axtype=xi' /                                            
    WAT2_001= 'wtype=linear axtype=eta' /                                           
    CTYPE3  = 'LINEAR  '           /                                                
    WAT3_001= 'wtype=linear axtype=wave' /                                          
    CRVAL3  =      19971.869140625 /                                                
    CD3_3   =         2.1321439743 /                                                
    AIRMASS =                1.374                                                  
    CRPIX3  =                   1.                                                  
    LTM1_1  =                   1.                                                  
    LTM2_2  =                   1.                                                  
    LTM3_3  =                   1.                                                  
    WAT0_001= 'system=world'
    END                                     
    '''
    '''
    # NOTE:
    Copied from util.log_rebin():
    lamRange: two elements vector containing the central wavelength
        of the first and last pixels in the spectrum, which is assumed
        to have constant wavelength scale! E.g. from the values in the
        standard FITS keywords: LAMRANGE = CRVAL1 + [0, CDELT1*(NAXIS1 - 1)].
        It must be LAMRANGE[0] < LAMRANGE[1].
    '''
    # lamRange1 = h1['CRVAL1'] + np.array([0., h1['CDELT1']*(h1['NAXIS1'] - 1)])  # original
    # lamRange1 = h1['CRVAL3'] + np.array([0., h1['CD3_3']*(h1['CRPIX3'])])  # [ 19971.86914062  19974.0012846 ]
    #  if I use CRPIX3, probably don't want CRPIX3 - 1 because CRPIX3 = 1., and need lamRange1[0] < lamRange1[1]
    lamRange1 = h1['CRVAL3'] + np.array(
        [0., h1['CD3_3'] *
         (h1['NAXIS3'] - 1)])  # [ 19971.86914062  24319.31070422]
    print(lamRange1, 'l1')

    # print(gal_lin[0][20]) all 0s
    # print((gal_lin[300][35])) NOT all 0s!
    # print(len(lamRange1))  # len(lamRange1) = 2, # len(gal_lin) = 2040, len(gal_lin[0]) = 69, len(gal_lin[0][1]) = 71
    # 2040 --> NAXIS 3, 69 --> NAXIS2, 71 --> NAXIS1
    # HMM: want gal_lin to be spectrum itself, which should just be 1d array
    # There's a len 2040 spectrum at each gal_lin[:,x,y]

    # CUT SPECTRUM TO WAVELENGTH RANGE 2.26 - 2.42
    # SO: gal_lin is an array len(2040) starting at lamRange1[0] and finishing at lamRange1[1], with each pixel in
    # between separated by h1['CD3_3']. So find [22600 - lamRange1[0]] / CD3_3, and that should give the number of
    # pixels between pixel 1 and the pixel corresponding roughly to 2.26 microns. Then find [24200 - lamRange1[1]] /
    # CD3_3, which should give the number of pixels between pixel 1 and the pixel corresponding to 2.42 microns.
    start = 22600.
    stop = 24200.
    cut1 = (start - lamRange1[0]) / h1['CD3_3']
    cut2 = (stop - lamRange1[0]) / h1['CD3_3']
    # print(cut1, cut2, 'cuts')  # 1232.62354281, 1983.04191009
    gal_lin = gal_lin[int(cut1):int(cut2)]  # [1233:1983]
    # start1 = h1['CRVAL3'] + h1['CD3_3'] * int(cut1)
    # stop1 = h1['CRVAL3'] + h1['CD3_3'] * int(cut2)
    # print(start1, stop1, 'me')
    lamRange1 = [
        h1['CRVAL3'] + h1['CD3_3'] * int(cut1),
        h1['CRVAL3'] + h1['CD3_3'] * int(cut2)
    ]
    print(lamRange1, 'l1, cut')
    # len(gal_lin) is now NOT 2040 but 1983 - 1233 = 750

    FWHM_gal = 4.2  # SAURON has an instrumental resolution FWHM of 4.2A.  # BUCKET: do I need this? If so what for?

    # If the galaxy is at significant redshift, one should bring the galaxy
    # spectrum roughly to the rest-frame wavelength, before calling pPXF
    # (See Sec2.4 of Cappellari 2017). In practice there is no
    # need to modify the spectrum in any way, given that a red shift
    # corresponds to a linear shift of the log-rebinned spectrum.
    # One just needs to compute the wavelength range in the rest-frame
    # and adjust the instrumental resolution of the galaxy observations.
    # This is done with the following three commented lines:
    #
    # z = 1.23 # Initial estimate of the galaxy redshift
    # lamRange1 = lamRange1/(1+z) # Compute approximate restframe wavelength range
    # FWHM_gal = FWHM_gal/(1+z)   # Adjust resolution in Angstrom

    # There's a len 2040 spectrum at each gal_lin[:,x,y]
    x = 33
    y = 35
    galaxy, logLam1, velscale = util.log_rebin(
        lamRange1, gal_lin[:, x, y])  # no input velscale --> function returns
    print(len(galaxy), 'len gal')  # 750 now because of cut to gal_lin!
    galaxy = galaxy / np.median(
        galaxy)  # Normalize spectrum to avoid numerical issues
    # print(galaxy)

    # BUCKET: constant noise/pix good assumption for me? If so what value do I use? TRY our noise! Maybe trust more?!
    # basically bootstrap the noise!
    # Do one fit with flat noise, then save the best fit spectrum and the residuals.
    # Then, iterate ~200 times. For these iterations, set bias = 0.0. Each iteration, for each pixel, use the spectrum
    # value as the center of a gaussian and use the residuals at that pixel value as the width of the gaussian. Draw
    # from the resultant distribution to make the new noise. For each iteration, save the output V, sigma, h3, h4, and
    # print each spectrum so that we can see it evolving (it should look more like a real spectrum, rather than smooth
    # curve without lines)
    noise = np.full_like(galaxy,
                         0.0047)  # Assume constant noise per pixel here

    # MEANTIME: why is output velocity close to systemic insted of close to 0, if I'm dealing with redshift already?
    # SET bias = 0
    #
    # print(noise.shape)  # 751,
    # print(galaxy.shape)  # 751,

    # Read the list of filenames from the Single Stellar Population library
    # by Vazdekis (2010, MNRAS, 404, 1639) http://miles.iac.es/. A subset
    # of the library is included for this example with permission
    vazdekis = glob.glob(
        file_dir +
        '/veltemps/*.fits')  # '/miles_models/Mun1.30Z*.fits')  # my new
    # BUCKET: what are FWHM of spectra in the veltemps library??
    FWHM_tem = 2.51  # Vazdekis+10 spectra have a constant resolution FWHM of 2.51A.
    # BUCKET: what spectral sampling compared to galaxy do we want for templates??

    # velscale_ratio = 2  # 1.23  # 2  # adopts 2x higher spectral sampling for templates than for galaxy
    # PROBLEM!! If velscale_ratio is not integer, we get issue later because we slice a list with velscale_ratio
    # so need to change velscale? But it's set by util.log_rebin originally! Only need this if oversampling the
    # templates, which I'm not doing

    # Extract the wavelength range and logarithmically rebin one spectrum
    # to a velocity scale 2x smaller than the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    print(vazdekis[0], 'template name')
    hdu = fits.open(
        vazdekis[0]
    )  # do for just one template to determine size needed for array containing all templates
    ssp = hdu[
        1].data  # was hdu[0], but that's generic header rather than science header
    h2 = hdu[1].header  # was hdu[0]
    '''
    for line in h2:
        print(line, h2[line])
    
    XTENSION IMAGE
    BITPIX -32
    NAXIS 1
    NAXIS1 1721
    PCOUNT 0
    GCOUNT 1
    EXTNAME SCI
    EXTVER 1
    INHERIT False
    ORIGIN NOAO-IRAF FITS Image Kernel July 2003
    OBJECT BD-01 3097
    DATE 2015-02-15T13:32:06
    IRAF-TLM 2015-02-15T13:32:30
    NFPAD 2015-02-14T14:40:41
    GEM-TLM 2015-02-14T14:40:41
    DISPAXIS 1
    PIXSCALE 0.043
    NSCUTSEC [1:2040,1145:1213]
    NSCUTSPC 13
    FIXPIX Feb 14  8:44 Bad pixel file is tmpdq20234_650
    CTYPE1 LINEAR
    CD1_1 2.13
    CTYPE2 LINEAR
    CD2_2 0.04570113
    DCLOG1 Transform
    DC-FLAG 0
    WCSDIM 3
    CRVAL1 20628.29
    CRPIX1 1.0
    CRPIX2 -28.0
    WAXMAP01 1 0 0 29 0 0
    WAT1_001 wtype=linear axtype=wave
    WAT2_001 wtype=linear axtype=eta
    CTYPE3 LINEAR
    WAT3_001 wtype=linear axtype=xi
    CRVAL3 1.751
    CD3_3 0.103
    LTV2 -29.0
    LTM1_1 1.0
    LTM2_2 1.0
    LTM3_3 1.0
    WAT0_001 system=image
    EXPTIME 25.0
    IMCMB001 xatfbrsnN20070508S0187.fits[SCI]
    IMCMB002 xatfbrsnN20070508S0190.fits[SCI]
    IMCMB003 xatfbrsnN20070508S0191.fits[SCI]
    IMCMB004 xatfbrsnN20070508S0194.fits[SCI]
    NCOMBINE 4
    GAINORIG 1.0
    RONORIG 0.0
    GAIN 2.666667
    RDNOISE 0.0
    '''
    # lamRange2 = h2['CRVAL1'] + np.array([0., h2['CDELT1']*(h2['NAXIS1'] - 1)])  # original
    lamRange2 = h2['CRVAL1'] + np.array([0., h2['CD1_1'] * (h2['NAXIS1'] - 1)
                                         ])  # BUCKET want NAXIS - 1?
    # lamRange2 = h2['CRVAL1'] + np.array([0., h2['CD1_1']*(h2['CRPIX1'])])  # or use CRPIX1??
    print(lamRange2, 'l2')  # [ 20628.29  24291.89]
    # print((lamRange2[1] - lamRange2[0])/h2['CD1_1'], 'num of steps in lam2')  # 1720.
    # print(len(ssp), 'len ssp')  # 1721
    sspNew, logLam2, velscale_temp = util.log_rebin(
        lamRange2, ssp, velscale=velscale)  # /velscale_ratio)
    # print(len(sspNew), 'len sspnew')  # 622 hmmmm NEED THIS TO BE >= (len(galaxy)=750)  # FIXED, now 1791
    templates = np.empty((sspNew.size, len(vazdekis)))

    # Convolve the whole Vazdekis library of spectral templates
    # with the quadratic difference between the SAURON and the
    # Vazdekis instrumental resolution. Logarithmically rebin
    # and store each template as a column in the array TEMPLATES.

    # Quadratic sigma difference in pixels Vazdekis --> SAURON
    # The formula below is rigorously valid if the shapes of the
    # instrumental spectral profiles are well approximated by Gaussians.
    #
    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    # sigma = FWHM_dif/2.355/h2['CDELT1']  # Sigma difference in pixels
    sigma = FWHM_dif / 2.355 / h2['CD1_1']  # Sigma difference in pixels

    for j, file in enumerate(
            vazdekis
    ):  # now for each template file; so why do the thing above with just 1??
        hdu = fits.open(file)
        # ssp = hdu[0].data
        ssp = hdu[1].data
        ssp = ndimage.gaussian_filter1d(ssp, sigma)
        # ndimage.gaussian_filter takes input array (ssp) and filters it. Sigma = standard deviation of Gaussian kernel
        # used to filter the array
        # note: discrete convolution is defined (for any 2 arrays a, v): (a*v)[n] == sum m(-inf to inf) of a[m]*v[n-m]
        # where a is the original curve and v is the gaussian
        # print(len(ssp))  # 1721 --> currently by default being resampled to be 116, want it to be resampled to be 71
        sspNew, logLam2, velscale_temp = util.log_rebin(
            lamRange2, ssp, velscale=velscale)  # /velscale_ratio)
        # print(velscale_temp, 'vt')  # 78.82967746
        # print(velscale, 'v')  # 78.82967746
        # print(len(sspNew))  # need this to be >= len(galaxy)  # now 1791
        templates[:, j] = sspNew / np.median(sspNew)  # Normalizes templates

    # print(len(templates[0]))  # len(templates)=29, len(templates[0] = 19)
    # The galaxy and the template spectra do not have the same starting wavelength.
    # For this reason an extra velocity shift DV has to be applied to the template
    # to fit the galaxy spectrum. We remove this artificial shift by using the
    # keyword VSYST in the call to PPXF below, so that all velocities are
    # measured with respect to DV. This assume the redshift is negligible.
    # In the case of a high-redshift galaxy one should de-redshift its
    # wavelength to the rest frame before using the line below (see above).
    #
    c = 299792.458
    dv = (logLam2[0] - logLam1[0]) * c  # km/s
    '''
    if velscale_ratio > 1:
        dv = (np.mean(logLam2[:velscale_ratio]) - logLam1[0])*c  # km/s
    else:
        dv = (logLam2[0] - logLam1[0])*c  # km/s
    '''

    z = 0.016561  # z = 0.0015  # Initial redshift estimate of the galaxy
    goodPixels = util.determine_goodpixels(logLam1, lamRange2, z)

    # Here the actual fit starts. The best fit is plotted on the screen.
    # Gas emission lines are excluded from the pPXF fit using the GOODPIXELS keyword.
    #
    vel = c * np.log(1 + z)  # eq.(8) of Cappellari (2017)
    start = [vel, 200.]  # [vel, 200.]  # (km/s), starting guess for [V, sigma]
    t = clock()
    #  print(galaxy.shape[0])  # = len(galaxy) = 750
    # print(goodPixels)

    # print(max(noise[:, x, y]), min(noise[:, x, y]), np.median(noise[:, x, y]), np.mean(noise[:, x, y]))
    # 0.00106575 -2.77079e-05 4.62628e-05 5.89877e-05
    pp = ppxf(templates,
              galaxy,
              noise,
              velscale,
              start,
              goodpixels=goodPixels,
              plot=True,
              moments=4,
              degree=4,
              vsyst=dv,
              velscale_ratio=1)  # velscale_ratio=velscale_ratio)

    print("Formal errors:")
    print("     dV    dsigma   dh3      dh4")
    print("".join("%8.2g" % f for f in pp.error * np.sqrt(pp.chi2)))

    print('Elapsed time in pPXF: %.2f s' % (clock() - t))

    # If the galaxy is at significant redshift z and the wavelength has been
    # de-redshifted with the three lines "z = 1.23..." near the beginning of
    # this procedure, the best-fitting redshift is now given by the following
    # commented line (equation 2 of Cappellari et al. 2009, ApJ, 704, L34;
    # http://adsabs.harvard.edu/abs/2009ApJ...704L..34C)
    #
    # print('Best-fitting redshift z:', (z + 1)*(1 + pp.sol[0]/c) - 1)
    return pp.bestfit, pp.galaxy, pp.sol  # output_spectrum, output_noise  # for use in noise_in
Пример #53
0
def run_stellar_templates(velscale):
    """ Run over stellar templates. """
    temp_dir = os.path.join(home, "stellar_templates/MILES_FWHM_3.6")
    standards_dir = os.path.join(home, "data/standards")
    table = os.path.join(tables_dir, "lick_standards.txt")
    ids = np.loadtxt(table, usecols=(0,), dtype=str).tolist()
    star_pars = np.loadtxt(table, usecols=(26,27,28,))
    for night in nights:
        cdir = os.path.join(standards_dir, night)
        os.chdir(cdir)
        standards = sorted([x for x in os.listdir(".") if x.endswith(".fits")])
        for standard in standards:
            name = standard.split(".")[0].upper()
            if name not in ids:
                continue
            print standard
            idx = ids.index(name)
            T, logg, FeH = star_pars[idx]
            tempfile= "MILES_Teff{0:.2f}_Logg{1:.2f}_MH{2:.2f}" \
                       "_linear_FWHM_3.6.fits".format(T, logg, FeH )
            os.chdir(temp_dir)
            template = pf.getdata(tempfile)
            htemp = pf.getheader(tempfile)
            wtemp = htemp["CRVAL1"] + htemp["CDELT1"] * \
                            (np.arange(htemp["NAXIS1"]) + 1 - htemp["CRPIX1"])
            os.chdir(cdir)
            dsigma = np.sqrt((3.7**2 - 3.6**2))/2.335/(wtemp[1]-wtemp[0])
            template = broad2hydra(wtemp, template, 3.6)
            data = pf.getdata(standard)
            w = wavelength_array(standard)
            lamRange1 = np.array([w[0], w[-1]])
            lamRange2 = np.array([wtemp[0], wtemp[-1]])
            # Rebin to log scale
            star, logLam1, velscale = util.log_rebin(lamRange1, data,
                                                       velscale=velscale)
            temp, logLam2, velscale = util.log_rebin(lamRange2, template,
                                                       velscale=velscale)
            w = np.exp(logLam1)
            goodpixels = np.argwhere((w>4700) & (w<6100)).T[0]
            noise = np.ones_like(star)
            dv = (logLam2[0]-logLam1[0])*c
            pp0 = ppxf(temp, star, noise, velscale, [300.,5], plot=False,
                       moments=2, degree=20, mdegree=-1, vsyst=dv, quiet=True,
                       goodpixels=goodpixels)
            noise = np.ones_like(noise) * np.nanstd(star - pp0.bestfit)
            pp0 = ppxf(temp, star, noise, velscale, [0.,5], plot=False,
                       moments=2, degree=20, mdegree=-1, vsyst=dv,
                       goodpixels=goodpixels)
            pp0.w = np.exp(logLam1)
            pp0.wtemp = np.exp(logLam2)
            pp0.template_linear = [wtemp, template]
            pp0.temp = temp
            pp0.ntemplates = 1
            pp0.ngas = 0
            pp0.has_emission = False
            pp0.dv = dv
            pp0.velscale = velscale
            pp0.ngas = 0
            pp0.nsky = 0
            if not os.path.exists("logs"):
                os.mkdir("logs")
            ppsave(pp0, "logs/{0}".format(standard.replace(".fits", "")))
            pp = ppload("logs/{0}".format(standard.replace(".fits", "")))
            pp = pPXF(standard, velscale, pp)
            pp.plot("logs/{0}".format(standard.replace(".fits", ".png")))
            # plt.show()
    return
Пример #54
0
def run_ppxf(spectra, velscale, ncomp=2, has_emission=True, mdegree=-1,
             degree=20, pkls=None, plot=False, data_sky=None):
    """ Run pPXF in a list of spectra"""
    if isinstance(spectra, str):
        spectra = [spectra]
    if isinstance(pkls, str):
        pkls = [pkls]
    if pkls == None:
        pkls = [x.replace(".fits", ".pkl") for x in spectra]
    ##########################################################################
    # Load templates for both stars and gas
    star_templates, logLam2, delta, miles= stellar_templates(velscale)
    gas_templates,logLam_gas, delta_gas, gas_files=emission_templates(velscale)
    ##########################################################################
    # Join templates in case emission lines are used.
    if has_emission:
        templates = np.column_stack((star_templates, gas_templates))
    else:
        templates = star_templates
    ##########################################################################
    if ncomp == 1:
        components = 0
        moments = [4]
        templates_names = miles
    elif ncomp == 2:
        components = np.hstack((np.zeros(len(star_templates[0])),
                                np.ones(len(gas_templates[0]))))
        moments = [4,2]
        templates_names = np.hstack((miles, gas_files))

    else:
        raise Exception("ncomp has to be 1 or 2.")
    for i, spec in enumerate(spectra):
        print "pPXF run of spectrum {0} ({1} of {2})".format(spec, i+1,
              len(spectra))
        pkl = pkls[i]
        ######################################################################
        # Read one galaxy spectrum and define the wavelength range
        specfile = os.path.join(data_dir, spec)
        hdu = pf.open(specfile)
        spec_lin = hdu[0].data
        h1 = pf.getheader(specfile)
        lamRange1 = h1['CRVAL1'] + np.array([0.,h1['CDELT1']*(h1['NAXIS1']-1)])
        ######################################################################
        # Degrade observed spectra to match template resolution
        FWHM_dif = np.sqrt(FWHM_tem**2 - FWHM_spec**2)
        sigma = FWHM_dif/2.355/delta # Sigma difference in pixels
        spec_lin = ndimage.gaussian_filter1d(spec_lin,sigma)
        ######################################################################
        # Rebin to log scale
        galaxy, logLam1, velscale = util.log_rebin(lamRange1, spec_lin, 
                                                   velscale=velscale)
        ######################################################################
        # First guess for the noise
        noise = np.ones_like(galaxy) * np.std(galaxy - medfilt(galaxy, 5))
        ######################################################################
        # Calculate difference of velocity between spectrum and templates
        # due to different initial wavelength
        dv = (logLam2[0]-logLam1[0])*c
        ######################################################################
        # Set first guess from setup files
        start, goodPixels = read_setup_file(spec, logLam1, mask_emline=False)
        ######################################################################
        # Expand start variable to include multiple components
        if ncomp > 1:
            start = [start, [start[0], 30]]
        ######################################################################
        # Read sky in needed
        if data_sky == None:
            sky = None
        else:
            sky_lin = pf.getdata(data_sky[i])
            sky_lin = ndimage.gaussian_filter1d(sky_lin,sigma)
            sky, logLam1, velscale = util.log_rebin(lamRange1, sky_lin,
                                                    velscale=velscale)
            sky = sky.reshape(-1,1)
        ######################################################################
        # First pPXF interaction
        if os.path.exists(spec.replace(".fits", ".pkl")):
            pp0 = pPXF(spec, velscale, pklfile=spec.replace(".fits", ".pkl"))
            noise0 = pp0.noise
        else:
            pp0 = ppxf(templates, galaxy, noise, velscale, start,
                       goodpixels=goodPixels, plot=False, moments=moments,
                       degree=12, mdegree=-1, vsyst=dv, component=components,
                       sky=sky)
            rms0 = galaxy[goodPixels] - pp0.bestfit[goodPixels]
            noise0 = 1.4826 * np.median(np.abs(rms0 - np.median(rms0)))
            noise0 = np.zeros_like(galaxy) + noise0
        # Second pPXF interaction, realistic noise estimation
        pp = ppxf(templates, galaxy, noise0, velscale, start,
                  goodpixels=goodPixels, plot=plot, moments=moments,
                  degree=degree, mdegree=mdegree, vsyst=dv,
                  component=components, sky=sky)
        # pp.template_files = templates_names
        # pp.has_emission = has_emission
        ######################################################################
        # Save to output file to keep session
        with open(pkl, "w") as f:
            pickle.dump(pp, f)
        ######################################################################
    return
Пример #55
0
def ppxf_nifs_kinematics(newgal=None, resid=None, centers=None, coords=[0, 0]):

    file_dir = path.dirname(path.realpath(__file__))  # path of this procedure

    # Read a galaxy spectrum and define the wavelength range
    file = file_dir + '/spectra/pgc12557_combined.fits'  # '/spectra/NGC4550_SAURON.fits'  # my current file location
    hdu = fits.open(file)
    gal_lin = hdu[1].data  # gal_lin = hdu[0].data
    h1 = hdu[
        1].header  # I need to use 1st extension header (0=general, 1=science, 2=variance, 3=data quality flags)

    lamRange1 = h1['CRVAL3'] + np.array(
        [0., h1['CD3_3'] *
         (h1['NAXIS3'] - 1)])  # [ 19971.86914062  24319.31070422]
    print(lamRange1, 'l1')

    # print(gal_lin[0][20]) all 0s  # print((gal_lin[300][35])) NOT all 0s!
    # len(gal_lin) = 2040, len(gal_lin[0]) = 69, len(gal_lin[0][1]) = 71
    # 2040 --> NAXIS 3, 69 --> NAXIS2, 71 --> NAXIS1
    # There's a len 2040 spectrum at each gal_lin[:,x,y] --> gal_lin[:, x, y] is an array len(2040) starting at
    # lamRange1[0] and finishing at lamRange1[1], with each pixel in between separated by h1['CD3_3'].

    # CUT SPECTRUM TO WAVELENGTH RANGE 2.26 - 2.42
    low_lim = 22600.
    up_lim = 24200.
    cut1 = int(
        (low_lim - lamRange1[0]) / h1['CD3_3']
    )  # num pixels between pix 1 & pix corresponding to 2.26 microns
    cut2 = int(
        (up_lim - lamRange1[0]) / h1['CD3_3']
    )  # num pixels between pix 1 & pix corresponding to 2.42 microns
    # print(cut1, cut2, 'cuts')  # 1232.62354281, 1983.04191009 --> int(cut1) = 1232, int(cut2) = 1983
    gal_lin = gal_lin[cut1:
                      cut2]  # cut gal_lin spectrum to new wavelength range
    start = h1['CRVAL3'] + h1['CD3_3'] * cut1
    stop = h1['CRVAL3'] + h1['CD3_3'] * cut2
    lamRange1 = [start, stop
                 ]  # redefine lamRange1 to correspond to new wavelength range
    print(lamRange1, 'l1, cut')
    # len(gal_lin) is now NOT 2040 but 1983 - 1233 = 750

    FWHM_gal = 4.2  # SAURON has an instrumental resolution FWHM of 4.2A.  # BUCKET: do I need this? If so what for?

    # If the galaxy is at significant redshift, one should bring the galaxy
    # spectrum roughly to the rest-frame wavelength, before calling pPXF
    # (See Sec2.4 of Cappellari 2017). In practice there is no
    # need to modify the spectrum in any way, given that a red shift
    # corresponds to a linear shift of the log-rebinned spectrum.
    # One just needs to compute the wavelength range in the rest-frame
    # and adjust the instrumental resolution of the galaxy observations.
    # This is done with the following three commented lines:
    #
    # z = 1.23 # Initial estimate of the galaxy redshift
    # lamRange1 = lamRange1/(1+z) # Compute approximate restframe wavelength range
    # FWHM_gal = FWHM_gal/(1+z)   # Adjust resolution in Angstrom

    # There's a len 2040 spectrum at each gal_lin[:,x,y]
    x = coords[0]
    y = coords[1]
    # if newgal is None:
    galaxy, logLam1, velscale = util.log_rebin(
        lamRange1, gal_lin[:, x, y])  # no input velscale --> fcn returns it
    print(len(galaxy), 'len gal')  # 750 now because of cut to gal_lin!
    print(np.median(galaxy))
    galaxy = galaxy / np.median(
        galaxy)  # Normalize spectrum to avoid numerical issues
    # else:
    #     galaxy, logLam1, velscale = util.log_rebin(lamRange1, newgal)  # newgal is the spectrum at coords x, y

    # basically bootstrap the noise!
    # Do one fit with flat noise, then save the best fit spectrum and the residuals.
    # Then, iterate ~200 times. For these iterations, set bias = 0.0. Each iteration, for each pixel, use the spectrum
    # value as the center of a gaussian and use the residuals at that pixel value as the width of the gaussian. Draw
    # from the resultant distribution to make the new noise. For each iteration, save the output V, sigma, h3, h4, and
    # print each spectrum so that we can see it evolving (it should look more like a real spectrum, rather than smooth
    # curve without lines)
    noise = np.full_like(galaxy,
                         0.0047)  # Assume constant noise per pixel here

    # MEANTIME: why is output velocity close to systemic insted of close to 0, if I'm dealing with redshift already?
    # SET bias = 0
    #
    print('shape', noise.shape)  # 751,
    # print(galaxy.shape)  # 751,

    # Read the list of filenames from the Single Stellar Population library
    # by Vazdekis (2010, MNRAS, 404, 1639) http://miles.iac.es/. A subset
    # of the library is included for this example with permission
    vazdekis = glob.glob(
        file_dir +
        '/veltemps/*.fits')  # '/miles_models/Mun1.30Z*.fits')  # my new
    # BUCKET: what are FWHM of spectra in the veltemps library??
    FWHM_tem = 2.51  # Vazdekis+10 spectra have a constant resolution FWHM of 2.51A.
    # BUCKET: what spectral sampling compared to galaxy do we want for templates??

    # velscale_ratio = 2  # 1.23  # 2  # adopts 2x higher spectral sampling for templates than for galaxy
    # PROBLEM!! If velscale_ratio is not integer, we get issue later because we slice a list with velscale_ratio
    # so need to change velscale? But it's set by util.log_rebin originally! Only need this if oversampling the
    # templates, which I'm not doing

    # Extract the wavelength range and logarithmically rebin one spectrum
    # to a velocity scale 2x smaller than the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    print(vazdekis[0], 'template name')
    hdu = fits.open(
        vazdekis[0]
    )  # do for just one template to determine size needed for array containing all templates
    ssp = hdu[
        1].data  # was hdu[0], but that's generic header rather than science header
    h2 = hdu[1].header  # was hdu[0]

    lamRange2 = h2['CRVAL1'] + np.array([0., h2['CD1_1'] * (h2['NAXIS1'] - 1)
                                         ])  # BUCKET want NAXIS - 1?
    print(lamRange2, 'l2')  # [ 20628.29  24291.89]
    # print((lamRange2[1] - lamRange2[0])/h2['CD1_1'], 'num of steps in lam2')  # 1720.
    # print(len(ssp), 'len ssp')  # 1721
    sspNew, logLam2, velscale_temp = util.log_rebin(
        lamRange2, ssp, velscale=velscale)  # /velscale_ratio)
    # print(len(sspNew), 'len sspnew')  # 622 hmmmm NEED THIS TO BE >= (len(galaxy)=750)  # FIXED, now 1791
    templates = np.empty((sspNew.size, len(vazdekis)))

    # Convolve the whole Vazdekis library of spectral templates
    # with the quadratic difference between the SAURON and the
    # Vazdekis instrumental resolution. Logarithmically rebin
    # and store each template as a column in the array TEMPLATES.

    # Quadratic sigma difference in pixels Vazdekis --> SAURON
    # The formula below is rigorously valid if the shapes of the
    # instrumental spectral profiles are well approximated by Gaussians.
    #
    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    # sigma = FWHM_dif/2.355/h2['CDELT1']  # Sigma difference in pixels
    sigma = FWHM_dif / 2.355 / h2['CD1_1']  # Sigma difference in pixels

    for j, file in enumerate(
            vazdekis
    ):  # now for each template file; so why do the thing above with just 1??
        hdu = fits.open(file)
        # ssp = hdu[0].data
        ssp = hdu[1].data
        ssp = ndimage.gaussian_filter1d(ssp, sigma)
        # ndimage.gaussian_filter takes input array (ssp) and filters it. Sigma = standard deviation of Gaussian kernel
        # used to filter the array
        # note: discrete convolution is defined (for any 2 arrays a, v): (a*v)[n] == sum m(-inf to inf) of a[m]*v[n-m]
        # where a is the original curve and v is the gaussian
        # print(len(ssp))  # 1721 --> currently by default being resampled to be 116, want it to be resampled to be 71
        sspNew, logLam2, velscale_temp = util.log_rebin(
            lamRange2, ssp, velscale=velscale)  # /velscale_ratio)
        # print(velscale_temp, 'vt')  # 78.82967746
        # print(velscale, 'v')  # 78.82967746
        # print(len(sspNew))  # need this to be >= len(galaxy)  # now 1791
        templates[:, j] = sspNew / np.median(sspNew)  # Normalizes templates

    # print(len(templates[0]))  # len(templates)=29, len(templates[0] = 19)
    # The galaxy and the template spectra do not have the same starting wavelength.
    # For this reason an extra velocity shift DV has to be applied to the template
    # to fit the galaxy spectrum. We remove this artificial shift by using the
    # keyword VSYST in the call to PPXF below, so that all velocities are
    # measured with respect to DV. This assume the redshift is negligible.
    # In the case of a high-redshift galaxy one should de-redshift its
    # wavelength to the rest frame before using the line below (see above).
    #
    c = 299792.458
    dv = (logLam2[0] - logLam1[0]) * c  # km/s
    '''
    if velscale_ratio > 1:
        dv = (np.mean(logLam2[:velscale_ratio]) - logLam1[0])*c  # km/s
    else:
        dv = (logLam2[0] - logLam1[0])*c  # km/s
    '''

    z = 0.016561  # z = 0.0015  # Initial redshift estimate of the galaxy
    goodPixels = util.determine_goodpixels(logLam1, lamRange2, z)

    # Here the actual fit starts. The best fit is plotted on the screen.
    # Gas emission lines are excluded from the pPXF fit using the GOODPIXELS keyword.
    #
    vel = c * np.log(1 + z)  # eq.(8) of Cappellari (2017)
    start = [vel, 200.]  # [vel, 200.]  # (km/s), starting guess for [V, sigma]
    t = clock()
    #  print(galaxy.shape[0])  # = len(galaxy) = 750
    # print(goodPixels)

    # print(max(noise[:, x, y]), min(noise[:, x, y]), np.median(noise[:, x, y]), np.mean(noise[:, x, y]))
    # 0.00106575 -2.77079e-05 4.62628e-05 5.89877e-05
    if newgal is None:
        pp = ppxf(templates,
                  galaxy,
                  noise,
                  velscale,
                  start,
                  goodpixels=goodPixels,
                  plot=True,
                  moments=4,
                  degree=4,
                  vsyst=dv,
                  velscale_ratio=1,
                  bias=0.)  # velscale_ratio=velscale_ratio)

        stuff = pp.bestfit, pp.galaxy, pp.sol, goodPixels
    else:
        pp = ppxf(templates,
                  galaxy,
                  noise,
                  velscale,
                  start,
                  goodpixels=goodPixels,
                  plot=True,
                  moments=4,
                  degree=4,
                  vsyst=dv,
                  velscale_ratio=1,
                  bias=0.)  # velscale_ratio=velscale_ratio)
        pp_new = ppxf(templates,
                      newgal,
                      noise,
                      velscale,
                      start,
                      goodpixels=goodPixels,
                      plot=False,
                      moments=4,
                      degree=4,
                      vsyst=dv,
                      velscale_ratio=1,
                      bias=0.)  # velscale_ratio=velscale_ratio)
        #   pp.plot()      # Plot best fit and gas lines
        x_ax = np.arange(galaxy.size)
        plt.plot(x_ax, pp.galaxy, 'k')
        plt.plot(x_ax, newgal, 'b')

        stuff = pp_new.bestfit, pp_new.galaxy, pp_new.sol

    print("Formal errors:")
    print("     dV    dsigma   dh3      dh4")
    print("".join("%8.2g" % f for f in pp.error * np.sqrt(pp.chi2)))

    print('Elapsed time in pPXF: %.2f s' % (clock() - t))

    # If the galaxy is at significant redshift z and the wavelength has been
    # de-redshifted with the three lines "z = 1.23..." near the beginning of
    # this procedure, the best-fitting redshift is now given by the following
    # commented line (equation 2 of Cappellari et al. 2009, ApJ, 704, L34;
    # http://adsabs.harvard.edu/abs/2009ApJ...704L..34C)
    #
    # print('Best-fitting redshift z:', (z + 1)*(1 + pp.sol[0]/c) - 1)

    return stuff  # output_spectrum, output_noise  # for use in noise_in
Пример #56
0
hdulist = fits.open(name + '.fits')
if len(hdulist) > 1:
    hdu = hdulist[1]
else:
    hdu = hdulist[0]

cube = hdu.data.T  #just remember to always transpose with fits files
hdr_cube = hdu.header
xs, ys, naxis = cube.shape
hdulist.close()
xcube, ycube = np.ogrid[-xc:xs - xc, -yc:ys - yc]
rCube = np.sqrt(xcube * xcube + ycube * ycube)

lamRange1 = hdr_cube['CRVAL3'] + np.array(
    [0., hdr_cube['CD3_3'] * (hdr_cube['NAXIS3'] - 1.)])
tg, logLam1, velscale = util.log_rebin(lamRange1, cube[10, 10, :])

# Read the template
hdu = fits.open('temp_final_%s.fits' % Z)
h_template = hdu[0].header
temp_lin = hdu[0].data

lamRange2 = h_template['CRVAL1'] + np.array(
    [0., h_template['CDELT1'] * (h_template['NAXIS1'] - 1.)])
templates, logLam2, velscale = util.log_rebin(lamRange2,
                                              temp_lin,
                                              velscale=velscale)

# Calculate the offset between the template and the galaxy
c = 299792.458
dv = (logLam2[0] - logLam1[0]) * c
def setup_spectral_library(velscale, FWHM_gal):

    # Read the list of filenames from the Single Stellar Population library
    # by Vazdekis et al. (2010, MNRAS, 404, 1639) http://miles.iac.es/.
    #
    # For this example I downloaded from the above website a set of
    # model spectra with default linear sampling of 0.9A/pix and default
    # spectral resolution of FWHM=2.51A. I selected a Salpeter IMF
    # (slope 1.30) and a range of population parameters:
    #
    #     [M/H] = [-1.71, -1.31, -0.71, -0.40, 0.00, 0.22]
    #     Age = range(1.0, 17.7828, 26, /LOG)
    #
    # This leads to a set of 156 model spectra with the file names like
    #
    #     Mun1.30Zm0.40T03.9811.fits
    #
    # IMPORTANT: the selected models form a rectangular grid in [M/H]
    # and Age: for each Age the spectra sample the same set of [M/H].
    #
    # We assume below that the model spectra have been placed in the
    # directory "miles_models" under the current directory.
    #
    vazdekis = glob.glob('miles_models/Mun1.30*.fits')
    FWHM_tem = 2.51 # Vazdekis+10 spectra have a resolution FWHM of 2.51A.

    # Extract the wavelength range and logarithmically rebin one spectrum
    # to the same velocity scale of the SAURON galaxy spectrum, to determine
    # the size needed for the array which will contain the template spectra.
    #
    hdu = pyfits.open(vazdekis[0])
    ssp = hdu[0].data
    h2 = hdu[0].header
    lamRange_temp = h2['CRVAL1'] + np.array([0.,h2['CDELT1']*(h2['NAXIS1']-1)])
    sspNew, logLam2, velscale = util.log_rebin(lamRange_temp, ssp, velscale=velscale)

    # Create a three dimensional array to store the
    # two dimensional grid of model spectra
    #
    nAges = 26
    nMetal = 6
    templates = np.empty((sspNew.size,nAges,nMetal))

    # Convolve the whole Vazdekis library of spectral templates
    # with the quadratic difference between the SAURON and the
    # Vazdekis instrumental resolution. Logarithmically rebin
    # and store each template as a column in the array TEMPLATES.

    # Quadratic sigma difference in pixels Vazdekis --> SAURON
    # The formula below is rigorously valid if the shapes of the
    # instrumental spectral profiles are well approximated by Gaussians.
    #
    FWHM_dif = np.sqrt(FWHM_gal**2 - FWHM_tem**2)
    sigma = FWHM_dif/2.355/h2['CDELT1'] # Sigma difference in pixels

    # Here we make sure the spectra are sorted in both [M/H]
    # and Age along the two axes of the rectangular grid of templates.
    # A simple alphabetical ordering of Vazdekis's naming convention
    # does not sort the files by [M/H], so we do it explicitly below
    #
    metal = ['m1.71', 'm1.31', 'm0.71', 'm0.40', 'p0.00', 'p0.22']
    for k, mh in enumerate(metal):
        files = [s for s in vazdekis if mh in s]
        for j, filename in enumerate(files):
            hdu = pyfits.open(filename)
            ssp = hdu[0].data
            ssp = ndimage.gaussian_filter1d(ssp,sigma)
            sspNew, logLam2, velscale = util.log_rebin(lamRange_temp, ssp, velscale=velscale)
            templates[:,j,k] = sspNew # Templates are *not* normalized here

    print(np.shape(templates))

    return templates, lamRange_temp
Пример #58
0
def ppxf_simulation_example():

    dir = 'spectra/'
    file = dir + 'Rbi1.30z+0.00t12.59.fits'
    hdu = pyfits.open(file)
    ssp = hdu[0].data
    h = hdu[0].header

    lamRange = h['CRVAL1'] + np.array([0.,h['CDELT1']*(h['NAXIS1']-1)])
    star, logLam, velscale = util.log_rebin(lamRange, ssp)

    # The finite sampling of the observed spectrum is modeled in detail:
    # the galaxy spectrum is obtained by oversampling the actual observed spectrum
    # to a high resolution. This represent the true spectrum, which is later resampled
    # to lower resolution to simulate the observations on the CCD. Similarly, the
    # convolution with a well-sampled LOSVD is done on the high-resolution spectrum,
    # and later resampled to the observed resolution before fitting with PPXF.

    factor = 10                    # Oversampling integer factor for an accurate convolution
    starNew = ndimage.interpolation.zoom(star,factor,order=1) # This is the underlying spectrum, known at high resolution
    star = rebin(starNew,factor)        # Make sure that the observed spectrum is the integral over the pixels

    vel = 0.3      # velocity in *pixels* [=V(km/s)/velScale]
    h3 = 0.1       # Adopted G-H parameters of the LOSVD
    h4 = -0.1
    sn = 60.        # Adopted S/N of the Monte Carlo simulation
    m = 300        # Number of realizations of the simulation
    sigmaV = np.linspace(0.8,4,m) # Range of sigma in *pixels* [=sigma(km/s)/velScale]

    result = np.zeros((m,4)) # This will store the results
    t = clock()
    np.random.seed(123) # for reproducible results

    for j in range(m):

        sigma = sigmaV[j]
        dx = int(abs(vel)+4.0*sigma)   # Sample the Gaussian and GH at least to vel+4*sigma
        x = np.linspace(-dx,dx,2*dx*factor+1) # Evaluate the Gaussian using steps of 1/factor pixels.
        w = (x - vel)/sigma
        w2 = w**2
        gauss = np.exp(-0.5*w2)/(np.sqrt(2.*np.pi)*sigma*factor) # Normalized total(gauss)=1
        h3poly = w*(2.*w2 - 3.)/np.sqrt(3.)           # H3(y)
        h4poly = (w2*(4.*w2 - 12.) + 3.)/np.sqrt(24.) # H4(y)
        losvd = gauss *(1. + h3*h3poly + h4*h4poly)

        galaxy = signal.fftconvolve(starNew,losvd,mode="same") # Convolve the oversampled spectrum
        galaxy = rebin(galaxy,factor) # Integrate spectrum into original spectral pixels
        noise = galaxy/sn        # 1sigma error spectrum
        galaxy = np.random.normal(galaxy, noise) # Add noise to the galaxy spectrum
        start = np.array([vel+np.random.random(), sigma*np.random.uniform(0.85,1.15)])*velscale # Convert to km/s

        pp = ppxf(star, galaxy, noise, velscale, start,
                  goodpixels=np.arange(dx,galaxy.size-dx),
                  plot=False, moments=4, bias=0.5)
        result[j,:] = pp.sol

    print('Calculation time: %.2f s' % (clock()-t))

    plt.clf()
    plt.subplot(221)
    plt.plot(sigmaV*velscale, result[:,0]-vel*velscale, '+k')
    plt.plot(sigmaV*velscale, sigmaV*velscale*0, '-r')
    plt.ylim(-40, 40)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$V - V_{in}\ (km\ s^{-1}$)')

    plt.subplot(222)
    plt.plot(sigmaV*velscale, result[:,1]-sigmaV*velscale, '+k')
    plt.plot(sigmaV*velscale, sigmaV*velscale*0, '-r')
    plt.ylim(-40, 40)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$\sigma - \sigma_{in}\ (km\ s^{-1}$)')

    plt.subplot(223)
    plt.plot(sigmaV*velscale, result[:,2], '+k')
    plt.plot(sigmaV*velscale, sigmaV*velscale*0+h3, '-r')
    plt.ylim(-0.2+h3, 0.2+h3)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$h_3$')

    plt.subplot(224)
    plt.plot(sigmaV*velscale, result[:,3], '+k')
    plt.plot(sigmaV*velscale, sigmaV*velscale*0+h4, '-r')
    plt.ylim(-0.2+h4, 0.2+h4)
    plt.xlabel('$\sigma_{in}\ (km\ s^{-1})$')
    plt.ylabel('$h_4$')

    plt.tight_layout()
    plt.pause(0.01)