Atmospheric transmittance at the oxygen A-band
The oxygen A-band is a spectral band of molecular oxygen $O_2$ in the wavelength region of about 759 nanometers to 771 nanometers. Molecular oxygen is quite remarkable because its ground state is a triplet configuration for the electrons and as everything would oxidize quite rapidly in our atmosphere if this would not be the case, we should be happy for this fact. The A-band is basically formed by the electronic transition from the ground state to the second excited singlet state in its lowest vibrational state. The band consists of a lot of individual transitions involving different rotational quantum states. For further reading pick your favorite spectroscopy textbook and have a look at the details (it is a rabbit hole with no end... and that's the fun part ;)).
Let's say we want to know the A-band spectrum at standard HITRAN conditions ($T=296\,\text{K}, p=1.0\,\text{atm}$) and what is the maximum transmittance through a 100 m air column. For simplicity we assume that the conditions (and abundance does not change along this air column.
Getting started
We start by loading the module:
julia> using HITRAN
Now we could specify a database using the function open_database
or just stick to the default database. If no database is specified, the package will just use a default database in a file named HITRAN.sqlite
in your current environment folder.
Populating the local database
We need line-by-line data, so let's fetch it using:
julia> fetch!("StdAtm", iso_id(["N2", "O2", "CO2", "H2O", "CH4"]), 12900, 13200, [:standard, :ht_self]);
[ Info: No custom HITRAN database specified, opening 'HITRAN.sqlite' (default) 2630
Now this command needs some explanation. First of all it is named fetch!
with exclamation mark because it modifies the underlying database and is therefore considered "mutating". The parameters are the following:
parameter | description | example value |
---|---|---|
name | A user-chosen identifier used as table name in the database | "StdAtm" |
global_iso_ids | A list of global isotopologue IDs. The iso_id function is a convenience function which allows to lookup iso ids by formula (either molecule or isotopologue) or by molecule/local id | iso_id(["N2", "O2", "CO2", "H2O", "CH4"]) |
ν_min | The minimum wavenumber (in $cm^{-1}$) to consider | 12900 |
ν_max | The maximum wavenumber (in $cm^{-1}$) to consider | 13200 |
parameters | A list of HITRAN line parameters to get. As nobody wants to remember these, there are shortcuts defined as symbols. The default HITRAN parameter set can be specified with :standard. In this case we additionally want to fetch the Hartmann-Tran paramters (if available). | [:standard, :ht_self] |
For this example it would be sufficient to just fetch O2 spectral lines as there are only some weak H2O lines in the A-band. But it showcases how a table containing multiple components can be setup.
Now that we have a table called "StdAtm" (for Standard Atmosphere) with some of the more relevant atmospheric constituents, we can already calculate a spectrum. One more important detail: The fetch commands generates a hash of the url used to query the HITRAN database. If you make a consecutive fetch!
call with exactly the same parameters, no new download will be initiated. This is also handy because you do not need to comment/uncomment fetch!
commands in your code to disable download. As soon as you change the parameters (for example the wavenumber limit) new data will be downloaded.
Calculating a spectrum
The most simple approach would be to just straight away call this command:
julia> wavenumbers, absorption_coefficient = α( ["StdAtm"] )
(12900.269191:0.01:13199.939191, [1.4903946624960187e-9, 1.2266333962521325e-9, 6.850773033507631e-10, 2.6358418367654267e-10, 7.581870359272896e-11, 2.5420227204685723e-11, 2.6434725864692407e-11, 6.81664848505016e-11, 1.9275110052664767e-10, 4.248277246656541e-10 … 7.553659996865661e-12, 8.335221227383e-12, 1.0292840140433695e-11, 1.9721445609075427e-11, 8.687101879563264e-11, 4.836010846013798e-10, 2.111724044035105e-9, 6.505288356125817e-9, 1.3854707655923233e-8, 2.030366539922462e-8])
As you can see, we get a range of wavenumber values and values for the absorption coefficient right away. But wait, how does the module know the atmospheric composition we are interested in? In short: It does not! If you just specify a table name to the α
function it will just calculate all spectral lines withing the table assuming their natural isotopologue abundance and does not take the proper gas mixture into account. See the function description of α
for all details. For this example, we can use a neat shortcut:
julia> wavenumbers, absorption_coefficient = α( ["StdAtm"]; components=default_environments[:dry_air] )
(12900.269191:0.01:13199.939191, [2.832690943125633e-9, 3.231158338723144e-9, 3.7166093935579818e-9, 4.3148493526887175e-9, 5.061127570521185e-9, 6.0039005691102835e-9, 7.209715633414868e-9, 8.768520796948074e-9, 1.0796293705719397e-8, 1.3425807293242e-8 … 2.7073190974006877e-15, 2.5625129614225664e-15, 2.4290980092873225e-15, 2.305920647548923e-15, 2.191967992395459e-15, 2.086348024620865e-15, 1.9882728910833393e-15, 1.89704480360403e-15, 1.8120440894652065e-15, 1.7327190312314336e-15])
The default_environment
variable is a Dict
containing standard mixtures. For now this is only dry air by using the key :dry_air
. See Environments for details for the environments.
The diluent parameter behaves a little bit differently for HITRAN.jl 0.1.1 and greater and differs from HAPI. The problem with the HAPI diluent specification is that the diluent :self
will apply to ALL gases in a mixture and is therefore wrong by design. To fix this, HITRAN.jl can actually work out the diluent itself given a gas mixture. The self
portion will be set to abundance specified in components and the air
portion is attributed to the remaining fraction. If H2O is part of the mixture the H2O
diluent will be set accordingly and the influence of water on the collisional broadening will be taken into account (if the necessary data is supplied by the HITRAN database).
The behaviour of the diluent parameter matches the HAPI behaviour for a single component specification. If you want to calculate a gas mixture, you have to provide a Dict
with the molecule/local isotopologue id as key and another Dict
as value containing the diluent as usual. It is possible to provide only diluent information for some components, the module will work out the other diluents automatically.
The final code
To sum it all up, the correct code (besides the warning above) for this example is:
julia> wavenumbers, absorption_coefficient = α(["StdAtm"]; components=(default_environments[:dry_air]) )
(12900.269191:0.01:13199.939191, [2.832690943125633e-9, 3.231158338723144e-9, 3.7166093935579818e-9, 4.3148493526887175e-9, 5.061127570521185e-9, 6.0039005691102835e-9, 7.209715633414868e-9, 8.768520796948074e-9, 1.0796293705719397e-8, 1.3425807293242e-8 … 2.7073190974006877e-15, 2.5625129614225664e-15, 2.4290980092873225e-15, 2.305920647548923e-15, 2.191967992395459e-15, 2.086348024620865e-15, 1.9882728910833393e-15, 1.89704480360403e-15, 1.8120440894652065e-15, 1.7327190312314336e-15])
This specifies that our oxygen is dilutet by the surrounding air mass which tells the module how to properly calculate the collision-broadening of the spectral lines.
To get the transmittance along our air column we can use the little helper function and specifying the air path length in centimeters:
julia> transmittance = transmittance_spectrum(absorption_coefficient, 100e2);
Full code & plotting
Let's put everything so far together and create a plot:
using HITRAN, Plots
fetch!("StdAtm", iso_id(["N2", "O2", "CO2", "H2O", "CH4"]), 12900, 13200, [:standard, :ht_self]);
wavenumbers, absorption_coefficient = α(["StdAtm"];
components=default_environments[:dry_air]
)
transmittance = transmittance_spectrum(absorption_coefficient, 100e2)
plot(
wavenumbers,
transmittance,
xlabel="Wavenumbers [1/cm]",
ylabel="Transmission",
title="Transmission along a 100 m air column",
leg=false
)