Physical Variables#

This notebook looks at some canonical transformations of sea surface height (SSH). These are derived variables that can be calculated from SSH and are often very good indicators of performance.

import autoroot
import typing as tp
from dataclasses import dataclass
import numpy as np
import pandas as pd
import xarray as xr
import metpy
from metpy.units import units
import xarray_dataclasses as xrdataclass
from oceanbench._src.geoprocessing import geostrophic_v2 as geocalc
import matplotlib.pyplot as plt
import seaborn as sns

sns.reset_defaults()
sns.set_context(context="talk", font_scale=0.7)

%load_ext autoreload
%autoreload 2
# file = "/gpfswork/rech/cli/uvo53rl/projects/jejeqx/data/natl60/NATL60-CJM165_GULFSTREAM_ssh_y2013.1y.nc"
file = "/Users/eman/code_projects/data/oceanbench-data-registry/osse_natl60/grid/gf_mod_ssh_daily.nc"

!ls $file
/Users/eman/code_projects/data/oceanbench-data-registry/osse_natl60/grid/gf_mod_ssh_daily.nc
da = xr.open_dataset(file)
# da["time"] = pd.to_datetime(da.time)
da = da.sortby("time")
# da = da.coarsen(lat=2, boundary="trim").mean()
da = da.sel(time=slice("2013-01-01", "2013-03-01"))
da
<xarray.Dataset>
Dimensions:  (time: 60, lat: 201, lon: 201)
Coordinates:
  * lon      (lon) float64 -65.0 -64.95 -64.9 -64.85 ... -55.1 -55.05 -55.0
  * lat      (lat) float64 33.0 33.05 33.1 33.15 33.2 ... 42.85 42.9 42.95 43.0
  * time     (time) datetime64[ns] 2013-01-01T12:00:00 ... 2013-03-01T12:00:00
Data variables:
    ssh      (time, lat, lon) float64 ...

Sea Surface Height#

\[ \begin{aligned} \text{Sea Surface Height}[m]: && \eta &=\boldsymbol{\eta}(\vec{\mathbf{x}},t) && && \boldsymbol{\eta}: \boldsymbol{\Omega}\times\boldsymbol{T}\rightarrow\mathbb{R} \end{aligned} \]
da["ssh"] = da.ssh * units.meters
da["ssh"].attrs["units"] = "m"
da["ssh"].attrs["long_name"] = "Sea Surface Height"
da["ssh"].attrs["standard_name"] = "sea_surface_height"

da["lat"] = da.lat * units.degree_north
da["lat"].attrs["long_name"] = "Latitude"
da["lat"].attrs["standard_name"] = "latitude"

da["lon"] = da.lon * units.degree_east
da["lon"].attrs["long_name"] = "Longitude"
da["lon"].attrs["standard_name"] = "longitude"
fig, ax = plt.subplots()

da.ssh.isel(time=1).plot.pcolormesh(ax=ax, cmap="viridis")

plt.show()
../../_images/0f766e7c36f9c3bf2bf70631545340b99c7415897ee1486e016d8dc3135ba01a.png

Stream Function#

\[ \begin{aligned} \text{Stream Function }[ms^{-1}]: && \psi &=\boldsymbol{\psi}(\vec{\mathbf{x}},t) && && \boldsymbol{\psi}: \boldsymbol{\Omega}\times\boldsymbol{T}\rightarrow\mathbb{R} \end{aligned} \]
\[ \psi = \frac{g}{f_0}\eta \]

Coriolis Parameter#

\[ f_0 = 2\Omega\sin(\varphi) \]

where:

  • \(\Omega\) - …

  • \(\varphi\) - latitude (radians)

f0 = metpy.calc.coriolis_parameter(latitude=np.deg2rad(da.lat)).mean()
f0
<xarray.DataArray ()>
<Quantity(8.967442585730005e-05, '1 / second')>

Gravity#

from metpy.constants import earth_gravity as GRAVITY
GRAVITY
9.80665 meter/second2
da["psi"] = geocalc.streamfunction(da, "ssh").psi
da
<xarray.Dataset>
Dimensions:  (time: 60, lat: 201, lon: 201)
Coordinates:
  * lon      (lon) float64 -65.0 -64.95 -64.9 -64.85 ... -55.1 -55.05 -55.0
  * lat      (lat) float64 33.0 33.05 33.1 33.15 33.2 ... 42.85 42.9 42.95 43.0
  * time     (time) datetime64[ns] 2013-01-01T12:00:00 ... 2013-03-01T12:00:00
Data variables:
    ssh      (time, lat, lon) float64 [m] 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
    psi      (time, lat, lon) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
fig, ax = plt.subplots()

da.psi.isel(time=10).plot.pcolormesh(ax=ax, cmap="viridis")

plt.show()
../../_images/d005b975a7a1421af020cf7d76b0d02fa06fa1d94812548a90c9ae79645282be.png

Velocities#

\[\begin{split} \begin{aligned} \text{U Velocity}[ms^{-1}]: && u &=\boldsymbol{u}(\vec{\mathbf{x}},t) && && \boldsymbol{\psi}: \boldsymbol{\Omega}\times\boldsymbol{T}\rightarrow\mathbb{R} \\ \text{V Velocity}[ms^{-1}]: && v &=\boldsymbol{v}(\vec{\mathbf{x}},t) && && \boldsymbol{\psi}: \boldsymbol{\Omega}\times\boldsymbol{T}\rightarrow\mathbb{R} \end{aligned} \end{split}\]
\[ \begin{aligned} u = -\frac{\partial \psi}{\partial y} && v = \frac{\partial \psi}{\partial x} \end{aligned} \]
da = da.assign = geocalc.geostrophic_velocities(da, variable="psi")
[autoreload of jupyter_client.provisioning.provisioner_base failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: can't apply this __setattr__ to KernelProvisionerMeta object
]
[autoreload of pygments.token failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: __class__ assignment: '_TokenType' object layout differs from '_TokenType'
]
[autoreload of pygments.style failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: can't apply this __setattr__ to StyleMeta object
]
[autoreload of pygments.lexer failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: can't apply this __setattr__ to LexerMeta object
]
[autoreload of prompt_toolkit.shortcuts.progress_bar.formatters failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 319, in update_instances
    refs = gc.get_referrers(old)
           ^^^^^^^^^^^^^^^^^^^^^
KeyboardInterrupt
]
[autoreload of jedi.inference.cache failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: can't apply this __setattr__ to CachedMetaClass object
]
[autoreload of jedi.inference.filters failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: can't apply this __setattr__ to _OverwriteMeta object
]
[autoreload of typing_extensions failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: can't apply this __setattr__ to _ProtocolMeta object
]
[autoreload of urllib3.exceptions failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 349, in update_class
    if update_generic(old_obj, new_obj):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 309, in update_function
    setattr(old, name, getattr(new, name))
ValueError: __init__() requires a code object with 1 free vars, not 0
]
[autoreload of urllib3.util.connection failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 475, in superreload
    module = reload(module)
             ^^^^^^^^^^^^^^
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/importlib/__init__.py", line 169, in reload
    _bootstrap._exec(spec, module)
  File "<frozen importlib._bootstrap>", line 621, in _exec
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/urllib3/util/connection.py", line 8, in <module>
    from .wait import NoWayToWaitForSocketError, wait_for_read
ImportError: cannot import name 'NoWayToWaitForSocketError' from 'urllib3.util.wait' (/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/urllib3/util/wait.py)
]
[autoreload of urllib3._collections failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 349, in update_class
    if update_generic(old_obj, new_obj):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 309, in update_function
    setattr(old, name, getattr(new, name))
ValueError: __init__() requires a code object with 1 free vars, not 0
]
[autoreload of urllib3.connection failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 475, in superreload
    module = reload(module)
             ^^^^^^^^^^^^^^
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/importlib/__init__.py", line 169, in reload
    _bootstrap._exec(spec, module)
  File "<frozen importlib._bootstrap>", line 621, in _exec
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/urllib3/connection.py", line 15, in <module>
    from .util.proxy import create_proxy_ssl_context
ImportError: cannot import name 'create_proxy_ssl_context' from 'urllib3.util.proxy' (/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/urllib3/util/proxy.py)
]
[autoreload of urllib3.response failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 349, in update_class
    if update_generic(old_obj, new_obj):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 309, in update_function
    setattr(old, name, getattr(new, name))
ValueError: __init__() requires a code object with 1 free vars, not 0
]
[autoreload of urllib3.connectionpool failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 349, in update_class
    if update_generic(old_obj, new_obj):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 309, in update_function
    setattr(old, name, getattr(new, name))
ValueError: __init__() requires a code object with 1 free vars, not 0
]
[autoreload of urllib3.poolmanager failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 349, in update_class
    if update_generic(old_obj, new_obj):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 309, in update_function
    setattr(old, name, getattr(new, name))
ValueError: __init__() requires a code object with 1 free vars, not 0
]
[autoreload of requests.packages.urllib3.util.retry failed: Traceback (most recent call last):
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 276, in check
    superreload(m, reload, self.old_objects)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 500, in superreload
    update_generic(old_obj, new_obj)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 397, in update_generic
    update(a, b)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 365, in update_class
    update_instances(old, new)
  File "/Users/eman/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/extensions/autoreload.py", line 323, in update_instances
    object.__setattr__(ref, "__class__", new)
TypeError: can't apply this __setattr__ to _RetryMeta object
]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File ~/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/core/async_helpers.py:129, in _pseudo_sync_runner(coro)
    121 """
    122 A runner that does not really allow async execution, and just advance the coroutine.
    123 
   (...)
    126 Credit to Nathaniel Smith
    127 """
    128 try:
--> 129     coro.send(None)
    130 except StopIteration as exc:
    131     return exc.value

File ~/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/IPython/core/interactiveshell.py:3278, in InteractiveShell.run_cell_async(self, raw_cell, store_history, silent, shell_futures, transformed_cell, preprocessing_exc_tuple, cell_id)
   3274     return error_before_exec(e)
   3276 # Give the displayhook a reference to our ExecutionResult so it
   3277 # can fill in the output value.
-> 3278 self.displayhook.exec_result = result
   3280 # Execute the user code
   3281 interactivity = "none" if silent else self.ast_node_interactivity

File ~/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/traitlets/traitlets.py:745, in TraitType.__set__(self, obj, value)
    743     raise TraitError('The "%s" trait is read-only.' % self.name)
    744 else:
--> 745     self.set(obj, value)

File ~/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/traitlets/traitlets.py:719, in TraitType.set(self, obj, value)
    718 def set(self, obj, value):
--> 719     new_value = self._validate(obj, value)
    720     try:
    721         old_value = obj._trait_values[self.name]

File ~/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/traitlets/traitlets.py:751, in TraitType._validate(self, obj, value)
    749     return value
    750 if hasattr(self, "validate"):
--> 751     value = self.validate(obj, value)
    752 if obj._cross_validation_lock is False:
    753     value = self._cross_validate(obj, value)

File ~/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/traitlets/traitlets.py:2311, in Instance.validate(self, obj, value)
   2309 def validate(self, obj, value):
   2310     assert self.klass is not None
-> 2311     if isinstance(value, self.klass):  # type:ignore[arg-type]
   2312         return value
   2313     else:

TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union
fig, ax = plt.subplots(ncols=2, figsize=(10,4))

da.u.isel(time=10, lat=slice(1,-1), lon=slice(1,-1)).plot.pcolormesh(ax=ax[0], cmap="gray")
da.v.isel(time=10, lat=slice(1,-1), lon=slice(1,-1)).plot.pcolormesh(ax=ax[1], cmap="gray")

plt.tight_layout()
plt.show()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/Users/eman/code_projects/oceanbench/jbook/content/geoprocess/physical_variables.ipynb Cell 24 line 3
      <a href='vscode-notebook-cell:/Users/eman/code_projects/oceanbench/jbook/content/geoprocess/physical_variables.ipynb#X31sZmlsZQ%3D%3D?line=0'>1</a> fig, ax = plt.subplots(ncols=2, figsize=(10,4))
----> <a href='vscode-notebook-cell:/Users/eman/code_projects/oceanbench/jbook/content/geoprocess/physical_variables.ipynb#X31sZmlsZQ%3D%3D?line=2'>3</a> da.u.isel(time=10, lat=slice(1,-1), lon=slice(1,-1)).plot.pcolormesh(ax=ax[0], cmap="gray")
      <a href='vscode-notebook-cell:/Users/eman/code_projects/oceanbench/jbook/content/geoprocess/physical_variables.ipynb#X31sZmlsZQ%3D%3D?line=3'>4</a> da.v.isel(time=10, lat=slice(1,-1), lon=slice(1,-1)).plot.pcolormesh(ax=ax[1], cmap="gray")
      <a href='vscode-notebook-cell:/Users/eman/code_projects/oceanbench/jbook/content/geoprocess/physical_variables.ipynb#X31sZmlsZQ%3D%3D?line=5'>6</a> plt.tight_layout()

File ~/miniconda3/envs/oceanbench_311/lib/python3.11/site-packages/xarray/core/common.py:278, in AttrAccessMixin.__getattr__(self, name)
    276         with suppress(KeyError):
    277             return source[name]
--> 278 raise AttributeError(
    279     f"{type(self).__name__!r} object has no attribute {name!r}"
    280 )

AttributeError: 'Dataset' object has no attribute 'u'

Kinetic Energy#

\[\begin{split} \begin{aligned} E &= \frac{1}{2}\int \mathbf{u}^2dr \\ E &\approx \frac{1}{2} \mathbb{E}\left[ \mathbf{u}^2\right] \\ &= \frac{1}{2} \mathbb{E}\left[ u^2 + v^2\right] \end{aligned} \end{split}\]
da = geocalc.kinetic_energy(da, variables=["u", "v"])
fig, ax = plt.subplots()

da.ke.isel(time=1, lat=slice(1,-1), lon=slice(1,-1)).plot.pcolormesh(ax=ax, cmap="YlGnBu_r", robust=True)

plt.show()
../../_images/3cef86876e5ffdc65c98823892c00fb3d39631a32fbe07896b0f5bb9803788e7.png

Relative Vorticity#

Somtimes called the vertical vorticity.

\[ \zeta = \frac{\partial v}{\partial x} - \frac{\partial u}{\partial y} \]

Note that the u,v velocities can be calculated from the stream function as

\[\begin{split} \begin{aligned} u &= -\frac{\partial \psi}{\partial y} && && v = \frac{\partial \psi}{\partial x}\\ \end{aligned} \end{split}\]

So plugging these into the equation, we get:

\[\begin{split} \begin{aligned} \zeta &= \frac{\partial}{\partial x}\left(\frac{\partial \psi}{\partial x}\right) - \frac{\partial}{\partial y}\left( -\frac{\partial \psi}{\partial y}\right) \\ \zeta &= \frac{\partial^2 \psi}{\partial x^2}+ \frac{\partial^2 \psi}{\partial y^2}\\ \zeta &=\nabla^2\psi \end{aligned} \end{split}\]

We can also calculate a normalized version

\[ \bar{\zeta} = \frac{\zeta}{f_0} \]

Note: This is closely related to the geostrophic eqns:

\[ \begin{aligned} \text{Relative Vorticity }[s^{-1}]: && \zeta &=\boldsymbol{\zeta}(\vec{\mathbf{x}},t) && && \boldsymbol{\xi}: \boldsymbol{\Omega}\times\boldsymbol{T}\rightarrow\mathbb{R} \end{aligned} \]
\[ \zeta = \nabla^2\psi \]
da = geocalc.relative_vorticity(da, variables=["u", "v"])
# da = geocalc.coriolis_normalized(da, "vort_r")
fig, ax = plt.subplots()

da.vort_r.isel(time=1).plot.pcolormesh(ax=ax, cmap="RdBu_r")

plt.show()
../../_images/ae54b097f3db8b079d34a49bfec3ddb524b992a48e6f720fe2028791cf67f157.png

Absolute Vorticity#

Somtimes called the horizontal divergence.

\[ \zeta = \frac{\partial v}{\partial x} + \frac{\partial u}{\partial y} \]

Note that the u,v velocities can be calculated from the stream function as

\[\begin{split} \begin{aligned} u &= -\frac{\partial \psi}{\partial y} && && v = \frac{\partial \psi}{\partial x}\\ \end{aligned} \end{split}\]

So plugging these into the equation, we get:

\[\begin{split} \begin{aligned} \zeta &= \frac{\partial}{\partial x}\left(\frac{\partial \psi}{\partial x}\right) + \frac{\partial}{\partial y}\left( -\frac{\partial \psi}{\partial y}\right) \\ \zeta &= \frac{\partial^2 \psi}{\partial x^2} - \frac{\partial^2 \psi}{\partial y^2} \end{aligned} \end{split}\]

We can also calculate a normalized version

\[ \bar{\zeta} = \frac{\zeta}{f_0} \]
da = geocalc.absolute_vorticity(da, variables=["u", "v"])
da = geocalc.coriolis_normalized(da, "vort_a")
fig, ax = plt.subplots()

da.vort_a.isel(time=10).plot.pcolormesh(ax=ax, cmap="RdBu_r")

plt.show()
../../_images/4e77d090a2a51a31b9104918634517bc27b877c60348674f508baeeb06678732.png

Divergence#

\[ \nabla \cdot \vec{\mathbf{u}} = \frac{\partial u}{\partial x} + \frac{\partial v}{\partial y} \]
da = geocalc.divergence(da, variables=["u", "v"])
da = geocalc.coriolis_normalized(da, "div")
fig, ax = plt.subplots()

da.div.isel(time=10).plot.pcolormesh(ax=ax, cmap="RdBu_r")

plt.show()
../../_images/e07cf7b33fd2aefb8984e521f07f5520cceb1c68e9d37940c1f9df3ec1428ec8.png

Enstropy#

This is a summarization of the relative vorticity

\[\begin{split} \begin{aligned} Z &= \frac{1}{2}\int \zeta^2 dr \\ Z &\approx \frac{1}{2} \mathbb{E}\left[ \zeta^2 \right] \\ \end{aligned} \end{split}\]
da = geocalc.enstrophy(da, variable="vort_r")
da = geocalc.coriolis_normalized(da, "ens")
fig, ax = plt.subplots()

da.ens.isel(time=10).plot.pcolormesh(ax=ax, cmap="RdBu_r")

plt.show()
../../_images/032b1d09f1cfaad6dd749372f66fa01508ec9c4e5b4ec21920e6f2dabe2833db.png

Strain#

Shear Strain#

We also have the Shearing Deformation given by:

\[ S_s = \frac{\partial v}{\partial x} + \frac{\partial u}{\partial y} \]
da = geocalc.shear_strain(da, variables=["u", "v"])
da
<xarray.Dataset>
Dimensions:       (time: 60, lat: 201, lon: 201)
Coordinates:
  * lon           (lon) float64 -65.0 -64.95 -64.9 -64.85 ... -55.1 -55.05 -55.0
  * lat           (lat) float64 33.0 33.05 33.1 33.15 ... 42.85 42.9 42.95 43.0
  * time          (time) datetime64[ns] 2013-01-01 2013-01-02 ... 2013-03-01
Data variables:
    ssh           (time, lat, lon) float64 <Quantity([[[ 0.52873772  0.528737...
    psi           (time, lat, lon) float64 <Quantity([[[ 57821.90125565  5782...
    u             (time, lat, lon) float64 <Quantity([[[ 0.09819786  0.098197...
    v             (time, lat, lon) float64 <Quantity([[[ 0.06750432 -0.067504...
    ke            (time, lat, lon) float64 <Quantity([[[7.09982675e-03 7.0998...
    vort_r        (time, lat, lon) float64 <Quantity([[[-21.03727654 -13.1933...
    vort_a        (time, lat, lon) float64 <Quantity([[[26.01496319 33.858852...
    div           (time, lat, lon) float64 <Quantity([[[-22.41076683 -11.8198...
    ens           (time, lat, lon) float64 <Quantity([[[1.31080192e+08 5.1554...
    shear_strain  (time, lat, lon) float64 <Quantity([[[ 1.24743972e-08 -1.24...
fig, ax = plt.subplots()

da.shear_strain.isel(time=10).plot.pcolormesh(ax=ax, cmap="RdBu_r")

plt.show()
../../_images/5313d96f113733595719da52f57f3d37ec4d4a3250f3986fe030eca4a74f5792.png

Normal Strain#

Sometimes called Stretching Deformation.

\[ \sigma_n = \frac{\partial u}{\partial x} - \frac{\partial v}{\partial y} \]
da = geocalc.tensor_strain(da, variables=["u", "v"])
fig, ax = plt.subplots()

da.tensor_strain.isel(time=10).plot.pcolormesh(ax=ax, cmap="RdBu_r")

plt.show()
../../_images/e762aa6d1803963424115ed9234151cebf16cca64279b36b7f73460ff3e5d06d.png

Strain Magnitude#

Often, we are interested in the give by:

\[ \sigma = \sqrt{\sigma_n^2 + \sigma_s^2} \]

Note: Also known as the total deformation.

The normal and shear strains are coordinate invariant. The vorticity and divergence and strain magnitude is coordinate invariant!

Often times, we use the relative strain magnitude:

\[ \bar{\sigma} = \frac{\sigma}{f_0} \]
da = geocalc.strain_magnitude(da, variables=["u", "v"])
da = geocalc.coriolis_normalized(da, variable="strain")
import cmocean as cmo

fig, ax = plt.subplots()

da.strain.isel(time=10).plot.pcolormesh(ax=ax, cmap=cmo.cm.speed, robust=True)

plt.show()
../../_images/7bbf3f658852d840a4345ca830ce4fc828aa9b6c836a9dc86ce778b8bb52c38c.png

Okubo-Weiss Parameter#

OW parameter [Okubo, 1970; Weiss, 1991] describes the relative dominance of deformation with respect to rotation of the flow.

This is a combination of the Strain (deformation rate) and the vorticity

\[ \sigma_o = \sigma_n^2 + \sigma_s^2 - \zeta^2 \]

where:

\[\begin{split} \begin{aligned} \text{Normal Strain}: && && \sigma_n &= \frac{\partial u}{\partial x} - \frac{\partial v}{\partial y} \\ \text{Shear Strain}: && && \sigma_s &= \frac{\partial v}{\partial x} + \frac{\partial u}{\partial y} \\ \text{Relative Vorticity}: && && \zeta &= \frac{\partial v}{\partial x} - \frac{\partial u}{\partial y} \end{aligned} \end{split}\]

Sources:

da = geocalc.okubo_weiss_param(da, variables=["u", "v"])
import cmocean as cmo

fig, ax = plt.subplots()

da.ow.isel(time=10).plot.contourf(ax=ax, cmap="cividis")

plt.show()
../../_images/dc88c95657f48fabb652b24d0f2b6d503374eb802bb531ecb1f6317efbbf7b49.png