Tracer budgets MOM6 NCAR configuration
The following variables are required at double precision output for closing the heat budget:
‘opottemptend’, ‘T_advection_xy’, ‘Th_tendency_vert_remap’, ‘boundary_forcing_heat_tendency’, ‘opottempdiff’, ‘opottemppmdiff’, ‘frazil_heat_tendency’, ‘KPP_NLT_temp_budget’, ‘T_lbdxy_cont_tendency’
The following variables are required at double precision to close the salt budget:
‘S_advection_xy’, ‘Sh_tendency_vert_remap’, ‘boundary_forcing_salt_tendency’, osaltpmdiff’, ‘osaltdiff’, ‘KPP_NLT_saln_budget’*1e-3 (because there is a bug in the conversion factor), ‘S_lbdxy_cont_tendency’
A short run with all this output at double precision is available here: /glade/scratch/deppenme/archive/gmom.e23.GJRAv3.TL319_t061_zstar_N65.testbudget2.001/ocn/hist/
Description of what they are can be found in the labels of the plot below.
TO DO:
test different vertical coordinate
test different temporal resolutions
Load modules, start cluster
[1]:
# Load required modules
import warnings
warnings.filterwarnings("ignore") # I don't want any warnings (:
# the usual suspects
import numpy as np
from datetime import date
from matplotlib import pyplot as plt
import cartopy.crs as ccrs
import xarray as xr
import glob
import nc_time_axis # it says I need this to plot.. not sure
# dask helpers
from mom6_tools.jobqueue import get_cluster
# get mom6-tools
import mom6_tools
[2]:
parallel, cluster, client = get_cluster(
40,
cluster_class='PBSCluster',
cores=4,
processes=1,
resource_spec='select=1:ncpus=1:mem=10GB',
)
client
Starting a dask cluster: PBSCluster
Requesting 40 workers...
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[2], line 1
----> 1 parallel, cluster, client = get_cluster(
2 40,
3 cluster_class='PBSCluster',
4 cores=4,
5 processes=1,
6 resource_spec='select=1:ncpus=1:mem=10GB',
7 )
8 client
File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/mom6_tools/jobqueue.py:300, in get_cluster(nw, cluster_class, args, config, **kwargs)
297 print('Requesting {} workers... \n'.format(nw))
298 if is_jobqueue_cluster:
299 # dask.config.set({'distributed.dashboard.link': '/proxy/{port}/status'})
--> 300 cluster = cluster_class(**kwargs)
301 cluster.scale(nw)
302 else:
File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/dask_jobqueue/core.py:661, in JobQueueCluster.__init__(self, n_workers, job_cls, loop, security, shared_temp_directory, silence_logs, name, asynchronous, dashboard_address, host, scheduler_options, scheduler_cls, interface, protocol, config_name, **job_kwargs)
656 if "processes" in self._job_kwargs and self._job_kwargs["processes"] > 1:
657 worker["group"] = [
658 "-" + str(i) for i in range(self._job_kwargs["processes"])
659 ]
--> 661 self._dummy_job # trigger property to ensure that the job is valid
663 super().__init__(
664 scheduler=scheduler,
665 worker=worker,
(...)
670 name=name,
671 )
673 if n_workers:
File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/dask_jobqueue/core.py:690, in JobQueueCluster._dummy_job(self)
688 address = "tcp://<insert-scheduler-address-here>:8786"
689 try:
--> 690 return self.job_cls(
691 address or "tcp://<insert-scheduler-address-here>:8786",
692 # The 'name' parameter is replaced inside Job class by the
693 # actual Dask worker name. Using 'dummy-name here' to make it
694 # more clear that cluster.job_script() is similar to but not
695 # exactly the same script as the script submitted for each Dask
696 # worker
697 name="dummy-name",
698 **self._job_kwargs
699 )
700 except TypeError as exc:
701 # Very likely this error happened in the self.job_cls constructor
702 # because an unexpected parameter was used in the JobQueueCluster
703 # constructor. The next few lines builds a more user-friendly error message.
704 match = re.search("(unexpected keyword argument.+)", str(exc))
File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/dask_jobqueue/pbs.py:55, in PBSJob.__init__(self, scheduler, name, queue, project, account, resource_spec, walltime, config_name, **base_class_kwargs)
43 def __init__(
44 self,
45 scheduler=None,
(...)
53 **base_class_kwargs
54 ):
---> 55 super().__init__(
56 scheduler=scheduler, name=name, config_name=config_name, **base_class_kwargs
57 )
59 if queue is None:
60 queue = dask.config.get("jobqueue.%s.queue" % self.config_name)
File ~/checkouts/readthedocs.org/user_builds/mom6-tools/envs/latest/lib/python3.10/site-packages/dask_jobqueue/core.py:202, in Job.__init__(self, scheduler, name, cores, memory, processes, nanny, protocol, security, interface, death_timeout, local_directory, extra, worker_command, worker_extra_args, job_extra, job_extra_directives, env_extra, job_script_prologue, header_skip, job_directives_skip, log_directory, shebang, python, job_name, config_name)
200 job_class_name = self.__class__.__name__
201 cluster_class_name = job_class_name.replace("Job", "Cluster")
--> 202 raise ValueError(
203 "You must specify how much cores and memory per job you want to use, for example:\n"
204 "cluster = {}(cores={}, memory={!r})".format(
205 cluster_class_name, cores or 8, memory or "24GB"
206 )
207 )
209 if python is None:
210 python = dask.config.get("jobqueue.%s.python" % self.config_name)
ValueError: You must specify how much cores and memory per job you want to use, for example:
cluster = PBSCluster(cores=4, memory='24GB')
[3]:
# get the data
dirname = "/glade/scratch/deppenme/archive/gmom.e23.GJRAv3.TL319_t061_zstar_N65.testbudget2.001/ocn/hist"
static = xr.open_dataset(*glob.glob(f"{dirname}/*static*.nc"))
ds_hb = xr.open_mfdataset(
sorted(glob.glob(f"{dirname}/gmom.e23.GJRAv3.TL319_t061_zstar_N65.testbudget2.001.mom6.hm_0001_01_??.nc")),
coords="minimal",
data_vars="minimal",
compat="override",
use_cftime=True,
parallel=True,
)
ds_hb.coords.update(static.drop("time"))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[3], line 3
1 # get the data
2 dirname = "/glade/scratch/deppenme/archive/gmom.e23.GJRAv3.TL319_t061_zstar_N65.testbudget2.001/ocn/hist"
----> 3 static = xr.open_dataset(*glob.glob(f"{dirname}/*static*.nc"))
4 ds_hb = xr.open_mfdataset(
5 sorted(glob.glob(f"{dirname}/gmom.e23.GJRAv3.TL319_t061_zstar_N65.testbudget2.001.mom6.hm_0001_01_??.nc")),
6 coords="minimal",
(...)
10 parallel=True,
11 )
12 ds_hb.coords.update(static.drop("time"))
TypeError: open_dataset() missing 1 required positional argument: 'filename_or_obj'
Heat budget
[4]:
# try for one location first
ds_0N140W = ds_hb.sel(xh=-140, yh=0, method='nearest')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[4], line 2
1 # try for one location first
----> 2 ds_0N140W = ds_hb.sel(xh=-140, yh=0, method='nearest')
NameError: name 'ds_hb' is not defined
[5]:
fig, ax = plt.subplots(1, 1, figsize=(5,6))
ax.plot(ds_0N140W.opottemptend.isel(time=5), ds_0N140W.zl, label='grid cell time tend')
ax.plot(ds_0N140W.T_advection_xy.isel(time=5), ds_0N140W.zl, label='horizontal convergence advective heat flux')
ax.plot(ds_0N140W.Th_tendency_vert_remap.isel(time=5), ds_0N140W.zl, label='across layer adv remapping vertical')
ax.plot(ds_0N140W.boundary_forcing_heat_tendency.isel(time=5), ds_0N140W.zl, label='boundary forcing')
ax.plot(ds_0N140W.opottempdiff.isel(time=5), ds_0N140W.zl, label='parameterized dianeutral diffusion')
ax.plot(ds_0N140W.opottemppmdiff.isel(time=5), ds_0N140W.zl, label='parameterized mesoscalte neutral diffusion')
ax.plot(ds_0N140W.frazil_heat_tendency.isel(time=5), ds_0N140W.zl, label='frazil ice formation')
ax.plot(ds_0N140W.KPP_NLT_temp_budget.isel(time=5), ds_0N140W.zl, label='Non-local KPP')
ax.plot(ds_0N140W.T_lbdxy_cont_tendency.isel(time=5), ds_0N140W.zl, label='Lateral diffusion')
ax.set_ylim(500,0)
ax.legend(loc='lower left')
ax.set_title(r'0$^{\circ}$N, 140$^{\circ}$W')
plt.savefig('hb_0N140W_mom_zstar.png', bbox_inches='tight')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 3
1 fig, ax = plt.subplots(1, 1, figsize=(5,6))
----> 3 ax.plot(ds_0N140W.opottemptend.isel(time=5), ds_0N140W.zl, label='grid cell time tend')
4 ax.plot(ds_0N140W.T_advection_xy.isel(time=5), ds_0N140W.zl, label='horizontal convergence advective heat flux')
5 ax.plot(ds_0N140W.Th_tendency_vert_remap.isel(time=5), ds_0N140W.zl, label='across layer adv remapping vertical')
NameError: name 'ds_0N140W' is not defined
[6]:
fig, ax = plt.subplots(1, 1, figsize=(5,6))
ax.plot(ds_0N140W.opottemptend.isel(time=5), ds_0N140W.zl, label='grid cell time tend')
ax.plot((ds_0N140W.T_advection_xy
+
ds_0N140W.Th_tendency_vert_remap
+
ds_0N140W.boundary_forcing_heat_tendency
+
ds_0N140W.opottempdiff
+
ds_0N140W.opottemppmdiff
+
ds_0N140W.frazil_heat_tendency
+
ds_0N140W.KPP_NLT_temp_budget
+
ds_0N140W.T_lbdxy_cont_tendency).isel(time=5), ds_0N140W.zl, label='sum others')
ax.set_ylim(500,0)
ax.legend(loc='lower left')
plt.savefig('hb_0N140W_mom_zstar_lhs_rhs_doubleprec.png', bbox_inches='tight')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[6], line 3
1 fig, ax = plt.subplots(1, 1, figsize=(5,6))
----> 3 ax.plot(ds_0N140W.opottemptend.isel(time=5), ds_0N140W.zl, label='grid cell time tend')
4 ax.plot((ds_0N140W.T_advection_xy
5 +
6 ds_0N140W.Th_tendency_vert_remap
(...)
17 +
18 ds_0N140W.T_lbdxy_cont_tendency).isel(time=5), ds_0N140W.zl, label='sum others')
20 ax.set_ylim(500,0)
NameError: name 'ds_0N140W' is not defined
[7]:
%%time
xr.testing.assert_allclose(ds_hb.opottemptend,
(ds_hb.T_advection_xy+ds_hb.Th_tendency_vert_remap+
ds_hb.boundary_forcing_heat_tendency+ds_hb.opottempdiff+
ds_hb.opottemppmdiff+ds_hb.frazil_heat_tendency+
ds_hb.KPP_NLT_temp_budget+ds_hb.T_lbdxy_cont_tendency), rtol=1e-10)
# This goes through so the heat budget is closed
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
File <timed eval>:1
NameError: name 'ds_hb' is not defined
Salt budget
[8]:
# figure with all components
fig, ax = plt.subplots(1, 1, figsize=(5,6))
ax.plot(ds_0N140W.osalttend.isel(time=3), ds_0N140W.zl, label='Tendency of Sea Water Salinity Expressed as Salt Content')
ax.plot(ds_0N140W.S_advection_xy.isel(time=3), ds_0N140W.zl, label='Horizontal convergence of residual mean advective fluxes of salt')
ax.plot(ds_0N140W.Sh_tendency_vert_remap.isel(time=3), ds_0N140W.zl, label='Vertical remapping tracer content tendency for Salt')
ax.plot(ds_0N140W.boundary_forcing_salt_tendency.isel(time=3), ds_0N140W.zl, label='Tendency due to parameterized mesoscale neutral diffusion')
ax.plot(ds_0N140W.osaltpmdiff.isel(time=3), ds_0N140W.zl, label='Tendency due to parameterized dianeutral mixing')
ax.plot(ds_0N140W.osaltdiff.isel(time=3), ds_0N140W.zl, label='across layer diffusion')
ax.plot(ds_0N140W.KPP_NLT_saln_budget.isel(time=3)*1e-3, ds_0N140W.zl, label='KPP non local salt')
ax.plot(ds_0N140W.S_lbdxy_cont_tendency.isel(time=3)*1e-3, ds_0N140W.zl, label='Redi')
ax.set_ylim(500,0)
ax.legend(loc='lower left')
ax.set_title(r'0$^{\circ}$N, 140$^{\circ}$W')
# plt.savefig('sb_0N140W_mom_zstar.png', bbox_inches='tight')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[8], line 4
1 # figure with all components
2 fig, ax = plt.subplots(1, 1, figsize=(5,6))
----> 4 ax.plot(ds_0N140W.osalttend.isel(time=3), ds_0N140W.zl, label='Tendency of Sea Water Salinity Expressed as Salt Content')
5 ax.plot(ds_0N140W.S_advection_xy.isel(time=3), ds_0N140W.zl, label='Horizontal convergence of residual mean advective fluxes of salt')
6 ax.plot(ds_0N140W.Sh_tendency_vert_remap.isel(time=3), ds_0N140W.zl, label='Vertical remapping tracer content tendency for Salt')
NameError: name 'ds_0N140W' is not defined
[9]:
# figure with total tendency and sum of components
fig, ax = plt.subplots(1, 1, figsize=(5,6))
ax.plot(ds_0N140W.osalttend.isel(time=3), ds_0N140W.zl, label='Tendency of Sea Water Salinity Expressed as Salt Content')
ax.plot((ds_0N140W.S_advection_xy + ds_0N140W.Sh_tendency_vert_remap +
ds_0N140W.boundary_forcing_salt_tendency + ds_0N140W.osaltpmdiff +
ds_0N140W.osaltdiff + ds_0N140W.KPP_NLT_saln_budget*1e-3 +
ds_0N140W.S_lbdxy_cont_tendency).isel(time=3), ds_0N140W.zl,
label='budget')
ax.set_ylim(500,0)
ax.legend(loc='lower left')
ax.set_title(r'0$^{\circ}$N, 140$^{\circ}$W')
# plt.savefig('sb_0N140W_mom_zstar.png', bbox_inches='tight')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[9], line 4
1 # figure with total tendency and sum of components
2 fig, ax = plt.subplots(1, 1, figsize=(5,6))
----> 4 ax.plot(ds_0N140W.osalttend.isel(time=3), ds_0N140W.zl, label='Tendency of Sea Water Salinity Expressed as Salt Content')
7 ax.plot((ds_0N140W.S_advection_xy + ds_0N140W.Sh_tendency_vert_remap +
8 ds_0N140W.boundary_forcing_salt_tendency + ds_0N140W.osaltpmdiff +
9 ds_0N140W.osaltdiff + ds_0N140W.KPP_NLT_saln_budget*1e-3 +
10 ds_0N140W.S_lbdxy_cont_tendency).isel(time=3), ds_0N140W.zl,
11 label='budget')
14 ax.set_ylim(500,0)
NameError: name 'ds_0N140W' is not defined
[10]:
%%time
# test whether it closes all over
xr.testing.assert_allclose(ds_hb.osalttend,
(ds_hb.S_advection_xy+ds_hb.Sh_tendency_vert_remap+
ds_hb.boundary_forcing_salt_tendency+ds_hb.osaltpmdiff+
ds_hb.osaltdiff+ds_hb.KPP_NLT_saln_budget*1e-3+ds_hb.S_lbdxy_cont_tendency),
rtol=1e-10)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
File <timed eval>:3
NameError: name 'ds_hb' is not defined
[ ]: