1818]
1919
2020
21+ def _adjust_RK_dt (time_interval , time , dt ):
22+ """Helper function to make sure dt does not go outside time_interval for RK methods"""
23+ if time_interval :
24+ dt = np .where (time + dt <= time_interval .right , dt , time_interval .right - time )
25+ dt = np .where (time + dt >= time_interval .left , dt , time - time_interval .left )
26+ return dt
27+
28+
2129def AdvectionRK2 (particles , fieldset ): # pragma: no cover
2230 """Advection of particles using second-order Runge-Kutta integration."""
31+ particles .dt = _adjust_RK_dt (fieldset .time_interval , particles .time , particles .dt )
2332 dt = particles .dt / np .timedelta64 (1 , "s" ) # TODO: improve API for converting dt to seconds
2433 (u1 , v1 ) = fieldset .UV [particles ]
2534 lon1 , lat1 = (particles .lon + u1 * 0.5 * dt , particles .lat + v1 * 0.5 * dt )
@@ -30,6 +39,7 @@ def AdvectionRK2(particles, fieldset): # pragma: no cover
3039
3140def AdvectionRK2_3D (particles , fieldset ): # pragma: no cover
3241 """Advection of particles using second-order Runge-Kutta integration including vertical velocity."""
42+ particles .dt = _adjust_RK_dt (fieldset .time_interval , particles .time , particles .dt )
3343 dt = particles .dt / np .timedelta64 (1 , "s" )
3444 (u1 , v1 , w1 ) = fieldset .UVW [particles ]
3545 lon1 = particles .lon + u1 * 0.5 * dt
@@ -43,32 +53,22 @@ def AdvectionRK2_3D(particles, fieldset): # pragma: no cover
4353
4454def AdvectionRK4 (particles , fieldset ): # pragma: no cover
4555 """Advection of particles using fourth-order Runge-Kutta integration."""
46-
47- def Update_locations (p ):
48- dt = p .dt / np .timedelta64 (1 , "s" ) # TODO: improve API for converting dt to seconds
49- (u1 , v1 ) = fieldset .UV [p ]
50- lon1 , lat1 = (p .lon + u1 * 0.5 * dt , p .lat + v1 * 0.5 * dt )
51- (u2 , v2 ) = fieldset .UV [p .time + 0.5 * p .dt , p .z , lat1 , lon1 , p ]
52- lon2 , lat2 = (p .lon + u2 * 0.5 * dt , p .lat + v2 * 0.5 * dt )
53- (u3 , v3 ) = fieldset .UV [p .time + 0.5 * p .dt , p .z , lat2 , lon2 , p ]
54- lon3 , lat3 = (p .lon + u3 * dt , p .lat + v3 * dt )
55- (u4 , v4 ) = fieldset .UV [p .time + p .dt , p .z , lat3 , lon3 , p ]
56- p .dlon += (u1 + 2 * u2 + 2 * u3 + u4 ) / 6.0 * dt
57- p .dlat += (v1 + 2 * v2 + 2 * v3 + v4 ) / 6.0 * dt
58-
59- if fieldset .time_interval is not None :
60- Update_locations (
61- particles [
62- (particles .time + particles .dt <= fieldset .time_interval .right )
63- & (particles .time + particles .dt >= fieldset .time_interval .left )
64- ]
65- )
66- else :
67- Update_locations (particles )
56+ particles .dt = _adjust_RK_dt (fieldset .time_interval , particles .time , particles .dt )
57+ dt = particles .dt / np .timedelta64 (1 , "s" ) # TODO: improve API for converting dt to seconds
58+ (u1 , v1 ) = fieldset .UV [particles ]
59+ lon1 , lat1 = (particles .lon + u1 * 0.5 * dt , particles .lat + v1 * 0.5 * dt )
60+ (u2 , v2 ) = fieldset .UV [particles .time + 0.5 * particles .dt , particles .z , lat1 , lon1 , particles ]
61+ lon2 , lat2 = (particles .lon + u2 * 0.5 * dt , particles .lat + v2 * 0.5 * dt )
62+ (u3 , v3 ) = fieldset .UV [particles .time + 0.5 * particles .dt , particles .z , lat2 , lon2 , particles ]
63+ lon3 , lat3 = (particles .lon + u3 * dt , particles .lat + v3 * dt )
64+ (u4 , v4 ) = fieldset .UV [particles .time + particles .dt , particles .z , lat3 , lon3 , particles ]
65+ particles .dlon += (u1 + 2 * u2 + 2 * u3 + u4 ) / 6.0 * dt
66+ particles .dlat += (v1 + 2 * v2 + 2 * v3 + v4 ) / 6.0 * dt
6867
6968
7069def AdvectionRK4_3D (particles , fieldset ): # pragma: no cover
7170 """Advection of particles using fourth-order Runge-Kutta integration including vertical velocity."""
71+ particles .dt = _adjust_RK_dt (fieldset .time_interval , particles .time , particles .dt )
7272 dt = particles .dt / np .timedelta64 (1 , "s" )
7373 (u1 , v1 , w1 ) = fieldset .UVW [particles ]
7474 lon1 = particles .lon + u1 * 0.5 * dt
@@ -92,6 +92,7 @@ def AdvectionRK4_3D_CROCO(particles, fieldset): # pragma: no cover
9292 """Advection of particles using fourth-order Runge-Kutta integration including vertical velocity.
9393 This kernel assumes the vertical velocity is the 'w' field from CROCO output and works on sigma-layers.
9494 """
95+ particles .dt = _adjust_RK_dt (fieldset .time_interval , particles .time , particles .dt )
9596 dt = particles .dt / np .timedelta64 (1 , "s" ) # TODO: improve API for converting dt to seconds
9697 sig_dep = particles .z / fieldset .H [particles .time , 0 , particles .lat , particles .lon ]
9798
@@ -148,6 +149,7 @@ def AdvectionRK45(particles, fieldset): # pragma: no cover
148149 Time-step dt is halved if error is larger than fieldset.RK45_tol,
149150 and doubled if error is smaller than 1/10th of tolerance.
150151 """
152+ particles .dt = _adjust_RK_dt (fieldset .time_interval , particles .time , particles .dt )
151153 dt = particles .dt / np .timedelta64 (1 , "s" ) # TODO: improve API for converting dt to seconds
152154
153155 c = [1.0 / 4.0 , 3.0 / 8.0 , 12.0 / 13.0 , 1.0 , 1.0 / 2.0 ]
0 commit comments