Generate missing C-grid coordinates¶
Climate model output is usually provided with geometric information like the position of the cell center and boundaries. Gridded observational datasets often lack these informations and provide only the position of either the gridcell center or cell boundary.
This makes the calculation of common vector calculus operators like the gradient difficult, and results depend on the particular method used.
xgcm
can infer the cell boundary or cell center location depending on the geometry of the gridded source dataset. This enables consistent and easily reproducible calculations across model and observational datasets.
The autogenerate module enables the user to apply the same methods to both model output and observational products, which enables better comparison and a unified workflow using different sources of data.
In this case xgcm can infer the missing coordinates to enable the creation of a grid object. Below we will illustrate how to infer coordinates for several example datasets (nonperiodic and periodic) and show how the resulting dataset can be used to perform common calculations like gradients and distance/area weighted averages on observational data.
Non periodic 1D example: Ocean temperature profile¶
First let’s import xarray and xgcm
[1]:
import numpy as np
import xarray as xr
from xgcm import Grid
from xgcm.autogenerate import generate_grid_ds
import matplotlib.pyplot as plt
%matplotlib inline
Below we will create a synthetic temperature profile with decreasing temperature at depth, with unevenly spaced depth intervals (commonly found in hydrographic data).
[2]:
# create a synthetic ocean temperature profile with uneven spacing in depth
z = np.hstack([np.arange(1,10, 1), np.arange(10,200, 10), np.arange(200,700, 20)])
# Create synthetic temperature profile with maximum temperature gradient at mid depth (e.g. the thermocline)
temp = ((np.cos(np.pi*z/700) + 1) + np.exp(-z/350) / 2) * 10
# Convert to xarray.Dataset
ds = xr.DataArray(temp, dims=['depth'], coords={'depth':z}).to_dataset(name='temperature')
ds.temperature.plot(y='depth', yincrease=False)
[2]:
[<matplotlib.lines.Line2D at 0x7fc47e6b6670>]
Infer the cell boundaries using xgcm.autogenerate¶
generate_grid_ds can infer the missing cell positions based on the given position (defaults to cell center) and the axis, which is defined by passing a dictionary with the physical axis as key and the dataset dimensions belonging to that axis as values.
[3]:
# Generate 'full' dataset, which includes additional coordinate `depth_left` and appropriate attributes.
ds_full = generate_grid_ds(ds, {'Z':'depth'})
print(ds_full)
print(ds.depth.data)
print(ds_full.depth_left.data)
<xarray.Dataset>
Dimensions: (depth: 53, depth_left: 53)
Coordinates:
* depth (depth) int64 1 2 3 4 5 6 7 8 ... 560 580 600 620 640 660 680
* depth_left (depth_left) float64 0.5 1.5 2.5 3.5 ... 630.0 650.0 670.0
Data variables:
temperature (depth) float64 24.99 24.97 24.96 24.94 ... 1.164 0.9193 0.7567
[ 1 2 3 4 5 6 7 8 9 10 20 30 40 50 60 70 80 90
100 110 120 130 140 150 160 170 180 190 200 220 240 260 280 300 320 340
360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680]
[5.00e-01 1.50e+00 2.50e+00 3.50e+00 4.50e+00 5.50e+00 6.50e+00 7.50e+00
8.50e+00 9.50e+00 1.50e+01 2.50e+01 3.50e+01 4.50e+01 5.50e+01 6.50e+01
7.50e+01 8.50e+01 9.50e+01 1.05e+02 1.15e+02 1.25e+02 1.35e+02 1.45e+02
1.55e+02 1.65e+02 1.75e+02 1.85e+02 1.95e+02 2.10e+02 2.30e+02 2.50e+02
2.70e+02 2.90e+02 3.10e+02 3.30e+02 3.50e+02 3.70e+02 3.90e+02 4.10e+02
4.30e+02 4.50e+02 4.70e+02 4.90e+02 5.10e+02 5.30e+02 5.50e+02 5.70e+02
5.90e+02 6.10e+02 6.30e+02 6.50e+02 6.70e+02]
We see now that a new dimension depth_left
was created, with cell boundaries shifted towards the surface
The default behaviour of generate_grid_ds is to extrapolate the grid position to the ‘left’ (e.g. towards the surface for a depth profile), assuming that the spacing in the two cells closest to the boundary (here: the first and second cell) is equal. Particular geometries might require adjustments of the boundary treatment, by specifying e.g. pad=0
to ensure the topmost cell boundary is located at the sea surface.
Finally we can create the xgcm.Grid object like we would from model output (see for example here)
[4]:
# Create grid object
grid = Grid(ds_full, periodic=False)
print(grid)
<xgcm.Grid>
Z Axis (not periodic, boundary=None):
* center depth --> left
* left depth_left --> center
Calculate vertical gradient¶
Now we have all the tools we need to calculate the vertical gradient just like with numerical model output
[5]:
# Calculate vertical distances located on the cellboundary
ds_full.coords['dzc'] = grid.diff(ds_full.depth, 'Z', boundary='extrapolate')
# Calculate vertical distances located on the cellcenter
ds_full.coords['dzt'] = grid.diff(ds_full.depth_left, 'Z', boundary='extrapolate')
[6]:
# note that the temperature gradient is located on the `depth_left` dimension,
# but no temperature information is available, to infer the gradient in the topmost grid cell.
# The following will pad with nan towards the surface. Alternatively the values could be padded with
# with a particular value or linearly extrapolated.
dtemp_dz = grid.diff(ds.temperature, 'Z', boundary='fill', fill_value=np.nan) / ds_full.dzc
print(dtemp_dz)
fig, ax1 = plt.subplots()
ax1.invert_yaxis()
ax2 = ax1.twiny()
ds.temperature.plot(ax=ax1, y='depth', color='C0')
ax1.set_xlabel('temperature [deg C]', color='C0')
dtemp_dz.plot(ax=ax2, y='depth_left', color='C1')
ax2.set_xlabel('vertical temperature gradient [deg C / m]', color='C1');
<xarray.DataArray (depth_left: 53)>
array([ nan, -0.01452675, -0.01468758, -0.01484852, -0.01500955,
-0.01517068, -0.01533191, -0.01549322, -0.01565462, -0.01581609,
-0.01670564, -0.01832588, -0.01994686, -0.02156426, -0.02317378,
-0.02477119, -0.02635229, -0.02791296, -0.02944913, -0.03095681,
-0.03243211, -0.0338712 , -0.03527037, -0.03662601, -0.0379346 ,
-0.03919276, -0.04039723, -0.04154487, -0.04263268, -0.04413764,
-0.04591988, -0.04741622, -0.04860995, -0.04948706, -0.05003634,
-0.05024945, -0.05012097, -0.04964842, -0.04883232, -0.04767612,
-0.04618617, -0.04437168, -0.04224465, -0.0398197 , -0.03711403,
-0.0341472 , -0.030941 , -0.02751928, -0.02390771, -0.02013362,
-0.01622573, -0.01221393, -0.00812903])
Coordinates:
* depth_left (depth_left) float64 0.5 1.5 2.5 3.5 ... 610.0 630.0 650.0 670.0
dzc (depth_left) int64 1 1 1 1 1 1 1 1 1 ... 20 20 20 20 20 20 20 20
[6]:
Text(0.5, 0, 'vertical temperature gradient [deg C / m]')
Depth weighted average¶
Another common operation for many climate datasets is a weighted mean along an unevenly spaced dimension. Using the grid spacing for the tracer cells earlier this becomes trivial.
[7]:
mean_temp = ds_full.temperature.mean('depth')
mean_temp_weighted = (ds_full.temperature * ds_full.dzt).sum('depth') / ds_full.dzt.sum('depth')
print(mean_temp.data)
print(mean_temp_weighted.data)
16.271481181388435
12.320585088179214
Periodic 2D example¶
Below we will show how to apply these methods similarly to a global surface wind field, which is periodic in the longitudinal (‘x’) direction. The dataset is stored in a zenodo archive.
[8]:
# download the data
import urllib.request
import shutil
url = 'https://zenodo.org/record/4421428/files/'
file_name = 'uvwnd.10m.gauss.2018.nc'
with urllib.request.urlopen(url + file_name) as response, open(file_name, 'wb') as out_file:
shutil.copyfileobj(response, out_file)
# open the data
ds = xr.open_dataset(file_name)
ds
[8]:
<xarray.Dataset> Dimensions: (lat: 94, lon: 192, nbnds: 2, time: 71) Coordinates: * lat (lat) float32 88.542 86.6531 84.7532 ... -86.6531 -88.542 * lon (lon) float32 0.0 1.875 3.75 5.625 ... 354.375 356.25 358.125 * time (time) datetime64[ns] 2018-01-01 2018-01-02 ... 2018-03-12 Dimensions without coordinates: nbnds Data variables: uwnd (time, lat, lon) float32 ... time_bnds (time, nbnds) float64 1.911e+06 1.911e+06 ... 1.913e+06 1.913e+06 vwnd (time, lat, lon) float32 ... Attributes: Conventions: COARDS title: mean daily NMC reanalysis (2014) history: created 2017/12 by Hoop (netCDF2.3) description: Data is from NMC initialized reanalysis\n(4x/day). It co... platform: Model References: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reana... dataset_title: NCEP-NCAR Reanalysis 1
- lat: 94
- lon: 192
- nbnds: 2
- time: 71
- lat(lat)float3288.542 86.6531 ... -86.6531 -88.542
- units :
- degrees_north
- actual_range :
- [ 88.542 -88.542]
- long_name :
- Latitude
- standard_name :
- latitude
- axis :
- Y
array([ 88.542 , 86.6531 , 84.7532 , 82.8508 , 80.9473 , 79.0435 , 77.1394 , 75.2351 , 73.3307 , 71.4262 , 69.5217 , 67.6171 , 65.7125 , 63.8079 , 61.9033 , 59.9986 , 58.0939 , 56.1893 , 54.2846 , 52.3799 , 50.4752 , 48.5705 , 46.6658 , 44.7611 , 42.8564 , 40.9517 , 39.047 , 37.1422 , 35.2375 , 33.3328 , 31.4281 , 29.5234 , 27.6186 , 25.7139 , 23.8092 , 21.9044 , 19.9997 , 18.095 , 16.1902 , 14.2855 , 12.3808 , 10.47604 , 8.57131 , 6.66657 , 4.76184 , 2.8571 , 0.952368, -0.952368, -2.8571 , -4.76184 , -6.66657 , -8.57131 , -10.47604 , -12.3808 , -14.2855 , -16.1902 , -18.095 , -19.9997 , -21.9044 , -23.8092 , -25.7139 , -27.6186 , -29.5234 , -31.4281 , -33.3328 , -35.2375 , -37.1422 , -39.047 , -40.9517 , -42.8564 , -44.7611 , -46.6658 , -48.5705 , -50.4752 , -52.3799 , -54.2846 , -56.1893 , -58.0939 , -59.9986 , -61.9033 , -63.8079 , -65.7125 , -67.6171 , -69.5217 , -71.4262 , -73.3307 , -75.2351 , -77.1394 , -79.0435 , -80.9473 , -82.8508 , -84.7532 , -86.6531 , -88.542 ], dtype=float32)
- lon(lon)float320.0 1.875 3.75 ... 356.25 358.125
- units :
- degrees_east
- long_name :
- Longitude
- actual_range :
- [ 0. 358.125]
- standard_name :
- longitude
- axis :
- X
array([ 0. , 1.875, 3.75 , 5.625, 7.5 , 9.375, 11.25 , 13.125, 15. , 16.875, 18.75 , 20.625, 22.5 , 24.375, 26.25 , 28.125, 30. , 31.875, 33.75 , 35.625, 37.5 , 39.375, 41.25 , 43.125, 45. , 46.875, 48.75 , 50.625, 52.5 , 54.375, 56.25 , 58.125, 60. , 61.875, 63.75 , 65.625, 67.5 , 69.375, 71.25 , 73.125, 75. , 76.875, 78.75 , 80.625, 82.5 , 84.375, 86.25 , 88.125, 90. , 91.875, 93.75 , 95.625, 97.5 , 99.375, 101.25 , 103.125, 105. , 106.875, 108.75 , 110.625, 112.5 , 114.375, 116.25 , 118.125, 120. , 121.875, 123.75 , 125.625, 127.5 , 129.375, 131.25 , 133.125, 135. , 136.875, 138.75 , 140.625, 142.5 , 144.375, 146.25 , 148.125, 150. , 151.875, 153.75 , 155.625, 157.5 , 159.375, 161.25 , 163.125, 165. , 166.875, 168.75 , 170.625, 172.5 , 174.375, 176.25 , 178.125, 180. , 181.875, 183.75 , 185.625, 187.5 , 189.375, 191.25 , 193.125, 195. , 196.875, 198.75 , 200.625, 202.5 , 204.375, 206.25 , 208.125, 210. , 211.875, 213.75 , 215.625, 217.5 , 219.375, 221.25 , 223.125, 225. , 226.875, 228.75 , 230.625, 232.5 , 234.375, 236.25 , 238.125, 240. , 241.875, 243.75 , 245.625, 247.5 , 249.375, 251.25 , 253.125, 255. , 256.875, 258.75 , 260.625, 262.5 , 264.375, 266.25 , 268.125, 270. , 271.875, 273.75 , 275.625, 277.5 , 279.375, 281.25 , 283.125, 285. , 286.875, 288.75 , 290.625, 292.5 , 294.375, 296.25 , 298.125, 300. , 301.875, 303.75 , 305.625, 307.5 , 309.375, 311.25 , 313.125, 315. , 316.875, 318.75 , 320.625, 322.5 , 324.375, 326.25 , 328.125, 330. , 331.875, 333.75 , 335.625, 337.5 , 339.375, 341.25 , 343.125, 345. , 346.875, 348.75 , 350.625, 352.5 , 354.375, 356.25 , 358.125], dtype=float32)
- time(time)datetime64[ns]2018-01-01 ... 2018-03-12
- long_name :
- Time
- delta_t :
- 0000-00-01 00:00:00
- standard_name :
- time
- axis :
- T
- avg_period :
- 0000-00-01 00:00:00
- coordinate_defines :
- start
- actual_range :
- [1910952. 1912632.]
array(['2018-01-01T00:00:00.000000000', '2018-01-02T00:00:00.000000000', '2018-01-03T00:00:00.000000000', '2018-01-04T00:00:00.000000000', '2018-01-05T00:00:00.000000000', '2018-01-06T00:00:00.000000000', '2018-01-07T00:00:00.000000000', '2018-01-08T00:00:00.000000000', '2018-01-09T00:00:00.000000000', '2018-01-10T00:00:00.000000000', '2018-01-11T00:00:00.000000000', '2018-01-12T00:00:00.000000000', '2018-01-13T00:00:00.000000000', '2018-01-14T00:00:00.000000000', '2018-01-15T00:00:00.000000000', '2018-01-16T00:00:00.000000000', '2018-01-17T00:00:00.000000000', '2018-01-18T00:00:00.000000000', '2018-01-19T00:00:00.000000000', '2018-01-20T00:00:00.000000000', '2018-01-21T00:00:00.000000000', '2018-01-22T00:00:00.000000000', '2018-01-23T00:00:00.000000000', '2018-01-24T00:00:00.000000000', '2018-01-25T00:00:00.000000000', '2018-01-26T00:00:00.000000000', '2018-01-27T00:00:00.000000000', '2018-01-28T00:00:00.000000000', '2018-01-29T00:00:00.000000000', '2018-01-30T00:00:00.000000000', '2018-01-31T00:00:00.000000000', '2018-02-01T00:00:00.000000000', '2018-02-02T00:00:00.000000000', '2018-02-03T00:00:00.000000000', '2018-02-04T00:00:00.000000000', '2018-02-05T00:00:00.000000000', '2018-02-06T00:00:00.000000000', '2018-02-07T00:00:00.000000000', '2018-02-08T00:00:00.000000000', '2018-02-09T00:00:00.000000000', '2018-02-10T00:00:00.000000000', '2018-02-11T00:00:00.000000000', '2018-02-12T00:00:00.000000000', '2018-02-13T00:00:00.000000000', '2018-02-14T00:00:00.000000000', '2018-02-15T00:00:00.000000000', '2018-02-16T00:00:00.000000000', '2018-02-17T00:00:00.000000000', '2018-02-18T00:00:00.000000000', '2018-02-19T00:00:00.000000000', '2018-02-20T00:00:00.000000000', '2018-02-21T00:00:00.000000000', '2018-02-22T00:00:00.000000000', '2018-02-23T00:00:00.000000000', '2018-02-24T00:00:00.000000000', '2018-02-25T00:00:00.000000000', '2018-02-26T00:00:00.000000000', '2018-02-27T00:00:00.000000000', '2018-02-28T00:00:00.000000000', '2018-03-01T00:00:00.000000000', '2018-03-02T00:00:00.000000000', '2018-03-03T00:00:00.000000000', '2018-03-04T00:00:00.000000000', '2018-03-05T00:00:00.000000000', '2018-03-06T00:00:00.000000000', '2018-03-07T00:00:00.000000000', '2018-03-08T00:00:00.000000000', '2018-03-09T00:00:00.000000000', '2018-03-10T00:00:00.000000000', '2018-03-11T00:00:00.000000000', '2018-03-12T00:00:00.000000000'], dtype='datetime64[ns]')
- uwnd(time, lat, lon)float32...
- long_name :
- mean Daily u-wind at 10 m
- units :
- m/s
- precision :
- 2
- GRIB_id :
- 33
- GRIB_name :
- U GRD
- var_desc :
- u-wind
- dataset :
- NCEP Reanalysis Daily Averages
- level_desc :
- 10 m
- statistic :
- Mean
- parent_stat :
- Individual Obs
- valid_range :
- [-102.2 102.2]
- actual_range :
- [-21. 25.8]
[1281408 values with dtype=float32]
- time_bnds(time, nbnds)float64...
array([[1910952., 1910976.], [1910976., 1911000.], [1911000., 1911024.], [1911024., 1911048.], [1911048., 1911072.], [1911072., 1911096.], [1911096., 1911120.], [1911120., 1911144.], [1911144., 1911168.], [1911168., 1911192.], [1911192., 1911216.], [1911216., 1911240.], [1911240., 1911264.], [1911264., 1911288.], [1911288., 1911312.], [1911312., 1911336.], [1911336., 1911360.], [1911360., 1911384.], [1911384., 1911408.], [1911408., 1911432.], [1911432., 1911456.], [1911456., 1911480.], [1911480., 1911504.], [1911504., 1911528.], [1911528., 1911552.], [1911552., 1911576.], [1911576., 1911600.], [1911600., 1911624.], [1911624., 1911648.], [1911648., 1911672.], [1911672., 1911696.], [1911696., 1911720.], [1911720., 1911744.], [1911744., 1911768.], [1911768., 1911792.], [1911792., 1911816.], [1911816., 1911840.], [1911840., 1911864.], [1911864., 1911888.], [1911888., 1911912.], [1911912., 1911936.], [1911936., 1911960.], [1911960., 1911984.], [1911984., 1912008.], [1912008., 1912032.], [1912032., 1912056.], [1912056., 1912080.], [1912080., 1912104.], [1912104., 1912128.], [1912128., 1912152.], [1912152., 1912176.], [1912176., 1912200.], [1912200., 1912224.], [1912224., 1912248.], [1912248., 1912272.], [1912272., 1912296.], [1912296., 1912320.], [1912320., 1912344.], [1912344., 1912368.], [1912368., 1912392.], [1912392., 1912416.], [1912416., 1912440.], [1912440., 1912464.], [1912464., 1912488.], [1912488., 1912512.], [1912512., 1912536.], [1912536., 1912560.], [1912560., 1912584.], [1912584., 1912608.], [1912608., 1912632.], [1912632., 1912656.]])
- vwnd(time, lat, lon)float32...
- long_name :
- mean Daily v-wind at 10 m
- units :
- m/s
- precision :
- 2
- GRIB_id :
- 34
- GRIB_name :
- V GRD
- var_desc :
- v-wind
- dataset :
- NCEP Reanalysis Daily Averages
- level_desc :
- 10 m
- statistic :
- Mean
- parent_stat :
- Individual Obs
- valid_range :
- [-102.2 102.2]
- actual_range :
- [-24.2 24.075]
[1281408 values with dtype=float32]
- Conventions :
- COARDS
- title :
- mean daily NMC reanalysis (2014)
- history :
- created 2017/12 by Hoop (netCDF2.3)
- description :
- Data is from NMC initialized reanalysis (4x/day). It consists of T62 variables interpolated to pressure surfaces from model (sigma) surfaces.
- platform :
- Model
- References :
- http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html
- dataset_title :
- NCEP-NCAR Reanalysis 1
[9]:
ds_full = generate_grid_ds(ds, {'X':'lon', 'Y':'lat'})
ds_full
[9]:
<xarray.Dataset> Dimensions: (lat: 94, lat_left: 94, lon: 192, lon_left: 192, nbnds: 2, time: 71) Coordinates: * lat (lat) float32 88.542 86.6531 84.7532 ... -86.6531 -88.542 * lon (lon) float32 0.0 1.875 3.75 5.625 ... 354.375 356.25 358.125 * time (time) datetime64[ns] 2018-01-01 2018-01-02 ... 2018-03-12 * lon_left (lon_left) float32 -0.9375 0.9375 2.8125 ... 355.3125 357.1875 * lat_left (lat_left) float32 89.48645 87.59755 ... -85.70315 -87.59755 Dimensions without coordinates: nbnds Data variables: uwnd (time, lat, lon) float32 ... time_bnds (time, nbnds) float64 1.911e+06 1.911e+06 ... 1.913e+06 1.913e+06 vwnd (time, lat, lon) float32 ... Attributes: Conventions: COARDS title: mean daily NMC reanalysis (2014) history: created 2017/12 by Hoop (netCDF2.3) description: Data is from NMC initialized reanalysis\n(4x/day). It co... platform: Model References: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reana... dataset_title: NCEP-NCAR Reanalysis 1
- lat: 94
- lat_left: 94
- lon: 192
- lon_left: 192
- nbnds: 2
- time: 71
- lat(lat)float3288.542 86.6531 ... -86.6531 -88.542
- units :
- degrees_north
- actual_range :
- [ 88.542 -88.542]
- long_name :
- Latitude
- standard_name :
- latitude
- axis :
- Y
array([ 88.542 , 86.6531 , 84.7532 , 82.8508 , 80.9473 , 79.0435 , 77.1394 , 75.2351 , 73.3307 , 71.4262 , 69.5217 , 67.6171 , 65.7125 , 63.8079 , 61.9033 , 59.9986 , 58.0939 , 56.1893 , 54.2846 , 52.3799 , 50.4752 , 48.5705 , 46.6658 , 44.7611 , 42.8564 , 40.9517 , 39.047 , 37.1422 , 35.2375 , 33.3328 , 31.4281 , 29.5234 , 27.6186 , 25.7139 , 23.8092 , 21.9044 , 19.9997 , 18.095 , 16.1902 , 14.2855 , 12.3808 , 10.47604 , 8.57131 , 6.66657 , 4.76184 , 2.8571 , 0.952368, -0.952368, -2.8571 , -4.76184 , -6.66657 , -8.57131 , -10.47604 , -12.3808 , -14.2855 , -16.1902 , -18.095 , -19.9997 , -21.9044 , -23.8092 , -25.7139 , -27.6186 , -29.5234 , -31.4281 , -33.3328 , -35.2375 , -37.1422 , -39.047 , -40.9517 , -42.8564 , -44.7611 , -46.6658 , -48.5705 , -50.4752 , -52.3799 , -54.2846 , -56.1893 , -58.0939 , -59.9986 , -61.9033 , -63.8079 , -65.7125 , -67.6171 , -69.5217 , -71.4262 , -73.3307 , -75.2351 , -77.1394 , -79.0435 , -80.9473 , -82.8508 , -84.7532 , -86.6531 , -88.542 ], dtype=float32)
- lon(lon)float320.0 1.875 3.75 ... 356.25 358.125
- units :
- degrees_east
- long_name :
- Longitude
- actual_range :
- [ 0. 358.125]
- standard_name :
- longitude
- axis :
- X
array([ 0. , 1.875, 3.75 , 5.625, 7.5 , 9.375, 11.25 , 13.125, 15. , 16.875, 18.75 , 20.625, 22.5 , 24.375, 26.25 , 28.125, 30. , 31.875, 33.75 , 35.625, 37.5 , 39.375, 41.25 , 43.125, 45. , 46.875, 48.75 , 50.625, 52.5 , 54.375, 56.25 , 58.125, 60. , 61.875, 63.75 , 65.625, 67.5 , 69.375, 71.25 , 73.125, 75. , 76.875, 78.75 , 80.625, 82.5 , 84.375, 86.25 , 88.125, 90. , 91.875, 93.75 , 95.625, 97.5 , 99.375, 101.25 , 103.125, 105. , 106.875, 108.75 , 110.625, 112.5 , 114.375, 116.25 , 118.125, 120. , 121.875, 123.75 , 125.625, 127.5 , 129.375, 131.25 , 133.125, 135. , 136.875, 138.75 , 140.625, 142.5 , 144.375, 146.25 , 148.125, 150. , 151.875, 153.75 , 155.625, 157.5 , 159.375, 161.25 , 163.125, 165. , 166.875, 168.75 , 170.625, 172.5 , 174.375, 176.25 , 178.125, 180. , 181.875, 183.75 , 185.625, 187.5 , 189.375, 191.25 , 193.125, 195. , 196.875, 198.75 , 200.625, 202.5 , 204.375, 206.25 , 208.125, 210. , 211.875, 213.75 , 215.625, 217.5 , 219.375, 221.25 , 223.125, 225. , 226.875, 228.75 , 230.625, 232.5 , 234.375, 236.25 , 238.125, 240. , 241.875, 243.75 , 245.625, 247.5 , 249.375, 251.25 , 253.125, 255. , 256.875, 258.75 , 260.625, 262.5 , 264.375, 266.25 , 268.125, 270. , 271.875, 273.75 , 275.625, 277.5 , 279.375, 281.25 , 283.125, 285. , 286.875, 288.75 , 290.625, 292.5 , 294.375, 296.25 , 298.125, 300. , 301.875, 303.75 , 305.625, 307.5 , 309.375, 311.25 , 313.125, 315. , 316.875, 318.75 , 320.625, 322.5 , 324.375, 326.25 , 328.125, 330. , 331.875, 333.75 , 335.625, 337.5 , 339.375, 341.25 , 343.125, 345. , 346.875, 348.75 , 350.625, 352.5 , 354.375, 356.25 , 358.125], dtype=float32)
- time(time)datetime64[ns]2018-01-01 ... 2018-03-12
- long_name :
- Time
- delta_t :
- 0000-00-01 00:00:00
- standard_name :
- time
- axis :
- T
- avg_period :
- 0000-00-01 00:00:00
- coordinate_defines :
- start
- actual_range :
- [1910952. 1912632.]
array(['2018-01-01T00:00:00.000000000', '2018-01-02T00:00:00.000000000', '2018-01-03T00:00:00.000000000', '2018-01-04T00:00:00.000000000', '2018-01-05T00:00:00.000000000', '2018-01-06T00:00:00.000000000', '2018-01-07T00:00:00.000000000', '2018-01-08T00:00:00.000000000', '2018-01-09T00:00:00.000000000', '2018-01-10T00:00:00.000000000', '2018-01-11T00:00:00.000000000', '2018-01-12T00:00:00.000000000', '2018-01-13T00:00:00.000000000', '2018-01-14T00:00:00.000000000', '2018-01-15T00:00:00.000000000', '2018-01-16T00:00:00.000000000', '2018-01-17T00:00:00.000000000', '2018-01-18T00:00:00.000000000', '2018-01-19T00:00:00.000000000', '2018-01-20T00:00:00.000000000', '2018-01-21T00:00:00.000000000', '2018-01-22T00:00:00.000000000', '2018-01-23T00:00:00.000000000', '2018-01-24T00:00:00.000000000', '2018-01-25T00:00:00.000000000', '2018-01-26T00:00:00.000000000', '2018-01-27T00:00:00.000000000', '2018-01-28T00:00:00.000000000', '2018-01-29T00:00:00.000000000', '2018-01-30T00:00:00.000000000', '2018-01-31T00:00:00.000000000', '2018-02-01T00:00:00.000000000', '2018-02-02T00:00:00.000000000', '2018-02-03T00:00:00.000000000', '2018-02-04T00:00:00.000000000', '2018-02-05T00:00:00.000000000', '2018-02-06T00:00:00.000000000', '2018-02-07T00:00:00.000000000', '2018-02-08T00:00:00.000000000', '2018-02-09T00:00:00.000000000', '2018-02-10T00:00:00.000000000', '2018-02-11T00:00:00.000000000', '2018-02-12T00:00:00.000000000', '2018-02-13T00:00:00.000000000', '2018-02-14T00:00:00.000000000', '2018-02-15T00:00:00.000000000', '2018-02-16T00:00:00.000000000', '2018-02-17T00:00:00.000000000', '2018-02-18T00:00:00.000000000', '2018-02-19T00:00:00.000000000', '2018-02-20T00:00:00.000000000', '2018-02-21T00:00:00.000000000', '2018-02-22T00:00:00.000000000', '2018-02-23T00:00:00.000000000', '2018-02-24T00:00:00.000000000', '2018-02-25T00:00:00.000000000', '2018-02-26T00:00:00.000000000', '2018-02-27T00:00:00.000000000', '2018-02-28T00:00:00.000000000', '2018-03-01T00:00:00.000000000', '2018-03-02T00:00:00.000000000', '2018-03-03T00:00:00.000000000', '2018-03-04T00:00:00.000000000', '2018-03-05T00:00:00.000000000', '2018-03-06T00:00:00.000000000', '2018-03-07T00:00:00.000000000', '2018-03-08T00:00:00.000000000', '2018-03-09T00:00:00.000000000', '2018-03-10T00:00:00.000000000', '2018-03-11T00:00:00.000000000', '2018-03-12T00:00:00.000000000'], dtype='datetime64[ns]')
- lon_left(lon_left)float32-0.9375 0.9375 ... 357.1875
- axis :
- X
- c_grid_axis_shift :
- -0.5
array([ -0.9375, 0.9375, 2.8125, 4.6875, 6.5625, 8.4375, 10.3125, 12.1875, 14.0625, 15.9375, 17.8125, 19.6875, 21.5625, 23.4375, 25.3125, 27.1875, 29.0625, 30.9375, 32.8125, 34.6875, 36.5625, 38.4375, 40.3125, 42.1875, 44.0625, 45.9375, 47.8125, 49.6875, 51.5625, 53.4375, 55.3125, 57.1875, 59.0625, 60.9375, 62.8125, 64.6875, 66.5625, 68.4375, 70.3125, 72.1875, 74.0625, 75.9375, 77.8125, 79.6875, 81.5625, 83.4375, 85.3125, 87.1875, 89.0625, 90.9375, 92.8125, 94.6875, 96.5625, 98.4375, 100.3125, 102.1875, 104.0625, 105.9375, 107.8125, 109.6875, 111.5625, 113.4375, 115.3125, 117.1875, 119.0625, 120.9375, 122.8125, 124.6875, 126.5625, 128.4375, 130.3125, 132.1875, 134.0625, 135.9375, 137.8125, 139.6875, 141.5625, 143.4375, 145.3125, 147.1875, 149.0625, 150.9375, 152.8125, 154.6875, 156.5625, 158.4375, 160.3125, 162.1875, 164.0625, 165.9375, 167.8125, 169.6875, 171.5625, 173.4375, 175.3125, 177.1875, 179.0625, 180.9375, 182.8125, 184.6875, 186.5625, 188.4375, 190.3125, 192.1875, 194.0625, 195.9375, 197.8125, 199.6875, 201.5625, 203.4375, 205.3125, 207.1875, 209.0625, 210.9375, 212.8125, 214.6875, 216.5625, 218.4375, 220.3125, 222.1875, 224.0625, 225.9375, 227.8125, 229.6875, 231.5625, 233.4375, 235.3125, 237.1875, 239.0625, 240.9375, 242.8125, 244.6875, 246.5625, 248.4375, 250.3125, 252.1875, 254.0625, 255.9375, 257.8125, 259.6875, 261.5625, 263.4375, 265.3125, 267.1875, 269.0625, 270.9375, 272.8125, 274.6875, 276.5625, 278.4375, 280.3125, 282.1875, 284.0625, 285.9375, 287.8125, 289.6875, 291.5625, 293.4375, 295.3125, 297.1875, 299.0625, 300.9375, 302.8125, 304.6875, 306.5625, 308.4375, 310.3125, 312.1875, 314.0625, 315.9375, 317.8125, 319.6875, 321.5625, 323.4375, 325.3125, 327.1875, 329.0625, 330.9375, 332.8125, 334.6875, 336.5625, 338.4375, 340.3125, 342.1875, 344.0625, 345.9375, 347.8125, 349.6875, 351.5625, 353.4375, 355.3125, 357.1875], dtype=float32)
- lat_left(lat_left)float3289.48645 87.59755 ... -87.59755
- axis :
- Y
- c_grid_axis_shift :
- -0.5
array([ 89.48645 , 87.59755 , 85.70315 , 83.802 , 81.89905 , 79.99541 , 78.091446, 76.18725 , 74.2829 , 72.37845 , 70.47395 , 68.5694 , 66.6648 , 64.7602 , 62.8556 , 60.95095 , 59.04625 , 57.1416 , 55.23695 , 53.332253, 51.42755 , 49.52285 , 47.61815 , 45.713448, 43.80875 , 41.90405 , 39.99935 , 38.0946 , 36.18985 , 34.28515 , 32.38045 , 30.47575 , 28.571 , 26.66625 , 24.76155 , 22.8568 , 20.95205 , 19.04735 , 17.142601, 15.23785 , 13.33315 , 11.42842 , 9.523675, 7.61894 , 5.714205, 3.80947 , 1.904734, 0. , -1.904734, -3.80947 , -5.714205, -7.61894 , -9.523675, -11.42842 , -13.33315 , -15.23785 , -17.142601, -19.04735 , -20.95205 , -22.8568 , -24.76155 , -26.66625 , -28.571 , -30.47575 , -32.38045 , -34.28515 , -36.18985 , -38.0946 , -39.99935 , -41.90405 , -43.80875 , -45.713448, -47.61815 , -49.52285 , -51.42755 , -53.332253, -55.23695 , -57.1416 , -59.04625 , -60.95095 , -62.8556 , -64.7602 , -66.6648 , -68.5694 , -70.47395 , -72.37845 , -74.2829 , -76.18725 , -78.091446, -79.99541 , -81.89905 , -83.802 , -85.70315 , -87.59755 ], dtype=float32)
- uwnd(time, lat, lon)float32...
- long_name :
- mean Daily u-wind at 10 m
- units :
- m/s
- precision :
- 2
- GRIB_id :
- 33
- GRIB_name :
- U GRD
- var_desc :
- u-wind
- dataset :
- NCEP Reanalysis Daily Averages
- level_desc :
- 10 m
- statistic :
- Mean
- parent_stat :
- Individual Obs
- valid_range :
- [-102.2 102.2]
- actual_range :
- [-21. 25.8]
[1281408 values with dtype=float32]
- time_bnds(time, nbnds)float641.911e+06 1.911e+06 ... 1.913e+06
array([[1910952., 1910976.], [1910976., 1911000.], [1911000., 1911024.], [1911024., 1911048.], [1911048., 1911072.], [1911072., 1911096.], [1911096., 1911120.], [1911120., 1911144.], [1911144., 1911168.], [1911168., 1911192.], [1911192., 1911216.], [1911216., 1911240.], [1911240., 1911264.], [1911264., 1911288.], [1911288., 1911312.], [1911312., 1911336.], [1911336., 1911360.], [1911360., 1911384.], [1911384., 1911408.], [1911408., 1911432.], [1911432., 1911456.], [1911456., 1911480.], [1911480., 1911504.], [1911504., 1911528.], [1911528., 1911552.], [1911552., 1911576.], [1911576., 1911600.], [1911600., 1911624.], [1911624., 1911648.], [1911648., 1911672.], [1911672., 1911696.], [1911696., 1911720.], [1911720., 1911744.], [1911744., 1911768.], [1911768., 1911792.], [1911792., 1911816.], [1911816., 1911840.], [1911840., 1911864.], [1911864., 1911888.], [1911888., 1911912.], [1911912., 1911936.], [1911936., 1911960.], [1911960., 1911984.], [1911984., 1912008.], [1912008., 1912032.], [1912032., 1912056.], [1912056., 1912080.], [1912080., 1912104.], [1912104., 1912128.], [1912128., 1912152.], [1912152., 1912176.], [1912176., 1912200.], [1912200., 1912224.], [1912224., 1912248.], [1912248., 1912272.], [1912272., 1912296.], [1912296., 1912320.], [1912320., 1912344.], [1912344., 1912368.], [1912368., 1912392.], [1912392., 1912416.], [1912416., 1912440.], [1912440., 1912464.], [1912464., 1912488.], [1912488., 1912512.], [1912512., 1912536.], [1912536., 1912560.], [1912560., 1912584.], [1912584., 1912608.], [1912608., 1912632.], [1912632., 1912656.]])
- vwnd(time, lat, lon)float32...
- long_name :
- mean Daily v-wind at 10 m
- units :
- m/s
- precision :
- 2
- GRIB_id :
- 34
- GRIB_name :
- V GRD
- var_desc :
- v-wind
- dataset :
- NCEP Reanalysis Daily Averages
- level_desc :
- 10 m
- statistic :
- Mean
- parent_stat :
- Individual Obs
- valid_range :
- [-102.2 102.2]
- actual_range :
- [-24.2 24.075]
[1281408 values with dtype=float32]
- Conventions :
- COARDS
- title :
- mean daily NMC reanalysis (2014)
- history :
- created 2017/12 by Hoop (netCDF2.3)
- description :
- Data is from NMC initialized reanalysis (4x/day). It consists of T62 variables interpolated to pressure surfaces from model (sigma) surfaces.
- platform :
- Model
- References :
- http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html
- dataset_title :
- NCEP-NCAR Reanalysis 1
As in the depth profile the longitude and latitude values are extended to the left
when the defaults are used. However, since the latitude is not periodic we can specify the position to extend to as outer
(more details here). This will extend the latitudinal positions both to the left and right, avoiding missing values later on.
[10]:
grid = Grid(ds_full, periodic=['X'])
grid
[10]:
<xgcm.Grid>
X Axis (periodic, boundary=None):
* center lon --> left
* left lon_left --> center
T Axis (not periodic, boundary=None):
* center time
Y Axis (not periodic, boundary=None):
* center lat --> left
* left lat_left --> center
Now we compute the difference (in degrees) along the longitude and latitude for both the cell center and the cell face. Since we are not taking the difference of a data variable across the periodic boundary, we need to specify the boundary_discontinutity
in order to avoid the introduction of artefacts at the boundary.
[11]:
dlong = grid.diff(ds_full.lon, 'X', boundary_discontinuity=360)
dlonc = grid.diff(ds_full.lon_left, 'X', boundary_discontinuity=360)
dlonc_wo_discontinuity = grid.diff(ds_full.lon_left, 'X')
dlatg = grid.diff(ds_full.lat, 'Y', boundary='fill', fill_value=np.nan)
dlatc = grid.diff(ds_full.lat_left, 'Y', boundary='fill', fill_value=np.nan)
dlonc.plot()
dlonc_wo_discontinuity.plot(linestyle='--')
[11]:
[<matplotlib.lines.Line2D at 0x7fc4752c4b50>]
Without adding the boundary_discontinuity
input, the last cell distance is calculated incorectly.
The values we just calculated are actually not cell distances, but instead differences in longitude and latitude (in degrees). In order to calculate operators like the gradient dlon
and dlat
have to be converted into approximate cartesian distances on a globe.
[12]:
def dll_dist(dlon, dlat, lon, lat):
"""Converts lat/lon differentials into distances in meters
PARAMETERS
----------
dlon : xarray.DataArray longitude differentials
dlat : xarray.DataArray latitude differentials
lon : xarray.DataArray longitude values
lat : xarray.DataArray latitude values
RETURNS
-------
dx : xarray.DataArray distance inferred from dlon
dy : xarray.DataArray distance inferred from dlat
"""
distance_1deg_equator = 111000.0
dx = dlon * xr.ufuncs.cos(xr.ufuncs.deg2rad(lat)) * distance_1deg_equator
dy = ((lon * 0) + 1) * dlat * distance_1deg_equator
return dx, dy
ds_full.coords['dxg'], ds_full.coords['dyg'] = dll_dist(dlong, dlatg, ds_full.lon, ds_full.lat)
ds_full.coords['dxc'], ds_full.coords['dyc'] = dll_dist(dlonc, dlatc, ds_full.lon, ds_full.lat)
Based on the distances we can estimate the area of each grid cell and compute the area-weighted meridional average temperature
[13]:
ds_full.coords['area_c'] = ds_full.dxc * ds_full.dyc
Compute zonal gradient of the surface wind field¶
Now that all needed grid metrics are available, we can compute the zonal temperature gradient similar as above.
[14]:
du_dx = grid.diff(ds_full.uwnd, 'X') / ds_full.dxg
du_dx
[14]:
<xarray.DataArray (time: 71, lat: 94, lon_left: 192)> array([[[ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, ..., 0.0000000e+00, -1.1802297e-05, 0.0000000e+00], [ 0.0000000e+00, 5.1437846e-06, 0.0000000e+00, ..., 0.0000000e+00, 5.1437846e-06, 0.0000000e+00], [-9.8517148e-06, -1.3135620e-05, -9.8517148e-06, ..., -6.5678100e-06, -6.5678100e-06, -9.8517148e-06], ..., [ 6.5678100e-06, 6.5678100e-06, 6.5678100e-06, ..., 0.0000000e+00, 3.2839050e-06, 6.5678100e-06], [ 1.5431353e-05, 2.0575138e-05, 1.5431353e-05, ..., 1.5431353e-05, 1.5431353e-05, 1.5431353e-05], [ 4.7209189e-05, 3.5406894e-05, 4.7209189e-05, ..., 4.7209189e-05, 3.5406894e-05, 4.7209189e-05]], [[ 0.0000000e+00, -1.1802297e-05, 0.0000000e+00, ..., 0.0000000e+00, -2.3604594e-05, 0.0000000e+00], [-5.1437846e-06, -5.1437846e-06, -5.1437846e-06, ..., -5.1437846e-06, -5.1437846e-06, 0.0000000e+00], [-6.5678100e-06, -9.8517148e-06, -1.3135620e-05, ..., -6.5678100e-06, -6.5678100e-06, -1.3135620e-05], ... [ 1.3135620e-05, 1.6419526e-05, 9.8517148e-06, ..., 2.2987335e-05, 1.6419526e-05, 1.9703430e-05], [ 2.5718922e-05, 2.0575138e-05, 1.5431353e-05, ..., 2.5718922e-05, 2.0575138e-05, 2.0575138e-05], [ 3.5406894e-05, 3.5406894e-05, 3.5406894e-05, ..., 4.7209189e-05, 4.7209189e-05, 3.5406894e-05]], [[ 0.0000000e+00, 1.1802297e-05, 0.0000000e+00, ..., 1.1802297e-05, 1.1802297e-05, 1.1802297e-05], [-5.1437846e-06, -5.1437846e-06, -1.0287569e-05, ..., -1.0287569e-05, -5.1437846e-06, -5.1437846e-06], [-1.3135620e-05, -1.3135620e-05, -9.8517148e-06, ..., -1.3135620e-05, -1.3135620e-05, -1.6419526e-05], ..., [ 1.3135620e-05, 1.3135620e-05, 9.8517148e-06, ..., 1.9703430e-05, 1.9703430e-05, 1.9703430e-05], [ 1.5431353e-05, 2.0575138e-05, 1.5431353e-05, ..., 2.0575138e-05, 2.5718922e-05, 2.0575138e-05], [ 4.7209189e-05, 4.7209189e-05, 4.7209189e-05, ..., 4.7209189e-05, 3.5406894e-05, 3.5406894e-05]]], dtype=float32) Coordinates: * time (time) datetime64[ns] 2018-01-01 2018-01-02 ... 2018-03-12 * lat (lat) float32 88.542 86.6531 84.7532 ... -84.7532 -86.6531 -88.542 * lon_left (lon_left) float32 -0.9375 0.9375 2.8125 ... 355.3125 357.1875 dxg (lon_left, lat) float32 5295.579 12150.587 ... 12150.587 5295.579
- time: 71
- lat: 94
- lon_left: 192
- 0.0 0.0 0.0 0.0 ... 4.720919e-05 3.5406894e-05 3.5406894e-05
array([[[ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, ..., 0.0000000e+00, -1.1802297e-05, 0.0000000e+00], [ 0.0000000e+00, 5.1437846e-06, 0.0000000e+00, ..., 0.0000000e+00, 5.1437846e-06, 0.0000000e+00], [-9.8517148e-06, -1.3135620e-05, -9.8517148e-06, ..., -6.5678100e-06, -6.5678100e-06, -9.8517148e-06], ..., [ 6.5678100e-06, 6.5678100e-06, 6.5678100e-06, ..., 0.0000000e+00, 3.2839050e-06, 6.5678100e-06], [ 1.5431353e-05, 2.0575138e-05, 1.5431353e-05, ..., 1.5431353e-05, 1.5431353e-05, 1.5431353e-05], [ 4.7209189e-05, 3.5406894e-05, 4.7209189e-05, ..., 4.7209189e-05, 3.5406894e-05, 4.7209189e-05]], [[ 0.0000000e+00, -1.1802297e-05, 0.0000000e+00, ..., 0.0000000e+00, -2.3604594e-05, 0.0000000e+00], [-5.1437846e-06, -5.1437846e-06, -5.1437846e-06, ..., -5.1437846e-06, -5.1437846e-06, 0.0000000e+00], [-6.5678100e-06, -9.8517148e-06, -1.3135620e-05, ..., -6.5678100e-06, -6.5678100e-06, -1.3135620e-05], ... [ 1.3135620e-05, 1.6419526e-05, 9.8517148e-06, ..., 2.2987335e-05, 1.6419526e-05, 1.9703430e-05], [ 2.5718922e-05, 2.0575138e-05, 1.5431353e-05, ..., 2.5718922e-05, 2.0575138e-05, 2.0575138e-05], [ 3.5406894e-05, 3.5406894e-05, 3.5406894e-05, ..., 4.7209189e-05, 4.7209189e-05, 3.5406894e-05]], [[ 0.0000000e+00, 1.1802297e-05, 0.0000000e+00, ..., 1.1802297e-05, 1.1802297e-05, 1.1802297e-05], [-5.1437846e-06, -5.1437846e-06, -1.0287569e-05, ..., -1.0287569e-05, -5.1437846e-06, -5.1437846e-06], [-1.3135620e-05, -1.3135620e-05, -9.8517148e-06, ..., -1.3135620e-05, -1.3135620e-05, -1.6419526e-05], ..., [ 1.3135620e-05, 1.3135620e-05, 9.8517148e-06, ..., 1.9703430e-05, 1.9703430e-05, 1.9703430e-05], [ 1.5431353e-05, 2.0575138e-05, 1.5431353e-05, ..., 2.0575138e-05, 2.5718922e-05, 2.0575138e-05], [ 4.7209189e-05, 4.7209189e-05, 4.7209189e-05, ..., 4.7209189e-05, 3.5406894e-05, 3.5406894e-05]]], dtype=float32)
- time(time)datetime64[ns]2018-01-01 ... 2018-03-12
- long_name :
- Time
- delta_t :
- 0000-00-01 00:00:00
- standard_name :
- time
- axis :
- T
- avg_period :
- 0000-00-01 00:00:00
- coordinate_defines :
- start
- actual_range :
- [1910952. 1912632.]
array(['2018-01-01T00:00:00.000000000', '2018-01-02T00:00:00.000000000', '2018-01-03T00:00:00.000000000', '2018-01-04T00:00:00.000000000', '2018-01-05T00:00:00.000000000', '2018-01-06T00:00:00.000000000', '2018-01-07T00:00:00.000000000', '2018-01-08T00:00:00.000000000', '2018-01-09T00:00:00.000000000', '2018-01-10T00:00:00.000000000', '2018-01-11T00:00:00.000000000', '2018-01-12T00:00:00.000000000', '2018-01-13T00:00:00.000000000', '2018-01-14T00:00:00.000000000', '2018-01-15T00:00:00.000000000', '2018-01-16T00:00:00.000000000', '2018-01-17T00:00:00.000000000', '2018-01-18T00:00:00.000000000', '2018-01-19T00:00:00.000000000', '2018-01-20T00:00:00.000000000', '2018-01-21T00:00:00.000000000', '2018-01-22T00:00:00.000000000', '2018-01-23T00:00:00.000000000', '2018-01-24T00:00:00.000000000', '2018-01-25T00:00:00.000000000', '2018-01-26T00:00:00.000000000', '2018-01-27T00:00:00.000000000', '2018-01-28T00:00:00.000000000', '2018-01-29T00:00:00.000000000', '2018-01-30T00:00:00.000000000', '2018-01-31T00:00:00.000000000', '2018-02-01T00:00:00.000000000', '2018-02-02T00:00:00.000000000', '2018-02-03T00:00:00.000000000', '2018-02-04T00:00:00.000000000', '2018-02-05T00:00:00.000000000', '2018-02-06T00:00:00.000000000', '2018-02-07T00:00:00.000000000', '2018-02-08T00:00:00.000000000', '2018-02-09T00:00:00.000000000', '2018-02-10T00:00:00.000000000', '2018-02-11T00:00:00.000000000', '2018-02-12T00:00:00.000000000', '2018-02-13T00:00:00.000000000', '2018-02-14T00:00:00.000000000', '2018-02-15T00:00:00.000000000', '2018-02-16T00:00:00.000000000', '2018-02-17T00:00:00.000000000', '2018-02-18T00:00:00.000000000', '2018-02-19T00:00:00.000000000', '2018-02-20T00:00:00.000000000', '2018-02-21T00:00:00.000000000', '2018-02-22T00:00:00.000000000', '2018-02-23T00:00:00.000000000', '2018-02-24T00:00:00.000000000', '2018-02-25T00:00:00.000000000', '2018-02-26T00:00:00.000000000', '2018-02-27T00:00:00.000000000', '2018-02-28T00:00:00.000000000', '2018-03-01T00:00:00.000000000', '2018-03-02T00:00:00.000000000', '2018-03-03T00:00:00.000000000', '2018-03-04T00:00:00.000000000', '2018-03-05T00:00:00.000000000', '2018-03-06T00:00:00.000000000', '2018-03-07T00:00:00.000000000', '2018-03-08T00:00:00.000000000', '2018-03-09T00:00:00.000000000', '2018-03-10T00:00:00.000000000', '2018-03-11T00:00:00.000000000', '2018-03-12T00:00:00.000000000'], dtype='datetime64[ns]')
- lat(lat)float3288.542 86.6531 ... -86.6531 -88.542
- units :
- degrees_north
- actual_range :
- [ 88.542 -88.542]
- long_name :
- Latitude
- standard_name :
- latitude
- axis :
- Y
array([ 88.542 , 86.6531 , 84.7532 , 82.8508 , 80.9473 , 79.0435 , 77.1394 , 75.2351 , 73.3307 , 71.4262 , 69.5217 , 67.6171 , 65.7125 , 63.8079 , 61.9033 , 59.9986 , 58.0939 , 56.1893 , 54.2846 , 52.3799 , 50.4752 , 48.5705 , 46.6658 , 44.7611 , 42.8564 , 40.9517 , 39.047 , 37.1422 , 35.2375 , 33.3328 , 31.4281 , 29.5234 , 27.6186 , 25.7139 , 23.8092 , 21.9044 , 19.9997 , 18.095 , 16.1902 , 14.2855 , 12.3808 , 10.47604 , 8.57131 , 6.66657 , 4.76184 , 2.8571 , 0.952368, -0.952368, -2.8571 , -4.76184 , -6.66657 , -8.57131 , -10.47604 , -12.3808 , -14.2855 , -16.1902 , -18.095 , -19.9997 , -21.9044 , -23.8092 , -25.7139 , -27.6186 , -29.5234 , -31.4281 , -33.3328 , -35.2375 , -37.1422 , -39.047 , -40.9517 , -42.8564 , -44.7611 , -46.6658 , -48.5705 , -50.4752 , -52.3799 , -54.2846 , -56.1893 , -58.0939 , -59.9986 , -61.9033 , -63.8079 , -65.7125 , -67.6171 , -69.5217 , -71.4262 , -73.3307 , -75.2351 , -77.1394 , -79.0435 , -80.9473 , -82.8508 , -84.7532 , -86.6531 , -88.542 ], dtype=float32)
- lon_left(lon_left)float32-0.9375 0.9375 ... 357.1875
- axis :
- X
- c_grid_axis_shift :
- -0.5
array([ -0.9375, 0.9375, 2.8125, 4.6875, 6.5625, 8.4375, 10.3125, 12.1875, 14.0625, 15.9375, 17.8125, 19.6875, 21.5625, 23.4375, 25.3125, 27.1875, 29.0625, 30.9375, 32.8125, 34.6875, 36.5625, 38.4375, 40.3125, 42.1875, 44.0625, 45.9375, 47.8125, 49.6875, 51.5625, 53.4375, 55.3125, 57.1875, 59.0625, 60.9375, 62.8125, 64.6875, 66.5625, 68.4375, 70.3125, 72.1875, 74.0625, 75.9375, 77.8125, 79.6875, 81.5625, 83.4375, 85.3125, 87.1875, 89.0625, 90.9375, 92.8125, 94.6875, 96.5625, 98.4375, 100.3125, 102.1875, 104.0625, 105.9375, 107.8125, 109.6875, 111.5625, 113.4375, 115.3125, 117.1875, 119.0625, 120.9375, 122.8125, 124.6875, 126.5625, 128.4375, 130.3125, 132.1875, 134.0625, 135.9375, 137.8125, 139.6875, 141.5625, 143.4375, 145.3125, 147.1875, 149.0625, 150.9375, 152.8125, 154.6875, 156.5625, 158.4375, 160.3125, 162.1875, 164.0625, 165.9375, 167.8125, 169.6875, 171.5625, 173.4375, 175.3125, 177.1875, 179.0625, 180.9375, 182.8125, 184.6875, 186.5625, 188.4375, 190.3125, 192.1875, 194.0625, 195.9375, 197.8125, 199.6875, 201.5625, 203.4375, 205.3125, 207.1875, 209.0625, 210.9375, 212.8125, 214.6875, 216.5625, 218.4375, 220.3125, 222.1875, 224.0625, 225.9375, 227.8125, 229.6875, 231.5625, 233.4375, 235.3125, 237.1875, 239.0625, 240.9375, 242.8125, 244.6875, 246.5625, 248.4375, 250.3125, 252.1875, 254.0625, 255.9375, 257.8125, 259.6875, 261.5625, 263.4375, 265.3125, 267.1875, 269.0625, 270.9375, 272.8125, 274.6875, 276.5625, 278.4375, 280.3125, 282.1875, 284.0625, 285.9375, 287.8125, 289.6875, 291.5625, 293.4375, 295.3125, 297.1875, 299.0625, 300.9375, 302.8125, 304.6875, 306.5625, 308.4375, 310.3125, 312.1875, 314.0625, 315.9375, 317.8125, 319.6875, 321.5625, 323.4375, 325.3125, 327.1875, 329.0625, 330.9375, 332.8125, 334.6875, 336.5625, 338.4375, 340.3125, 342.1875, 344.0625, 345.9375, 347.8125, 349.6875, 351.5625, 353.4375, 355.3125, 357.1875], dtype=float32)
- dxg(lon_left, lat)float325295.579 12150.587 ... 5295.579
array([[ 5295.579, 12150.587, 19032.219, ..., 19032.219, 12150.587, 5295.579], [ 5295.579, 12150.587, 19032.219, ..., 19032.219, 12150.587, 5295.579], [ 5295.579, 12150.587, 19032.219, ..., 19032.219, 12150.587, 5295.579], ..., [ 5295.579, 12150.587, 19032.219, ..., 19032.219, 12150.587, 5295.579], [ 5295.579, 12150.587, 19032.219, ..., 19032.219, 12150.587, 5295.579], [ 5295.579, 12150.587, 19032.219, ..., 19032.219, 12150.587, 5295.579]], dtype=float32)
The values of the gradient are correctly located on the cell boundary on the x-axis and on the cell center in the y-axis
[15]:
import cartopy.crs as ccrs
fig, axarr = plt.subplots(ncols=2, nrows=3, figsize=[16,20],
subplot_kw=dict(projection=ccrs.Orthographic(0, -30)))
for ti,tt in enumerate(np.arange(0,30, 10)):
ax1 = axarr[ti,0]
ax2 = axarr[ti,1]
time = ds_full.time.isel(time=tt).data
ds_full.uwnd.isel(time=tt).plot(ax=ax1, transform=ccrs.PlateCarree(),robust=True)
du_dx.isel(time=tt).plot(ax=ax2, transform=ccrs.PlateCarree(), robust=True)
ax1.set_title('Zonal Surface Wind %s' %time)
ax2.set_title('Zonal Gradient of Zonal Surface Wind %s' %time)
for ax in [ax1, ax2]:
ax.set_global(); ax.coastlines();
/srv/conda/envs/notebook/lib/python3.8/site-packages/cartopy/io/__init__.py:260: DownloadWarning: Downloading: https://naciscdn.org/naturalearth/110m/physical/ne_110m_coastline.zip
warnings.warn('Downloading: {}'.format(url), DownloadWarning)
The resulting gradient is correctly computed across the periodic (x-axis) boundary.
Area weighted average¶
By using the approximated cell area, we can easily compute the area weighted average of the zonal wind.
[16]:
u = ds_full.uwnd.mean('time')
u_mean = u.mean('lat')
u_mean_weighted = (u * u.area_c).sum('lat') / (u.area_c).sum('lat')
u_mean.plot(label='unweighted mean')
u_mean_weighted.plot(label='area weighted mean')
plt.legend()
plt.ylabel('zonal wind [m/s]')
plt.gca().autoscale('tight')
Thes two lines show the importance of applying a weighted mean, when the grid spacing is irregular (e.g. datasets gridded on a regular lat-lon grid).