0% found this document useful (0 votes)
29 views167 pages

Mom6 Tools Readthedocs Io en Latest

The mom6-tools documentation provides guidance on installing and using tools for analyzing MOM6-CESM model solutions. It includes installation instructions via PyPI and conda-forge, examples of configuring cases, generating ocean masks, and extracting ocean statistics. The documentation is aimed at users looking to leverage the functionalities of mom6-tools for their modeling and analysis needs.

Uploaded by

Pedro Nobre
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views167 pages

Mom6 Tools Readthedocs Io en Latest

The mom6-tools documentation provides guidance on installing and using tools for analyzing MOM6-CESM model solutions. It includes installation instructions via PyPI and conda-forge, examples of configuring cases, generating ocean masks, and extracting ocean statistics. The documentation is aimed at users looking to leverage the functionalities of mom6-tools for their modeling and analysis needs.

Uploaded by

Pedro Nobre
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 167

mom6-tools Documentation

Release 0.0.post86

mom6-tools developers

Nov 12, 2020


User guide

1 Installation (Coming Soon!) 3


1.1 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
1.3 Installing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

2 Indices and tables 163

i
ii
mom6-tools Documentation, Release 0.0.post86

Tools to support analysis of MOM6-CESM model solutions. See documentation for more information.

User guide 1
mom6-tools Documentation, Release 0.0.post86

2 User guide
CHAPTER 1

Installation (Coming Soon!)

mom6-tools can be installed from PyPI with pip:


pip install mom6-tools

It is also available from conda-forge for conda installations:


conda install -c conda-forge mom6-tools

User guide
• Examples

1.1 Examples

1.1.1 Example on how to configure a case using mom6-tools

This is a very simple example showing how to read diag_config.yaml, create a case instance, compute a clima-
tology and visualize the results.
[1]: from mom6_tools.DiagsCase import DiagsCase
import yaml
import xarray as xr
import matplotlib
from mom6_tools import m6toolbox
%matplotlib inline

[2]: # 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)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])

3
mom6-tools Documentation, Release 0.0.post86

[4]: dcase.casename
[4]: 'g.c2b6.GJRA.TL319_t061.long_JRA_mct.076'

[5]: # Load the grid


grd = dcase.grid
MOM6 grid successfully loaded...

[6]: parallel, cluster, client = m6toolbox.request_workers(6)


Requesting 6 workers...

/proxy/46593/status

[7]: RUNDIR = dcase.get_value('RUNDIR')

%time ds = xr.open_mfdataset(RUNDIR+'/'+dcase.casename+'.mom6.sfc_*.nc', \
parallel=True, data_vars='minimal', chunks={'time': 12},\
coords='minimal', compat='override')
CPU times: user 4.67 s, sys: 494 ms, total: 5.16 s
Wall time: 1min 37s

[8]: ds
[8]: <xarray.Dataset>
Dimensions: (nv: 2, time: 21170, xh: 540, xq: 540, yh: 458, yq: 458)
Coordinates:
* yh (yh) float64 -79.2 -79.08 -78.95 -78.82 ... 87.64 87.71 87.74
* nv (nv) float64 1.0 2.0
* xh (xh) float64 -286.7 -286.0 -285.3 -284.7 ... 71.33 72.0 72.67
* yq (yq) float64 -79.14 -79.01 -78.89 -78.76 ... 87.68 87.73 87.74
* xq (xq) float64 -286.3 -285.7 -285.0 -284.3 ... 71.67 72.33 73.0
* time (time) object 0001-01-01 12:00:00 ... 0058-12-31 12:00:00
Data variables:
SSH (time, yh, xh) float32 dask.array<chunksize=(12, 458, 540), meta=np.
˓→ndarray>

tos (time, yh, xh) float32 dask.array<chunksize=(12, 458, 540), meta=np.


˓→ndarray>

sos (time, yh, xh) float32 dask.array<chunksize=(12, 458, 540), meta=np.


˓→ndarray>

SSU (time, yh, xq) float32 dask.array<chunksize=(12, 458, 540), meta=np.


˓→ndarray>

SSV (time, yq, xh) float32 dask.array<chunksize=(12, 458, 540), meta=np.


˓→ndarray>

speed (time, yh, xh) float32 dask.array<chunksize=(12, 458, 540), meta=np.


˓→ndarray>

mlotst (time, yh, xh) float32 dask.array<chunksize=(12, 458, 540), meta=np.


˓→ndarray>

oml (time, yh, xh) float32 dask.array<chunksize=(12, 458, 540), meta=np.


˓→ndarray>

average_T1 (time) object dask.array<chunksize=(12,), meta=np.ndarray>


average_T2 (time) object dask.array<chunksize=(12,), meta=np.ndarray>
average_DT (time) timedelta64[ns] dask.array<chunksize=(12,), meta=np.ndarray>
time_bnds (time, nv) timedelta64[ns] dask.array<chunksize=(12, 2), meta=np.
˓→ndarray>

(continues on next page)

4 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


Attributes:
filename: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076.mom6.sfc_0001.nc
title: MOM6 diagnostic fields table for CESM case: g.c2b6.GJR...
associated_files: area_t: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076.mom6.s...
grid_type: regular
grid_tile: N/A

[9]: # Plot 5-yearly average sst


sst = ds['tos'].mean('time').load()

[10]: sst.plot(vmin=-2, vmax=32)


[10]: <matplotlib.collections.QuadMesh at 0x2b1e95f82da0>

[ ]: dd

1.1.2 Masks generation

The porpuses of this notebook is to show how to generate ocean masks for different regions. It uses functions genBas-
inMasks.

[1]: from mom6_tools.m6plot import xyplot


from mom6_tools.m6toolbox import genBasinMasks
from mom6_tools.MOM6grid import MOM6grid
from mom6_tools.DiagsCase import DiagsCase
import yaml
import numpy
import xarray as xr
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline
Basemap module not found. Some regional plots may not function properly

1.1. Examples 5
mom6-tools Documentation, Release 0.0.post86

[2]: # 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)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
RUNDIR = dcase.get_value('RUNDIR')
print('Run directory is:', RUNDIR)
print('Casename is:', dcase.casename)
Run directory is: /glade/scratch/gmarques/g.c2b6.GJRA.TL319_t061.long_JRA_mct.076/run
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: stream = True


# Load mom6 grid
grd = dcase.grid
depth = grd.depth_ocean
# remote Nan's, otherwise genBasinMasks won't work
depth[numpy.isnan(depth)] = 0.0
MOM6 grid successfully loaded...

Create masks for different regions

[5]: basin_code = genBasinMasks(grd.geolon, grd.geolat, depth)


11.16427964664149 64.78854837178643 [391, 434]

Check code number for each region defined

[6]: vals = numpy.unique(basin_code)

[7]: for v in vals:


dummy = numpy.zeros(basin_code.shape)
dummy[basin_code == v] = v
dummy = numpy.ma.masked_where(depth == 0., dummy)
plt.figure(figsize=(12,8))
xyplot(dummy, grd.geolon, grd.geolat,title='Code = '+str(v))

<Figure size 864x576 with 0 Axes>

6 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

<Figure size 864x576 with 0 Axes>

<Figure size 864x576 with 0 Axes>

1.1. Examples 7
mom6-tools Documentation, Release 0.0.post86

<Figure size 864x576 with 0 Axes>

<Figure size 864x576 with 0 Axes>

8 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

<Figure size 864x576 with 0 Axes>

<Figure size 864x576 with 0 Axes>

1.1. Examples 9
mom6-tools Documentation, Release 0.0.post86

<Figure size 864x576 with 0 Axes>

<Figure size 864x576 with 0 Axes>

10 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

<Figure size 864x576 with 0 Axes>

<Figure size 864x576 with 0 Axes>

1.1. Examples 11
mom6-tools Documentation, Release 0.0.post86

<Figure size 864x576 with 0 Axes>

<Figure size 864x576 with 0 Axes>

12 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[8]: # reload codes as dataarray


basin_code = genBasinMasks(grd.geolon, grd.geolat, depth, xda=True)
11.16427964664149 64.78854837178643 [391, 434]

Noticed that point [391, 434] does not belong to any of the masks generated. This is okay but let see where this point
is located:

[9]: plt.figure(figsize=(12,8))
xyplot(basin_code[0,:].values, grd.geolon, grd.geolat)
plt.plot(grd.geolon[434,391], grd.geolat[434,391],'xr', ms=10);
<Figure size 864x576 with 0 Axes>

1.1. Examples 13
mom6-tools Documentation, Release 0.0.post86

Now, let’s plot the masking for all the regions:

[10]: for r in range(len(basin_code.region)):


#plt.figure(figsize=(12,8))
xyplot((basin_code[0,:]+basin_code[r,:]*2).values, grd.geolon, grd.geolat,
title=str(basin_code['region'][r].values))

14 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 15
mom6-tools Documentation, Release 0.0.post86

16 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 17
mom6-tools Documentation, Release 0.0.post86

18 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 19
mom6-tools Documentation, Release 0.0.post86

20 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1.3 Ocean stats

[1]: from mom6_tools.DiagsCase import DiagsCase


import yaml,os
import pandas as pd
(continues on next page)

1.1. Examples 21
mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


import glob
import xarray
import cftime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams.update({'font.size': 22})

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
print('Casename is:', dcase.casename)
RUNDIR = dcase.get_value('RUNDIR')
all_files = glob.glob(os.path.join(RUNDIR, "ocean.stats"))
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: colnames = ['Step','Day','Truncs','Energy/Mass','Maximum CFL', 'Mean Sea Level',


˓→'Total Mass', 'Mean Salin', 'Mean Temp', 'Frac Mass Err', 'Salin Err', 'Temp Err']

units = ['nondim','days','nondim','m2 s-2','nondim', 'm', 'kg', 'PSU', 'degC', 'nondim


˓→', 'PSU', 'degC']

[5]: df = pd.read_csv(all_files[0], header=1, error_bad_lines=False, sep=',', names =


˓→colnames)

[6]: df.head(10)
[6]: Step Day Truncs Energy/Mass Maximum CFL \
0 0 0.0 0 En 2.4571649248052563E-23 CFL 0.00000
1 23 1.0 0 En 9.8082713560573701E-04 CFL 0.05888
2 47 2.0 0 En 1.0477053248426859E-03 CFL 0.05146
3 71 3.0 0 En 1.1103548714490880E-03 CFL 0.05868
4 95 4.0 0 En 1.0897107455835520E-03 CFL 0.06285
5 119 5.0 0 En 1.0783292792344746E-03 CFL 0.07048
6 143 6.0 0 En 1.0541041612146653E-03 CFL 0.06984
7 167 7.0 0 En 1.0405843511657768E-03 CFL 0.09139
8 191 8.0 0 En 1.0315200927403297E-03 CFL 0.07750
9 215 9.0 0 En 1.0428894544672127E-03 CFL 0.08749

Mean Sea Level Total Mass Mean Salin Mean Temp Frac Mass Err \
0 SL -1.3599E-10 M 1.38614E+21 S 34.7202 T 3.5781 Me 0.00E+00
1 SL -1.3812E-10 M 1.38614E+21 S 34.7202 T 3.5780 Me 1.78E-19
2 SL -1.3812E-10 M 1.38614E+21 S 34.7202 T 3.5780 Me 1.73E-20
3 SL -1.3883E-10 M 1.38614E+21 S 34.7202 T 3.5779 Me -1.34E-19
4 SL -1.3599E-10 M 1.38614E+21 S 34.7202 T 3.5779 Me -4.33E-19
5 SL -1.3812E-10 M 1.38614E+21 S 34.7202 T 3.5778 Me 3.42E-19
6 SL -1.3670E-10 M 1.38614E+21 S 34.7202 T 3.5778 Me 1.21E-19
7 SL -1.3670E-10 M 1.38614E+21 S 34.7202 T 3.5779 Me 2.71E-19
8 SL -1.3812E-10 M 1.38614E+21 S 34.7202 T 3.5779 Me 4.49E-19
9 SL -1.4097E-10 M 1.38614E+21 S 34.7202 T 3.5780 Me -2.09E-19

Salin Err Temp Err


(continues on next page)

22 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


0 Se 0.00E+00 Te 0.00E+00
1 Se 1.66E-16 Te -1.62E-18
2 Se -1.73E-17 Te -6.76E-18
3 Se -1.62E-17 Te 3.13E-18
4 Se -7.36E-18 Te -2.23E-18
5 Se 5.70E-17 Te 3.63E-18
6 Se -1.85E-17 Te -9.41E-19
7 Se 1.30E-17 Te 5.78E-19
8 Se -2.64E-17 Te 1.02E-18
9 Se 2.38E-17 Te 1.99E-18

[7]: # transfor to xarray and change/rename the coords


xr = df.to_xarray()
del xr['index'], xr['Step']
xr = xr.rename({'index': 'Day'})
xr.set_coords('Day')
[7]: <xarray.Dataset>
Dimensions: (Day: 21176)
Coordinates:
* Day (Day) float64 0.0 1.0 2.0 ... 2.117e+04 2.117e+04 2.117e+04
Data variables:
Truncs (Day) int64 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0
Energy/Mass (Day) object ' En 2.4571649248052563E-23' ... ' En 1.
˓→0158479597159721E-03'

Maximum CFL (Day) object ' CFL 0.00000' ... ' CFL 0.08558'
Mean Sea Level (Day) object ' SL -1.3599E-10' ... ' SL -1.3243E-10'
Total Mass (Day) object ' M 1.38614E+21' ... ' M 1.38614E+21'
Mean Salin (Day) object ' S 34.7202' ' S 34.7202' ... ' S 34.7203'
Mean Temp (Day) object ' T 3.5781' ' T 3.5780' ... ' T 3.6890'
Frac Mass Err (Day) object ' Me 0.00E+00' ... ' Me 8.69E-20'
Salin Err (Day) object ' Se 0.00E+00' ... ' Se -4.23E-17'
Temp Err (Day) object ' Te 0.00E+00' ... ' Te -7.12E-21'

[8]: # add attrs units


k = 1
for var in xr.variables:
print(var,k, units[k])
xr[var].attrs['units'] = units[k]
k = k + 1
Day 1 days
Truncs 2 nondim
Energy/Mass 3 m2 s-2
Maximum CFL 4 nondim
Mean Sea Level 5 m
Total Mass 6 kg
Mean Salin 7 PSU
Mean Temp 8 degC
Frac Mass Err 9 nondim
Salin Err 10 PSU
Temp Err 11 degC

1.1. Examples 23
mom6-tools Documentation, Release 0.0.post86

Some columns have strings in them (e.g., CFL and En) and we need to remove them.

[9]: colnames = ['Energy/Mass','Maximum CFL', 'Mean Sea Level', 'Total Mass', 'Mean Salin',
˓→ 'Mean Temp', 'Frac Mass Err', 'Salin Err', 'Temp Err']

for var in colnames:


print(var)
nt = len(xr[var])
dummy = np.zeros(nt)
for t in range(nt):
dummy[t] = float(str(xr[var][t].values).strip().split()[1])

xr[var].values[:] = dummy[:]
Energy/Mass
Maximum CFL
Mean Sea Level
Total Mass
Mean Salin
Mean Temp
Frac Mass Err
Salin Err
Temp Err

[10]: xr = xr.astype(float)
xr.set_coords('Day')
#xr['Day'] = xr['Day']/365.
for var in colnames:
plt.figure(figsize=(12,8))
xr[var].plot()

24 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 25
mom6-tools Documentation, Release 0.0.post86

26 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 27
mom6-tools Documentation, Release 0.0.post86

28 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[11]: df_stats = xarray.open_dataset(RUNDIR+'/ocean.stats.nc')


df_stats
[11]: <xarray.Dataset>
Dimensions: (Interface: 66, Layer: 65, Time: 21176)
Coordinates:
* Layer (Layer) float64 1.25 3.75 6.25 ... 5.627e+03 5.876e+03
* Interface (Interface) float64 0.0 2.5 5.0 ... 5.503e+03 5.751e+03 6e+03
* Time (Time) timedelta64[ns] 0 days 1 days ... 21170 days
Data variables:
Ntrunc (Time) float64 ...
En (Time) float64 ...
APE (Time, Interface) float64 ...
KE (Time, Layer) float64 ...
H0 (Time, Interface) float64 ...
Mass_lay (Time, Layer) float64 ...
Mass (Time) float64 ...
Mass_chg (Time) float64 ...
Mass_anom (Time) float64 ...
max_CFL_trans (Time) float64 ...
max_CFL_lin (Time) float64 ...
Salt (Time) float64 ...
Salt_chg (Time) float64 ...
Salt_anom (Time) float64 ...
Heat (Time) float64 ...
Heat_chg (Time) float64 ...
Heat_anom (Time) float64 ...
age (Time) float64 ...
(continues on next page)

1.1. Examples 29
mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


Attributes:
filename: ./ocean.stats.nc

[12]: for var in df_stats.variables:


#print(var)
if var not in ['KE','APE','H0','Mass_lay','Layer', 'Interface','Time']:
plt.figure(figsize=(10,8))
df_stats[var].plot()

30 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 31
mom6-tools Documentation, Release 0.0.post86

32 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 33
mom6-tools Documentation, Release 0.0.post86

34 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 35
mom6-tools Documentation, Release 0.0.post86

36 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 37
mom6-tools Documentation, Release 0.0.post86

38 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 39
mom6-tools Documentation, Release 0.0.post86

40 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 41
mom6-tools Documentation, Release 0.0.post86

42 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[ ]:

1.1.4 Analysis of Surface Fields

mom6_tools.MOM6grid returns an object with MOM6 grid data.


mom6_tools.latlon_analysis has a collection of tools used to perform spatial analysis (e.g., time averages
and spatial mean).
The goal of this notebook is the following:
1) server as an example of how to post-process CESM/MOM6 output;
2) create time averages of surface fields;
3) create time-series of globally-averaged surface fields;
4) compare model results vs. observations (TODO);
5) compare model results vs. another model results (TODO).

1.1. Examples 43
mom6-tools Documentation, Release 0.0.post86

[1]: %matplotlib inline


from mom6_tools.MOM6grid import MOM6grid
from mom6_tools.DiagsCase import DiagsCase
from mom6_tools.latlon_analysis import time_mean_latlon
import matplotlib.pyplot as plt
import warnings, yaml
warnings.filterwarnings("ignore")
Basemap module not found. Some regional plots may not function properly

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
RUNDIR = dcase.get_value('RUNDIR')
print('Run directory is:', RUNDIR)
print('Casename is:', dcase.casename)
Run directory is: /glade/scratch/gmarques/g.c2b6.GJRA.TL319_t061.long_JRA_mct.076/run
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: # The following parameters must be set accordingly


######################################################
# Path to the run directory
path = "/glade/scratch/gmarques/"+dcase.casename+"/run/"
# name of ocean static file
static = dcase.casename+'.mom6.static.nc'
# name of forcing file
surface = dcase.casename+'.mom6.sfc_00*.nc'
# initial and final years for computing time mean
year_start = 1
year_end = 85
# array with 2D forcing variables to be processed
variables = ['SST','SSS','SSH']
# Put your name and email address below
author = 'Gustavo Marques ([email protected])'
######################################################
# create an empty class object
class args:
pass

args.infile = path+surface
# set avg dates
avg = diag_config_yml['Avg']
args.start_date = avg['start_date']
args.end_date = avg['end_date']
args.case_name = dcase.casename
args.variables = variables
args.savefigs = False
args.time_series = True
args.nw = 6 # requesting 6 workers

[5]: # load mom6 grid


grd = MOM6grid(path+static)
(continues on next page)

44 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


# plot time averages. If variables is NOT specified, all 2D variables will be plotted.
#time_mean_latlon_plot(args,grd, variables=args.variables)
time_mean_latlon(args,grd)
MOM6 grid successfully loaded...

Requesting 6 workers...

/proxy/38817/status
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-5-f6d6526d1eb0> in <module>
3 # plot time averages. If variables is NOT specified, all 2D variables will be
˓→plotted.

4 #time_mean_latlon_plot(args,grd, variables=args.variables)
----> 5 time_mean_latlon(args,grd)

~/libs/mom6-tools/mom6_tools/latlon_analysis.py in time_mean_latlon(args, grd,


˓→variables)

174 dtime = ds.time.values


175 data = np.ma.masked_invalid(ds1[var].values)
--> 176 ds_new = create_xarray_dataset(var,units,dtime)
177 # loop in time
178 for t in range(0,len(dtime)):

UnboundLocalError: local variable 'units' referenced before assignment

[ ]:

1.1.5 Analysis of Forcing Fields

mom6_tools.MOM6grid returns an object with MOM6 grid data.


mom6_tools.latlon_analysis has a collection of tools used to perform spatial analysis (e.g., time averages
and spatial mean).
The goal of this notebook is the following:
1) serve as an example of how to post-process CESM/MOM6 output;
2) create time averages of forcing fields;
3) create time-series of globally-averaged forcing fields;
4) compare model results vs. observations (TODO);
5) compare model results vs. another model results (TODO).

[1]: %matplotlib inline


from mom6_tools.MOM6grid import MOM6grid
from mom6_tools.DiagsCase import DiagsCase
from mom6_tools.m6toolbox import genBasinMasks
from mom6_tools.latlon_analysis import time_mean_latlon
import matplotlib.pyplot as plt
import numpy as np
import yaml

1.1. Examples 45
mom6-tools Documentation, Release 0.0.post86

Basemap module not found. Some regional plots may not function properly

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
RUNDIR = dcase.get_value('RUNDIR')
print('Run directory is:', RUNDIR)
print('Casename is:', dcase.casename)
Run directory is: /glade/scratch/gmarques/g.c2b6.GJRA.TL319_t061.long_JRA_mct.076/run
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: # create an empty class object


class args:
pass

args.case_name = dcase.casename
args.start_date = ''
args.end_date = ''
args.savefigs = False

[5]: # set avg dates


avg = diag_config_yml['Avg']
if not args.start_date : args.start_date = avg['start_date']
if not args.end_date : args.end_date = avg['end_date']

[9]: # The following parameters must be set accordingly


######################################################
# name of forcing file
forcing = dcase.casename+'.mom6.hm*.nc'
######################################################

args.infile = RUNDIR+'/'+forcing
# array with 2D forcing variables to be processed
args.variables = ['hfds','PRCmE','taux','tauy']
args.savefigs = False
args.time_series = True
args.nw = 6 # number of workers

[10]: # Load the grid


grd = dcase.grid
depth = grd.depth_ocean
# remove Nan's, otherwise genBasinMasks won't work
depth[np.isnan(depth)] = 0.0
basin_code = genBasinMasks(grd.geolon, grd.geolat, depth, verbose=False)
11.16427964664149 64.78854837178643 [391, 434]

[11]: %matplotlib inline


# plot time averages. If variables is NOT specified, all 2D variables will be plotted.
(continues on next page)

46 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


#time_mean_latlon_plot(args,grd, variables=args.variables)
time_mean_latlon(args,grd,args.variables)
Requesting 6 workers...

/proxy/45255/status
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-11-41e50666a1cc> in <module>
2 # plot time averages. If variables is NOT specified, all 2D variables will be
˓→plotted.

3 #time_mean_latlon_plot(args,grd, variables=args.variables)
----> 4 time_mean_latlon(args,grd,args.variables)

~/libs/mom6-tools/mom6_tools/latlon_analysis.py in time_mean_latlon(args, grd,


˓→variables)

134 ds = xr.open_mfdataset(args.infile, \
135 parallel=True, data_vars='minimal', chunks={'time': 12},\
--> 136 coords='minimal', compat='override', preprocess=preprocess)
137 else:
138 ds = xr.open_mfdataset(args.infile, \

~/miniconda3/envs/analysis/lib/python3.7/site-packages/xarray/backends/api.py in open_
˓→mfdataset(paths, chunks, concat_dim, compat, preprocess, engine, lock, data_vars,

˓→coords, combine, autoclose, parallel, join, **kwargs)

931 coords=coords,
932 join=join,
--> 933 from_openmfds=True,
934 )
935 elif combine == "nested":

~/miniconda3/envs/analysis/lib/python3.7/site-packages/xarray/core/combine.py in auto_
˓→combine(datasets, concat_dim, compat, data_vars, coords, fill_value, join, from_

˓→openmfds)

853 coords=coords,
854 fill_value=fill_value,
--> 855 join=join,
856 )
857

~/miniconda3/envs/analysis/lib/python3.7/site-packages/xarray/core/combine.py in _old_
˓→auto_combine(datasets, concat_dim, compat, data_vars, coords, fill_value, join)

917 join=join,
918 )
--> 919 for vars, datasets in grouped
920 ]
921 else:

~/miniconda3/envs/analysis/lib/python3.7/site-packages/xarray/core/combine.py in
˓→<listcomp>(.0)

917 join=join,
918 )
--> 919 for vars, datasets in grouped
920 ]
921 else:

~/miniconda3/envs/analysis/lib/python3.7/site-packages/xarray/core/combine.py in _
(continues on next page)
˓→auto_concat(datasets, dim, data_vars, coords, fill_value, join, compat)

1.1. Examples 47
mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


953 elif len(concat_dims) == 0:
954 raise ValueError(
--> 955 "cannot infer dimension to concatenate: "
956 "supply the ``concat_dim`` argument "
957 "explicitly"

ValueError: cannot infer dimension to concatenate: supply the ``concat_dim`` argument


˓→explicitly

[ ]:

1.1.6 Temperature and Salinity at Depth Levels

The goal of this notebook is the following:


1) serve as an example of how to post-process CESM/MOM6 output;
2) create time averages of T/S fields at depth levels and compared agains observations (PHC2);
/glade/p/cesm/omwg/obs_data/phc/PHC2_TEMP_tx0.66v1_34lev_ann_avg.nc
/glade/p/cesm/omwg/obs_data/phc/PHC2_SALT_tx0.66v1_34lev_ann_avg.nc
5) compare model results vs. another model results (TODO).
Temprature and salinity comparisons (model vs obs) at selected depth levels are grouped into the following regions:
Global, Antarctic, and Arctic.

[1]: %matplotlib inline


from mom6_tools.MOM6grid import MOM6grid
from mom6_tools.m6plot import xycompare, polarcomparison
from mom6_tools.DiagsCase import DiagsCase
from mom6_tools import m6toolbox
import yaml
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
from IPython.display import display, Markdown, Latex
import warnings
warnings.filterwarnings("ignore")
Basemap module not found. Some regional plots may not function properly

[2]: # 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)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
print('Casename is:', dcase.casename)
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: # Load the grid


grd = dcase.grid

48 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

MOM6 grid successfully loaded...

[5]: parallel, cluster, client = m6toolbox.request_workers(6)


Requesting 6 workers...

/proxy/38119/status

[15]: client
[15]: <Client: not connected>

[16]: # Compute the climatology dataset


#dset_climo = climo.stage()
variables = ['thetao', 'so', 'time', 'time_bnds']
RUNDIR = dcase.get_value('RUNDIR')

def preprocess(ds):
''' Compute montly averages and return the dataset with variables'''
return ds[variables].resample(time="1Y", closed='left', \
keep_attrs=True).mean(dim='time', keep_attrs=True)

ds = xr.open_mfdataset(RUNDIR+'/'+dcase.casename+'.mom6.h_*.nc', \
parallel=True, data_vars='minimal', \
coords='minimal', compat='override', preprocess=preprocess)

[8]: # load model output, averaged over 20 years


#out = dset_climo['20Y']
start_date = '0001-01-01'
end_date = '0058-12-31'
%time ds = ds.sel(time=slice(start_date, end_date))
CPU times: user 4.9 ms, sys: 973 µs, total: 5.87 ms
Wall time: 5.33 ms

[9]: print('Time averaging...')


%time
temp = np.ma.masked_invalid(ds.thetao.mean('time').values)
salt = np.ma.masked_invalid(ds.so.mean('time').values)
Time averaging...
CPU times: user 3 µs, sys: 0 ns, total: 3 µs
Wall time: 4.53 µs

[10]: client.close(); cluster.close()

[11]: # load PHC2 data


phc_path = '/glade/p/cesm/omwg/obs_data/phc/'
phc_temp = xr.open_mfdataset(phc_path+'PHC2_TEMP_tx0.66v1_34lev_ann_avg.nc', decode_
˓→coords=False, decode_times=False)

phc_salt = xr.open_mfdataset(phc_path+'PHC2_SALT_tx0.66v1_34lev_ann_avg.nc', decode_


˓→coords=False, decode_times=False)

1.1. Examples 49
mom6-tools Documentation, Release 0.0.post86

Global

[17]: %matplotlib inline


km = len(phc_temp['depth'])
for k in range(km):
if ds['z_l'][k].values < 100.0:
temp_obs = np.ma.masked_invalid(phc_temp['TEMP'][k,:].values)
xycompare(temp[k,:] , temp_obs, grd.geolon, grd.geolat, area=grd.area_t,
title1 = 'model temperature, depth ='+str(ds['z_l'][k].values)+ 'm',
title2 = 'observed temperature, depth ='+str(phc_temp['depth'][k].
˓→values)+ 'm',

suptitle=dcase.casename + ', averaged '+str(start_date)+ ' and ' +str(end_


˓→date),

clim=(-1.9,30.), dcolormap=plt.cm.bwr,
extend='both', dextend='neither', dlim=(-2,2),
show= True)
salt_obs = np.ma.masked_invalid(phc_salt['SALT'][k,:].values)
xycompare( salt[k,:] , salt_obs, grd.geolon, grd.geolat, area=grd.area_t,
title1 = 'model salinity, depth ='+str(ds['z_l'][k].values)+ 'm',
title2 = 'observed salinity, depth ='+str(phc_temp['depth'][k].values)+ 'm
˓→',

suptitle=dcase.casename, clim=(30,39.), dcolormap=plt.cm.bwr,


extend='both', dextend='neither', dlim=(-2,2),
show= True)

50 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 51
mom6-tools Documentation, Release 0.0.post86

52 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 53
mom6-tools Documentation, Release 0.0.post86

54 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 55
mom6-tools Documentation, Release 0.0.post86

56 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 57
mom6-tools Documentation, Release 0.0.post86

58 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 59
mom6-tools Documentation, Release 0.0.post86

60 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 61
mom6-tools Documentation, Release 0.0.post86

62 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Antarctic

[18]: # loop over depths and compare TS fields


km = len(phc_temp['depth'])
for k in range(km):
if (ds['z_l'][k].values < 100.):
temp_obs = np.ma.masked_invalid(phc_temp['TEMP'][k,:].values)
polarcomparison(temp[k,:] , temp_obs, grd,
title1 = 'model temperature, depth ='+str(ds['z_l'][k].values)+ 'm',
title2 = 'observed temperature, depth ='+str(phc_temp['depth'][k].
˓→values)+ 'm',

extend='both', dextend='neither', clim=(-1.9,10.5), dlim=(-2,2),


˓→dcolormap=plt.cm.bwr,

suptitle=dcase.casename + ', averaged '+str(start_date)+ ' to '


˓→+str(end_date),

proj='SP', show= True)

salt_obs = np.ma.masked_invalid(phc_salt['SALT'][k,:].values)
polarcomparison( salt[k,:] , salt_obs, grd,
title1 = 'model salinity, depth ='+str(ds['z_l'][k].values)+ 'm',
title2 = 'observed salinity, depth ='+str(phc_temp['depth'][k].values)+
˓→'m',

extend='both', dextend='neither', clim=(33.,35.), dlim=(-2,2),


˓→dcolormap=plt.cm.bwr,

suptitle=dcase.casename + ', averaged '+str(start_date)+ ' to '


˓→+str(end_date),

proj='SP', show= True)

1.1. Examples 63
mom6-tools Documentation, Release 0.0.post86

64 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 65
mom6-tools Documentation, Release 0.0.post86

66 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 67
mom6-tools Documentation, Release 0.0.post86

68 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 69
mom6-tools Documentation, Release 0.0.post86

70 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 71
mom6-tools Documentation, Release 0.0.post86

72 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 73
mom6-tools Documentation, Release 0.0.post86

74 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 75
mom6-tools Documentation, Release 0.0.post86

Arctic

[19]: # loop over depths and compare TS fields


km = len(phc_temp['depth'])
for k in range(km):
if (ds['z_l'][k].values < 100.):
temp_obs = np.ma.masked_invalid(phc_temp['TEMP'][k,:].values)
polarcomparison(temp[k,:] , temp_obs, grd,
title1 = 'model temperature, depth ='+str(ds['z_l'][k].values)+ 'm',
title2 = 'observed temperature, depth ='+str(phc_temp['depth'][k].
˓→values)+ 'm',

extend='both', dextend='neither', clim=(-1.9,10.5), dlim=(-2,2),


˓→dcolormap=plt.cm.bwr,

suptitle=dcase.casename + ', averaged '+str(start_date)+ ' to ' +str(end_


˓→date),

proj='NP', show= True)

salt_obs = np.ma.masked_invalid(phc_salt['SALT'][k,:].values)
polarcomparison( salt[k,:] , salt_obs, grd,
title1 = 'model salinity, depth ='+str(ds['z_l'][k].values)+ 'm',
title2 = 'observed salinity, depth ='+str(phc_temp['depth'][k].values)+ 'm
˓→',

extend='both', dextend='neither', clim=(32.,34.5), dlim=(-2,2),


˓→dcolormap=plt.cm.bwr,

suptitle=dcase.casename + ', averaged '+str(start_date)+ ' to ' +str(end_


˓→date),

proj='NP', show= True)

76 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 77
mom6-tools Documentation, Release 0.0.post86

78 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 79
mom6-tools Documentation, Release 0.0.post86

80 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 81
mom6-tools Documentation, Release 0.0.post86

82 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 83
mom6-tools Documentation, Release 0.0.post86

84 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 85
mom6-tools Documentation, Release 0.0.post86

86 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 87
mom6-tools Documentation, Release 0.0.post86

88 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[ ]:

[ ]:

1.1.7 Equatorial Upperocean model vs. obs comparison

The goal of this notebook is the following:


1) serve as an example of how to post-process CESM/MOM6 output;
2) create time averages of T, S and VEL fields and compared agains observations (PHC2 and Johnson et al, 2002);
/glade/p/cesm/omwg/obs_data/phc/PHC2_TEMP_tx0.66v1_34lev_ann_avg.nc
/glade/p/cesm/omwg/obs_data/phc/PHC2_SALT_tx0.66v1_34lev_ann_avg.nc
/glade/p/cesm/omwg/obs_data/johnson_pmel/meanfit_m.nc
TODO: * Compare potential density plots; * compare model results vs. another model results (TODO);

[1]: %matplotlib inline


from mom6_tools.MOM6grid import MOM6grid
from mom6_tools.m6toolbox import shiftgrid, request_workers
from mom6_tools.m6plot import yzcompare, yzplot
from mom6_tools.DiagsCase import DiagsCase
import yaml
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
from IPython.display import display, Markdown, Latex
import warnings
warnings.filterwarnings("ignore")
Basemap module not found. Some regional plots may not function properly

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
print('Casename is:', dcase.casename)
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: # Load the grid


RUNDIR = dcase.get_value('RUNDIR')
grd = MOM6grid(RUNDIR+'/'+dcase.casename+'.mom6.static.nc', xrformat=True)
grd_eq = grd.sel(yh=slice(-10,10))
MOM6 grid successfully loaded...

[5]: parallel, cluster, client = request_workers(6)

1.1. Examples 89
mom6-tools Documentation, Release 0.0.post86

Requesting 6 workers...

/proxy/8787/status

[6]: client
[6]: <Client: 'tcp://10.148.10.19:32847' processes=0 threads=0, memory=0 B>

[7]: # Compute the climatology dataset


#dset_climo = climo.stage()
variables = ['thetao', 'so', 'uo', 'time', 'time_bnds', 'e']
RUNDIR = dcase.get_value('RUNDIR')

def preprocess(ds):
''' Compute yearly averages and return the dataset with variables'''
return ds[variables].resample(time="1Y", closed='left', \
keep_attrs=True).mean(dim='time', keep_attrs=True)

ds = xr.open_mfdataset(RUNDIR+'/'+dcase.casename+'.mom6.h_*.nc', \
parallel=True, data_vars='minimal', \
coords='minimal', compat='override', preprocess=preprocess)

[8]: # load obs


phc_path = '/glade/p/cesm/omwg/obs_data/phc/'
phc_temp = xr.open_mfdataset(phc_path+'PHC2_TEMP_tx0.66v1_34lev_ann_avg.nc')#.
˓→sel(Y=slice(-10,10))

phc_salt = xr.open_mfdataset(phc_path+'PHC2_SALT_tx0.66v1_34lev_ann_avg.nc')#.
˓→sel(Y=slice(-10,10))

johnson = xr.open_dataset('/glade/p/cesm/omwg/obs_data/johnson_pmel/meanfit_m.nc')

[9]: # get theta and salt and rename coordinates to be the same as the model's
thetao_obs = phc_temp.TEMP.rename({'X': 'xh','Y': 'yh', 'depth': 'z_l'});
salt_obs = phc_salt.SALT.rename({'X': 'xh','Y': 'yh', 'depth': 'z_l'});

[10]: # set coordinates to the same as the model's


thetao_obs['xh'] = ds.xh; thetao_obs['yh'] = ds.yh;
salt_obs['xh'] = ds.xh; salt_obs['yh'] = ds.yh;

[11]: # select in space and time


avg = diag_config_yml['Avg']
start_date = avg['start_date']
end_date = avg['end_date']

%time ds = ds.sel(time=slice(start_date, end_date)).sel(yh=slice(-10,10)).isel(z_


˓→i=slice(0,15)).isel(z_l=slice(0,14))

CPU times: user 14.5 ms, sys: 0 ns, total: 14.5 ms


Wall time: 14 ms

[12]: print('Time averaging...')


thetao = ds.thetao.mean('time')
so = ds.so.mean('time')
uo = ds.uo.mean('time')
eta = ds.e.mean('time')

90 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Time averaging...

[13]: print('Selecting equatorial data...')


# find point closest to eq. and select data
j = np.abs( grd_eq.geolat[:,0].values - 0. ).argmin()
temp_eq = np.ma.masked_invalid(thetao.isel(yh=j).values)
salt_eq = np.ma.masked_invalid(so.isel(yh=j).values)
u_eq = np.ma.masked_invalid(uo.isel(yh=j).values)
e_eq = np.ma.masked_invalid(eta.isel(yh=j).values)
thetao_obs_eq = np.ma.masked_invalid(thetao_obs.sel(yh=slice(-10,10)).isel(yh=j).
˓→isel(z_l=slice(0,14)).values)

salt_obs_eq = np.ma.masked_invalid(salt_obs.sel(yh=slice(-10,10)).isel(yh=j).isel(z_
˓→l=slice(0,14)).values)

Selecting equatorial data...

[14]: client.close(); cluster.close()

[15]: y = ds.yh.values
zz = ds.z_i.values
x = ds.xh.values
[X, Z] = np.meshgrid(x, zz)
z = 0.5 * ( Z[:-1] + Z[1:])

[16]: %matplotlib inline


fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(14,16))
yzcompare(temp_eq , thetao_obs_eq, x, -Z,
title1 = 'model temperature',
title2 = 'observed temperature (PHC/Levitus)', axis=ax,
suptitle=dcase.casename + ', averaged '+str(start_date)+ ' to ' +str(end_
˓→date),

extend='neither', dextend='neither', clim=(6,31.), dlim=(-5,5), dcolormap=plt.


˓→cm.bwr)

1.1. Examples 91
mom6-tools Documentation, Release 0.0.post86

92 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[17]: %matplotlib inline


fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(12,16))
yzcompare(salt_eq , salt_obs_eq, x, -Z,
title1 = 'model salinity',
title2 = 'observed salinity (PHC/Levitus)', axis=ax,
suptitle=dcase.casename + ', averaged '+str(start_date)+ ' to ' +str(end_
˓→date),

extend='neither', dextend='neither', clim=(33.5,37.), dlim=(-1,1),


˓→dcolormap=plt.cm.bwr)

1.1. Examples 93
mom6-tools Documentation, Release 0.0.post86

94 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[18]: %matplotlib inline


fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(12,8))
yzplot(temp_eq, x, -Z, axis=ax, clim=(5,31), landcolor=[0., 0., 0.], ignore=np.nan)
cs1 = ax.contour( x + 0*z, -z, temp_eq, colors='k',); plt.clabel(cs1,fmt='%2.1f',
˓→fontsize=14)

plt.ylim(-400,0)
[18]: (-400, 0)

[19]: fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(12,8))


yzplot(thetao_obs_eq, x, -Z, axis=ax, clim=(5,31))
cs1 = ax.contour( x + 0*z, -z, thetao_obs_eq, colors='k',); plt.clabel(cs1,fmt='%2.1f
˓→', fontsize=14)

ax.set_ylim(-400,0)
[19]: (-400, 0)

1.1. Examples 95
mom6-tools Documentation, Release 0.0.post86

[20]: # Shift model data to compare against obs


tmp, lonh = shiftgrid(thetao.xh[-1].values, thetao[0,0,:].values, ds.thetao.xh.values)
tmp, lonq = shiftgrid(uo.xq[-1].values, uo[0,0,:].values, uo.xq.values)

thetao['xh'].values[:] = lonh
so['xh'].values[:] = lonh
uo['xq'].values[:] = lonq

[21]: # y and z from obs


y_obs = johnson.YLAT11_101.values
zz = np.arange(0,510,10)
[Y, Z_obs] = np.meshgrid(y_obs, zz)
z_obs = 0.5 * ( Z_obs[0:-1,:] + Z_obs[1:,] )

[22]: # y and z from model


y_model = thetao.yh.values
z = eta.z_i.values
[Y, Z_model] = np.meshgrid(y_model, z)
z_model = 0.5 * ( Z_model[0:-1,:] + Z_model[1:,:] )

[23]: longitudes = [143., 156., 165., 180., 190., 205., 220., 235., 250., 265.]

[24]: # Temperature
for l in longitudes:
(continues on next page)

96 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(16,8))
dummy_model = np.ma.masked_invalid(thetao.sel(xh=l, method='nearest').values)
dummy_obs = np.ma.masked_invalid(johnson.POTEMPM.sel(XLON=l, method='nearest').
˓→values)

yzplot(dummy_model, y_model, -Z_model, clim=(9,29), axis=ax1, zlabel='Depth',


˓→ylabel='Latitude', title=str(dcase.casename))

cs1 = ax1.contour( y_model + 0*z_model, -z_model, dummy_model, levels=np.arange(0,


˓→30,2), colors='k',); plt.clabel(cs1,fmt='%3.1f', fontsize=14)

ax1.set_ylim(-400,0)
yzplot(dummy_obs, y_obs, -Z_obs, clim=(9,29), axis=ax2, zlabel='Depth', ylabel=
˓→'Latitude', title='Johnson et al (2002)')

cs2 = ax2.contour( y_obs + 0*z_obs, -z_obs, dummy_obs, levels=np.arange(0,30,2),


˓→colors='k',); plt.clabel(cs2,fmt='%3.1f', fontsize=14)

ax2.set_ylim(-400,0)
plt.suptitle('Temperature [C] @ '+str(l)+ ', averaged between '+str(start_date)+'
˓→and '+str(end_date))

1.1. Examples 97
mom6-tools Documentation, Release 0.0.post86

98 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 99
mom6-tools Documentation, Release 0.0.post86

100 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 101


mom6-tools Documentation, Release 0.0.post86

[25]: for l in longitudes:


# Salt
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(16,8))
dummy_model = np.ma.masked_invalid(so.sel(xh=l, method='nearest').values)
dummy_obs = np.ma.masked_invalid(johnson.SALINITYM.sel(XLON=l, method='nearest').
˓→values)

yzplot(dummy_model, y_model, -Z_model, clim=(32,36), axis=ax1, zlabel='Depth',


˓→ylabel='Latitude', title=str(dcase.casename))

cs1 = ax1.contour( y_model + 0*z_model, -z_model, dummy_model, levels=np.


˓→arange(32,36,0.5), colors='k',); plt.clabel(cs1,fmt='%3.1f', fontsize=14)

ax1.set_ylim(-400,0)
yzplot(dummy_obs, y_obs, -Z_obs, clim=(32,36), axis=ax2, zlabel='Depth', ylabel=
˓→'Latitude', title='Johnson et al (2002)')

cs2 = ax2.contour( y_obs + 0*z_obs, -z_obs, dummy_obs, levels=np.arange(32,36,0.


˓→5), colors='k',); plt.clabel(cs2,fmt='%3.1f', fontsize=14)

ax2.set_ylim(-400,0)
plt.suptitle('Salinity [psu] @ '+str(l)+ ', averaged between '+str(start_date)+'
˓→and '+str(end_date))

102 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 103


mom6-tools Documentation, Release 0.0.post86

104 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 105


mom6-tools Documentation, Release 0.0.post86

106 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[26]: for l in longitudes:


# uo
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(16,8))
dummy_model = np.ma.masked_invalid(uo.sel(xq=l, method='nearest').values)
dummy_obs = np.ma.masked_invalid(johnson.UM.sel(XLON=l, method='nearest').values)
yzplot(dummy_model, y_model, -Z_model, clim=(-1,1), axis=ax1, zlabel='Depth',
˓→ylabel='Latitude', title=str(dcase.casename))

cs1 = ax1.contour( y_model + 0*z_model, -z_model, dummy_model, levels=np.arange(-


˓→1,1,0.1), colors='k',); plt.clabel(cs1,fmt='%3.1f', fontsize=14)
(continues on next page)

1.1. Examples 107


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


ax1.set_ylim(-400,0)
yzplot(dummy_obs, y_obs, -Z_obs, clim=(-1,1), axis=ax2, zlabel='Depth', ylabel=
˓→'Latitude', title='Johnson et al (2002)')

cs2 = ax2.contour( y_obs + 0*z_obs, -z_obs, dummy_obs, levels=np.arange(-1,1,0.1),


˓→ colors='k',); plt.clabel(cs2,fmt='%3.1f', fontsize=14)

ax2.set_ylim(-400,0)
plt.suptitle('Eastward velocity [m/s] @ '+str(l)+ ', averaged between '+str(start_
˓→date)+' and '+str(end_date))

108 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 109


mom6-tools Documentation, Release 0.0.post86

110 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 111


mom6-tools Documentation, Release 0.0.post86

[27]: x_obs = johnson.XLON.values


[X_obs, Z_obs] = np.meshgrid(x_obs, zz)
z_obs = 0.5 * ( Z_obs[:-1,:] + Z_obs[1:,:] )

[28]: x_model = so.xh.values


z = eta.z_i.values
[X, Z_model] = np.meshgrid(x_model, z)
z_model = 0.5 * ( Z_model[:-1,:] + Z_model[1:,:] )

112 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[32]: #from mom6_tools.m6plot import


fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(16,8))
dummy_obs = np.ma.masked_invalid(johnson.UM.sel(YLAT11_101=0).values)
dummy_model = np.ma.masked_invalid(uo.sel(yh=0, method='nearest').values)

yzplot(dummy_model, x_model, -Z_model, clim=(-0.4,1.2), axis=ax1, landcolor=[0., 0.,


˓→0.], title=str(dcase.casename), ylabel='Longitude', yunits=r'$^o$E' )

cs1 = ax1.contour( x_model + 0*z_model, -z_model, dummy_model, levels=np.arange(-1.2,


˓→1.2,0.1), colors='k',); plt.clabel(cs1,fmt='%2.1f', fontsize=14)

ax1.set_xlim(143,265); ax1.set_ylim(-400,0)
yzplot(dummy_obs, x_obs, -Z_obs, clim=(-0.4,1.2), axis=ax2, title='Johnson et al
˓→(2002)', ylabel='Longitude', yunits=r'$^o$E' )

cs1 = ax2.contour( x_obs + 0*z_obs, -z_obs, dummy_obs, levels=np.arange(-1.2,1.2,0.


˓→1), colors='k',); plt.clabel(cs1,fmt='%2.1f', fontsize=14)

ax2.set_xlim(143,265); ax2.set_ylim(-400,0)
plt.suptitle('Eastward velocity [m/s] along the Equatorial Pacific, averaged between
˓→'+str(start_date)+' and '+str(end_date))

[32]: Text(0.5, 0.98, 'Eastward velocity [m/s] along the Equatorial Pacific, averaged
˓→between 0029-01-01 and 0059-01-01')

[ ]:

1.1.8 Globally Averaged Ocean Temperature and Salinity

[1]: from mom6_tools.DiagsCase import DiagsCase


import yaml
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import xarray as xr

1.1. Examples 113


mom6-tools Documentation, Release 0.0.post86

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
print('Casename is:', dcase.casename)
RUNDIR = dcase.get_value('RUNDIR')
print('RUNDIR:', RUNDIR)
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076
RUNDIR: /glade/scratch/gmarques/g.c2b6.GJRA.TL319_t061.long_JRA_mct.076/run

[4]: # load data


ds = xr.open_mfdataset(RUNDIR+'/*.mom6.hm_*nc',decode_times=False)

Time series

[5]: matplotlib.rcParams.update({'font.size': 18})


fig, axes = plt.subplots(nrows=2, figsize=(16, 8))
ax = axes[0]
ax.plot(ds.time.data/365., ds.thetaoga[:,0].data)
ax.set_ylabel(r'$^o$C')
ax.set_title("Global average temperature")
fig.autofmt_xdate()

ax = axes[1]
ax.plot(ds.time.data/365., ds.soga[:,0].data)
ax.set_title("Global average salinity")
ax.set_ylabel('PSU')
ax.set_ylim(ds.soga.min(),ds.soga.max())
ax.set_xlabel('Year')
fig.autofmt_xdate()

114 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[ ]:

1.1.9 Meridional Overturning

mom6_tools.moc functions for computing and plotting meridional overturning.


The goal of this notebook is the following:
1) server as an example on to compute a meridional overturning streamfunction (global and Atalntic) from
CESM/MOM output;
2) evaluate model experiments by comparing transports against observed estimates and other model results.

[1]: %matplotlib inline


import matplotlib
import numpy as np
import xarray as xr
# mom6_tools
from mom6_tools.moc import *
from mom6_tools.DiagsCase import DiagsCase
from mom6_tools.m6toolbox import request_workers, genBasinMasks, add_global_attrs
import matplotlib.pyplot as plt
import warnings, yaml, os
warnings.filterwarnings("ignore")
Basemap module not found. Some regional plots may not function properly

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

# Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
RUNDIR = dcase.get_value('RUNDIR')
print('Run directory is:', RUNDIR)
print('Casename is:', dcase.casename)
Run directory is: /glade/scratch/gmarques/g.c2b6.GJRA.TL319_t061.long_JRA_mct.076/run
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[3]: # The following parameters must be set accordingly


######################################################
# add your name and email address below
author = 'Gustavo Marques ([email protected])'
######################################################
# create an empty class object
class args:
pass

args.infile = RUNDIR
args.monthly = dcase.casename+'.mom6.h_*nc'
args.sigma2 = dcase.casename+'.mom6.rho2_*nc'
args.start_date = ''
args.end_date = ''
args.case_name = dcase.casename
(continues on next page)

1.1. Examples 115


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


args.label = ''
args.savefigs = False

[4]: # set avg dates


avg = diag_config_yml['Avg']
if not args.start_date : args.start_date = avg['start_date']
if not args.end_date : args.end_date = avg['end_date']

[5]: # Load the grid


grd = dcase.grid
depth = grd.depth_ocean
# remove Nan's, otherwise genBasinMasks won't work
depth[np.isnan(depth)] = 0.0
basin_code = genBasinMasks(grd.geolon, grd.geolat, depth, verbose=False)
MOM6 grid successfully loaded...

11.16427964664149 64.78854837178643 [391, 434]

[6]: parallel, cluster, client = m6toolbox.request_workers(6)


Requesting 6 workers...

/proxy/43847/status

[7]: client
[7]: <Client: 'tcp://10.148.10.19:45211' processes=0 threads=0, memory=0 B>

[8]: def preprocess(ds):


variables = ['vmo','vhml','vhGM']
for v in variables:
if v not in ds.variables:
ds[v] = xr.zeros_like(ds.vo)
return ds[variables]

[9]: print('\n Reading dataset...')


# load data
%time ds = xr.open_mfdataset(RUNDIR+'/'+dcase.casename+'.mom6.h_*.nc', parallel=True,
˓→\

combine="nested", concat_dim="time",
˓→preprocess=preprocess).chunk({"time": 12})

Reading dataset...
CPU times: user 1.6 s, sys: 185 ms, total: 1.78 s
Wall time: 27.5 s

[10]: # compute yearly means first since this will be used in the time series
print('\n Computing yearly means...')
%time ds_yr = ds.resample(time="1Y", closed='left').mean('time')

Computing yearly means...


CPU times: user 1.15 s, sys: 11.4 ms, total: 1.16 s
Wall time: 1.14 s

116 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[11]: print('\n Selecting data between {} and {}...'.format(args.start_date, args.end_date))


%time ds_sel = ds_yr.sel(time=slice(args.start_date, args.end_date))

Selecting data between 0029-01-01 and 0059-01-01...


CPU times: user 13.4 ms, sys: 0 ns, total: 13.4 ms
Wall time: 11.9 ms

[12]: print('\n Computing time mean...')


%time ds_mean = ds_sel.mean('time').compute()

Computing time mean...


CPU times: user 2.04 s, sys: 412 ms, total: 2.45 s
Wall time: 11.8 s

[14]: stream = True


# create a ndarray subclass
class C(np.ndarray): pass

if 'vmo' in ds.variables:
varName = 'vmo'; conversion_factor = 1.e-9
elif 'vh' in ds.variables:
varName = 'vh'; conversion_factor = 1.e-6
if 'zw' in ds.variables: conversion_factor = 1.e-9 # Backwards compatible for when
˓→we had wrong units for 'vh'

else: raise Exception('Could not find "vh" or "vmo" in file "%s"'%(args.infile+args.


˓→static))

tmp = np.ma.masked_invalid(ds_mean[varName].values)
tmp = tmp[:].filled(0.)
VHmod = tmp.view(C)
VHmod.units = ds[varName].units

Zmod = m6toolbox.get_z(ds, depth, varName)

if args.case_name != '': case_name = args.case_name + ' ' + args.label


else: case_name = rootGroup.title + ' ' + args.label

Global MOC

[15]: %matplotlib inline

# Global MOC
m6plot.setFigureSize([16,9],576,debug=False)
axis = plt.gca()
cmap = plt.get_cmap('dunnePM')
zg = Zmod.min(axis=-1); psiPlot = MOCpsi(VHmod)*conversion_factor
psiPlot = 0.5 * (psiPlot[0:-1,:]+psiPlot[1::,:])
yyg = grd.geolat_c[:,:].max(axis=-1)+0*zg

ci=m6plot.pmCI(0.,40.,5.)
plotPsi(yyg, zg, psiPlot, ci, 'Global MOC [Sv]')
(continues on next page)

1.1. Examples 117


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


plt.xlabel(r'Latitude [$\degree$N]')
plt.suptitle(case_name)
plt.gca().invert_yaxis()
findExtrema(yyg, zg, psiPlot, max_lat=-30.)
findExtrema(yyg, zg, psiPlot, min_lat=25., min_depth=250.)
findExtrema(yyg, zg, psiPlot, min_depth=2000., mult=-1.)

[16]: # create dataset to store results


moc = xr.Dataset(data_vars={ 'moc' : (('z_l','yq'), psiPlot),
'amoc' : (('z_l','yq'), np.zeros((psiPlot.shape))),
'moc_FFM' : (('z_l','yq'), np.zeros((psiPlot.shape))),
'moc_GM' : (('z_l','yq'), np.zeros((psiPlot.shape))),
'amoc_45' : (('time'), np.zeros((ds_yr.time.shape))),
'moc_GM_ACC' : (('time'), np.zeros((ds_yr.time.shape))),
'amoc_26' : (('time'), np.zeros((ds_yr.time.shape))) },
coords={'z_l': ds.z_l, 'yq':ds.yq, 'time':ds_yr.time})
attrs = {'description': 'MOC time-mean sections and time-series', 'unit': 'Sv',
˓→'start_date': avg['start_date'],

'end_date': avg['end_date']}
add_global_attrs(moc,attrs)

Atlantic MOC

[18]: m6plot.setFigureSize([16,9],576,debug=False)
cmap = plt.get_cmap('dunnePM')
m = 0*basin_code; m[(basin_code==2) | (basin_code==4) | (basin_code==6) | (basin_
˓→code==7) | (basin_code==8)]=1

ci=m6plot.pmCI(0.,22.,2.)
(continues on next page)

118 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


z = (m*Zmod).min(axis=-1); psiPlot = MOCpsi(VHmod, vmsk=m*np.roll(m,-1,axis=-
˓→2))*conversion_factor

psiPlot = 0.5 * (psiPlot[0:-1,:]+psiPlot[1::,:])


yy = grd.geolat_c[:,:].max(axis=-1)+0*z
plotPsi(yy, z, psiPlot, ci, 'Atlantic MOC [Sv]')
plt.xlabel(r'Latitude [$\degree$N]')
plt.suptitle(case_name)
plt.gca().invert_yaxis()
findExtrema(yy, z, psiPlot, min_lat=26.5, max_lat=27., min_depth=250.) # RAPID
findExtrema(yy, z, psiPlot, min_lat=44, max_lat=46., min_depth=250.) # RAPID
findExtrema(yy, z, psiPlot, max_lat=-33.)
findExtrema(yy, z, psiPlot)
findExtrema(yy, z, psiPlot, min_lat=5.)
moc['amoc'].data = psiPlot

AMOC profile at 26N

[19]: rapid_vertical = xr.open_dataset('/glade/work/gmarques/cesm/datasets/RAPID/moc_


˓→vertical.nc')

[20]: if 'zl' in ds:


zl=ds.zl.values
elif 'z_l' in ds:
zl=ds.z_l.values
else:
raise ValueError("Dataset does not have vertical coordinate zl or z_l")

1.1. Examples 119


mom6-tools Documentation, Release 0.0.post86

[21]: fig, ax = plt.subplots(nrows=1, ncols=1)


ax.plot(rapid_vertical.stream_function_mar.mean('time'), rapid_vertical.depth, 'k',
˓→label='RAPID')

ax.plot(moc['amoc'].sel(yq=26, method='nearest'), moc.z_l, label=case_name)


ax.legend()
plt.gca().invert_yaxis()
plt.grid()
ax.set_xlabel('AMOC @ 26N [Sv]')
ax.set_ylabel('Depth [m]')
[21]: Text(0, 0.5, 'Depth [m]')

AMOC time series

[24]: dtime = ds_yr.time.values

amoc_26 = np.zeros(len(dtime))
amoc_45 = np.zeros(len(dtime))
moc_GM_ACC = np.zeros(len(dtime))

# loop in time
for t in range(len(dtime)):
tmp = np.ma.masked_invalid(ds_yr[varName].sel(time=dtime[t]).values)
tmp = tmp[:].filled(0.)
psi = MOCpsi(tmp, vmsk=m*np.roll(m,-1,axis=-2))*conversion_factor
psi = 0.5 * (psi[0:-1,:]+psi[1::,:])
amoc_26[t] = findExtrema(yy, z, psi, min_lat=26.5, max_lat=27., plot=False)
amoc_45[t] = findExtrema(yy, z, psi, min_lat=44., max_lat=46., plot=False)
tmp_GM = np.ma.masked_invalid(ds_yr['vhGM'][t,:].values)
tmp_GM = tmp_GM[:].filled(0.)
psiGM = MOCpsi(tmp_GM)*conversion_factor
psiGM = 0.5 * (psiGM[0:-1,:]+psiGM[1::,:])
moc_GM_ACC[t] = findExtrema(yyg, zg, psiGM, min_lat=-65., max_lat=-30, mult=-1.,
˓→plot=False)

[25]: # add dataarays to the moc dataset


moc['amoc_26'].data = amoc_26
(continues on next page)

120 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


moc['amoc_45'].data = amoc_45
moc['moc_GM_ACC'].data = moc_GM_ACC

[26]: moc['moc_GM_ACC'].plot()
[26]: [<matplotlib.lines.Line2D at 0x2b78932e5d30>]

AMOC @ 26 𝑜 N

[27]: # load AMOC time series data (5th) cycle used in Danabasoglu et al., doi:10.1016/j.
˓→ocemod.2015.11.007

path = '/glade/p/cesm/omwg/amoc/COREII_AMOC_papers/papers/COREII.variability/data.
˓→original/'

amoc_core_26 = xr.open_dataset(path+'AMOCts.cyc5.26p5.nc')
# load AMOC from POP JRA-55
amoc_pop_26 = xr.open_dataset('/glade/u/home/bryan/MOM6-modeloutputanalysis/'
'AMOC_series_26n.g210.GIAF_JRA.v13.gx1v7.01.nc')
# load RAPID time series
rapid = xr.open_dataset('/glade/work/gmarques/cesm/datasets/RAPID/moc_transports.nc').
˓→resample(time="1Y",

closed='left',keep_attrs=True).mean('time',keep_
˓→attrs=True)

# plot
fig = plt.figure(figsize=(12, 6))
plt.plot(np.arange(len(moc.time))+1958.5 ,moc['amoc_26'].values, color='k',
˓→label=case_name, lw=2)

# core data
core_mean = amoc_core_26['MOC'].mean(axis=0).data
core_std = amoc_core_26['MOC'].std(axis=0).data
plt.plot(amoc_core_26.time,core_mean, 'k', label='CORE II (group mean)', color='
˓→#1B2ACC', lw=1)

plt.fill_between(amoc_core_26.time, core_mean-core_std, core_mean+core_std,


alpha=0.25, edgecolor='#1B2ACC', facecolor='#089FFF')
# pop data
plt.plot(np.arange(len(amoc_pop_26.time))+1958.5 ,amoc_pop_26.AMOC_26n.values, color=
˓→'r', label='POP', lw=1)
(continues on next page)

1.1. Examples 121


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


# rapid
plt.plot(np.arange(len(rapid.time))+2004.5 ,rapid.moc_mar_hc10.values, color='green',
˓→label='RAPID', lw=1)

plt.title('AMOC @ 26 $^o$ N', fontsize=16)


plt.ylim(5,20)
plt.xlim(1948,1958.5+len(moc.time))
plt.xlabel('Time [years]', fontsize=16); plt.ylabel('Sv', fontsize=16)
plt.legend(fontsize=13, ncol=2)
[27]: <matplotlib.legend.Legend at 0x2b78937566d8>

AMOC @ 45 𝑜 N

[29]: amoc_core_45 = xr.open_dataset(path+'AMOCts.cyc5.45.nc')


amoc_pop_45 = xr.open_dataset('/glade/u/home/bryan/MOM6-modeloutputanalysis/'
'AMOC_series_45n.g210.GIAF_JRA.v13.gx1v7.01.nc')

# plot
fig = plt.figure(figsize=(12, 6))
plt.plot(np.arange(len(moc.time))+1958.5 ,moc['amoc_45'].values, color='k',
˓→label=case_name, lw=2)

# core data
core_mean = amoc_core_45['MOC'].mean(axis=0).data
core_std = amoc_core_45['MOC'].std(axis=0).data
plt.plot(amoc_core_45.time,core_mean, 'k', label='CORE II (group mean)', color='
˓→#1B2ACC', lw=1)

plt.fill_between(amoc_core_45.time, core_mean-core_std, core_mean+core_std,


alpha=0.25, edgecolor='#1B2ACC', facecolor='#089FFF')
# pop data
plt.plot(np.arange(len(amoc_pop_45.time))+1958. ,amoc_pop_45.AMOC_45n.values, color='r
˓→', label='POP', lw=1) (continues on next page)

122 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)

plt.title('AMOC @ 45 $^o$ N', fontsize=16)


plt.ylim(5,20)
plt.xlim(1948,1958+len(moc.time))
plt.xlabel('Time [years]', fontsize=16); plt.ylabel('Sv', fontsize=16)
plt.legend(fontsize=13, ncol=3)
[29]: <matplotlib.legend.Legend at 0x2b78aaea6438>

Submesoscale-induced Global MOC

[31]: # create a ndarray subclass


class C(np.ndarray): pass

if 'vhml' in ds.variables:
varName = 'vhml'; conversion_factor = 1.e-9
else: raise Exception('Could not find "vhml" in file "%s"'%(args.infile+args.monthly))

tmp = np.ma.masked_invalid(ds_mean[varName].values)
tmp = tmp[:].filled(0.)
VHmod = tmp.view(C)
VHmod.units = ds[varName].units

# Global MOC
m6plot.setFigureSize([16,9],576,debug=False)
axis = plt.gca()
cmap = plt.get_cmap('dunnePM')
z = Zmod.min(axis=-1); psiPlot = MOCpsi(VHmod)*conversion_factor
psiPlot = 0.5 * (psiPlot[0:-1,:]+psiPlot[1::,:])
#yy = y[1:,:].max(axis=-1)+0*z
yy = grd.geolat_c[:,:].max(axis=-1)+0*z
(continues on next page)

1.1. Examples 123


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


ci=m6plot.pmCI(0.,20.,2.)
plotPsi(yy, z, psiPlot, ci, 'Global MOC [Sv] due to vhML', zval=[0.,-400.,-6500.])
plt.xlabel(r'Latitude [$\degree$N]')
plt.suptitle(case_name)
plt.gca().invert_yaxis()
moc['moc_FFM'].data = psiPlot

Eddy(GM)-induced Global MOC

[32]: # create a ndarray subclass


class C(np.ndarray): pass

if 'vhGM' in ds.variables:
varName = 'vhGM'; conversion_factor = 1.e-9
else: raise Exception('Could not find "vhGM" in file "%s"'%(args.infile+args.monthly))

tmp = np.ma.masked_invalid(ds_mean[varName].values)
tmp = tmp[:].filled(0.)
VHmod = tmp.view(C)
VHmod.units = ds[varName].units

# Global MOC
m6plot.setFigureSize([16,9],576,debug=False)
axis = plt.gca()
cmap = plt.get_cmap('dunnePM')
z = Zmod.min(axis=-1); psiPlot = MOCpsi(VHmod)*conversion_factor
psiPlot = 0.5 * (psiPlot[0:-1,:]+psiPlot[1::,:])
yy = grd.geolat_c[:,:].max(axis=-1)+0*z
(continues on next page)

124 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


ci=m6plot.pmCI(0.,20.,1.)
plotPsi(yy, z, psiPlot, ci, 'Global MOC [Sv] due to GM')
plt.xlabel(r'Latitude [$\degree$N]')
plt.suptitle(case_name)
findExtrema(yy, z, psiPlot, min_lat=-65., max_lat=-30, mult=-1.)
plt.gca().invert_yaxis()
moc['moc_GM'].data = psiPlot

Sigma-2 space (to be implemented. . . )

[ ]: # load data
ds = xr.open_mfdataset(args.infile+args.sigma2,decode_times=False)

# create a ndarray subclass


class C(np.ndarray): pass

if 'vmo' in ds.variables:
varName = 'vmo'; conversion_factor = 1.e-9
elif 'vh' in ds.variables:
varName = 'vh'; conversion_factor = 1.e-6
if 'zw' in ds.variables: conversion_factor = 1.e-9 # Backwards compatible for when
˓→we had wrong units for 'vh'

else: raise Exception('Could not find "vh" or "vmo" in file "%s"'%(args.infile+args.


˓→static))

tmp = np.ma.masked_invalid(ds[varName].sel(time=slice(ti,tf)).mean('time').data)
tmp = tmp[:].filled(0.)
(continues on next page)

1.1. Examples 125


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


VHmod = tmp.view(C)
VHmod.units = ds[varName].units

Zmod = m6toolbox.get_z(ds, depth, varName)

if args.case_name != '': case_name = args.case_name + ' ' + args.label


else: case_name = rootGroup.title + ' ' + args.label

[34]: # release workers


client.close(); cluster.close()

[ ]:

1.1.10 Poleward Heat Transport

mom6_tools.polar_heat_transport collection of functions for computing and plotting poleward heat trans-
port.
The goal of this notebook is the following:
1) server as an example on to compute polar heat transport from CESM/MOM output;
2) evaluate model experiments by comparing transports against observed estimates;
3) compare model results vs. another model results (TODO).

[1]: %matplotlib inline


from mom6_tools.poleward_heat_transport import *
from mom6_tools.m6toolbox import genBasinMasks
from mom6_tools.DiagsCase import DiagsCase
import mom6_tools.m6toolbox
from datetime import datetime, date
import yaml
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import xarray as xr
import warnings
warnings.filterwarnings("ignore")
Basemap module not found. Some regional plots may not function properly

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
RUNDIR = dcase.get_value('RUNDIR')
print('Run directory is:', RUNDIR)
print('Casename is:', dcase.casename)
Run directory is: /glade/scratch/gmarques/g.c2b6.GJRA.TL319_t061.long_JRA_mct.076/run
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

126 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[4]: # create an empty class object


class args:
pass

args.case_name = dcase.casename
args.start_date = ''
args.end_date = ''
args.savefigs = False

[5]: # set avg dates


avg = diag_config_yml['Avg']
if not args.start_date : args.start_date = avg['start_date']
if not args.end_date : args.end_date = avg['end_date']

[6]: # Load the grid


grd = dcase.grid
depth = grd.depth_ocean
# remove Nan's, otherwise genBasinMasks won't work
depth[np.isnan(depth)] = 0.0
basin_code = genBasinMasks(grd.geolon, grd.geolat, depth, verbose=False)
MOM6 grid successfully loaded...

11.16427964664149 64.78854837178643 [391, 434]

[7]: parallel, cluster, client = m6toolbox.request_workers(6)


Requesting 6 workers...

/proxy/46825/status

[8]: client
[8]: <Client: 'tcp://10.148.10.19:40143' processes=0 threads=0, memory=0 B>

[9]: def preprocess(ds):


''' Compute montly averages and return the dataset with variables'''
ds
for var in variables:
print('Processing {}'.format(var))
if var not in ds.variables:
print('WARNING: ds does not have variable {}. Creating dataarray with zeros'.
˓→format(var))

jm, im = grd.geolat.shape
tm = len(ds.time)
da = xr.DataArray(numpy.zeros((tm, jm, im)), dims=['time', 'yq','xh'], \
coords={'yq' : grd.yq, 'xh' : grd.xh, 'time' : ds.time}).rename(var)
ds = xr.merge([ds, da])
return ds[variables]

[10]: print('\n Reading monthly (hm_*) dataset...')


# load data
variables = ['T_ady_2d', 'T_diffy_2d', 'T_lbd_diffy_2d']

%time ds = xr.open_mfdataset(RUNDIR+'/'+dcase.casename+'.mom6.hm_*.nc', \
parallel=True, data_vars='minimal', chunks={'time': 12},\
coords='minimal', compat='override', preprocess=preprocess)

1.1. Examples 127


mom6-tools Documentation, Release 0.0.post86

Reading monthly (hm_*) dataset...


CPU times: user 34.2 s, sys: 43.3 s, total: 1min 17s
Wall time: 1min 29s

[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)).load()

Selecting data between 0029-01-01 and 0059-01-01...


CPU times: user 5.52 s, sys: 2.35 s, total: 7.87 s
Wall time: 15.2 s

[12]: print('\n Computing yearly means...')


%time ds_sel = ds_sel.resample(time="1Y", closed='left',keep_attrs=True).mean('time',
˓→keep_attrs=True)

Computing yearly means...


CPU times: user 1.2 s, sys: 125 ms, total: 1.33 s
Wall time: 1.31 s

[13]: print('\n Computing time mean...')


%time ds_sel = ds_sel.mean('time').load()

Computing time mean...


CPU times: user 83.1 ms, sys: 15.3 ms, total: 98.4 ms
Wall time: 95 ms

[14]: # release workers


client.close(); cluster.close()

[16]: stream = True


# create a ndarray subclass
class C(np.ndarray): pass

varName = 'T_ady_2d'
if varName in ds.variables:
tmp = np.ma.masked_invalid(ds_sel[varName].values)
tmp = tmp[:].filled(0.)
advective = tmp.view(C)
advective.units = ds[varName].units
else:
raise Exception('Could not find "T_ady_2d" in ds')

varName = 'T_diffy_2d'
if varName in ds.variables:
tmp = np.ma.masked_invalid(ds_sel[varName].values)
tmp = tmp[:].filled(0.)
diffusive = tmp.view(C)
diffusive.units = ds[varName].units
else:
diffusive = None
warnings.warn('Diffusive temperature term not found. This will result in an
˓→underestimation of the heat transport.')

(continues on next page)

128 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)

varName = 'T_lbd_diffy_2d'
if varName in ds.variables:
tmp = np.ma.masked_invalid(ds_sel[varName].values)
tmp = tmp[:].filled(0.)
lbd = tmp.view(C)
#lbd.units = ds[varName].units
else:
lbd = None
warnings.warn('Lateral boundary mixing term not found. This will result in an
˓→underestimation of the heat transport.')

[17]: %matplotlib inline


# plot model vs obs
plt_heat_transport_model_vs_obs(advective, diffusive, lbd, basin_code, grd, args)

1.1. Examples 129


mom6-tools Documentation, Release 0.0.post86

130 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[ ]:

1.1.11 Transport across sections

mom6_tools.section_transports collection of functions for computing and plotting time-series of transports


across vertical sections.
The goal of this notebook is the following:
1) server as an example on how to post-process the CESM/MOM6 vertical sections defined in diag_table. The
location of the current vertical sections computed online can be found at the end of this notebook;
2) evaluate model experiments by comparing transports against observed estimates;
3) compare model results vs. another model results (TODO).

1.1. Examples 131


mom6-tools Documentation, Release 0.0.post86

[1]: %matplotlib inline


from mom6_tools.section_transports import Transport, options
import matplotlib.pyplot as plt
from mom6_tools.DiagsCase import DiagsCase
import yaml

[2]: # Read in the yaml file


diag_config_yml_path = "/glade/u/home/gmarques/libs/mom6-tools/docs/source/examples/
˓→diag_config.yml"

diag_config_yml = yaml.load(open(diag_config_yml_path,'r'), Loader=yaml.Loader)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
RUNDIR = dcase.get_value('RUNDIR')
print('Run directory is:', RUNDIR)
print('Casename is:', dcase.casename)
Run directory is: /glade/scratch/gmarques/g.c2b6.GJRA.TL319_t061.long_JRA_mct.076/run
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: # create an empty class object


class args:
pass

Define the arguments expected by class “Transport”. These have been hard-coded here fow now. . .

[5]: args.case_name = dcase.casename


path = "/glade/scratch/gmarques/"+dcase.casename+"/run/"
args.infile = path
# set avg dates
avg = diag_config_yml['Avg']
args.start_date = '0001-01-01' # override start date
args.end_date = avg['end_date']
args.label = ''
args.debug = False

Observed flows, more options can be added here


• Griffies et al., 2016: OMIP contribution to CMIP6: experimental and diagnostic protocol for the physical com-
ponent of the Ocean Model Intercomparison Project. Geosci. Model. Dev., 9, 3231-3296. doi:10.5194/gmd-9-
3231-2016

[6]: observedFlows = {'Agulhas':(129.8,143.6), 'Barents Opening':2.0, 'Bering Strait':(0.7,


˓→1.1), 'Davis Strait':(-2.1,-1.1), 'Denmark Strait':(-4.8,-2.0),

'Drake Passage':(129.8,143.6), 'English Channel':(0.01,0.1), 'Faroe-


˓→Scotland':(0.8,1.0), 'Florida-Bahamas':(28.9,34.3),

'Fram Strait':(-4.7,0.7), 'Gibraltar Strait':0.11, 'Gibraltar Strait


˓→':(-1.0, 1.0), 'Iceland-Faroe':(4.35,4.85),

'Indonesian Throughflow':(-15.,-13.), 'Mozambique Channel':(-25.6,-7.


˓→8), 'Pacific Equatorial Undercurrent':(24.5,28.3),

'Taiwan-Luzon Strait':(-3.0,-1.8), 'Windward Passage':(-15.,5.)}


# We need some estimated transport for the following:
# Bab_al_mandeb_Strait
# Iceland-Norway
# Hormuz Strait

Below we define a function for plotting transport time series. Note the following:

132 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

green = mean transport is within observed values


red = mean transport is not within observed values
gray = either there isn’t observed values to compare with or just a mean value is available (not a range)

[7]: def plotPanel(section,observedFlows=None,colorCode=True):


ax = plt.subplot(1,1,1)
color = '#c3c3c3'; obsLabel = None
if section.label in observedFlows.keys():
if isinstance(observedFlows[section.label],tuple):
if colorCode == True:
if min(observedFlows[section.label]) <= section.data.mean() <=
˓→max(observedFlows[section.label]):

color = '#90ee90'
else: color = '#f26161'
obsLabel = str(min(observedFlows[section.label])) + ' to ' +
˓→str(max(observedFlows[section.label]))

else: obsLabel = str(observedFlows[section.label])


plt.plot(section.time,section.data,color=color)
plt.title(section.label,fontsize=14)
plt.text(0.04,0.11,'Mean = '+'{0:.2f}'.format(section.data.mean()),transform=ax.
˓→transAxes,fontsize=14)

if obsLabel is not None: plt.text(0.04,0.04,'Obs. = '+obsLabel,transform=ax.


˓→transAxes,fontsize=14)

if section.ylim is not None: plt.ylim(section.ylim)


plt.ylabel('Transport (Sv)',fontsize=14); plt.xlabel('Time since beginning of run
˓→(yr)',fontsize=14)

return

Plot section transports in alphabetical order

Agulhas Section

[8]: agulhas = Transport(args,'agulhas_section','umo',label='Agulhas',ylim=(140,190))


plotPanel(agulhas, observedFlows=observedFlows)

1.1. Examples 133


mom6-tools Documentation, Release 0.0.post86

Bab al mandeb Strait (Red Sea)

[9]: bab = Transport(args,'Bab_al_mandeb_Strait','umo',label='Bab al mandeb Strait',ylim=(-


˓→0.5, 0.5))

plotPanel(bab, observedFlows=observedFlows)

Bering Strait

[10]: bering = Transport(args,'Bering_Strait','vmo',label='Bering Strait',ylim=(-2,3))


plotPanel(bering, observedFlows=observedFlows)

134 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Barents opening

[11]: barents = Transport(args,'Barents_opening','vmo',label='Barents Opening',ylim=(-2,10))


plotPanel(barents, observedFlows=observedFlows)

Davis Strait

[12]: davis = Transport(args,'Davis_Strait','vmo',label='Davis Strait',ylim=(-4.0,0.5))


plotPanel(davis, observedFlows=observedFlows)

Denmark Strait

[13]: denmark = Transport(args,'Denmark_Strait','vmo',label='Denmark Strait',ylim=(-12,2))


plotPanel(denmark, observedFlows=observedFlows)

1.1. Examples 135


mom6-tools Documentation, Release 0.0.post86

Drake Passage

[14]: drake = Transport(args,'Drake_Passage','umo',label='Drake Passage',ylim=(140,190))


plotPanel(drake, observedFlows=observedFlows)

English Channel

[15]: english = Transport(args,'English_Channel','umo',label='English Channel',ylim=(-0.4,0.


˓→4))

plotPanel(english, observedFlows=observedFlows)

136 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Florida Bahamas

[26]: florida = Transport(args,'Florida_Bahamas','vmo',label='Florida-Bahamas',ylim=(12,20))


plotPanel(florida, observedFlows=observedFlows)

Fram Strait

[17]: fram = Transport(args,'Fram_Strait','vmo',label='Fram Strait',ylim=(-10,8))


plotPanel(fram, observedFlows=observedFlows)

1.1. Examples 137


mom6-tools Documentation, Release 0.0.post86

Gibraltar Strait

[18]: gibraltar = Transport(args,'Gibraltar_Strait','umo',label='Gibraltar Strait',ylim=(-1.


˓→0,1.0))

plotPanel(gibraltar, observedFlows=observedFlows)

Hormuz Strait (Persian Gulf or Arabic Sea)

[19]: hormuz = Transport(args,'Hormuz_Strait','umo',label='Hormuz Strait',ylim=(-0.5,0.5))


plotPanel(hormuz, observedFlows=observedFlows)

138 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Iceland Norway

[20]: iceland = Transport(args,'Iceland_Norway','vmo',label='Iceland-Norway',ylim=(-5,17))


plotPanel(iceland, observedFlows=observedFlows)

Indonesian Throughflow

[21]: indo = Transport(args,'Indonesian_Throughflow','vmo',label='Indonesian Throughflow',


˓→ylim=(-20,0))

plotPanel(indo, observedFlows=observedFlows)

1.1. Examples 139


mom6-tools Documentation, Release 0.0.post86

Mozambique Channel

[22]: mozambique = Transport(args,'Mozambique_Channel','vmo',label='Mozambique Channel',


˓→ylim=(-50,10))

plotPanel(mozambique, observedFlows=observedFlows)

Pacific undercurrent

[23]: euc = Transport(args,'Pacific_undercurrent','umo',label='Pacific Equatorial


˓→Undercurrent',ylim=None, zlim=(0,350))

plotPanel(euc, observedFlows=observedFlows)

140 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Taiwan Luzon

[24]: taiwan = Transport(args,'Taiwan_Luzon','umo',label='Taiwan-Luzon Strait',ylim=(-15,


˓→10))

plotPanel(taiwan, observedFlows=observedFlows)

Windward Passage

[25]: windward = Transport(args,'Windward_Passage','vmo',label='Windward Passage',ylim=(-10,


˓→10))

plotPanel(windward, observedFlows=observedFlows)

1.1. Examples 141


mom6-tools Documentation, Release 0.0.post86

1.1.12 Sea ice analysis

[1]: %matplotlib inline


from mom6_tools.MOM6grid import MOM6grid
from mom6_tools.DiagsCase import DiagsCase
from ncar_jobqueue import NCARCluster
from dask.distributed import Client
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature
import numpy as np
import xarray as xr
from mom6_tools.m6plot import polarplot
import warnings, yaml
warnings.filterwarnings("ignore")
Basemap module not found. Some regional plots may not function properly

[2]: # 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)

[3]: # Create the case instance


dcase = DiagsCase(diag_config_yml['Case'])
print('Casename is:', dcase.casename)
Casename is: g.c2b6.GJRA.TL319_t061.long_JRA_mct.076

[4]: # Load the grid


RUNDIR = dcase.get_value('RUNDIR')
grd = MOM6grid(RUNDIR+'/'+dcase.casename+'.mom6.static.nc', xrformat=False)
MOM6 grid successfully loaded...

142 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[5]: # The following parameters must be set accordingly


######################################################
year_start = '0100-01-01'
year_end = '0116-12-31'
# Put your name and email address below
author = 'Gustavo Marques ([email protected])'
######################################################
# create an empty class object
class args:
pass

args.start_date = year_start
args.end_date = year_end
args.savefigs = False
args.time_series = True

[6]: # Create the climatology instance


cluster = NCARCluster(project='P93300612')
cluster.scale(2)
cluster
VBox(children=(HTML(value='<h2>NCARCluster</h2>'), HBox(children=(HTML(value='\n<div>
˓→\n <style scoped>\n ....

[7]: client = Client(cluster)


print(cluster.dashboard_link)
client
https://jupyterhub.ucar.edu/ch/user/gmarques/proxy/8787/status
[7]: <Client: 'tcp://10.148.10.19:46785' processes=0 threads=0, memory=0 B>

[16]: variables = ['hi', 'aice', 'time']


RUNDIR = dcase.get_value('RUNDIR')

def preprocess(ds):
'''Return the dataset with variables'''
return ds[variables]

%time ds = xr.open_mfdataset(RUNDIR+'/'+dcase.casename+'.cice.h.*.nc', \
parallel=True, chunks={'time': 12}, data_vars='minimal', \
preprocess=preprocess)
CPU times: user 1min 19s, sys: 7.99 s, total: 1min 27s
Wall time: 6min 1s

[17]: 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))

Selecting data between 0100-01-01 and 0116-12-31...


CPU times: user 7.92 ms, sys: 6.13 ms, total: 14.1 ms
Wall time: 14.5 ms

[18]: print('\n Computing time mean...')


%time ds_sel_mean = ds_sel.mean('time').compute()

1.1. Examples 143


mom6-tools Documentation, Release 0.0.post86

Computing time mean...


CPU times: user 47.9 s, sys: 1.03 s, total: 48.9 s
Wall time: 2min 39s

[19]: print('Computing monthly climatology...')


%time ds_monthly = ds.groupby("time.month").mean('time').compute()
Computing monthly climatology...
CPU times: user 1min 20s, sys: 1.72 s, total: 1min 22s
Wall time: 4min 22s

[20]: # load obs


obs_path = '/glade/work/gmarques/cesm/datasets/Seaice/'
obs_NH = xr.open_dataset(obs_path+'OBS_NSIDC_sat_NH_T2Ms_sic.nc')
obs_SH = xr.open_dataset(obs_path+'OBS_NSIDC_sat_SH_T2Ms_sic.nc')

[21]: obs_NH_mean = obs_NH.mean('time').compute()


obs_SH_mean = obs_SH.mean('time').compute()

[22]: obs_NH_monthly = obs_NH.groupby("time.month").mean('time').compute()


obs_SH_monthly = obs_SH.groupby("time.month").mean('time').compute()

Sea ice thickness

Annual mean

[23]: # Sea ice thickness


aice_mean = np.ma.masked_invalid(ds_monthly['aice'].mean('month').values) * 100.
hi_mean = np.ma.masked_invalid(ds_monthly['hi'].mean('month').values)
hi_mean = np.ma.masked_where(aice_mean < 15.0, hi_mean)
suptitle = ('ANN mean sea ice thickness, ' + str(args.start_date) + ' to ' + str(args.
˓→end_date))

%matplotlib inline
# SH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.SouthPolarStereo())
polarplot(hi_mean, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,2), axis=ax)

plt.suptitle(suptitle)

# NH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.NorthPolarStereo())
polarplot(hi_mean, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,4), axis=ax, proj='NP')

plt.suptitle(suptitle)
[23]: Text(0.5, 0.98, 'ANN mean sea ice thickness, 0100-01-01 to 0116-12-31')

144 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.1. Examples 145


mom6-tools Documentation, Release 0.0.post86

JFM

[24]: aice_JFM = np.ma.masked_invalid(ds_monthly['aice'].sel(month=[1,2,3]).mean('month').


˓→values) * 100.

hi_JFM = np.ma.masked_invalid(ds_monthly['hi'].sel(month=[1,2,3]).mean('month').
˓→values)

hi_JFM = np.ma.masked_where(aice_JFM < 15.0, hi_JFM)


suptitle = ('JFM mean sea ice thickness, ' + str(args.start_date) + ' to ' + str(args.
˓→end_date))

%matplotlib inline
# SH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.SouthPolarStereo())
polarplot(hi_JFM, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,2), axis=ax)

plt.suptitle(suptitle)

# NH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.NorthPolarStereo())
polarplot(hi_JFM, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,4), axis=ax, proj='NP')

(continues on next page)

146 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


plt.suptitle(suptitle)
[24]: Text(0.5, 0.98, 'JFM mean sea ice thickness, 0100-01-01 to 0116-12-31')

1.1. Examples 147


mom6-tools Documentation, Release 0.0.post86

AMJ

[25]: aice_AMJ = np.ma.masked_invalid(ds_monthly['aice'].sel(month=[4,5,6]).mean('month').


˓→values) * 100.

hi_AMJ = np.ma.masked_invalid(ds_monthly['hi'].sel(month=[4,5,6]).mean('month').
˓→values)

hi_AMJ = np.ma.masked_where(aice_AMJ < 15.0, hi_AMJ)


suptitle = ('AMJ mean sea ice thickness, ' + str(args.start_date) + ' to ' + str(args.
˓→end_date))

%matplotlib inline
# SH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.SouthPolarStereo())
polarplot(hi_AMJ, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,2), axis=ax)

plt.suptitle(suptitle)

# NH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.NorthPolarStereo())
polarplot(hi_AMJ, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,4), axis=ax, proj='NP')

(continues on next page)

148 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


plt.suptitle(suptitle)
[25]: Text(0.5, 0.98, 'AMJ mean sea ice thickness, 0100-01-01 to 0116-12-31')

1.1. Examples 149


mom6-tools Documentation, Release 0.0.post86

JAS

[26]: aice_JAS = np.ma.masked_invalid(ds_monthly['aice'].sel(month=[7,8,9]).mean('month').


˓→values) * 100.

hi_JAS = np.ma.masked_invalid(ds_monthly['hi'].sel(month=[7,8,9]).mean('month').
˓→values)

hi_JAS = np.ma.masked_where(aice_JAS < 15.0, hi_JAS)


suptitle = ('JAS mean sea ice thickness, ' + str(args.start_date) + ' to ' + str(args.
˓→end_date))

%matplotlib inline
# SH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.SouthPolarStereo())
polarplot(hi_JAS, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,2), axis=ax)

plt.suptitle(suptitle)

# NH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.NorthPolarStereo())
polarplot(hi_JAS, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,4), axis=ax, proj='NP')

(continues on next page)

150 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


plt.suptitle(suptitle)
[26]: Text(0.5, 0.98, 'JAS mean sea ice thickness, 0100-01-01 to 0116-12-31')

1.1. Examples 151


mom6-tools Documentation, Release 0.0.post86

OND

[27]: aice_OND = np.ma.masked_invalid(ds_monthly['aice'].sel(month=[10,11,12]).mean('month


˓→').values) * 100.

hi_OND = np.ma.masked_invalid(ds_monthly['hi'].sel(month=[10,11,12]).mean('month').
˓→values)

hi_OND = np.ma.masked_where(aice_OND < 15.0, hi_OND)


suptitle = ('OND mean sea ice thickness, ' + str(args.start_date) + ' to ' + str(args.
˓→end_date))

%matplotlib inline
# SH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.SouthPolarStereo())
polarplot(hi_OND, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,2), axis=ax)

plt.suptitle(suptitle)

# NH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.NorthPolarStereo())
polarplot(hi_OND, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_ncar,
˓→clim=(0,4), axis=ax, proj='NP')

(continues on next page)

152 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


plt.suptitle(suptitle)
[27]: Text(0.5, 0.98, 'OND mean sea ice thickness, 0100-01-01 to 0116-12-31')

1.1. Examples 153


mom6-tools Documentation, Release 0.0.post86

[28]: (obs_SH_mean.sic * 100.).plot()


[28]: <matplotlib.collections.QuadMesh at 0x2b218a8c7ef0>

154 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

[30]: tmp = obs_SH_mean['sic'].values * 100.


#tmp1 = np.ma.masked_where(tmp < 15.0, tmp)
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.SouthPolarStereo())
ax.contour(obs_SH_mean.lon.values, obs_SH_mean.lat.values, tmp, levels=[16.5],
˓→transform=ccrs.PlateCarree(), colors='black')

[30]: <matplotlib.contour.QuadContourSet at 0x2b218b2b42e8>

Sea ice concentration

[32]:
aice_mean = np.ma.masked_where(aice_mean <= 15.0, aice_mean)

suptitle = ('ANN mean ice concentration, ' + str(args.start_date) + ' to ' + str(args.
˓→end_date))

%matplotlib inline
# SH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.SouthPolarStereo())
polarplot(aice_mean, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_
˓→ncar, clim=(0,100), axis=ax)

ax.contour(obs_SH_mean.lon.values, obs_SH_mean.lat.values, tmp, levels=[16.5],


˓→transform=ccrs.PlateCarree(), colors='black',

linestyles='solid')
(continues on next page)

1.1. Examples 155


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


plt.suptitle(suptitle)

# NH
fig = plt.figure(figsize=(10,8))
ax = plt.gca(projection=ccrs.NorthPolarStereo())
polarplot(aice_mean, grd, title=dcase.casename, debug=False, colormap=plt.cm.gist_
˓→ncar, clim=(0,100), axis=ax, proj='NP')

plt.suptitle(suptitle)
[32]: Text(0.5, 0.98, 'ANN mean ice concentration, 0100-01-01 to 0116-12-31')

156 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Northern Hemisphere

Maximum sea ice thickness

[33]: from mom6_tools.latlon_analysis import create_xarray_dataset, plot_area_ave_stats


from mom6_tools.m6plot import myStats

[ ]: dtime = seaice.time.values
# variable name
var = 'hi'
# create datasets
ds_sh = create_xarray_dataset(var,'m',dtime)
ds_nh = create_xarray_dataset(var,'m',dtime)

# loop in time
for t in range(0,len(dtime)):
# northern hemisphere
tmp = np.ma.masked_invalid(seaice[var].sel(time=dtime[t]).values)
tmp_nh = np.ma.masked_where(grd.geolat < 0, tmp)
# get stats
sMin, sMax, mean, std, rms = myStats(tmp_nh, area=None)
(continues on next page)

1.1. Examples 157


mom6-tools Documentation, Release 0.0.post86

(continued from previous page)


# update Dataset
ds_nh[var][1,t] = sMax
# southern hemisphere
tmp_sh = np.ma.masked_where(grd.geolat > 0, tmp)
# get stats
sMin, sMax, mean, std, rms = myStats(tmp_sh, area=None)
# update Dataset
ds_sh[var][1,t] = sMax

Southern Hemisphere

[ ]: sh = ds_sh.sel(stats='max')
fig = plt.figure(figsize=(12, 6))
ax = fig.add_subplot(111)
sh.hi.plot(ax=ax)
plt.title('Maximum sea ice thickness, southern hemisphere', fontsize=14)
plt.xlabel('Time [years]')

Northern Hemisphere

[ ]: nh = ds_nh.sel(stats='max')
fig = plt.figure(figsize=(12, 6))
ax = fig.add_subplot(111)
nh.hi.plot(ax=ax)
plt.title('Maximum sea ice thickness, northern hemisphere', fontsize=14)
plt.xlabel('Time [years]')

Sea ice extent

[ ]: dtime = seaice.time.values
# variable name
var = 'aice'
#
area_sh = []
area_nh = []

# loop in time
for t in range(len(dtime)):
tmp = np.ma.masked_invalid(seaice[var].sel(time=dtime[t]).values)
# mask southern hemisphere
tmp_nh = np.ma.masked_where(grd.geolat < 0, grd.area_t)
# mask northern hemisphere
tmp_sh = np.ma.masked_where(grd.geolat > 0, grd.area_t)
# mask if aggregrated concentration <= 0.15
tmp_nh = np.ma.masked_where(tmp <= 0.15, tmp_nh*tmp)
tmp_sh = np.ma.masked_where(tmp <= 0.15, tmp_sh*tmp)
# append data
area_sh.append(np.sum(tmp_sh)*1.0e-12) # 1.0e6 km^2
area_nh.append(np.sum(tmp_nh)*1.0e-12) # 1.0e6 km^2

158 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

Southern hemisphere

[ ]: fig = plt.figure(figsize=(12, 6))


plt.plot(dtime,area_sh)
plt.title('Sea ice area, southern hemisphere', fontsize=14)
plt.xlabel('Time [years]', fontsize=14); plt.ylabel('x 1.0e6 km$^2$', fontsize=14)

Northern hemisphere

[ ]: fig = plt.figure(figsize=(12, 6))


plt.plot(dtime,area_nh)
plt.title('Sea ice area, northern hemisphere', fontsize=14)
plt.xlabel('Time [years]', fontsize=14); plt.ylabel('x 1.0e6 km$^2$', fontsize=14)

Under development

[ ]: import matplotlib.path as mpath


fig = plt.figure(figsize=[10, 8])
ice = (seaice.aice[-1,:,:].data)
ax1 = plt.subplot(1, 1, 1, projection=ccrs.NorthPolarStereo())
ax1.set_extent([-180, 180, 50, 90], ccrs.PlateCarree())
ax1.add_feature(cartopy.feature.LAND)
ax1.gridlines()
# Compute a circle in axes coordinates, which we can use as a boundary
# for the map. We can pan/zoom as much as we like - the boundary will be
# permanently circular.
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)
ax1.set_boundary(circle, transform=ax1.transAxes)
#colormap = 'rainbow'
cs = ax1.pcolormesh(grd.geolon,grd.geolat,ice,transform=ccrs.PlateCarree(),cmap=
˓→'Blues_r', shading='flat')

fig.colorbar(cs)
# Add Land
ax1.add_feature( cartopy.feature.LAND, zorder=1, edgecolor='none', facecolor='#fae5c9
˓→') #fae5c9')

# add Ocean
ax1.add_feature(cartopy.feature.OCEAN)
# Add coastline
ax1.coastlines(color='black')
# Add lat lon rings
ax1.gridlines(alpha='0.1',color='black')
im1 = ax1.contour(grd.geolon,grd.geolat,ice,[15],colors='red', transform=ccrs.
˓→PlateCarree())

plt.title('Model, Years ' + str(args.year_start) + ' to ' + str(args.year_end))

[ ]:

Reference

1.1. Examples 159


mom6-tools Documentation, Release 0.0.post86

1.2 API Reference

This page provides an auto-generated summary of mom6-tool’s API. For more details and examples, refer to the
relevant chapters in the main part of the documentation.

1.2.1 Transports across vertical sections

section_transports

1.2.2 Meridional overturning

moc

1.2.3 Poleward heat transport

poleward_heat_transport

1.2.4 Toolbox

m6toolbox A collection of useful functions. . .

1.2.5 Plotting tools

m6plot

1.3 Installing

You can install mom6-tools with pip, conda, or by installing from source.

1.3.1 Pip

Pip can be used to install mom6-tools:

pip install mom6-tools

1.3.2 Conda

To install the latest version of mom6-tools from the conda-forge repository using conda:

conda install -c conda-forge mom6-tools

160 Chapter 1. Installation (Coming Soon!)


mom6-tools Documentation, Release 0.0.post86

1.3.3 Install from Source

To install mom6-tools from source, clone the repository from github:

git clone https://github.com/NCAR/mom6-tools.git


cd mom6-tools
pip install -e .

You can also install directly from git master branch:

pip install git+https://github.com/NCAR/mom6-tools

1.3.4 Test

To run mom6-tools’s tests with pytest:

git clone https://github.com/NCAR/mom6-tools.git


cd mom6-tools
pytest - v

1.3. Installing 161


mom6-tools Documentation, Release 0.0.post86

162 Chapter 1. Installation (Coming Soon!)


CHAPTER 2

Indices and tables

• genindex
• modindex
• search

163

You might also like