{ "cells": [ { "cell_type": "markdown", "id": "0affcd5f", "metadata": {}, "source": [ "# Part 2: Thermal Wind\n", "Andrew Delman, updated 2025-07-24.\n", "\n", "## Objectives\n", "\n", "To use ECCO state estimate output to explore thermal wind and its use in understanding the ocean circulation.\n", "\n", "By the end of the tutorial, you will be able to:\n", "\n", "* Plot transects along lines of latitude in the ECCO native grid\n", "* Rotate fields in model axes to true zonal/meridional orientation\n", "* Relate the density structure to the direction of oceanic flow (thermal wind balance)\n", "* Estimate oceanic velocity using thermal wind and assumption of a level of no motion\n", "\n", "## Introduction\n", "\n", "In the previous tutorial we established that geostrophic balance explains most of the oceanic circulation--at least at the spatial and temporal scales of ECCOv4r4 output. Now we consider thermal wind, a property of geostrophic flow that has been very useful to atmospheric and ocean scientists alike. Thermal wind balance is derived directly from geostrophic balance (in horizontal directions)\n", "\n", "$$\n", "v_g = \\frac{1}{f\\rho}\\frac{\\partial{p}}{\\partial{x}}\n", "$$\n", "$$\n", "u_g = -\\frac{1}{f\\rho}\\frac{\\partial{p}}{\\partial{y}}\n", "$$\n", "\n", "and hydrostatic balance (in the vertical direction)\n", "\n", "$$\n", "\\frac{\\partial{p}}{\\partial{z}} = -{\\rho}g\n", "$$\n", "\n", "Therefore by differentiating geostrophic balance along the $z$ axis and assuming hydrostatic conditions, we get thermal wind balance:\n", "\n", "$$\n", "\\frac{\\partial{v_g}}{\\partial{z}} = -\\frac{g}{f\\rho}\\frac{\\partial{\\rho}}{\\partial{x}}\n", "$$\n", "$$\n", "\\frac{\\partial{u_g}}{\\partial{z}} = \\frac{g}{f\\rho}\\frac{\\partial{\\rho}}{\\partial{y}}\n", "$$\n", "\n", "(cf. Vallis ch. 2.8, Kundu and Cohen ch. 14.5, Gill ch. 7.7)\n", "\n", "The *thermal wind* name originates from the application of these equations to atmospheric dynamics, where the velocities are the wind and density is mostly a function of temperature. But the balance is just as important to oceanic dynamics. In both the atmosphere and ocean, thermal wind enabled early measurements of temperature (and salinity in the ocean) to be used to construct velocity fields, where velocities are often difficult to measure directly. And even in present times when velocities can be measured directly, the thermal wind relation connects changes in heat and salt content to changes in the ocean circulation.\n", "\n", "## Viewing and Plotting Density\n", "\n", "### Transect on a single tile\n", "\n", "Let's use the density and velocity output datasets from ECCOv4r4 for January 2000, as used in the previous tutorial. This time, we'll focus on ```tile=10```, which is rotated counterclockwise so that the $j$ index increases with increasing longitude (not latitude), and the $i$ index increases with *decreasing* latitude. Tiles 7-12 (the 8th through 13th tiles, remember Python indexing starts at 0) are rotated in this way, as illustrated in the following tile plot\n", "\n", "\n", "\n", "For this tutorial, we will need the ECCO datasets with the following ShortNames:\n", "\n", "- **ECCO_L4_OCEAN_VEL_LLC0090GRID_MONTHLY_V4R4** (Jan 2000)\n", "- **ECCO_L4_DENS_STRAT_PRESS_LLC0090GRID_MONTHLY_V4R4** (Jan 2000)\n", "- **ECCO_L4_GEOMETRY_LLC0090GRID_V4R4** (no time dimension)\n", "\n", "To download these datasets to your local machine, we use the `ecco_access` Python package. See the `ecco_access` [documentation](https://ecco-access.readthedocs.io) for instructions on how to set this up. If not working in the AWS cloud, the \"access mode\" for retrieving the datasets is `download_ifspace` by default, which downloads the data (under `~/Downloads/ECCO_V4r4_PODAAC/`) only if it will occupy <50% of available storage. If it will occupy more than this amount of storage, an error is returned. See the [access modes](https://ecco-access.readthedocs.io/ECCO_access_modes.html) tutorial for more information on these modes.\n", "\n", "> Tip: If you are working in the AWS Cloud, you can specify `incloud_access = True`, which will then use mode = `s3_open_fsspec` by default. The `s3_open_fsspec` mode downloads pre-generated `.json` files that essentially act as an index to the data files, greatly speeding up access to them within the AWS Cloud.\n", "\n", "We are going to load the density dataset and plot density on longitude-depth axes following the line in the grid nearest to $26^{o}$ N, i.e., ```i = 73```." ] }, { "cell_type": "code", "execution_count": 1, "id": "c13e11ca", "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 expanduser,join\n", "user_home_dir = expanduser('~')\n", "\n", "if incloud_access:\n", " access_mode = 's3_open_fsspec'\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", "# first import needed packages\n", "import numpy as np\n", "import xarray as xr\n", "import xmitgcm\n", "import xgcm\n", "import glob\n", "import sys\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 * # import from ecco_po_tutorials.py module downloaded in the last tutorial\n", "\n", "\n", "# ShortNames\n", "vel_monthly_shortname = \"ECCO_L4_OCEAN_VEL_LLC0090GRID_MONTHLY_V4R4\"\n", "denspress_monthly_shortname = \"ECCO_L4_DENS_STRAT_PRESS_LLC0090GRID_MONTHLY_V4R4\"\n", "grid_params_shortname = \"ECCO_L4_GEOMETRY_LLC0090GRID_V4R4\"" ] }, { "cell_type": "code", "execution_count": 3, "id": "15f040c1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Size of files to be downloaded to instance is 0.029 GB,\n", "which is 0.02% of the 143.718 GB available storage.\n", "Proceeding with file downloads via NASA Earthdata URLs\n", "DL Progress: 100%|###########################| 1/1 [00:03<00:00, 3.02s/it]\n", "\n", "=====================================\n", "total downloaded: 30.98 Mb\n", "avg download speed: 10.25 Mb/s\n", "Time spent = 3.021937131881714 seconds\n", "\n", "\n" ] }, { "data": { "text/html": [ "
<xarray.Dataset> Size: 89MB\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 dask.array<chunksize=(50,), meta=np.ndarray>\n",
" Zl (k_l) float32 200B dask.array<chunksize=(50,), meta=np.ndarray>\n",
" time_bnds (time, nv) datetime64[ns] 16B dask.array<chunksize=(1, 2), meta=np.ndarray>\n",
" XC_bnds (tile, j, i, nb) float32 2MB dask.array<chunksize=(13, 90, 90, 4), meta=np.ndarray>\n",
" YC_bnds (tile, j, i, nb) float32 2MB dask.array<chunksize=(13, 90, 90, 4), meta=np.ndarray>\n",
" Z_bnds (k, nv) float32 400B dask.array<chunksize=(50, 2), meta=np.ndarray>\n",
"Dimensions without coordinates: nv, nb\n",
"Data variables:\n",
" RHOAnoma (time, k, tile, j, i) float32 21MB dask.array<chunksize=(1, 25, 7, 45, 45), meta=np.ndarray>\n",
" DRHODR (time, k_l, tile, j, i) float32 21MB dask.array<chunksize=(1, 25, 7, 45, 45), meta=np.ndarray>\n",
" PHIHYD (time, k, tile, j, i) float32 21MB dask.array<chunksize=(1, 25, 7, 45, 45), meta=np.ndarray>\n",
" PHIHYDcR (time, k, tile, j, i) float32 21MB dask.array<chunksize=(1, 25, 7, 45, 45), meta=np.ndarray>\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 Density, Stratification, and ...\n",
" uuid: 166a1992-4182-11eb-82f9-0cc47a3f43f9