Skip to content

Commit 9cfce55

Browse files
Use RK2 for CROCO advection
1 parent 9451fd2 commit 9cfce55

4 files changed

Lines changed: 25 additions & 45 deletions

File tree

docs/user_guide/examples/tutorial_croco_3D.ipynb

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,11 @@
3737
"import matplotlib.pyplot as plt\n",
3838
"import numpy as np\n",
3939
"import polars as pl\n",
40-
"import xarray as xr\n",
4140
"\n",
4241
"import parcels\n",
4342
"import parcels.tutorial\n",
4443
"\n",
45-
"ds_fields = parcels.tutorial.open_dataset(\"CROCOidealized_data/data\")\n",
46-
"\n",
47-
"ds_fields.load(); # Preload data to speed up access"
44+
"ds_fields = parcels.tutorial.open_dataset(\"CROCOidealized_data/data\")"
4845
]
4946
},
5047
{
@@ -92,7 +89,10 @@
9289
"fieldset = parcels.FieldSet.from_sgrid_conventions(ds_fset)\n",
9390
"\n",
9491
"# Add the critical depth (`hc`) as context to the fieldset\n",
95-
"fieldset.add_context(\"hc\", ds_fields.hc.item())"
92+
"fieldset.add_context(\"hc\", ds_fields.hc.item())\n",
93+
"\n",
94+
"# Convert the FieldSet to windowed arrays for better performance\n",
95+
"fieldset = fieldset.to_windowed_arrays()"
9696
]
9797
},
9898
{
@@ -132,7 +132,7 @@
132132
")\n",
133133
"\n",
134134
"pset.execute(\n",
135-
" [parcels.kernels.AdvectionRK4_3D_CROCO, DeleteParticle],\n",
135+
" [parcels.kernels.AdvectionRK2_3D_CROCO, DeleteParticle],\n",
136136
" runtime=np.timedelta64(50_000, \"s\"),\n",
137137
" dt=np.timedelta64(100, \"s\"),\n",
138138
" output_file=outputfile,\n",
@@ -173,7 +173,7 @@
173173
"ax.set_xlabel(\"X [km]\")\n",
174174
"ax.set_xlim(30, 170)\n",
175175
"ax.set_ylabel(\"Depth [m]\")\n",
176-
"ax.set_title(\"Particles in idealized CROCO velocity field using AdvectionRK4_3D_CROCO\")\n",
176+
"ax.set_title(\"Particles in idealized CROCO velocity field using AdvectionRK2_3D_CROCO\")\n",
177177
"plt.tight_layout()\n",
178178
"plt.show()"
179179
]
@@ -189,7 +189,7 @@
189189
"cell_type": "markdown",
190190
"metadata": {},
191191
"source": [
192-
"It may be insightful to compare this 3D run with the `AdvectionRK4_3D_CROCO` kernel with a run where the vertical velocity (`W`) is set to zero. In that case, the particles will not stay on their initial depth levels but instead follow sigma-layers."
192+
"It may be insightful to compare this 3D run with the `AdvectionRK2_3D_CROCO` kernel with a run where the vertical velocity (`W`) is set to zero. In that case, the particles will not stay on their initial depth levels but instead follow sigma-layers."
193193
]
194194
},
195195
{
@@ -221,7 +221,7 @@
221221
")\n",
222222
"\n",
223223
"pset_noW.execute(\n",
224-
" [parcels.kernels.AdvectionRK4_3D_CROCO, DeleteParticle],\n",
224+
" [parcels.kernels.AdvectionRK2_3D_CROCO, DeleteParticle],\n",
225225
" runtime=np.timedelta64(50_000, \"s\"),\n",
226226
" dt=np.timedelta64(100, \"s\"),\n",
227227
" output_file=outputfile,\n",
@@ -273,9 +273,9 @@
273273
"cell_type": "markdown",
274274
"metadata": {},
275275
"source": [
276-
"For Advection, you will need to use the `AdvectionRK4_3D_CROCO` kernel, which works slightly different from the normal 3D advection kernel because it converts the vertical velocity in sigma-units. The conversion from z to sigma is done at every time step, using the `convert_z_to_sigma_croco()` function.\n",
276+
"For Advection, you will need to use the `AdvectionRK2_3D_CROCO` kernel, which works slightly different from the normal 3D advection kernel because it converts the vertical velocity in sigma-units. The conversion from z to sigma is done at every time step, using the `convert_z_to_sigma_croco()` function.\n",
277277
"\n",
278-
"In particular, the following algorithm is used (note that the RK4 version is slightly more complex than this Euler-Forward version, but the idea is identical). Also note that the vertical velocity is linearly interpolated here, which gives much better results than the default C-grid interpolation.\n",
278+
"In particular, the following algorithm is used (note that the RK2 version is slightly more complex than this Euler-Forward version, but the idea is identical). Also note that the vertical velocity is linearly interpolated here, which gives much better results than the default C-grid interpolation.\n",
279279
"\n",
280280
"```python\n",
281281
"sigma = particles.z / fieldset.h[particles.t, 0, particles.y, particles.x]\n",
@@ -297,6 +297,11 @@
297297
"z_new = sigma_new * fieldset.h[particles.t, 0, y_new, x_new, particles]\n",
298298
"```"
299299
]
300+
},
301+
{
302+
"cell_type": "markdown",
303+
"metadata": {},
304+
"source": []
300305
}
301306
],
302307
"metadata": {

src/parcels/kernels/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
DiffusionUniformKh,
1414
)
1515
from ._sigmagrids import (
16-
AdvectionRK4_3D_CROCO,
16+
AdvectionRK2_3D_CROCO,
1717
SampleOmegaCroco,
1818
convert_z_to_sigma_croco,
1919
)
@@ -32,7 +32,7 @@
3232
"AdvectionDiffusionM1",
3333
"DiffusionUniformKh",
3434
# sigmagrids
35-
"AdvectionRK4_3D_CROCO",
35+
"AdvectionRK2_3D_CROCO",
3636
"SampleOmegaCroco",
3737
"convert_z_to_sigma_croco",
3838
]

src/parcels/kernels/_sigmagrids.py

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ def SampleOmegaCroco(particles, fieldset):
3535
particles.omega = fieldset.omega[particles.t, sigma, particles.y, particles.x, particles]
3636

3737

38-
# TODO change to RK2 (once RK4 yields same results as v3)
39-
def AdvectionRK4_3D_CROCO(particles, fieldset): # pragma: no cover
40-
"""Advection of particles using fourth-order Runge-Kutta integration including vertical velocity.
38+
def AdvectionRK2_3D_CROCO(particles, fieldset): # pragma: no cover
39+
"""Advection of particles using second-order Runge-Kutta integration including vertical velocity.
4140
This kernel assumes the vertical velocity is the 'w' field from CROCO output and works on sigma-layers.
4241
It also uses linear interpolation of the W field, which gives much better results than the default C-grid interpolation.
4342
"""
@@ -57,31 +56,7 @@ def AdvectionRK4_3D_CROCO(particles, fieldset): # pragma: no cover
5756
(u2, v2) = fieldset.UV[particles.t + 0.5 * dt, sig1, y1, x1, particles]
5857
w2 = fieldset.W[particles.t + 0.5 * dt, sig1, y1, x1, particles]
5958
w2 *= sig_dep1 / fieldset.h[particles.t + 0.5 * dt, np.zeros_like(particles.z), y1, x1]
60-
x2 = particles.x + u2 * 0.5 * dt
61-
y2 = particles.y + v2 * 0.5 * dt
62-
sig_dep2 = sigma + w2 * 0.5 * dt
63-
dep2 = sig_dep2 * fieldset.h[particles.t + 0.5 * dt, np.zeros_like(particles.z), y2, x2]
6459

65-
sig2 = convert_z_to_sigma_croco(fieldset, particles.t + 0.5 * dt, dep2, y2, x2, particles)
66-
(u3, v3) = fieldset.UV[particles.t + 0.5 * dt, sig2, y2, x2, particles]
67-
w3 = fieldset.W[particles.t + 0.5 * dt, sig2, y2, x2, particles]
68-
w3 *= sig_dep2 / fieldset.h[particles.t + 0.5 * dt, np.zeros_like(particles.z), y2, x2]
69-
x3 = particles.x + u3 * dt
70-
y3 = particles.y + v3 * dt
71-
sig_dep3 = sigma + w3 * dt
72-
dep3 = sig_dep3 * fieldset.h[particles.t + dt, np.zeros_like(particles.z), y3, x3]
73-
74-
sig3 = convert_z_to_sigma_croco(fieldset, particles.t + dt, dep3, y3, x3, particles)
75-
(u4, v4) = fieldset.UV[particles.t + dt, sig3, y3, x3, particles]
76-
w4 = fieldset.W[particles.t + dt, sig3, y3, x3, particles]
77-
w4 *= sig_dep3 / fieldset.h[particles.t + dt, np.zeros_like(particles.z), y3, x3]
78-
x4 = particles.x + u4 * dt
79-
y4 = particles.y + v4 * dt
80-
sig_dep4 = sigma + w4 * dt
81-
82-
dep4 = sig_dep4 * fieldset.h[particles.t + dt, np.zeros_like(particles.z), y4, x4]
83-
particles.dx += (u1 + 2 * u2 + 2 * u3 + u4) / 6 * dt
84-
particles.dy += (v1 + 2 * v2 + 2 * v3 + v4) / 6 * dt
85-
particles.dz += (
86-
(dep1 - particles.z) * 2 + 2 * (dep2 - particles.z) * 2 + 2 * (dep3 - particles.z) + dep4 - particles.z
87-
) / 6
60+
particles.dx += u2 * dt
61+
particles.dy += v2 * dt
62+
particles.dz += w2 * dt

tests/test_sigmagrids.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import parcels
44
import parcels.tutorial
55
from parcels import Particle, ParticleSet, Variable
6-
from parcels.kernels import AdvectionRK4_3D_CROCO, SampleOmegaCroco, convert_z_to_sigma_croco
6+
from parcels.kernels import AdvectionRK2_3D_CROCO, SampleOmegaCroco, convert_z_to_sigma_croco
77

88

99
def test_conversion_3DCROCO():
@@ -71,7 +71,7 @@ def test_advection_3DCROCO():
7171
pset = ParticleSet(fieldset=fieldset, pclass=pclass, x=X, y=Y, z=Z)
7272

7373
pset.execute(
74-
[AdvectionRK4_3D_CROCO, SampleOmegaCroco], runtime=np.timedelta64(runtime, "s"), dt=np.timedelta64(100, "s")
74+
[AdvectionRK2_3D_CROCO, SampleOmegaCroco], runtime=np.timedelta64(runtime, "s"), dt=np.timedelta64(100, "s")
7575
)
7676
np.testing.assert_allclose(pset.z, Z.flatten(), atol=5) # TODO lower this atol
7777
np.testing.assert_allclose(pset.x, [x + runtime for x in X.flatten()], atol=1e-3)

0 commit comments

Comments
 (0)