Skip to content

Commit 0f2be37

Browse files
Merge branch 'docs/tutorial_fesom' of github.com:Parcels-Code/Parcels into docs/tutorial_fesom
2 parents 8820d21 + 701ce13 commit 0f2be37

1 file changed

Lines changed: 114 additions & 7 deletions

File tree

docs/user_guide/examples/tutorial_fesom.ipynb

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,17 @@
2626
"execution_count": null,
2727
"metadata": {},
2828
"outputs": [],
29-
"source": "from pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport matplotlib.tri as mtri\nimport numpy as np\nimport uxarray as ux\n\nimport parcels\nimport parcels.tutorial"
29+
"source": [
30+
"from pathlib import Path\n",
31+
"\n",
32+
"import matplotlib.pyplot as plt\n",
33+
"import matplotlib.tri as mtri\n",
34+
"import numpy as np\n",
35+
"import uxarray as ux\n",
36+
"\n",
37+
"import parcels\n",
38+
"import parcels.tutorial"
39+
]
3040
},
3141
{
3242
"cell_type": "markdown",
@@ -46,14 +56,15 @@
4656
"outputs": [],
4757
"source": [
4858
"for name in [\n",
49-
" \"FESOM_periodic_channel/fesom_channel\", # grid description\n",
59+
" \"FESOM_periodic_channel/fesom_channel\", # grid description\n",
5060
" \"FESOM_periodic_channel/u.fesom_channel\", # zonal velocity (face-registered)\n",
5161
" \"FESOM_periodic_channel/v.fesom_channel\", # meridional velocity (face-registered)\n",
5262
" \"FESOM_periodic_channel/w.fesom_channel\", # vertical velocity (node-registered)\n",
5363
"]:\n",
5464
" parcels.tutorial.open_dataset(name)\n",
5565
"\n",
5666
"from parcels._datasets.remote import _DATA_HOME\n",
67+
"\n",
5768
"data_dir = Path(_DATA_HOME) / \"data\" / \"FESOM_periodic_channel\"\n",
5869
"\n",
5970
"grid_path = str(data_dir / \"fesom_channel.nc\")\n",
@@ -88,7 +99,9 @@
8899
"metadata": {},
89100
"outputs": [],
90101
"source": [
91-
"ds = ux.open_mfdataset(grid_path, data_paths).rename_vars({\"u\": \"U\", \"v\": \"V\", \"w\": \"W\"})\n",
102+
"ds = ux.open_mfdataset(grid_path, data_paths).rename_vars(\n",
103+
" {\"u\": \"U\", \"v\": \"V\", \"w\": \"W\"}\n",
104+
")\n",
92105
"ds"
93106
]
94107
},
@@ -113,7 +126,10 @@
113126
"execution_count": null,
114127
"metadata": {},
115128
"outputs": [],
116-
"source": "ds = parcels.convert.fesom_to_ugrid(ds)\nprint(\"dims:\", dict(ds.sizes))"
129+
"source": [
130+
"ds = parcels.convert.fesom_to_ugrid(ds)\n",
131+
"print(\"dims:\", dict(ds.sizes))"
132+
]
117133
},
118134
{
119135
"cell_type": "markdown",
@@ -155,7 +171,35 @@
155171
"execution_count": null,
156172
"metadata": {},
157173
"outputs": [],
158-
"source": "lon_grid, lat_grid = np.meshgrid(\n np.linspace(0.5, 4.0, 10),\n np.linspace(3.0, 15.0, 4),\n)\nlon = lon_grid.ravel()\nlat = lat_grid.ravel()\nz = np.full(lon.size, 50.0) # release at 50 m depth\n\npset = parcels.ParticleSet(\n fieldset=fieldset, pclass=parcels.Particle, lon=lon, lat=lat, z=z,\n)\n\noutput_file = parcels.ParticleFile(\"output-fesom.parquet\", outputdt=np.timedelta64(1, \"h\"))\n\npset.execute(\n [parcels.kernels.AdvectionRK4],\n runtime=np.timedelta64(2, \"D\"),\n dt=np.timedelta64(5, \"m\"),\n output_file=output_file,\n verbose_progress=False,\n)"
174+
"source": [
175+
"lon_grid, lat_grid = np.meshgrid(\n",
176+
" np.linspace(0.5, 4.0, 10),\n",
177+
" np.linspace(3.0, 15.0, 4),\n",
178+
")\n",
179+
"lon = lon_grid.ravel()\n",
180+
"lat = lat_grid.ravel()\n",
181+
"z = np.full(lon.size, 50.0) # release at 50 m depth\n",
182+
"\n",
183+
"pset = parcels.ParticleSet(\n",
184+
" fieldset=fieldset,\n",
185+
" pclass=parcels.Particle,\n",
186+
" lon=lon,\n",
187+
" lat=lat,\n",
188+
" z=z,\n",
189+
")\n",
190+
"\n",
191+
"output_file = parcels.ParticleFile(\n",
192+
" \"output-fesom.parquet\", outputdt=np.timedelta64(1, \"h\")\n",
193+
")\n",
194+
"\n",
195+
"pset.execute(\n",
196+
" [parcels.kernels.AdvectionRK4],\n",
197+
" runtime=np.timedelta64(2, \"D\"),\n",
198+
" dt=np.timedelta64(5, \"m\"),\n",
199+
" output_file=output_file,\n",
200+
" verbose_progress=False,\n",
201+
")"
202+
]
159203
},
160204
{
161205
"cell_type": "markdown",
@@ -167,7 +211,70 @@
167211
"execution_count": null,
168212
"metadata": {},
169213
"outputs": [],
170-
"source": "df = parcels.read_particlefile(\"output-fesom.parquet\")\n\ntriang = mtri.Triangulation(\n ds.uxgrid.node_lon.values,\n ds.uxgrid.node_lat.values,\n triangles=ds.uxgrid.face_node_connectivity.values,\n)\n\ndepth_idx = int(np.argmin(np.abs(ds.zc.values - 50.0)))\nU_face = np.asarray(ds[\"U\"].isel(zc=depth_idx)).squeeze()\nV_face = np.asarray(ds[\"V\"].isel(zc=depth_idx)).squeeze()\nspeed = np.hypot(U_face, V_face)\n\nfig, ax = plt.subplots(figsize=(11, 5))\n\n# Background: speed at the release depth.\ntpc = ax.tripcolor(triang, facecolors=speed, shading=\"flat\", cmap=\"Blues\")\nfig.colorbar(tpc, ax=ax, label=\"speed [m/s]\", location=\"left\", shrink=0.85)\n\n# Velocity arrows at face centres. Drawing in lon/lat space (angles/scale_units\n# \"xy\") keeps the arrows aligned with the trajectories; length tracks speed.\nstep = max(1, U_face.size // 400)\nxf = ds.uxgrid.face_lon.values\nyf = ds.uxgrid.face_lat.values\nmax_speed = float(np.nanmax(speed))\nq = ax.quiver(\n xf[::step], yf[::step], U_face[::step], V_face[::step],\n angles=\"xy\", scale_units=\"xy\", scale=max_speed / 0.3,\n color=\"k\", width=0.0018, pivot=\"tail\",\n)\nax.quiverkey(q, 0.86, 1.04, max_speed, f\"{max_speed:.2f} m/s\", labelpos=\"E\", coordinates=\"axes\")\n\n# Particle paths (grey lines) and positions coloured by time.\nfor traj in df.sort(\"time\").partition_by(\"particle_id\"):\n ax.plot(traj[\"lon\"], traj[\"lat\"], color=\"0.4\", linewidth=0.6, alpha=0.7, zorder=2)\nax.scatter(lon, lat, facecolors=\"none\", edgecolors=\"k\", s=60, label=\"release\", zorder=3)\nsc = ax.scatter(\n df[\"lon\"], df[\"lat\"], c=df[\"time\"].dt.total_seconds(), s=6, cmap=\"viridis\", zorder=3,\n)\nfig.colorbar(sc, ax=ax, label=\"time since release [s]\", shrink=0.85)\n\nax.set_xlabel(\"Longitude [deg E]\")\nax.set_ylabel(\"Latitude [deg N]\")\nax.set_title(f\"FESOM2 velocity at z ≈ {float(ds.zc.values[depth_idx]):.1f} m with particle trajectories\")\nax.legend(loc=\"upper right\")\nplt.show()"
214+
"source": [
215+
"df = parcels.read_particlefile(\"output-fesom.parquet\")\n",
216+
"\n",
217+
"triang = mtri.Triangulation(\n",
218+
" ds.uxgrid.node_lon.values,\n",
219+
" ds.uxgrid.node_lat.values,\n",
220+
" triangles=ds.uxgrid.face_node_connectivity.values,\n",
221+
")\n",
222+
"\n",
223+
"depth_idx = int(np.argmin(np.abs(ds.zc.values - 50.0)))\n",
224+
"U_face = np.asarray(ds[\"U\"].isel(zc=depth_idx)).squeeze()\n",
225+
"V_face = np.asarray(ds[\"V\"].isel(zc=depth_idx)).squeeze()\n",
226+
"speed = np.hypot(U_face, V_face)\n",
227+
"\n",
228+
"fig, ax = plt.subplots(figsize=(11, 5))\n",
229+
"\n",
230+
"# Background: speed at the release depth.\n",
231+
"tpc = ax.tripcolor(triang, facecolors=speed, shading=\"flat\", cmap=\"Blues\")\n",
232+
"fig.colorbar(tpc, ax=ax, label=\"speed [m/s]\", location=\"left\", shrink=0.85)\n",
233+
"\n",
234+
"# Velocity arrows at face centres. Drawing in lon/lat space (angles/scale_units\n",
235+
"# \"xy\") keeps the arrows aligned with the trajectories; length tracks speed.\n",
236+
"step = max(1, U_face.size // 400)\n",
237+
"xf = ds.uxgrid.face_lon.values\n",
238+
"yf = ds.uxgrid.face_lat.values\n",
239+
"max_speed = float(np.nanmax(speed))\n",
240+
"q = ax.quiver(\n",
241+
" xf[::step],\n",
242+
" yf[::step],\n",
243+
" U_face[::step],\n",
244+
" V_face[::step],\n",
245+
" angles=\"xy\",\n",
246+
" scale_units=\"xy\",\n",
247+
" scale=max_speed / 0.3,\n",
248+
" color=\"k\",\n",
249+
" width=0.0018,\n",
250+
" pivot=\"tail\",\n",
251+
")\n",
252+
"ax.quiverkey(\n",
253+
" q, 0.86, 1.04, max_speed, f\"{max_speed:.2f} m/s\", labelpos=\"E\", coordinates=\"axes\"\n",
254+
")\n",
255+
"\n",
256+
"# Particle paths (grey lines) and positions coloured by time.\n",
257+
"for traj in df.sort(\"time\").partition_by(\"particle_id\"):\n",
258+
" ax.plot(traj[\"lon\"], traj[\"lat\"], color=\"0.4\", linewidth=0.6, alpha=0.7, zorder=2)\n",
259+
"ax.scatter(lon, lat, facecolors=\"none\", edgecolors=\"k\", s=60, label=\"release\", zorder=3)\n",
260+
"sc = ax.scatter(\n",
261+
" df[\"lon\"],\n",
262+
" df[\"lat\"],\n",
263+
" c=df[\"time\"].dt.total_seconds(),\n",
264+
" s=6,\n",
265+
" cmap=\"viridis\",\n",
266+
" zorder=3,\n",
267+
")\n",
268+
"fig.colorbar(sc, ax=ax, label=\"time since release [s]\", shrink=0.85)\n",
269+
"\n",
270+
"ax.set_xlabel(\"Longitude [deg E]\")\n",
271+
"ax.set_ylabel(\"Latitude [deg N]\")\n",
272+
"ax.set_title(\n",
273+
" f\"FESOM2 velocity at z ≈ {float(ds.zc.values[depth_idx]):.1f} m with particle trajectories\"\n",
274+
")\n",
275+
"ax.legend(loc=\"upper right\")\n",
276+
"plt.show()"
277+
]
171278
},
172279
{
173280
"cell_type": "markdown",
@@ -198,4 +305,4 @@
198305
},
199306
"nbformat": 4,
200307
"nbformat_minor": 4
201-
}
308+
}

0 commit comments

Comments
 (0)