diff --git a/docs/user_guide/examples/tutorial_manipulating_field_data.ipynb b/docs/user_guide/examples/tutorial_manipulating_field_data.ipynb index c023e68e8..5b0c8a869 100644 --- a/docs/user_guide/examples/tutorial_manipulating_field_data.ipynb +++ b/docs/user_guide/examples/tutorial_manipulating_field_data.ipynb @@ -13,13 +13,121 @@ "id": "1", "metadata": {}, "source": [ - "Because Parcels `Field` objects are built on top of `xarray` DataArrays, you can leverage the powerful data manipulation capabilities of `xarray` to preprocess or modify your field data before using it in particle simulations. This tutorial provides some examples of how to leverage that power." + "Because Parcels `Field` objects are built on top of `xarray` DataArrays, you can leverage the powerful data manipulation capabilities of `xarray` to preprocess or modify your field data before using it in particle simulations. This tutorial provides some common examples of how to leverage that power - however we highly recommend also reading the Xarray documentation!\n", + "\n", + "Let's start with some imports." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "2", "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import xarray as xr\n", + "\n", + "import parcels\n", + "import parcels.tutorial" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "## Looping field data and overriding the time dimension\n", + "\n", + "Sometimes we want to loop field data (e.g., use one year of data again ten times), or we want to completely override the time dimension.\n", + "\n", + "In previous versions of Parcels (pre version 4) this was done via Parcels function parameters `timestamps` and `time_periodic`. In this version of Parcels, we simply just manipulate the Xarray objects directly before passing the objects to Parcels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "ds_fields = parcels.tutorial.open_dataset(\n", + " \"CopernicusMarine_data_for_Argo_tutorial/data\"\n", + ")\n", + "ds_fields" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "Here we're dealing with daily data for from 2024-01-01 to 2024-02-01 (32 observations in total).\n", + "\n", + "Let's loop this data for a total of 90 days." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "N_TIME = ds_fields.time.size\n", + "N_TIME_TARGET = 90\n", + "\n", + "time_indices = np.arange(N_TIME_TARGET) % N_TIME\n", + "new_time_coordinate = np.arange(\n", + " np.datetime64(\"2000-01-01\"),\n", + " np.datetime64(\"2000-01-01\") + N_TIME_TARGET * np.timedelta64(1, \"D\"),\n", + " np.timedelta64(1, \"D\"),\n", + ").astype(\"datetime64[ns]\")\n", + "print(time_indices)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7", + "metadata": {}, + "outputs": [], + "source": [ + "ds_periodic = ds_fields.isel(time=time_indices)\n", + "ds_periodic[\"time\"] = new_time_coordinate\n", + "\n", + "# Now we have our periodic Dataset, let's take a look at the U velocity at a given position\n", + "# to verify\n", + "ds_periodic[\"uo\"].isel(depth=0, latitude=0, longitude=0).plot()" + ] + }, + { + "cell_type": "markdown", + "id": "8", + "metadata": {}, + "source": [ + "From this example, its easy to see how we can completely override the time dimension. For example, by adding a linear offset to the coordinates to make the data for February (and the first few days of March)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9", + "metadata": {}, + "outputs": [], + "source": [ + "new_time_coordinate = ds_fields.time.values + np.timedelta64(31, \"D\")\n", + "\n", + "ds_offset = ds_fields.copy()\n", + "ds_offset[\"time\"] = new_time_coordinate\n", + "ds_offset" + ] + }, + { + "cell_type": "markdown", + "id": "10", + "metadata": {}, "source": [ "## Summing Fields\n", "In some applications, you may want to sum multiple fields together to create a combined effect on particle movement. For example, you might want to combine ocean currents with wind-driven surface drift. This tutorial demonstrates how to sum multiple fields in Parcels and visualize the resulting particle trajectories.\n", @@ -34,17 +142,10 @@ { "cell_type": "code", "execution_count": null, - "id": "3", + "id": "11", "metadata": {}, "outputs": [], "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import xarray as xr\n", - "\n", - "import parcels\n", - "import parcels.tutorial\n", - "\n", "# Load the CopernicusMarine data in the Agulhas region from the example_datasets\n", "ds_fields = parcels.tutorial.open_dataset(\n", " \"CopernicusMarine_data_for_Argo_tutorial/data\"\n", @@ -67,7 +168,7 @@ }, { "cell_type": "markdown", - "id": "4", + "id": "12", "metadata": {}, "source": [ "Now here comes the trick: we can simply sum the fields together using `xarray` operations" @@ -76,7 +177,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -87,7 +188,7 @@ }, { "cell_type": "markdown", - "id": "6", + "id": "14", "metadata": {}, "source": [ "```{note}\n", @@ -97,7 +198,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "15", "metadata": {}, "source": [ "We can then run the same simulation as in the [Kernel loop explanation tutorial](explanation_kernelloop.md), but now using the combined fields. We only need the default advection kernel now, since the effects of both currents and winds are already included in the summed fields." @@ -106,7 +207,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "16", "metadata": { "tags": [ "hide-output" @@ -143,7 +244,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "17", "metadata": {}, "source": [ "We can then plot the trajectories, and confirm that they particles move the same as in the [Kernel loop explanation tutorial](explanation_kernelloop.md), where we combined the effects of currents and winds using two separate kernels." @@ -152,7 +253,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -167,7 +268,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Parcels:test (3.14.6)", + "display_name": "docs", "language": "python", "name": "python3" }, diff --git a/docs/user_guide/v4-migration.md b/docs/user_guide/v4-migration.md index ac4e687d2..358a00356 100644 --- a/docs/user_guide/v4-migration.md +++ b/docs/user_guide/v4-migration.md @@ -227,6 +227,14 @@ Use Particle.add_variables(), which also takes a list of Vari
+
+Parameters indices, timestamps, and time_periodic removed from FieldSet constructors. +
+
+Simply manipulate the datasets with Xarray to the same effect before passing them to Parcels. +
+
+ ## ParticleSet