Interacting with climt¶
As we saw in the Quickstart section, climt has two kinds of entities for the user to interact with: model components and model state. Here, we will take a closer look at both these elements.
Model State¶
The model state is a dictionary whose keys are names of
quantities and values are sympl DataArrays. The sympl DataArray is
a thin wrapper over the xarray DataArray that makes it units aware. To ensure
model scripts are readable not just by specialists, names
of quantities use the descriptive CF Convention. Only
in the case where the CF Convention names are really
unwieldy, like air_temperature_at_effective_cloud_top_defined_by_infrared_radiation
for
example, we use more convenient names.
DataArrays are a more human-friendly way of handling numerical arrays. DataArrays label the dimensions of an array and provide various mathematical functions which can be directly applied to arrays. sympl DataArrays in addition allow conversion between units, a feature required to allow interoperability between components which expect inputs in different units.
Let’s create a 3-d model state to see how useful DataArrays are:
In [1]: import climt
In [2]: import matplotlib.pyplot as plt
In [3]: import numpy as np
# Create some components
In [4]: radiation = climt.GrayLongwaveRadiation()
In [5]: convection = climt.DryConvectiveAdjustment()
We need to tell climt what the model dimensions are. This is done
by the get_grid
function. This function takes three arguments
which are the number of grid points in the three directions, and
provides a state dictionary containing the definition of a grid.
Passing this grid state dictionary onto get_default_state
makes
climt aware of the dimensions required by the model:
In [6]: grid = climt.get_grid(ny=3, nz=5)
# Get a state dictionary filled with required quantities
# for the components to run
In [7]: state = climt.get_default_state([radiation, convection], grid_state=grid)
In [8]: state['air_temperature']
Out[8]:
<xarray.DataArray 'air_temperature' (mid_levels: 5, lat: 3, lon: 1)>
array([[[290.],
[290.],
[290.]],
[[290.],
[290.],
[290.]],
[[290.],
[290.],
[290.]],
[[290.],
[290.],
[290.]],
[[290.],
[290.],
[290.]]])
Dimensions without coordinates: mid_levels, lat, lon
Attributes:
units: degK
climt does not interpret any of the dimension attributes in
state quantities other than units
. The values and labels of coordinates
are mainly for users and components. For instance, SimplePhysics
requires that the y dimension be called latitude
. So, any
model that uses SimplePhysics
has to label one of the
dimensions as latitude.
As you can see, air_temperature
has
- a uniform value of 290
- coordinates of latitude and mid_levels
- units of degK, which is the notation used in climt (and Sympl) for degrees Kelvin.
It is also fairly easy to change units. The to_units()
method can
be used as below to return a DataArray with the equivalent temperature in degrees Farenheit:
In [9]: state['air_temperature'].to_units('degF')
Out[9]:
<xarray.DataArray 'air_temperature' (mid_levels: 5, lat: 3, lon: 1)>
array([[[62.33],
[62.33],
[62.33]],
[[62.33],
[62.33],
[62.33]],
[[62.33],
[62.33],
[62.33]],
[[62.33],
[62.33],
[62.33]],
[[62.33],
[62.33],
[62.33]]])
Dimensions without coordinates: mid_levels, lat, lon
Attributes:
units: degF
Note
climt always names the vertical coordinate as mid_levels
or interface_levels
,
however, the state dictionary will contain a key corresponding to the name
of the vertical coordinate specified by get_grid
.
As mentioned previously, DataArrays are a user-friendly way of handling numerical or numpy
arrays. The numpy array underlying any DataArray is easily accessed using the values
attribute:
In [10]: type(state['air_temperature'].values)
Out[10]: numpy.ndarray
and can also be modified easily:
In [11]: state['air_temperature'].values[:] = 291
The right hand side can also be any numpy array, as long as it has the same dimensions (or can be broadcasted to the same dimensions) as the current numpy array.
Note
It is recommended to use the syntax ...values[:] = ...
rather than ...values =
...
, as the former modifies the numpy array in-place. In either case, DataArrays check to
ensure the dimensions (or shape) of the new data matches with the current dimensions.
You can perform any of the functions supported by xarray on the model state quantities.
In [12]: state['air_temperature'].sum()
Out[12]:
<xarray.DataArray 'air_temperature' ()>
array(4365.)
You can also directly plot DataArrays:
In [13]: state['air_temperature'].plot()
Out[13]: <matplotlib.collections.QuadMesh at 0x7fd059deb358>
DataArrays are a very powerful way of dealing with array-oriented data, and you should read more about xarray, and not just for using climt!
Model Components¶
Components are representations of physical processes. You can see all available components in climt in the section Components.
All components take some inputs from the model state, and return outputs or tendencies along with diagnostics (if any).
Diagnostics are quantities computed while calculating outputs or tendencies. For example, a radiation component calculates heating rates. However, in the process of calculating these heating rates, it also calculates the radiative flux at each interface level.
# These are the tendencies returned by radiation
In [14]: radiation.tendency_properties
Out[14]: {'air_temperature': {'units': 'degK s^-1'}}
# These are the diagnostics returned by radiation
In [15]: radiation.diagnostic_properties
Out[15]:
{'downwelling_longwave_flux_in_air': {'dims': ['interface_levels', '*'],
'units': 'W m^-2',
'alias': 'lw_down'},
'upwelling_longwave_flux_in_air': {'dims': ['interface_levels', '*'],
'units': 'W m^-2',
'alias': 'lw_up'},
'longwave_heating_rate': {'dims': ['mid_levels', '*'],
'units': 'degK day^-1'}}
# These are the outputs returned by convection
In [16]: convection.output_properties
Out[16]: {'air_temperature': {'units': 'degK'}, 'specific_humidity': {'units': 'kg/kg'}}
# convection returns no diagnostics
In [17]: convection.diagnostic_properties
Out[17]: {}
No component will return both outputs and tendencies. The
tendency of a quantity \(X\) is given by \(\frac{dX}{dt}\), and so
the units of a quantity returned as a tendency will always have per second
as as suffix: i.e, if a component is returning air_temperature
as
a tendency, then its units will be degK/s
.