Create planets and stars

[ ]:
import astropy.units as u
import numpy as np
from exo_k import Spectrum, wavenumber_grid_R
from matplotlib import pyplot as plt

from pytmosph3r import planet, star

Creating planets with units

[ ]:
planet_surface_gravity = 1000 * u.cm / u.s ** 2  # not si
planet_radius = 1 * u.Rearth  # Not SI

p = planet.Planet(surface_gravity=planet_surface_gravity, radius=planet_radius)

print(f'|{p.surface_gravity=} | {p.mass=} | {p.radius=}|')

We can see that by providing quantities (ie value with a unit), pytmosph3r was able to do the correct conversion to the units system used internally.

To use the mass of the planet inplace of the surface gravity, a helper function is provided and can be used in the following manner:

[ ]:
planet_mass = p.mass * u.kg

q = planet.Planet(surface_gravity=planet.mass_to_surface_gravity(mass=planet_mass, radius=planet_radius),
                  radius=planet_radius)

print(f'|{p.surface_gravity=} | {p.mass=} | {p.radius=}|')
print(f'|{q.surface_gravity=} | {q.mass=} | {q.radius=}|')

We see that both planets share the same properties as expected.

Creating stars with units, blackbodies, and real stars

pytmosph3r provide multiple way to store the properties and behavior of a star. For example the star radius is used to compute ratio, or the spectrum method allow to get the flux emitted by the star.

At the current time, we allow to define a star as a blackbody or by providing the flux density at the star surface.

[ ]:
print(star.BaseStar.__subclasses__())

If a star follow the behavior of a blackbody, we allow to define it as a function of its effective temperature or its bolometric luminosity (defined on the spectral range, not \(\mathbb{R}^+\)):

[ ]:
star_radius = 1. * u.Rsun
[ ]:
star_effective_temperature = 5700 * u.K
star_bolometric_luminosity = star.luminosity_from_temperature(temperature=star_effective_temperature,
                                                              radius=star_radius)  # helper function

star_from_eff_temperature = star.BlackbodyStar.fromEffectiveTemperature(temperature=5700 * u.K, radius=star_radius)
star_from_bolometric_luminosity = star.BlackbodyStar.fromBolometricLuminosity(
        bolometric_luminosity=star_bolometric_luminosity, radius=star_radius)

Then, we can plot the flux of the star at its surface or at a given distance (from its center) from it:

[ ]:
wnedges = wavenumber_grid_R(1000, 16667, 200)  # wavenumber edges grid
wns = (wnedges[1:] + wnedges[:-1]) / 2  # center of each cell
distance = star_radius + 1.e-3 * u.AU  # distance from the star center where we want to observe the flux

spectrum_bb_surface: Spectrum = star_from_eff_temperature.spectrum(wnedges,
                                                                   wns)  # get the flux at the surface, `distance=None` => no rescaling done
spectrum_bb_distance: Spectrum = star_from_eff_temperature.spectrum(wnedges, wns,
                                                                    distance=distance.to_value(
                                                                        u.m))  # get the distance, ie rescaled
[ ]:
fig, ax = plt.subplots(nrows=1, ncols=1, squeeze=True)
spectrum_bb_surface.plot_spectrum(ax, x_axis='wls', xscale='log', label='Flux at surface')
spectrum_bb_distance.plot_spectrum(ax, x_axis='wls', xscale='log', label=f'Flux at {(distance - star_radius).to(u.AU)} from the surface')
fig.suptitle('Comparaison of the flux received at different distance')
fig.legend(loc='center right')
fig.tight_layout()

In the case where you want to use a custom spectrum, the class pytmosph3r.star.SpectrumStar allow you to have the same behavior, by taking a exo_k.Spectrum as parameter. For example, if we want to add a noise to the spectrum from the previous blackbody:

[ ]:
spectrum_noised = spectrum_bb_surface.copy() + Spectrum(value=np.random.normal(0, 100, wns.shape), wnedges=wnedges,
                                                        wns=wns)
star_from_spectrum = star.SpectrumStar(spectrum=spectrum_noised, radius=star_radius)

And like previously, we can plot the spectrum at different distance.

[ ]:
fig, ax = plt.subplots(nrows=1, ncols=1, squeeze=True)

# Spectrum from a star with a custom spectrum at the surface
# under the hood `distance=None` is the same as `distance={star radius in meter}`
star_from_spectrum.spectrum(wnedges, wns, star_radius.to_value(u.m)).plot_spectrum(ax, x_axis='wls', xscale='log',
                                                                                   label=f'Flux with noised at surface')
star_from_spectrum.spectrum(wnedges, wns, distance.to_value(u.m)).plot_spectrum(ax, x_axis='wls', xscale='log',
                                                                                label=f'Flux with noised at {(distance - star_radius).to(u.AU)} from the surface')

# Blackbody
spectrum_bb_surface.plot_spectrum(ax, x_axis='wls', xscale='log', label='Flux at surface')
spectrum_bb_distance.plot_spectrum(ax, x_axis='wls', xscale='log', label=f'Flux at {(distance - star_radius).to(u.AU)} from the surface')


fig.suptitle('Comparaison ')
ax.legend(loc='best')
fig.tight_layout()