Skip to content

Commit 2082b12

Browse files
Merge branch 'v4-dev' into reference-api-v4
2 parents c233a50 + 6442f06 commit 2082b12

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1481
-1801
lines changed

docs/_static/concepts_diagram.png

489 KB
Loading

docs/community/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ Are you interested in advanced analysis and diagnostics of Parcels output or Lag
9696
9797
+++
9898
99-
```{button-link} https://github.com/Parcels-code/Lagrangian_diags
99+
```{button-link} https://lagrangian-diags.readthedocs.io/en/latest/
100100
:click-parent:
101101
:color: secondary
102102
:expand:

docs/getting_started/concepts_overview.md

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
file_format: mystnb
3+
kernelspec:
4+
name: python3
5+
---
6+
7+
# 📖 Parcels conceptual workflow
8+
9+
Parcels is a set of Python classes and methods to create customisable particle tracking simulations using gridded output from (ocean) circulation models.
10+
11+
Here, we will explain the most important classes and functions. This overview can be useful to start understanding the different components we use in Parcels, and to structure the code in a simulation script.
12+
13+
A Parcels simulation is generally built up from four different components:
14+
15+
1. [**FieldSet**](#1-fieldset). The input dataset of gridded fields (e.g. ocean current velocity, temperature) in which virtual particles are defined.
16+
2. [**ParticleSet**](#2-particleset). The dataset of virtual particles. These always contain time, z, lat, and lon, for which initial values must be defined. The ParticleSet may also contain other, custom variables.
17+
3. [**Kernels**](#3-kernels). Kernels perform some specific operation on the particles every time step (e.g. advect the particles with the three-dimensional flow; or interpolate the temperature field to the particle location).
18+
4. [**Execute**](#4-execute). Execute the simulation. The core method which integrates the operations defined in Kernels for a given runtime and timestep, and writes output to a ParticleFile.
19+
20+
We discuss each component in more detail below. The subsections titled **"Learn how to"** link to more detailed [how-to guide notebooks](../user_guide/index.md) and more detailed _explanations_ of Parcels functionality are included under **"Read more about"** subsections. The full list of classes and methods is in the [API reference](../reference.md). If you want to learn by doing, check out the [quickstart tutorial](./tutorial_quickstart.md) to start creating your first Parcels simulation.
21+
22+
```{figure} ../_static/concepts_diagram.png
23+
:alt: Parcels concepts diagram
24+
:width: 100%
25+
26+
Parcels concepts diagram with key classes in blue boxes
27+
```
28+
29+
## 1. FieldSet
30+
31+
Parcels provides a framework to simulate particles **within a set of fields**, such as flow velocities and temperature. To start a parcels simulation we must define this dataset with the **`parcels.FieldSet`** class.
32+
33+
The input dataset from which to create a `parcels.FieldSet` can be an [`xarray.Dataset`](https://docs.xarray.dev/en/stable/user-guide/data-structures.html#dataset) with output from a hydrodynamic model or reanalysis. Such a dataset usually contains a number of gridded variables (e.g. `"U"`), which in Parcels become `parcels.Field` objects. A list of `parcels.Field` objects is stored in a `parcels.FieldSet` in an analoguous way to how `xarray.DataArray` objects combine to make an `xarray.Dataset`.
34+
35+
For several common input datasets, such as the Copernicus Marine Service analysis products, Parcels has a specific method to read and parse the data correctly:
36+
37+
```python
38+
dataset = xr.open_mfdataset("insert_copernicus_data_files.nc")
39+
fieldset = parcels.FieldSet.from_copernicusmarine(dataset)
40+
```
41+
42+
In some cases, we might want to combine `parcels.Field`s from different sources in the same `parcels.FieldSet`, such as ocean currents from one dataset and Stokes drift from another. This is possible in Parcels by adding each `parcels.Field` separately:
43+
44+
```python
45+
dataset1 = xr.dataset("insert_current_data_files.nc")
46+
dataset2 = xr.dataset("insert_stokes_data_files.nc")
47+
48+
Ucurrent = parcels.Field(name="Ucurrent", data=dataset1["Ucurrent"], grid=parcels.XGrid.from_dataset(dataset1), interp_method=parcels.interpolators.XLinear)
49+
Ustokes = parcels.Field(name="Ustokes", data=dataset2["Ustokes"], grid=parcels.XGrid.from_dataset(dataset2), interp_method=parcels.interpolators.XLinear)
50+
51+
fieldset = parcels.FieldSet([Ucurrent, Ustokes])
52+
```
53+
54+
### Grid
55+
56+
Each `parcels.Field` is defined on a grid. With Parcels, we can simulate particles in fields on both structured (**`parcels.XGrid`**) and unstructured (**`parcels.UxGrid`**) grids. The grid is defined by the coordinates of grid cell nodes, edges, and faces. `parcels.XGrid` objects are based on [`xgcm.Grid`](https://xgcm.readthedocs.io/en/latest/grids.html), while `parcels.UxGrid` objects are based on [`uxarray.Grid`](https://uxarray.readthedocs.io/en/stable/generated/uxarray.Grid.html#uxarray.Grid) objects.
57+
58+
```{admonition} 📖 Read more about grids
59+
:class: seealso
60+
- [Grids explanation](../user_guide/examples/explanation_grids.md)
61+
```
62+
63+
### Interpolation
64+
65+
To find the value of a `parcels.Field` at any particle location, Parcels interpolates the gridded field. Depending on the variable, grid, and required accuracy, different interpolation methods may be appropriate. Parcels comes with a number of built-in **`parcels.interpolators`**.
66+
67+
```{admonition} 📖 Read more about interpolation
68+
:class: seealso
69+
- [Interpolation explanation](../user_guide/examples/explanation_interpolation.md)
70+
```
71+
72+
```{admonition} 🖥️ Learn how to use Parcels interpolators
73+
:class: seealso
74+
- [Interpolators guide](../user_guide/examples/tutorial_interpolation.ipynb)
75+
```
76+
77+
## 2. ParticleSet
78+
79+
Once the environment has a `parcels.FieldSet` object, you can start defining your particles in a **`parcels.ParticleSet`** object. This object requires:
80+
81+
1. The `parcels.FieldSet` object in which the particles will be released.
82+
2. The type of `parcels.Particle`: A default `Particle` or a custom `Particle`-type with additional `Variable`s (see the [custom kernel example](custom-kernel)).
83+
3. Initial conditions for each `Variable` defined in the `Particle`, most notably the release coordinates of `time`, `z`, `lat` and `lon`.
84+
85+
```python
86+
time = np.array([0])
87+
z = np.array([0])
88+
lat = np.array([0])
89+
lon = np.array([0])
90+
91+
# Create a ParticleSet
92+
pset = parcels.ParticleSet(fieldset=fieldset, pclass=parcels.Particle, time=time, z=z, lat=lat, lon=lon)
93+
```
94+
95+
```{admonition} 🖥️ Learn more about how to create ParticleSets
96+
:class: seealso
97+
- [Release particles at different times](../user_guide/examples/tutorial_delaystart.ipynb)
98+
```
99+
100+
## 3. Kernels
101+
102+
A **`parcels.Kernel`** object is a little snippet of code, which is applied to the particles in the `ParticleSet`, for every time step during a simulation. Kernels define the computation or numerical integration done by Parcels, and can represent many processes such as advection, ageing, growth, or simply the sampling of a field.
103+
104+
Advection of a particle by the flow, the change in position $\mathbf{x}(t) = (lon(t), lat(t))$ at time $t$, can be described by the equation:
105+
106+
$$
107+
\begin{aligned}
108+
\frac{\text{d}\mathbf{x}(t)}{\text{d}t} = \mathbf{v}(\mathbf{x}(t),t),
109+
\end{aligned}
110+
$$
111+
112+
where $\mathbf{v}(\mathbf{x},t) = (u(\mathbf{x},t), v(\mathbf{x},t))$ describes the ocean velocity field at position $\mathbf{x}$ at time $t$.
113+
114+
In Parcels, we can write a kernel function which integrates this equation at each timestep `particles.dt`. To do so, we need the ocean velocity field `fieldset.UV` at the `particles` location, and compute the change in position, `particles.dlon` and `particles.dlat`.
115+
116+
```python
117+
def AdvectionEE(particles, fieldset):
118+
"""Advection of particles using Explicit Euler (aka Euler Forward) integration."""
119+
(u1, v1) = fieldset.UV[particles]
120+
particles.dlon += u1 * particles.dt
121+
particles.dlat += v1 * particles.dt
122+
```
123+
124+
Basic kernels are included in Parcels to compute advection and diffusion. The standard advection kernel is `parcels.kernels.AdvectionRK2`, a [second-order Runge-Kutta integrator](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods#The_Runge%E2%80%93Kutta_method) of the advection function.
125+
126+
```{warning}
127+
It is advised _not_ to update the particle coordinates (`particles.time`, `particles.z`, `particles.lat`, or `particles.lon`) directly within a Kernel, as that can negatively interfere with the way that particle movements by different kernels are vectorially added. Use a change in the coordinates: `particles.dlon`, `particles.dlat` and/or `particles.dz`. Read the [kernel loop tutorial](https://docs.oceanparcels.org/en/latest/examples/tutorial_kernelloop.html) to understand why.
128+
```
129+
130+
(custom-kernel)=
131+
We can write custom kernels to add many different types of 'behaviour' to the particles. To do so, we write a function with two arguments: `particles` and `fieldset`. We can then write any computation as a function of any variables defined in the `Particle` and any `Field` defined in the `FieldSet`. Kernels can then be combined by creating a `list` of the kernels. The kernels are executed in order:
132+
133+
```python
134+
# Create a custom Particle object with an "age" variable
135+
CustomParticle = parcels.Particle.add_variable(
136+
parcels.Variable("age", initial=0)
137+
)
138+
139+
# Create a custom kernel which keeps track of the particle age
140+
def Age(particles, fieldset):
141+
particles.age += particles.dt
142+
143+
# define all kernels to be executed on particles using an (ordered) list
144+
kernels = [Age, parcels.kernels.AdvectionRK4]
145+
```
146+
147+
```{note}
148+
Every Kernel must be a function with the following (and only those) arguments: `(particles, fieldset)`
149+
```
150+
151+
```{warning}
152+
We have to be careful with writing kernels for vector fields on Curvilinear grids. While Parcels automatically rotates the "U" and "V" field when necessary, this is not the case for other fields such as Stokes drift. [This guide](../user_guide/examples/tutorial_nemo_curvilinear.ipynb) describes how to use a curvilinear grid in Parcels.
153+
```
154+
155+
```{admonition} 📖 Read more about the Kernel loop
156+
:class: seealso
157+
- [The Kernel loop](../user_guide/examples/explanation_kernelloop.md)
158+
```
159+
160+
```{admonition} 🖥️ Learn how to write kernels
161+
:class: seealso
162+
- [Sample fields like temperature](../user_guide/examples/tutorial_sampling.ipynb).
163+
- [Mimic the behaviour of ARGO floats](../user_guide/examples/tutorial_Argofloats.ipynb).
164+
- [Add diffusion to approximate subgrid-scale processes and unresolved physics](../user_guide/examples/tutorial_diffusion.ipynb).
165+
- [Convert between units in m/s and degrees](../user_guide/examples/tutorial_unitconverters.ipynb).
166+
```
167+
168+
## 4. Execute
169+
170+
The execution of the simulation is done using the method **`parcels.ParticleSet.execute()`**, given the `FieldSet`, `ParticleSet`, and `Kernels` defined in the previous steps. This method requires the following arguments:
171+
172+
1. The kernels to be executed.
173+
2. The `runtime` defining how long the execution loop runs. Alternatively, you may define the `endtime` at which the execution loop stops.
174+
3. The timestep `dt` at which to execute the kernels.
175+
4. (Optional) The `ParticleFile` object to write the output to.
176+
177+
```python
178+
dt = np.timedelta64(5, "m")
179+
runtime = np.timedelta64(1, "D")
180+
181+
# Run the simulation
182+
pset.execute(pyfunc=kernels, dt=dt, runtime=runtime)
183+
```
184+
185+
### Output
186+
187+
To analyse the particle data generated in the simulation, we need to define a `parcels.ParticleFile` and add it as an argument to `parcels.ParticleSet.execute()`. The output will be written in a [zarr format](https://zarr.readthedocs.io/en/stable/), which can be opened as an `xarray.Dataset`. The dataset will contain the particle data with at least `time`, `z`, `lat` and `lon`, for each particle at timesteps defined by the `outputdt` argument.
188+
189+
There are many ways to analyze particle output, and although we provide [a short tutorial to get started](./tutorial_output.ipynb), we recommend writing your own analysis code and checking out other projects such as [trajan](https://opendrift.github.io/trajan/index.html) and [Lagrangian Diagnostics](https://lagrangian-diags.readthedocs.io/en/latest/).
190+
191+
```{admonition} 🖥️ Learn how to run a simulation
192+
:class: seealso
193+
- [Choose an appropriate timestep and integrator](../user_guide/examples/tutorial_numerical_accuracy.ipynb)
194+
- [Work with Parcels output](./tutorial_output.ipynb)
195+
```

docs/getting_started/index.md

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,12 @@ Getting started with parcels is easy; here you will find:
44

55
```{toctree}
66
:maxdepth: 1
7-
Installation guide <installation.md>
8-
Quickstart tutorial <tutorial_quickstart.md>
9-
Parcels concepts explainer <concepts_overview.md>
10-
Simple output tutorial <tutorial_output.ipynb>
11-
12-
```
13-
14-
```{note}
15-
TODO: Add links to Reference API in quickstart tutorial
7+
📦 Installation guide <installation.md>
8+
🎓 Quickstart tutorial <tutorial_quickstart.md>
9+
🎓 Output tutorial <tutorial_output.ipynb>
10+
📖 Conceptual workflow <explanation_concepts.md>
1611
```
1712

1813
```{note}
19-
TODO: Rewrite parcels concepts overview. This .md file should contain most of what is currently in the tutorial_parcels_structure notebook.
14+
TODO: Add links to Reference API in quickstart tutorial and concepts explanation
2015
```

docs/getting_started/installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Installation guide
1+
# 📦 Installation guide
22

33
## Basic Installation
44

docs/getting_started/tutorial_output.ipynb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"cell_type": "markdown",
66
"metadata": {},
77
"source": [
8-
"# Working with Parcels output\n"
8+
"# 🎓 Working with Parcels output"
99
]
1010
},
1111
{
@@ -124,6 +124,15 @@
124124
")"
125125
]
126126
},
127+
{
128+
"cell_type": "markdown",
129+
"metadata": {},
130+
"source": [
131+
"```{note}\n",
132+
"TODO: add section on chunking\n",
133+
"```"
134+
]
135+
},
127136
{
128137
"attachments": {},
129138
"cell_type": "markdown",

docs/getting_started/tutorial_quickstart.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ kernelspec:
44
name: python3
55
---
66

7-
# Quickstart tutorial
7+
# 🎓 Quickstart tutorial
88

99
Welcome to the **Parcels** quickstart tutorial, in which we will go through all the necessary steps to run a simulation.
1010
The code in this notebook can be used as a starting point to run Parcels in your own environment. Along the way we will
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# 📖 Grids
2+
3+
Parcels `Field` objects exist on a (structured) `parcels.XGrid` or (unstructured) `parcels.Uxgrid`. Here we describe these grids on a conceptual level.
4+
5+
```{note}
6+
The contents for this page are still under development in v4.
7+
TODO
8+
- link to xgcm.Grid documentation
9+
- adapt from v3 grid indexing tutorial (../examples_v3/documentation_indexing.ipynb)
10+
```

docs/user_guide/examples/explanation_interpolation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Interpolator explanation
1+
# 📖 Interpolators Overview and API
22

33
Interpolation is an important functionality of Parcels. On this page we will discuss the way it is
44
implemented in **Parcels** and how to write a custom interpolator function.

0 commit comments

Comments
 (0)