Open sgdecker opened 2 years ago
Oops, clumsy keyboarding there! Here is the working example. The feature request is for the commented out code to work:
from datetime import datetime, timedelta
import xarray as xr
from xarray.backends import NetCDF4DataStore
import metpy.calc as mpcalc
from metpy.interpolate import interpolate_to_isosurface
from metpy.plots import FilledContourPlot, MapPanel, PanelContainer
from metpy.units import units
from siphon.catalog import TDSCatalog
def get_nam212(init_time, valid_time):
"""Obtain NAM data on the 212 grid."""
ymd = init_time.strftime('%Y%m%d')
hr = init_time.strftime('%H')
filename = f'{ymd}_{hr}00.grib2'
ds_name = 'NAM_CONUS_40km_conduit_' + filename
cat_name = ('https://thredds.ucar.edu/thredds/catalog/grib/NCEP/NAM/'
'CONUS_40km/conduit/' + ds_name + '/catalog.xml')
cat = TDSCatalog(cat_name)
ds = cat.datasets[ds_name]
ncss = ds.subset()
query = ncss.query()
query.time(valid_time).variables('all')
nc = ncss.get_data(query)
data = xr.open_dataset(NetCDF4DataStore(nc)).metpy.parse_cf()
return data
def extract_and_normalize(xda, name):
var = xda.squeeze()
var = mpcalc.smooth_gaussian(var, 16)
var = var.rename({var.metpy.vertical.name: 'pres'})
var = var.rename(name).metpy.assign_latitude_longitude()
return var
init_time = datetime(2021, 12, 6, 12)
plot_time = init_time + timedelta(hours=6)
nam = get_nam212(init_time, plot_time)
tmpk = extract_and_normalize(nam['Temperature_isobaric'], 'tmpk')
urel = extract_and_normalize(nam['u-component_of_wind_isobaric'], 'urel')
vrel = extract_and_normalize(nam['v-component_of_wind_isobaric'], 'vrel')
ds = xr.merge((tmpk, urel, vrel), combine_attrs='drop_conflicts')
ds['theta'] = mpcalc.potential_temperature(ds['pres'], ds['tmpk'])
ds['pv'] = mpcalc.potential_vorticity_baroclinic(ds['theta'], ds['pres'], ds['urel'], ds['vrel'])
# Feature request: Allow this
#pvu = 1e-6 * units('degK') / units('kg') * units('m2') / units('s')
#theta_dt = interpolate_to_isosurface(ds['pv'], ds['theta'], 2*pvu)
# Workaround
pv = ds['pv'].values
theta = ds['theta'].values
theta_dyn_trop = interpolate_to_isosurface(pv, theta, 2e-6)
theta_dt = xr.DataArray(theta_dyn_trop, dims=['y', 'x'],
coords={'y': ds['theta'].y, 'x': ds['theta'].x, 'metpy_crs': ds['theta'].metpy_crs},
attrs=ds.attrs)
fcp = FilledContourPlot()
fcp.data = theta_dt
fcp.colorbar = 'horizontal'
mp = MapPanel()
mp.area = [-97, -60, 33, 49]
mp.layers = ['coastline', 'borders', 'states']
mp.plots = [fcp]
pc = PanelContainer()
pc.size = (12, 8)
pc.panels = [mp]
pc.show()
Completely reasonable request for that to work. However, the problem is xarray, not units. If you try:
theta_dt = interpolate_to_isosurface(ds['pv'].metpy.unit_array, ds['theta'].metpy.unit_array, 2*pvu)
you'll see that call succeeds (though it later fails in declarative because theta_dt
isn't a DataArray
).
Units isn't always the problem. 😉
I've updated the issue title to reflect this.
Discussed in https://github.com/Unidata/MetPy/discussions/2237