Skip to content

Commit bb5d0f4

Browse files
Vectorising Pull Kernel
Introducing Pull as normal Kernel (but not performance-optimised yet)
1 parent 56e3048 commit bb5d0f4

2 files changed

Lines changed: 24 additions & 38 deletions

File tree

docs/user_guide/examples_v3/tutorial_interaction.ipynb

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@
5858
"import xarray as xr\n",
5959
"from matplotlib.animation import FuncAnimation\n",
6060
"\n",
61-
"plt.rcParams[\"animation.html\"] = \"jshtml\"\n",
61+
"import parcels\n",
6262
"\n",
63-
"import parcels"
63+
"# for interactive display of animations\n",
64+
"plt.rcParams[\"animation.html\"] = \"jshtml\""
6465
]
6566
},
6667
{
@@ -73,43 +74,28 @@
7374
"def Pull(particles, fieldset):\n",
7475
" \"\"\"InterActionKernel that \"pulls\" all neighbor particles\n",
7576
" toward the attracting particle with a constant velocity\"\"\"\n",
76-
" distances = []\n",
77-
" na_neighbors = []\n",
78-
" # only execute kernel for particles that are 'attractor'\n",
79-
" if not particles.attractor:\n",
80-
" return StateCode.Success\n",
81-
" for n in neighbors:\n",
82-
" if n.attractor:\n",
83-
" continue\n",
84-
" x_p = np.array([particle.depth, particle.lat, particle.lon])\n",
85-
" x_n = np.array([n.depth, n.lat, n.lon])\n",
86-
"\n",
87-
" # compute distance between attracted and attracting particle\n",
88-
" distances.append(np.linalg.norm(x_p - x_n))\n",
89-
" na_neighbors.append(n)\n",
90-
"\n",
91-
" velocity = 0.04 # predefined attracting velocity\n",
92-
" for n in na_neighbors:\n",
93-
" assert n.dt == particle.dt\n",
94-
" dx = np.array(\n",
95-
" [particle.lat - n.lat, particle.lon - n.lon, particle.depth - n.depth]\n",
96-
" )\n",
97-
" dx_norm = np.linalg.norm(dx)\n",
77+
" interaction_distance = 0.5\n",
78+
" velocity = -0.04 # predefined attracting velocity\n",
9879
"\n",
99-
" # calculate vector of position change\n",
100-
" distance = velocity * n.dt\n",
101-
" d_vec = distance * dx / dx_norm\n",
80+
" lon_a = particles.lon[np.where(particles.attractor)[0]]\n",
81+
" dx = particles.lon - lon_a[:, None]\n",
82+
" lat_a = particles.lat[np.where(particles.attractor)[0]]\n",
83+
" dy = particles.lat - lat_a[:, None]\n",
10284
"\n",
103-
" # define mutation function for mutator\n",
104-
" def f(n, dlat, dlon, ddepth):\n",
105-
" n.lat_nextloop += (\n",
106-
" dlat # note that we need to change the locations for the next loop\n",
107-
" )\n",
108-
" n.lon_nextloop += dlon\n",
109-
" n.depth_nextloop += ddepth\n",
85+
" distances = np.sqrt(dx**2 + dy**2) # TODO use np.linalg.norm?\n",
86+
"\n",
87+
" dx = np.where(distances < interaction_distance, dx, 0.0)\n",
88+
" dy = np.where(distances < interaction_distance, dy, 0.0)\n",
89+
"\n",
90+
" dx_norm = np.where(distances > 0, dx / distances, 0)\n",
91+
" particles.dlon += (\n",
92+
" np.sum(dx_norm, axis=0) * velocity\n",
93+
" ) # * particles.dt / np.timedelta64(1, \"s\")\n",
11094
"\n",
111-
" # add mutation to the mutator\n",
112-
" mutator[n.id].append((f, d_vec))"
95+
" dy_norm = np.where(distances > 0, dy / distances, 0)\n",
96+
" particles.dlat += (\n",
97+
" np.sum(dy_norm, axis=0) * velocity\n",
98+
" ) # * particles.dt / np.timedelta64(1, \"s\")"
11399
]
114100
},
115101
{
@@ -163,7 +149,7 @@
163149
"\n",
164150
"kernels = [\n",
165151
" parcels.kernels.DiffusionUniformKh,\n",
166-
" # Pull, # Add the Pull kernel defined above\n",
152+
" Pull, # Add the Pull kernel defined above\n",
167153
"]\n",
168154
"\n",
169155
"pset.execute(\n",

src/parcels/_core/particleset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ def _active_particles_mask(self, time, dt):
261261
return active_indices
262262

263263
def _compute_neighbor_tree(self, time, dt):
264-
active_mask = self._active_particles_mask(time, dt)
264+
active_mask = self._active_particles_mask(time, dt) # TODO still needed with KernelParticles?
265265

266266
self._values = np.vstack(
267267
(

0 commit comments

Comments
 (0)