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_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)
 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_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)
    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))
示例#8
0
time_stamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
result_dict = {'samples':result.samples, 'weights':result.weights, 'logl':result.logl}
joblib.dump(result_dict, 'multinest_results_{}.joblib.save'.format(time_stamp))


# Establish the Range in Wavelength to plot high resolution figures
wave_min = wave_bins.min()
wave_max = wave_bins.max()

n_theory_pts = 500
wavelengths_theory = np.linspace(wave_min, wave_max, n_theory_pts)
half_diff_lam = 0.5*np.median(np.diff(wavelengths_theory))

# Setup calculator to use the theoretical wavelengths
calculator = TransitDepthCalculator(include_condensation=True)
calculator.change_wavelength_bins(np.transpose([wavelengths_theory-half_diff_lam, wavelengths_theory+half_diff_lam]))

retriever._validate_params(fit_info, calculator)

# Allocate the best-fit parameters from the `result` class
best_params_arr = result.samples[np.argmax(result.logl)]
best_params_dict = {key:val for key,val in zip(fit_info.fit_param_names, best_params_arr)}

# Set the static parameteres to the default values
for key in fit_info.all_params.keys():
    if key not in best_params_dict.keys():
        best_params_dict[key] = fit_info.all_params[key].best_guess

# Assign the best fit model parameters to necessary variables
Rs = best_params_dict['Rs']
示例#9
0
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()
示例#10
0
    def __init__(self, *args, **kwargs):
        super(TestMieAbsorption, self).__init__(*args, **kwargs)

        # We're storing this object to take advantage of its cache, not
        # for speed, but to test the cache
        self.calc = TransitDepthCalculator()
    return np.array(wavelength_bins)


def spitzer_bins():
    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
    def run_multinest(self,
                      transit_bins,
                      transit_depths,
                      transit_errors,
                      eclipse_bins,
                      eclipse_depths,
                      eclipse_errors,
                      fit_info,
                      include_condensation=True,
                      plot_best=False,
                      **nestle_kwargs):
        '''Runs nested sampling to retrieve atmospheric parameters.

        Parameters
        ----------
        transit_bins : array_like, shape (N,2)
            Wavelength bins, where wavelength_bins[i][0] is the start
            wavelength and wavelength_bins[i][1] is the end wavelength for
            bin i.
        transit_depths : array_like, length N
            Measured transit depths for the specified wavelength bins
        transit_errors : array_like, length N
            Errors on the aforementioned transit depths
        eclipse_bins : array_like, shape (N,2)
            Wavelength bins, where wavelength_bins[i][0] is the start
            wavelength and wavelength_bins[i][1] is the end wavelength for
            bin i.
        eclipse_depths : array_like, length N
            Measured eclipse depths for the specified wavelength bins
        eclipse_errors : array_like, length N
            Errors on the aforementioned eclipse depths
        fit_info : :class:`.FitInfo` object
            Tells us what parameters to
            freely vary, and in what range those parameters can vary. Also
            sets default values for the fixed parameters.
        include_condensation : bool, optional
            When determining atmospheric abundances, whether to include
            condensation.
        plot_best : bool, optional
            If True, plots the best fit model with the data
        **nestle_kwargs : keyword arguments to pass to nestle's sample method

        Returns
        -------
        result : Result object
            This returns the object returned by nestle.sample, slightly
            modified.  The object is
            dictionary-like and has many useful items.  For example,
            result.samples (or alternatively, result["samples"]) are the
            parameter values of each sample, result.weights contains the
            weights, result.logl contains the ln likelihoods, and result.logp
            contains the ln posteriors (this is added by PLATON).  result.logz
            is the natural logarithm of the evidence.
        '''
        transit_calc = TransitDepthCalculator(
            include_condensation=include_condensation)
        transit_calc.change_wavelength_bins(transit_bins)
        eclipse_calc = EclipseDepthCalculator()
        eclipse_calc.change_wavelength_bins(eclipse_bins)

        self._validate_params(fit_info, transit_calc)

        def transform_prior(cube):
            new_cube = np.zeros(len(cube))
            for i in range(len(cube)):
                new_cube[i] = fit_info._from_unit_interval(i, cube[i])
            return new_cube

        def multinest_ln_like(cube):
            return self._ln_like(cube, transit_calc, eclipse_calc, fit_info,
                                 transit_depths, transit_errors,
                                 eclipse_depths, eclipse_errors)

        def callback(callback_info):
            print("Iteration {}: {}".format(callback_info["it"],
                                            self.pretty_print(fit_info)))

        result = nestle.sample(multinest_ln_like,
                               transform_prior,
                               fit_info._get_num_fit_params(),
                               callback=callback,
                               method='multi',
                               **nestle_kwargs)

        result.logp = result.logl + np.array(
            [fit_info._ln_prior(params) for params in result.samples])
        best_params_arr = result.samples[np.argmax(result.logp)]

        write_param_estimates_file(
            nestle.resample_equal(result.samples, result.weights),
            best_params_arr, np.max(result.logp), fit_info.fit_param_names)

        if plot_best:
            self._ln_prob(best_params_arr,
                          transit_calc,
                          eclipse_calc,
                          fit_info,
                          transit_depths,
                          transit_errors,
                          eclipse_depths,
                          eclipse_errors,
                          plot=True)
        return result
    def run_emcee(self,
                  transit_bins,
                  transit_depths,
                  transit_errors,
                  eclipse_bins,
                  eclipse_depths,
                  eclipse_errors,
                  fit_info,
                  nwalkers=50,
                  nsteps=1000,
                  include_condensation=True,
                  plot_best=False):
        '''Runs affine-invariant MCMC to retrieve atmospheric parameters.

        Parameters
        ----------
        transit_bins : array_like, shape (N,2)
            Wavelength bins, where wavelength_bins[i][0] is the start
            wavelength and wavelength_bins[i][1] is the end wavelength for
            bin i.
        transit_depths : array_like, length N
            Measured transit depths for the specified wavelength bins
        transit_errors : array_like, length N
            Errors on the aforementioned transit depths
        eclipse_bins : array_like, shape (N,2)
            Wavelength bins, where wavelength_bins[i][0] is the start
            wavelength and wavelength_bins[i][1] is the end wavelength for
            bin i.
        eclipse_depths : array_like, length N
            Measured eclipse depths for the specified wavelength bins
        eclipse_errors : array_like, length N
            Errors on the aforementioned eclipse depths
        fit_info : :class:`.FitInfo` object
            Tells the method what parameters to
            freely vary, and in what range those parameters can vary. Also
            sets default values for the fixed parameters.
        nwalkers : int, optional
            Number of walkers to use
        nsteps : int, optional
            Number of steps that the walkers should walk for
        include_condensation : bool, optional
            When determining atmospheric abundances, whether to include
            condensation.
        plot_best : bool, optional
            If True, plots the best fit model with the data

        Returns
        -------
        result : EnsembleSampler object
            This returns emcee's EnsembleSampler object.  The most useful
            attributes in this item are result.chain, which is a (W x S X P)
            array where W is the number of walkers, S is the number of steps,
            and P is the number of parameters; and result.lnprobability, a
            (W x S) array of log probabilities.  For your convenience, this
            object also contains result.flatchain, which is a (WS x P) array
            where WS = W x S is the number of samples; and
            result.flatlnprobability, an array of length WS
        '''

        initial_positions = fit_info._generate_rand_param_arrays(nwalkers)
        transit_calc = TransitDepthCalculator(
            include_condensation=include_condensation)
        transit_calc.change_wavelength_bins(transit_bins)
        eclipse_calc = EclipseDepthCalculator()
        eclipse_calc.change_wavelength_bins(eclipse_bins)

        self._validate_params(fit_info, transit_calc)

        sampler = emcee.EnsembleSampler(
            nwalkers,
            fit_info._get_num_fit_params(),
            self._ln_prob,
            args=(transit_calc, eclipse_calc, fit_info, transit_depths,
                  transit_errors, eclipse_depths, eclipse_errors))

        for i, result in enumerate(
                sampler.sample(initial_positions, iterations=nsteps)):
            if (i + 1) % 10 == 0:
                print("Step {}: {}".format(i + 1, self.pretty_print(fit_info)))

        best_params_arr = sampler.flatchain[np.argmax(
            sampler.flatlnprobability)]

        write_param_estimates_file(sampler.flatchain, best_params_arr,
                                   np.max(sampler.flatlnprobability),
                                   fit_info.fit_param_names)

        if plot_best:
            self._ln_prob(best_params_arr,
                          transit_calc,
                          eclipse_calc,
                          fit_info,
                          transit_depths,
                          transit_errors,
                          eclipse_depths,
                          eclipse_errors,
                          plot=True)

        return sampler
 def __init__(self):
     '''
     The SpectrumGenerator generates spectra at different resolutions and
     with noises
     '''
     self.calculator = TransitDepthCalculator()