Skip to content

Commit 83b4b3f

Browse files
reint-fischerreint-fischer
authored andcommitted
fix statuscodes boolean indexing and wording
1 parent f979f90 commit 83b4b3f

File tree

1 file changed

+26
-25
lines changed

1 file changed

+26
-25
lines changed

docs/user_guide/examples/explanation_kernelloop.md

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ kernelspec:
66

77
# The Parcels Kernel loop
88

9-
This tutorial explains how Parcels executes multiple Kernels, and what happens under the hood when you combine Kernels.
9+
On this page we discuss Parcels' execution loop, and what happens under the hood when you combine multiple Kernels.
1010

1111
This is probably not very relevant when you only use the built-in Advection kernels, but can be important when you are writing and combining your own Kernels!
1212

@@ -18,7 +18,7 @@ In order to make sure that the displacements of a particle in the different Kern
1818

1919
## Basic implementation
2020

21-
Below is a structured overview of the Kernel loop is implemented. Note that this is for `lon` only, but the same process is applied for `lat` and `z`.
21+
Below is a structured overview of how the Kernel loop is implemented. Note that this is for `time` and `lon` only, but the process for `lon` is also applied to `lat` and `z`.
2222

2323
1. Initialise an extra Variable `particles.dlon=0`
2424

@@ -38,9 +38,9 @@ Below is a structured overview of the Kernel loop is implemented. Note that this
3838

3939
Besides having commutable Kernels, the main advantage of this implementation is that, when using Field Sampling with e.g. `particles.temp = fieldset.Temp[particles.time, particles.z, particles.lat, particles.lon]`, the particle location stays the same throughout the entire Kernel loop. Additionally, this implementation ensures that the particle location is the same as the location of the sampled field in the output file.
4040

41-
## Example with multiple Kernels
41+
## Example with currents and winds
4242

43-
Below is a simple example of some particles at the surface of the ocean. We create an idealised zonal wind flow that will "push" a particle that is already affected by the surface currents. The Kernel loop ensures that these two forces act at the same time and location, as we will show.
43+
Below is a simple example of some particles at the surface of the ocean. We create an idealised zonal wind flow that will "push" a particle that is already affected by the surface currents. The Kernel loop ensures that these two forces act at the same time and location.
4444

4545
```{code-cell}
4646
import matplotlib.pyplot as plt
@@ -87,7 +87,7 @@ def wind_kernel(particles, fieldset):
8787
)
8888
```
8989

90-
Run a simulation where we apply first kernels as `[AdvectionRK4, wind_kernel]`
90+
First run a simulation where we apply kernels as `[AdvectionRK4, wind_kernel]`
9191

9292
```{code-cell}
9393
:tags: [hide-output]
@@ -98,29 +98,30 @@ lats = np.linspace(-32.5, -30.5, npart)
9898
9999
pset = parcels.ParticleSet(fieldset, pclass=parcels.Particle, z=z, lat=lats, lon=lons)
100100
output_file = parcels.ParticleFile(
101-
store="advection_then_wind.zarr", outputdt=timedelta(hours=6)
101+
store="advection_then_wind.zarr", outputdt=np.timedelta64(6,'h')
102102
)
103103
pset.execute(
104104
[parcels.kernels.AdvectionRK4, wind_kernel],
105-
runtime=timedelta(days=5),
106-
dt=timedelta(hours=1),
105+
runtime=np.timedelta64(5,'D'),
106+
dt=np.timedelta64(1,'h'),
107107
output_file=output_file,
108108
)
109109
```
110110

111-
And also run a simulation where we apply the kernels in the reverse order as `[wind_kernel, AdvectionRK4]`
111+
Then also run a simulation where we apply the kernels in the reverse order as `[wind_kernel, AdvectionRK4]`
112112

113113
```{code-cell}
114+
:tags: [hide-output]
114115
pset_reverse = parcels.ParticleSet(
115116
fieldset, pclass=parcels.Particle, z=z, lat=lats, lon=lons
116117
)
117118
output_file_reverse = parcels.ParticleFile(
118-
store="wind_then_advection.zarr", outputdt=timedelta(hours=6)
119+
store="wind_then_advection.zarr", outputdt=np.timedelta64(6,"h")
119120
)
120121
pset_reverse.execute(
121122
[wind_kernel, parcels.kernels.AdvectionRK4],
122-
runtime=timedelta(days=5),
123-
dt=timedelta(hours=1),
123+
runtime=np.timedelta64(5,"D"),
124+
dt=np.timedelta64(1,"h"),
124125
output_file=output_file_reverse,
125126
)
126127
```
@@ -160,34 +161,34 @@ Once an error is thrown (for example, a Field Interpolation error), then the `pa
160161
For example, you can write a Kernel that checks for `particles.state == StatusCode.ErrorOutOfBounds` and deletes the particle, and then append this to the Kernel list in `pset.execute()`.
161162

162163
```
163-
def CheckOutOfBounds(particles, fieldset):
164-
if particles.state == StatusCode.ErrorOutOfBounds:
165-
particles.delete()
164+
def DeleteOutOfBounds(particles, fieldset):
165+
out_of_bounds = particles.state == StatusCode.ErrorOutOfBounds
166+
particles[out_of_bounds].state = StatusCode.Delete
166167
167168
168-
def CheckError(particles, fieldset):
169-
if particles.state >= 50: # This captures all Errors
170-
particles.delete()
169+
def DeleteAnyError(particles, fieldset):
170+
any_error = particles.state >= 50 # This captures all Errors
171+
particles[any_error].state = StatusCode.Delete
171172
```
172173

173174
But of course, you can also write code for more sophisticated behaviour than just deleting the particle. It's up to you! Note that if you don't delete the particle, you will have to update the `particles.state = StatusCode.Success` yourself. For example:
174175

175176
```
176177
def Move1DegreeWest(particles, fieldset):
177-
if particles.state == StatusCode.ErrorOutOfBounds:
178-
particles.dlon -= 1.0
179-
particles.state = StatusCode.Success
178+
out_of_bounds = particles.state == StatusCode.ErrorOutOfBounds
179+
particles[out_of_bounds].dlon -= 1.0
180+
particles[out_of_bounds].state = StatusCode.Success
180181
```
181182

182183
Or, if you want to make sure that particles don't escape through the water surface
183184

184185
```
185186
def KeepInOcean(particles, fieldset):
186-
if particles.state == StatusCode.ErrorThroughSurface:
187-
particles.dz = 0.0
188-
particles.state = StatusCode.Success
187+
through_surface = particles.state == StatusCode.ErrorThroughSurface
188+
particles[through_surface].dz = 0.0
189+
particles[through_surface].state = StatusCode.Success
189190
```
190191

191192
Kernel functions such as the ones above can then be added to the list of kernels in `pset.execute()`.
192193

193-
Note that these Kernels that control what to do with `particles.state` should typically be added at the _end_ of the Kernel list, because otherwise later Kernels may overwrite the `particles.state` or the `particle_dlon` variables.
194+
Note that these Kernels that control what to do with `particles.state` should typically be added at the _end_ of the Kernel list, because otherwise later Kernels may overwrite the `particles.state` or the `particle.dlon` variables.

0 commit comments

Comments
 (0)