Source code for simudo.util.blackbody
from functools import partial
import numpy as np
from cached_property import cached_property
from scipy.integrate import quad
__all__ = ['Blackbody']
[docs]class Blackbody():
def __init__(self, temperature):
unit_registry = temperature._REGISTRY
self.unit_registry = unit_registry
self.temperature = temperature
@property
def u(self):
return self.unit_registry
[docs] def blackbody_I_E(self, energy_unit):
u = self.u
h, c = u.h, u.c
fac = (2*energy_unit**3/h**3/c**2)
return (fac, lambda T, E: E**3/np.expm1(E/T))
[docs] def blackbody_I_E_solar(self):
''' (energy unit, dimensionful prefactor, B_E in energy_unit) '''
eu = self.u.eV
fac, f = self.blackbody_I_E(eu)
fac = fac.to('1/m**2/s')
T = (self.temperature * self.u.boltzmann_constant).m_as(eu)
return (eu, fac, partial(f, T))
[docs] def blackbody_I_E_solar_on_earth(self):
eu, factor, f = self.blackbody_I_E_solar()
return (eu, factor*self.distance_factor*self.geometric_factor, f)
[docs] def photon_flux_integral(self, eu_prefactor_B, E0, E1):
eu, factor, f = eu_prefactor_B
r = quad(lambda E: f(E)/E, E0.m_as(eu), E1.m_as(eu))[0]
return (r*factor).to('1/m^2/s')
[docs] def photon_flux_integral_on_earth(self, E0, E1):
'''Assuming an observer at normal incidence on Earth, compute
the photon flux coming from a black sun in a given energy range.
Parameters
----------
E0:
Lower bound on photon energy.
E1:
Upper bound on photon energy.
Returns
-------
photon_flux: quantity
Photon flux.
'''
return self.photon_flux_integral(
self.blackbody_I_E_solar_on_earth(), E0, E1).to('1/cm^2/s')
[docs] def total_intensity_on_earth(self):
eu, factor, f = self.blackbody_I_E_solar_on_earth()
r = quad(f, 0, 20.)[0]
return (r*factor*eu).to('W/m^2')
@cached_property
def geometric_factor(self):
# because we're emitting into half of a hemisphere worth of solid angle
factor = 2*np.pi
# because there's a cosine factor for intensity that we're integrating over
factor *= 0.5
return factor
@cached_property
def distance_factor(self):
earth_sun_distance = 149.6e6
sun_radius = 695508
return (sun_radius / earth_sun_distance)**2
[docs] def non_overlapping_energy_ranges(self, energies, inf=None):
'''Helper method for computing non-overlapping energy ranges.
Parameters
----------
energies: dict
Mapping where keys are arbitrary (typically: names of transitions
or optical fields), and values are energy range lower bounds.
inf: optional
Upper limit on energy. By default, 20 eV.
Returns
-------
ranges: dict
Mapping with the same keys as the :code:`energies` argument, and
where the values are tuples :code:`(lower, upper)` such that the
lower bound is equal to :code:`energies[k]`, and the upper bound
is the smallest energy that is above :code:`lower`. If none
exists, then :code:`upper` is the :code:`inf` argument.
'''
if inf is None:
inf = 20 * self.u.eV
Es = list(energies.items())
Es.sort(reverse=True, key=lambda x: x[1])
result = {}
prev = inf
for k, E in Es:
result[k] = (E, prev)
prev = E
return result