Getting Started#
Welcome to pyROX! These notebooks (also available on GitHub) will explain how to use pyROX and some of its features.
After installation, pyROX can be called directly from a terminal using the pyROX command. The first positional argument should be a python-script with configuration parameters. This notebook outlines examples of these parameters and how they can be used to calculate the line-by-line opacity cross-sections of AlH.
[1]:
from pyROX import utils, cross_sections
Configuration parameters#
We’ll use the AloHa line list calculated by the ExoMol team as the input data for pyROX. The configuration file examples/exomol_alh/exomol_alh.py begins with some basic information on the database and species.
[2]:
# Basic information on database and species
database = 'exomol' # Can be ['exomol', 'hitran', 'hitemp', 'kurucz']
species = 'alh' # Species name
mass = 27.98948 # Can be found in *.def.json file
Units in pyROX
Internally, pyROX uses SI units and the output products are thus also in units of m, m\(^2\)(/molecule), Pa, and K for wavelength, cross-sections, pressure and temperature, respectively. However, since line lists are not in SI we have chosen to allow more generally adopted units for the input parameters (e.g. amu, µm, cm\(^{-1}\)). Warnings are raised to show the expected unit of the given parameters.
Next, we define the directories where the input-data and output-data should be stored. In addition, we provide a URL to download the definition-file (*.def.json) from the ExoMol website. This file is read in and the partition-function, transitions and state-energies will be downloaded and stored in the input_data_dir directory. In addition, we’ll download pressure-broadening coefficients for perturbations by H\(_2\) and He.
Note
The download instructions are different for the other databases (see “Downloading”).
[3]:
# Input/output-directories
input_data_dir = '../../examples/exomol_alh/input_data/'
output_data_dir = '../../examples/exomol_alh/'
# Instructions to download from ExoMol database
urls = [
'https://www.exomol.com/db/AlH/27Al-1H/AloHa/27Al-1H__AloHa.def.json',
'https://www.exomol.com/db/AlH/27Al-1H/27Al-1H__H2.broad',
'https://www.exomol.com/db/AlH/27Al-1H/27Al-1H__He.broad',
]
The downloaded files are 27Al-1H__AloHa.trans.bz2, 27Al-1H__AloHa.states.bz2, and 27Al-1H__AloHa.pf which are given as the transitions, states, and partition_function keys.
[4]:
# Input-data files
files = dict(
transitions = f'{input_data_dir}/27Al-1H__AloHa.trans.bz2',
states = f'{input_data_dir}/27Al-1H__AloHa.states.bz2',
partition_function = f'{input_data_dir}/27Al-1H__AloHa.pf',
)
Pressure-temperature and wavenumber grids#
Next, we define the pressure-temperature grid on which to calculate the opacities (\(8\times2=16\) PT-points in this example).
In addition, we’ll set up the wavenumber grid ranging from wavelengths \(\lambda=0.3\) to \(28\ \mathrm{\mu m}\) with an equal spacing in wavenumber \(\Delta\nu=0.01\ \mathrm{cm^{-1}}\).
Note
The wavenumber/wavelength grid can be defined in several ways:
Reading in custom wavelengths (in µm) from a file (e.g.
wave_file='wave_um.dat').Defining the range explicitly using
wave_min=0.3,wave_max=28.0(in µm) ornu_min,nu_max(in cm-1).Using an equal wavenumber- or wavelength-spacing (e.g.
delta_nu=0.01in cm-1 ordelta_wave=1e-3in µm).Using a fixed resolution (e.g.
resolution=1e6).
The adaptive_nu_grid flag will make the wavenumber grid coarser if the lines are substantially broadened (i.e. at high pressures), which speeds up the line-profile calculations. The adaptive_nu_grid flag only works for equal wavenumber-spacings.
[5]:
import numpy as np
# Pressure and temperature grids
P_grid = np.logspace(-3, 2, 6) # [bar]
T_grid = np.array([1000,2000]) # [K]
# Wavenumber grid
wave_min = 0.3; wave_max = 28.0 # [um]
delta_nu = 0.01 # [cm^-1]
adaptive_nu_grid = True # Switch to sparser wavenumber grid for high broadening?
Broadening information#
pyROX considers three sources of broadening: Doppler, natural, and pressure (or Van der Waals) broadening. Doppler broadening is caused by the aborber’s thermal motion and is thus controlled by the transition energy and temperature (\(\gamma_\mathrm{D} \propto \nu_0\sqrt{T}\)). Natural broadening arises from the uncertainty principle and can be described with the Einstein \(A_{ul}\) coefficient of each transition \(\gamma_\mathrm{N}\propto A_{ul}\). The Doppler and natural broadening widths are automatically calculated by pyROX.
Pressure broadening results from perturbations by other atoms/molecules and can be described in a multitude of ways, depending on the absorber, perturber, quantum states etc. In this case, we assume an atmosphere dominated by H2 and He and provide information in the perturber_info dictionary. For each perturber, we specify its volume-mixing ratio (VMR) and refer to a file which contains the broadening coefficients \(\gamma\) and \(n\). The pressure-broadening coefficient is
then calculated as the sum over all perturbers
where \(T_\mathrm{ref}=296\ \mathrm{K}\) is a reference temperature.
Note
The pressure broadening description has various options which are outlined in “Pressure Broadening”.
[6]:
# Pressure-broadening information
perturber_info = dict(
H2 = dict(VMR=0.85, file=f'{input_data_dir}/27Al-1H__H2.broad'), # Read from file
He = dict(VMR=0.15, file=f'{input_data_dir}/27Al-1H__He.broad'),
)
Line-strength and wing cutoffs#
The convolution of a Gaussian profile (Doppler) and a Lorentzian profile (natural+pressure) results in a Voigt profile, which is generally slow to compute as no analytical function exists. Since line lists can consist of millions/billions of transitions, it can be beneficial to ignore lines with minor contributions to the total opacity.
The global_cutoff parameter removes any transitions with line-strengths, \(S(T)\), below the given threshold. The local_cutoff is given as a fraction of the cumulative line-strength within a wavenumber grid-point, \(S_\mathrm{tot}(T,\nu_i)\). Any transitions with line-strengths below local_cutoff\(\cdot S_\mathrm{tot}(T,\nu_i)\) are removed and their strengths get added to the strongest line in that bin. No cutoffs are applied if the respective parameter is not given.
The wing_cutoff controls the extent to which the line profile is computed. Since different prescriptions exist in the literature, pyROX allows the wing_cutoff to be a function which takes the Voigt-width (in \(\mathrm{cm^{-1}}\)) and pressure (in bar) as input arguments. The function should output the cutoff distance from the line centre in \(\mathrm{cm^{-1}}\). The default function (used here) follows Gharib-Nezhad et al.
(2024).
[7]:
# Line-strength cutoffs
global_cutoff = 1e-45 # [cm^-1 / (molecule cm^-2)]
local_cutoff = 0.25
# Function with arguments gamma_V [cm^-1], and P [bar]
wing_cutoff = lambda gamma_V, P: 25 if P<=200 else 100 # Gharib-Nezhad et al. (2024)
Downloading from the database#
We now have all the parameters to calculate the AlH cross-sections! If pyROX is called from the command line, it requires the first positional argument to be a python-script with the above parameters. For instance,
pyROX examples/exomol_alh/exomol_alh.py
ran from the pyROX base-directory should find the exomol_alh.py configuration-file and set up a config object that is used to initialise the code. In this notebook, we’ll set up the config object manually with the following code-block.
Note
Simple CPU parallelisation is supported through the joblib framework. By default, pyROX will use only one CPU unless the N_CPUs argument is given (in this example 4).
[8]:
# Setup a configuration object (done automatically when running pyROX from the command line)
config = utils.update_config_with_args(
database=database,
species=species,
mass=mass,
input_data_dir=input_data_dir,
output_data_dir=output_data_dir,
urls=urls,
files=files,
P_grid=P_grid,
T_grid=T_grid,
wave_min=wave_min,
wave_max=wave_max,
delta_nu=delta_nu,
adaptive_nu_grid=adaptive_nu_grid,
perturber_info=perturber_info,
local_cutoff=local_cutoff,
global_cutoff=global_cutoff,
wing_cutoff=wing_cutoff,
N_CPUs=4,
)
Updating configuration with new parameters
[pyROXWarning] Adding parameter "database" as "exomol".
[pyROXWarning] Adding parameter "species" as "alh".
[pyROXWarning] Adding parameter "mass" as 27.98948.
[pyROXWarning] Adding parameter "input_data_dir" as "../../examples/exomol_alh/input_data/".
[pyROXWarning] Adding parameter "output_data_dir" as "../../examples/exomol_alh/".
[pyROXWarning] Adding parameter "urls" as ['https://www.exomol.com/db/AlH/27Al-1H/AloHa/27Al-1H__AloHa.def.json', 'https://www.exomol.com/db/AlH/27Al-1H/27Al-1H__H2.broad', 'https://www.exomol.com/db/AlH/27Al-1H/27Al-1H__He.broad'].
[pyROXWarning] Adding parameter "files" as {'transitions': '../../examples/exomol_alh/input_data//27Al-1H__AloHa.trans.bz2', 'states': '../../examples/exomol_alh/input_data//27Al-1H__AloHa.states.bz2', 'partition_function': '../../examples/exomol_alh/input_data//27Al-1H__AloHa.pf'}.
[pyROXWarning] Adding parameter "P_grid" as [1.e-03 1.e-02 1.e-01 1.e+00 1.e+01 1.e+02].
[pyROXWarning] Adding parameter "T_grid" as [1000 2000].
[pyROXWarning] Adding parameter "wave_min" as 0.3.
[pyROXWarning] Adding parameter "wave_max" as 28.0.
[pyROXWarning] Adding parameter "delta_nu" as 0.01.
[pyROXWarning] Adding parameter "adaptive_nu_grid" as True.
[pyROXWarning] Adding parameter "perturber_info" as {'H2': {'VMR': 0.85, 'file': '../../examples/exomol_alh/input_data//27Al-1H__H2.broad'}, 'He': {'VMR': 0.15, 'file': '../../examples/exomol_alh/input_data//27Al-1H__He.broad'}}.
[pyROXWarning] Adding parameter "local_cutoff" as 0.25.
[pyROXWarning] Adding parameter "global_cutoff" as 1e-45.
[pyROXWarning] Adding parameter "wing_cutoff" as <function <lambda> at 0x7f029c0c8300>.
[pyROXWarning] Adding parameter "N_CPUs" as 4.
We’ll now initialise the data object and download the line-list data from the ExoMol database. This is equivalent to the command (ran from the pyROX base-directory)
pyROX examples/exomol_alh/exomol_alh.py --download
[9]:
# Download from the ExoMol database
data = cross_sections.load_data_object(config, download=True)
------------------------------------------------------------
Line-by-line Absorption from ExoMol
------------------------------------------------------------
Downloading data from ExoMol
Downloading "https://www.exomol.com/db/AlH/27Al-1H/AloHa/27Al-1H__AloHa.def.json"
Downloading "https://www.exomol.com/db/AlH/27Al-1H/27Al-1H__H2.broad"
Downloading "https://www.exomol.com/db/AlH/27Al-1H/27Al-1H__He.broad"
Downloading "https://www.exomol.com/db/AlH/27Al-1H/AloHa/27Al-1H__AloHa.pf"
Downloading "https://www.exomol.com/db/AlH/27Al-1H/AloHa/27Al-1H__AloHa.states.bz2"
Downloading "https://www.exomol.com/db/AlH/27Al-1H/AloHa/27Al-1H__AloHa.trans.bz2"
Reading parameters from the configuration file
[pyROXWarning] Please make sure that the following parameters are given in the expected units:
[pyROXWarning] - P_grid [bar]
[pyROXWarning] - T_grid [K]
[pyROXWarning] - delta_nu [cm^-1]
[pyROXWarning] - global_cutoff [cm^-1 / (molecule cm^-2)]
[pyROXWarning] - mass [amu]
[pyROXWarning] - wave_max [um]
[pyROXWarning] - wave_min [um]
[pyROXWarning] - wing_cutoff [cm^-1]
Wavelength-grid:
Wavelength: 0.30 - 28 um
Wavenumber: 357 - 33333 cm^-1
Fixed wavenumber-spacing: 0.010 cm^-1
Number of grid points: 3297620
Adaptive grid: True
Pressure broadening info:
- H2: VMR=0.85, mass=2.02 amu | "../../examples/exomol_alh/input_data/27Al-1H__H2.broad"
- He: VMR=0.15, mass=4.00 amu | "../../examples/exomol_alh/input_data/27Al-1H__He.broad"
Mean molecular weight of perturbers: 2.31 amu
PT-grid:
P: [1.e-03 1.e-02 1.e-01 1.e+00 1.e+01 1.e+02] bar
T: [1000 2000] K
Calculating cross-sections#
The line-list data should be found in the input_data_dir directory and we can calculate the opacity cross-sections from them. The following code-block is equivalent to running the command
pyROX examples/exomol_alh/exomol_alh.py --calculate --progress_bar
[10]:
data.calculate_temporary_outputs(
progress_bar=True, # Show progress bar
#overwrite=False, # If True, answer "yes" to all overwrite prompts
)
Calculating cross-sections
Reading states file
Reading states from "../../examples/exomol_alh/input_data/27Al-1H__AloHa.states.bz2"
Reading transitions from "../../examples/exomol_alh/input_data/27Al-1H__AloHa.trans.bz2"
Number of lines loaded: 29725
100%|████████████████████| 12/12 [00:26<00:00, 2.24s/it, N_lines_computed=28486, P=1e+01 bar, T=2000 K]
Saving temporary cross-sections to "/net/lem/data2/regt/pyROX/examples/exomol_alh/tmp/xsec_27Al-1H__AloHa.trans.hdf5"
This will save a temporary output-file in the output_data_dir/tmp directory. The reason for saving temporary files is to help parallelisation of the calculations (see “Parallelisation”) and extensions of the pressure-temperature grid.
Adding more PT-points#
Here, we’ll extend the temperature grid with two more values, \(T=500\) and \(3000\ \mathrm{K}\). To avoid overwriting the previous output, we’ll also change the base filename (tmp_output_basename) from xsec.hdf5 (default) to xsec_added_PT.hdf5. The equivalent command is
pyROX examples/exomol_alh/exomol_alh.py -c -pbar --T_grid 500 3000 --tmp_output_basename xsec_added_PT.hdf5
Important
When extending the pressure-temperature grid, it is important that the final combined grid can be made rectangular. That is, every temperature should be calculated for every pressure. Setting P_grid=1 (and T_grid=[500,3000]) would result in an error in this example.
[11]:
# Update the configuration parameters
config = utils.update_config_with_args(
config=config, # Update the previous configuration
T_grid=[500,3000], # Calculate for new temperatures [K]
tmp_output_basename='xsec_added_PT.hdf5', # Make a new filename to avoid overwriting
)
# Re-load the data object
data = cross_sections.load_data_object(config, download=False)
# Calculate the cross-sections again
data.calculate_temporary_outputs(
progress_bar=True, # Show progress bar
#overwrite=False, # If True, answer "yes" to all overwrite prompts
)
Updating configuration with new parameters
[pyROXWarning] Overwriting parameter "T_grid" from [1000 2000] to [500, 3000].
[pyROXWarning] Adding parameter "tmp_output_basename" as "xsec_added_PT.hdf5".
------------------------------------------------------------
Line-by-line Absorption from ExoMol
------------------------------------------------------------
Reading parameters from the configuration file
[pyROXWarning] Please make sure that the following parameters are given in the expected units:
[pyROXWarning] - P_grid [bar]
[pyROXWarning] - T_grid [K]
[pyROXWarning] - delta_nu [cm^-1]
[pyROXWarning] - global_cutoff [cm^-1 / (molecule cm^-2)]
[pyROXWarning] - mass [amu]
[pyROXWarning] - wave_max [um]
[pyROXWarning] - wave_min [um]
[pyROXWarning] - wing_cutoff [cm^-1]
Wavelength-grid:
Wavelength: 0.30 - 28 um
Wavenumber: 357 - 33333 cm^-1
Fixed wavenumber-spacing: 0.010 cm^-1
Number of grid points: 3297620
Adaptive grid: True
Pressure broadening info:
- H2: VMR=0.85, mass=0.00 amu | "../../examples/exomol_alh/input_data/27Al-1H__H2.broad"
- He: VMR=0.15, mass=0.00 amu | "../../examples/exomol_alh/input_data/27Al-1H__He.broad"
Mean molecular weight of perturbers: 0.00 amu
PT-grid:
P: [1.e-03 1.e-02 1.e-01 1.e+00 1.e+01 1.e+02] bar
T: [ 500 3000] K
Calculating cross-sections
Reading states file
Reading states from "../../examples/exomol_alh/input_data/27Al-1H__AloHa.states.bz2"
Reading transitions from "../../examples/exomol_alh/input_data/27Al-1H__AloHa.trans.bz2"
Number of lines loaded: 29725
100%|████████████████████| 12/12 [00:24<00:00, 2.08s/it, N_lines_computed=28487, P=1e+01 bar, T=3000 K]
Saving temporary cross-sections to "/net/lem/data2/regt/pyROX/examples/exomol_alh/tmp/xsec_added_PT_27Al-1H__AloHa.trans.hdf5"
Merging temporary output-files and plotting#
The two files in the output_data_dir/tmp directory can now be merged into a final, combined pressure-temperature grid. We’ll also make a figure of the computed opacity cross-sections. The following code-block is equivalent to running the command
pyROX examples/exomol_alh/exomol_alh.py --save --plot
[12]:
data.save_combined_outputs(
#overwrite=False, # If True, answer "yes" to all overwrite prompts
)
fig, ax = data.plot_combined_outputs(
T_to_plot=[500,1000,2000,3000],
P_to_plot=[1e-2, 1, 1e2], # [bar]
return_fig_ax=True
)
fig.show()
Combining temporary files and saving final output
Merging 2 temporary files into a single grid
Temporary files:
- "xsec_27Al-1H__AloHa.trans.hdf5"
- "xsec_added_PT_27Al-1H__AloHa.trans.hdf5"
Combining PT-grids of temporary files
Saving final output to "/net/lem/data2/regt/pyROX/examples/exomol_alh/xsec.hdf5"
Plotting cross-sections
Important
The final output-file is saved as a compressed hdf5-type. It has four datasets:
P_grid: Pressure grid points (in Pa).T_grid: Temperature grid points (in K).wave: Wavelength grid points (in m).log10(xsec): Base-10 logarithm of the opacity cross-sections (in log10[m2 molecule-1]) with shape (wave,P_grid,T_grid).
Converting to pRT3-format#
pyROX offers built-in support for converting its standard output format into an h5-file that can be read in with petitRADTRANS v3. To generate the right filename and add metadata to the h5-file, we’ll have to add the pRT3_metadata dictionary to the config object.
[13]:
# Metadata to be stored in pRT3's .h5 file
pRT3_metadata = dict(
DOI = '10.1093/mnras/stad3802', # DOI of the data
mol_name = 'AlH', # Using the right capitalisation
linelist = 'AloHa', # Line-list name, used in .h5 filename
isotopologue_id = {'Al':27, 'H':1}, # Atomic number of each element
)
The following code-block will convert the opacities into the pRT3-format and is equivalent to the command
pyROX examples/exomol_alh/exomol_alh.py --convert_to_pRT3
[14]:
# Update the configuration parameters
config = utils.update_config_with_args(
config=config, # Update the previous configuration
pRT3_metadata=pRT3_metadata, # Add metadata
)
# Re-load the data object
data = cross_sections.load_data_object(config, download=False)
# Convert to the pRT3 format
data.convert_to_pRT3(contributor='Your name!')
Updating configuration with new parameters
[pyROXWarning] Adding parameter "pRT3_metadata" as {'DOI': '10.1093/mnras/stad3802', 'mol_name': 'AlH', 'linelist': 'AloHa', 'isotopologue_id': {'Al': 27, 'H': 1}}.
------------------------------------------------------------
Line-by-line Absorption from ExoMol
------------------------------------------------------------
Reading parameters from the configuration file
[pyROXWarning] Please make sure that the following parameters are given in the expected units:
[pyROXWarning] - P_grid [bar]
[pyROXWarning] - T_grid [K]
[pyROXWarning] - delta_nu [cm^-1]
[pyROXWarning] - global_cutoff [cm^-1 / (molecule cm^-2)]
[pyROXWarning] - mass [amu]
[pyROXWarning] - wave_max [um]
[pyROXWarning] - wave_min [um]
[pyROXWarning] - wing_cutoff [cm^-1]
Wavelength-grid:
Wavelength: 0.30 - 28 um
Wavenumber: 357 - 33333 cm^-1
Fixed wavenumber-spacing: 0.010 cm^-1
Number of grid points: 3297620
Adaptive grid: True
Pressure broadening info:
- H2: VMR=0.85, mass=0.00 amu | "../../examples/exomol_alh/input_data/27Al-1H__H2.broad"
- He: VMR=0.15, mass=0.00 amu | "../../examples/exomol_alh/input_data/27Al-1H__He.broad"
Mean molecular weight of perturbers: 0.00 amu
PT-grid:
P: [1.e-03 1.e-02 1.e-01 1.e+00 1.e+01 1.e+02] bar
T: [ 500 3000] K
Converting to petitRADTRANS-v3.0 format
Saved to "/net/lem/data2/regt/pyROX/examples/exomol_alh/27Al-1H__AloHa.R1e+06_0.3-28.0mu.xsec.petitRADTRANS.h5"