Skip to content

Commit bf6e4c6

Browse files
Adding Particle Advection to nesting tutorial
1 parent 28e4254 commit bf6e4c6

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

docs/examples/documentation_nesting.ipynb

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,114 @@
357357
"plt.tight_layout()\n",
358358
"plt.show()"
359359
]
360+
},
361+
{
362+
"cell_type": "markdown",
363+
"id": "19",
364+
"metadata": {},
365+
"source": [
366+
"## Advecting particles with nest transitions\n",
367+
"\n",
368+
"We can now set up a particle advection simulation using the nested grids. We first combine all the Fields into a single FieldSet. \n",
369+
"\n",
370+
"We rename the individual Fields by appending the nest index to their names, so that we can easily identify which Field belongs to which nest. We also add the `NestID` Field to the FieldSet (note that Parcels v4 supports combining structured and unstructured Fields into one FieldSet, which is very convenient for this usecase)."
371+
]
372+
},
373+
{
374+
"cell_type": "code",
375+
"execution_count": null,
376+
"id": "20",
377+
"metadata": {},
378+
"outputs": [],
379+
"source": [
380+
"fields = [NestID]\n",
381+
"for i, ds in enumerate(ds_in.values()):\n",
382+
" # TODO : remove depth dimension when Parcels supports 2D copernicusmarine datasets\n",
383+
" ds = ds.assign_coords(depth=np.array([0]))\n",
384+
" ds[\"depth\"].attrs[\"axis\"] = \"Z\"\n",
385+
"\n",
386+
" fset = parcels.FieldSet.from_copernicusmarine(ds)\n",
387+
" for fld in fset.fields.values():\n",
388+
" fld.name = f\"{fld.name}{i}\"\n",
389+
" fields.append(fld)\n",
390+
"fieldset = parcels.FieldSet(fields)"
391+
]
392+
},
393+
{
394+
"cell_type": "markdown",
395+
"id": "21",
396+
"metadata": {},
397+
"source": [
398+
"We then define a custom Advection kernel that advects particles using the appropriate velocity Field based on the `NestID` at the particle's location. Note that for simplicity, we use Eulerian advection here, but in a real-world application you would typically use a higher-order scheme."
399+
]
400+
},
401+
{
402+
"cell_type": "code",
403+
"execution_count": null,
404+
"id": "22",
405+
"metadata": {},
406+
"outputs": [],
407+
"source": [
408+
"def AdvectEE_Nests(particles, fieldset):\n",
409+
" particles.nestID = fieldset.NestID[particles]\n",
410+
"\n",
411+
" # TODO because of KernelParticle bug (GH #2143), we need to copy lon/lat/time to local variables\n",
412+
" time = particles.time\n",
413+
" z = particles.z\n",
414+
" lat = particles.lat\n",
415+
" lon = particles.lon\n",
416+
" u = np.zeros_like(particles.lon)\n",
417+
" v = np.zeros_like(particles.lat)\n",
418+
"\n",
419+
" unique_ids = np.unique(particles.nestID)\n",
420+
" for nid in unique_ids:\n",
421+
" mask = particles.nestID == nid\n",
422+
" UVField = getattr(fieldset, f\"UV{nid}\")\n",
423+
" (u[mask], v[mask]) = UVField[time[mask], z[mask], lat[mask], lon[mask]]\n",
424+
"\n",
425+
" particles.dlon += u * particles.dt\n",
426+
" particles.dlat += v * particles.dt\n",
427+
"\n",
428+
"\n",
429+
"pset = parcels.ParticleSet(\n",
430+
" fieldset, pclass=NestParticle, lon=X.flatten(), lat=Y.flatten()\n",
431+
")\n",
432+
"ofile = parcels.ParticleFile(\"nest_particles.zarr\", outputdt=np.timedelta64(1, \"h\"))\n",
433+
"pset.execute(\n",
434+
" AdvectEE_Nests,\n",
435+
" runtime=np.timedelta64(24, \"h\"),\n",
436+
" dt=np.timedelta64(1, \"h\"),\n",
437+
" output_file=ofile,\n",
438+
")"
439+
]
440+
},
441+
{
442+
"cell_type": "markdown",
443+
"id": "23",
444+
"metadata": {},
445+
"source": [
446+
"And finally we plot the particles moving through the nested grids, confirming that they correctly transition between the nests based on their location."
447+
]
448+
},
449+
{
450+
"cell_type": "code",
451+
"execution_count": null,
452+
"id": "24",
453+
"metadata": {},
454+
"outputs": [],
455+
"source": [
456+
"fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n",
457+
"\n",
458+
"ds_out = xr.open_zarr(\"nest_particles.zarr\")\n",
459+
"\n",
460+
"cmap = plt.get_cmap(\"viridis\", 3)\n",
461+
"sc = ax.scatter(ds_out.lon, ds_out.lat, c=ds_out.nestID, s=4, cmap=cmap, vmin=0, vmax=2)\n",
462+
"\n",
463+
"cbar = plt.colorbar(sc, ticks=[0, 1, 2], ax=ax)\n",
464+
"cbar.set_label(\"Nest ID\")\n",
465+
"ax.set_title(\"Particle advection through nests\")\n",
466+
"plt.show()"
467+
]
360468
}
361469
],
362470
"metadata": {

0 commit comments

Comments
 (0)