def get_frac_dev(self, logZ, CO_ratio, custom_abundances):
        Rp = 7.14e7
        Mp = 2.0e27
        Rs = 7e8
        T = 1200
        depth_calculator = TransitDepthCalculator()
        wavelengths, transit_depths = depth_calculator.compute_depths(
            Rs, Mp, Rp, T, logZ=logZ, CO_ratio=CO_ratio,
            custom_abundances=custom_abundances, cloudtop_pressure=1e4)

        # This ExoTransmit run is done without SH, since it's not present in
        # GGchem
        ref_wavelengths, ref_depths = np.loadtxt("tests/testing_data/hot_jupiter_spectra.dat", unpack=True, skiprows=2)
        ref_depths /= 100

        frac_dev = np.abs(ref_depths - transit_depths) / ref_depths

        '''plt.plot(wavelengths, transit_depths, label="platon")
        plt.plot(ref_wavelengths, ref_depths, label="ExoTransmit")
        plt.legend()

        plt.figure()
        plt.plot(np.log10(frac_dev))
        plt.show()'''

        return frac_dev
    def test_power_law_haze(self):
        Rs = R_sun     
        Mp = M_jup     
        Rp = R_jup      
        T = 1200
        abundances = AbundanceGetter().get(0, 0.53)
        for key in abundances:
            abundances[key] *= 0
        abundances["H2"] += 1
        depth_calculator = TransitDepthCalculator()
        wavelengths, transit_depths, info_dict = depth_calculator.compute_depths(
            Rs, Mp, Rp, T, logZ=None, CO_ratio=None, cloudtop_pressure=np.inf,
            custom_abundances = abundances,
            add_gas_absorption=False, add_collisional_absorption=False, full_output=True)
                
        g = G * Mp / Rp**2
        H = k_B * T / (2 * AMU * g)
        gamma = 0.57721
        polarizability = 0.8059e-30
        sigma = 128. * np.pi**5/3 * polarizability**2 / depth_calculator.atm.lambda_grid**4
        kappa = sigma / (2 * AMU)

        P_surface = 1e8
        R_surface = info_dict["radii"][-1]
        tau_surface = P_surface/g * np.sqrt(2*np.pi*R_surface/H) * kappa
        analytic_R = R_surface + H*(gamma + np.log(tau_surface) + scipy.special.expn(1, tau_surface))
        
        analytic_depths = analytic_R**2 / Rs**2
        
        ratios = analytic_depths / transit_depths
        relative_diffs = np.abs(ratios - 1)
        self.assertTrue(np.all(relative_diffs < 0.001))
    def test_k_coeffs_unbinned(self):
        xsec_calc = TransitDepthCalculator(method="xsec")
        ktab_calc = TransitDepthCalculator(method="ktables")
                
        xsec_wavelengths, xsec_depths = xsec_calc.compute_depths(R_sun, M_jup, R_jup, 1000)

        #Smooth from R=1000 to R=100 to match ktables
        N = 10
        smoothed_xsec_wavelengths = uniform_filter(xsec_wavelengths, N)[::N]
        smoothed_xsec_depths = uniform_filter(xsec_depths, N)[::N]
        ktab_wavelengths, ktab_depths = ktab_calc.compute_depths(R_sun, M_jup, R_jup, 1000)
        
        diffs = np.abs(ktab_depths - smoothed_xsec_depths[:-1])
        self.assertTrue(np.median(diffs) < 20e-6)
        self.assertTrue(np.percentile(diffs, 95) < 50e-6)
        self.assertTrue(np.max(diffs) < 150e-6)
 def test_unbound_atmosphere(self):
     Rp = 6.378e6
     Mp = 5.97e20 # Note how low this is--10^-4 Earth masses!
     Rs = 6.97e8
     T = 300
     depth_calculator = TransitDepthCalculator()
     with self.assertRaises(AtmosphereError):
         wavelengths, transit_depths = depth_calculator.compute_depths(
             Rs, Mp, Rp, T, logZ=0.2, CO_ratio=1.1, T_star=6100)
    def test_bin_wavelengths(self):
        Rp = 7.14e7
        Mp = 7.49e26
        Rs = 7e8
        T = 1200
        depth_calculator = TransitDepthCalculator()
        bins = np.array([[0.4,0.6], [1,1.1], [1.2,1.4], [3.2,4], [5,6]])
        bins *= 1e-6
        depth_calculator.change_wavelength_bins(bins)

        wavelengths, transit_depths = depth_calculator.compute_depths(
            Rs, Mp, Rp, T, logZ=0.2, CO_ratio=1.1, T_star=6100)
        self.assertEqual(len(wavelengths), len(bins))
        self.assertEqual(len(transit_depths), len(bins))

        wavelengths, transit_depths = depth_calculator.compute_depths(
            Rs, Mp, Rp, T, logZ=0.2, CO_ratio=1.1, T_star=12000)
        self.assertEqual(len(wavelengths), len(bins))
        self.assertEqual(len(transit_depths), len(bins))
    def test_k_coeffs_binned(self):
        wavelengths = np.exp(np.arange(np.log(0.31e-6), np.log(29e-6), 1./20))
        wavelength_bins = np.array([wavelengths[0:-1], wavelengths[1:]]).T
        
        xsec_calc = TransitDepthCalculator(method="xsec")
        xsec_calc.change_wavelength_bins(wavelength_bins)
        ktab_calc = TransitDepthCalculator(method="ktables")
        ktab_calc.change_wavelength_bins(wavelength_bins)
                
        wavelengths, xsec_depths = xsec_calc.compute_depths(R_sun, M_jup, R_jup, 300, logZ=1, CO_ratio=1.5)
        wavelengths, ktab_depths = ktab_calc.compute_depths(R_sun, M_jup, R_jup, 300, logZ=1, CO_ratio=1.5)
        
        diffs = np.abs(ktab_depths - xsec_depths)

        '''plt.semilogx(wavelengths, xsec_depths)
        plt.semilogx(wavelengths, ktab_depths)
        plt.figure()
        plt.semilogx(wavelengths, 1e6 * diffs)
        plt.show()'''
        
        self.assertTrue(np.median(diffs) < 10e-6)
        self.assertTrue(np.percentile(diffs, 95) < 20e-6)
        self.assertTrue(np.max(diffs) < 30e-6)
Example #7
0
scatt_slope = best_params_dict['scatt_slope']
error_multiple = best_params_dict['error_multiple']
T_star = best_params_dict['T_star']

T_spot = best_params_dict['T_spot']
spot_cov_frac = best_params_dict['spot_cov_frac']
frac_scale_height = best_params_dict['frac_scale_height']
log_number_density = best_params_dict['log_number_density']
log_part_size = best_params_dict['log_part_size']
part_size_std = best_params_dict['part_size_std']
ri = best_params_dict['ri']

# Compute best-fit theoretical model
try:
    wavelengths, calculated_depths = calculator.compute_depths(
        Rs, Mp, Rp, T_eq, logZ, CO_ratio,
        scattering_factor=10**log_scatt_factor, scattering_slope=scatt_slope,
        cloudtop_pressure=10**log_cloudtop_P, T_star=T_star)
except AtmosphereError as e:
    print(e)

# Plot the data on top of the best fit high-resolution model
plt.errorbar(METRES_TO_UM * np.mean(wave_bins, axis=1), depths, yerr=errors, fmt='.', color='k', zorder=100)
plt.plot(METRES_TO_UM * wavelengths, calculated_depths)

plt.xlabel("Wavelength (um)")
plt.ylabel("Transit depth")
plt.xscale('log')

plt.tight_layout()

if bayesian_model == 'multinest':
import numpy as np
import matplotlib.pyplot as plt

from platon.transit_depth_calculator import TransitDepthCalculator
from platon.constants import M_jup, R_sun, R_jup

# All quantities in SI
Rs = 1.16 * R_sun  #Radius of star
Mp = 0.73 * M_jup  #Mass of planet
Rp = 1.40 * R_jup  #Radius of planet
T = 1200  #Temperature of isothermal part of the atmosphere

#create a TransitDepthCalculator object and compute wavelength dependent transit depths
depth_calculator = TransitDepthCalculator(
    method="ktables")  #put "xsec" for opacity sampling
wavelengths, transit_depths = depth_calculator.compute_depths(
    Rs, Mp, Rp, T, CO_ratio=0.2, cloudtop_pressure=1e4)

# Uncomment the code below to print

#print("#Wavelength(m)       Depth")
#for i in range(len(wavelengths)):
#    print(wavelengths[i], transit_depths[i])

# Uncomment the code below to plot

#plt.semilogx(1e6*wavelengths, transit_depths)
#plt.xlabel("Wavelength (um)")
#plt.ylabel("Transit depth")
#plt.show()
    def test_bounds_checking(self):
        Rp = 7.14e7
        Mp = 7.49e26
        Rs = 7e8
        T = 1200
        logZ = 0
        CO_ratio = 1.1
        calculator = TransitDepthCalculator()
        
        with self.assertRaises(AtmosphereError):
            calculator.compute_depths(Rs, Mp, Rp, 199, logZ=logZ, CO_ratio=CO_ratio)
        with self.assertRaises(AtmosphereError):
            calculator.compute_depths(Rs, Mp, Rp, 3001, logZ=logZ, CO_ratio=CO_ratio)
        with self.assertRaises(ValueError):
            calculator.compute_depths(Rs, Mp, Rp, T, logZ=-1.1, CO_ratio=CO_ratio)
        with self.assertRaises(ValueError):
            calculator.compute_depths(Rs, Mp, Rp, T, logZ=3.1, CO_ratio=CO_ratio)
        with self.assertRaises(ValueError):
            calculator.compute_depths(Rs, Mp, Rp, T, logZ=logZ, CO_ratio=0.01)
            
        with self.assertRaises(ValueError):
            calculator.compute_depths(Rs, Mp, Rp, T, logZ=logZ, CO_ratio=11)

        with self.assertRaises(ValueError):
            calculator.compute_depths(Rs, Mp, Rp, T, logZ=logZ, CO_ratio=CO_ratio, cloudtop_pressure=1e-4)
        
        with self.assertRaises(ValueError):
            calculator.compute_depths(Rs, Mp, Rp, T, logZ=logZ, CO_ratio=CO_ratio, cloudtop_pressure=1.1e8)

        # Infinity should be fine
        calculator.compute_depths(Rs, Mp, Rp, T, logZ=logZ, CO_ratio=CO_ratio, cloudtop_pressure=np.inf)
    wave_bins = []
    wave_bins.append([3.2, 4.0])
    wave_bins.append([4.0, 5.0])
    return 1e-6 * np.array(wave_bins)


bins = np.concatenate([stis_bins(), wfc3_bins(), spitzer_bins()])

R_guess = 1.4 * R_jup
T_guess = 1200

depth_calculator = TransitDepthCalculator()
depth_calculator.change_wavelength_bins(bins)
wavelengths, depths = depth_calculator.compute_depths(1.19 * R_sun,
                                                      0.73 * M_jup,
                                                      R_guess,
                                                      T_guess,
                                                      T_star=6091)

# Uncomment the code below to print

#print("#Wavelength(um)  Depth")
#for i in range(len(wavelengths)):
#    print(wavelengths[i], depths[i])

# Uncomment the code below to plot

#plt.plot(1e6*wavelengths, depths)
#plt.xlabel("Wavelength (um)")
#plt.ylabel("Transit depth")
#plt.show()
Example #11
0
depth_calculator = TransitDepthCalculator(Rs, g)

wavelength_bins = []
stis_wavelengths = np.linspace(0.4e-6, 0.7e-6, 30)
for i in range(len(stis_wavelengths) - 1):
    wavelength_bins.append([stis_wavelengths[i], stis_wavelengths[i + 1]])

wfc_wavelengths = np.linspace(1.1e-6, 1.7e-6, 30)
for i in range(len(wfc_wavelengths) - 1):
    wavelength_bins.append([wfc_wavelengths[i], wfc_wavelengths[i + 1]])

wavelength_bins.append([3.2e-6, 4e-6])
wavelength_bins.append([4e-6, 5e-6])
depth_calculator.change_wavelength_bins(wavelength_bins)

wavelengths, transit_depths = depth_calculator.compute_depths(
    Rp, temperature, logZ=logZ, CO_ratio=CO, cloudtop_pressure=1e3)
#wavelengths, depths2 = depth_calculator.compute_depths(71414515.1348402, P_prof

retriever = Retriever()

fit_info = retriever.get_default_fit_info(Rs,
                                          g,
                                          0.99 * Rp,
                                          0.9 * temperature,
                                          logZ=2,
                                          CO_ratio=1,
                                          add_fit_params=True)

errors = np.random.normal(scale=50e-6, size=len(transit_depths))
transit_depths += errors
Example #12
0
Rs = 0.947 * R_sun
Mp = 8.145 * M_earth
Rp = 1.7823 * R_earth

T = 1970
logZ = 1.09
CO_ratio = 1.57
log_cloudtop_P = 4.875

#create a TransitDepthCalculator object and compute wavelength dependent transit depths
depth_calculator = TransitDepthCalculator()
wavelengths, transit_depths, info = depth_calculator.compute_depths(
    Rs,
    Mp,
    Rp,
    T,
    T_star=5196,
    logZ=logZ,
    CO_ratio=CO_ratio,
    cloudtop_pressure=10.0**log_cloudtop_P,
    full_output=True)

color_bins = 1e-6 * np.array([
    [4, 5],
    [3.2, 4],
    [1.1, 1.7],
])

visualizer = Visualizer()
image, scale = visualizer.draw(info,
                               color_bins,
                               star_color=[1, 1, 0.9],
class SpectrumGenerator:
    def __init__(self):
        '''
        The SpectrumGenerator generates spectra at different resolutions and
        with noises
        '''
        self.calculator = TransitDepthCalculator()

    def generate_spectrum(self,
                          Rs,
                          Mp,
                          Rp,
                          T_planet,
                          T_star,
                          Ms,
                          logZ=0,
                          CO_ratio=0.53,
                          scattering_factor=1,
                          cloudtop_pressure=np.inf,
                          resolution=None,
                          noise_level=None,
                          max_wavelength=3e-5,
                          min_wavelength=3e-7,
                          albedo=0.8):
        '''
        Generates a spectrum using the PLATON TransitDepthCalculator.

        Parameters
        ----------
        Rs : float
            Stellar radius in solar radii
        Mp : float
            Planet mass in Jupiter masses
        Rp : float
            Planet radius in Jupiter radii
        T_planet : float
            Temperature of the isothermal atmosphere in Kelvin
        T_star : float
            Blackbody temperature of the star
        Ms : float
            Mass of the star in solar masses
        logZ : float, optional
            base-10 logarithm of the metallicity in solar units. Default is 0.
        CO_ratio : float, optional
            C/O atomic ratio in the atmosphere. The default value is 0.53
            (solar) value.
        scattering_factor : float, optional
            Makes rayleigh scattering this many times as strong. Default is 1
        cloudtop_pressure : float, optional
            Pressure level (in PA) below which light cannot penetrate. Use
            np.inf for cloudless. Default is np.inf
        resolution : int or None, optional
            If provided, will produce spectra of the given spectral resolution.
            Default is None
        noise_level : float or None, optional
            The noise on the data in ppm. If provided, Gaussian noise will be
            added to the spectrum. Default is None.
        max_wavelength : float, optional
            The maximum wavelength to consider in m. Default is 3e-5
        min_wavelength : float, optional
            The minimum wavelength to consider in m. Default is 3e-7

        Returns
        -------
        spectrum : TransitCurveGen.Spectrum
            A Spectrum object containing all the information on the spectrum
        '''

        # Generate the basic spectrum
        wavelengths, depths = self.calculator.compute_depths(
            Rs * R_sun,
            Mp * M_jup,
            Rp * R_jup,
            T_planet,
            logZ=logZ,
            CO_ratio=CO_ratio,
            scattering_factor=scattering_factor,
            cloudtop_pressure=cloudtop_pressure)

        # Remove wavelengths not of interest
        # First cut off the large wavelengths from depths and wavelengths.
        # MUST be done in this order else depths can't reference wavelengths
        depths = depths[wavelengths <= max_wavelength]
        wavelengths = wavelengths[wavelengths <= max_wavelength]

        depths = depths[wavelengths >= min_wavelength]
        wavelengths = wavelengths[wavelengths >= min_wavelength]

        # Convolve to give a particular resolution
        if resolution is not None:
            wavelengths, depths = self._bin_spectrum(wavelengths, depths,
                                                     resolution)

        # Add in noise if required
        if noise_level is not None:
            wavelengths, depths = self._add_noise(wavelengths, depths,
                                                  noise_level)

        info_dict = {
            'Rs': Rs,
            'Mp': Mp,
            'Rp': Rp,
            'T_planet': T_planet,
            'logZ': logZ,
            'CO_ratio': CO_ratio,
            'scattering_factor': scattering_factor,
            'cloudtop_pressure': cloudtop_pressure,
            'resolution': resolution,
            'noise': noise_level,
            'T_star': T_star,
            'Ms': Ms,
            'albedo': albedo
        }

        return Spectrum(wavelengths, depths, info_dict)

    def _bin_spectrum(self, wavelengths, depths, R):
        '''
        Bins a given spectrum to a spectral resolution R

        Parameters
        ----------
        wavelengths : array_like, shape (n_wavelengths,)
            The wavelengths of each data point. We assume that these are
            logarithmically spaced.
        depths : array_like, shape (n_wavelengths,)
            The transit depth of each data point.
        R : int
            Spectral resolution to bin to.

        Returns
        -------
        wavelengths : np.array
            The centre wavelength of each new wavelength bin
        depths : np.array
            The transit depth in each of the new wavelength bins

        Notes
        -----
        The binning is done using convolution with a top-hat.
        '''
        # Take log base-10 of the wavelengths to work on resolution
        log_wl = np.log10(wavelengths)

        # Find the wavelength spacing in log space
        delta = round(log_wl[1] - log_wl[0], 7)

        # Find the original resolution of the spectrum
        R_original = 1 // delta

        if R > R_original:
            raise ValueError(
                'Spectrum has resolution {}: cannot increase resolution to {}'.
                format(R_original, R))

        # Work out how many current wl bins we need for the given resolution
        nbins = int(1 // (R * delta))

        # Do the binning
        wavelengths = wavelengths[:(wavelengths.size // nbins) *
                                  nbins].reshape(-1, nbins).mean(axis=1)
        depths = depths[:(depths.size // nbins) * nbins].reshape(
            -1, nbins).mean(axis=1)

        return wavelengths, depths

    def _add_noise(self, wavelengths, depths, noise_ppm):
        '''
        Adds Gaussian noise to a given spectrum

        Parameters
        ----------
        wavelengths : array_like, shape (n_wavelengths,)
            The wavelengths of each data point. We assume that these are
            logarithmically spaced.
        depths : array_like, shape (n_wavelengths,)
            The transit depth of each data point.
        noise_ppm : int
            The noise in parts per million

        Returns
        -------
        wavelengths : np.array
            The wavelengths
        depths : np.array
            The depths with Gaussian noise added.
        '''

        disp_arr = np.zeros(len(depths))

        for i, d in enumerate(depths):
            disp_arr[i] = np.random.normal(0, noise_ppm * 1e-6)

        depths += disp_arr

        return wavelengths, depths