Source code for pyspectools.astro.radiative


""" radiative.py

    Routines for calculating quantities useful for
    radiative transfer, such as Einstein coefficients
"""
import numpy as np
import pandas as pd
from scipy import constants

from pyspectools.units import kbcm, MHz2cm


[docs]def parse_str(filepath): # Function that will parse a .str file from SPCAT # This file can be generated by supplying 0020 as # the first flag in the `.int` file. # Returns a Pandas dataframe names = [ "Frequency", "RTDM", "Formatting", "Upper QN", "Lower QN", "Dipole Category" ] # Use fixed-width reading in pandas str_df = pd.read_fwf( filepath, widths=[15, 15, 5, 12, 12, 11], names=names, index=False ) return str_df
[docs]def I2S(I, Q, frequency, E_lower, T=300.): """ Function for converting intensity (in nm^2 MHz) to the more standard intrinsic linestrength, S_ij mu^2. Parameters ---------- I - float The log of the transition intensity, typically given in catalog files Q - float Partition function at specified temperature T frequency - float Frequency of the transition in MHz E_lower - float Energy of the lower state in wavenumbers T - float Temperature in Kelvin Returns ------- siju - float Value of the intrinsic linestrength """ E_upper = calc_E_upper(frequency, E_lower) # top part of the equation A = 10.**I * Q lower_factor = boltzmann_factor(E_lower, T) # Boltzmann factors upper_factor = boltzmann_factor(E_upper, T) # Calculate the lower part of the equation # The prefactor included here is taken from Brian # Drouin's notes B = (4.16231e-5 * frequency * (lower_factor - upper_factor)) return A / B
[docs]def calc_E_upper(frequency, E_lower): """ Calculate the upper state energy, for a given lower state energy and the frequency of the transition. Parameters ---------- frequency - float Frequency of the transition in MHz E_lower - float Lower state energy in wavenumbers Returns ------- E_upper - float Upper state energy in wavenumbers """ transition_freq = MHz2cm(frequency) return transition_freq + E_lower
[docs]def boltzmann_factor(E, T): """ Calculate the Boltzmann weighting for a given state and temperature. Parameters ---------- E - float State energy in wavenumbers T - float Temperature in Kelvin Returns ------- boltzmann_factor - float Unitless Boltzmann factor for the state """ return np.exp(-E / (kbcm * T))
[docs]def approx_Q_linear(B, T): """ Approximate rotational partition function for a linear molecule. Parameters ---------- B - float Rotational constant in MHz. T - float Temperature in Kelvin. Returns ------- Q - float Rotational partition function at temperature T. """ Q = 2.0837e4 * (T / B) return Q
[docs]def approx_Q_top(A, B, T, sigma=1, C=None): """ Approximate expression for the (a)symmetric top partition function. The expression is adapted from Gordy and Cook, p.g. 57 equation 3.68. By default, the prolate top is used if the C constant is not specified, where B = C. Oblate case can also be specified if A = C. Parameters ---------- A - float Rotational constant for the A principal axis, in MHz. B - float Rotational constant for the B principal axis, in MHz. T - float Temperature in Kelvin sigma - int Rotational level degeneracy; i.e. spin statistics C - float, optional Rotational constant for the C principal axis, in MHz. Defaults to None, which will reduce to the prolate top case. Returns ------- Q - float Partition function for the molecule at temperature T """ if C is None: # For a symmetric top, B = C C = B Q = (5.34e6 / sigma) * (T**3. / (A * B * C))**0.5 return Q
[docs]def einsteinA(S, frequency): # Prefactor is given in the PGopher Intensity formulae # http://pgopher.chm.bris.ac.uk/Help/intensityformulae.htm # Units of the prefactor are s^-1 MHz^-3 D^-2 # Units of Einstein A coefficient should be in s^-1 prefactor = 1.163965505e-20 return prefactor * frequency**3. * S
[docs]def calc_einstein(str_filepath): """ High-level function for calculating Einstein A coefficients for a given .str file output from SPCAT. """ str_df = parse_str(str_filepath) # Calculate the transition moment dipole from the # square of the str output str_df["TDM"] = str_df["RTDM"]**2. # Calculate the Einstein A coefficients in units # of per second str_df["Einstein A"] = einsteinA( str_df["TDM"], str_df["Frequency"] ) # Sort the dataframe by ascending frequency str_df = str_df.sort_values(["Frequency"], ascending=True) return str_df