The Atmospheric State#

The atmospheric state at it’s fundamental core is:

  • Extinction specified on the model geometry grid points.

  • Single scatter albedo specified on the model geometry grid points.

  • (optional) Scattering parameters (Legendre coefficients, phase functions) specified at the model geometry grid points

  • A representation of surface scattering (e.g. Lambertian surface)

It is possible to directly specify these quantities, however the easier way to use the model is through what we refer to as constituents.

Note

SASKTRAN2 is designed to perform efficient calculations for a static geometry and multiple atmospheric states. For this reason all atmospheric optical quantities contain an explicit wavelength dimension. Instead of extinction being a 1-D array at the geometry grid points, it is a 2-D array (wavelength, geometry). We refer to this dimension as the wavelength dimension because that is most commonly what it is, but in reality it can be any dimension where the atmospheric state varies.

Setting the Atmosphere from Constituents#

Most of the time the easiest way to construct the atmosphere is using something that we call the constituent interface. All this means is that the atmosphere is constructed in pieces through objects called constituents rather than all at once. An example constituent could be Rayleigh scattering, or ozone absorption, or a Lambertian surface.

We start by setting up our sasktran2.Atmosphere object

import numpy as np
import sasktran2 as sk

model_geometry = sk.Geometry1D(cos_sza=0.6,
                                solar_azimuth=0,
                                earth_radius_m=6372000,
                                altitude_grid_m=np.arange(0, 65001, 1000),
                                interpolation_method=sk.InterpolationMethod.LinearInterpolation,
                                geometry_type=sk.GeometryType.Spherical)

config = sk.Config()

wavel = np.arange(280.0, 800.0, 0.1)
atmosphere = sk.Atmosphere(model_geometry, config, wavelengths_nm=wavel)

Note that here we have explicity passed the wavelength_nm parameter to the atmospheric state. Most atmospheric constituents require that the wavelength (or wavenumber) is known in order to look up things like cross sections from databases. On the same token, most constituents require that atmospheric temperature and/or pressure is known for similar reasons, we can add that to the atmosphere

sk.climatology.us76.add_us76_standard_atmosphere(atmosphere)

atmosphere.pressure_pa

atmosphere.temperature_k
array([288.15 , 281.65 , 275.15 , 268.66 , 262.17 , 255.68 , 249.19 ,
       242.7  , 236.21 , 229.73 , 223.25 , 221.93 , 220.61 , 219.29 ,
       217.97 , 216.65 , 216.65 , 216.65 , 216.65 , 216.65 , 216.65 ,
       217.63 , 218.61 , 219.59 , 220.57 , 221.55 , 222.542, 223.534,
       224.526, 225.518, 226.51 , 228.894, 231.278, 233.662, 236.046,
       238.43 , 240.814, 243.198, 245.582, 247.966, 250.35 , 252.38 ,
       254.41 , 256.44 , 258.47 , 260.5  , 262.53 , 264.56 , 266.59 ,
       268.62 , 270.65 , 268.287, 265.924, 263.561, 261.198, 258.835,
       256.472, 254.109, 251.746, 249.383, 247.02 , 244.276, 241.532,
       238.788, 236.044, 233.3  ])

In this case we used one of SASKTRAN2’s built in climatologies to set temperature/pressure. Alternatively the properties sasktran2.Atmosphere.pressure_pa and sasktran2.Atmosphere.temperature_k can be directly accessed and set to any user desired values.

Now that our base atmosphere is constructed, we can start adding constituents

atmosphere["rayleigh"] = sk.constituent.Rayleigh()

will add Rayleigh scattering to the atmosphere. If we want to add ozone absorption with a constant VMR profile of 1ppm, we can do,

alt_grid = np.arange(0, 100001, 10000)

atmosphere["ozone"] = sk.constituent.VMRAltitudeAbsorber(
    optical_property=sk.optical.O3DBM(),
    altitudes_m=alt_grid,
    vmr=np.ones_like(alt_grid) * 1e-6
)

There are a few things to pay attention to here. The first is that the altitude grid is different than our global geometry grid. Constituents aren’t limited to being specified on the global geometry grid, interpolation to this grid will be internally performed at some stage though. The second thing is that we provided something known as an optical property. An optical property is, in essence, a database of particle cross sections and possibly scattering properties.

Once a constituent is added to the atmosphere it is possible to access it directly and modify it

atmosphere["ozone"].vmr *= 2

print(atmosphere["ozone"].vmr)
[2.e-06 2.e-06 2.e-06 2.e-06 2.e-06 2.e-06 2.e-06 2.e-06 2.e-06 2.e-06
 2.e-06]

Available Constituents#

sasktran2.constituent.Rayleigh([method, ...])

An implementation of Rayleigh scattering.

sasktran2.constituent.VMRAltitudeAbsorber(...)

An atmospheric constituent that is specified through volume mixing ratio (VMR) on an altitude grid.

sasktran2.constituent.ExtinctionScatterer(...)

A scattering constituent that is defined by a number density on an altitude grid and an optical property

sasktran2.constituent.NumberDensityScatterer(...)

A scattering constituent that is defined by a number density on an altitude grid and an optical property

sasktran2.constituent.GaussianHeightExtinction(...)

A constituent that is defined by a gaussian-shaped extinction profile.

sasktran2.constituent.LambertianSurface(albedo)

A Lambertian surface that is defined by albedo at discrete grid points.