Custom PAH Physics
Overview
The pah_spec package relies on a set of pre-computed basis spectra \(\tilde{p}_{\lambda_{\rm em}}(\lambda_{\rm abs})\) (Eq. 3 of Richie & Hensley 2026) to generate PAH spectra. Defining these \(\tilde{p}_{\lambda_{\rm em}}(\lambda_{\rm abs})\) requires the specification of PAH energy and absorption cross-section (\(C_{\rm abs}\)) models. We provide a set of default, pre-computed \(\tilde{p}_{\lambda_{\rm em}}(\lambda_{\rm abs})\) using the PAH physics model described in Section 3 of Richie & Hensley 2026 (based on the Draine et al. 2021 model).
However, since the single photon approximation (SPA) is agnostic to the choice of PAH physics model, one may wish to employ a different PAH model to generate SPA spectra. To this end, we provide the capability to run pah_spec with custom PAH physics models. The steps to do this are:
Define Python functions encapsulating the desired energy and/or cross-section models
Compute a set of basis spectra using the custom energy and/or cross-section model
Employ the
pah_spec.PahSpecAPI with the custom basis spectra
The following instructions show how to modify the cross-section and energy functions simultaneously, but note that it is also possible to modify these functions one at a time.
1. Defining Compatible PAH Physics Python Functions
Up to three Python functions are required as inputs to pah_spec.PahSpec to utilize custom PAH physics.
Required function for custom cross-sections:
c_abs_func(wavelength_arr, radius_arr)
This function takes an array of PAH radii and wavelengths as inputs and returns the absorption cross-sections \(C_{\rm abs}\) for ionized and neutral PAHs. This function MUST have the same signature as pah_spec.PahSpec.calc_c_abs().
Specifically, c_abs_func() must take an astropy.units.Quantity array of PAH radii (in units of Angstroms) and an astropy.units.Quantity array of wavelengths (in \(\rm \mu m\)) as inputs and return two astropy.units.Quantity arrays of dimensions (len(grain_sizes), len(wavelength_arr)) of cross-sections (in \(\rm cm^2\)) for ionized and neutral PAHs, respectively.
Required functions for custom energy:
pah_energy_func(grain_size, temp_arr)pah_mode_energy_func(grain_size)
pah_energy_func() MUST have the same signature as pah_spec.calc_pah_energy(), which takes a single astropy.units.Quantity grain radius (in Angstroms) and an astropy.units.Quantity array of temperatures (in Kelvin) as inputs and returns an astropy.units.Quantity array of PAH vibrational energies of length len(temp_arr) (in ergs).
pah_mode_energy_func() MUST have the same signature as pah_spec.calc_pah_mode_energies(), which calculates the normal vibrational mode energies of the PAH that arise from \(\rm C\)–\(\rm C\) and \(\rm C\)–\(\rm H\) in-plane and out-of-plane bending and \(\rm C\)–\(\rm H\) stretching. It takes a single astropy.units.Quantity PAH radius (in Angstroms) and returns an astropy.units.Quantity array of vibrational mode energies (in ergs) sorted in order of increasing energy.
2. Computing Custom Basis Spectra
Once defined, the above functions can be passed to the pah_spec.PahSpec API to compute a set of custom basis spectra. This can be done follows:
ps = pah_spec.PahSpec(c_abs_func=custom_c_abs_func, pah_energy_func=custom_pah_energy_func)
ps.generate_basis_spectra(ps.grain_sizes, ps.emission_wavelengths, ion=True, pah_mode_energy_func=custom_pah_mode_energy_func)
ps.generate_basis_spectra(ps.grain_sizes, ps.emission_wavelengths, ion=False, pah_mode_energy_func=custom_pah_mode_energy_func)
The operative step is the specification of the c_abs_func and pah_energy_func arguments in defining the the pah_spec.PahSpec and the pah_mode_energy_func argument in pah_spec.PahSpec.generate_basis_spectra(). See our Examples for instructions on using pah_spec.PahSpec.generate_basis_spectra().
Once this function finishes running (it will take several hours to run), new basis_ion.h5 and basis_neu.h5 data files will be generated.
3. Generating PAH Spectra With Custom PAH Physics
Once the new basis_ion.h5 and basis_neu.h5 data files have been created, they can be used to generate PAH spectra. To do this, you must define a new pah_spec.PahSpec object using the new basis spectra. This can be done by specifying their location with the basis_dir argument when deifning the new pah_spec.PahSpec object:
ps = pah_spec.PahSpec(c_abs_func=custom_c_abs_func, pah_energy_func=custom_pah_energy_func, basis_dir="/path/to/custom/basis/spectra")
Note that you MUST use the same energy and/or cross-section functions used to compute the basis spectra when defining the new pah_spec.PahSpec object.
After this step, you can use pah_spec.PahSpec.generate_spectrum() to compute PAH spectra using your own PAH physics!