Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for CROCO 3D velocities #1641

Merged
merged 53 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
5114096
Add RK4 version of CROCO 3D kernel
erikvansebille Aug 6, 2024
e7c6d47
Start implementing fieldset.from_croco()
erikvansebille Aug 6, 2024
40b76ac
Using MITgcm-style horizonal interpolation for CROCO
erikvansebille Aug 7, 2024
47e6914
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 7, 2024
ab2e876
Cleaning up spaces in parcels.h
erikvansebille Aug 7, 2024
b3a5f4c
Fixing CROCO upper layer sampling
erikvansebille Aug 7, 2024
7f72e8e
Setting CROCO vertical interpolation method to linear in JIT
erikvansebille Aug 7, 2024
71d3351
Rewriting CROCO 3D advection kernel to use fieldset.UVW sampling
erikvansebille Aug 7, 2024
0ced1ec
Fix loading of CROCO grid when dimension lengths are 1 larger than va…
erikvansebille Aug 7, 2024
9fefe5b
Adding support for 2D advection in from_croco
erikvansebille Aug 7, 2024
b31d69e
Temporarily silencing assert in pop dask chunking test
erikvansebille Aug 7, 2024
f66a4b7
Support for sampling depth in m in croco sigma layers
erikvansebille Aug 8, 2024
d21f0a8
Merge branch 'JIT_keeping_track_highest_errorcode' into croco_3D_velo…
erikvansebille Aug 8, 2024
ccf1034
Creating extra 3DSigma category for sigma vector fields
erikvansebille Aug 8, 2024
651bbdc
Adding non-vectorfield-sampling support for croco in scipy
erikvansebille Aug 8, 2024
b51ee68
Simplifying code by not requiring H field as part of VectorField class
erikvansebille Aug 8, 2024
a1764e3
Minor fix in field error handling
erikvansebille Aug 8, 2024
95641a0
xfail dask test_pop
VeckoTheGecko Aug 8, 2024
14a6705
Undoing temporary commenting of assert in example_dask_chunking as no…
erikvansebille Aug 9, 2024
dd129b8
Using time in fieldset.H interpolation (to possibly allow for time-ev…
erikvansebille Aug 9, 2024
18405f6
Adding CROCO tutorial
erikvansebille Aug 9, 2024
9da5f25
Updating CROCO tutorial
erikvansebille Aug 9, 2024
edcc19a
Minor change to CROCO 3D algorithm
erikvansebille Aug 9, 2024
d7e8e3c
Merge branch 'JIT_keeping_track_highest_errorcode' into croco_3D_velo…
erikvansebille Aug 9, 2024
eb5e65e
Fixing bug in codegenerator error-code handling
erikvansebille Aug 9, 2024
4321b41
Merge branch 'master' into croco_3D_velocities
erikvansebille Aug 9, 2024
c51a735
Update algorithm description in croco 3D tutorial
erikvansebille Aug 9, 2024
8255585
Adding nbsphinx-thumbnail tag to first plot of croco notebook, to sho…
erikvansebille Aug 9, 2024
2a35e36
Expanding docstring of fieldset.from_croco
erikvansebille Aug 12, 2024
ef2929a
Merge branch 'master' into croco_3D_velocities
erikvansebille Aug 12, 2024
b9f0827
Merge commit '7c8bbc76c0c2d9936b52867a9998fccf220f9042' into croco-merge
VeckoTheGecko Aug 16, 2024
0731ffe
Merge branch 'master' into croco_3D_velocities
erikvansebille Aug 16, 2024
31b806e
Merge branch 'master' into croco_3D_velocities
erikvansebille Aug 16, 2024
e146ff3
Merge branch 'master' into croco_3D_velocities
erikvansebille Aug 27, 2024
bc30596
Merge branch 'master' into croco_3D_velocities
erikvansebille Aug 30, 2024
f6448ae
Updating Field init to not check for W interp_method in croco
erikvansebille Aug 30, 2024
76b0b8a
Removing redef of VectorType
erikvansebille Aug 30, 2024
226b79e
Merge branch 'master' into croco_3D_velocities
erikvansebille Aug 30, 2024
baa680a
Merge branch 'master' into croco_3D_velocities
erikvansebille Sep 6, 2024
b7e668a
Add filter for velocity interpolation warning for CROCO
erikvansebille Sep 6, 2024
c229759
Merge branch 'master' into croco_3D_velocities
erikvansebille Sep 16, 2024
74fdf5c
Adding normal field evaluation to CROCO unit test
erikvansebille Sep 17, 2024
5071f7d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 17, 2024
b4cf369
Adding support for 'normal' Fields in CROCO
erikvansebille Sep 17, 2024
7d147c3
Always passing H field to particle_loop for CROCO
erikvansebille Sep 17, 2024
391ac9c
Adding H field only if it exists
erikvansebille Sep 17, 2024
c9bfb97
Merge branch 'master' into croco_3D_velocities
erikvansebille Sep 17, 2024
9ac4aad
Merge branch 'master' into croco_3D_velocities
erikvansebille Oct 14, 2024
5148f6b
Adding alert box to discuss w versus omega choice in from_croco
erikvansebille Oct 14, 2024
4e30feb
Adding 3DSigma vector_type
erikvansebille Oct 14, 2024
c2f2b38
Fixing review comments
erikvansebille Oct 15, 2024
c376f0d
Reverting change in review
erikvansebille Oct 15, 2024
e73b275
update _FileBuffer signature to avoid kwargs
erikvansebille Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/documentation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Parcels has several documentation and tutorial Jupyter notebooks and scripts whi
../examples/documentation_indexing.ipynb
../examples/tutorial_nemo_curvilinear.ipynb
../examples/tutorial_nemo_3D.ipynb
../examples/tutorial_croco_3D.ipynb
../examples/tutorial_NestedFields.ipynb
../examples/tutorial_timevaryingdepthdimensions.ipynb
../examples/tutorial_periodic_boundaries.ipynb
Expand Down
332 changes: 332 additions & 0 deletions docs/examples/tutorial_croco_3D.ipynb

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions parcels/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class ParcelsAST(ast.AST):
) # corresponds with `interp_method` (which can also be dict mapping field names to method)
PathLike = str | os.PathLike
Mesh = Literal["spherical", "flat"] # corresponds with `mesh`
VectorType = Literal["3D", "2D"] | None # corresponds with `vector_type`
VectorType = Literal["3D", "3DSigma", "2D"] | None # corresponds with `vector_type`
ChunkMode = Literal["auto", "specific", "failsafe"] # corresponds with `chunk_mode`
GridIndexingType = Literal["pop", "mom5", "mitgcm", "nemo"] # corresponds with `gridindexingtype`
GridIndexingType = Literal["pop", "mom5", "mitgcm", "nemo", "croco"] # corresponds with `gridindexingtype`
UpdateStatus = Literal["not_updated", "first_updated", "updated"] # corresponds with `_update_status`
TimePeriodic = float | datetime.timedelta | Literal[False] # corresponds with `time_periodic`
NetcdfEngine = Literal["netcdf4", "xarray", "scipy"]
Expand Down
54 changes: 53 additions & 1 deletion parcels/application_kernels/advection.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@

from parcels.tools.statuscodes import StatusCode

__all__ = ["AdvectionRK4", "AdvectionEE", "AdvectionRK45", "AdvectionRK4_3D", "AdvectionAnalytical"]
__all__ = [
"AdvectionRK4",
"AdvectionEE",
"AdvectionRK45",
"AdvectionRK4_3D",
"AdvectionAnalytical",
"AdvectionRK4_3D_CROCO",
]


def AdvectionRK4(particle, fieldset, time):
Expand Down Expand Up @@ -40,6 +47,51 @@
particle_ddepth += (w1 + 2 * w2 + 2 * w3 + w4) / 6 * particle.dt # noqa


def AdvectionRK4_3D_CROCO(particle, fieldset, time):
"""Advection of particles using fourth-order Runge-Kutta integration including vertical velocity.
This kernel assumes the vertical velocity is the 'w' field from CROCO output and works on sigma-layers.
"""
sig_dep = particle.depth / fieldset.H[time, 0, particle.lat, particle.lon]

Check warning on line 54 in parcels/application_kernels/advection.py

View check run for this annotation

Codecov / codecov/patch

parcels/application_kernels/advection.py#L54

Added line #L54 was not covered by tests

(u1, v1, w1) = fieldset.UVW[time, particle.depth, particle.lat, particle.lon, particle]
w1 *= sig_dep / fieldset.H[time, 0, particle.lat, particle.lon]
lon1 = particle.lon + u1 * 0.5 * particle.dt
lat1 = particle.lat + v1 * 0.5 * particle.dt
sig_dep1 = sig_dep + w1 * 0.5 * particle.dt
dep1 = sig_dep1 * fieldset.H[time, 0, lat1, lon1]

Check warning on line 61 in parcels/application_kernels/advection.py

View check run for this annotation

Codecov / codecov/patch

parcels/application_kernels/advection.py#L56-L61

Added lines #L56 - L61 were not covered by tests

(u2, v2, w2) = fieldset.UVW[time + 0.5 * particle.dt, dep1, lat1, lon1, particle]
w2 *= sig_dep1 / fieldset.H[time, 0, lat1, lon1]
lon2 = particle.lon + u2 * 0.5 * particle.dt
lat2 = particle.lat + v2 * 0.5 * particle.dt
sig_dep2 = sig_dep + w2 * 0.5 * particle.dt
dep2 = sig_dep2 * fieldset.H[time, 0, lat2, lon2]

Check warning on line 68 in parcels/application_kernels/advection.py

View check run for this annotation

Codecov / codecov/patch

parcels/application_kernels/advection.py#L63-L68

Added lines #L63 - L68 were not covered by tests

(u3, v3, w3) = fieldset.UVW[time + 0.5 * particle.dt, dep2, lat2, lon2, particle]
w3 *= sig_dep2 / fieldset.H[time, 0, lat2, lon2]
lon3 = particle.lon + u3 * particle.dt
lat3 = particle.lat + v3 * particle.dt
sig_dep3 = sig_dep + w3 * particle.dt
dep3 = sig_dep3 * fieldset.H[time, 0, lat3, lon3]

Check warning on line 75 in parcels/application_kernels/advection.py

View check run for this annotation

Codecov / codecov/patch

parcels/application_kernels/advection.py#L70-L75

Added lines #L70 - L75 were not covered by tests

(u4, v4, w4) = fieldset.UVW[time + particle.dt, dep3, lat3, lon3, particle]
w4 *= sig_dep3 / fieldset.H[time, 0, lat3, lon3]
lon4 = particle.lon + u4 * particle.dt
lat4 = particle.lat + v4 * particle.dt
sig_dep4 = sig_dep + w4 * particle.dt
dep4 = sig_dep4 * fieldset.H[time, 0, lat4, lon4]

Check warning on line 82 in parcels/application_kernels/advection.py

View check run for this annotation

Codecov / codecov/patch

parcels/application_kernels/advection.py#L77-L82

Added lines #L77 - L82 were not covered by tests

particle_dlon += (u1 + 2 * u2 + 2 * u3 + u4) / 6 * particle.dt # noqa
particle_dlat += (v1 + 2 * v2 + 2 * v3 + v4) / 6 * particle.dt # noqa
particle_ddepth += ( # noqa
(dep1 - particle.depth) * 2
+ 2 * (dep2 - particle.depth) * 2
+ 2 * (dep3 - particle.depth)
+ dep4
- particle.depth
) / 6

Check warning on line 92 in parcels/application_kernels/advection.py

View check run for this annotation

Codecov / codecov/patch

parcels/application_kernels/advection.py#L84-L92

Added lines #L84 - L92 were not covered by tests


def AdvectionEE(particle, fieldset, time):
"""Advection of particles using Explicit Euler (aka Euler Forward) integration."""
(u1, v1) = fieldset.UV[particle]
Expand Down
52 changes: 40 additions & 12 deletions parcels/compilation/codegenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,13 @@


class VectorFieldEvalNode(IntrinsicNode):
def __init__(self, field, args, var, var2, var3, convert=True):
def __init__(self, field, args, var, var2, var3, var4, convert=True):
self.field = field
self.args = args
self.var = var # the variable in which the interpolated field is written
self.var2 = var2 # second variable for UV interpolation
self.var3 = var3 # third variable for UVW interpolation
self.var4 = var4 # extra variable for sigma-scaling for croco
self.convert = convert # whether to convert the result (like field.applyConversion)


Expand All @@ -107,12 +108,13 @@


class NestedVectorFieldEvalNode(IntrinsicNode):
def __init__(self, fields, args, var, var2, var3):
def __init__(self, fields, args, var, var2, var3, var4):
self.fields = fields
self.args = args
self.var = var # the variable in which the interpolated field is written
self.var2 = var2 # second variable for UV interpolation
self.var3 = var3 # third variable for UVW interpolation
self.var4 = var4 # extra variable for sigma-scaling for croco


class GridNode(IntrinsicNode):
Expand Down Expand Up @@ -285,9 +287,10 @@
elif isinstance(node.value, VectorFieldNode):
tmp = self.get_tmp()
tmp2 = self.get_tmp()
tmp3 = self.get_tmp() if node.value.obj.vector_type == "3D" else None
tmp3 = self.get_tmp() if "3D" in node.value.obj.vector_type else None
tmp4 = self.get_tmp() if "3DSigma" in node.value.obj.vector_type else None
# Insert placeholder node for field eval ...
self.stmt_stack += [VectorFieldEvalNode(node.value, node.slice, tmp, tmp2, tmp3)]
self.stmt_stack += [VectorFieldEvalNode(node.value, node.slice, tmp, tmp2, tmp3, tmp4)]
# .. and return the name of the temporary that will be populated
if tmp3:
return ast.Tuple([ast.Name(id=tmp), ast.Name(id=tmp2), ast.Name(id=tmp3)], ast.Load())
Expand All @@ -300,8 +303,9 @@
elif isinstance(node.value, NestedVectorFieldNode):
tmp = self.get_tmp()
tmp2 = self.get_tmp()
tmp3 = self.get_tmp() if list.__getitem__(node.value.obj, 0).vector_type == "3D" else None
self.stmt_stack += [NestedVectorFieldEvalNode(node.value, node.slice, tmp, tmp2, tmp3)]
tmp3 = self.get_tmp() if "3D" in list.__getitem__(node.value.obj, 0).vector_type else None
tmp4 = self.get_tmp() if "3DSigma" in list.__getitem__(node.value.obj, 0).vector_type else None
self.stmt_stack += [NestedVectorFieldEvalNode(node.value, node.slice, tmp, tmp2, tmp3, tmp4)]
if tmp3:
return ast.Tuple([ast.Name(id=tmp), ast.Name(id=tmp2), ast.Name(id=tmp3)], ast.Load())
else:
Expand Down Expand Up @@ -371,7 +375,8 @@
# get a temporary value to assign result to
tmp1 = self.get_tmp()
tmp2 = self.get_tmp()
tmp3 = self.get_tmp() if node.func.field.obj.vector_type == "3D" else None
tmp3 = self.get_tmp() if "3D" in node.func.field.obj.vector_type else None
tmp4 = self.get_tmp() if "3DSigma" in node.func.field.obj.vector_type else None
# whether to convert
convert = True
if "applyConversion" in node.keywords:
Expand All @@ -382,7 +387,7 @@
# convert args to Index(Tuple(*args))
args = ast.Index(value=ast.Tuple(node.args, ast.Load()))

self.stmt_stack += [VectorFieldEvalNode(node.func.field, args, tmp1, tmp2, tmp3, convert)]
self.stmt_stack += [VectorFieldEvalNode(node.func.field, args, tmp1, tmp2, tmp3, tmp4, convert)]
if tmp3:
return ast.Tuple([ast.Name(id=tmp1), ast.Name(id=tmp2), ast.Name(id=tmp3)], ast.Load())
else:
Expand Down Expand Up @@ -421,6 +426,8 @@
self.fieldset = fieldset
self.ptype = ptype
self.field_args = collections.OrderedDict()
if isinstance(fieldset.U, Field) and fieldset.U.gridindexingtype == "croco" and hasattr(fieldset, "H"):
self.field_args["H"] = fieldset.H # CROCO requires H field
VeckoTheGecko marked this conversation as resolved.
Show resolved Hide resolved
self.vector_field_args = collections.OrderedDict()
self.const_args = collections.OrderedDict()

Expand Down Expand Up @@ -456,7 +463,7 @@
for kvar in self.kernel_vars + self.array_vars:
if kvar in funcvars:
funcvars.remove(kvar)
self.ccode.body.insert(0, c.Value("int", "parcels_interp_state"))
self.ccode.body.insert(0, c.Statement("int parcels_interp_state = 0"))
if len(funcvars) > 0:
for f in funcvars:
self.ccode.body.insert(0, c.Statement(f"type_coord {f} = 0"))
Expand Down Expand Up @@ -819,6 +826,16 @@
self.visit(node.field)
self.visit(node.args)
args = self._check_FieldSamplingArguments(node.args.ccode)
statements_croco = []
if "croco" in node.field.obj.gridindexingtype and node.field.obj.name != "H":
statements_croco.append(
c.Assign(
"parcels_interp_state",
f"temporal_interpolation({args[3]}, {args[2]}, 0, time, H, &particles->xi[pnum*ngrid], &particles->yi[pnum*ngrid], &particles->zi[pnum*ngrid], &particles->ti[pnum*ngrid], &{node.var}, LINEAR, {node.field.obj.gridindexingtype.upper()})",

Check warning on line 834 in parcels/compilation/codegenerator.py

View check run for this annotation

Codecov / codecov/patch

parcels/compilation/codegenerator.py#L832-L834

Added lines #L832 - L834 were not covered by tests
)
)
statements_croco.append(c.Statement(f"{node.var} = {args[1]}/{node.var}"))
args = (args[0], node.var, args[2], args[3])
ccode_eval = node.field.obj._ccode_eval(node.var, *args)
stmts = [
c.Assign("parcels_interp_state", ccode_eval),
Expand All @@ -830,12 +847,22 @@
conv_stat = c.Statement(f"{node.var} *= {ccode_conv}")
stmts += [conv_stat]

node.ccode = c.Block(stmts + [c.Statement("CHECKSTATUS_KERNELLOOP(parcels_interp_state)")])
node.ccode = c.Block(statements_croco + stmts + [c.Statement("CHECKSTATUS_KERNELLOOP(parcels_interp_state)")])

def visit_VectorFieldEvalNode(self, node):
self.visit(node.field)
self.visit(node.args)
args = self._check_FieldSamplingArguments(node.args.ccode)
statements_croco = []
if "3DSigma" in node.field.obj.vector_type:
statements_croco.append(
c.Assign(
"parcels_interp_state",
f"temporal_interpolation({args[3]}, {args[2]}, 0, time, H, &particles->xi[pnum*ngrid], &particles->yi[pnum*ngrid], &particles->zi[pnum*ngrid], &particles->ti[pnum*ngrid], &{node.var}, LINEAR, {node.field.obj.U.gridindexingtype.upper()})",

Check warning on line 861 in parcels/compilation/codegenerator.py

View check run for this annotation

Codecov / codecov/patch

parcels/compilation/codegenerator.py#L859-L861

Added lines #L859 - L861 were not covered by tests
)
)
statements_croco.append(c.Statement(f"{node.var4} = {args[1]}/{node.var}"))
args = (args[0], node.var4, args[2], args[3])
ccode_eval = node.field.obj._ccode_eval(
node.var, node.var2, node.var3, node.field.obj.U, node.field.obj.V, node.field.obj.W, *args
)
Expand All @@ -845,12 +872,13 @@
statements = [c.Statement(f"{node.var} *= {ccode_conv1}"), c.Statement(f"{node.var2} *= {ccode_conv2}")]
else:
statements = []
if node.convert and node.field.obj.vector_type == "3D":
if node.convert and "3D" in node.field.obj.vector_type:
ccode_conv3 = node.field.obj.W._ccode_convert(*args)
statements.append(c.Statement(f"{node.var3} *= {ccode_conv3}"))
conv_stat = c.Block(statements)
node.ccode = c.Block(
[
c.Block(statements_croco),

Check warning on line 881 in parcels/compilation/codegenerator.py

View check run for this annotation

Codecov / codecov/patch

parcels/compilation/codegenerator.py#L881

Added line #L881 was not covered by tests
c.Assign("parcels_interp_state", ccode_eval),
c.Assign("particles->state[pnum]", "max(particles->state[pnum], parcels_interp_state)"),
conv_stat,
Expand Down Expand Up @@ -891,7 +919,7 @@
statements = [c.Statement(f"{node.var} *= {ccode_conv1}"), c.Statement(f"{node.var2} *= {ccode_conv2}")]
else:
statements = []
if fld.vector_type == "3D":
if "3D" in fld.vector_type:
ccode_conv3 = fld.W._ccode_convert(*args)
statements.append(c.Statement(f"{node.var3} *= {ccode_conv3}"))
cstat += [
Expand Down
Loading
Loading