This tutorial shows how to load and save datasets, and also how it can be manipulated.
The pygchem.datasets
module provides functions to load and save CTM datasets:
from pygchem import datasets
NOTE: In the PyGChem development version, this module was previously named datafields
and has been recently renamed to datasets
(4-12-2014).
if
from pygchem import datasets
doesn't work, try
import pygchem.datafields as datasets
to use this notebook.
PyGChem uses Iris (http://scitools.org.uk/iris/) for handling CTM datasets. Iris provides a data abstraction layer that is based on the Climate and Forecast (CF) data model (http://cfconventions.org/) and which allows to isolate analysis and visualisation code from data format specifics. It natively supports read/write access to the (CF)netCDF format. PyGChem currently adds support to the BPCH format and the netCDF files created with the GAMAP routines BPCH2NC and BPCH2COARDS (read access only).
With Iris, a data field (data + metadata) relative to a particular phenomenon is represented by a iris.cube.Cube
object (more info on Iris data strutures here). Iris also supports basic data manipulation operations, such as arithmetic, interpolation, and statistics. This tutorial shows only a few examples. For a more detailled description of these features, see the Iris user guide.
This tutorial uses the datasets created by the 1-year GEOS-Chem benchmark simulations. These are available for download via anonymous FTP from ftp://ftp.as.harvard.edu/gcgrid/geos-chem/.
For running the code cells below, you must specify the root folder of your local copy of these benchmarks:
bmk_root = '/home/bovy/geoschem'
The function pygchem.datasets.load
allows to load the content of a BPCH file or a netCDF file into a list of iris.cube.Cube
objects. This function is just an alias of the iris.load
function. Note that it doesn't load all the data into memory but enough information to select, manipulate and retreive the data.
See the Iris documentation: loading iris cubes for more details.
cd into the 1-year benchmark (v10-01c Run1)
%cd {bmk_root}/1yr_benchmarks/v10-01/v10-01c/Run1
/home/bovy/geoschem/1yr_benchmarks/v10-01/v10-01c/Run1
The line below loads the BPCH file corresponding to the first month of the simulation:
filename = 'bpch/ctm.bpch.v10-01c-geosfp-Run1.20120801'
dataset = datasets.load(filename)
The line below print the list of the 20 lasts data fields of the list (name, units, dimensions and coordinates). Note that the field name may be reformatted during the loading so that it is consistent with the name set by the GAMAP's netCDF writing routines. Note also that the units may also be reformatted as required by the udunits2 library (used by Iris).
print dataset[-20:]
0: WETDLS_S__IEPOX / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 1: WETDLS_S__ISOPN / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 2: WETDLS_S__MAP / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 3: WETDLS_S__MMN / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 4: WETDLS_S__MOBA / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 5: WETDLS_S__MP / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 6: WETDLS_S__MSA / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 7: WETDLS_S__NH3 / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 8: WETDLS_S__NH4 / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 9: WETDLS_S__NIT / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 10: WETDLS_S__NITs / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 11: WETDLS_S__OCPI / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 12: WETDLS_S__OCPO / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 13: WETDLS_S__PROPNN / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 14: WETDLS_S__RIP / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 15: WETDLS_S__SALA / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 16: WETDLS_S__SALC / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 17: WETDLS_S__SO2 / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 18: WETDLS_S__SO4 / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72) 19: WETDLS_S__SO4s / (kg/s) (longitude: 72; latitude: 46; model_level_number: 72)
The same function can be used for loading the content of the netCDF files. The netCDF files available in this simulation were created by the 'BPCH2COARDS' GAMAP routine. As there are differences between the COARDS Conventions and the CF Conventions, we have to use a callback function 'gamap_bpch2coards' to properly load the content of the netCDF file into Iris cubes:
filename = 'netcdf/v10-01c-geosfp-Run1.20120801.nc'
clb = datasets.load_callbacks['gamap_bpch2coards']
dataset = datasets.load(filename, callback=clb)
/home/python/PythonEnvs/pygchem_gitmaster_py27/lib/python2.7/site-packages/iris/fileformats/_pyke_rules/compiled_krb/fc_rules_cf_fc.py:1358: UserWarning: Failed to create 'lon' dimension coordinate: The points array must be strictly monotonic. Gracefully creating 'lon' auxiliary coordinate instead. error=e_msg))
print dataset[-20:]
0: OD_MAP_S__SBC / (cm2/cm3) (-- : 59; latitude: 46; longitude: 72) 1: OD_MAP_S__SD / (cm2/cm3) (-- : 59; latitude: 46; longitude: 72) 2: OD_MAP_S__SOC / (cm2/cm3) (-- : 59; latitude: 46; longitude: 72) 3: OD_MAP_S__SSO4 / (cm2/cm3) (-- : 59; latitude: 46; longitude: 72) 4: OD_MAP_S__SSSa / (cm2/cm3) (-- : 59; latitude: 46; longitude: 72) 5: OD_MAP_S__SSSc / (cm2/cm3) (-- : 59; latitude: 46; longitude: 72) 6: PEDGE_S__PSURF / (mb) (Eta Edges: 73; latitude: 46; longitude: 72) 7: PL_BC_S__BLKC / (kg) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 8: PL_OC_S__ORGC / (kg) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 9: SALTSRCE__SALA / (kg) (latitude: 46; longitude: 72) 10: SALTSRCE__SALC / (kg) (latitude: 46; longitude: 72) 11: SO2_AC_S__SO2 / (kg S) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 12: SO2_AN_S__SO2 / (kg S) (-- : 2; latitude: 46; longitude: 72) 13: SO2_BIOB__SO2 / (kg S) (latitude: 46; longitude: 72) 14: SO2_BIOF__SO2 / (kg S) (latitude: 46; longitude: 72) 15: SO2_EV_S__SO2 / (kg S) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 16: SO2_NV_S__SO2 / (kg S) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 17: SO2_SHIP__SO2 / (kg S) (latitude: 46; longitude: 72) 18: SO4_AN_S__SO4 / (kg S) (-- : 2; latitude: 46; longitude: 72) 19: SO4_BIOF__SO4 / (kg S) (latitude: 46; longitude: 72)
PyGChem also provides a callback for loading netCDF files created by the GAMAP routine 'BPCH2NC':
% cd {bmk_root}/1yr_benchmarks/v9-02/v9-02r/geos5/Run0
/home/bovy/geoschem/1yr_benchmarks/v9-02/v9-02r/geos5/Run0
filename = 'netcdf/v9-02r-geos5-Run0.20050101.nc'
clb = datasets.load_callbacks['gamap_bpch2nc']
dataset = datasets.load(filename, callback=clb)
print dataset[-20:]
0: OD-MAP-S__OPSSc / (1) (-- : 38; latitude: 46; longitude: 72) 1: OD-MAP-S__OPTD / (1) (-- : 38; latitude: 46; longitude: 72) 2: OD-MAP-S__SBC / (cm2/cm3) (-- : 38; latitude: 46; longitude: 72) 3: OD-MAP-S__SD / (cm2/cm3) (-- : 38; latitude: 46; longitude: 72) 4: OD-MAP-S__SOC / (cm2/cm3) (-- : 38; latitude: 46; longitude: 72) 5: OD-MAP-S__SSO4 / (cm2/cm3) (-- : 38; latitude: 46; longitude: 72) 6: OD-MAP-S__SSSa / (cm2/cm3) (-- : 38; latitude: 46; longitude: 72) 7: OD-MAP-S__SSSc / (cm2/cm3) (-- : 38; latitude: 46; longitude: 72) 8: PEDGE-S__PSURF / (mb) (-- : 48; latitude: 46; longitude: 72) 9: SALTSRCE__SALA / (kg) (latitude: 46; longitude: 72) 10: SALTSRCE__SALC / (kg) (latitude: 46; longitude: 72) 11: SO2-AC-S__SO2 / (kg S) (model_level_number: 47; latitude: 46; longitude: 72) 12: SO2-AN-S__SO2 / (kg S) (-- : 2; latitude: 46; longitude: 72) 13: SO2-BIOB__SO2 / (kg S) (latitude: 46; longitude: 72) 14: SO2-BIOF__SO2 / (kg S) (latitude: 46; longitude: 72) 15: SO2-EV-S__SO2 / (kg S) (model_level_number: 47; latitude: 46; longitude: 72) 16: SO2-NV-S__SO2 / (kg S) (model_level_number: 47; latitude: 46; longitude: 72) 17: SO2-SHIP__SO2 / (kg S) (latitude: 46; longitude: 72) 18: SO4-AN-S__SO4 / (kg S) (-- : 2; latitude: 46; longitude: 72) 19: SO4-BIOF__SO4 / (kg S) (latitude: 46; longitude: 72)
%cd {bmk_root}/1yr_benchmarks/v10-01/v10-01c/Run1
/home/bovy/geoschem/1yr_benchmarks/v10-01/v10-01c/Run1
For large datasets, it is possible to constrain the load to match specific metadata or to load only a subset of the data. It is recommended as the loading is faster with given constraints.
The following example loads only the "IJ_AVG_S__O3" variable:
filename = 'netcdf/v10-01c-geosfp-Run1.20120801.nc'
clb = datasets.load_callbacks['gamap_bpch2coards']
dataset = datasets.load(filename, "IJ_AVG_S__O3",
callback=clb)
print dataset
0: IJ_AVG_S__O3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72)
We can specify multiple variables:
dataset = datasets.load(filename, ["IJ_AVG_S__O3", "IJ_AVG_S__NO"],
callback=clb)
print dataset
0: IJ_AVG_S__O3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 1: IJ_AVG_S__NO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72)
It is also possible to define more advanced constraints. For example, to load all "IJ-AVG-$" diagnostics:
import iris
check_ij_avg = lambda cube: cube.name().startswith("IJ_AVG_S")
ij_avg = iris.Constraint(cube_func=check_ij_avg)
dataset = datasets.load(filename, ij_avg,
callback=clb)
print dataset
0: IJ_AVG_S__ACET / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 1: IJ_AVG_S__ALD2 / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 2: IJ_AVG_S__ALK4 / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 3: IJ_AVG_S__BCPI / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 4: IJ_AVG_S__BCPO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 5: IJ_AVG_S__Br / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 6: IJ_AVG_S__Br2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 7: IJ_AVG_S__BrCl / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 8: IJ_AVG_S__BrNO2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 9: IJ_AVG_S__BrNO3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 10: IJ_AVG_S__BrO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 11: IJ_AVG_S__C2H6 / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 12: IJ_AVG_S__C3H8 / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 13: IJ_AVG_S__CCl4 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 14: IJ_AVG_S__CFC11 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 15: IJ_AVG_S__CFC12 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 16: IJ_AVG_S__CFCX / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 17: IJ_AVG_S__CH2Br2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 18: IJ_AVG_S__CH2O / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 19: IJ_AVG_S__CH3Br / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 20: IJ_AVG_S__CH3CCl3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 21: IJ_AVG_S__CH3Cl / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 22: IJ_AVG_S__CH4 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 23: IJ_AVG_S__CHBr3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 24: IJ_AVG_S__CO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 25: IJ_AVG_S__Cl / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 26: IJ_AVG_S__Cl2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 27: IJ_AVG_S__Cl2O2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 28: IJ_AVG_S__ClNO2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 29: IJ_AVG_S__ClNO3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 30: IJ_AVG_S__ClO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 31: IJ_AVG_S__ClOO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 32: IJ_AVG_S__DMS / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 33: IJ_AVG_S__DST1 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 34: IJ_AVG_S__DST2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 35: IJ_AVG_S__DST3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 36: IJ_AVG_S__DST4 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 37: IJ_AVG_S__GLYC / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 38: IJ_AVG_S__H1211 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 39: IJ_AVG_S__H1301 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 40: IJ_AVG_S__H2402 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 41: IJ_AVG_S__H2O / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 42: IJ_AVG_S__H2O2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 43: IJ_AVG_S__HAC / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 44: IJ_AVG_S__HBr / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 45: IJ_AVG_S__HCFC22 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 46: IJ_AVG_S__HCFCX / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 47: IJ_AVG_S__HCl / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 48: IJ_AVG_S__HNO2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 49: IJ_AVG_S__HNO3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 50: IJ_AVG_S__HNO4 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 51: IJ_AVG_S__HOBr / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 52: IJ_AVG_S__HOCl / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 53: IJ_AVG_S__IEPOX / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 54: IJ_AVG_S__ISOP / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 55: IJ_AVG_S__ISOPN / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 56: IJ_AVG_S__MACR / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 57: IJ_AVG_S__MAP / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 58: IJ_AVG_S__MEK / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 59: IJ_AVG_S__MMN / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 60: IJ_AVG_S__MOBA / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 61: IJ_AVG_S__MP / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 62: IJ_AVG_S__MPN / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 63: IJ_AVG_S__MSA / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 64: IJ_AVG_S__MVK / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 65: IJ_AVG_S__N2O / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 66: IJ_AVG_S__N2O5 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 67: IJ_AVG_S__NH3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 68: IJ_AVG_S__NH4 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 69: IJ_AVG_S__NIT / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 70: IJ_AVG_S__NITs / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 71: IJ_AVG_S__NO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 72: IJ_AVG_S__NO2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 73: IJ_AVG_S__NO3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 74: IJ_AVG_S__O3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 75: IJ_AVG_S__OCPI / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 76: IJ_AVG_S__OCPO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 77: IJ_AVG_S__OCS / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 78: IJ_AVG_S__OClO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 79: IJ_AVG_S__PAN / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 80: IJ_AVG_S__PMN / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 81: IJ_AVG_S__PPN / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 82: IJ_AVG_S__PROPNN / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 83: IJ_AVG_S__PRPE / (ppb) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 84: IJ_AVG_S__R4N2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 85: IJ_AVG_S__RCHO / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 86: IJ_AVG_S__RIP / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 87: IJ_AVG_S__SALA / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 88: IJ_AVG_S__SALC / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 89: IJ_AVG_S__SO2 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 90: IJ_AVG_S__SO4 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72) 91: IJ_AVG_S__SO4s / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 72)
A more advanced example, combining constraints and extracting data subsets:
def lon_subset(cell):
"""
return True or False as to whether the cell
center in question should be kept
"""
return cell > 0. and cell < 20.
lon_cst = iris.Constraint(longitude=lon_subset)
dataset = datasets.load(filename,
"IJ_AVG_S__O3" & lon_cst,
callback=clb)
print dataset
# note the reduced grid-size for the longitude
0: IJ_AVG_S__O3 / (ppbv) (atmosphere_hybrid_sigma_pressure_coordinate: 72; latitude: 46; longitude: 3)
It is possible to load multiple files at once. The pygchem.datafields.load
function will try to merge the fields when it is possible, i.e., when the multiple fields describing the same phenomenom overlap in space and/or time, so that it reduces at the minimum the number of loaded fields.
The following example load the "IJ_AVG_S__O3" diagnostic for the entire 1-year simulation:
# note the wildcard character in the filename
# (UNIX expressions are supported)
filename = 'bpch/ctm.bpch.v10-01c-geosfp-Run1.*'
diagnostics = ["BXHGHT_S__BXHEIGHT",
"BXHGHT_S__N(AIR)",
"IJ_AVG_S__NO2"]
dataset = datasets.load(filename, diagnostics)
print dataset
# note the additional time dimension
0: BXHGHT_S__BXHEIGHT / (m) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) 1: BXHGHT_S__N(AIR) / (count/m3) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) 2: IJ_AVG_S__NO2 / (ppbv) (time: 12; longitude: 72; latitude: 46; model_level_number: 72)
Merging fields may take a long time. If speed matters, it is still possible to load the fields without any merging:
dataset_nomerge = datasets.load_raw(filename, diagnostics)
print dataset_nomerge
0: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 1: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 2: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 3: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 4: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 5: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 6: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 7: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 8: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 9: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 10: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 11: BXHGHT_S__BXHEIGHT / (m) (longitude: 72; latitude: 46; model_level_number: 72) 12: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 13: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 14: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 15: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 16: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 17: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 18: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 19: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 20: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 21: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 22: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 23: BXHGHT_S__N(AIR) / (count/m3) (longitude: 72; latitude: 46; model_level_number: 72) 24: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 25: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 26: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 27: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 28: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 29: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 30: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 31: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 32: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 33: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 34: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72) 35: IJ_AVG_S__NO2 / (ppbv) (longitude: 72; latitude: 46; model_level_number: 72)
We can extract data subsets and/or specific fields from a loaded list of fields:
dataset_lon_subset = dataset.extract(lon_cst)
print dataset_lon_subset
0: BXHGHT_S__BXHEIGHT / (m) (time: 12; longitude: 3; latitude: 46; model_level_number: 72) 1: BXHGHT_S__N(AIR) / (count/m3) (time: 12; longitude: 3; latitude: 46; model_level_number: 72) 2: IJ_AVG_S__NO2 / (ppbv) (time: 12; longitude: 3; latitude: 46; model_level_number: 72)
To select only one field (cube), the extract_strict
method can be used:
no2_avg = dataset.extract_strict("IJ_AVG_S__NO2")
print no2_avg
IJ_AVG_S__NO2 / (ppbv) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: time x - - - longitude - x - - latitude - - x - model_level_number - - - x Attributes: ctm_units: ppbv model: GEOSFP
Datasets can be written to a netCDF file (with the CF-conventions) using the function save
of the datafields
module (an alias to the iris.save
function).
outfile = 'netcdf/test.nc'
datasets.save(dataset, outfile)
A text representation of (the header information of) the written netCDF file using the ncdump
utility (provided with the netCDF4 package):
!ncdump -h netcdf/test.nc
netcdf test { dimensions: time = UNLIMITED ; // (12 currently) longitude = 72 ; latitude = 46 ; model_level_number = 72 ; bnds = 2 ; variables: float BXHGHT_S__BXHEIGHT(time, longitude, latitude, model_level_number) ; BXHGHT_S__BXHEIGHT:standard_name = "BXHGHT_S__BXHEIGHT" ; BXHGHT_S__BXHEIGHT:long_name = "Grid box height" ; BXHGHT_S__BXHEIGHT:units = "m" ; BXHGHT_S__BXHEIGHT:ctm_units = "m" ; BXHGHT_S__BXHEIGHT:grid_mapping = "latitude_longitude" ; int latitude_longitude ; latitude_longitude:grid_mapping_name = "latitude_longitude" ; latitude_longitude:longitude_of_prime_meridian = 0. ; latitude_longitude:earth_radius = 6367470. ; double time(time) ; time:axis = "T" ; time:bounds = "time_bnds" ; time:units = "hours since 1985-01-01 00:00:00" ; time:standard_name = "time" ; time:calendar = "standard" ; double time_bnds(time, bnds) ; double longitude(longitude) ; longitude:axis = "X" ; longitude:bounds = "longitude_bnds" ; longitude:units = "degrees_east" ; longitude:standard_name = "longitude" ; double longitude_bnds(longitude, bnds) ; double latitude(latitude) ; latitude:axis = "Y" ; latitude:bounds = "latitude_bnds" ; latitude:units = "degrees_north" ; latitude:standard_name = "latitude" ; double latitude_bnds(latitude, bnds) ; int64 model_level_number(model_level_number) ; model_level_number:units = "1" ; model_level_number:standard_name = "model_level_number" ; float BXHGHT_S__N\(AIR\)(time, longitude, latitude, model_level_number) ; BXHGHT_S__N\(AIR\):standard_name = "BXHGHT_S__N(AIR)" ; BXHGHT_S__N\(AIR\):long_name = "Number density of air" ; BXHGHT_S__N\(AIR\):units = "count/m3" ; BXHGHT_S__N\(AIR\):ctm_units = "molec/m3" ; BXHGHT_S__N\(AIR\):grid_mapping = "latitude_longitude" ; float IJ_AVG_S__NO2(time, longitude, latitude, model_level_number) ; IJ_AVG_S__NO2:standard_name = "IJ_AVG_S__NO2" ; IJ_AVG_S__NO2:long_name = "NO2 tracer" ; IJ_AVG_S__NO2:units = "ppbv" ; IJ_AVG_S__NO2:ctm_units = "ppbv" ; IJ_AVG_S__NO2:grid_mapping = "latitude_longitude" ; // global attributes: :model = "GEOSFP" ; :Conventions = "CF-1.5" ; }
Loading the written file using the load
function:
print datasets.load('netcdf/test.nc')
0: BXHGHT_S__BXHEIGHT / (m) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) 1: BXHGHT_S__N(AIR) / (count/m3) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) 2: IJ_AVG_S__NO2 / (ppbv) (time: 12; longitude: 72; latitude: 46; model_level_number: 72)
It is also possible to write the datasets to the BPCH format, using the low-level function write_bpch
in the module pygchem.io.bpch
(not yet documented).
Print a string representation of the data field (cube):
print no2_avg
IJ_AVG_S__NO2 / (ppbv) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: time x - - - longitude - x - - latitude - - x - model_level_number - - - x Attributes: ctm_units: ppbv model: GEOSFP
Get or set the name(s) of the field with the following function and/or attributes:
no2_avg.name()
'IJ_AVG_S__NO2'
PyGChem considers that the GEOS-Chem variable name (category + tracer) is a standard name, although it is not CF-compliant (i.e., not listed in the standard name table of the udunits package).
no2_avg.standard_name
'IJ_AVG_S__NO2'
long_name
is the full name of the diagnostic
no2_avg.long_name
'NO2 tracer'
var_name
is the (netCDF) variable name
no2_avg.var_name
'IJ_AVG_S__NO2'
Any attribute of the data field is stored in the following dictionary
no2_avg.attributes
{'ctm_units': 'ppbv', 'model': 'GEOSFP'}
Get the field units:
no2_avg.units
Unit('ppbv')
It is easy to change the units of the field (data values are re-computed accordingly):
no2_avg.convert_units('ppmv')
print no2_avg
IJ_AVG_S__NO2 / (ppmv) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: time x - - - longitude - x - - latitude - - x - model_level_number - - - x Attributes: ctm_units: ppbv model: GEOSFP
Retreiving a coordinate by name:
lat_coord = no2_avg.coord('latitude')
Coordinate data and metadata:
lat_coord.points
array([-89., -86., -82., -78., -74., -70., -66., -62., -58., -54., -50., -46., -42., -38., -34., -30., -26., -22., -18., -14., -10., -6., -2., 2., 6., 10., 14., 18., 22., 26., 30., 34., 38., 42., 46., 50., 54., 58., 62., 66., 70., 74., 78., 82., 86., 89.])
lat_coord.bounds
array([[-90., -88.], [-88., -84.], [-84., -80.], [-80., -76.], [-76., -72.], [-72., -68.], [-68., -64.], [-64., -60.], [-60., -56.], [-56., -52.], [-52., -48.], [-48., -44.], [-44., -40.], [-40., -36.], [-36., -32.], [-32., -28.], [-28., -24.], [-24., -20.], [-20., -16.], [-16., -12.], [-12., -8.], [ -8., -4.], [ -4., 0.], [ 0., 4.], [ 4., 8.], [ 8., 12.], [ 12., 16.], [ 16., 20.], [ 20., 24.], [ 24., 28.], [ 28., 32.], [ 32., 36.], [ 36., 40.], [ 40., 44.], [ 44., 48.], [ 48., 52.], [ 52., 56.], [ 56., 60.], [ 60., 64.], [ 64., 68.], [ 68., 72.], [ 72., 76.], [ 76., 80.], [ 80., 84.], [ 84., 88.], [ 88., 90.]])
lat_coord.units
Unit('degrees_north')
The field data can be accessed with the data
attribute. It returns a Numpy array.
It is very easy to manipulate data fields (Iris cubes)
Indexing a cube return a new cube.
print no2_avg
IJ_AVG_S__NO2 / (ppmv) (time: 12; longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: time x - - - longitude - x - - latitude - - x - model_level_number - - - x Attributes: ctm_units: ppbv model: GEOSFP
# Get the first element of the 1st and last dimensions (time and model level number)
no2_avg_t0_l1 = no2_avg[0, :, :, 0]
print no2_avg_t0_l1
IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46) Dimension coordinates: longitude x - latitude - x Scalar coordinates: model_level_number: 1 time: 2012-08-01 00:00:00, bound=(2012-08-01 00:00:00, 2012-09-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP
Note that another way to extract a subset is by applying one or more constraints on the cube (see above).
The slice
method allow iterating over layers or time slices (return a Python generator). The slices can be 1-dimensional or n-dimensional.
The example below generate time slices (returns a 3-d cube for each time slice).
no2_avg_time_slices = no2_avg.slices(['longitude', 'latitude', 'model_level_number'])
for s in no2_avg_time_slices:
print s
IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2012-08-01 00:00:00, bound=(2012-08-01 00:00:00, 2012-09-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2012-09-01 00:00:00, bound=(2012-09-01 00:00:00, 2012-10-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2012-10-01 00:00:00, bound=(2012-10-01 00:00:00, 2012-11-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2012-11-01 00:00:00, bound=(2012-11-01 00:00:00, 2012-12-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2012-12-01 00:00:00, bound=(2012-12-01 00:00:00, 2013-01-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2013-01-01 00:00:00, bound=(2013-01-01 00:00:00, 2013-02-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2013-02-01 00:00:00, bound=(2013-02-01 00:00:00, 2013-03-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2013-03-01 00:00:00, bound=(2013-03-01 00:00:00, 2013-04-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2013-04-01 00:00:00, bound=(2013-04-01 00:00:00, 2013-05-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2013-05-01 00:00:00, bound=(2013-05-01 00:00:00, 2013-06-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2013-06-01 00:00:00, bound=(2013-06-01 00:00:00, 2013-07-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP IJ_AVG_S__NO2 / (ppmv) (longitude: 72; latitude: 46; model_level_number: 72) Dimension coordinates: longitude x - - latitude - x - model_level_number - - x Scalar coordinates: time: 2013-07-01 00:00:00, bound=(2013-07-01 00:00:00, 2013-08-01 00:00:00) Attributes: ctm_units: ppbv model: GEOSFP
The example below calculate the sum over the vertical levels
import iris.analysis
no2_avg_sum_levels = no2_avg.collapsed('model_level_number', iris.analysis.SUM)
print no2_avg_sum_levels
IJ_AVG_S__NO2 / (ppmv) (time: 12; longitude: 72; latitude: 46) Dimension coordinates: time x - - longitude - x - latitude - - x Scalar coordinates: model_level_number: 36, bound=(1, 72) Attributes: ctm_units: ppbv model: GEOSFP Cell methods: sum: model_level_number
/home/python/PythonEnvs/pygchem_gitmaster_py27/lib/python2.7/site-packages/iris/coords.py:954: UserWarning: Collapsing a non-contiguous coordinate. Metadata may not be fully descriptive for 'model_level_number'. warnings.warn(msg.format(self.name()))
The example below calculates the total columns of the tracer for all grid cells and all time slices:
# extract the data fields (cubes) needed to compute the tracer columns
box_heights = dataset.extract_strict("BXHGHT_S__BXHEIGHT")
n_air = dataset.extract_strict("BXHGHT_S__N(AIR)")
# convert units back to ppbv for the NO2 tracer
no2_avg.convert_units('ppbv')
# calculate the columns
no2_avg_columns = (box_heights * n_air * no2_avg).collapsed('model_level_number',
iris.analysis.SUM)
# set name convert units to count/cm2 (count is used for #molecules)
no2_avg_columns.rename("NO2 columns")
no2_avg_columns.convert_units('count/cm2')
# string repr
print no2_avg_columns
NO2 columns / (count/cm2) (time: 12; longitude: 72; latitude: 46) Dimension coordinates: time x - - longitude - x - latitude - - x Scalar coordinates: model_level_number: 36, bound=(1, 72) Cell methods: sum: model_level_number
Iris provides some modules for basic dataset plotting. It is built on top of matplotlib, and it uses the cartopy package for map projections.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import iris.quickplot as qplt
%matplotlib inline
Plot the NO2 total columns for the first time slice:
fig = plt.figure(figsize=(10, 8))
qplt.contourf(no2_avg_columns[0], 15)
plt.gca().coastlines()
<cartopy.mpl.feature_artist.FeatureArtist at 0x7f77d9a4ce90>
A Hovmoller diagram example
import matplotlib.dates as mdates
no2_hovmoller = no2_avg_columns.collapsed('latitude',
iris.analysis.MEAN)
fig = plt.figure(figsize=(10, 8))
qplt.contourf(no2_hovmoller, 20)
# fine control over time axis ticks and labels
plt.gca().yaxis.set_major_locator(mdates.MonthLocator())
plt.gca().yaxis.set_major_formatter(mdates.DateFormatter('%m-%Y'))
plt.gca().set_ylabel("Time")
/home/python/PythonEnvs/pygchem_gitmaster_py27/lib/python2.7/site-packages/iris/cube.py:2750: UserWarning: Collapsing spatial coordinate 'latitude' without weighting warnings.warn(msg.format(coord.name()))
<matplotlib.text.Text at 0x7f77d9491b10>
For loading datasets, Pygchem reads the information stored in the diaginfo.dat
and tracerinfo.dat
files. The module pygchem.diagnostics
provides a basic API for reading / writing these files and handling their contents.
from pygchem import diagnostics
To load a couple of files:
dinfo = diagnostics.CTMDiagnosticInfo(diaginfo_file='diaginfo.dat',
tracerinfo_file='tracerinfo.dat')
A CTMDiagnosticInfo
object contains all information stored in those files. The attributes categories
and diagnostics
contains each record (line) in diaginfo.dat
and tracerinfo.dat
, respectively
dinfo.categories
Key | CTMCategory | |
0 | IJ-AVG-$ | CTMCategory(offset=0, name=IJ-AVG-$, description=Tracer concentration) |
1 | IJ-24H-$ | CTMCategory(offset=0, name=IJ-24H-$, description=24-hr avg tracer conc.) |
2 | INST-MAP | CTMCategory(offset=0, name=INST-MAP, description=Instantaneous tracer) |
3 | IJ-MAX-$ | CTMCategory(offset=0, name=IJ-MAX-$, description=Surface peak concentration) |
4 | ANTHSRCE | CTMCategory(offset=1000, name=ANTHSRCE, description=Anthropogenic emissions) |
5 | BIOFSRCE | CTMCategory(offset=1000, name=BIOFSRCE, description=Biofuel emissions) |
6 | NO-AC-$ | CTMCategory(offset=1000, name=NO-AC-$, description=Aircraft NO) |
7 | NO-AN-$ | CTMCategory(offset=1000, name=NO-AN-$, description=Anthropogenic NO) |
8 | NO-BIOB | CTMCategory(offset=1000, name=NO-BIOB, description=Biomass NO) |
9 | NO-BIOF | CTMCategory(offset=1000, name=NO-BIOF, description=Biofuel NO) |
10 | NO-LI-$ | CTMCategory(offset=1000, name=NO-LI-$, description=Lightning NO) |
11 | NO-SOIL | CTMCategory(offset=1000, name=NO-SOIL, description=Soil NO) |
12 | NO-FERT | CTMCategory(offset=1000, name=NO-FERT, description=Fertilizer NO) |
13 | NO-STRT | CTMCategory(offset=1000, name=NO-STRT, description=Stratopsheric NO) |
14 | INST_COL | CTMCategory(offset=2000, name=INST_COL, description=Instantaneous columns) |
15 | CV-FLX-$ | CTMCategory(offset=3000, name=CV-FLX-$, description=Convective mass flux) |
16 | TURBMC-$ | CTMCategory(offset=3000, name=TURBMC-$, description=PBL mixing mass flux) |
17 | EW-FLX-$ | CTMCategory(offset=3000, name=EW-FLX-$, description=E/W transport flux) |
18 | NS-FLX-$ | CTMCategory(offset=3000, name=NS-FLX-$, description=N/S transport flux) |
19 | UP-FLX-$ | CTMCategory(offset=3000, name=UP-FLX-$, description=Up/down transport flux) |
20 | STRT-FLX | CTMCategory(offset=3000, name=STRT-FLX, description=Flux from stratosphere) |
21 | RN--SRCE | CTMCategory(offset=3000, name=RN--SRCE, description=Rn-Pb-Be source) |
22 | RN-DECAY | CTMCategory(offset=3000, name=RN-DECAY, description=Rn-Pb-Be loss) |
23 | WETDCV-$ | CTMCategory(offset=3000, name=WETDCV-$, description=Conv wet scavenging) |
24 | WETDLS-$ | CTMCategory(offset=3000, name=WETDLS-$, description=Wet deposition) |
25 | MC-FRC-$ | CTMCategory(offset=3000, name=MC-FRC-$, description=Moist conv fraction) |
26 | DMS-BIOG | CTMCategory(offset=4000, name=DMS-BIOG, description=Biogenic DMS) |
27 | DUSTSRCE | CTMCategory(offset=4000, name=DUSTSRCE, description=Dust emission) |
28 | NVOCSRCE | CTMCategory(offset=4000, name=NVOCSRCE, description=NVOC emissions) |
29 | SALTSRCE | CTMCategory(offset=4000, name=SALTSRCE, description=Seasalt emission) |
30 | SO2-AC-$ | CTMCategory(offset=4000, name=SO2-AC-$, description=Aircraft SO2 emissions) |
31 | SO2-AN-$ | CTMCategory(offset=4000, name=SO2-AN-$, description=Anthro SO2 emissions) |
32 | SO2-BIOB | CTMCategory(offset=4000, name=SO2-BIOB, description=Biomass SO2 emissions) |
33 | SO2-BIOF | CTMCategory(offset=4000, name=SO2-BIOF, description=Biofuel SO2 emissions) |
34 | SO2-EV-$ | CTMCategory(offset=4000, name=SO2-EV-$, description=Erup. Volcano SO2) |
35 | SO2-NV-$ | CTMCategory(offset=4000, name=SO2-NV-$, description=Non-Erup. Volcano SO2) |
36 | SO2-SHIP | CTMCategory(offset=4000, name=SO2-SHIP, description=SO2 from ship exhaust) |
37 | SO4-AN-$ | CTMCategory(offset=4000, name=SO4-AN-$, description=Anthro SO4 emissions) |
38 | SO4-BIOF | CTMCategory(offset=4000, name=SO4-BIOF, description=Biofuel SO4 emissions) |
39 | NH3-ANTH | CTMCategory(offset=4000, name=NH3-ANTH, description=Anthro NH3 emissions) |
40 | NH3-NATU | CTMCategory(offset=4000, name=NH3-NATU, description=Natural NH3 emissions) |
41 | NH3-BIOB | CTMCategory(offset=4000, name=NH3-BIOB, description=Biomass NH3 emissions) |
42 | NH3-BIOF | CTMCategory(offset=4000, name=NH3-BIOF, description=Biofuel NH3 emissions) |
43 | TROPO-AV | CTMCategory(offset=4000, name=TROPO-AV, description=Trop avg'd tracer) |
44 | TCMASS-$ | CTMCategory(offset=4000, name=TCMASS-$, description=Tracer mass (kg)) |
45 | PEDGE-$ | CTMCategory(offset=10000, name=PEDGE-$, description=Pressure at level edges) |
46 | PS-PTOP | CTMCategory(offset=10000, name=PS-PTOP, description=Pressure level edges) |
47 | DAO-FLDS | CTMCategory(offset=11000, name=DAO-FLDS, description=GMAO 2-D met fields) |
48 | DAO-3D-$ | CTMCategory(offset=12000, name=DAO-3D-$, description=GMAO 3-D met fields) |
49 | JV-MAP-$ | CTMCategory(offset=13000, name=JV-MAP-$, description=Photolysis rates) |
50 | OD-MAP-$ | CTMCategory(offset=14000, name=OD-MAP-$, description=Optical Depths) |
... | ... | ... |
137 | IJ-PSC-$ | CTMCategory(offset=55000, name=IJ-PSC-$, description=PSC restart file) |
These attributes behave like a Python list, with added key reference and database lookup-like capabilities. Each item of the list coorespond to a record.
# get the 1st category (a Record like object)
cat_ij_avg = dinfo.categories[0]
cat_ij_avg
CTMCategory(offset=0, name=IJ-AVG-$, description=Tracer concentration)
cat_ij_avg.name
'IJ-AVG-$'
cat_ij_avg.offset
0
# convert the record object to a dict
cat_ij_avg.to_dict()
{'description': 'Tracer concentration', 'name': 'IJ-AVG-$', 'offset': 0}
It is aslo possible to filter the data (queries):
# select a category based on its name (key)
dinfo.categories.select_item("NS-FLX-$")
CTMCategory(offset=3000, name=NS-FLX-$, description=N/S transport flux)
# select a diagnostic (tracer) based on its number (key)
dinfo.diagnostics.select_item(11)
CTMDiagnostic(number=11, name=ALD2, full_name=ALD2 tracer, unit=ppbC, scale=1000000000.0, chemical=True, molecular_weight=0.012, hydrocarbon=True, carbon_weight=2)
# select categories based on other attributes
dinfo.categories.select(offset=3000)
Key | CTMCategory | |
0 | CV-FLX-$ | CTMCategory(offset=3000, name=CV-FLX-$, description=Convective mass flux) |
1 | TURBMC-$ | CTMCategory(offset=3000, name=TURBMC-$, description=PBL mixing mass flux) |
2 | EW-FLX-$ | CTMCategory(offset=3000, name=EW-FLX-$, description=E/W transport flux) |
3 | NS-FLX-$ | CTMCategory(offset=3000, name=NS-FLX-$, description=N/S transport flux) |
4 | UP-FLX-$ | CTMCategory(offset=3000, name=UP-FLX-$, description=Up/down transport flux) |
5 | STRT-FLX | CTMCategory(offset=3000, name=STRT-FLX, description=Flux from stratosphere) |
6 | RN--SRCE | CTMCategory(offset=3000, name=RN--SRCE, description=Rn-Pb-Be source) |
7 | RN-DECAY | CTMCategory(offset=3000, name=RN-DECAY, description=Rn-Pb-Be loss) |
8 | WETDCV-$ | CTMCategory(offset=3000, name=WETDCV-$, description=Conv wet scavenging) |
9 | WETDLS-$ | CTMCategory(offset=3000, name=WETDLS-$, description=Wet deposition) |
10 | MC-FRC-$ | CTMCategory(offset=3000, name=MC-FRC-$, description=Moist conv fraction) |
# advanced selection
dinfo.diagnostics.select(lambda d: d.unit == 'ppbC' and d.number > 10)
Key | CTMDiagnostic | |
0 | 11 | CTMDiagnostic(number=11, name=ALD2, full_name=ALD2 tracer, unit=ppbC, scale=1000000000.0, chemical=True, molecular_weight=0.012, hydrocarbon=True, carbon_weight=2) |
1 | 18 | CTMDiagnostic(number=18, name=PRPE, full_name=PRPE tracer, unit=ppbC, scale=1000000000.0, chemical=True, molecular_weight=0.012, hydrocarbon=True, carbon_weight=3) |
2 | 19 | CTMDiagnostic(number=19, name=C3H8, full_name=C3H8 tracer, unit=ppbC, scale=1000000000.0, chemical=True, molecular_weight=0.012, hydrocarbon=True, carbon_weight=3) |
3 | 21 | CTMDiagnostic(number=21, name=C2H6, full_name=C2H6 tracer, unit=ppbC, scale=1000000000.0, chemical=True, molecular_weight=0.012, hydrocarbon=True, carbon_weight=2) |
We can add or remove entries:
new_tracer = diagnostics.CTMDiagnostic(9999, 'NEW', full_name='a new tracer')
dinfo.diagnostics.append(new_tracer)
dinfo.diagnostics[-1]
CTMDiagnostic(number=9999, name=NEW, full_name=a new tracer, unit=unitless, scale=1.0, chemical=True, molecular_weight=0.0, hydrocarbon=False, carbon_weight=0)
# select the new tracer added to the list
s = dinfo.diagnostics.select(9999)
# remove the selected entry
s.selection_remove()
dinfo.diagnostics[-1]
CTMDiagnostic(number=24004, name=N(AIR), full_name=Number density of air, unit=molec/m3, scale=1.0, chemical=False, molecular_weight=0.0, hydrocarbon=False, carbon_weight=1)
Exporting to diaginfo and tracerinfo files:
dinfo.save_diaginfo('diaginfo_test.dat')
dinfo.save_tracerinfo('tracerinfo_test.dat')
--------------------------------------------------------------------------- NotYetImplementedError Traceback (most recent call last) <ipython-input-61-9a028bf8abc0> in <module>() ----> 1 dinfo.save_diaginfo('diaginfo_test.dat') 2 dinfo.save_tracerinfo('tracerinfo_test.dat') /home/bovy/GitRepos/PyGChem/pygchem/diagnostics.pyc in save_diaginfo(self, filename) 127 TODO: 128 """ --> 129 raise NotYetImplementedError() 130 131 def save_tracerinfo(self, filename): NotYetImplementedError: