{ "cells": [ { "cell_type": "markdown", "id": "a10192dd", "metadata": {}, "source": [ "# Part 3a: Steric height\n", "Andrew Delman. Updated 2026-05-15.\n", "\n", "## Objectives\n", "\n", "To use ECCO state output to investigate steric height anomalies.\n", "\n", "By the end of this tutorial, you will be able to:\n", "\n", "* Compute steric height anomaly (SHA)\n", "* Compare SHA with sea surface height\n", "* Use the Jackett and McDougall (1995) equation of state to carry out conversions of temperature and salinity to specific volume/density\n", "* Estimate contributions of temperature and salinity to SHA" ] }, { "cell_type": "markdown", "id": "a1f264c4", "metadata": {}, "source": [ "## Introduction\n", "\n", "### Steric height anomaly formulation\n", "\n", "Though the density of ocean water changes relatively little compared to the density of air and other gases, even relatively small variations in ocean water density have large impacts on the ocean circulation and sea level variations. Under the conditions of hydrostatic balance (conditions assumed by the MITgcm model configuration run in ECCO v4r4), the vertical gradient of pressure $\\partial{p}/\\partial{z}$ is a function of density $\\rho$ and gravitational acceleration $g$:\n", "\n", "$$\n", "\\frac{\\partial{p}}{\\partial{z}} = -{\\rho}g\n", "$$\n", "\n", "When the density of a parcel water changes, e.g. because its temperature or salinity changes, the parcel of water expands or contracts, and this has an effect on the vertical height of the parcel. This can be expressed in terms of the change in height between two pressure surfaces.\n", "\n", "$$\n", "{\\Delta}z = \\frac{{\\Delta}p}{-{\\rho}g}\n", "$$\n", "\n", "or in integral form\n", "\n", "$$\n", "h = \\int_{p_r}^{p} \\frac{dp}{-{\\rho}g}\n", "$$\n", "\n", "which can also be notated in terms of the specific volume $V_{sp} \\equiv 1/\\rho$\n", "\n", "$$\n", "h = \\int_{p_r}^{p} -\\frac{V_{sp}}{g} \\, dp\n", "$$\n", "\n", "(cf. Gill ch. 7.7, or discussion of thickness in Vallis ch. 2.6)\n", "\n", "where $h$ is the steric height at pressure level $p$ relative to some reference pressure level $p_r$. The atmospheric analogue to steric height is called *thickness*, and is commonly used in meteorology and atmospheric science. Generally we are less interested in the value of the steric height itself than in its spatial or temporal variation, so the steric height anomaly $h^{\\prime}$ can be defined in terms of a specific volume anomaly $V_{sp}^{\\prime}$\n", "\n", "$$\n", "h^{\\prime} = \\int_{p_r}^{p} -\\frac{V_{sp}^{\\prime}}{g} \\, dp\n", "$$\n", "\n", "where $V_{sp}^{\\prime}$ is the anomaly from the a reference specific volume $V_r$. Sometimes the literature also refers to the geopotential anomaly, which is the steric height anomaly times $g$ (i.e., the above equation without dividing by $g$) and has units m$^2$ s$^{-2}$.\n", "\n", "\n", "\n", "### Equation of state\n", "\n", "Since we will be computing seawater density and its components associated with temperature and salinity changes, we need to use an [equation of state](https://en.wikipedia.org/wiki/TEOS-10) for seawater. Currently the international standard equation of state is [TEOS-10](https://www.teos-10.org/), which has the [GSW-Python package](https://teos-10.github.io/GSW-Python/) to facilitate computations in Python. However, ECCO's configuration of MITgcm uses an older version of the equation of state introduced by [Jackett and McDougall (1995)](https://doi.org/10.1175/1520-0426(1995)012%3C0381:MAOHPT%3E2.0.CO;2) to compute density variations. We will use this equation of state (abbreviated JMD95) here. Conveniently, there is a [Python implementation of JMD95](https://github.com/brian-rose/MITgcmutils/blob/master/MITgcmutils/jmd95.py) so that it is not necessary to code this ourselves. The *jmd95.py* module is included in the tutorial repository to facilitate its use here.\n", "\n", "## Open files\n", "\n", "For this tutorial, we will need the ECCO datasets with the following ShortNames:\n", "\n", "- **ECCO_L4_GEOMETRY_LLC0090GRID_V4R4** (no time dimension)\n", "- **ECCO_L4_DENS_STRAT_PRESS_LLC0090GRID_MONTHLY_V4R4** (Jan 2000)\n", "- **ECCO_L4_SSH_LLC0090GRID_MONTHLY_V4R4** (Jan 2000)\n", "- **ECCO_L4_TEMP_SALINITY_LLC0090GRID_MONTHLY_V4R4** (Jan 2000)\n", "\n", "The notebook uses the `ecco_access` Python package to download these datasets. See [this tutorial](https://ecco-access.readthedocs.io/Using_ECCO_access.html) for more info on how to use `ecco_access`. If you are working on an AWS instance, just set `incloud_access = True` in the 1st cell and the datasets will be downloaded to your instance or opened remotely on S3 depending on your available storage." ] }, { "cell_type": "code", "execution_count": 1, "id": "a3e52ae3", "metadata": {}, "outputs": [], "source": [ "# specify incloud_access = True if working in the AWS Cloud, otherwise False\n", "incloud_access = False\n", "\n", "from os.path import join,expanduser\n", "user_home_dir = expanduser('~')\n", "\n", "if incloud_access:\n", " access_mode = 's3_get_ifspace'\n", " download_root_dir = None\n", " # specify location to store json files that will speed up S3 data access\n", " jsons_root_dir = join(user_home_dir,'MZZ') \n", "else:\n", " access_mode = 'download_ifspace'\n", " # specify location to store downloaded files\n", " # ~/Downloads/ECCO_V4r4_PODAAC is also the default path used for download_root_dir; \n", " # change as needed\n", " download_root_dir = join(user_home_dir,'Downloads','ECCO_V4r4_PODAAC')\n", " jsons_root_dir = None \n", "\n", "\n", "# import needed packages\n", "import numpy as np\n", "import xarray as xr\n", "import glob\n", "import sys\n", "user_home_dir = expanduser('~')\n", "import matplotlib.pyplot as plt\n", "\n", "import ecco_v4_py as ecco\n", "import ecco_access as ea\n", "from ecco_po_tutorials import *\n", "\n", "# import function that computes density in jmd95.py module\n", "from jmd95 import densjmd95" ] }, { "cell_type": "code", "execution_count": 2, "id": "4de2d0de-e1eb-4fd7-b615-12a0f96462e5", "metadata": {}, "outputs": [], "source": [ "# ShortNames\n", "grid_params_shortname = \"ECCO_L4_GEOMETRY_LLC0090GRID_V4R4\"\n", "denspress_monthly_shortname = \"ECCO_L4_DENS_STRAT_PRESS_LLC0090GRID_MONTHLY_V4R4\"\n", "SSH_monthly_shortname = \"ECCO_L4_SSH_LLC0090GRID_MONTHLY_V4R4\"\n", "TS_monthly_shortname = \"ECCO_L4_TEMP_SALINITY_LLC0090GRID_MONTHLY_V4R4\"\n", "\n", "ShortNames_list = [grid_params_shortname,denspress_monthly_shortname,\\\n", " SSH_monthly_shortname,TS_monthly_shortname]" ] }, { "cell_type": "code", "execution_count": 3, "id": "7a620c27-72df-4e3b-96f8-1b9090ee6047", "metadata": {}, "outputs": [], "source": [ "# specify location to store downloaded files\n", "\n", "# ~/Downloads/ECCO_V4r4_PODAAC is also the default path used for download_root_dir; \n", "# change as needed\n", "download_root_dir = join(user_home_dir,'Downloads','ECCO_V4r4_PODAAC')" ] }, { "cell_type": "markdown", "id": "8e145a18", "metadata": {}, "source": [ "### Grid and density/pressure files\n", "\n", "If you've completed the previous tutorials you are quite familiar with these files by now." ] }, { "cell_type": "code", "execution_count": 4, "id": "f0dd396b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Download to directory /home/jpluser/Downloads/ECCO_V4r4_PODAAC/ECCO_L4_GEOMETRY_LLC0090GRID_V4R4\n", "Size of files to be downloaded to instance is 0.008 GB,\n", "which is 0.04% of the 18.521 GB available storage.\n", "Proceeding with file downloads via NASA Earthdata URLs\n", "DL Progress: 100%|###########################| 1/1 [00:02<00:00, 2.30s/it]\n", "\n", "=====================================\n", "total downloaded: 8.57 Mb\n", "avg download speed: 3.72 Mb/s\n", "Time spent = 2.3052399158477783 seconds\n", "\n", "\n", "Download to directory /home/jpluser/Downloads/ECCO_V4r4_PODAAC/ECCO_L4_DENS_STRAT_PRESS_LLC0090GRID_MONTHLY_V4R4\n", "Size of files to be downloaded to instance is 0.029 GB,\n", "which is 0.16% of the 18.513 GB available storage.\n", "Proceeding with file downloads via NASA Earthdata URLs\n", "DL Progress: 100%|###########################| 1/1 [00:03<00:00, 3.32s/it]\n", "\n", "=====================================\n", "total downloaded: 30.98 Mb\n", "avg download speed: 9.32 Mb/s\n", "Time spent = 3.32550048828125 seconds\n", "\n", "\n" ] } ], "source": [ "# load grid parameters\n", "ds_grid = ea.ecco_podaac_to_xrdataset(grid_params_shortname,\\\n", " mode=access_mode,\\\n", " download_root_dir=download_root_dir,\\\n", " jsons_root_dir=jsons_root_dir,\\\n", " prompt_request_payer=False)\n", "ds_grid = ds_grid.compute() # load into memory (rather than delaying computation)\n", "\n", "# density/pressure dataset\n", "ds_denspress = ea.ecco_podaac_to_xrdataset(denspress_monthly_shortname,\\\n", " StartDate=\"2000-01\",EndDate=\"2000-01\",\\\n", " mode=access_mode,\\\n", " download_root_dir=download_root_dir,\\\n", " jsons_root_dir=jsons_root_dir,\\\n", " prompt_request_payer=False)\n", "ds_denspress = ds_denspress.compute()" ] }, { "cell_type": "markdown", "id": "8dbac0b6", "metadata": {}, "source": [ "### Sea surface height file\n", "\n", "To look at the impact of steric height variations, we will also be looking at the actual sea surface height field from ECCOv4. Consulting the [variable list](https://raw.githubusercontent.com/ECCO-GROUP/ECCO-v4-Python-Tutorial/master/varlist/v4r4_nctiles_monthly_varlist.txt) for monthly mean output, we find that the datasets containing sea surface height have ShortName ```ECCO_L4_SSH_LLC0090GRID_MONTHLY_V4R4```. To start, we access the granule of that dataset corresponding to January 2000 (2000-01)." ] }, { "cell_type": "code", "execution_count": 5, "id": "31d224f4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Download to directory /home/jpluser/Downloads/ECCO_V4r4_PODAAC/ECCO_L4_SSH_LLC0090GRID_MONTHLY_V4R4\n", "Size of files to be downloaded to instance is 0.006 GB,\n", "which is 0.03% of the 18.484 GB available storage.\n", "Proceeding with file downloads via NASA Earthdata URLs\n", "DL Progress: 100%|###########################| 1/1 [00:02<00:00, 2.31s/it]\n", "\n", "=====================================\n", "total downloaded: 5.92 Mb\n", "avg download speed: 2.56 Mb/s\n", "Time spent = 2.3119957447052 seconds\n", "\n", "\n" ] }, { "data": { "text/html": [ "
<xarray.Dataset> Size: 7MB\n",
"Dimensions: (i: 90, i_g: 90, j: 90, j_g: 90, tile: 13, time: 1, nv: 2, nb: 4)\n",
"Coordinates: (12/13)\n",
" * i (i) int32 360B 0 1 2 3 4 5 6 7 8 9 ... 81 82 83 84 85 86 87 88 89\n",
" * i_g (i_g) int32 360B 0 1 2 3 4 5 6 7 8 ... 81 82 83 84 85 86 87 88 89\n",
" * j (j) int32 360B 0 1 2 3 4 5 6 7 8 9 ... 81 82 83 84 85 86 87 88 89\n",
" * j_g (j_g) int32 360B 0 1 2 3 4 5 6 7 8 ... 81 82 83 84 85 86 87 88 89\n",
" * tile (tile) int32 52B 0 1 2 3 4 5 6 7 8 9 10 11 12\n",
" * time (time) datetime64[ns] 8B 2000-01-16T12:00:00\n",
" ... ...\n",
" YC (tile, j, i) float32 421kB -88.24 -88.38 -88.52 ... -88.08 -88.1\n",
" XG (tile, j_g, i_g) float32 421kB -115.0 -115.0 ... -102.9 -109.0\n",
" YG (tile, j_g, i_g) float32 421kB -88.18 -88.32 ... -87.99 -88.02\n",
" time_bnds (time, nv) datetime64[ns] 16B 2000-01-01 2000-02-01\n",
" XC_bnds (tile, j, i, nb) float32 2MB -115.0 -115.0 ... -115.0 -108.5\n",
" YC_bnds (tile, j, i, nb) float32 2MB -88.18 -88.32 ... -88.18 -88.16\n",
"Dimensions without coordinates: nv, nb\n",
"Data variables:\n",
" SSH (time, tile, j, i) float32 421kB nan nan nan nan ... nan nan nan\n",
" SSHIBC (time, tile, j, i) float32 421kB nan nan nan nan ... nan nan nan\n",
" SSHNOIBC (time, tile, j, i) float32 421kB nan nan nan nan ... nan nan nan\n",
" ETAN (time, tile, j, i) float32 421kB nan nan nan nan ... nan nan nan\n",
"Attributes: (12/57)\n",
" acknowledgement: This research was carried out by the Jet Pr...\n",
" author: Ian Fenty and Ou Wang\n",
" cdm_data_type: Grid\n",
" comment: Fields provided on the curvilinear lat-lon-...\n",
" Conventions: CF-1.8, ACDD-1.3\n",
" coordinates_comment: Note: the global 'coordinates' attribute de...\n",
" ... ...\n",
" time_coverage_duration: P1M\n",
" time_coverage_end: 2000-02-01T00:00:00\n",
" time_coverage_resolution: P1M\n",
" time_coverage_start: 2000-01-01T00:00:00\n",
" title: ECCO Sea Surface Height - Monthly Mean llc9...\n",
" uuid: a7c2a1c4-400c-11eb-9f79-0cc47a3f49c3<xarray.Dataset> Size: 47MB\n",
"Dimensions: (i: 90, i_g: 90, j: 90, j_g: 90, k: 50, k_u: 50, k_l: 50,\n",
" k_p1: 51, tile: 13, time: 1, nv: 2, nb: 4)\n",
"Coordinates: (12/22)\n",
" * i (i) int32 360B 0 1 2 3 4 5 6 7 8 9 ... 81 82 83 84 85 86 87 88 89\n",
" * i_g (i_g) int32 360B 0 1 2 3 4 5 6 7 8 ... 81 82 83 84 85 86 87 88 89\n",
" * j (j) int32 360B 0 1 2 3 4 5 6 7 8 9 ... 81 82 83 84 85 86 87 88 89\n",
" * j_g (j_g) int32 360B 0 1 2 3 4 5 6 7 8 ... 81 82 83 84 85 86 87 88 89\n",
" * k (k) int32 200B 0 1 2 3 4 5 6 7 8 9 ... 41 42 43 44 45 46 47 48 49\n",
" * k_u (k_u) int32 200B 0 1 2 3 4 5 6 7 8 ... 41 42 43 44 45 46 47 48 49\n",
" ... ...\n",
" Zu (k_u) float32 200B -10.0 -20.0 -30.0 ... -5.678e+03 -6.134e+03\n",
" Zl (k_l) float32 200B 0.0 -10.0 -20.0 ... -5.244e+03 -5.678e+03\n",
" time_bnds (time, nv) datetime64[ns] 16B 2000-01-01 2000-02-01\n",
" XC_bnds (tile, j, i, nb) float32 2MB -115.0 -115.0 ... -115.0 -108.5\n",
" YC_bnds (tile, j, i, nb) float32 2MB -88.18 -88.32 ... -88.18 -88.16\n",
" Z_bnds (k, nv) float32 400B 0.0 -10.0 -10.0 ... -5.678e+03 -6.134e+03\n",
"Dimensions without coordinates: nv, nb\n",
"Data variables:\n",
" THETA (time, k, tile, j, i) float32 21MB nan nan nan ... nan nan nan\n",
" SALT (time, k, tile, j, i) float32 21MB nan nan nan ... nan nan nan\n",
"Attributes: (12/62)\n",
" acknowledgement: This research was carried out by the Jet...\n",
" author: Ian Fenty and Ou Wang\n",
" cdm_data_type: Grid\n",
" comment: Fields provided on the curvilinear lat-l...\n",
" Conventions: CF-1.8, ACDD-1.3\n",
" coordinates_comment: Note: the global 'coordinates' attribute...\n",
" ... ...\n",
" time_coverage_duration: P1M\n",
" time_coverage_end: 2000-02-01T00:00:00\n",
" time_coverage_resolution: P1M\n",
" time_coverage_start: 2000-01-01T00:00:00\n",
" title: ECCO Ocean Temperature and Salinity - Mo...\n",
" uuid: f72f9b24-4181-11eb-bf7d-0cc47a3f4871