Skip to content

Commit 1fd82a8

Browse files
Remove _constrain_dt_to_within_time_interval function (#2754)
* Removing the _constrain_dt_to_within_time_interval helper function As not needed anymore with recent kernel loop change This simplifies the Kernels and reverts #2378 * Using particles.dt directly in sigmagrids
1 parent eb0f6b9 commit 1fd82a8

2 files changed

Lines changed: 76 additions & 99 deletions

File tree

src/parcels/kernels/_advection.py

Lines changed: 63 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -17,76 +17,62 @@
1717
]
1818

1919

20-
def _constrain_dt_to_within_time_interval(time_interval, time, dt):
21-
"""Helper function to make sure dt does not go outside time_interval.
22-
23-
This is especially relevant for higher-order RK methods (RK2, RK4, RK45),
24-
which require interpolations at time + dt. If time is at the edges of the
25-
time_interval (typically the last integration step), such an operation would
26-
lead to an OutofTimeError.
27-
"""
28-
if time_interval:
29-
dt = np.where(time + dt <= time_interval.time_length_as_flt, dt, time_interval.time_length_as_flt - time)
30-
dt = np.where(time + dt >= 0, dt, time)
31-
return dt
32-
33-
3420
def AdvectionRK2(particles, fieldset): # pragma: no cover
3521
"""Advection of particles using second-order Runge-Kutta integration."""
36-
dt = _constrain_dt_to_within_time_interval(fieldset.time_interval, particles.t, particles.dt)
3722
(u1, v1) = fieldset.UV[particles]
38-
x1, y1 = (particles.x + u1 * 0.5 * dt, particles.y + v1 * 0.5 * dt)
39-
(u2, v2) = fieldset.UV[particles.t + 0.5 * dt, particles.z, y1, x1, particles]
40-
particles.dx += u2 * dt
41-
particles.dy += v2 * dt
23+
x1 = particles.x + u1 * 0.5 * particles.dt
24+
y1 = particles.y + v1 * 0.5 * particles.dt
25+
(u2, v2) = fieldset.UV[particles.t + 0.5 * particles.dt, particles.z, y1, x1, particles]
26+
particles.dx += u2 * particles.dt
27+
particles.dy += v2 * particles.dt
4228

4329

4430
def AdvectionRK2_3D(particles, fieldset): # pragma: no cover
4531
"""Advection of particles using second-order Runge-Kutta integration including vertical velocity."""
46-
dt = _constrain_dt_to_within_time_interval(fieldset.time_interval, particles.t, particles.dt)
4732
(u1, v1, w1) = fieldset.UVW[particles]
48-
x1 = particles.x + u1 * 0.5 * dt
49-
y1 = particles.y + v1 * 0.5 * dt
50-
z1 = particles.z + w1 * 0.5 * dt
51-
(u2, v2, w2) = fieldset.UVW[particles.t + 0.5 * dt, z1, y1, x1, particles]
52-
particles.dx += u2 * dt
53-
particles.dy += v2 * dt
54-
particles.dz += w2 * dt
33+
x1 = particles.x + u1 * 0.5 * particles.dt
34+
y1 = particles.y + v1 * 0.5 * particles.dt
35+
z1 = particles.z + w1 * 0.5 * particles.dt
36+
(u2, v2, w2) = fieldset.UVW[particles.t + 0.5 * particles.dt, z1, y1, x1, particles]
37+
particles.dx += u2 * particles.dt
38+
particles.dy += v2 * particles.dt
39+
particles.dz += w2 * particles.dt
5540

5641

5742
def AdvectionRK4(particles, fieldset): # pragma: no cover
5843
"""Advection of particles using fourth-order Runge-Kutta integration."""
59-
dt = _constrain_dt_to_within_time_interval(fieldset.time_interval, particles.t, particles.dt)
6044
(u1, v1) = fieldset.UV[particles]
61-
x1, y1 = (particles.x + u1 * 0.5 * dt, particles.y + v1 * 0.5 * dt)
62-
(u2, v2) = fieldset.UV[particles.t + 0.5 * dt, particles.z, y1, x1, particles]
63-
x2, y2 = (particles.x + u2 * 0.5 * dt, particles.y + v2 * 0.5 * dt)
64-
(u3, v3) = fieldset.UV[particles.t + 0.5 * dt, particles.z, y2, x2, particles]
65-
x3, y3 = (particles.x + u3 * dt, particles.y + v3 * dt)
66-
(u4, v4) = fieldset.UV[particles.t + dt, particles.z, y3, x3, particles]
67-
particles.dx += (u1 + 2 * u2 + 2 * u3 + u4) / 6.0 * dt
68-
particles.dy += (v1 + 2 * v2 + 2 * v3 + v4) / 6.0 * dt
45+
x1 = particles.x + u1 * 0.5 * particles.dt
46+
y1 = particles.y + v1 * 0.5 * particles.dt
47+
(u2, v2) = fieldset.UV[particles.t + 0.5 * particles.dt, particles.z, y1, x1, particles]
48+
x2 = particles.x + u2 * 0.5 * particles.dt
49+
y2 = particles.y + v2 * 0.5 * particles.dt
50+
(u3, v3) = fieldset.UV[particles.t + 0.5 * particles.dt, particles.z, y2, x2, particles]
51+
x3 = particles.x + u3 * particles.dt
52+
y3 = particles.y + v3 * particles.dt
53+
(u4, v4) = fieldset.UV[particles.t + particles.dt, particles.z, y3, x3, particles]
54+
particles.dx += (u1 + 2 * u2 + 2 * u3 + u4) / 6.0 * particles.dt
55+
particles.dy += (v1 + 2 * v2 + 2 * v3 + v4) / 6.0 * particles.dt
6956

7057

7158
def AdvectionRK4_3D(particles, fieldset): # pragma: no cover
7259
"""Advection of particles using fourth-order Runge-Kutta integration including vertical velocity."""
73-
dt = _constrain_dt_to_within_time_interval(fieldset.time_interval, particles.t, particles.dt)
7460
(u1, v1, w1) = fieldset.UVW[particles]
75-
x1 = particles.x + u1 * 0.5 * dt
76-
y1 = particles.y + v1 * 0.5 * dt
77-
z1 = particles.z + w1 * 0.5 * dt
78-
(u2, v2, w2) = fieldset.UVW[particles.t + 0.5 * dt, z1, y1, x1, particles]
79-
x2 = particles.x + u2 * 0.5 * dt
80-
y2 = particles.y + v2 * 0.5 * dt
81-
z2 = particles.z + w2 * 0.5 * dt
82-
(u3, v3, w3) = fieldset.UVW[particles.t + 0.5 * dt, z2, y2, x2, particles]
83-
x3 = particles.x + u3 * dt
84-
y3 = particles.y + v3 * dt
85-
z3 = particles.z + w3 * dt
86-
(u4, v4, w4) = fieldset.UVW[particles.t + dt, z3, y3, x3, particles]
87-
particles.dx += (u1 + 2 * u2 + 2 * u3 + u4) / 6 * dt
88-
particles.dy += (v1 + 2 * v2 + 2 * v3 + v4) / 6 * dt
89-
particles.dz += (w1 + 2 * w2 + 2 * w3 + w4) / 6 * dt
61+
x1 = particles.x + u1 * 0.5 * particles.dt
62+
y1 = particles.y + v1 * 0.5 * particles.dt
63+
z1 = particles.z + w1 * 0.5 * particles.dt
64+
(u2, v2, w2) = fieldset.UVW[particles.t + 0.5 * particles.dt, z1, y1, x1, particles]
65+
x2 = particles.x + u2 * 0.5 * particles.dt
66+
y2 = particles.y + v2 * 0.5 * particles.dt
67+
z2 = particles.z + w2 * 0.5 * particles.dt
68+
(u3, v3, w3) = fieldset.UVW[particles.t + 0.5 * particles.dt, z2, y2, x2, particles]
69+
x3 = particles.x + u3 * particles.dt
70+
y3 = particles.y + v3 * particles.dt
71+
z3 = particles.z + w3 * particles.dt
72+
(u4, v4, w4) = fieldset.UVW[particles.t + particles.dt, z3, y3, x3, particles]
73+
particles.dx += (u1 + 2 * u2 + 2 * u3 + u4) / 6 * particles.dt
74+
particles.dy += (v1 + 2 * v2 + 2 * v3 + v4) / 6 * particles.dt
75+
particles.dz += (w1 + 2 * w2 + 2 * w3 + w4) / 6 * particles.dt
9076

9177

9278
def AdvectionEE(particles, fieldset): # pragma: no cover
@@ -105,8 +91,7 @@ def AdvectionRK45(particles, fieldset): # pragma: no cover
10591
Time-step dt is halved if error is larger than fieldset.RK45_tol,
10692
and doubled if error is smaller than 1/10th of tolerance.
10793
"""
108-
dt = _constrain_dt_to_within_time_interval(fieldset.time_interval, particles.t, particles.dt)
109-
sign_dt = np.sign(dt)
94+
sign_dt = np.sign(particles.dt)
11095

11196
c = [1.0 / 4.0, 3.0 / 8.0, 12.0 / 13.0, 1.0, 1.0 / 2.0]
11297
A = [
@@ -120,42 +105,37 @@ def AdvectionRK45(particles, fieldset): # pragma: no cover
120105
b5 = [16.0 / 135.0, 0.0, 6656.0 / 12825.0, 28561.0 / 56430.0, -9.0 / 50.0, 2.0 / 55.0]
121106

122107
(u1, v1) = fieldset.UV[particles]
123-
x1, y1 = (particles.x + u1 * A[0][0] * dt, particles.y + v1 * A[0][0] * dt)
124-
(u2, v2) = fieldset.UV[particles.t + c[0] * dt, particles.z, y1, x1, particles]
125-
x2, y2 = (
126-
particles.x + (u1 * A[1][0] + u2 * A[1][1]) * dt,
127-
particles.y + (v1 * A[1][0] + v2 * A[1][1]) * dt,
128-
)
129-
(u3, v3) = fieldset.UV[particles.t + c[1] * dt, particles.z, y2, x2, particles]
130-
x3, y3 = (
131-
particles.x + (u1 * A[2][0] + u2 * A[2][1] + u3 * A[2][2]) * dt,
132-
particles.y + (v1 * A[2][0] + v2 * A[2][1] + v3 * A[2][2]) * dt,
133-
)
134-
(u4, v4) = fieldset.UV[particles.t + c[2] * dt, particles.z, y3, x3, particles]
135-
x4, y4 = (
136-
particles.x + (u1 * A[3][0] + u2 * A[3][1] + u3 * A[3][2] + u4 * A[3][3]) * dt,
137-
particles.y + (v1 * A[3][0] + v2 * A[3][1] + v3 * A[3][2] + v4 * A[3][3]) * dt,
138-
)
139-
(u5, v5) = fieldset.UV[particles.t + c[3] * dt, particles.z, y4, x4, particles]
140-
x5, y5 = (
141-
particles.x + (u1 * A[4][0] + u2 * A[4][1] + u3 * A[4][2] + u4 * A[4][3] + u5 * A[4][4]) * dt,
142-
particles.y + (v1 * A[4][0] + v2 * A[4][1] + v3 * A[4][2] + v4 * A[4][3] + v5 * A[4][4]) * dt,
143-
)
144-
(u6, v6) = fieldset.UV[particles.t + c[4] * dt, particles.z, y5, x5, particles]
145-
146-
x_4th = (u1 * b4[0] + u2 * b4[1] + u3 * b4[2] + u4 * b4[3] + u5 * b4[4]) * dt
147-
y_4th = (v1 * b4[0] + v2 * b4[1] + v3 * b4[2] + v4 * b4[3] + v5 * b4[4]) * dt
148-
x_5th = (u1 * b5[0] + u2 * b5[1] + u3 * b5[2] + u4 * b5[3] + u5 * b5[4] + u6 * b5[5]) * dt
149-
y_5th = (v1 * b5[0] + v2 * b5[1] + v3 * b5[2] + v4 * b5[3] + v5 * b5[4] + v6 * b5[5]) * dt
108+
x1 = particles.x + u1 * A[0][0] * particles.dt
109+
y1 = particles.y + v1 * A[0][0] * particles.dt
110+
(u2, v2) = fieldset.UV[particles.t + c[0] * particles.dt, particles.z, y1, x1, particles]
111+
x2 = particles.x + (u1 * A[1][0] + u2 * A[1][1]) * particles.dt
112+
y2 = particles.y + (v1 * A[1][0] + v2 * A[1][1]) * particles.dt
113+
(u3, v3) = fieldset.UV[particles.t + c[1] * particles.dt, particles.z, y2, x2, particles]
114+
x3 = particles.x + (u1 * A[2][0] + u2 * A[2][1] + u3 * A[2][2]) * particles.dt
115+
y3 = particles.y + (v1 * A[2][0] + v2 * A[2][1] + v3 * A[2][2]) * particles.dt
116+
(u4, v4) = fieldset.UV[particles.t + c[2] * particles.dt, particles.z, y3, x3, particles]
117+
x4 = particles.x + (u1 * A[3][0] + u2 * A[3][1] + u3 * A[3][2] + u4 * A[3][3]) * particles.dt
118+
y4 = particles.y + (v1 * A[3][0] + v2 * A[3][1] + v3 * A[3][2] + v4 * A[3][3]) * particles.dt
119+
(u5, v5) = fieldset.UV[particles.t + c[3] * particles.dt, particles.z, y4, x4, particles]
120+
x5 = particles.x + (u1 * A[4][0] + u2 * A[4][1] + u3 * A[4][2] + u4 * A[4][3] + u5 * A[4][4]) * particles.dt
121+
y5 = particles.y + (v1 * A[4][0] + v2 * A[4][1] + v3 * A[4][2] + v4 * A[4][3] + v5 * A[4][4]) * particles.dt
122+
(u6, v6) = fieldset.UV[particles.t + c[4] * particles.dt, particles.z, y5, x5, particles]
123+
124+
x_4th = (u1 * b4[0] + u2 * b4[1] + u3 * b4[2] + u4 * b4[3] + u5 * b4[4]) * particles.dt
125+
y_4th = (v1 * b4[0] + v2 * b4[1] + v3 * b4[2] + v4 * b4[3] + v5 * b4[4]) * particles.dt
126+
x_5th = (u1 * b5[0] + u2 * b5[1] + u3 * b5[2] + u4 * b5[3] + u5 * b5[4] + u6 * b5[5]) * particles.dt
127+
y_5th = (v1 * b5[0] + v2 * b5[1] + v3 * b5[2] + v4 * b5[3] + v5 * b5[4] + v6 * b5[5]) * particles.dt
150128

151129
kappa = np.sqrt(np.pow(x_5th - x_4th, 2) + np.pow(y_5th - y_4th, 2))
152130

153-
good_particles = (kappa <= fieldset.RK45_tol) | (np.fabs(dt) <= np.fabs(fieldset.RK45_min_dt))
131+
good_particles = (kappa <= fieldset.RK45_tol) | (np.fabs(particles.dt) <= np.fabs(fieldset.RK45_min_dt))
154132
particles.dx += np.where(good_particles, x_5th, 0)
155133
particles.dy += np.where(good_particles, y_5th, 0)
156134

157135
increase_dt_particles = (
158-
good_particles & (kappa <= fieldset.RK45_tol / 10) & (np.fabs(dt * 2) <= np.fabs(fieldset.RK45_max_dt))
136+
good_particles
137+
& (kappa <= fieldset.RK45_tol / 10)
138+
& (np.fabs(particles.dt * 2) <= np.fabs(fieldset.RK45_max_dt))
159139
)
160140
particles.next_dt = np.where(increase_dt_particles, particles.dt * 2, particles.dt)
161141
particles.next_dt = np.where(

src/parcels/kernels/_sigmagrids.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import numpy as np
44

5-
from parcels.kernels._advection import _constrain_dt_to_within_time_interval
6-
75

86
def convert_z_to_sigma_croco(fieldset, t, z, y, x, particle):
97
"""Calculate local sigma level of the particles, by linearly interpolating the
@@ -49,27 +47,26 @@ def AdvectionRK2_3D_CROCO(particles, fieldset): # pragma: no cover
4947
category=RuntimeWarning,
5048
) # Needed because of linear sampling of W with sigma conversion
5149

52-
dt = _constrain_dt_to_within_time_interval(fieldset.time_interval, particles.t, particles.dt)
5350
sigma = particles.z / fieldset.h[particles.t, np.zeros_like(particles.z), particles.y, particles.x]
5451

5552
sig = convert_z_to_sigma_croco(fieldset, particles.t, particles.z, particles.y, particles.x, particles)
5653
(u1, v1) = fieldset.UV[particles.t, sig, particles.y, particles.x, particles]
5754
w1 = fieldset.W[particles.t, sig, particles.y, particles.x, particles]
5855
w1 *= sigma / fieldset.h[particles.t, np.zeros_like(particles.z), particles.y, particles.x]
59-
x1 = particles.x + u1 * 0.5 * dt
60-
y1 = particles.y + v1 * 0.5 * dt
61-
sig_dep1 = sigma + w1 * 0.5 * dt
56+
x1 = particles.x + u1 * 0.5 * particles.dt
57+
y1 = particles.y + v1 * 0.5 * particles.dt
58+
sig_dep1 = sigma + w1 * 0.5 * particles.dt
6259
dep1 = sig_dep1 * fieldset.h[particles.t, np.zeros_like(particles.z), y1, x1]
6360

64-
sig1 = convert_z_to_sigma_croco(fieldset, particles.t + 0.5 * dt, dep1, y1, x1, particles)
65-
(u2, v2) = fieldset.UV[particles.t + 0.5 * dt, sig1, y1, x1, particles]
66-
w2 = fieldset.W[particles.t + 0.5 * dt, sig1, y1, x1, particles]
67-
w2 *= sig_dep1 / fieldset.h[particles.t + 0.5 * dt, np.zeros_like(particles.z), y1, x1]
68-
x2 = particles.x + u2 * 0.5 * dt
69-
y2 = particles.y + v2 * 0.5 * dt
70-
sig_dep2 = sigma + w2 * 0.5 * dt
71-
dep2 = sig_dep2 * fieldset.h[particles.t + 0.5 * dt, np.zeros_like(particles.z), y2, x2]
61+
sig1 = convert_z_to_sigma_croco(fieldset, particles.t + 0.5 * particles.dt, dep1, y1, x1, particles)
62+
(u2, v2) = fieldset.UV[particles.t + 0.5 * particles.dt, sig1, y1, x1, particles]
63+
w2 = fieldset.W[particles.t + 0.5 * particles.dt, sig1, y1, x1, particles]
64+
w2 *= sig_dep1 / fieldset.h[particles.t + 0.5 * particles.dt, np.zeros_like(particles.z), y1, x1]
65+
x2 = particles.x + u2 * 0.5 * particles.dt
66+
y2 = particles.y + v2 * 0.5 * particles.dt
67+
sig_dep2 = sigma + w2 * 0.5 * particles.dt
68+
dep2 = sig_dep2 * fieldset.h[particles.t + 0.5 * particles.dt, np.zeros_like(particles.z), y2, x2]
7269

73-
particles.dx += u2 * dt
74-
particles.dy += v2 * dt
70+
particles.dx += u2 * particles.dt
71+
particles.dy += v2 * particles.dt
7572
particles.dz += (dep1 - particles.z) + (dep2 - particles.z)

0 commit comments

Comments
 (0)