Antarctic Intermediate Water (AAIW)

Purpose:

Compute and plot the buoyancy contribution to potential vorticity over the Pacific Sector of the Southern Ocean.

Acknowledgment

This notebook builds on work by John Krasting (NOAA/GFDL). The original version can be found at: https://github.com/jkrasting/mar/blob/main/src/gfdlnb/notebooks/ocean/AAIW_PV.ipynb.

[1]:
%load_ext autoreload
%autoreload 2
[2]:
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")
import matplotlib
import numpy as np
import xarray as xr
import momlevel as ml
from mom6_tools.jobqueue import get_cluster
import cartopy.crs as ccrs
from mom6_tools.MOM6grid import MOM6grid
from mom6_tools.m6toolbox import add_global_attrs
from mom6_tools.m6toolbox import cime_xmlquery
from mom6_tools.m6toolbox import weighted_temporal_mean_vars
from mom6_tools.m6toolbox import geoslice
from mom6_tools.aaiw_pv import plot_aaiw_pv, plot_aaiw_pv_obs
import matplotlib.pyplot as plt
import yaml, os, intake
Basemap module not found. Some regional plots may not function properly
[3]:
# Read in the yaml file
diag_config_yml_path = "diag_config.yml"
diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)
[4]:
caseroot = diag_config_yml['Case']['CASEROOT']
casename = cime_xmlquery(caseroot, 'CASE')
DOUT_S = cime_xmlquery(caseroot, 'DOUT_S')
if DOUT_S:
  OUTDIR = cime_xmlquery(caseroot, 'DOUT_S_ROOT')+'/ocn/hist/'
else:
  OUTDIR = cime_xmlquery(caseroot, 'RUNDIR')

print('Output directory is:', OUTDIR)
print('Casename is:', casename)
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In[4], line 2
      1 caseroot = diag_config_yml['Case']['CASEROOT']
----> 2 casename = cime_xmlquery(caseroot, 'CASE')
      3 DOUT_S = cime_xmlquery(caseroot, 'DOUT_S')
      4 if DOUT_S:

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/mom6_tools/m6toolbox.py:47, in cime_xmlquery(caseroot, varname)
     45 """run CIME's xmlquery for varname in the directory caseroot, return the value"""
     46 try:
---> 47   value = subprocess.check_output(
     48       ["./xmlquery", "-N", "--value", varname],
     49       stderr=subprocess.STDOUT,
     50       cwd=caseroot,
     51   )
     52 except subprocess.CalledProcessError:
     53   value = subprocess.check_output(
     54       ["./xmlquery", "--value", varname], stderr=subprocess.STDOUT, cwd=caseroot
     55   )

File ~/.asdf/installs/python/3.10.20/lib/python3.10/subprocess.py:421, in check_output(timeout, *popenargs, **kwargs)
    418         empty = b''
    419     kwargs['input'] = empty
--> 421 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    422            **kwargs).stdout

File ~/.asdf/installs/python/3.10.20/lib/python3.10/subprocess.py:503, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    500     kwargs['stdout'] = PIPE
    501     kwargs['stderr'] = PIPE
--> 503 with Popen(*popenargs, **kwargs) as process:
    504     try:
    505         stdout, stderr = process.communicate(input, timeout=timeout)

File ~/.asdf/installs/python/3.10.20/lib/python3.10/subprocess.py:971, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)
    967         if self.text_mode:
    968             self.stderr = io.TextIOWrapper(self.stderr,
    969                     encoding=encoding, errors=errors)
--> 971     self._execute_child(args, executable, preexec_fn, close_fds,
    972                         pass_fds, cwd, env,
    973                         startupinfo, creationflags, shell,
    974                         p2cread, p2cwrite,
    975                         c2pread, c2pwrite,
    976                         errread, errwrite,
    977                         restore_signals,
    978                         gid, gids, uid, umask,
    979                         start_new_session)
    980 except:
    981     # Cleanup if the child failed starting.
    982     for f in filter(None, (self.stdin, self.stdout, self.stderr)):

File ~/.asdf/installs/python/3.10.20/lib/python3.10/subprocess.py:1863, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1861     if errno_num != 0:
   1862         err_msg = os.strerror(errno_num)
-> 1863     raise child_exception_type(errno_num, err_msg, err_filename)
   1864 raise child_exception_type(err_msg)

FileNotFoundError: [Errno 2] No such file or directory: '/glade/work/gmarques/cesm.cases/G/g.e30_a07c_cesm.GJRAv4.TL319_t232_wgx3_hycom1_N75.2025.130/'
[5]:
# The following parameters must be set accordingly
######################################################
# add your name and email address below
author = 'Gustavo Marques (gmarques@ucar.edu)'
######################################################
# create an empty class object
class args:
  pass

# load avg dates
avg = diag_config_yml['Avg']

args.infile = OUTDIR
args.monthly = casename+diag_config_yml['Fnames']['z']
args.static = casename+diag_config_yml['Fnames']['static']
args.geom =   casename+diag_config_yml['Fnames']['geom']
args.start_date = avg['start_date']
args.end_date = avg['end_date']
args.casename = casename
args.label = diag_config_yml['Case']['SNAME']
args.savefigs = False
args.outdir = 'PNG/AAIW_PV/'
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 13
     10 # load avg dates
     11 avg = diag_config_yml['Avg']
---> 13 args.infile = OUTDIR
     14 args.monthly = casename+diag_config_yml['Fnames']['z']
     15 args.static = casename+diag_config_yml['Fnames']['static']

NameError: name 'OUTDIR' is not defined
[6]:
# read grid info
geom_file = OUTDIR+'/'+args.geom
if os.path.exists(geom_file):
  grd = MOM6grid(OUTDIR+'/'+args.static, geom_file, xrformat=True)
else:
  grd = MOM6grid(OUTDIR+'/'+args.static, xrformat=True)

try:
  depth = grd.depth_ocean
except:
  depth = grd.deptho
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[6], line 2
      1 # read grid info
----> 2 geom_file = OUTDIR+'/'+args.geom
      3 if os.path.exists(geom_file):
      4   grd = MOM6grid(OUTDIR+'/'+args.static, geom_file, xrformat=True)

NameError: name 'OUTDIR' is not defined
[7]:
# Coriolis
coriolis = ml.derived.calc_coriolis(grd.geolat)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[7], line 2
      1 # Coriolis
----> 2 coriolis = ml.derived.calc_coriolis(grd.geolat)

NameError: name 'grd' is not defined
[8]:
parallel, cluster, client = get_cluster(6, cluster_class='PBSCluster')
client
Starting a dask cluster: PBSCluster

Requesting 6 workers...

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[8], line 1
----> 1 parallel, cluster, client = get_cluster(6, cluster_class='PBSCluster')
      2 client

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/mom6_tools/jobqueue.py:300, in get_cluster(nw, cluster_class, args, config, **kwargs)
    297 print('Requesting {} workers... \n'.format(nw))
    298 if is_jobqueue_cluster:
    299   # dask.config.set({'distributed.dashboard.link': '/proxy/{port}/status'})
--> 300   cluster = cluster_class(**kwargs)
    301   cluster.scale(nw)
    302 else:

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/dask_jobqueue/core.py:656, in JobQueueCluster.__init__(self, n_workers, job_cls, loop, security, shared_temp_directory, silence_logs, name, asynchronous, dashboard_address, host, scheduler_options, scheduler_cls, interface, protocol, config_name, **job_kwargs)
    653 self._job_kwargs = job_kwargs
    655 worker = {"cls": self.job_cls, "options": self._job_kwargs}
--> 656 if "processes" in self._job_kwargs and self._job_kwargs["processes"] > 1:
    657     worker["group"] = [
    658         "-" + str(i) for i in range(self._job_kwargs["processes"])
    659     ]
    661 self._dummy_job  # trigger property to ensure that the job is valid

TypeError: '>' not supported between instances of 'NoneType' and 'int'
[9]:
def preprocess(ds):
    ''' Return a dataset desired variables'''
    variables = ['thetao', 'so', 'volcello']
    return ds[variables]
[10]:
print('\n Reading dataset...')
# load data
%time ds = xr.open_mfdataset(OUTDIR+'/'+args.monthly, parallel=True, \
                             combine="nested", concat_dim="time", \
                             preprocess=preprocess).chunk({"time": 12})

 Reading dataset...
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
File <timed exec>:1

NameError: name 'OUTDIR' is not defined
[11]:
print('\n Selecting data between {} and {}...'.format(args.start_date, args.end_date))
%time ds_sel = ds.sel(time=slice(args.start_date, args.end_date))
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[11], line 1
----> 1 print('\n Selecting data between {} and {}...'.format(args.start_date, args.end_date))
      2 get_ipython().run_line_magic('time', 'ds_sel = ds.sel(time=slice(args.start_date, args.end_date))')

AttributeError: type object 'args' has no attribute 'start_date'
[12]:
attrs =  {
         'description': 'Annual mean thetao, so and volcello',
         'reduction_method': 'annual mean weighted by days in each month',
         'casename': casename
         }
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[12], line 4
      1 attrs =  {
      2          'description': 'Annual mean thetao, so and volcello',
      3          'reduction_method': 'annual mean weighted by days in each month',
----> 4          'casename': casename
      5          }

NameError: name 'casename' is not defined
[13]:
ds_ann = weighted_temporal_mean_vars(ds_sel, attrs=attrs)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[13], line 1
----> 1 ds_ann = weighted_temporal_mean_vars(ds_sel, attrs=attrs)

NameError: name 'ds_sel' is not defined
[14]:
ds_mean = ds_ann.mean("time")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[14], line 1
----> 1 ds_mean = ds_ann.mean("time")

NameError: name 'ds_ann' is not defined
[15]:
%%time
zeta = 0.0
n2 = ml.derived.calc_n2(ds_mean.thetao, ds_mean.so)
pv = ml.derived.calc_pv(zeta, coriolis, n2, interp_n2=False, units="cm")
pv = pv.transpose("z_l", "yh", "xh")
pv = pv.load()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
File <timed exec>:2

NameError: name 'ds_mean' is not defined
[16]:
# Add the latitude and longitude as new coordinates to the pv DataArray
pv = pv.assign_coords({
    "latitude": (("yh", "xh"), grd.geolat.data),
    "longitude": (("yh", "xh"), grd.geolon.data)
})
#pv
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[16], line 2
      1 # Add the latitude and longitude as new coordinates to the pv DataArray
----> 2 pv = pv.assign_coords({
      3     "latitude": (("yh", "xh"), grd.geolat.data),
      4     "longitude": (("yh", "xh"), grd.geolon.data)
      5 })
      6 #pv

NameError: name 'pv' is not defined
[17]:
ds_mean = ds_mean.assign_coords({
    "latitude": (("yh", "xh"), grd.geolat.data),
    "longitude": (("yh", "xh"), grd.geolon.data)
})
#ds_mean
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[17], line 1
----> 1 ds_mean = ds_mean.assign_coords({
      2     "latitude": (("yh", "xh"), grd.geolat.data),
      3     "longitude": (("yh", "xh"), grd.geolon.data)
      4 })
      5 #ds_mean

NameError: name 'ds_mean' is not defined
[18]:
#pv['longitude'] = lon
#pv = pv.assign_coords(longitude=lon)
[19]:
pv = geoslice(pv, x=(-180,-70),y=(-65,0), xcoord="longitude", ycoord="latitude")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[19], line 1
----> 1 pv = geoslice(pv, x=(-180,-70),y=(-65,0), xcoord="longitude", ycoord="latitude")

NameError: name 'pv' is not defined
[20]:
%matplotlib inline
ds_mean.thetao[0,:].plot(vmin=-2, vmax=32)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[20], line 2
      1 get_ipython().run_line_magic('matplotlib', 'inline')
----> 2 ds_mean.thetao[0,:].plot(vmin=-2, vmax=32)

NameError: name 'ds_mean' is not defined

Visulaize selected region

[21]:
fig = plt.figure(figsize=(12, 6))
ax = plt.axes(projection=ccrs.PlateCarree())
ax.coastlines()
ax.gridlines()
pv[8,:].plot(ax=ax, cbar_kwargs={"orientation": "horizontal"}, transform=ccrs.PlateCarree())
ax.gridlines(draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--')
ax.set_extent([-180, -65, -65, 0], crs=ccrs.PlateCarree())
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[21], line 5
      3 ax.coastlines()
      4 ax.gridlines()
----> 5 pv[8,:].plot(ax=ax, cbar_kwargs={"orientation": "horizontal"}, transform=ccrs.PlateCarree())
      6 ax.gridlines(draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--')
      7 ax.set_extent([-180, -65, -65, 0], crs=ccrs.PlateCarree())

NameError: name 'pv' is not defined
../_images/examples_aaiw_pv_22_1.png
[22]:
levels, colors = ml.util.get_pv_colormap()
yindex = pv.latitude.mean("xh")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[22], line 2
      1 levels, colors = ml.util.get_pv_colormap()
----> 2 yindex = pv.latitude.mean("xh")

NameError: name 'pv' is not defined

Calcualte the Volume

[23]:
volcello = geoslice(ds_mean.volcello, x=(-180,-70),y=(-65,0),
                             xcoord="longitude", ycoord="latitude")
volume = xr.where(pv > 60.0, volcello, np.nan).sel(z_l=slice(700, None)).sum()
volume = volume.load()
print(f"Volume of water with PV > 60 cm-2 s-1: {float(volume/1.0e15)} x 1.0e^15")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[23], line 1
----> 1 volcello = geoslice(ds_mean.volcello, x=(-180,-70),y=(-65,0),
      2                              xcoord="longitude", ycoord="latitude")
      3 volume = xr.where(pv > 60.0, volcello, np.nan).sel(z_l=slice(700, None)).sum()
      4 volume = volume.load()

NameError: name 'ds_mean' is not defined

Make zonal mean plots

[24]:
# Take the zonal mean
pv = pv.weighted(grd.areacello.fillna(0)).mean("xh")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[24], line 2
      1 # Take the zonal mean
----> 2 pv = pv.weighted(grd.areacello.fillna(0)).mean("xh")

NameError: name 'pv' is not defined
[25]:
pv = pv.transpose("z_l", "yh")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[25], line 1
----> 1 pv = pv.transpose("z_l", "yh")

NameError: name 'pv' is not defined

Bouyancy contribution to PV from model

[26]:
%matplotlib inline
args.label = args.label + ', average between ' + args.start_date + ' and ' + args.end_date
plot_aaiw_pv(yindex, pv.z_l, pv, volume, levels, colors, args)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[26], line 2
      1 get_ipython().run_line_magic('matplotlib', 'inline')
----> 2 args.label = args.label + ', average between ' + args.start_date + ' and ' + args.end_date
      3 plot_aaiw_pv(yindex, pv.z_l, pv, volume, levels, colors, args)

AttributeError: type object 'args' has no attribute 'label'

Temperatude and salinity from model

[27]:
thetao = geoslice(ds_mean.thetao, x=(-180,-70),y=(-65,0), xcoord="longitude", ycoord="latitude").weighted(grd.areacello.fillna(0)).mean("xh").sel(z_l=slice(0,1800.))
so = geoslice(ds_mean.so, x=(-180,-70),y=(-65,0), xcoord="longitude", ycoord="latitude").weighted(grd.areacello.fillna(0)).mean("xh").sel(z_l=slice(0,1800.))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[27], line 1
----> 1 thetao = geoslice(ds_mean.thetao, x=(-180,-70),y=(-65,0), xcoord="longitude", ycoord="latitude").weighted(grd.areacello.fillna(0)).mean("xh").sel(z_l=slice(0,1800.))
      2 so = geoslice(ds_mean.so, x=(-180,-70),y=(-65,0), xcoord="longitude", ycoord="latitude").weighted(grd.areacello.fillna(0)).mean("xh").sel(z_l=slice(0,1800.))

NameError: name 'ds_mean' is not defined
[28]:
fig, ax = plt.subplots(1, 2, figsize=(14, 6), sharey=True)

# Plot potential temperature
cf1 = ax[0].contourf(thetao.yh, -thetao.z_l, thetao, levels=20, cmap='RdYlBu_r', extend='both')
c1 = ax[0].contour(thetao.yh, -thetao.z_l, thetao, levels=10, colors='k', linewidths=0.5)
ax[0].clabel(c1, inline=True, fontsize=8)
ax[0].set_ylabel('Depth (m)')
ax[1].set_xlabel('Latitude')
ax[0].set_title('Potential Temperature (°C)')
ax[0].invert_yaxis()
plt.colorbar(cf1, ax=ax[0], label='Thetao (°C)', orientation='horizontal')

# Plot salinity
cf2 = ax[1].contourf(so.yh, -so.z_l, so, levels=20, cmap='viridis', extend='both')
c2 = ax[1].contour(so.yh, -so.z_l, so, levels=10, colors='k', linewidths=0.5)
ax[1].clabel(c2, inline=True, fontsize=8)
ax[1].set_xlabel('Latitude')
ax[1].set_title('Salinity (PSU)')
ax[1].invert_yaxis()
plt.colorbar(cf2, ax=ax[1], label='Salinity (PSU)', orientation='horizontal')

# Adjust layout for clarity
plt.tight_layout()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[28], line 4
      1 fig, ax = plt.subplots(1, 2, figsize=(14, 6), sharey=True)
      3 # Plot potential temperature
----> 4 cf1 = ax[0].contourf(thetao.yh, -thetao.z_l, thetao, levels=20, cmap='RdYlBu_r', extend='both')
      5 c1 = ax[0].contour(thetao.yh, -thetao.z_l, thetao, levels=10, colors='k', linewidths=0.5)
      6 ax[0].clabel(c1, inline=True, fontsize=8)

NameError: name 'thetao' is not defined
../_images/examples_aaiw_pv_33_1.png
[29]:
description = 'buoyancy contribution to potential vorticity over the Pacific Sector of the Southern Ocean'
attrs = {'description': description,
         'unit': 'cm2 s-1',
         'start_date': args.start_date,
         'end_date': args.end_date}
add_global_attrs(pv,attrs)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[29], line 4
      1 description = 'buoyancy contribution to potential vorticity over the Pacific Sector of the Southern Ocean'
      2 attrs = {'description': description,
      3          'unit': 'cm2 s-1',
----> 4          'start_date': args.start_date,
      5          'end_date': args.end_date}
      6 add_global_attrs(pv,attrs)

AttributeError: type object 'args' has no attribute 'start_date'
[30]:
print('Saving netCDF files...')
os.makedirs('ncfiles', exist_ok=True)
pv.to_netcdf('ncfiles/'+str(args.casename)+'_AAIW_PV.nc')
Saving netCDF files...
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[30], line 3
      1 print('Saving netCDF files...')
      2 os.makedirs('ncfiles', exist_ok=True)
----> 3 pv.to_netcdf('ncfiles/'+str(args.casename)+'_AAIW_PV.nc')

NameError: name 'pv' is not defined

Bouyancy contribution to PV, temperatude and salinity from obs

[31]:
catalog = intake.open_catalog(diag_config_yml['oce_cat'])
ds_obs = catalog['rg-argo-2018'].to_dask()
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[31], line 1
----> 1 catalog = intake.open_catalog(diag_config_yml['oce_cat'])
      2 ds_obs = catalog['rg-argo-2018'].to_dask()

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/__init__.py:186, in open_catalog(uri, **kwargs)
    179     raise ValueError(
    180         f"Unknown catalog driver '{driver}'. "
    181         "Do you need to install a new driver from the plugin directory? "
    182         "https://intake.readthedocs.io/en/latest/plugin-directory.html\n"
    183         f"Current registry: {list(sorted(registry))}"
    184     )
    185 try:
--> 186     return registry[driver](uri, **kwargs)
    187 except VersionError:
    188     # warn that we are switching to V2? The file will be read twice
    189     return from_yaml_file(uri, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/local.py:617, in YAMLFileCatalog.__init__(self, path, text, autoreload, **kwargs)
    615 self.filesystem = kwargs.pop("fs", None)
    616 self.access = "name" not in kwargs
--> 617 super(YAMLFileCatalog, self).__init__(**kwargs)

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/base.py:128, in Catalog.__init__(self, entries, name, description, metadata, ttl, getenv, getshell, persist_mode, storage_options, user_parameters)
    126 self.updated = time.time()
    127 self._entries = entries if entries is not None else self._make_entries_container()
--> 128 self.force_reload()

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/base.py:186, in Catalog.force_reload(self)
    184 """Imperative reload data now"""
    185 self.updated = time.time()
--> 186 self._load()

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/local.py:652, in YAMLFileCatalog._load(self, reload)
    650     logger.warning("Use of '!template' deprecated - fixing")
    651     text = text.replace("!template ", "")
--> 652 self.parse(text)

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/local.py:730, in YAMLFileCatalog.parse(self, text)
    728 # Second, we validate the schema and semantics
    729 context = dict(root=self._dir)
--> 730 result = CatalogParser(data, context=context, getenv=self.getenv, getshell=self.getshell)
    731 if result.errors:
    732     raise exceptions.ValidationError(
    733         "Catalog '{}' has validation errors:\n\n{}"
    734         "".format(self.path, "\n".join(result.errors)),
    735         result.errors,
    736     )

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/local.py:342, in CatalogParser.__init__(self, data, getenv, getshell, context)
    340 self.getenv = getenv
    341 self.getshell = getshell
--> 342 self._data = self._parse(data)

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/local.py:565, in CatalogParser._parse(self, data)
    561 if (data.get("version", None) or data.get("metadata", {}).get("version", None) or 1) > 1:
    562     raise VersionError("Not a V1 Catalog; perhaps use intake.open_catalog")
    564 return dict(
--> 565     plugin_sources=self._parse_plugins(data),
    566     data_sources=self._parse_data_sources(data),
    567     metadata=data.get("metadata", {}),
    568     name=data.get("name"),
    569     description=data.get("description"),
    570 )

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/catalog/local.py:400, in CatalogParser._parse_plugins(self, data)
    397 elif "module" in plugin_source:
    398     import intake
--> 400     intake.import_name(plugin_source["module"])
    401 elif "dir" in plugin_source:
    402     self.error(
    403         "The key 'dir', and in general the feature of registering "
    404         "plugins from a directory of Python scripts outside of "
    405         "sys.path, is no longer supported. Use 'module'.",
    406         plugin_source,
    407     )

File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/intake/utils.py:27, in import_name(name)
     25 modname = name.split(":", 1)[0]
     26 logger.debug("Importing: '%s'" % modname)
---> 27 mod = importlib.import_module(modname)
     28 if ":" in name:
     29     end = name.split(":")[1]

File ~/.asdf/installs/python/3.10.20/lib/python3.10/importlib/__init__.py:126, in import_module(name, package)
    124             break
    125         level += 1
--> 126 return _bootstrap._gcd_import(name[level:], package, level)

File <frozen importlib._bootstrap>:1050, in _gcd_import(name, package, level)

File <frozen importlib._bootstrap>:1027, in _find_and_load(name, import_)

File <frozen importlib._bootstrap>:1004, in _find_and_load_unlocked(name, import_)

ModuleNotFoundError: No module named 'intake_xarray'
[32]:
plot_aaiw_pv_obs(ds_obs, levels, colors)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[32], line 1
----> 1 plot_aaiw_pv_obs(ds_obs, levels, colors)

NameError: name 'ds_obs' is not defined