コード例 #1
0
def dust_cont_integrate(dust_mass, dust_temp, dust_beta):
    """
    Integrate over the IR spectral energy distribution. Calculate SFR based on Kennicut relation.
    Prints output to console.

    :param dust_mass: in kg
    :param dust_temp: in K
    :param dust_beta: dimensionless
    :return:
    """

    # Total IR is 8 - 1000 microns
    lum_tir = integrate.quad(
        lambda x: dust_lum(x, dust_mass, dust_temp, dust_beta), c / (1000e-6),
        c / (8e-6))
    print("Ltir (10^12 Lsol) = ",
          sigfig(lum_tir[0] * u.W.to(u.solLum) * 1e-12, 3))

    # Far IR is 42.5 - 122.5 microns
    lum_fir = integrate.quad(
        lambda x: dust_lum(x, dust_mass, dust_temp, dust_beta), c / (122.5e-6),
        c / (42.5e-6))
    print("Lfir (10^12 Lsol) =",
          sigfig(lum_fir[0] * u.W.to(u.solLum) * 1e-12, 3))

    # Kennicutt+98 relation scaled to Chabrier IMF
    print("SFR_Kennicutt98 (Msol/yr)",
          sigfig(lum_tir[0] * u.W.to(u.solLum) * 1e-10, 3))
    # print("SFR", Ltir[0]*4.5e-37/1.7) # Salpeter to Chabrier is a facotr of 1.7

    # Kennicutt+12 relation scaled to Chabrier IMF
    print(
        "SFR_Kennicutt12 (Msol/yr)",
        sigfig(10**(np.log10(lum_tir[0] * u.W.to(u.erg / u.s)) - 43.41) / 1.7,
               3))
コード例 #2
0
ファイル: examples.py プロジェクト: lboogaard/interferopy
def spectrum_aperture_paper():
    """
    Compute residual corrected spectrum. Fit a Gaussian plus a continuum.
    Generate paper quality plot.
    """
    filename = "./data/Pisco.cube.50kms.image.fits"
    ra, dec = (205.533741, 9.477317341)  # [degrees] we know where the source is
    radius = 1.3  # [arcsec] we know the size of the aperture we want
    scale = 1e3  # map units are Jy/beam, will use to scale fluxes to mJy

    # load the cube and perform residual scaling spectrum extraction
    mcub = MultiCube(filename)  # because the cubes follow a naming convention, will open several present cubes
    spectrum, err, tab = mcub.spectrum_corrected(ra=ra, dec=dec, radius=radius, calc_error=True)
    freqs = mcub.freqs  # this will be the x-axis

    # fit the spectrum with a Gaussian on top of a constant continuum, initial fit parameters (p0) must be set manually
    popt, pcov = curve_fit(iftools.gausscont, freqs, spectrum, p0=(1, 5, 222.5, 0.2), sigma=err, absolute_sigma=True)
    cont, amp, nu, sigma = popt
    cont_err, amp_err, nu_err, sigma_err = np.sqrt(np.diagonal(pcov))
    # compute some further numbers from the fit
    sigma_kms = iftools.ghz2kms(sigma, nu)
    fwhm_kms = iftools.sig2fwhm(sigma_kms)
    fwhm_err_kms = iftools.sig2fwhm(iftools.ghz2kms(sigma_err, nu))
    integral_fit = amp * sigma_kms * np.sqrt(2 * np.pi)
    integral_err = integral_fit * np.sqrt((sigma_err / sigma) ** 2 + (nu_err / nu) ** 2 + (amp_err / amp) ** 2)

    txt = "[CII] Flux = " + str(iftools.sigfig(integral_fit, 2)) \
          + r" $\pm$ " + str(iftools.sigfig(integral_err, 1)) + " Jy km/s\n" \
          + "[CII] FWHM = " + str(iftools.sigfig(int(fwhm_kms), 2)) \
          + r" $\pm$ " + str(iftools.sigfig(int(fwhm_err_kms), 1)) + " km/s\n" \
          + "Freq = " + str(iftools.sigfig(nu, 6)) \
          + r" $\pm$ " + str(iftools.sigfig(nu_err, 1)) + " GHz\n" \
          + "Continuum = " + str(iftools.sigfig(cont * scale, 2)) \
          + r" $\pm$ " + str(iftools.sigfig(cont_err * scale, 1)) + " mJy\n"

    # print("Gaussian fit:")
    # print("Flux = " + str(iftools.sigfig(integral_fit, 2)) + " +- " + str(iftools.sigfig(integral_err, 1)) + " Jy.km/s")
    # print("FWHM = " + str(iftools.sigfig(fwhm_kms, 2)) + " +- " + str(iftools.sigfig(fwhm_err_kms, 1)) + " km/s")
    # print("Freq = " + str(iftools.sigfig(nu, 7)) + " +- " + str(iftools.sigfig(nu_err, 1)) + " GHz")

    # plot the spectrum, fill around the fitted continuum value
    fig, ax = plt.subplots(figsize=(4.8, 3))
    ax.plot(freqs, spectrum * scale, color="black", drawstyle='steps-mid', lw=0.75)
    ax.fill_between(freqs, spectrum * scale, cont * scale, color="skyblue", step='mid', lw=0, alpha=0.3)

    ax.text(0.98, 0.95, txt, va='top', ha='right', transform=ax.transAxes)

    # Plot the uncorrected specturum as well
    # ax.plot(freqs, tab["flux_image"] * scale, color="black", drawstyle='steps-mid', lw=0.5, ls="--")

    # plot Gaussian fit
    x_gauss = np.linspace(freqs[0], freqs[-1], 1000)
    y_gauss = iftools.gausscont(x_gauss, *popt)
    ax.plot(x_gauss, y_gauss * scale, color="firebrick")

    # add velocity axis based around the fitted peak
    vels = mcub.cubes["image"].vels(nu)
    ax2 = ax.twiny()

    # match ranges of the two axes
    ax.set_xlim(freqs[0], freqs[-1])
    ax2.set_xlim(vels[0], vels[-1])

    # add axis labels
    ax.tick_params(direction='in', which="both")
    ax.set_xlabel("Frequency (GHz)")
    ax.set_ylabel("Aperture flux density (mJy)")
    ax2.tick_params(direction='in', which="both")
    ax2.set_xlabel(r"Velocity (km s$^{-1}$)")

    # add the zero line
    ax.axhline(0, color="gray", lw=0.5, ls=":")

    plt.savefig("./plots/spectrum_aperture_paper.pdf", bbox_inches="tight")  # save plot
    plt.savefig("./thumbnails/spectrum_aperture_paper.png", bbox_inches="tight", dpi=72)  # web raster version

    plt.show()
コード例 #3
0
def dust_cont_fit():
    """
    Fit a modified black body dust continuum emission to observed flux density data points.
    File for input flux densities, redshift, and exact fitting method are currently hardcoded.
    Uses dust_sobs, which takes cmb heating and contrast into account by default.

    :return:
    """

    # Points to fit, inputs need so to be in SI units
    t = Table.read("./data/Pisco_continuum_fluxes.txt",
                   format="ascii.commented_header")
    freqs = t["freq_ghz"] * 1e9  # to Hz
    fluxes = t["flux_jy"] * 1e-26  # to W/Hz/m2
    fluxes_err = t["flux_err_jy"] * 1e-26  # to W/Hz/m2

    # Parameters for the black body emission
    # These are either fixed, or used as intial guess for fitting if chosen to be free parameters
    z = 7.5413  # redshift
    dust_mass = 1e37  # in kilograms
    dust_temp = 47  # T_dust in Kelvins
    dust_beta = 1.9  # modified black body exponent

    dust_mass_err = 0
    dust_temp_err = 0
    dust_beta_err = 0

    # several fitting scenarios, choose one
    # lambdas are used to set non-free parameters, because curve_fit wants only the variable and free params
    # Parameters are degenerate, so be careful with error interpretation

    # Fit Mdust only - this could be used if you only have a single point, for example
    if 0:
        popt, pcov = curve_fit(lambda freqs, dust_mass: dust_sobs(
            freqs, z, dust_mass, dust_temp, dust_beta),
                               freqs,
                               fluxes,
                               p0=(dust_mass),
                               sigma=fluxes_err,
                               absolute_sigma=True)
        dust_mass = popt[0]
        dust_mass_err = np.diagonal(pcov)[0]

    # Fit Mdust and T - to constrain the temperature, the black body peak needs to be sampled
    if 0:
        popt, pcov = curve_fit(lambda freqs, dust_mass, dust_temp: dust_sobs(
            freqs, z, dust_mass, dust_temp, dust_beta),
                               freqs,
                               fluxes,
                               p0=(dust_mass, dust_temp),
                               sigma=fluxes_err,
                               absolute_sigma=True)
        dust_mass, dust_temp = popt
        dust_mass_err, dust_temp_err = np.sqrt(np.diagonal(pcov))

    # Fit Mdust and beta - the best option on the Rayleigh-Jeans tail
    if 1:
        popt, pcov = curve_fit(lambda freqs, dust_mass, dust_beta: dust_sobs(
            freqs, z, dust_mass, dust_temp, dust_beta),
                               freqs,
                               fluxes,
                               p0=(dust_mass, dust_beta),
                               sigma=fluxes_err,
                               absolute_sigma=True)
        dust_mass, dust_beta = popt
        dust_mass_err, dust_beta_err = np.sqrt(np.diagonal(pcov))

    # Fit Mdust and T and beta - not recommended due to degeneracy
    if 0:
        popt, pcov = curve_fit(
            lambda freqs, dust_mass, dust_temp, dust_beta: dust_sobs(
                freqs, z, dust_mass, dust_temp, dust_beta),
            freqs,
            fluxes,
            p0=(dust_mass, dust_temp, dust_beta),
            sigma=fluxes_err,
            absolute_sigma=True)
        dust_mass, dust_temp, dust_beta = popt
        dust_mass_err, dust_temp_err, dust_beta_err = np.sqrt(
            np.diagonal(pcov))

    print("dust_mass (10^8 Msol) = ",
          sigfig(dust_mass * u.kg.to(u.solMass) * 1e-8, 3), " +- ",
          sigfig(dust_mass_err * u.kg.to(u.solMass) * 1e-8, 1))
    print("dust_temp (K) = ", sigfig(dust_temp, 3), " +- ",
          sigfig(dust_temp_err, 1))
    print("dust_beta = ", sigfig(dust_beta, 3), " +- ",
          sigfig(dust_beta_err, 1))

    return dust_mass, dust_temp, dust_beta