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))
def ppxf_population_example_sdss():

    # Read SDSS DR8 galaxy spectrum taken from here http://www.sdss3.org/dr8/
    # The spectrum is *already* log rebinned by the SDSS DR8
    # pipeline and log_rebin should not be used in this case.
    #
    file = 'spectra/NGC3522_SDSS.fits'
    hdu = pyfits.open(file)
    t = hdu[1].data
    z = float(hdu[1].header["Z"]) # SDSS redshift estimate

    # Only use the wavelength range in common between galaxy and stellar library.
    #
    mask = (t.field('wavelength') > 3540) & (t.field('wavelength') < 7409)
    galaxy = t[mask].field('flux')/np.median(t[mask].field('flux'))  # Normalize spectrum to avoid numerical issues
    wave = t[mask].field('wavelength')

    # The noise level is chosen to give Chi^2/DOF=1 without regularization (REGUL=0)
    #
    noise = galaxy*0 + 0.01528           # Assume constant noise per pixel here

    # The velocity step was already chosen by the SDSS pipeline
    # and we convert it below to km/s
    #
    c = 299792.458 # speed of light in km/s
    velscale = np.log(wave[1]/wave[0])*c
    FWHM_gal = 2.76 # SDSS has an instrumental resolution FWHM of 2.76A.

    templates, lamRange_temp = setup_spectral_library(velscale, FWHM_gal)

    # 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 = (np.log(lamRange_temp[0])-np.log(wave[0]))*c # km/s
    vel = c*z # Initial estimate of the galaxy velocity in km/s
    goodpixels = util.determine_goodpixels(np.log(wave),lamRange_temp,vel)

    # Here the actual fit starts. The best fit is plotted on the screen.
    #
    # IMPORTANT: Ideally one would like not to use any polynomial in the fit
    # as the continuum shape contains important information on the population.
    # Unfortunately this is often not feasible, due to small calibration
    # uncertainties in the spectral shape. To avoid affecting the line strength of
    # the spectral features, we exclude additive polynomials (DEGREE=-1) and only use
    # multiplicative ones (MDEGREE=10). This is only recommended for population, not
    # for kinematic extraction, where additive polynomials are always recommended.
    #
    start = [vel, 180.] # (km/s), starting guess for [V,sigma]

    # See the pPXF documentation for the keyword REGUL,
    # for an explanation of the following two lines
    #
    templates /= np.median(templates) # Normalizes templates by a scalar
    regul_err = 0.004 # Desired regularization error

    t = clock()

    plt.clf()
    plt.subplot(211)

    pp = ppxf(templates, galaxy, noise, velscale, start,
              goodpixels=goodpixels, plot=True, moments=4, degree=-1,
              vsyst=dv, clean=False, mdegree=10, regul=1./regul_err)

    # When the two numbers below are the same, the solution is the smoothest
    # consistent with the observed spectrum.
    #
    print('Desired Delta Chi^2: %.4g' % np.sqrt(2*goodpixels.size))
    print('Current Delta Chi^2: %.4g' % ((pp.chi2 - 1)*goodpixels.size))
    print('Elapsed time in PPXF: %.2f s' % (clock() - t))

    plt.subplot(212)
    s = templates.shape
    print(s)
    weights = pp.weights.reshape(s[1],s[2])/pp.weights.sum()
    plt.imshow(np.rot90(weights), interpolation='nearest', cmap='gist_heat',
               aspect='auto', extent=(np.log10(1.0), np.log10(17.7828), -1.9, 0.45))
    plt.colorbar()
    plt.title("Mass Fraction")
    plt.xlabel("log$_{10}$ Age (Gyr)")
    plt.ylabel("[M/H]")
    plt.tight_layout()
    plt.show()

    vazdekis = glob.glob('miles_models/Mun1.30*.fits')
    '''
Example #3
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))
Example #4
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
Example #5
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
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_population_example_sdss():

    # Read SDSS DR8 galaxy spectrum taken from here http://www.sdss3.org/dr8/
    # The spectrum is *already* log rebinned by the SDSS DR8
    # pipeline and log_rebin should not be used in this case.
    #
    file = 'spectra/NGC3522_SDSS_DR8.fits'
    hdu = fits.open(file)
    t = hdu[1].data
    z = float(hdu[1].header["Z"])  # SDSS redshift estimate

    # Only use the wavelength range in common between galaxy and stellar library.
    #
    mask = (t['wavelength'] > 3540) & (t['wavelength'] < 7409)
    flux = t['flux'][mask]
    galaxy = flux / np.median(
        flux)  # Normalize spectrum to avoid numerical issues
    wave = t['wavelength'][mask]

    # The noise level is chosen to give Chi^2/DOF=1 without regularization (REGUL=0)
    #
    noise = galaxy * 0 + 0.01528  # Assume constant noise per pixel here

    # The velocity step was already chosen by the SDSS pipeline
    # and we convert it below to km/s
    #
    c = 299792.458  # speed of light in km/s
    velscale = np.log(wave[1] / wave[0]) * c
    FWHM_gal = 2.76  # SDSS has an instrumental resolution FWHM of 2.76A.

    templates, lamRange_temp, logAge_grid, metal_grid = \
        setup_spectral_library(velscale, FWHM_gal)

    # 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 = c * np.log(lamRange_temp[0] / wave[0])  # km/s
    goodpixels = util.determine_goodpixels(np.log(wave), lamRange_temp, z)

    # Here the actual fit starts. The best fit is plotted on the screen.
    #
    # IMPORTANT: Ideally one would like not to use any polynomial in the fit
    # as the continuum shape contains important information on the population.
    # Unfortunately this is often not feasible, due to small calibration
    # uncertainties in the spectral shape. To avoid affecting the line strength of
    # the spectral features, we exclude additive polynomials (DEGREE=-1) and only use
    # multiplicative ones (MDEGREE=10). This is only recommended for population, not
    # for kinematic extraction, where additive polynomials are always recommended.
    #
    vel = c * np.log(1 + z)  # Initial estimate of the galaxy velocity in km/s
    start = [vel, 180., 0, 0]  # (km/s), starting guess for [V,sigma]

    # See the pPXF documentation for the keyword REGUL,
    # for an explanation of the following two lines
    #
    templates /= np.median(templates)  # Normalizes templates by a scalar
    regul_err = 0.004  # Desired regularization error

    t = clock()

    plt.clf()
    plt.subplot(211)

    pp = ppxf(templates,
              galaxy,
              noise,
              velscale,
              start,
              goodpixels=goodpixels,
              plot=True,
              moments=4,
              degree=-1,
              vsyst=dv,
              clean=False,
              mdegree=10,
              regul=1. / regul_err)

    # When the two numbers below are the same, the solution is the smoothest
    # consistent with the observed spectrum.
    #
    print('Desired Delta Chi^2: %.4g' % np.sqrt(2 * goodpixels.size))
    print('Current Delta Chi^2: %.4g' % ((pp.chi2 - 1) * goodpixels.size))
    print('Elapsed time in PPXF: %.2f s' % (clock() - t))

    print('Mass-weighted <logAge> [Gyr]: %.3g' %
          (np.sum(pp.weights * logAge_grid.ravel()) / np.sum(pp.weights)))
    print('Mass-weighted <[M/H]>: %.3g' %
          (np.sum(pp.weights * metal_grid.ravel()) / np.sum(pp.weights)))

    plt.subplot(212)
    s = templates.shape
    weights = pp.weights.reshape(s[1:]) / pp.weights.sum()
    plt.imshow(np.rot90(weights),
               interpolation='nearest',
               cmap='gist_heat',
               aspect='auto',
               origin='upper',
               extent=[np.log10(1), np.log10(17.7828), -1.9, 0.45])
    plt.colorbar()
    plt.title("Mass Fraction")
    plt.xlabel("log$_{10}$ Age (Gyr)")
    plt.ylabel("[M/H]")
    plt.tight_layout()
    plt.show()
Example #8
0
            lam, full, full_data, logAge_grid, metal_grid, templates = \
            load_bc03_library(x, velscale*(0.9999), FWHM_gal=1, version='S')
        else:
            lam, full, full_data, logAge_grid, metal_grid, templates = \
            load_bc03_library(x, velscale*(0.9999), FWHM_gal=0.1, version='S')
            
        lamRange_temp = [wave[0],wave[-1]]
        
        #normalize templates by median scalar
        norm=np.median(templates)
        templates /= norm
        full /= norm
        
        dv = c*np.log(lamRange_temp[0]/wave[0])  # km/s
        
        goodpixels = util.determine_goodpixels(log_wave, lamRange_temp, z)

        start = [c*np.log(1 + z), 0.01]#3*velscale]
        fixed = [True, True]#, False, False]
        fixed = [False, False]
        print start
        
        pp = ppxf(templates, galaxy, noise, velscale, start,
          goodpixels=goodpixels, plot=False, moments=2, degree=-1,
          vsyst=dv, clean=False, regul=1,
          mdegree=0, reddening=0.1,lam=wave,
          fixed=fixed
          )

        # noise *= np.sqrt(pp.chi2)
        # pp = ppxf(templates, galaxy, noise, velscale, start,
def ppxf_kinematics_example_sdss():

    # Read SDSS DR8 galaxy spectrum taken from here http://www.sdss3.org/dr8/
    # The spectrum is *already* log rebinned by the SDSS DR8
    # pipeline and log_rebin should not be used in this case.
    #
    file = 'spectra/NGC3522_SDSS.fits'
    hdu = pyfits.open(file)
    t = hdu[1].data
    z = float(hdu[1].header["Z"]) # SDSS redshift estimate

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

    # The velocity step was already chosen by the SDSS pipeline
    # and we convert it below to km/s
    #
    c = 299792.458 # speed of light in km/s
    velscale = np.log(wave[1]/wave[0])*c
    FWHM_gal = 2.76 # SDSS has an instrumental resolution FWHM of 2.76A.

    # 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:
    #
    # z = 1.23 # Initial estimate of the galaxy redshift
    # wave = wave/(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')
    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 = 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 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

    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]-np.log(wave[0]))*c # km/s
    vel = c*z # Initial estimate of the galaxy velocity in km/s
    goodpixels = util.determine_goodpixels(np.log(wave),lamRange2,vel)

    # 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=10, 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))
Example #10
0
def ppxfit(ncompfit, brot, bfract, mom):

    velscale = 110.
    file = 'NGC0528-V500.rscube.fits'
    hdu = pyfits.open(file)
    gal_lin = hdu[0].data
    h1 = hdu[0].header

    medfl = np.loadtxt("medgalpy.txt")
    x = medfl[:, 0]
    y = medfl[:, 1]
    sig = medfl[:, 2]
    noise = medfl[:, 3]

    bins = np.loadtxt("voronoi_2d_binning_output.txt", skiprows=1)
    x = bins[:, 0]
    y = bins[:, 1]
    binnum = bins[:, 2]

    binco = np.loadtxt("bins.txt")
    xbin = binco[:, 0]
    ybin = binco[:, 1]

    file = 'galaxybinspy.fits'  # spectra arranged horizontally
    hdu = pyfits.open(file)
    gal_bin = hdu[0].data
    gs = gal_bin.shape
    nbins = gs[0]
    xcut = 0.0
    ycut = 0.0
    delta = h1['CDELT3']
    lamRange1 = h1['CRVAL3'] + np.array(
        [xcut * delta, delta * ((h1['NAXIS3'] - 1) - ycut)])
    FWHM_gal = 6.0  # CALIFA has an instrumental resolution FWHM of 6A.

    galaxyz, logLam1, velscale = util.log_rebin(lamRange1,
                                                gal_bin[0, :],
                                                velscale=velscale)

    galaxy = np.empty((galaxyz.size, nbins))
    noise = np.empty((galaxyz.size, nbins))

    for j in range(nbins):
        galaxy[:, j], logLam1, velscale = util.log_rebin(lamRange1,
                                                         gal_bin[j, :],
                                                         velscale=velscale)
        galaxy[:, j] = galaxy[:, j] / np.median(
            galaxy[:, j])  # Normalize spectrum to avoid numerical issues
        noise[:,
              j] = galaxy[:,
                          j] * 0 + 0.0049  # Assume constant noise per pixel here

    #dir='/home/ppxmt3/astro/MILES/'
    dir = 'galspec/'
    miles = glob.glob(dir + 'Mun*.fits')
    miles.sort()
    FWHM_tem = 2.5  # Miles spectra have a resolution FWHM of 1.8A.

    age = np.empty(len(miles))
    met = np.empty(len(miles))
    #age=np.chararray(len(miles),itemsize=7)
    #met=np.chararray(len(miles),itemsize=5)

    for j in range(len(miles)):
        ast = miles[j][22:29]
        mst = miles[j][17:21]
        pm = miles[j][16:17]
        if pm == 'p': pmn = '+'
        elif pm == 'm': pmn = '-'
        mstpm = (pmn, mst)
        #met[j,:]=miles[j][16:19]
        age[j] = float(ast)
        met[j] = float("".join(mstpm))

    #age2,inda=np.unique(age,return_inverse=True)
    #met2,ind=np.unique(met,return_inverse=True)

    #c=1
    #for i in range(len(age2)/2):
        #indout=np.where(age==age2[c])[0]
        ##print(indout)
        #miles=np.delete(miles,indout)
        #age=np.delete(age,indout)
        #c=c+2

        # Extract the wavelength range and logarithmically rebin one spectrum
        # to the same velocity scale of the CALIFA galaxy spectrum, to determine
        # the size needed for the array which will contain the template spectra.

    hdu = pyfits.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)

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

    # Quadratic sigma difference in pixels miles --> CALIFA
    # 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

    #==========================================================================================================================
    #One component fit - saves veloctiy values in 'NGC528_onecompkin.txt' to be used as initial estimates for two component fit

    if ncompfit == 1:

        templates = np.empty((sspNew.size, len(miles)))
        for j in range(len(miles)):
            hdu = pyfits.open(miles[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

        c = 299792.458
        dv = (logLam2[0] - logLam1[0]) * c  # km/s

        vel = 4750.  # 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)

        start = np.zeros(2)
        output = np.zeros((nbins, 5))
        output[:, 0] = xbin[:]
        output[:, 1] = ybin[:]

        start[:] = [vel, 3. * velscale]  # (km/s), starting guess for [V,sigma]

        for j in range(nbins):
            print('On ', j + 1, ' out of ', nbins)
            print(start)
            pp = ppxf(templates,
                      galaxy[:, j],
                      noise[:, j],
                      velscale,
                      start,
                      goodpixels=goodPixels,
                      degree=4,
                      vsyst=dv,
                      plot=True,
                      moments=mom)
            kinem = np.loadtxt("ppxfout.txt")
            if mom == 2:
                output[j, 2] = kinem[0]  #vel
                output[j, 3] = kinem[1]  #sigma
                output[j, 4] = kinem[2]  #chisq
            if mom == 4:
                output[j, 2] = kinem[0]  #vel
                output[j, 3] = kinem[1]  #sigma
                output[j, 4] = kinem[4]  #chisq

        np.savetxt('NGC528_onecompkinm2nch.txt', output, fmt="%10.3g")

#=========================================================================================================================
#Two component fit

    elif ncompfit == 2:

        # To determine flux fraction of bulge. Set bfract to 0 to disable

        # 'bulgediskblock.fits' is created by running GALFIT to get a galfit.01 file of best fit parameters, then using
        # '>galfit -o3 galfit.01' to get cube of galaxy image, bulge image and disk image

        if bfract == 1:
            file = 'bulgediskblock.fits'
            hdu = pyfits.open(file)
            galb = hdu[1].data
            bulge = hdu[2].data
            disk = hdu[3].data

            # Bin bulge and disk images into same binning as datacube
            nbins = xbin.shape[0]
            avbulge = np.zeros(nbins)
            avdisk = np.zeros(nbins)
            avtot = np.zeros(nbins)
            binflux = np.zeros(nbins)
            x = x.astype(int)
            y = y.astype(int)
            for j in range(nbins):
                b = np.where(binnum == j)[0]
                valbin = b.size
                if valbin == 1:
                    avbulge[j] = bulge[y[b], x[b]]
                    avdisk[j] = disk[y[b], x[b]]
                    avtot[j] = galb[x[b], y[b]]
                else:
                    avbulge[j] = np.median(bulge[y[b], x[b]])
                    avdisk[j] = np.median(disk[y[b], x[b]])
                    avtot[j] = np.median(galb[x[b], y[b]])

            bulge_fraction = avbulge / (avbulge + avdisk)

            hdu = pyfits.PrimaryHDU(bulge_fraction)
            hdu.writeto('bulge_fraction.fits', clobber=True)


#====================================================================================

        templates = np.empty((sspNew.size, 2 * len(miles)))
        ssparr = np.empty((ssp.size, len(miles)))

        for j in range(len(miles)):
            hdu = pyfits.open(miles[j])
            ssparr[:, j] = hdu[0].data
            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
        for j in range(len(miles), 2 * len(miles)):
            hdu = pyfits.open(miles[j - len(miles)])
            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

        component = np.zeros((2 * len(miles)), dtype=np.int)
        component[0:len(miles)] = 0
        component[len(miles):] = 1

        c = 299792.458
        dv = (logLam2[0] - logLam1[0]) * c  # km/s
        vel = 4750.  # 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)

        kin = np.loadtxt('NGC528_onecompkinnch.txt')
        xbin = kin[:, 0]
        ybin = kin[:, 1]
        vpxf = kin[:, 2]
        spxf = kin[:, 3]
        occh = kin[:, 4]
        velbulge = vel
        sigdisk = 50.

        file = 'bulge_fraction.fits'  # Read out bulge fraction for each bin
        hdu = pyfits.open(file)
        bulge_fraction = hdu[0].data

        bvel = np.zeros(nbins)
        bsig = np.zeros(nbins)
        bh3 = np.zeros(nbins)
        bh4 = np.zeros(nbins)
        dvel = np.zeros(nbins)
        dsig = np.zeros(nbins)
        dh3 = np.zeros(nbins)
        dh4 = np.zeros(nbins)
        bwt = np.zeros(nbins)
        dwt = np.zeros(nbins)
        output = np.zeros((nbins, 10 + (2 * (mom - 2))))
        popoutput = np.zeros((nbins, 6))
        output[:, 0] = xbin[:]
        output[:, 1] = ybin[:]
        popoutput[:, 0] = xbin[:]
        popoutput[:, 1] = ybin[:]

        bmet = np.zeros(nbins)
        bage = np.zeros(nbins)
        dage = np.zeros(nbins)
        dmet = np.zeros(nbins)
        count = 0
        for j in range(2, nbins - 1):
            print('Bin number:', j + 1, 'out of', nbins)
            print('Bulge fraction:', bulge_fraction[j])
            if spxf[j] > 350: spxf[j] = 350.
            if abs(vpxf[j] - 4750.) > 300: vpxf[j] = 4750.

            #start = np.array([[vpxf[j], spxf[j]],[vpxf[j],sigdisk]]) # (km/s), starting guess for [V,sigma]

            start = np.array([[velbulge, spxf[j]], [vpxf[j], sigdisk]
                              ])  # (km/s), starting guess for [V,sigma]
            print('Starting velocity estimates:', start[0, 0], start[0, 1],
                  start[1, 0], start[1, 1])
            print('Xbin:', xbin[j], 'Ybin:', ybin[j])
            t = clock()
            pp = ppxf(templates,
                      galaxy[:, j],
                      noise[:, j],
                      velscale,
                      start,
                      bulge_fraction=bulge_fraction[j],
                      goodpixels=goodPixels,
                      moments=[mom, mom],
                      degree=4,
                      vsyst=dv,
                      component=component,
                      brot=1,
                      plot=True)  #brot=0 for nonrotating, brot=1 for rotating
            #Kinematics

            kinem = np.loadtxt("ppxfout.txt")
            wts = np.loadtxt("ppxfoutwt.txt")

            if mom == 2:
                output[j, 2] = kinem[0, 0]  #bvel
                output[j, 3] = kinem[0, 1]  #bsig
                output[j, 4] = kinem[1, 0]  #dvel
                output[j, 5] = kinem[1, 1]  #dsig
                output[j, 6] = wts[0]  #bulge weight
                output[j, 7] = wts[1]  #disk weight
                output[j, 8] = wts[2]  #chisqn
                output[j, 9] = wts[3]  #chisq

            if mom == 4:
                output[j, 2] = kinem[0, 0]  #bvel
                output[j, 3] = kinem[0, 1]  #bsig
                output[j, 4] = kinem[0, 2]  #bh3
                output[j, 5] = kinem[0, 3]  #bh4
                output[j, 6] = kinem[1, 0]  #dvel
                output[j, 7] = kinem[1, 1]  #dsig
                output[j, 8] = kinem[1, 2]  #dh3
                output[j, 9] = kinem[1, 3]  #dh4
                output[j, 10] = wts[0]  #bulge weight
                output[j, 11] = wts[1]  #disk weight
                output[j, 12] = wts[2]  #chisqn
                output[j, 13] = wts[3]  #chisq
                print(wts[0], wts[1])
                print('Chisq difference from one comp fit (pos = improved)',
                      occh[j] - wts[2])
                if occh[j] > wts[2]: count = count + 1
            bwt[j] = wts[0]
            dwt[j] = wts[1]

            #Populations

            #wtsb=np.loadtxt("ppxfoutwtsb.txt")
            #wtsd=np.loadtxt("ppxfoutwtsd.txt")
            #shwb=wtsb.shape
            #shwd=wtsd.shape

            #if len(shwb) > 1:
        #bulgewt=np.array(wtsb[0,:])
        #bulgewt=bulgewt/bulgewt.sum()
        #bulgewtin=np.array(wtsb[1,:],dtype=int)
        #else:
        #bulgewt=1.
        #bulgewtin=np.int(wtsb[1])
        #if len(shwd) > 1:
        #diskwt=np.array(wtsd[0,:])
        #diskwt=diskwt/diskwt.sum()
        #diskwtin=np.array(wtsd[1,:],dtype=int)
        #else:
        #diskwt=1.
        #diskwtin=np.int(wtsd[1])

        #bage[j]=np.dot(bulgewt,age[bulgewtin])
        #bmet[j]=np.dot(bulgewt,met[bulgewtin])
        #dage[j]=np.dot(diskwt,age[diskwtin])
        #dmet[j]=np.dot(diskwt,met[diskwtin])

        #popoutput[j,2]=bage[j]
        #popoutput[j,3]=bmet[j]
        #popoutput[j,4]=dage[j]
        #popoutput[j,5]=dmet[j]

        #Plots

        #ssparr=templates
        #print(gal_bin.shape)
        #gal_bin=galaxy
        #print(gal_bin.shape)
        #bulgespec=ssparr[:,bulgewtin].dot(bulgewt)
        #diskspec=ssparr[:,diskwtin].dot(diskwt)
        #diskspec=diskspec/np.median(diskspec)
        #bulgespec=bulgespec/np.median(bulgespec)
        #plt.xlabel("Wavelength")
        #plt.ylabel("Counts")
        #plt.plot(5*(gal_bin[goodPixels,j]/np.median(gal_bin[goodPixels,j])), 'k')
        #plt.plot(3*(bulgespec[goodPixels]), 'r')
        #plt.plot(2*(diskspec[goodPixels]), 'b')
        #plt.plot(5*(bulgespec[goodPixels]+diskspec[goodPixels])/np.median(bulgespec[goodPixels]+diskspec[goodPixels]), 'g')
        #plt.savefig('outfit')

        np.savetxt('NGC528conskinnchcheckbrot.txt', output, fmt="%10.3g")
Example #11
0
def ppxf_kinematics(bin_sci, ppxf_file, ppxf_bestfit, template_fits, template_resolution, lam_range=[4173., 5404.],
                    vel_init=1500., sig_init=100., bias=0., plot=False, quiet=True, badPixels=[], clean=False):
    """
    Follow the pPXF usage example by Michile Cappellari
    INPUT: DIR_SCI_COMB (comb_fits_sci_{S/N}/bin_sci_{S/N}.fits), TEMPLATE_* (spectra/Mun1.30z*.fits)
    OUTPUT: PPXF_FILE (ppxf_output_sn30.txt), OUT_BESTFIT_FITS (ppxf_fits/ppxf_bestfit_sn30.fits)
    """

    if os.path.exists(ppxf_file):
        print('File {} already exists'.format(ppxf_file))
        return

    # Read a galaxy spectrum and define the wavelength range
    assert len(glob.glob(bin_sci.format('*'))) > 0, 'Binned spectra {} not found'.format(glob.glob(bin_sci.format('*')))

    # hdu = fits.open(in_file[0])
    # gal_lin = hdu[0].data
    # h1 = hdu[0].header

    with fits.open(bin_sci.format(0)) as gal_hdu:
        gal_lin = gal_hdu[0].data
        gal_hdr = gal_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.

    # lamRange1 is now variable lam_range (because I was lazy and didnt put headers into the binned spectra)
    FWHM_gal = 2.3  # GMOS IFU has an instrumental resolution FWHM of 2.3 A

    # 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

    galaxy, logLam1, velscale = util.log_rebin(lam_range, gal_lin)
    galaxy = galaxy / np.median(galaxy)  # Normalize spectrum to avoid numerical issues

    # 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.

    template_spectra = glob.glob(template_fits)
    assert len(template_spectra) > 0, 'Template spectra not found: {}'.format(template_fits)
    FWHM_tem = template_resolution

    # 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)))

    with fits.open(template_spectra[0]) as temp_hdu:
        ssp = temp_hdu[0].data
        h2 = temp_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(template_spectra)))

    # 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.

    # FROM GWENS IDL SCRIPT ----------------------------------------------------------
    # Example: BC03 spectra have a resolution of 3A at 5100A, this corresponds to sigma ~ 3.0/5100*3e5/2.35 = 75 km/s.
    # The GMOS IFU has an instrumental resolution of 2.3 A, this corresponds to sigma ~ 2.3/5100*3e5/2.35 = 56.8 km/s.
    # The quadratic difference is sigma = sqrt(56.8^2 - 75^2) = undefined
    # (the above reasoning can be applied if the shape of the instrumental spectral profiles can be well approximated
    # by a Gaussian).
    # For the lower resolution models, we must degrade the DATA to fit the models.
    # Thus: The quadratic difference is sigma = sqrt(75^2 - 56.8^2) = 49.0 km/s
    # ---------------------------------------------------------------------------------

    # FWHM_dif = np.sqrt(FWHM_gal ** 2 - template_resolution ** 2)
    FWHM_dif = np.sqrt(FWHM_tem ** 2 - FWHM_gal ** 2)
    sigma = FWHM_dif / 2.355 / h2['CDELT1']  # SIGMA DIFFERENCE IN PIXELS, 1.078435697220085

    # Logarithmically rebin the whole Mun library of spectra, and store each template as a column in the array TEMPLATES

    # for j in range(len(vazdekis)):
    # hdu = fits.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

    for j in range(len(template_spectra)):
        with fits.open(template_spectra[j]) as temp_hdu_j:
            ssp_j = temp_hdu_j[0].data
        ssp_j = ndimage.gaussian_filter1d(ssp_j, sigma)
        sspNew, logLam2, velscale = util.log_rebin(lamRange2, ssp_j, 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).

    vel_list = []
    sig_list = []
    dV_list = []
    dsigma_list = []

    h3_list = []
    h4_list = []
    dh3_list = []
    dh4_list = []

    for j in range(len(glob.glob(bin_sci.format('*')))):
        b_gal = fits.getdata(bin_sci.format(j), 0)

        b_gal = ndimage.gaussian_filter1d(b_gal, sigma)

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

        c = 299792.458
        dv = (logLam2[0] - logLam1[0]) * c  # km/s

        # vel = 1500.  # Initial estimate of the galaxy velocity in km/s
        z = np.exp(vel_init / c) - 1  # Relation between velocity and redshift in pPXF

        goodPixels = util.determine_goodpixels(logLam1, lamRange2, z)
        if len(badPixels) > 0:
            indices = []
            for idx, pix in enumerate(goodPixels):
                if pix in badPixels:
                    indices.append(idx)
            goodPixels = np.delete(goodPixels, indices)

        # 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_init, sig_init]  # (km/s), starting guess for [V,sigma]
        t = clock()

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

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

        # 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 + sol[0]/c) - 1

        # Gwen obtains the velocity and sigma information from the SOL parameter
        # moments = 4 so sol = [vel, sig, h3, h4]
        vel_list.append(pp.sol[0])
        sig_list.append(pp.sol[1])
        dV_list.append((pp.error * np.sqrt(pp.chi2))[0])
        dsigma_list.append((pp.error * np.sqrt(pp.chi2))[1])

        h3_list.append(pp.sol[2])
        h4_list.append(pp.sol[3])
        dh3_list.append((pp.error * np.sqrt(pp.chi2))[2])
        dh4_list.append((pp.error * np.sqrt(pp.chi2))[3])

        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.format(j), clobber=True)

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

    np.savetxt(ppxf_file,
               np.column_stack([vel_list, sig_list, h3_list, h4_list, dV_list, dsigma_list, dh3_list, dh4_list]),
               fmt=b'%10.6f  %10.6f  %10.6f  %10.6f  %10.6f  %10.6f  %10.6f  %10.6f',
               header='velocity    sigma       h3           h4         dV          dsigma       dh3         dh4')

    return vel_list
Example #12
0
            lam, full, full_data, logAge_grid, metal_grid, templates = \
            load_bc03_library(x, velscale*(0.9999), FWHM_gal=1, version='S')
        else:
            lam, full, full_data, logAge_grid, metal_grid, templates = \
            load_bc03_library(x, velscale*(0.9999), FWHM_gal=0.1, version='S')

        lamRange_temp = [wave[0], wave[-1]]

        #normalize templates by median scalar
        norm = np.median(templates)
        templates /= norm
        full /= norm

        dv = c * np.log(lamRange_temp[0] / wave[0])  # km/s

        goodpixels = util.determine_goodpixels(log_wave, lamRange_temp, z)

        start = [c * np.log(1 + z), 0.01]  #3*velscale]
        fixed = [True, True]  #, False, False]
        fixed = [False, False]
        print start

        pp = ppxf(templates,
                  galaxy,
                  noise,
                  velscale,
                  start,
                  goodpixels=goodpixels,
                  plot=False,
                  moments=2,
                  degree=-1,
Example #13
0
def ppxfit(ncompfit, brot, bfract, mom):

    velscale = 110.0
    file = "NGC0528-V500.rscube.fits"
    hdu = pyfits.open(file)
    gal_lin = hdu[0].data
    h1 = hdu[0].header

    medfl = np.loadtxt("medgalpy.txt")
    x = medfl[:, 0]
    y = medfl[:, 1]
    sig = medfl[:, 2]
    noise = medfl[:, 3]

    bins = np.loadtxt("voronoi_2d_binning_output.txt", skiprows=1)
    x = bins[:, 0]
    y = bins[:, 1]
    binnum = bins[:, 2]

    binco = np.loadtxt("bins.txt")
    xbin = binco[:, 0]
    ybin = binco[:, 1]

    file = "galaxybinspy.fits"  # spectra arranged horizontally
    hdu = pyfits.open(file)
    gal_bin = hdu[0].data
    gs = gal_bin.shape
    nbins = gs[0]
    xcut = 0.0
    ycut = 0.0
    delta = h1["CDELT3"]
    lamRange1 = h1["CRVAL3"] + np.array([xcut * delta, delta * ((h1["NAXIS3"] - 1) - ycut)])
    FWHM_gal = 6.0  # CALIFA has an instrumental resolution FWHM of 6A.

    galaxyz, logLam1, velscale = util.log_rebin(lamRange1, gal_bin[0, :], velscale=velscale)

    galaxy = np.empty((galaxyz.size, nbins))
    noise = np.empty((galaxyz.size, nbins))

    for j in range(nbins):
        galaxy[:, j], logLam1, velscale = util.log_rebin(lamRange1, gal_bin[j, :], velscale=velscale)
        galaxy[:, j] = galaxy[:, j] / np.median(galaxy[:, j])  # Normalize spectrum to avoid numerical issues
        noise[:, j] = galaxy[:, j] * 0 + 0.0049  # Assume constant noise per pixel here

        # dir='/home/ppxmt3/astro/MILES/'
    dir = "galspec/"
    miles = glob.glob(dir + "Mun*.fits")
    miles.sort()
    FWHM_tem = 2.5  # Miles spectra have a resolution FWHM of 1.8A.

    age = np.empty(len(miles))
    met = np.empty(len(miles))
    # age=np.chararray(len(miles),itemsize=7)
    # met=np.chararray(len(miles),itemsize=5)

    for j in range(len(miles)):
        ast = miles[j][22:29]
        mst = miles[j][17:21]
        pm = miles[j][16:17]
        if pm == "p":
            pmn = "+"
        elif pm == "m":
            pmn = "-"
        mstpm = (pmn, mst)
        # met[j,:]=miles[j][16:19]
        age[j] = float(ast)
        met[j] = float("".join(mstpm))

        # age2,inda=np.unique(age,return_inverse=True)
        # met2,ind=np.unique(met,return_inverse=True)

        # c=1
        # for i in range(len(age2)/2):
        # indout=np.where(age==age2[c])[0]
        ##print(indout)
        # miles=np.delete(miles,indout)
        # age=np.delete(age,indout)
        # c=c+2

        # Extract the wavelength range and logarithmically rebin one spectrum
        # to the same velocity scale of the CALIFA galaxy spectrum, to determine
        # the size needed for the array which will contain the template spectra.

    hdu = pyfits.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)

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

    # Quadratic sigma difference in pixels miles --> CALIFA
    # 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

    # ==========================================================================================================================
    # One component fit - saves veloctiy values in 'NGC528_onecompkin.txt' to be used as initial estimates for two component fit

    if ncompfit == 1:

        templates = np.empty((sspNew.size, len(miles)))
        for j in range(len(miles)):
            hdu = pyfits.open(miles[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

        c = 299792.458
        dv = (logLam2[0] - logLam1[0]) * c  # km/s

        vel = 4750.0  # 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)

        start = np.zeros(2)
        output = np.zeros((nbins, 5))
        output[:, 0] = xbin[:]
        output[:, 1] = ybin[:]

        start[:] = [vel, 3.0 * velscale]  # (km/s), starting guess for [V,sigma]

        for j in range(nbins):
            print("On ", j + 1, " out of ", nbins)
            print(start)
            pp = ppxf(
                templates,
                galaxy[:, j],
                noise[:, j],
                velscale,
                start,
                goodpixels=goodPixels,
                degree=4,
                vsyst=dv,
                plot=True,
                moments=mom,
            )
            kinem = np.loadtxt("ppxfout.txt")
            if mom == 2:
                output[j, 2] = kinem[0]  # vel
                output[j, 3] = kinem[1]  # sigma
                output[j, 4] = kinem[2]  # chisq
            if mom == 4:
                output[j, 2] = kinem[0]  # vel
                output[j, 3] = kinem[1]  # sigma
                output[j, 4] = kinem[4]  # chisq

        np.savetxt("NGC528_onecompkinm2nch.txt", output, fmt="%10.3g")

    # =========================================================================================================================
    # Two component fit

    elif ncompfit == 2:

        # To determine flux fraction of bulge. Set bfract to 0 to disable

        # 'bulgediskblock.fits' is created by running GALFIT to get a galfit.01 file of best fit parameters, then using
        # '>galfit -o3 galfit.01' to get cube of galaxy image, bulge image and disk image

        if bfract == 1:
            file = "bulgediskblock.fits"
            hdu = pyfits.open(file)
            galb = hdu[1].data
            bulge = hdu[2].data
            disk = hdu[3].data

            # Bin bulge and disk images into same binning as datacube
            nbins = xbin.shape[0]
            avbulge = np.zeros(nbins)
            avdisk = np.zeros(nbins)
            avtot = np.zeros(nbins)
            binflux = np.zeros(nbins)
            x = x.astype(int)
            y = y.astype(int)
            for j in range(nbins):
                b = np.where(binnum == j)[0]
                valbin = b.size
                if valbin == 1:
                    avbulge[j] = bulge[y[b], x[b]]
                    avdisk[j] = disk[y[b], x[b]]
                    avtot[j] = galb[x[b], y[b]]
                else:
                    avbulge[j] = np.median(bulge[y[b], x[b]])
                    avdisk[j] = np.median(disk[y[b], x[b]])
                    avtot[j] = np.median(galb[x[b], y[b]])

            bulge_fraction = avbulge / (avbulge + avdisk)

            hdu = pyfits.PrimaryHDU(bulge_fraction)
            hdu.writeto("bulge_fraction.fits", clobber=True)

        # ====================================================================================

        templates = np.empty((sspNew.size, 2 * len(miles)))
        ssparr = np.empty((ssp.size, len(miles)))

        for j in range(len(miles)):
            hdu = pyfits.open(miles[j])
            ssparr[:, j] = hdu[0].data
            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
        for j in range(len(miles), 2 * len(miles)):
            hdu = pyfits.open(miles[j - len(miles)])
            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

        component = np.zeros((2 * len(miles)), dtype=np.int)
        component[0 : len(miles)] = 0
        component[len(miles) :] = 1

        c = 299792.458
        dv = (logLam2[0] - logLam1[0]) * c  # km/s
        vel = 4750.0  # 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)

        kin = np.loadtxt("NGC528_onecompkinnch.txt")
        xbin = kin[:, 0]
        ybin = kin[:, 1]
        vpxf = kin[:, 2]
        spxf = kin[:, 3]
        occh = kin[:, 4]
        velbulge = vel
        sigdisk = 50.0

        file = "bulge_fraction.fits"  # Read out bulge fraction for each bin
        hdu = pyfits.open(file)
        bulge_fraction = hdu[0].data

        bvel = np.zeros(nbins)
        bsig = np.zeros(nbins)
        bh3 = np.zeros(nbins)
        bh4 = np.zeros(nbins)
        dvel = np.zeros(nbins)
        dsig = np.zeros(nbins)
        dh3 = np.zeros(nbins)
        dh4 = np.zeros(nbins)
        bwt = np.zeros(nbins)
        dwt = np.zeros(nbins)
        output = np.zeros((nbins, 10 + (2 * (mom - 2))))
        popoutput = np.zeros((nbins, 6))
        output[:, 0] = xbin[:]
        output[:, 1] = ybin[:]
        popoutput[:, 0] = xbin[:]
        popoutput[:, 1] = ybin[:]

        bmet = np.zeros(nbins)
        bage = np.zeros(nbins)
        dage = np.zeros(nbins)
        dmet = np.zeros(nbins)
        count = 0
        for j in range(2, nbins - 1):
            print("Bin number:", j + 1, "out of", nbins)
            print("Bulge fraction:", bulge_fraction[j])
            if spxf[j] > 350:
                spxf[j] = 350.0
            if abs(vpxf[j] - 4750.0) > 300:
                vpxf[j] = 4750.0

            # start = np.array([[vpxf[j], spxf[j]],[vpxf[j],sigdisk]]) # (km/s), starting guess for [V,sigma]

            start = np.array([[velbulge, spxf[j]], [vpxf[j], sigdisk]])  # (km/s), starting guess for [V,sigma]
            print("Starting velocity estimates:", start[0, 0], start[0, 1], start[1, 0], start[1, 1])
            print("Xbin:", xbin[j], "Ybin:", ybin[j])
            t = clock()
            pp = ppxf(
                templates,
                galaxy[:, j],
                noise[:, j],
                velscale,
                start,
                bulge_fraction=bulge_fraction[j],
                goodpixels=goodPixels,
                moments=[mom, mom],
                degree=4,
                vsyst=dv,
                component=component,
                brot=1,
                plot=True,
            )  # brot=0 for nonrotating, brot=1 for rotating
            # Kinematics

            kinem = np.loadtxt("ppxfout.txt")
            wts = np.loadtxt("ppxfoutwt.txt")

            if mom == 2:
                output[j, 2] = kinem[0, 0]  # bvel
                output[j, 3] = kinem[0, 1]  # bsig
                output[j, 4] = kinem[1, 0]  # dvel
                output[j, 5] = kinem[1, 1]  # dsig
                output[j, 6] = wts[0]  # bulge weight
                output[j, 7] = wts[1]  # disk weight
                output[j, 8] = wts[2]  # chisqn
                output[j, 9] = wts[3]  # chisq

            if mom == 4:
                output[j, 2] = kinem[0, 0]  # bvel
                output[j, 3] = kinem[0, 1]  # bsig
                output[j, 4] = kinem[0, 2]  # bh3
                output[j, 5] = kinem[0, 3]  # bh4
                output[j, 6] = kinem[1, 0]  # dvel
                output[j, 7] = kinem[1, 1]  # dsig
                output[j, 8] = kinem[1, 2]  # dh3
                output[j, 9] = kinem[1, 3]  # dh4
                output[j, 10] = wts[0]  # bulge weight
                output[j, 11] = wts[1]  # disk weight
                output[j, 12] = wts[2]  # chisqn
                output[j, 13] = wts[3]  # chisq
                print(wts[0], wts[1])
                print("Chisq difference from one comp fit (pos = improved)", occh[j] - wts[2])
                if occh[j] > wts[2]:
                    count = count + 1
            bwt[j] = wts[0]
            dwt[j] = wts[1]

            # Populations

            # wtsb=np.loadtxt("ppxfoutwtsb.txt")
            # wtsd=np.loadtxt("ppxfoutwtsd.txt")
            # shwb=wtsb.shape
            # shwd=wtsd.shape

            # if len(shwb) > 1:
            # bulgewt=np.array(wtsb[0,:])
            # bulgewt=bulgewt/bulgewt.sum()
            # bulgewtin=np.array(wtsb[1,:],dtype=int)
            # else:
            # bulgewt=1.
            # bulgewtin=np.int(wtsb[1])
            # if len(shwd) > 1:
            # diskwt=np.array(wtsd[0,:])
            # diskwt=diskwt/diskwt.sum()
            # diskwtin=np.array(wtsd[1,:],dtype=int)
            # else:
            # diskwt=1.
            # diskwtin=np.int(wtsd[1])

            # bage[j]=np.dot(bulgewt,age[bulgewtin])
            # bmet[j]=np.dot(bulgewt,met[bulgewtin])
            # dage[j]=np.dot(diskwt,age[diskwtin])
            # dmet[j]=np.dot(diskwt,met[diskwtin])

            # popoutput[j,2]=bage[j]
            # popoutput[j,3]=bmet[j]
            # popoutput[j,4]=dage[j]
            # popoutput[j,5]=dmet[j]

            # Plots

            # ssparr=templates
            # print(gal_bin.shape)
            # gal_bin=galaxy
            # print(gal_bin.shape)
            # bulgespec=ssparr[:,bulgewtin].dot(bulgewt)
            # diskspec=ssparr[:,diskwtin].dot(diskwt)
            # diskspec=diskspec/np.median(diskspec)
            # bulgespec=bulgespec/np.median(bulgespec)
            # plt.xlabel("Wavelength")
            # plt.ylabel("Counts")
            # plt.plot(5*(gal_bin[goodPixels,j]/np.median(gal_bin[goodPixels,j])), 'k')
            # plt.plot(3*(bulgespec[goodPixels]), 'r')
            # plt.plot(2*(diskspec[goodPixels]), 'b')
            # plt.plot(5*(bulgespec[goodPixels]+diskspec[goodPixels])/np.median(bulgespec[goodPixels]+diskspec[goodPixels]), 'g')
            # plt.savefig('outfit')

        np.savetxt("NGC528conskinnchcheckbrot.txt", output, fmt="%10.3g")