The atmosphere

The atmosphere in ARTS is represented by three key components: the atmospheric field, the atmospheric field data, and the atmospheric point.

The atmospheric field contains all physical data of the entire atmosphere. Each property of the atmospheric field (temperature field, pressure field, VMR fields, etc.) is stored as an atmospheric field data object, representing the full 3D field of that property. The local state of the atmospheric field is represented by an atmospheric point. An atmospheric point effectively holds the local state of the atmosphere at a specific location.

Key notations:

  • AtmField: The atmospheric field. An instance is in this text named: atm_field.

  • AtmData: The atmospheric field data. An instance is in this text named: atm_data.

  • AtmPoint: The local atmospheric state. An instance is in this text named: atm_point.

Note

This text will also only deal with the core functionality of each of these three classes. For more advanced and supplementary functionality, please see the API documentation of the classes themselves. We will explicitly not cover file handling, data conversion, or other such topics in this text.

The full atmospheric field

An atmospheric field is represented by the class AtmField. It is often presumed in ARTS that it is possible to draw a path through the atmosphere that either hits the top of the atmosphere or the surface of the planet.

The atmospheric field holds a collection of atmospheric field data, AtmData, that can be accessed and modified through a dict-like interface. An atmospheric field has a maximum altitude, top_of_atmosphere, above which it is considered undefined. It has no minimum altitude, instead relying on an external ellipsoid and elevation field to define the surface of the planet below it. The ellipsoid and the elevation field are (often) part of the SurfaceField class and are described in The surface and planet. The atmospheric field can be called as if it were a function taking altitude, latitude, and longitude coordinate arguments to compute or extract the local atmospheric state, AtmPoint.

The core operations on atm_field are:

  • atm_field[key]: Accessing relevant atmospheric field data: AtmData. See Atmospheric field/point data access for more information on what constitutes a valid key

  • atm_field.top_of_atmosphere: The maximum altitude of the atmosphere in meters. This is the altitude above which the atmospheric field is undefined.

  • atm_field(alt, lat, lon): Compute the local atmospheric state (AtmPoint) at the given coordinate. It is an error to call this with alt > atm_field.top_of_atmosphere.

Shorthand graph for atm_field:

digraph g { bgcolor="#00000000"; rankdir = "TD"; ratio = auto; node [ color = "#0271BB" fontcolor = "white" style = "filled,rounded" shape = "rectangle" ]; "Named data" [ label = "atm_field" style = "filled" ]; "Access Operator" [ label = "atm_field[key]" shape = "ellipse" ]; "Data attribute" [ label = "atm_field.top_of_atmosphere" shape = "ellipse" ]; "Call operator" [ label = "atm_field(alt, lat, lon)" shape = "ellipse" ]; "Single type of data" [ label = "AtmData" ]; "The altitude that defines the top of the atmosphere"; "Point-wise state of the atmosphere" [ label = "AtmPoint" ]; "Named data" -> "Access Operator" [ arrowhead = "none" ]; "Named data" -> "Data attribute" [ arrowhead = "none" ]; "Named data" -> "Call operator" [ arrowhead = "none" ]; "Access Operator" -> "Single type of data"; "Call operator" -> "Point-wise state of the atmosphere"; "Data attribute" -> "The altitude that defines the top of the atmosphere"; }

A single atmospheric point

An atmospheric point holds the local state of the atmosphere. This is required for local calculations of radiative transfer properties, such as absorption, scattering, emission, etc. An atmospheric point is represented by an instance of AtmPoint.

The main use on an atmospheric point is to access the local, numerical state of the atmosphere.

The core operations on atm_point are:

Shorthand graph for atm_point:

digraph g { bgcolor="#00000000"; rankdir = "TD"; ratio = auto; node [ color = "#0271BB" fontcolor = "white" style = "filled,rounded" shape = "rectangle" ]; "Named data" [ label = "atm_point" style = "filled" ]; "Access Operator" [ label = "atm_point[key]" shape = "ellipse" ]; "pressure" [ label = "atm_point.pressure" shape = "ellipse" ]; "temperature" [ label = "atm_point.temperature" shape = "ellipse" ]; "mag" [ label = "atm_point.mag" shape = "ellipse" ]; "wind" [ label = "atm_point.wind" shape = "ellipse" ]; "float" [ label = "float" ]; "Vector3" [ label = "Vector3" ]; "Named data" -> "Access Operator" [ arrowhead = "none" ]; "Named data" -> "temperature" [ arrowhead = "none" ]; "Named data" -> "pressure" [ arrowhead = "none" ]; "Named data" -> "mag" [ arrowhead = "none" ]; "Named data" -> "wind" [ arrowhead = "none" ]; "Access Operator" -> "float"; "pressure" -> "float"; "temperature" -> "float"; "mag" -> "Vector3"; "wind" -> "Vector3"; }

Note

The atmospheric point does not know where it is in the atmosphere. This information is only available in the atmospheric field. Positional data must be retained by the user if it is needed for calculations.

Atmospheric field/point data access

The access operator atm_field[key] is used to get and set atmospheric field data (AtmData) in the atmospheric field through the use of types of keys. Likewise, the access operator atm_point[key] is used to get and set data in the atmospheric point, though it deals with pure floating point data. Each type of key is meant to represent a different type of atmospheric data. The following types of keys are available:

  • AtmKey: Basic atmospheric data. Defines temperature [K], pressure [Pa], wind [m/s], and magnetic [T] components.

  • SpeciesEnum: Content of species. This most often means “volume mixing ratio” (VMR) but for historical reasons there are exceptions. VMRs need not sum up to 1 for practical reasons.

  • SpeciesIsotope: Isotopologue ratios. These are ratios of different isotopologues of the same species. As for VMRs they need not sum up to 1 per species for practical reasons. These are defaulted to values extracted from HITRAN, complemented by other sources as necessary.

  • QuantumIdentifier: Non-LTE data. These are the state distributions of energy levels of molecules required for non-LTE calculations.

  • ScatteringSpeciesProperty: Scattering properties of the atmosphere. These are properties of the atmosphere that are relevant for scattering calculations.

Shorthand graph for key of different types:

digraph g { bgcolor="#00000000"; rankdir = "TD"; ratio = auto; node [ color = "#0271BB" fontcolor = "white" style = "filled,rounded" shape = "rectangle" ]; "a0" [ label = "key type" style = "filled" ]; "b0" [ label = "AtmKey" shape = "ellipse" ]; "b1" [ label = "SpeciesEnum" shape = "ellipse" ]; "b2" [ label = "SpeciesIsotope" shape = "ellipse" ]; "b3" [ label = "QuantumIdentifier" shape = "ellipse" ]; "b4" [ label = "ScatteringSpeciesProperty" shape = "ellipse" ]; "c0" [ label = "T, P, Mag, Wind" ]; "c1" [ label = "VMR of O2, H2O, N2, CO2, ..." ]; "c2" [ label = "Isotopologue ratios of O2-66, O2-67, H2O-161, H2O-162, ..." ]; "c3" [ label = "Energy level distributions" ]; "c4" [ label = "Scattering properties" ]; a0 -> b0 [ arrowhead = "none" ]; a0 -> b1 [ arrowhead = "none" ]; a0 -> b2 [ arrowhead = "none" ]; a0 -> b3 [ arrowhead = "none" ]; a0 -> b4 [ arrowhead = "none" ]; b0 -> c0; b1 -> c1; b2 -> c2; b3 -> c3; b4 -> c4; }

Tip

Both atm_field["temperature"] and atm_field[pyarts.arts.AtmKey.temperature] will give the same AtmData back in python. This is because pyarts.arts.AtmKey("temperature") == pyarts.arts.AtmKey.temperature. The same is also true when accessing atm_point, though it gives floating point values.

Note

Using python str instead of the correct type may in very rare circumstances cause name-collisions. Such name-collisions cannot be checked for. If it happens to you, please use the appropriate key type manually to correct the problem.

Atmospheric field data

The atmospheric field data is a core component of the atmospheric field. It is stored in an instance of AtmData. This type holds the entire atmospheric data for a single atmospheric property, such as the full 3D temperature field, the full 3D pressure field, etc. It also holds the logic for how to interpolate and extrapolate this data to any altitude, latitude, and longitude point. As such, atmospheric field data can also be called as if it were a function taking altitude, latitude, and longitude to return the local floating point state of the atmospheric property it holds.

These are the core operations on atm_data:

  • atm_data.data: The core data in variant form. See Data types for what it represents.

  • atm_data.alt_upp: The settings for how to extrapolate above the allowed altitude. What is “allowed” is defined by the data type.

  • atm_data.alt_low: The settings for how to extrapolate below the allowed altitude. What is “allowed” is defined by the data type.

  • atm_data.lat_upp: The settings for how to extrapolate above the allowed latitude. What is “allowed” is defined by the data type.

  • atm_data.lat_low: The settings for how to extrapolate below the allowed latitude. What is “allowed” is defined by the data type.

  • atm_data.lon_upp: The settings for how to extrapolate above the allowed longitude. What is “allowed” is defined by the data type.

  • atm_data.lon_low: The settings for how to extrapolate below the allowed longitude. What is “allowed” is defined by the data type.

  • atm_data(alt, lat, lon): Extract the floating point value of the data at one specific altitude, latitude, and longitude. Returns a single float. Cannot respect the top of the atmosphere because it is not available to the data. Instead, will strictly respect the extrapolation settings.

Shorthand graph:

digraph g { bgcolor="#00000000"; rankdir = "TD"; ratio = auto; node [ color = "#0271BB" fontcolor = "white" style = "filled,rounded" shape = "rectangle" ]; "Named data" [ label = "atm_data" style = "filled" ]; "Data variant" [ label = "atm_data.data" shape = "ellipse" ]; "Extrapolation settings" [ label = <atm_data.alt_upp<BR/>atm_data.alt_low<BR/>atm_data.lat_upp<BR/>atm_data.lat_low<BR/>atm_data.lon_upp<BR/>atm_data.lon_low> shape = "ellipse" ]; "Call operator -> float" [ label = "atm_data(alt, lat, lon)" shape = "ellipse" ]; "The variant data" [ label = "The data type" ]; "Type of extrapolation" [ label = "Extrapolation settings" ]; "float" [ label = "Point-wise data; a float" ]; "Named data" -> "Data variant" [ arrowhead = "none" ]; "Named data" -> "Extrapolation settings" [ arrowhead = "none" ]; "Named data" -> "Call operator -> float" [ arrowhead = "none" ]; "Data variant" -> "The variant data"; "Extrapolation settings" -> "Type of extrapolation"; "Call operator -> float" -> "float"; }

Tip

An AtmData is implicitly constructible from each of the Data types described below. The extrapolation settings will be set to appropriate defaults when an implicit construction takes place. These default settings depend on the type and even available data.

Note

If the extrapolation settings or the data itself cannot be used to extract a value at a point using the call-operator, the AtmData will raise an exception. This is to ensure that the user is aware of the problem. Changing the extrapolation settings will likely fix the immediate problem, but be aware that the consequences of doing so might yield numerical differences from what was originally expected.

Extrapolation rules

The rules for extrapolation is governed by InterpolationExtrapolation. Please see its documentation for more information. Extrapolation happens only outside the grids of the data. Interpreting the data inside a grid is done on a type-by-type basis.

Data types

Below are the types of data that can be stored in the atmospheric data. Each data type has its own rules for how to interpret, interpolate, and extrapolate the data.

Tip

Different atmospheric field data types can be mixed in the same atmospheric field. There are no restrictions on how many types can be used in the same atmospheric field.

Numeric

Numeric data simply means that the atmosphere contains constant data. Extrapolation rules are not relevant for this data type as it is constant everywhere. An example of using Numeric as atmospheric field data is given in the following code block.

import matplotlib.pyplot as plt
import numpy as np
import pyarts

atm_field = pyarts.arts.AtmField(toa=100e3)
atm_field["mag_u"] = 50e-6
atm_field["mag_v"] = 0
atm_field["mag_w"] = 3.14

fig = plt.figure(figsize=(14, 8))
fig, subs = pyarts.plots.AtmField.plot(atm_field, alts=np.linspace(0, 100e3), fig=fig, keys=["mag_u", "mag_v", "mag_w"])
subs[0].set_title("Magnetic profile u-component")
subs[1].set_title("Magnetic profile v-component")
subs[2].set_title("Magnetic profile w-component")
subs[0].set_ylabel("Altitude [m]")
[sub.set_xlabel("Field strength [T]") for sub in subs]
plt.show()

(Source code, svg, pdf)

_images/guide-user-atmospheric_field-1.svg

GriddedField3

If the atmospheric data is of the type GriddedField3, the data is defined on a grid of altitude, latitude, and longitude. It interpolates linearly between the grid points when extracting point-wise data. For sake of this linear interpolation, longitude is treated as a cyclic coordinate. This data type fully respects the rules of extrapolation outside its grid. An example of using GriddedField3 as atmospheric field data is given in the following code block.

import matplotlib.pyplot as plt
import numpy as np
import pyarts

atm_field = pyarts.arts.AtmField(toa=100e3)
atm_field["t"] = pyarts.arts.GriddedField3.fromxml("planets/Earth/afgl/tropical/t.xml")
atm_field["O2"] = pyarts.arts.GriddedField3.fromxml("planets/Earth/afgl/tropical/O2.xml")
atm_field["H2O"] = pyarts.arts.GriddedField3.fromxml("planets/Earth/afgl/tropical/H2O.xml")

fig = plt.figure(figsize=(14, 8))
fig, subs = pyarts.plots.AtmField.plot(atm_field, alts=np.linspace(0, 100e3), fig=fig, keys=["t", "O2", "H2O"])
subs[0].set_title("Temperature profile")
subs[1].set_title("O$_2$ VMR profile")
subs[2].set_title("H$_2$O VMR profile")
subs[0].set_ylabel("Altitude [m]")
subs[0].set_xlabel("Temperature [K]")
subs[1].set_xlabel("O$_2$ VMR [-]")
subs[2].set_xlabel("H$_2$O VMR [-]")
subs[2].set_xscale("log")
plt.show()

(Source code, svg, pdf)

_images/guide-user-atmospheric_field-2.svg

Tip

It is possible to use any number of 1-long grids in a GriddedField3 meant for use as a AtmData. The 1-long grids will by default apply the “nearest” interpolation rule for those grids, potentially reducing the atmospheric data to a 1D profile if only the altitude is given, or even a constant if all three grids are 1-long.

Note

If the GriddedField3 does not cover the full range of the atmosphere, the extrapolation rules will be used to extrapolate it. By default, these rules are set to not allow any extrapolation. This can be changed by setting the extrapolation settings as needed. See headers Extrapolation rules and Atmospheric field data for more information.

NumericTernaryOperator

This operator (NumericTernaryOperator) represents that the atmospheric property is purely a function of altitude, latitude, and longitude. The operator takes three arguments and returns a float. Extrapolation rules are not relevant for this data type as it is a function. An example of using NumericTernaryOperator as atmospheric field data is given in the following code block.

import matplotlib.pyplot as plt
import numpy as np
import pyarts

h = pyarts.arts.GriddedField3.fromxml("planets/Earth/afgl/tropical/p.xml").grids[0]
p = pyarts.arts.GriddedField3.fromxml("planets/Earth/afgl/tropical/p.xml").data.flatten()

def h2p(alt, *args):
    return np.interp(alt, h, p)

atm_field = pyarts.arts.AtmField(toa=100e3)
atm_field["O3"] = lambda alt, lat, lon: 6e-6 if 25e3 < alt < 45e3 else 0
atm_field["p"] = h2p

fig = plt.figure(figsize=(14, 8))
fig, subs = pyarts.plots.AtmField.plot(atm_field, alts=np.linspace(0, 100e3), fig=fig, keys=["O3",'p'])
subs[0].set_title("Ozone profile using lambda-expression")
subs[0].legend().remove()
subs[1].set_title("Pressure profile using python function")
subs[0].set_ylabel("Altitude [m]")
subs[0].set_xlabel("O$_3$ VMR [-]")
subs[1].set_xlabel("Pressure [Pa]")
subs[1].set_xscale("log")
plt.show()

(Source code, svg, pdf)

_images/guide-user-atmospheric_field-3.svg

Tip

Any kind of python function-like object can be used as a NumericTernaryOperator. It must simply take three floats and return another float. If you want to pass in a custom class all you need is to define __call__(self, alt, lat, lon) for it.

Note

Some workspace methods populate parts of the atmospheric field with NumericTernaryOperator objects. One example is atmospheric_fieldIGRF(). These functions are generally faster than manually created NumericTernaryOperator in python. They have 3 advantages: 1) C++ is faster than python, 2) there is no python wrapper overhead for the function call, and 3) we can know if these methods are safe for parallel execution, so we do not need to engage the python GIL.