Skip to content

Commit ce74485

Browse files
Merge pull request #2248 from Parcels-code/gsw_tutorial
Adding a tutorial to show gsw use in Kernels
2 parents 2588538 + b2c5043 commit ce74485

File tree

6 files changed

+156
-588
lines changed

6 files changed

+156
-588
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "0",
6+
"metadata": {},
7+
"source": [
8+
"# Using the `gsw` toolbox to compute density"
9+
]
10+
},
11+
{
12+
"cell_type": "markdown",
13+
"id": "1",
14+
"metadata": {},
15+
"source": [
16+
"This tutorial shows how to use the [`gsw` toolbox](https://teos-10.github.io/GSW-Python/) (the Gibbs SeaWater Oceanographic Toolbox of TEOS-10) within Parcels to compute density from temperature and salinity fields. The `gsw` toolbox can be installed via `conda install gsw`."
17+
]
18+
},
19+
{
20+
"cell_type": "markdown",
21+
"id": "2",
22+
"metadata": {},
23+
"source": [
24+
"First, load the necessary libraries and the data:"
25+
]
26+
},
27+
{
28+
"cell_type": "code",
29+
"execution_count": null,
30+
"id": "3",
31+
"metadata": {},
32+
"outputs": [],
33+
"source": [
34+
"import gsw # The package to calculate density from temperature, salinity and depth\n",
35+
"import numpy as np\n",
36+
"import xarray as xr\n",
37+
"\n",
38+
"import parcels\n",
39+
"\n",
40+
"# Load the CopernicusMarine data in the Agulhas region from the example_datasets\n",
41+
"example_dataset_folder = parcels.download_example_dataset(\n",
42+
" \"CopernicusMarine_data_for_Argo_tutorial\"\n",
43+
")\n",
44+
"\n",
45+
"ds = xr.open_mfdataset(f\"{example_dataset_folder}/*.nc\", combine=\"by_coords\")\n",
46+
"\n",
47+
"# TODO check how we can get good performance without loading full dataset in memory\n",
48+
"ds.load() # load the dataset into memory\n",
49+
"\n",
50+
"fieldset = parcels.FieldSet.from_copernicusmarine(ds)"
51+
]
52+
},
53+
{
54+
"cell_type": "markdown",
55+
"id": "4",
56+
"metadata": {},
57+
"source": [
58+
"Now, define a custom Particle class that includes temperature, salinity, and density as variables, and create a ParticleSet with one particle at a known location:"
59+
]
60+
},
61+
{
62+
"cell_type": "code",
63+
"execution_count": null,
64+
"id": "5",
65+
"metadata": {},
66+
"outputs": [],
67+
"source": [
68+
"GSWParticle = parcels.Particle.add_variable(\n",
69+
" [\n",
70+
" parcels.Variable(\"temp\", dtype=np.float32, initial=np.nan),\n",
71+
" parcels.Variable(\"salt\", dtype=np.float32, initial=np.nan),\n",
72+
" parcels.Variable(\"density\", dtype=np.float32, initial=np.nan),\n",
73+
" ]\n",
74+
")\n",
75+
"\n",
76+
"# Initiate one Argo float in the Agulhas Current\n",
77+
"pset = parcels.ParticleSet(\n",
78+
" fieldset=fieldset,\n",
79+
" pclass=GSWParticle,\n",
80+
" lon=[32],\n",
81+
" lat=[-31],\n",
82+
" z=[200],\n",
83+
")"
84+
]
85+
},
86+
{
87+
"cell_type": "markdown",
88+
"id": "6",
89+
"metadata": {},
90+
"source": [
91+
"Now (as the core part of this tutorial) define a custom kernel that uses the `gsw` toolbox to compute density from temperature and salinity:"
92+
]
93+
},
94+
{
95+
"cell_type": "code",
96+
"execution_count": null,
97+
"id": "7",
98+
"metadata": {},
99+
"outputs": [],
100+
"source": [
101+
"def ParcelsGSW(particles, fieldset):\n",
102+
" particles.temp = fieldset.thetao[particles]\n",
103+
" particles.salt = fieldset.so[particles]\n",
104+
" pressure = gsw.p_from_z(-particles.z, particles.lat)\n",
105+
" particles.density = gsw.density.rho(particles.salt, particles.temp, pressure)"
106+
]
107+
},
108+
{
109+
"cell_type": "markdown",
110+
"id": "8",
111+
"metadata": {},
112+
"source": [
113+
"Finally, run the `ParcelsGSW` Kernel for one timestep and check (for Continuous Integration purposes) that the computed density is as expected:"
114+
]
115+
},
116+
{
117+
"cell_type": "code",
118+
"execution_count": null,
119+
"id": "9",
120+
"metadata": {},
121+
"outputs": [],
122+
"source": [
123+
"pset.execute(ParcelsGSW, runtime=np.timedelta64(1, \"s\"), dt=np.timedelta64(1, \"s\"))\n",
124+
"\n",
125+
"np.testing.assert_allclose(pset.density, [1026.8281], rtol=1e-5)\n",
126+
"\n",
127+
"print(\n",
128+
" f\"Temperature: {pset.temp[0]:.2f}, Salinity: {pset.salt[0]:.2f}, Density: {pset.density[0]:.2f}\"\n",
129+
")"
130+
]
131+
}
132+
],
133+
"metadata": {
134+
"kernelspec": {
135+
"display_name": "parcels",
136+
"language": "python",
137+
"name": "python3"
138+
},
139+
"language_info": {
140+
"codemirror_mode": {
141+
"name": "ipython",
142+
"version": 3
143+
},
144+
"file_extension": ".py",
145+
"mimetype": "text/x-python",
146+
"name": "python",
147+
"nbconvert_exporter": "python",
148+
"pygments_lexer": "ipython3",
149+
"version": "3.13.5"
150+
}
151+
},
152+
"nbformat": 4,
153+
"nbformat_minor": 5
154+
}

pixi.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ tests-notebooks = "pytest --nbval-lax -k 'argo' docs/examples"
7777
jupyter = "*"
7878
trajan = "*"
7979
matplotlib-base = ">=2.0.2"
80+
gsw = "*"
8081

8182
[feature.docs.dependencies]
8283
numpydoc = "!=1.9.0"

src/parcels/_tutorial.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
],
4848
"CopernicusMarine_data_for_Argo_tutorial": [
4949
"cmems_mod_glo_phy-cur_anfc_0.083deg_P1D-m_uo-vo_31.00E-33.00E_33.00S-30.00S_0.49-2225.08m_2024-01-01-2024-02-01.nc",
50+
"cmems_mod_glo_phy-so_anfc_0.083deg_P1D-m_so_31.00E-33.00E_33.00S-30.00S_0.49-2225.08m_2024-01-01-2024-02-01.nc",
5051
"cmems_mod_glo_phy-thetao_anfc_0.083deg_P1D-m_thetao_31.00E-33.00E_33.00S-30.00S_0.49-2225.08m_2024-01-01-2024-02-01.nc",
5152
],
5253
"DecayingMovingEddy_data": [

0 commit comments

Comments
 (0)