Pre-tabulated spectroscopic tables
NEMESIS performs the calculations of the gaseous opacities using pre-tabulated tables. These tables can either include the k-coefficients (Spectroscopy.ILBL = 0) (see Irwin et al. (2008) for a detailed definition), or the line-by-line absorption cross sections computed at each specific wavelength (Spectroscopy.ILBL = 2). In this notebook, we provide some examples showing how archNEMESIS can be used to read this pre-tabulated tables that will later be used to compute the forward model.
In archNEMESIS, the information about the Spectroscopy class is read from the HDF5 input files, in particular the number of gases NGAS, the flag for the look-up table type ILBL, and the location of the look-up tables LOCATION. In the case that we read the inputs from the standard NEMESIS files, then the main input files describing the spectroscopy of the gaseous species in the atmosphere are the .kls file (for ILBL = 0) and the .lls file (for ILBL = 2).
[1]:
import archnemesis as ans
import numpy as np
import matplotlib.pyplot as plt
1. Reading the line-by-line tables
In this section, we show how archNEMESIS can be used to read the pre-tabulated line-by-line tables, which include the absorption cross sections of a given molecule in a grid of temperatures and pressures. In addition, archNEMESIS includes a set of functions to interpolate the cross sections to any specified pressure and temperature level.
Reading the header of the tables
[2]:
#Initialising spectroscopy class with ILBL = 2 (line-by-line)
Spectroscopy = ans.Spectroscopy_0(ILBL=2)
Spectroscopy.NGAS = 2 #We define two gases in the class
Spectroscopy.LOCATION = ['h2o_lbltab.lta',
'co2_lbltab.lta']
#Reading the header information
Spectroscopy.read_header()
#Printing summary information
Spectroscopy.summary_info()
Calculation type ILBL :: 2 (line-by-line)
Number of radiatively-active gaseous species :: 2
Gaseous species :: ['H2O (1)', 'CO2']
Number of spectral points :: 15001
Wavelength range :: 3750.0 - 3765.0000007124618
Step size :: 0.0010000000474974513
Number of temperature levels :: 5
Temperature range :: 100.0 - 200.0 K
Number of pressure levels :: 5
Pressure range :: 4.539993e-05 - 0.13533528 atm
Reading the information in the tables
Once the header of the tables is read, we can also read the cross sections in a specified spectral range and store the data in the Spectroscopy class. Once this is performed, we can plot and analyse the cross sections or perform some other calculations. It must be noted that the cross sections in the pre-tabulated tables are multiplied by a factor of 10\(^{20}\) that must be accounted for by the user.
[3]:
#Reading the information in the lbl-tables in a specified spectral range
Wavemin = 3750.
Wavemax = 3760.
Spectroscopy.read_tables(Wavemin,Wavemax)
#Plotting the cross sections at a given temperature and pressure
gasname = ['']*Spectroscopy.NGAS
for i in range(Spectroscopy.NGAS):
gasname1 = ans.gas_info[str(Spectroscopy.ID[i])]['name']
if Spectroscopy.ISO[i]!=0:
gasname1 = gasname1+' ('+str(Spectroscopy.ISO[i])+')'
gasname[i] = gasname1
#Plotting the cross sections
fig,ax1 = plt.subplots(1,1,figsize=(10,4))
iP = 3
iT = 3
for i in range(Spectroscopy.NGAS):
ax1.plot(Spectroscopy.WAVE,Spectroscopy.K[:,iP,iT,i]*1.0e-20,label=gasname[i])
ax1.set_title('Pressure :: '+str(Spectroscopy.PRESS[iP])+' atm - Temperature :: '+str(Spectroscopy.TEMP[iT])+' K')
ax1.legend()
ax1.set_yscale('log')
ax1.set_ylim(1.0e-25,1.0e-14)
ax1.set_xlim(Spectroscopy.WAVE.min(),Spectroscopy.WAVE.max())
ax1.set_xlabel('Wavelength ($\mu$m)')
ax1.set_ylabel('Absorption cross section (cm$^2$)')
ax1.set_facecolor('lightgray')
ax1.grid()
Calculating the cross sections at an arbitrary temperature or pressure
The cross sections in the pre-tabulated tables are calculated at different levels of pressure and temperature. However, we might need to calculate the cross sections at a different level, which requires an interpolation. There is a function in archNEMESIS to perform this interpolation.
[7]:
NPoints = 2
Press = [0.02,0.1] #Atm
Temp = [128.,173.]
k = Spectroscopy.calc_klbl(NPoints,Press,Temp)
fig,(ax) = plt.subplots(2,1,figsize=(10,5),sharex=True)
for i in range(Spectroscopy.NGAS):
for j in range(NPoints):
ax[i].plot(Spectroscopy.WAVE,k[:,j,i]*1.0e-20,label='Pressure :: '+str(Press[j])+' atm - Temperature :: '+str(Temp[j])+' K')
ax[i].set_yscale('log')
ax[i].set_ylabel('Absorption cross section (cm$^2$)')
ax[i].set_title(gasname[i])
ax[i].legend()
ax[i].grid()
ax[i].set_facecolor('lightgray')
ax[Spectroscopy.NGAS-1].set_xlabel('Wavenumber (cm$^{-1}$)')
plt.tight_layout()
3. Reading the tables from the input files
Similar to the examples we have shown in the two previous sections, we can initialise the Spectroscopy class by reading the inputs files instead. In particular, we can use the built-in functions in the Spectroscopy class to perform this calculations.
Initialising the class from the archNEMESIS HDF5 input file
[12]:
#Initialising the class
Spectroscopy = ans.Spectroscopy_0(ILBL=2)
Spectroscopy.NGAS = 2 #We define two gases in the class
Spectroscopy.LOCATION = ['h2o_lbltab.lta',
'co2_lbltab.lta']
#Writing information into HDF5 file
Spectroscopy.write_hdf5('example_archnemesis')
#Later, we can read this file to read directly the information in the HDF5 file
Spectroscopy = ans.Spectroscopy_0()
Spectroscopy.read_hdf5('example_archnemesis')
Spectroscopy.summary_info()
Calculation type ILBL :: 2 (line-by-line)
Number of radiatively-active gaseous species :: 2
Gaseous species :: ['H2O (1)', 'CO2']
Number of spectral points :: 15001
Wavelength range :: 3750.0 - 3765.0000007124618
Step size :: 0.0010000000474974513
Number of temperature levels :: 5
Temperature range :: 100.0 - 200.0 K
Number of pressure levels :: 5
Pressure range :: 4.539993e-05 - 0.13533528 atm
Initialising the class from the NEMESIS .lls and .kls files
[13]:
#.lls file
#############################################################
#Writing name of the .lls file including the path to the pre-tabulated table
LBLname1 = 'h2o_lbltab.lta'
LBLname2 = 'co2_lbltab.lta'
f = open('example.lls','w')
f.write(LBLname1+' \n')
f.write(LBLname2)
f.close()
#Initialising spectroscopy class with ILBL = 2 (line-by-line)
Spectroscopy = ans.Spectroscopy_0(ILBL=2)
#Reading .lls file
#Note this function just read the headers of the pre-tabulated tables to get some preliminary information
Spectroscopy.read_lls('example')
#Printing summary information
Spectroscopy.summary_info()
#.kls file
#############################################################
print('----------------------------------------------------')
#Writing name of the .kls file including the path to the pre-tabulated table
Kname1 = 'h2o_ktab.kta'
Kname2 = 'co2_ktab.kta'
f = open('example.kls','w')
f.write(Kname1+' \n')
f.write(Kname2)
f.close()
#Initialising spectroscopy class with ILBL = 0 (correlated k)
Spectroscopy = ans.Spectroscopy_0(ILBL=0)
#Reading .kls file
#Note this function just read the headers of the pre-tabulated tables to get some preliminary information
Spectroscopy.read_kls('example')
#Printing summary information
Spectroscopy.summary_info()
Calculation type ILBL :: 2 (line-by-line)
Number of radiatively-active gaseous species :: 2
Gaseous species :: ['H2O (1)', 'CO2']
Number of spectral points :: 15001
Wavelength range :: 3750.0 - 3765.0000007124618
Step size :: 0.0010000000474974513
Number of temperature levels :: 5
Temperature range :: 100.0 - 200.0 K
Number of pressure levels :: 5
Pressure range :: 4.539993e-05 - 0.13533528 atm
----------------------------------------------------
Calculation type ILBL :: 0 (k-distribution)
Number of radiatively-active gaseous species :: 2
Gaseous species :: ['H2O', 'CO2']
Number of g-ordinates :: 10
Number of spectral points :: 351
Wavelength range :: 0.9125000238418579 - 5.287500089034438
Step size :: 0.012500000186264515
Spectral resolution of the k-tables (FWHM) :: 0.02500000037252903
Number of temperature levels :: 5
Temperature range :: 100.0 - 200.0 K
Number of pressure levels :: 5
Pressure range :: 3.0590232e-07 - 0.049787067 atm