# Py4CAtS—PYthon for Computational ATmospheric Spectroscopy

^{*}

^{†}

*Keywords:*infrared; radiative transfer; molecular absorption; line-by-line

Next Article in Journal

Next Article in Special Issue

Next Article in Special Issue

Previous Article in Journal

Previous Article in Special Issue

Previous Article in Special Issue

Deutsches Zentrum für Luft- und Raumfahrt (DLR), Institut für Methodik der Fernerkundung (IMF), 82234 Oberpfaffenhofen, Germany

Author to whom correspondence should be addressed.

Current address: EUMETSAT, 64283 Darmstadt, Germany.

Received: 5 April 2019
/
Revised: 3 May 2019
/
Accepted: 6 May 2019
/
Published: 10 May 2019

(This article belongs to the Special Issue Radiative Transfer Models of Atmospheric and Cloud Properties)

Radiation is a key process in the atmosphere. Numerous radiative transfer codes have been developed spanning a large range of wavelengths, complexities, speeds, and accuracies. In the infrared and microwave, line-by-line codes are crucial esp. for modeling and analyzing high-resolution spectroscopic observations. Here we present Py4CAtS—PYthon scripts for Computational ATmospheric Spectroscopy, a Python re-implemen-tation of the Fortran Generic Atmospheric Radiation Line-by-line Code GARLIC, where computationally-intensive code sections use the Numeric/Scientific Python modules for highly optimized array processing. The individual steps of an infrared or microwave radiative transfer computation are implemented in separate scripts (and corresponding functions) to extract lines of relevant molecules in the spectral range of interest, to compute line-by-line cross sections for given pressure(s) and temperature(s), to combine cross sections to absorption coefficients and optical depths, and to integrate along the line-of-sight to transmission and radiance/intensity. Py4CAtS can be used in three ways: in the (Unix/Windows/Mac) console/terminal, inside the (I)Python interpreter, or Jupyter notebook. The basic design of the package, numerical and computational aspects relevant for optimization, and a sketch of the typical workflow are presented. In conclusion, Py4CAtS provides a versatile environment for “interactive” (and batch) line-by-line radiative transfer modeling.

Radiative transfer is an important aspect in various branches of physics, esp. in the atmospheric sciences, both for Earth and (exo-)planets [1,2,3]. Many radiative transfer models have been developed in recent decades (see [4], for an early review and https://en.wikipedia.org/wiki/Atmospheric_radiative_transfer_codes for an up-to-date listing (All links in this paper were checked and active 4 April 2019.)), ranging from simple approximations to complex, often highly optimized codes and usually tailored to a specific spectral domain.

An essential prerequisite for the analysis of data recorded by atmospheric remote sensing instruments as well as for theoretical investigations such as retrieval assessments is a flexible, yet efficient and reliable radiative transfer model (RTM). Furthermore, as the retrieval of atmospheric parameters is in general a nonlinear optimization problem (inverse problem), the retrieval code must be closely connected to the radiative transfer code (forward model).

Radiative transfer depends on the state of the atmosphere (pressure, temperature, composition), the optical properties of the atmospheric constituents (molecules and particles), geometry, and spectral range. Because of the numerous parameters the setup of a radiative transfer calculation can be cumbersome and error prone, and several interfaces have been developed to ease the application. MODO ([5], see also http://www.rese.ch/products/modo/) is a “graphical front-end” to the MODTRAN [6] radiative transfer code, and a Python interface to MODTRAN’s predecessor, the low-resolution band model LOWTRAN, is available at https://pypi.org/project/lowtran/. Wilson [7], see also http://www.py6s.rtwilson.com/, has developed a Python interface to the widely used 6S (Second Simulation of the Satellite Signal in the Solar Spectrum, [8]) model.

In the infrared and microwave region, line-by-line (lbl) modeling of molecular absorption is mandatory esp. for high spectral resolution. Furthermore, lbl models are required for the setup and verification of fast parameterized models, e.g., band, k-distribution, or exponential sum fitting models [6,9,10]. Moreover, lbl models are ideal for radiative transfer in planetary atmospheres, where fast models often parameterized for Earth-like conditions are not suitable [11,12].

An essential input for lbl radiative transfer codes are the molecules’ optical properties compiled in databases such as HITRAN [13], HITEMP [14], GEISA [15], the JPL and CDMS catalogs [16,17,18], or ExoMol [19] that list line parameters (center frequency, line strength, broadening parameters etc.) for millions to billions of lines of some dozen molecules. Lbl models are computationally challenging because of the large number of spectral lines to be considered and the large number of wavenumber grid points required for adequate sampling. Nevertheless, lbl models are available for almost half a century, e.g., FASCODE or 4A (Fast Atmospheric Signature Code, Automatized Atmospheric Absorption Atlas, [20,21]). Thanks to the increased computational power (and because of the increased number of high-resolution Earth and planetary spectra) a variety of codes has been developed since these early efforts, e.g., ARTS (Atmospheric Radiative Transfer Simulator, [22,23,24]), GARLIC (Generic Atmospheric Radiation Line-by-line Code, [25]), GenLN2 [26], KOPRA (Karlsruhe Optimized & Precise Radiative transfer Algorithm, [27]), LblRTM (Line-by-line Radiative Transfer Model, [28]), LinePak [29], RFM (Reference Forward Model, [30]), $\sigma $-IASI [31], and VSTAR (Versatile Software for Transfer of Atmospheric Radiation, [32]).

Several web sites offer an Internet access to lbl databases and/or lbl models: “HITRANonline” [33] at http://hitran.org/ allows the downloading of line and other data from the most recent HITRAN version. With the “Information System HITRAN on the Web (HotW)” at http://hitran.tsu.ru (see also http://spectra.iao.ru/) several types of spectra can be simulated using HITRAN data. The HITRAN Application Programming Interface (HAPI) [34] is “a set of routines in Python which aims to provide remote access to functionality and data given by the HITRANonline”. A similar service (visualization etc.) for the GEISA database is offered at https://cds-espri.ipsl.upmc.fr/geisa/. The “wavelength search engine” SpectraPlot ([35], see also http://www.spectraplot.com/) is a “web-based application for simulating spectra of atomic and molecular gases” employing, among others, HITRAN and HITEMP. http://www.spectralcalc.com/ provides a web interface to the widely used LinePak [29] model (with extended functionality for subscribed users). Goddard’s Planetary Spectrum Generator (PSG, https://psg.gsfc.nasa.gov/, Villanueva et al. [36]) can be used to generate high-resolution spectra of planetary bodies (e.g., planets, moons, comets, exoplanets). Knowledge of the atmospheric transmission is also important for ground-based astronomy observations, and some tools for the correction of telluric absorption are available, e.g., MolecFit ([37], see also https://www.uibk.ac.at/eso/software/molecfit.html.en) and TAPAS (Transmissions Atmosphériques Personnalisées Pour l’AStronomie, [38], online at http://cds-espri.ipsl.fr/tapas/) (both codes use LblRTM). An early attempt to a “virtual lab” providing a web interface to MIRART (the Fortran 77 predecessor of GARLIC, [39]) and FASCODE is described in Ernst et al. [40].

In general, RTMs incl. lbl models work as a kind of “black-box”. Given a set of specifications on spectral range, atmospheric conditions, geometry etc. compiled in an input file (or configuration file etc., e.g., the `TAPE5` used by LOWTRAN, MODTRAN, and FASCODE), the program is executed reading this input file (and probably some further auxiliary files, e.g., the lbl database) and one or several spectra (transmission, radiance, …) are returned (e.g., saved in file(s)). This approach is clearly advantageous when numerous transmission and/or radiance spectra must be generated, e.g., for the operational analysis of thousands or millions of observed spectra. However, to better understand the physics of radiative transfer, inspection of intermediate variables can provide useful insight. For example, the selection of an appropriate spectral range or measurement geometry is crucial for the design and setup of a new measurement system, and analysis and visualization of line parameters, absorption cross sections and coefficients, layer optical depths, etc. can be useful. Methods and tools have been developed for the “automated” definition of “microwindows”, i.e., spectral intervals optimized for retrieval of temperature or molecular concentrations from thermal emission infrared observations (e.g., [41,42,43,44,45,46]). Despite these and similar efforts interactive and flexible RTMs with an easy access to all kind of intermediate variables (“step-by-step”, similar to a debugger) appear to be useful, also for pedagogical purposes.

Py4CAtS—Python for Computational Atmospheric Spectroscopy—has been developed with this intention. Since its first release in the mid-1990s [47,48] Python has become increasingly popular for scientific computing [49,50]. Thanks to its numerous extension packages, in particular NumPy/SciPy [51], the “Python-based ecosystem” ([52], https://scipy.org/) is widely considered to be the language of choice in many areas, e.g., atmospheric science and astrophysics [53,54,55].

Originally, the development of Py4CAtS was motivated by the idea of computational steering [56], i.e., numerically time-consuming tasks such as the lbl evaluation of molecular absorption cross sections are performed by a code (e.g., GARLIC subroutines) written in compiled languages such as Fortran (or C, C++, …) that is made accessible from Python (or another scripting language) using a wrapper such as PyFort [57] or F2Py [58]. More precisely, the intention was to call subroutines of GARLIC from Python. Unfortunately porting the wrapper code from one machine to another turned out to be difficult and time-consuming with early versions of PyFort. However, thanks to the increased performance of NumPy a Python implementation of lbl cross sections became feasible, i.e., the interface to GARLIC’s subroutines became less important. Accordingly, the further development of GARLIC and Py4CAtS became largely independent, and Py4CAtS is now a full lbl radiative transfer tool kit delivering absorption cross sections and coefficients, optical depths, transmissions, weighting functions, and radiances.

The paper is organized as follows: After a brief review of the basic facts of lbl infrared and microwave (for brevity simply IR in the following) radiative transfer in the following section some numerical and implementation aspects are discussed in Section 2.2. Usage of the code as well as some implementation details are presented in Section 3. The paper continues with a discussion of several aspects in Section 4 before the final conclusion in Section 5. Implementation aspects are described in the Appendix A.

Radiative transfer in the IR is essentially described by the Schwarzschild equation and Beer-Lambert law (assuming negligible scattering and local thermal equilibrium in an inhomogeneous atmosphere [1,2,3]). Given pressure p and temperature T and line parameters from HITRAN, GEISA, etc. the first step of a simulation is to compute the absorption cross section (xs) for a particular molecule m
where $\nu $ is the wavenumber and the sum comprises all relevant lines characterized by position ${\widehat{\nu}}_{ml}$, strength ${S}_{ml}$, and broadening parameter ${\gamma}_{ml}$. The line strength $S\left(T\right)$ at temperature T is obtained as (note that indices for lines and molecules have been omitted)
with reference strength $S\left({T}_{0}\right)$ and lower state energy ${E}_{\mathrm{i}}$ from the database; $Q\left(T\right)$ is the product of rotational and vibrational partition functions (for details see [25], subsection 3.4 or [59]) and c, h, and ${k}_{\mathrm{B}}$ are speed of light, the Planck constant, and the Boltzmann constant, respectively. The combined effect of pressure broadening (corresponding to a Lorentzian profile ${g}_{\mathrm{L}}$) and Doppler broadening (corresponding to a Gaussian profile ${g}_{\mathrm{G}}$) is described by a convolution resulting in the Voigt line profile [60]

$${k}_{m}(\nu ,p,T)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}\sum _{l}{S}_{ml}\left(T\right)\phantom{\rule{0.222222em}{0ex}}g(\nu ;\phantom{\rule{0.166667em}{0ex}}{\widehat{\nu}}_{ml},{\gamma}_{ml}(p,T))\phantom{\rule{3.33333pt}{0ex}}.$$

$$S\left(T\right)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}S\left({T}_{0}\right)\phantom{\rule{0.222222em}{0ex}}\frac{Q\left({T}_{0}\right)}{Q\left(T\right)}\phantom{\rule{3.33333pt}{0ex}}\frac{exp(-{E}_{\mathrm{i}}/{k}_{\mathrm{B}}T)}{exp(-{E}_{\mathrm{i}}/{k}_{\mathrm{B}}{T}_{0})}\phantom{\rule{3.33333pt}{0ex}}\frac{1\phantom{\rule{0.166667em}{0ex}}-\phantom{\rule{0.166667em}{0ex}}exp(-hc\widehat{\nu}/{k}_{\mathrm{B}}T)}{1\phantom{\rule{0.166667em}{0ex}}-\phantom{\rule{0.166667em}{0ex}}exp(-hc\widehat{\nu}/{k}_{\mathrm{B}}{T}_{0})}.$$

$${g}_{\mathrm{V}}(\nu -\widehat{\nu},{\gamma}_{\mathrm{L}},{\gamma}_{\mathrm{G}})\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}{g}_{\mathrm{L}}\otimes {g}_{\mathrm{G}}\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}{\int}_{-\infty}^{\infty}\mathrm{d}{\nu}^{\prime}\phantom{\rule{0.277778em}{0ex}}{g}_{\mathrm{L}}(\nu -{\nu}^{\prime},{\gamma}_{\mathrm{L}})\phantom{\rule{0.166667em}{0ex}}\times \phantom{\rule{0.166667em}{0ex}}{g}_{\mathrm{G}}({\nu}^{\prime}-\widehat{\nu},{\gamma}_{\mathrm{G}})\phantom{\rule{3.33333pt}{0ex}}.$$

The Lorentz and Gauss half widths $\gamma $ (at half maximum, HWHM) are pressure- and temperature- dependent,
where the air-broadening coefficient ${\gamma}_{\mathrm{L}}^{0}$ and exponent n are given in the database for reference pressure ${p}_{0}$ and temperature ${T}_{0}$, and $\mu $ is the molecular mass. Please note that contributions to the Lorentzian width (4) due to self-broadening have been ignored: Except for water at Earth’s bottom of atmosphere (BoA), molecular mixing ratios are usually very small, and the self-broadening contribution would be small to negligible. Moreover, the self-broadening coefficient is often close to the foreign broadening coefficient (or even undefined, at least for older versions of HITRAN and GEISA). Clearly, for planetary atmospheres (e.g., Mars or Venus) self-broadening can be an important issue.

$$\begin{array}{cc}\hfill {\gamma}_{\mathrm{L}}\phantom{\rule{3.33333pt}{0ex}}& =\phantom{\rule{3.33333pt}{0ex}}{\gamma}_{\mathrm{L}}^{0}\phantom{\rule{0.166667em}{0ex}}\frac{p}{{p}_{0}}\phantom{\rule{0.166667em}{0ex}}{\left(\frac{{T}_{0}}{T}\right)}^{n}\hfill \end{array}$$

$$\begin{array}{cc}\hfill {\gamma}_{\mathrm{G}}\phantom{\rule{3.33333pt}{0ex}}& =\phantom{\rule{3.33333pt}{0ex}}\widehat{\nu}\sqrt{\frac{2ln2\phantom{\rule{0.166667em}{0ex}}{k}_{\mathrm{B}}T}{\mu {c}^{2}}}\hfill \end{array}$$

The increasing quality of spectroscopic observations has indicated deficiencies of the Voigt profile, and several more advanced profiles have been suggested [61,62]. In addition to the Lorentz, Gauss, and Voigt profile, implementations of the Rautian and speed-dependent Voigt profile [63] are available.

The absorption coefficient (ac) is defined as the sum of all molecular cross sections scaled by the molecular number densities ${n}_{m}$ (in general depending on altitude z and the corresponding pressure)

$$\alpha (\nu ,z,p,T)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}\sum _{m}{n}_{m}\left(z\right)\phantom{\rule{0.166667em}{0ex}}{k}_{m}(\nu ,p\left(z\right),T\left(z\right))\phantom{\rule{3.33333pt}{0ex}}.$$

Integration of the absorption coefficient along the line-of-sight gives the optical depth (od), i.e., for a plane-parallel atmosphere and a vertical path from altitude ${z}_{\mathrm{lo}}$ to ${z}_{\mathrm{hi}}$

$$\tau \left(\nu \right)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}{\int}_{{z}_{\mathrm{lo}}}^{{z}_{\mathrm{hi}}}\alpha (\nu ,z,p,T)\phantom{\rule{0.166667em}{0ex}}\mathrm{d}z\phantom{\rule{3.33333pt}{0ex}}.$$

This is closely related to the monochromatic transmission describing the ratio of incoming and outgoing radiation

$$\mathcal{T}\left(\nu \right)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}exp(-\tau (\nu \left)\right)\phantom{\rule{3.33333pt}{0ex}}.$$

Finally, the integral form of Schwarzschild’s equation gives the (spectral) radiance or intensity (ri)
where the first term describes an attenuated background contribution ${I}_{\mathrm{b}}$ at a distance ${s}_{\mathrm{b}}$ from the observer (corresponding to the optical depth ${\tau}_{\mathrm{b}}$), e.g., from Earth’s (or a planet’s) surface in case of nadir-viewing. The source function in the second term is Planck’s function depending on temperature,

$$\begin{array}{cc}\hfill I\left(\nu \right)\phantom{\rule{3.33333pt}{0ex}}& =\phantom{\rule{3.33333pt}{0ex}}{I}_{\mathrm{b}}\left(\nu \right)\phantom{\rule{0.166667em}{0ex}}{\mathrm{e}}^{-{\tau}_{\mathrm{b}}\left(\nu \right)}\phantom{\rule{0.277778em}{0ex}}+\phantom{\rule{0.277778em}{0ex}}\underset{0}{\overset{{\tau}_{\mathrm{b}}}{\int}}B(\nu ,T\left({\tau}^{\prime}\right))\phantom{\rule{0.277778em}{0ex}}{\mathrm{e}}^{-{\tau}^{\prime}}\phantom{\rule{0.222222em}{0ex}}\mathrm{d}{\tau}^{\prime}\hfill \end{array}$$

$$\begin{array}{cc}\hfill \phantom{\rule{3.33333pt}{0ex}}& =\phantom{\rule{3.33333pt}{0ex}}{I}_{\mathrm{b}}\left(\nu \right)\phantom{\rule{0.166667em}{0ex}}{\mathrm{e}}^{-{\tau}_{\mathrm{b}}\left(\nu \right)}\phantom{\rule{0.277778em}{0ex}}-\phantom{\rule{0.277778em}{0ex}}\underset{0}{\overset{{s}_{\mathrm{b}}}{\int}}B(\nu ,T\left({s}^{\prime}\right))\phantom{\rule{0.277778em}{0ex}}\frac{\partial \mathcal{T}}{\partial {s}^{\prime}}\phantom{\rule{0.222222em}{0ex}}\mathrm{d}{s}^{\prime}\hfill \end{array}$$

$$B(\nu ,T)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}\frac{2h{c}^{2}{\nu}^{3}}{exp(hc\nu /{k}_{\mathrm{B}}T)-1}\phantom{\rule{3.33333pt}{0ex}}.$$

The finite spectral resolution of measured spectra can be modeled by convolution of the monochromatic transmission (8) and/or radiance (9) with an appropriate spectral response function (SRF, a.k.a. instrument line shape, ILS), e.g.,

$$\tilde{I}=I\otimes \mathrm{SRF}\phantom{\rule{3.33333pt}{0ex}}.$$

Weighting functions (wf) are an important concept for atmospheric temperature sounding and are a measure of the contribution of a particular atmospheric layer to the radiation seen by an observer, see Equation (10). They are defined by $\frac{\partial \mathcal{T}}{\partial z}$ for a vertical path, or more generally
for a slant path with $s=z/cos\theta $ and zenith angle $\theta $ (with $\theta =0$ and $\theta ={180}^{\circ}$ for vertical uplooking and downlooking, respectively).

$$\frac{\partial \mathcal{T}(\nu ,s)}{\partial s}\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}-\mathcal{T}(\nu ,s)\phantom{\rule{0.166667em}{0ex}}\alpha (\nu ,s)$$

For the computation of the Voigt profile ${g}_{\mathrm{V}}$ (3) depending on three variables it is convenient to introduce the Voigt function $K(x,y)$ depending on two variables, essentially the distance x to the center peak and the ratio y of the line widths
with $x\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}\sqrt{ln2}\phantom{\rule{3.33333pt}{0ex}}(\nu -\widehat{\nu})/{\gamma}_{\mathrm{G}}$ and $y\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}\sqrt{ln2}\phantom{\rule{3.33333pt}{0ex}}{\gamma}_{\mathrm{L}}/{\gamma}_{\mathrm{G}}$. As there is no closed-form solution for this convolution integral, numerical approximations are mandatory. Most modern algorithms consider the complex error function [64,65] whose real part is identical to the Voigt function

$$\begin{array}{cc}\hfill {g}_{\mathrm{V}}(\nu -\widehat{\nu},{\gamma}_{\mathrm{L}},{\gamma}_{\mathrm{G}})\phantom{\rule{3.33333pt}{0ex}}& =\phantom{\rule{3.33333pt}{0ex}}\frac{\sqrt{ln2/\pi}}{{\gamma}_{\mathrm{G}}}\phantom{\rule{3.33333pt}{0ex}}K(x,y)\hfill \end{array}$$

$$\begin{array}{cc}\hfill K(x,y)\phantom{\rule{3.33333pt}{0ex}}& =\frac{y}{\pi}\phantom{\rule{3.33333pt}{0ex}}\underset{-\infty}{\overset{\infty}{\int}}\frac{{e}^{-{t}^{2}}}{{(x-t)}^{2}+{y}^{2}}\phantom{\rule{3.33333pt}{0ex}}\mathrm{d}t\hfill \end{array}$$

$$w\left(z\right)\phantom{\rule{3.33333pt}{0ex}}\equiv \phantom{\rule{3.33333pt}{0ex}}K(x,y)\phantom{\rule{0.166667em}{0ex}}+\phantom{\rule{0.166667em}{0ex}}\mathrm{i}L(x,y)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}\frac{\mathrm{i}}{\pi}\phantom{\rule{3.33333pt}{0ex}}{\int}_{-\infty}^{\infty}\phantom{\rule{3.33333pt}{0ex}}\frac{{e}^{-{t}^{2}}}{z-t}\phantom{\rule{3.33333pt}{0ex}}\mathrm{d}t\phantom{\rule{2.em}{0ex}}\mathrm{with}\phantom{\rule{1.em}{0ex}}z=x+\mathrm{i}y\phantom{\rule{3.33333pt}{0ex}}.$$

Rational approximations, closely related to continued fractions and defined as the quotient of two polynomials [66,67], have been used successfully for a large variety of functions including the complex error function (e.g., [68,69,70]). Py4CAtS (like GARLIC) uses an optimized combination [71] of the Humlíček [69] and Weideman [70] algorithms
where $Z=\frac{L+\mathrm{i}z}{L-\mathrm{i}z}$ and $L\phantom{\rule{0.166667em}{0ex}}=\phantom{\rule{0.166667em}{0ex}}{2}^{-1/4}{N}^{1/2}$. For $N=24$ this provides an accuracy better than ${10}^{-4}$ everywhere except for very small y and intermediate x that are hardly relevant in practice; for $N=32$ the relative error $|\Delta K|/K$ is less than $8\times {10}^{-5}$ for all $x,y$ of interest.

$$w\left(z\right)\phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}\left\{\begin{array}{cc}\frac{\mathrm{i}z/\sqrt{\pi}}{{z}^{2}-\frac{1}{2}}\hfill & \left|x\right|+y>15\hfill \\ \frac{{\pi}^{-1/2}}{L-\mathrm{i}z}\phantom{\rule{3.33333pt}{0ex}}+\phantom{\rule{3.33333pt}{0ex}}\frac{2}{{(L-\mathrm{i}z)}^{2}}{\displaystyle \sum _{n=0}^{N-1}}{a}_{n+1}{Z}^{n}\phantom{\rule{2.em}{0ex}}\hfill & \mathrm{otherwise}\hfill \end{array}\right.$$

Because of the huge number of Voigt function evaluations even highly optimized complex error function algorithms are insufficient and further optimizations are mandatory. Py4CAtS evaluates the monochromatic cross sections on a uniform (equidistant) wavenumber grid with the spacing estimated as a fraction of the “typical” line widths, i.e., $\delta \nu =\langle \gamma \rangle /n$ with the mean half width $\langle \gamma \rangle $ and a default sampling rate $n=4$. In case of the Voigt line profile (3), its width is estimated using an approximation due to Whiting [72] (accurate to about one percent)

$$\begin{array}{cc}{\gamma}_{\mathrm{V}}& \approx \phantom{\rule{3.33333pt}{0ex}}\frac{1}{2}\left({\gamma}_{\mathrm{L}}+\sqrt{{\gamma}_{\mathrm{L}}^{2}+4{\gamma}_{\mathrm{G}}^{2}}\right).\end{array}$$

Please note that $\delta \nu $ and hence the number of grid points and cross section values are dependent on pressure, temperature, and molecular mass (via Equations (4), (5), and (18)), and change with atmospheric level and molecule. These wavenumber steps are clearly appropriate in the line center region; however, in the line wings the profiles are relatively smooth (roughly $g(\nu -\widehat{\nu})\approx 1/{(\nu -\widehat{\nu})}^{2}$ for the Lorentz or Voigt profile) and a coarser grid would be sufficient.

Py4CAtS uses a two- or three-grid approach [73]. In the two-grid scheme, the Voigt line profile is calculated on the fine grid only in the line center region, and on a coarse grid (typically with spacing $\Delta \nu =8\delta \nu $) in the entire spectral region. The line profiles are accumulated independently to the fine and coarse grid cross sections, i.e., the interpolation of the coarse grid cross section is done only once after all lines have been summed up. This allows a speed-up roughly in the order of the ratio of fine and coarse grid points. A significant further speed-up can be achieved with three grids of fine, medium, and coarse resolution and exploitation of the asymptotic properties of the profile function.

From the very beginning of the code development (MIRART, GARLIC, and Py4CAtS) numerical schemes have been used whenever possible. Hence, in contrast to most lbl radiative transfer codes dividing the atmosphere into a series of layers with constant pressure, temperature, and concentrations (Curtis-Godson approximation), Py4CAtS and GARLIC are level-based and exploit numerical quadrature for Equations (7) and (9). In particular, the optical depth is approximated by the sum of absorption coefficients according to the trapezoid rule (e.g., [66]). For the Schwarzschild equation (9) both codes use optical depth $\tau $ as integration variable and assume that the Planck function varies linearly or exponentially with optical depth within a layer,
for ${\tau}_{l}\le \tau \le {\tau}_{l+1}$ (corresponding to the altitude interval $[{z}_{l},{z}_{l+1}]$). Note the slightly different notation for the Planck function’s argument here compared to Equation (11) (the optical depth depends on wavenumber and temperature). With both approximations the integral (9) can be computed analytically within a layer.

$$\begin{array}{ccc}\hfill B\left(\tau \right)& \phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}{b}_{0}B\left({\tau}_{l}\right)+{b}_{1}B\left({\tau}_{l+1}\right)\hfill & \phantom{\rule{2.em}{0ex}}\mathrm{with}\phantom{\rule{4.pt}{0ex}}{b}_{0}=\frac{{\tau}_{l+1}-\tau}{{\tau}_{l+1}-{\tau}_{l}}\phantom{\rule{4.pt}{0ex}}\mathrm{and}\phantom{\rule{4.pt}{0ex}}{b}_{1}=\frac{\tau -{\tau}_{l}}{{\tau}_{l+1}-{\tau}_{l}}\hfill \end{array}$$

$$\begin{array}{ccc}\hfill B\left(\tau \right)& \phantom{\rule{3.33333pt}{0ex}}=\phantom{\rule{3.33333pt}{0ex}}B\left({\tau}_{l}\right)\phantom{\rule{0.166667em}{0ex}}{\mathrm{e}}^{\beta (\tau -{\tau}_{l})}\hfill & \phantom{\rule{2.em}{0ex}}\mathrm{with}\phantom{\rule{4.pt}{0ex}}\beta =log(B\left({\tau}_{l}\right)/B\left({\tau}_{l+1}\right))/({\tau}_{l+1}-{\tau}_{l})\hfill \end{array}$$

Because the overall runtime is essentially determined by the evaluation of the cross sections, the speed of level-based and layer-based radiative transfer is equivalent (assuming that the number of levels and layers is comparable). With respect to accuracy, none of the two approaches is superior or inferior; in fact, neither of the intercomparison studies [74,75,76] identified path integration as an issue. For an in-depth discussion of the “linear-in-$\tau $” vs. “exponential-in-$\tau $” approximations as well as some further quadrature schemes see subsection 4.1 of the GARLIC paper [25].

In Py4CAtS the individual steps of an IR radiative transfer computation are implemented in a series of modules and functions, see Figure 1:

`higstract`: extract (select) lines of relevant molecules in the spectral range of interest;`lbl2xs`: compute lbl cross sections for given pressure(s) and temperature(s): Equation (1);`xs2ac`: multiply cross sections with number densities and sum over all molecules: Equation (6);`ac2od`: integrate absorption coefficients along the line-of-sight through the atmosphere to the vertical optical depth (7);

All Python source files along with supplementary files are delivered as a single tarball. Unpacking this file will create four directories with the source files in `src`, data in `data`, documentation in `doc`, and executable scripts in `bin`. Actually, the files in the `bin` directory are just links to the scripts in the `src` directory (e.g., `bin/lbl2xs` is a link to `src/lbl2xs.py`), and in the following subsection it is assumed that the `bin` directory is included in the shell’s search path for executables (`PATH` environment variable for Unix-like systems). When Py4CAtS is used inside the IPython interpreter (see Section 3.2), all functions etc. should have been imported using a statement such as `%run /home/schreier/py4cats/src/py4cats.py`. Importing Py4CAtS can be easily done automatically by an appropriate modification of the (I)Python configuration file, e.g., by adding this file to the list of files to run at IPython startup. (In IPython 6 this list is defined by `c.InteractiveShellApp.exec_files` in `.ipython/profile_default/iypthon_config.py`.)

A typical session in a Unix/Linux environment (console/terminal) is shown in Figure 2. After creating a new directory, the first step is to extract the relevant lines from the HITRAN or GEISA data base using `higstract`. (Data are available at hitran.org and http://cds-espri.ipsl.upmc.fr/. Py4CAtS can read the original data file as is, i.e., the 160-byte fixed-width format used since HITRAN 2004 or the 100-byte format of the older HITRAN versions. Regarding GEISA, the format of a single record (corresponding to a “physical line”) has changed slightly from version to version, and Py4CAtS parses the file name to select the appropriate reader.) Please note that for this command at least one option is mandatory, i.e., the spectral range (here 50 to $60\phantom{\rule{0.166667em}{0ex}}{\mathrm{cm}}^{-1}$) or a molecule must be specified (for convenience, `higstract -m main …` can be used to extract line data for the first seven molecules (${\mathrm{H}}_{2}\mathrm{O}$, ${\mathrm{CO}}_{2}$, …, ${\mathrm{O}}_{2}$) of HITRAN or GEISA.) `higstract` saves the data in several tabular ASCII files, one file per molecule. By default, each file has five columns for line position $\widehat{\nu}$, strengths S, energy E, air-broadening parameter ${\gamma}_{\mathrm{L}}^{0}$, and the exponent n and is named as `H2O.vSEan` etc., where the extension indicates the columns (further parameters, e.g., for self-broadening, can be requested with the format option `-f`).

The next step is to compute absorption cross sections according to Equation (1). Without any option, cross sections are computed for the reference pressure and temperature used in the line parameter database, i.e., ${p}_{0}=1013.25\phantom{\rule{0.166667em}{0ex}}\mathrm{mb}$ and ${T}_{0}=296\phantom{\rule{0.166667em}{0ex}}\mathrm{K}$ for HITRAN and GEISA. Alternatively, pressure(s) and temperature(s) can be specified with the `-p` and `-T` option. For atmospheric applications it is more convenient to read the data from a file (e.g., “midlatitude summer” (mls) data assuming the first three column list altitudes, pressure, and temperature). Again, the cross sections will be saved in files, one per molecule, using NumPy’s pickle format or alternatively ASCII tabular or HITRAN formatted files.

The computation continues to absorption coefficients by summing all cross sections (level-by-level) scaled with the molecular concentrations, cf. Equation (6), and integrating these to the layer (or delta) optical depth, Equation (7). Finally, the radiance seen by an observer at ground and by a spaceborne observer (actually an observer at top of atmosphere, ToA) is computed.

In each step of the calculation the results are written to file(s), and read in for the next step. Obviously, this can be quite time-consuming esp. for ASCII files (reading NumPy pickled files is surprisingly fast). In particular, the cross section files can be very large (depending on the spectral region, the size of the spectral interval, the number of molecules, and atmospheric levels, etc.). For many applications some of the intermediate quantities are not of interest, and the file transfer operations can be omitted, e.g., (see the dashed arrows in Figure 2)

`lbl2ac`compute lbl cross sections and combine to absorption coefficients;`lbl2od`compute lbl cross sections and absorption coefficients, then integrate to optical depth.`xs2od`multiply cross sections with densities, sum over molecules, and integrate to optical depth.

In addition to these scripts there are several further Python files that contain functions used by these “main” scripts (e.g., to read or write the data), but can also be executed stand-alone. (Technically, the very first line of all executable scripts is something like `#!/usr/bin/env python` and the last segment of the module starts with `if __name__==’__main__’:`.) The scripts `lines.py`, `xSection.py`, `absCo.py`, `oDepth.py` can be used to read, extract subsets in the spectral or altitude regime, summarize, plot, or reformat the respective data. `molecules.py` collects properties (e.g., mass) of the IR relevant molecules and the ID numbers used in the HITRAN and GEISA database. `atmos1D.py` is useful to handle the atmospheric data (p, T, VMRs, …). The functions in `hitran.py` and `geisa.py` are used by `higstract.py`, but can be used as a “low-level” interface to the respective dataset. Unit conversions are implemented in the `cgsUnit.py` module (note that internally Py4CAtS uses cgs units consistently, see Appendix A.6). Furthermore, `radiance2radiance.py` and `radiance2Kelvin.py` allow the conversion of radiance spectra, e.g., wavenumber ⟷ wavelength or to equivalent brightness temperature using the inverse of Planck’s function (11).

The `lbl2ac`, `lbl2od`, or `xs2od` scripts clearly help to avoid the time-consuming reading and writing of some of the intermediate quantities, however, these scripts turn Py4CAtS back into the “black-box” radiative transfer discussed above.

When executing the series of individual steps, the subsequent steps must re-read the data saved in the previous step(s) from file(s) and check the consistency of the data. For example, the `xs2ac.py` script will test if all cross sections cover the same spectral interval, and if the pressures and temperatures match those in the atmospheric data file. Accordingly, a substantial part of the code is devoted to implement appropriate tests. A prerequisite for these tests is that all relevant attributes are saved in the file along with the spectra; for example, a single cross section is saved along with its pressure, temperature, and wavenumber grid specification.

Access to intermediate quantities is especially useful for visualization. In the (I)Python interpreter, graphics packages such as Matplotlib [77] allow the plotting of any kind of array. For plotting as well as for the subsequent processing steps it is important to have all attributes of a spectrum available. However, a function returning an array for the spectrum together with its attributes (e.g., with a call such as `lines_h2o, pRef, tRef = higstract(’/data/hitran/86/lines’, ’H2O’)`) would be cumbersome, and collecting the return values in a dictionary would not significantly improve this. In Py4CAtS this problem is solved by means of subclassed and/or structured NumPy arrays that will be briefly described (in Appendices Appendix A.4 and Appendix A.5) after a presentation of the typical workflow illustrated in Figure 3.

Knowledge of the atmospheric state, i.e., pressure, temperature, and molecular composition as a function of altitude, is indispensable for lbl modeling and radiative transfer. The Py4CAtS scripts called from the console automatically read these data from a file (along with the line data, cross section data, etc.) This is essentially accomplished by the function `atmRead` of the `atmos1D.py` module, e.g., the command `mls = atmRead(’/data/atmos/20/mls.xy’)` returns the data of the “midlatitude summer” atmosphere of the AFGL dataset [78] regridded to 20 levels (see the very first input labelled `In[1]:` in Figure 3). `atmRead` essentially expects a tabular ascii file with rows corresponding to the atmospheric levels and columns for altitudes, pressure (and/or air density), temperature, and molecular concentrations. Two comment lines are mandatory: `#what:` followed by the column identifiers and `#units:` followed by the physical units (e.g., “km”).

All data are stored internally in cgs units, e.g., pressure is converted to $\mathrm{dyn}/{\mathrm{cm}}^{2}=\mathrm{g}/\mathrm{cm}/{\mathrm{s}}^{2}$. Molecular concentrations are stored as number densities (i.e., if the data file contains volume mixing ratios (VMR), these are converted to densities by multiplication with the air number density $n=p/\left(kT\right)$). VMR can be obtained with the `vmr` function, e.g., `vmr(mls)`. Further convenience functions of the `atmos1D.py` module include `vcd` to integrate the (molecular and air) number densities along a vertical path through the atmosphere to the “Vertical Column Density” ($N=\int n\left(z\right)\phantom{\rule{0.166667em}{0ex}}\mathrm{d}z$ with default limits given by top and bottom of atmosphere, ${z}_{\mathrm{ToA}}$ and ${z}_{\mathrm{BoA}}$), `cmr` for the “Column Mixing Ratio”, i.e., the ratio of the molecular VCDs and the air VCD.

The `atmRegrid (mls, zNew, …)` function allows interpolation of the atmospheric data to a new altitude grid. If the limits of the new grid exceed the old limits, `atmRegrid` prints a warning. The actual results are depending on the chosen interpolation scheme; in case of the default linear interpolation NumPy’s `interp` function simply repeats the very first or last value at BoA or ToA, respectively.

Data from different files can be combined with the `atmMerge` function, e.g.,

The data can be easily visualized using the standard Matplotlib [77] functions (e.g., `plot(mls[’T’],mls[’z’])`), but for convenience Py4CAtS provides a function `atmPlot` that expects a single structured array or a list thereof as first argument. (For some general remarks on visualization see Appendix A.2.) For example, `atmPlot(mls)` shows temperature vs. altitude, and `atmPlot([mls,mlw], ’O3’, ’mb’)` compares ozone profiles of the midlatitude summer and winter atmospheres with pressure as vertical axis. Finally, the function `atmSave` can be used to write the data to file (see also Appendix A.1).

For the following presentation assume that you are interested in carbon monoxide (CO) retrievals from the thermal IR observations as done by IASI (e.g., [79,80]) or AIRS [81].

Similar to the atmospheric data, the line data can be plotted using Matplotlib’s functions, or, more conveniently, with Py4CAtS’ function, e.g., `atlas(llDict)`. The `atlas` function (named after Park et al. [82]) can be used with a single `lineArray` or a list or dictionary of `lineArray`s and displays line strength vs. position by default.

In the next step the line parameters can be used to compute molecular cross sections, see the `In[3]:` block in Figure 3. `xs = lbl2xs(llDict[’CO’])` returns the cross section of CO in the spectral range around $2140\phantom{\rule{0.166667em}{0ex}}{\mathrm{cm}}^{-1}$ for the database (here HITRAN) reference pressure and temperature. A single cross section is stored in a subclassed NumPy array (i.e., `type(xs) → xsArray`) with “attributes” such as lower and upper wavenumber bound, pressure, temperature, and molecule stored in further items, e.g., `xs.x` or `xs.p`. As a default, the Voigt profile is considered. Please note that the cross sections are evaluated on a uniform wavenumber grid (with spacing defined by the mean line width, see Section 2.2.1), so it is sufficient (and more memory efficient) to save the very first and very last grid point only.

Cross sections for different pressures and temperatures are obtained by specifying the second or third function argument of `lbl2xs`. Please note that the data type returned by `lbl2xs` in these examples is different, i.e., the type is depending on the number of $p,T$ pairs and the type of the line data (a single or a dictionary of `lineArray`, essentially the number of molecules). In the very first example (CO and one $p,T$) in Figure 3 a single subclassed NumPy array `xsArray` is returned, whereas a list of `xsArray`’s is returned for a list of $p,T$ pairs and a single molecule. Finally, the last example gives a dictionary of lists of `xsArray`’s, each list for a single molecule and a dictionary entry for each molecule.

The `xSection.py` module has a function `xsPlot` to visualize the cross sections, e.g., `xsPlot(xss)`. This function works recursively (cf. Appendix A.3), i.e., it can be called with a single `xsArray`, a list thereof, or a dictionary of (lists of) `xsArray`’s. Figure 4 demonstrates the combined use of the `atlas` and `xsPlot` functions exploiting Matplotlib’s function `twinx` to share the common wavenumber axis. The functions `xsInfo` and `xsSave` can be used with a single cross section array, a list of cross sections, or a dictionary of lists to summarize the cross sections’ properties or to write the data to file(s); Reading cross section data from file(s) is possible with the `xsRead` function.

Given cross sections of some molecules on a set of $p,T$ levels along with the atmospheric data, in particular the molecular number densities, the absorption coefficient (8) for all levels are generated with `acList = xs2ac (mls, xssDict)`. The list contains a spectrum for each atmospheric $p,T$ level, where each spectrum is stored in a subclassed NumPy array: `type(acList[0]) → acArray` similar to the cross sections, i.e., with attributes stored as, e.g., `ac.x` and `ac.z` for the wavenumber range and altitude, respectively. Please note that the number of levels in the atmospheric data set (here `mls`) and the lengths of the cross section lists in the `xssDict` dictionary must be identical. Furthermore, all molecules with cross section data must be contained in the atmospheric data (but there can be some “unused” molecules in the atmospheric data set).

The absorption coefficients can be plotted with the standard Matplotlib functions, but Py4CAtS also has a function to make this easier: `acPlot(acList)`. The function `acInfo(acList)` prints essential information about the absorption coefficients (Actually it is a loop calling the corresponding `info` method of `acArray`, i.e., `for ac in acList: ac.info()`).

The data can be saved to file (tabular ascii) with the standard NumPy `savetxt` or Py4CAtS’ `awrite` function. The `acSave` function automatically saves the absorption coefficients along with the atmospheric data, and the `acRead` function allows reading of the data (incl. the associated atmosphere) back from file, e.g., `absCo = acRead(acFile)`. Both `acSave` and `acRead` also support HITRAN formatted files or Python/NumPy’s internal pickle format.

The next step is to integrate the absorption coefficients along the (vertical) path through the atmosphere using the function `ac2dod` (see `In[4]` in Figure 3). Similar to cross sections and absorption coefficients this returns a list of `(nLevels-1)` subclassed NumPy arrays `odArray`, where each list member is essentially the delta / differential / layer optical depth spectrum along with its attributes lower and upper altitudes, pressures, and temperatures (and the wavenumber interval, too).

The optical depths instances can be combined by addition or subtraction, e.g., the delta optical depths of the first (bottom) two layers can be added by `dodList[0]+dodList[1]` (see Figure 5). The main purpose of the `__add__` special method is to combine the optical depths from neighboring layers, but it can also be used to sum the optical depths of different molecules in one layer.

Please note that the `ac2dod` function (and the `xs2dod`, `lbl2od`, … function discussed below) only return delta optical depths (dod), further functions can be used to convert to cumulative or total optical depth. Summation of all layer optical depths with the `dod2tod` function delivers the total optical depth and `dod2cod` returns the (ac)cumulated optical depth. By default, the accumulation is starting with the very first layer (usually at BoA) and the very last element of the generated list should be the total optical depth, whereas `cod = dod2cod(dodList,True)` starts accumulating with the very last layer and the very first `cod[0]` corresponds to the total optical depth.

A quick-look of optical depth(s) can be generated with the `odPlot` function, and the data (incl. the attributes) can be saved to file using `odSave` using ASCII, netcdf, or pickle format. Later, the optical depth data can be read from file into a (new) IPython session with `oDepth = odRead (odFile)`.

The `oDepthOne` function returns the distance ${s}_{1}$ from the (uplooking or downlooking) observer to the point, where the optical depth is one, $\tau (\nu ,{s}_{1})=1.0$, corresponding to a transmission that has decreased to $\mathcal{T}=1/e$. This distance should roughly correspond to the location of the weighting function maximum.

Alternatively, given the delta/layer optical depths the weighting functions can be approximated by finite differencing using the `dod2wf(dodList,zObs,angle)` function, but starting from the absorption coefficient is much more reliable. For weighting functions of a horizontal path (zenith angle $\theta ={90}^{\circ}$) see the first remark in Section 4.2.

The function `wfSave(wgtFct, …)` and `wfRead(wfFile, …)` can be used to save and read the data, and `wfPlot(wgtFct[, wavenumber, …])` provides a simple visualization tool. If (a) specific wavenumber(s) are given, a 2D plot is presented, otherwise a contour plot is generated. An example of weighting functions for microwave temperature sounding in the region of the oxygen rotation band is given in Figure 6.

The `dod2ri` function evaluates the Schwarzschild integral (9) and returns the radiance or intensity, again a subclassed NumPy array `riArray` with attributes for wavenumber interval, altitude, pressure, and temperature minimum/maximum, observer zenith angle, and background temperature, see the last block in Figure 3. Without optional arguments, the radiance seen by an uplooking observer at the surface (BoA) is computed, whereas `dod2ri (dodList, 180.0, mls[’T’][0])` gives the radiance for a nadir-viewing observer looking down from ToA with an angle of ${180.0}^{\circ}$ (relative to the zenith angle) to Earth; the third argument specifies the surface temperature ${T}_{\mathrm{b}}$ (here the BoA temperature of the midlatitude summer (mls) atmosphere) that is used to evaluate a Planck background contribution in (9) with ${I}_{\mathrm{b}}\left(\nu \right)=B(\nu ,{T}_{\mathrm{b}})$.

Please note that `dod2ri` does not have any argument to specify the observer altitude, i.e., it computes the radiance at BoA or ToA for an angle smaller or larger than ${90}^{\circ}$ (a horizontal path with angle ${90}^{\circ}$ is not implemented). If you want to model the radiance, say, for an airborne observer downlooking from $10\phantom{\rule{0.166667em}{0ex}}\mathrm{km}$ and have a list of layer optical depths for an atmosphere with a uniform altitude grid of $1\phantom{\rule{0.166667em}{0ex}}\mathrm{km}$ (hence layer thickness $1\phantom{\rule{0.166667em}{0ex}}\mathrm{km}$), supply a list of the first ten optical depths only, i.e., `dod2ri(dodList[:10],180)`. (See also the remark on limitations in Section 4.6.)

A further Boolean optional argument can be given to switch to the “B exponential-in $\tau $” approximation instead of the default “B linear-in $\tau $”, see Section 2.2.2.

To plot and save the radiance spectrum (along with the wavenumber grid) in a file use the `riPlot` and `riSave` functions, respectively. To convolve the radiance spectrum I with a spectral response function according to (12), a special method `convolve` has been implemented, e.g., `radBox1 = radiance.convolve()` uses the default “box” with a half width $1.0\phantom{\rule{0.166667em}{0ex}}{\mathrm{cm}}^{-1}$. Likewise, `radGauss2 = radiance.convolve(2.0,’G’)` uses a Gaussian response function with HWHM $2.0\phantom{\rule{0.166667em}{0ex}}{\mathrm{cm}}^{-1}$. The `convolve` special method is also available for the `odArray` and `wfArray` classes (in the first case the convolution operates on the corresponding transmission).

If some of the intermediate quantities are not required, it is possible to go directly from line and atmospheric data to optical depths using `dodList = lbl2od (mls, llDict)`. Likewise, cross sections and absorption coefficients can be bypassed with the `lbl2ac` and `xs2dod` functions. Please note that `lbl2ac` and `lbl2od` “inherit” most options accepted by `lbl2xs` or `xs2ac`.

To compute cross sections, absorption coefficients, and optical depths for some spectral range ${\nu}_{\mathrm{lo}}\cdots {\nu}_{\mathrm{hi}}$, all lines in an extended spectral range ${\nu}_{\mathrm{lo}}-\delta \cdots {\nu}_{\mathrm{hi}}+\delta $ should be considered, where $\delta $ is typically some wavenumbers ($\phantom{\rule{0.166667em}{0ex}}{\mathrm{cm}}^{-1}$). However, unless specified as fourth optional argument `xLimits` of the `lbl2xs` function or as option `-x` of the command line script `lbl2xs.py` (and similarly for the `lbl2ac` and `lbl2od` functions), the cross sections, absorption coefficients, and optical depths returned by Py4CAtS are computed on a uniform grid in the interval $[{\nu}_{\mathrm{first}},{\nu}_{\mathrm{last}}]$ where the lower and upper limits correspond to the position of the very first and last line returned by `higstract`. As the `higstract` and `lbl2xs` scripts are completely independent, this extension is not done automatically. The impact of line wing contributions on cross sections is demonstrated in Figure 7.

The functions `ac2dod` or `lbl2od` do not have an angle as argument, so the optical depth returned is always the vertical optical depth through the atmosphere. If transmission (or weighting functions) for a horizontal path (i.e., zenith angle ${90}^{\circ}$, hence a homogeneous atmosphere) are needed, the transmission $\mathcal{T}(\nu ,s)=exp(-\alpha (\nu \left)l\right)$ can be readily evaluated as a function of path length l given an appropriate absorption coefficient $\alpha $. Likewise, the weighting functions are easily computed according to (13) as the product of transmission $\mathcal{T}(\nu ,s)$ times the absorption coefficient $\alpha $ for some lengths l.

An observer “inside” a layer, i.e., with the observer altitude different from any atmospheric altitude grid point, is not supported by Py4CAtS. However, if one needs an observer at a specific altitude (e.g., $3.14159\phantom{\rule{0.166667em}{0ex}}\mathrm{km}$), one can interpolate the atmospheric profiles to a new grid including this point and proceed as usual.

As indicated above, Py4CAtS has originally been a (partial) re-implementation of GARLIC. GARLIC has been thoroughly verified by intercomparisons with other lbl codes such as ARTS and KOPRA (e.g., [74,75,76]). Furthermore, it has been recently validated by intercomparison with spectra of the ACE-FTS instrument [84,85,86]. Figure 8 shows an intercomparison of GARLIC and Py4CAtS brightness temperature spectra. For the monochromatic spectra differences are mostly below one Kelvin except for a few spikes near strong lines. The convolved spectra agree within some hundredth Kelvin.

Please note that in principle the radiance spectrum could have been generated with a single statement `dod2ri(lbl2od(atmRead(’mls.xy’, higstract(’lines’,(2100,2150)), 180.,` `mls[’T’][0])`; however, to properly account for line wing contributions (cf. discussion in Section 4.1) the spectral interval has been specified explicitly.

Despite the efficiency of NumPy’s array processing GARLIC is significantly faster than Py4CAtS. In GARLIC the computation of molecular cross sections, absorption coefficients, and radiances is exploiting the multi-core architecture of modern CPUs, i.e., parallelization by means of OpenMP (see section 3.3 of the GARLIC paper [25]). This allows about a factor 50 speed-up for the Fortran-OpenMP implementation compared to the NumPy implementation on an eight-core desktop for the radiance spectra shown here.

Given line and atmospheric data, a radiance spectrum is essentially generated by the sequence `atmRead`, `higstract`, `lbl2od`, and `dod2ri`. Likewise, atmospheric transmission can be modeled with the fourth and last step `exp(-dod2tod(…))`. If a series of synthetic spectra must be modeled, a combination of these functions into a single function might be convenient. However, such a function is currently not provided in Py4CAtS because the appropriate implementation is clearly depending on the actual task: For an assessment of the impact of spectroscopic data or spectral range on atmospheric radiances, a function combining `higstract – lbl2od – dod2ri` would be adequate (with atmospheric data ingested only once), whereas the impact of atmospheric data on radiances could be studied with the combination of `atmRead – lbl2od – dod2ri`. Furthermore, the main modeling task can easily be performed with a single statement such as `dod2ri(lbl2od(atmData,llDict),…)`. Indeed, this can also be easily used for retrieval purposes, e.g., by a combination with the nonlinear least squares solvers of the `scipy.optimize` package.

- Spherical atmospheres: modeling radiance and/or transmission for limb sounding is not possible; Py4CAtS is assuming a plane-parallel atmosphere. Please note that the quadrature schemes of Section 2.2.2 also work for limb geometry.
- Jacobians: Several tools have been developed for automatic differentiation of Python code (see http://www.autodiff.org), so derivatives of spectra w.r.t. atmospheric parameters etc. could be implemented similar to the approach used in GARLIC [94]. This is currently not foreseen.
- Other line parameter databases (see also http://hitran.org/links/): In addition to HITRAN/HITEMP and GEISA, further databases have been developed such as ExoMol [19] and databases dedicated to specific spectral regions (e.g., JPL and CDMS catalogs, Pickett et al. [16], Endres et al. [18]), specific molecules (e.g., [95,96,97]), or satellite missions [96,98]. Some of these databases have a format similar to HITRAN and GEISA and an appropriate reader could be readily implemented, whereas an implementation of other databases would require some more effort because of their different organization. Please note that a Python script
`ExoMol_to_HITRAN.py`has been developed by the ExoMol consortium, see https://github.com/xnx/ExoMol_to_HITRAN. - Predefined cross sections: Both HITRAN and GEISA include a large collection of IR (and UV) cross sections esp. for heavy molecules that can be relevant for atmospheric absorption. Reading and further processing of these data is not yet implemented in Py4CAtS.
- Py4CAtS stores only the “core” line parameters required for cross section modeling. In contrast, HAPI [34] can also keep track of line assignments, transition IDs etc. However, Py4CAtS has been developed with atmospheric spectroscopy as target application, but not molecular spectroscopy.

Py4CAtS, a Python package developed for “computational atmospheric spectroscopy”, has been presented and its usage in a Unix-like console or within the (I)Python interpreter/notebook (recommended) has been demonstrated. Starting with line data from HITRAN or GEISA and atmospheric data, the scripts and functions allow the computation of cross sections, absorption coefficients, optical depths, weighting functions, and radiances. In particular, they also provide easy access to all intermediate quantities esp. for visualization.

When the development of Py4CAtS started, lbl modeling with Python appeared to be quite ambitious. However, thanks to NumPy and its dramatic performance improvements, atmospheric radiative transfer modeling with Python can now be done with reasonable speed. In fact, our recent benchmark tests of Voigt and complex error function algorithms indicated that NumPy implementations are not significantly slower than Fortran implementations [102].

As emphasized above, the intention for Py4CAtS has not been a highly efficient and accurate lbl radiative transfer code, and the package is not considered to be a competitor for the codes mentioned in the introduction. Nevertheless, despite the speed limitations of interpreters such as Python and the omission of limb geometry, continuum, or scattering Py4CAtS is believed to be attractive because of the flexibility and ease of use. The future development of Py4CAtS will certainly be driven by further optimizations and extensions of its functionality.

Py4CAtS is free software and can be redistributed and/or modified under the terms of the GNU General Public License as published by the Free Software Foundation. A tarball of the Python source files is available at our department’s server at https://atmos.eoc.dlr.de/tools/Py4CAtS/. Py4CAtS is also registered at the Astrophysics Source Code Library (ASCL) with the permalink http://ascl.net/1905.002. The sources have been thoroughly checked with Pep8, PyFlakes, PyChecker, and PyLint. In addition to the sources, the model atmospheres of the Anderson et al. [78] compilation are available in various resolutions (number of altitude levels), and an excerpt of the HITRAN 1986 database [103]. Furthermore, a directory `doc` provides a tutorial/users’ guide along with extensive documentation of the individual modules. The html files have been produced with `pydoc3`.

Conceptualization and methodology, F.S.; Software, F.S. with support from all co-authors; Validation, all authors; Writing—original draft preparation, F.S.; Writing—review and editing, all authors.

Development of PyCAtS has been partially supported by several projects, especially the ESA-ESTEC study ESASlight (contract No. AO/1-5433/07/NL/HE). Furthermore, funding by the World Data Center for Remote Sensing of the Atmosphere (WDC-RSAT) and in the DFG project SCHR 1125/3-1 is gratefully acknowledged.

Thomas Trautmann and Mathias Milz have used Py4CAtS in lectures and seminars at the Universität Leipzig (Germany) and at the Luleå University of Technology (Kiruna, Sweden), respectively. Thanks also go to Thomas Trautmann and Mourad Hamidouche for careful reading of the manuscript. Finally, numerous students and colleagues gave valuable feedback and recommendations, most notably Dmitry Efremenko, Mourad Hamidouche, Michael Hess, Michał Szajkowski, Haoran Xu, Jian Xu (DLR-IMF), Mareike Kenntner (DLR-IPA), and Claudia Emde and Bernhard Mayer (LMU-MIM).

The authors declare no conflict of interest.

The following abbreviations are frequently used in this manuscript:

BoA | Bottom of Atmosphere |

GARLIC | Generic Atmospheric Radiation Line-by-line Infrared Code |

HWHM | half width half maximum |

IR | infrared |

lbl | line-by-line |

Py4CAtS | PYthon scripts for Computational ATmospheric Spectroscopy |

ToA | Top of Atmosphere |

ac | absorption coefficient |

od | optical depth |

ri | radiance intensity |

wf | weighting function |

vmr | volume mixing ratio |

xs | cross section |

In the first three subsections some common aspects of reading, writing, and plotting of the data are discussed. Special data types implemented in Py4CAtS are described in Appendices Appendix A.4 and Appendix A.5. Finally, three modules that should be of interest not only for “computational atmospheric spectroscopy” are presented.

Atmospheric data, cross sections, absorption coefficients, optical depths, weighting functions, and radiance spectra can be written to data files with the functions `atmSave`, `xsSave`, `acSave`, `odSave`, `wfSave`, and `riSave`. Likewise, the data are read from file using `atmRead`, `xsRead`, `acRead`, `odRead`, `wfRead`, and `riRead`. In all cases tabular ASCII files are supported, in some cases Python’s / NumPy’s pickle format or netcdf I/O is also available. Cross section and absorption coefficient files can also use the HITRAN format. (The HITRAN cross section format is extensively described at https://hitran.org/docs/cross-sections-definitions/. In brief, each “portion” starts with a header line defining the molecule, wavenumber range, number of data in this set, temperature (K), pressure (Torr) etc. Following this header, the “values are arranged in records containing ten values of fields of ten for each cross-section”.)

For completeness, the `higstract` function to read the HITRAN and GEISA database (and extract some lines) should be mentioned here, too. The extracted lines can be saved to file with `save_lines_core` for the “core parameters” only (i.e., position, strength etc.) or `save_lines_orig` for the original format (Please note that there is no tool to convert data from HITRAN to GEISA format or back). To read a set of line data files (HITRAN/GEISA extracts of core parameters) use `read_line_file` that returns a single “`lineArray`” for a single file (molecule) or a dictionary thereof.

All routines saving data in ASCII format use the `awrite` function from the `aeiou` module, see Appendix A.8 for details.

The functions `atmPlot`, `atlas`, `xsPlot`, `acPlot`, `odPlot`, `riPlot`, and `wfPlot` can be used to plot atmospheric profiles (default temperature vs. altitude, with z (default, or p) as vertical abscissa), spectroscopic line data (default strength vs. position), molecular absorption cross sections and coefficients, optical depths, radiance/intensity, and weighting functions. Please note that these functions can be called with a single array or a list of arrays (exploiting Python’s recursive capabilities, see Appendix A.3). The name `atlas` goes back to the Atlas of absorption lines from 0 to 17,900 $\phantom{\rule{0.166667em}{0ex}}{\mathrm{cm}}^{-1}$ by Park et al. [82] that served as pictorial representation of the HITRAN 86 database.

Please note that these functions serve to provide quicklooks of the various spectra etc. and are not designed for highly fancy, publication-ready plots. However, the source code of these functions can be exploited as a starting point for more sophisticated plots. And x or y axis labels and limits, legend (entries, positions, …), title, and curve colors, markers, styles and widths can be changed interactively in IPython/Matplotlib.

Some functions exploit Python’s recursive capabilities to make their use as flexible as possible. In particular, `lbl2xs` can be called with

- a single
`lineArray`holding the line parameters (position, strengths, …) of a single molecule and a single $(p,T)$ pair (that defaults to STP $1\phantom{\rule{0.166667em}{0ex}}\mathrm{atm},\phantom{\rule{3.33333pt}{0ex}}296\phantom{\rule{0.166667em}{0ex}}\mathrm{K}$); - a dictionary or list of
`lineArray`’s and a single $(p,T)$ pair; - a single
`lineArray`and a list/array of pressures and/or a list/array of temperatures (if both p and T are arrays (or lists), their length must be identical!); - a dictionary (list) of
`lineArray`’s and (a list/array of) pressure(s) and temperature(s).

Likewise, `xsPlot` can be called with a single cross section `xsArray`, or with a (nested) list or dictionary of `xsArray`’s. Similarly, an `odArray` instance or a list of optical depths can be visualized using `odPlot`, and `acPlot` and `riPlot` work in the same way. Furthermore, `atmPlot` and `atmInfo` accept a single or a list of atmospheric data. Finally, `ac2wf` is called recursively in case of a finite field-of-view.

The spectra of molecular cross sections, absorption coefficients, (layer, cumulative, and total) optical depths, weighting functions, and radiances are stored in subclassed NumPy arrays to hold extra information as attributes, e.g., the minimum and maximum wavenumber is stored in `xs.x`, `ac.x`, and `od.x`, respectively (technically the `x` attribute is an instance of the `Interval` class defined in the `pairTypes.py` module, see Appendix A.9). Pressure and temperature of the cross section and absorption coefficient are single floats for the corresponding atmospheric level, whereas for optical depths they are `PairOfFloats` corresponding to the atmospheric layer.

In addition to these attributes, `xsArray` defines several methods, e.g., (note the parentheses!)

`xs.info()`- — print “essential” information;
`xs.dx()`- — compute the grid point spacing (essentially
`xs.x.size()/(len(xs)-1)`); `xs.grid()`- — returns the uniform wavenumber grid array;
`xs.regrid(n)`- — interpolate to a denser uniform grid (usually n is larger than
`len(xs)`); `xs.__eq__(other)`- — compare two cross sections using the
`==`operator, i.e.,`xs1==xs2`returns`True`if the wavenumber intervals, pressure, temperature, and the spectra itself agree (approximately).

The same methods are also defined for `acArray`, `odArray`, and `riArray`, where in addition there is also a method `truncate` returning the spectrum in a smaller wavenumber interval. Furthermore, a method `convolve` has been implemented in the `riArray` class to smooth the radiance with a box, triangle, or Gaussian spectral response function.

For `odArray` there are also `__add__` and `__sub__` methods to add and subtract optical depths, see Figure 5. These combinations can only be performed if both spectra are defined in the same wavenumber interval, i.e., `od1.x` and `od2.x` are identical. In general, the two optical depths are given on different wavenumber grids, so the coarser spectrum is regridded to the resolution of the denser spectrum first. The `__mul__` method can be used to scale optical depths with a (float) number, e.g., to account for a slant path `od/cosdg(60)`.

The core parameters (position, strength, width, …) of the lines extracted from the HITRAN or GEISA databases are also saved internally in a subclassed array `lineArray`. However, in contrast to the arrays mentioned above (that all have just a single dimension) this has “rows and columns”, where the rows correspond to the spectral lines/transitions, and the columns correspond to center wavenumber ${\widehat{\nu}}_{l}$, line strength ${S}_{l}$, etc. To make these columns easily accessible, `lineArray` is a subclassed structured array (see next section Appendix A.5) with attributes holding information about molecule and reference pressure and temperature.

As described in the NumPy User Guide http://docs.scipy.org/doc/numpy/user/basics.rec.html, “These arrays permit one to manipulate the data by the structs or by fields of the struct”. The main difference to standard NumPy arrays is that one can access the “columns” of these arrays by names (strings) instead of numbers, similar to dictionary entries.

Py4CAtS uses structured arrays for the atmospheric data (see Section 3.2.1) and the line parameters (see Section 3.2.2, actually `lineArray` is a subclassed and structured NumPy array). Several utility functions are collected in the `struc_array.py` module: `loadStrucArray` reads tabular ASCII files and automatically assign names to the fields (columns) given the information in the file header or as an optional argument to the function. Further functions allow the changing of these field names, to insert additional fields, to extract fields, or to delete a field.

The function `cgs` from the `cgsUnits.py` module can be used to convert physical quantities to or from the cgs base unit, e.g., $\mathtt{cgs}{(}^{\prime}{\mathtt{kg}}^{\prime})\to \mathtt{1000}.$ or $\mathtt{cgs}{(}^{\prime}!{\mathtt{km}}^{\prime})\to \mathtt{1}\mathtt{e}-\mathtt{5}$ or $\mathtt{cgs}{(}^{\prime}\mathtt{mb}\phantom{\rule{0.166667em}{0ex}}!\phantom{\rule{0.166667em}{0ex}}{\mathtt{atm}}^{\prime},\mathtt{1013.25})\to \mathtt{1.0}$ (where the exclamation mark separates the original (input) and final (output) unit). Please note that the optional second argument “`data`” can be a float, list of floats, or a NumPy array.

Two further modules `radiance2radiance.py` and `radiance2Kelvin.py` help to convert radiances. With the function `radiance2radiance` one can change the power and/or area and/or spectral unit of radiances, e.g., $\mathrm{nW}\leftrightarrow \mathrm{erg}/\mathrm{s}$ or wavenumber ↔ frequency ↔ wavelength. Likewise, `radiance2Kelvin` allows the conversion of radiances to equivalent brightness temperatures using the “inverse” of the Planck function (11).

When development of the Py4CAtS tools started, Python only offered the `getopt` module providing only limited functionality. Parsing the arguments and options given on the (Unix/Linux) shell command line essentially comprises a series of common tasks, e.g., type checking and conversion, so these extra steps were finally implemented in a new module `command_parser.py` building on top of `getopt.py`. Later on, a new module `optparse` had been added to the Python Standard Library, which is now superseded by the newer and more advanced `argparse` module.

Although `argparse` has some nice features currently not available in `command_parser`, it also has one serious deficiency related to range checks of the given input. In case of integer or float input arguments/options it is frequently required to check if the number falls within a certain range, e.g., pressures and temperatures should be positive, or the percentage concentration should be in the range $(0.0,100.0)$. `argparse` only can check if the input is in a given list of possibilities, e.g., `diceNumber in [1,2,3,4,5,6]`, but a statement such as `200<=temperature<=300` cannot be used. (Several solutions are discussed in the web, but none of them appears attractive.) And more sophisticated checks such as `constraint=’all([digit.strip().isdigit()` `for digit in split(columns,",")])’` are impossible.

A set of functions for some common tasks as reading and parsing the comments in the file header are collected in this module. In addition, there is the `awrite` function that serves as a “slightly better” version of NumPy’s `savetxt` function: the format option is more intelligent, and instead of a single `header` string to be written to the file header `awrite` also accepts a list of strings for the header. Most importantly, there is only a single mandatory argument: the data array to save/write. If no output file is given, `awrite` prints the output on the screen (`sys.stdout`). Accordingly, the sequence of arguments is changed from `savetxt(fname,data,…)` to `awrite(data,fname=None,…)`. Furthermore, `awrite` makes it easier to save several NumPy arrays (all with the same number of rows), for example `awrite ([xGrid, yValues, aMatrix], ’allInOne.file’)`.

This module defines several classes for `Interval`, `pairOfInts`, and `PairOfFloats`. The `Interval` is frequently used in Py4CAtS, e.g., for the wavenumber region of interest: `xLimits=Interval(10.,20.)`.

- Goody, R.; Yung, Y. Atmospheric Radiation—Theoretical Basis, 2nd ed.; Oxford University Press: Oxford, UK, 1989. [Google Scholar]
- Liou, K.N. An Introduction to Atmospheric Radiation; Academic Press: Orlando, FL, USA, 1980. [Google Scholar]
- Zdunkowski, W.; Trautmann, T.; Bott, A. Radiation in the Atmosphere—A Course in Theoretical Meteorology; Cambridge University Press: Cambridge, UK, 2007. [Google Scholar]
- Wiscombe, W. Atmospheric Radiation: 1975–1983. Rev. Geophys. Space Phys.
**1983**, 21, 997. [Google Scholar] [CrossRef] - Schläpfer, D. MODO: An interface to MODTRAN for the simulation of imaging spectrometry at-sensor signals. In Proceedings of the Tenth Jet Propulsion Laboratory Airborne Earth Science Workshop, Pasadena, CA, USA, 27 February–2 March 2001; Green, R., Ed.; Volume JPL-02-1, pp. 343–350. [Google Scholar]
- Berk, A.; Anderson, G.; Acharya, P.; Bernstein, L.; Muratov, L.; Lee, J.; Fox, M.; Adler-Golden, S.; Chetwynd, J.; Hoke, M.; et al. MODTRAN 5: A reformulated atmospheric band model with auxiliary species and practical multiple scattering options: Update. In Proceedings of the Algorithms and Technologies for Multispectral, Hyperspectral, and Ultraspectral Imagery XI, Orlando, FL, USA, 28 March–1 April 2005; Shen, S., Lewis, P., Eds.; Volume 5806, pp. 662–667. [Google Scholar] [CrossRef]
- Wilson, R. Py6S: A Python interface to the 6S radiative transfer model. Comput. Geosci.
**2013**, 51, 166–171. [Google Scholar] [CrossRef][Green Version] - Vermote, E.; Tanré, D.; Deuzé, J.; Herman, M.; Morcette, J.J. Second Simulation of the Satellite Signal in the Solar Spectrum, 6S: An Overview. IEEE Trans. Geosci. Remote Sens.
**1997**, 35, 675–686. [Google Scholar] [CrossRef] - Lacis, A.; Oinas, V. A Description of the Correlated k Distribution Method for Modeling Nongray Gaseous Absorption, Thermal Emission, and Multiple Scattering in Vertically Inhomogeneous Atmospheres. J. Geophys. Res.
**1991**, 96, 9027–9063. [Google Scholar] [CrossRef] - Wiscombe, W.; Evans, J. Exponential-sum fitting of radiative transmission functions. J. Comput. Phys.
**1977**, 24, 416–444. [Google Scholar] [CrossRef] - Heng, K.; Marley, M. Radiative Transfer for Exoplanet Atmospheres. In Handbook of Exoplanets; Deeg, H.J., Belmonte, J.A., Eds.; Springer International Publishing: New York, NY, USA, 2018; pp. 2137–2152. [Google Scholar]
- Madhusudhan, N. Atmospheric Retrieval of Exoplanets. In Handbook of Exoplanets; Deeg, H.J., Belmonte, J.A., Eds.; Springer: New York, NY, USA, 2018. [Google Scholar]
- Gordon, I.E.; Rothman, L.S.; Hill, C.; Kochanov, R.V.; Tan, Y.; Bernath, P.F.; Birk, M.; Boudon, V.; Campargue, A.; Chance, K.V.; et al. The HITRAN2016 molecular spectroscopic database. J. Quant. Spectrosc. Radiat. Transf.
**2017**, 203, 3–69. [Google Scholar] [CrossRef] - Rothman, L.; Gordon, I.; Barber, R.; Dothe, H.; Gamache, R.; Goldman, A.; Perevalov, V.; Tashkun, S.; Tennyson, J. HITEMP, the high-temperature molecular spectroscopic database. J. Quant. Spectrosc. Radiat. Transf.
**2010**, 111, 2139–2150. [Google Scholar] [CrossRef] - Jacquinet-Husson, N.; Armante, R.; Scott, N.A.; Chédin, A.; Crépeau, L.; Boutammine, C.; Bouhdaoui, A.; Crevoisier, C.; Capelle, V.; Boonne, C.; et al. The 2015 edition of the GEISA spectroscopic database. J. Mol. Spectrosc.
**2016**, 327, 31–72. [Google Scholar] [CrossRef][Green Version] - Pickett, H.; Poynter, R.; Cohen, E.; Delitsky, M.; Pearson, J.; Müller, H. Submillimeter, millimeter, and microwave spectral line catalog. J. Quant. Spectrosc. Radiat. Transf.
**1998**, 60, 883–890. [Google Scholar] [CrossRef] - Müller, H.; Schlöder, F.; Stutzki, J.; Winnewisser, G. The Cologne Database for Molecular Spectroscopy, CDMS: A useful tool for astronomers and spectroscopists. J. Mol. Struct.
**2005**, 742, 215–227. [Google Scholar] [CrossRef] - Endres, C.P.; Schlemmer, S.; Schilke, P.; Stutzki, J.; Müller, H.S. The Cologne Database for Molecular Spectroscopy, CDMS, in the Virtual Atomic and Molecular Data Centre, VAMDC. J. Mol. Spectrosc.
**2016**, 327, 95–104. [Google Scholar] [CrossRef][Green Version] - Tennyson, J.; Yurchenko, S.N.; Al-Refaie, A.F.; Barton, E.J.; Chubb, K.L.; Coles, P.A.; Diamantopoulou, S.; Gorman, M.N.; Hill, C.; Lam, A.Z.; et al. The ExoMol database: Molecular line lists for exoplanet and other hot atmospheres. J. Mol. Spectrosc.
**2016**, 327, 73–94. [Google Scholar] [CrossRef][Green Version] - Clough, S.; Kneizys, F.; Rothman, L.; Gallery, W. Atmospheric transmittance and radiance: FASCOD1B. Proc. SPIE
**1981**, 277, 152–166. [Google Scholar] [CrossRef] - Scott, N.; Chédin, A. A Fast Line-by-Line Method for Atmospheric Absorption Computations: The Automatized Atmospheric Absorption Atlas. J. Appl. Meteorol.
**1981**, 20, 802–812. [Google Scholar] [CrossRef][Green Version] - Buehler, S.A.; Eriksson, P.; Kuhn, T.; von Engeln, A.; Verdes, C. ARTS, the atmospheric radiative transfer simulator. J. Quant. Spectrosc. Radiat. Transf.
**2005**, 91, 65–93. [Google Scholar] [CrossRef][Green Version] - Eriksson, P.; Buehler, S.A.; Davis, C.; Emde, C.; Lemke, O. ARTS, the atmospheric radiative transfer simulator, version 2. J. Quant. Spectrosc. Radiat. Transf.
**2011**, 112, 1551–1558. [Google Scholar] [CrossRef][Green Version] - Buehler, S.A.; Mendrok, J.; Eriksson, P.; Perrin, A.; Larsson, R.; Lemke, O. ARTS, the atmospheric radiative transfer simulator—Version 2.2, the planetary toolbox edition. Geosci. Model Dev.
**2018**, 11, 1537–1556. [Google Scholar] [CrossRef] - Schreier, F.; Gimeno García, S.; Hedelt, P.; Hess, M.; Mendrok, J.; Vasquez, M.; Xu, J. GARLIC—A General Purpose Atmospheric Radiative Transfer Line-by-Line Infrared-Microwave Code: Implementation and Evaluation. J. Quant. Spectrosc. Radiat. Transf.
**2014**, 137, 29–50. [Google Scholar] [CrossRef] - Edwards, D. Atmospheric transmittance and radiance calculations using line–by–line computer models. In Proceedings of the Modelling of the Atmosphere, Orlando, FL, USA, 4–8 April 1988; Volume 928, pp. 94–116. [Google Scholar] [CrossRef]
- Stiller, G.; von Clarmann, T.; Funke, B.; Glatthor, N.; Hase, F.; Höpfner, M.; Linden, A. Sensitivity of trace gas abundances retrievals from infrared limb emission spectra to simplifying approximations in radiative transfer modelling. J. Quant. Spectrosc. Radiat. Transf.
**2002**, 72, 249–280. [Google Scholar] [CrossRef] - Clough, S.; Shephard, M.; Mlawer, E.; Delamere, J.; Iacono, M.; Cady-Pereira, K.; Boukabara, S.; Brown, P. Atmospheric radiative transfer modeling: A summary of the AER codes. J. Quant. Spectrosc. Radiat. Transf.
**2005**, 91, 233–244. [Google Scholar] [CrossRef] - Gordley, L.; Marshall, B.; Chu, D. LINEPAK: Algorithms for modeling spectral transmittance and radiance. J. Quant. Spectrosc. Radiat. Transf.
**1994**, 52, 563. [Google Scholar] [CrossRef] - Dudhia, A. The Reference Forward Model (RFM). J. Quant. Spectrosc. Radiat. Transf.
**2017**, 186, 243–253. [Google Scholar] [CrossRef][Green Version] - Amato, U.; Masiello, G.; Serio, C.; Viggiano, M. The σ–IASI code for the calculation of infrared atmospheric radiance and its derivatives. Environ. Model. Softw.
**2002**, 17, 651–667. [Google Scholar] [CrossRef] - Bailey, J.; Kedziora-Chudczer, L. Modelling the spectra of planets, brown dwarfs and stars using VStar. Mon. Not. R. Astron. Soc.
**2012**, 419, 1913–1929. [Google Scholar] [CrossRef] - Hill, C.; Gordon, I.E.; Kochanov, R.V.; Barrett, L.; Wilzewski, J.S.; Rothman, L.S. HITRANonline: An online interface and the flexible representation of spectroscopic data in the HITRAN database. J. Quant. Spectrosc. Radiat. Transf.
**2015**, 177, 4–14. [Google Scholar] [CrossRef] - Kochanov, R.; Gordon, I.; Rothman, L.; Wcisło, P.; Hill, C.; Wilzewski, J. HITRAN Application Programming Interface (HAPI): A comprehensive approach to working with spectroscopic data. J. Quant. Spectrosc. Radiat. Transf.
**2016**, 177, 15–30. [Google Scholar] [CrossRef] - Goldenstein, C.; Miller, V.; Spearrin, R.; Strand, C. SpectraPlot.com: Integrated spectroscopic modeling of atomic and molecular gases. J. Quant. Spectrosc. Radiat. Transf.
**2017**, 200, 249–257. [Google Scholar] [CrossRef][Green Version] - Villanueva, G.; Smith, M.; Protopapa, S.; Faggi, S.; Mandell, A. Planetary Spectrum Generator: An accurate online radiative transfer suite for atmospheres, comets, small bodies and exoplanets. J. Quant. Spectrosc. Radiat. Transf.
**2018**, 217, 86–104. [Google Scholar] [CrossRef][Green Version] - Smette, A.; Sana, H.; Noll, S.; Horst, H.; Kausch, W.; Kimeswenger, S.; Barden, M.; Szyszka, C.; Jones, A.M.; Gallenne, A.; et al. Molecfit: A general tool for telluric absorption correction. Astron. Astrophys.
**2015**, 576, A77. [Google Scholar] [CrossRef][Green Version] - Bertaux, L.; Lallement, R.; Ferron, S.; Boonne, C.; Bodichon, R. TAPAS, a web-based service of atmospheric transmission computation for astronomy. Astron. Astrophys.
**2014**, 564, A46. [Google Scholar] [CrossRef] - Schreier, F.; Böttger, U. MIRART, A Line-By-Line Code for Infrared Atmospheric Radiation Computations incl. Derivatives. Atmos. Ocean. Opt.
**2003**, 16, 262–268. [Google Scholar] - Ernst, T.; Rother, T.; Schreier, F.; Wauer, J.; Balzer, W. DLR’s Virtual Lab: Scientific Software just a mouse click away. Comput. Sci. Eng.
**2003**, 5, 70–79. [Google Scholar] [CrossRef] - von Clarmann, T.; Echle, G. Selection of Optimized Microwindows for Atmospheric Spectroscopy. Appl. Opt.
**1998**, 37, 7661–7669. [Google Scholar] [CrossRef] - Echle, G.; von Clarmann, T.; Dudhia, A.; Flaud, J.M.; Funke, B.; Glatthor, N.; Kerridge, B.; López-Puertas, M.; Martin-Torres, F.; Stiller, G. Optimized Spectral Microwindows for Data Analysis of the Michelson Interferometer for Passive Atmospheric Sounding on the Environmental Satellite. Appl. Opt.
**2000**, 39, 5531–5540. [Google Scholar] [CrossRef] - Dudhia, A.; Jay, V.; Rodgers, C. Microwindow selection for high-resolution-sounders. Appl. Opt.
**2002**, 41, 3665–3673. [Google Scholar] [CrossRef] - Rabier, F.; Fourrié, N.; Chafai, D.; Prunet, P. Channel Selection Methods for Infrared Atmospheric Sounding Interferometer Radiances. Quart. J. R. Met. Soc.
**2002**, 128, 1011–2027. [Google Scholar] [CrossRef] - Crevoisier, C.; Chedin, A.; Scott, N.A. AIRS channel selection for CO
_{2}and other trace-gas retrievals. Quart. J. R. Met. Soc.**2003**, 129, 2719–2740. [Google Scholar] [CrossRef] - Kuai, L.; Natraj, V.; Shia, R.; Miller, C.; Yung, Y. Channel selection using information content analysis: A case study of CO
_{2}retrieval from near infrared measurements. J. Quant. Spectrosc. Radiat. Transf.**2010**, 111, 1296–1304. [Google Scholar] [CrossRef] - Dubois, P.; Hinsen, K.; Hugunin, J. Numerical Python. Comput. Phys.
**1996**, 10, 262–267. [Google Scholar] [CrossRef] - Watters, A.; van Rossum, G.; Ahlstrom, J.C. Internet Programming with Python; M & T Books: New York, NY, USA, 1996. [Google Scholar]
- Oliphant, T. Python for Scientific Computing. Comput. Sci. Eng.
**2007**, 9, 10–20. [Google Scholar] [CrossRef][Green Version] - Langtangen, H.P. Python Scripting for Computational Science, 3rd ed.; Texts in Computational Science and Engineering; Springer: New York, NY, USA, 2008; Volume 3. [Google Scholar]
- van der Walt, S.; Colbert, S.; Varoquaux, G. The NumPy Array: A Structure for Efficient Numerical Computation. Comput. Sci. Eng.
**2011**, 13, 22–30. [Google Scholar] [CrossRef][Green Version] - Pérez, F.; Granger, B.; Hunter, J. Python: An Ecosystem for Scientific Computing. Comput. Sci. Eng.
**2011**, 13, 13–21. [Google Scholar] [CrossRef] - Lin, J.W.B. Why Python is the next wave in earth sciences computing. Bull. Am. Met. Soc.
**2012**, 93, 1823–1824. [Google Scholar] [CrossRef] - Raspaud, M.; Hoese, D.; Dybbroe, A.; Lahtinen, P.; Devasthale, A.; Itkin, M.; Hamann, U.; Rasmussen, L.Ø.; Nielsen, E.; Leppelt, T.; et al. PyTroll: An Open-Source, Community-Driven Python Framework to Process Earth Observation Satellite Data. Bull. Am. Met. Soc.
**2018**, 99, 1329–1336. [Google Scholar] [CrossRef][Green Version] - Astropy Collaboration; Robitaille, T.P.; Tollerud, E.J.; Greenfield, P.; Droettboom, M.; Bray, E.; Aldcroft, T.; Davis, M.; Ginsburg, A.; Price-Whelan, A.; et al. Astropy: A community Python package for astronomy. Astron. Astrophys.
**2013**, 558, A33. [Google Scholar] [CrossRef][Green Version] - Parker, S.; Johnson, C.; Beazley, D. Computational Steering Software Systems and Strategies. IEEE Comput. Sci. Eng.
**1997**, 4, 50–59. [Google Scholar] [CrossRef] - Dubois, P.; Yang, T.Y. Extending Python with Fortran. Comput. Sci. Eng.
**1999**, 1, 66–73. [Google Scholar] [CrossRef] - Peterson, P. F2PY: A tool for connecting Fortran and Python programs. Int. J. Comput. Sci. Eng.
**2009**, 4, 296–305. [Google Scholar] [CrossRef] - Norton, R.; Rinsland, C. ATMOS data processing and science analysis methods. Appl. Opt.
**1991**, 30, 389–400. [Google Scholar] [CrossRef] - Armstrong, B. Spectrum Line Profiles: The Voigt Function. J. Quant. Spectrosc. Radiat. Transf.
**1967**, 7, 61–88. [Google Scholar] [CrossRef] - Varghese, P.; Hanson, R. Collisional narrowing effects on spectral line shapes measured at high resolution. Appl. Opt.
**1984**, 23, 2376–2385. [Google Scholar] [CrossRef] - Tennyson, J.; Bernath, P.; Campargue, A.; Császár, A.; Daumont, L.; Gamache, R.; Hodges, J.; Lisak, D.; Naumenko, O.; Rothman, L.; et al. Recommended isolated-line profile for representing high-resolution spectroscopic transitions (IUPAC Technical Report). Pure Appl. Chem.
**2014**, 86, 1931–1943. [Google Scholar] [CrossRef][Green Version] - Schreier, F. Computational Aspects of Speed-Dependent Voigt Profiles. J. Quant. Spectrosc. Radiat. Transf.
**2017**, 187, 44–53. [Google Scholar] [CrossRef] - NIST Digital Library of Mathematical Functions; Online companion to [65]; National Institute of Standards and Technology: Gaithersburg, MD, USA, 2010.
- Olver, F.; Lozier, D.; Boisvert, R.; Clark, C. (Eds.) NIST Handbook of Mathematical Functions; Print companion to [64]; Cambridge University Press: New York, NY, USA, 2010. [Google Scholar]
- Ralston, A.; Rabinowitz, P. A First Course in Numerical Analysis, 2nd ed.; McGraw–Hill Book Company: New York, NY, USA, 1978. [Google Scholar]
- Cuyt, A.; Petersen, V.; Verdonk, B.; Waadeland, H.; Jones, W. Handbook of Continued Fractions for Special Functions; Springer: New York, NY, USA, 2008. [Google Scholar]
- Humlíček, J. An efficient method for evaluation of the complex probability function: The Voigt function and its derivatives. J. Quant. Spectrosc. Radiat. Transf.
**1979**, 21, 309–313. [Google Scholar] [CrossRef] - Humlíček, J. Optimized computation of the Voigt and complex probability function. J. Quant. Spectrosc. Radiat. Transf.
**1982**, 27, 437–444. [Google Scholar] [CrossRef] - Weideman, J. Computation of the Complex Error Function. SIAM J. Num. Anal.
**1994**, 31, 1497–1518. [Google Scholar] [CrossRef] - Schreier, F. Optimized Implementations of Rational Approximations for the Voigt and Complex Error Function. J. Quant. Spectrosc. Radiat. Transf.
**2011**, 112, 1010–1025. [Google Scholar] [CrossRef] - Whiting, E. An empirical approximation to the Voigt profile. J. Quant. Spectrosc. Radiat. Transf.
**1968**, 8, 1379–1384. [Google Scholar] [CrossRef] - Schreier, F. Optimized evaluation of a large sum of functions using a three-grid approach. Comput. Phys. Commun.
**2006**, 174, 783–802. [Google Scholar] [CrossRef] - Schreier, F.; Milz, M.; Buehler, S.A.; von Clarmann, T. Intercomparison of three microwave/infrared high resolution line-by-line radiative transfer codes. J. Quant. Spectrosc. Radiat. Transf.
**2018**, 211, 64–77. [Google Scholar] [CrossRef] - von Clarmann, T.; Höpfner, M.; Funke, B.; López-Puertas, M.; Dudhia, A.; Jay, V.; Schreier, F.; Ridolfi, M.; Ceccherini, S.; Kerridge, B.; et al. Modeling of Atmospheric Mid–Infrared Radiative Transfer: The AMIL2DA Algorithm Intercomparison Experiment. J. Quant. Spectrosc. Radiat. Transf.
**2003**, 78, 381–407. [Google Scholar] [CrossRef] - Melsheimer, C.; Verdes, C.; Buehler, S.A.; Emde, C.; Eriksson, P.; Feist, D.; Ichizawa, S.; John, V.; Kasai, Y.; Kopp, G.; et al. Intercomparison of General Purpose Clear Sky Atmospheric Radiative Transfer Models for the Millimeter/Submillimeter Spectral Range. Radio Sci.
**2005**, 40, RS1007. [Google Scholar] [CrossRef] - Hunter, J. Matplotlib: A 2D Graphics Environment. Comput. Sci. Eng.
**2007**, 9, 90–95. [Google Scholar] [CrossRef] - Anderson, G.; Clough, S.; Kneizys, F.; Chetwynd, J.; Shettle, E. AFGL Atmospheric Constituent Profiles (0–120 km); Technical Report TR-86-0110; AFGL: Hanscom AFB, MA, USA, 1986. [Google Scholar]
- Fortems-Cheiney, A.; Chevallier, F.; Pison, I.; Bousquet, P.; Carouge, C.; Clerbaux, C.; Coheur, P.F.; George, M.; Hurtmans, D.; Szopa, S. On the capability of IASI measurements to inform about CO surface emissions. Atmos. Chem. Phys.
**2009**, 9, 8735–8743. [Google Scholar] [CrossRef][Green Version] - George, M.; Clerbaux, C.; Bouarar, I.; Coheur, P.F.; Deeter, M.; Edwards, D.; Francis, G.; Gille, J.; Hadji-Lazaro, J.; Hurtmans, D.; et al. An examination of the long-term CO records from MOPITT and IASI: Comparison of retrieval methodology. Atmos. Meas. Tech.
**2015**, 8, 4313–4328. [Google Scholar] [CrossRef] - McMillan, W.; Barnet, C.; Strow, L.; Chahine, M.; McCourt, M.; Warner, J.; Novelli, P.; Korontzi, S.; Maddy, E.; Datta, S. Daily global maps of carbon monoxide from NASA’s Atmospheric Infrared Sounder. Geophys. Res. Lett.
**2005**, 32, L11801. [Google Scholar] [CrossRef] - Park, J.; Rothman, L.; Rinsland, C.; Richardson, D.; Namkung, J. Atlas of Absorption Lines from 0 to 17,900 cm
^{-1}; Reference Publication 1188; NASA: Washington, DC, USA, 1987. - Murtagh, D.; Frisk, U.; Merino, F.; Ridal, M.; Jonsson, A.; Stegman, J.; Witt, G.; Eriksson, P.; Jiménez, C.; Megie, G.; et al. An overview of the Odin atmospheric mission. Can. J. Phys.
**2002**, 80, 309–319. [Google Scholar] [CrossRef] - Hughes, R.; Bernath, P.; Boone, C. ACE infrared spectral atlases of the Earth’s atmosphere. J. Quant. Spectrosc. Radiat. Transf.
**2014**, 148, 18–21. [Google Scholar] [CrossRef] - Bernath, P.F. The Atmospheric Chemistry Experiment (ACE). J. Quant. Spectrosc. Radiat. Transf.
**2017**, 186, 3–16. [Google Scholar] [CrossRef] - Schreier, F.; Städt, S.; Hedelt, P.; Godolt, M. Transmission Spectroscopy with the ACE-FTS Infrared Spectral Atlas of Earth: A Model Validation and Feasibility Study. Mol. Astrophys.
**2018**, 11, 1–22. [Google Scholar] [CrossRef] - Richard, C.; Gordon, I.; Rothman, L.; Abel, M.; Frommhold, L.; Gustafsson, M.; Hartmann, J.M.; Hermans, C.; Lafferty, W.; Orton, G.; et al. New section of the HITRAN database: Collision-Induced Absorption (CIA). J. Quant. Spectrosc. Radiat. Transf.
**2012**, 113, 1276–1285. [Google Scholar] [CrossRef] - Clough, S.; Kneizys, F.; Davies, R. Line Shape and the Water Vapor Continuum. Atmos. Res.
**1989**, 23, 229–241. [Google Scholar] [CrossRef] - Tipping, R.; Ma, Q. Theory of the water vapor continuum and validations. Atmos. Res.
**1995**, 36, 69–94. [Google Scholar] [CrossRef][Green Version] - Green, P.D.; Newman, S.M.; Beeby, R.J.; Murray, J.E.; Pickering, J.C.; Harries, J.E. Recent advances in measurement of the water vapour continuum in the far-infrared spectral region. Philos. Trans. R. Soc. A Math. Phys. Eng. Sci.
**2012**, 370, 2637–2655. [Google Scholar] [CrossRef][Green Version] - Mlawer, E.; Payne, V.; Moncet, J.L.; Delamere, J.; Alvarado, M.; Tobin, D. Development and recent evaluation of the MT-CKD model of continuum absorption. Philos. Trans. R. Soc. Lond. Ser. A
**2012**, 370, 2520–2556. [Google Scholar] [CrossRef] - Shine, K.; Ptashnik, I.; Rädel, G. The Water Vapour Continuum: Brief History and Recent Developments. Surv. Geophys.
**2012**, 33, 535–555. [Google Scholar] [CrossRef] - Shine, K.; Campargue, A.; Mondelain, D.; McPheat, R.; Ptashnik, I.; Weidmann, D. The water vapour continuum in near-infrared windows—Current understanding and prospects for its inclusion in spectroscopic databases. J. Mol. Spectrosc.
**2016**, 327, 193–208. [Google Scholar] [CrossRef] - Schreier, F.; Gimeno García, S.; Vasquez, M.; Xu, J. Algorithmic vs. finite difference Jacobians for infrared atmospheric radiative transfer. J. Quant. Spectrosc. Radiat. Transf.
**2015**, 164, 147–160. [Google Scholar] [CrossRef] - Tashkun, S.A.; Perevalov, V.I.; Teffo, J.L.; Bykov, A.D.; Lavrentieva, N.N. CDSD-1000, the high-temperature carbon dioxide spectroscopic databank. J. Quant. Spectrosc. Radiat. Transf.
**2003**, 82, 165–196. [Google Scholar] [CrossRef] - Nikitin, A.; Lyulin, O.; Mikhailenko, S.; Perevalov, V.; Filippov, N.; Grigoriev, I.; Morino, I.; Yoshida, Y.; Matsunaga, T. GOSAT-2014 methane spectral line list. J. Quant. Spectrosc. Radiat. Transf.
**2015**, 154, 63–71. [Google Scholar] [CrossRef] - Tashkun, S.; Perevalov, V.; Lavrentieva, N. NOSD-1000, the high-temperature nitrous oxide spectroscopic databank. J. Quant. Spectrosc. Radiat. Transf.
**2016**, 177, 43–48. [Google Scholar] [CrossRef] - Brown, L.; Gunson, M.; Toth, R.; Irion, F.; Rinsland, C.; Goldman, A. 1995 Atmospheric Trace Molecule Spectroscopy (ATMOS) Linelist. Appl. Opt.
**1996**, 35, 2828–2848. [Google Scholar] [CrossRef] - Stamnes, K.; Tsay, S.C.; Wiscombe, W.; Jayaweera, K. Numerically Stable Algorithm for Discrete–Ordinate–Method Radiative Transfer in Multiple Scattering and Emitting Layered Media. Appl. Opt.
**1988**, 27, 2502–2509. [Google Scholar] [CrossRef] - Mayer, B.; Kylling, A. Technical note: The libRadtran software package for radiative transfer calculations— Description and examples of use. Atmos. Chem. Phys.
**2005**, 5, 1855–1877. [Google Scholar] [CrossRef] - Emde, C.; Buras-Schnell, R.; Kylling, A.; Mayer, B.; Gasteiger, J.; Hamann, U.; Kylling, J.; Richter, B.; Pause, C.; Dowling, T.; et al. The libRadtran software package for radiative transfer calculations (version 2.0.1). Geosci. Model Dev.
**2016**, 9, 1647–1672. [Google Scholar] [CrossRef][Green Version] - Schreier, F. The Voigt and complex error function: Humlíček’s rational approximation generalized. Mon. Not. R. Astron. Soc.
**2018**, 479, 3068–3075. [Google Scholar] [CrossRef] - Rothman, L.; Gamache, R.; Goldman, A.; Brown, L.; Toth, R.; Pickett, H.; Poynter, P.; Flaud, J.M.; Camy-Peyret, C.; Barbe, A.; et al. The HITRAN database: 1986 edition. Appl. Opt.
**1987**, 26, 4058. [Google Scholar] [CrossRef]

dll = higstract(’/data/hitran/2000/lines’,(4273,4312), ’main’) # dict of line lists xss = lbl2xs(dll) # dict of cross sections atlas(dll); twinx(); xsPlot(xss)

sas = atmRead(’/data/atmos/50/subarcticSummer.xy’, zToA=80) dll = higstract(’/data/hitran/2000/lines’,(0,10), ’main’); del dll[’CO’] acList = lbl2ac(sas, dll, (1.65,2)) wgtFct = ac2wf(acList, 180) ssmtFreqs=array([50.5, 53.2, 54.35, 54.9, 58.825, 59.4, 58.4,])*1e9/c subplot(121); wfPlot(wgtFct, wavenumber=ssmtFreqs) subplot(122); wfPlot(wgtFct, nLevels=50)

vLimits = Interval(2100.0,2150.0) mls = atmRead(’/data/atmos/50/mls.xy’, zToA=100) dll = higstract(’/data/hitran/2000/lines’,vLimits+20, ’main’) # dict. of line lists radNadir = dod2ri(lbl2od(mls,dll,vLimits+5),180.,mls[’T’][0]) # monochrom radiance radNadirG = radNadir.convolve(1.0,’G’) # Gauss spectral response btNadir = radiance2Kelvin(radNadir.grid(),radNadir) # equ brightness temperature btNadirG = radiance2Kelvin(radNadirG.grid(),radNadirG)

© 2019 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (http://creativecommons.org/licenses/by/4.0/).