Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
07060e3
Change parcels expected vertical dimensions to `zc` and `zf`
fluidnumerics-joe Jan 6, 2026
b35fcbe
Change nz,nz1 -> zf, zc
fluidnumerics-joe Jan 6, 2026
6b03fc0
Fix broken tests and dim/coord renaming and indexing
fluidnumerics-joe Jan 7, 2026
1daca5e
Add test for icon data and default to zeroInterpolator when not found
fluidnumerics-joe Jan 7, 2026
b999dee
Change ux interpolator names to new convention
fluidnumerics-joe Jan 7, 2026
97d95a5
Add interpolators to complete the [face,node]x[zc,zf] placements
fluidnumerics-joe Jan 7, 2026
ae64500
Add exactness tests
fluidnumerics-joe Jan 8, 2026
f0d3f51
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 8, 2026
f6f578f
Allow setting "mesh" parameter in from_* methods for ux data
fluidnumerics-joe Jan 8, 2026
16799b1
Use signed areas for 2-D area calculation
fluidnumerics-joe Jan 8, 2026
62df2d4
Merge branch 'feature/from_icon' of github.com:OceanParcels/Parcels i…
fluidnumerics-joe Jan 8, 2026
4a2f048
Fix abandoned merge block
fluidnumerics-joe Jan 8, 2026
914f54b
Fix vertical coordinate name to match new convention in nestedgrids t…
fluidnumerics-joe Jan 8, 2026
7c33272
Update tutorials to use new vertical grid naming convention and add d…
fluidnumerics-joe Jan 8, 2026
cab7b61
Assign appropriate interpolator to p field
fluidnumerics-joe Jan 9, 2026
717eabd
Merge branch 'feature/from_icon' of github.com:OceanParcels/Parcels i…
fluidnumerics-joe Jan 9, 2026
8254c0c
Change number of faces in check
fluidnumerics-joe Jan 9, 2026
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
30 changes: 9 additions & 21 deletions docs/user_guide/examples/tutorial_interpolation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,10 @@
"source": [
"## Interpolators on unstructured grids\n",
"Parcels v4 supports the use of general circulation model output that is defined on unstructured grids. We include basic interpolators to help you get started, including\n",
"- `UxPiecewiseConstantFace` - this interpolator implements piecewise constant interpolation and is appropriate for data that is registered to the face centers of the unstructured grid\n",
"- `UxPiecewiseLinearNode` - this interpolator implements barycentric interpolation and is appropriate for data that is registered to the corner vertices of the unstructured grid faces\n",
"- `UxConstantFaceConstantZC` - this interpolator implements piecewise constant interpolation in both the lateral and vertical directions. It is appropriate for data that is registered to the face centers of the unstructured grid and centered on vertical layers.\n",
"- `UxLinearNodeConstantZC` - this interpolator implements barycentric interpolation in the lateral direction and piecewise constant in the vertical direction. It is appropriate for data that is registered to the corner vertices of the unstructured grid faces and centered on vertical layers.\n",
"- `UxLinearNodeLinearZF` - this interpolator implements barycentric interpolation in the lateral direction and piecewise linear interpolation in the vertical direction. It is appropriate for data that is registered to the corner vertices of the unstructured grid faces and on vertical layer interfaces.\n",
"- `UxConstantFaceLinearZF` - this interpolator implements piecewise constant interpolation in the lateral direction and piecewise linear interpolation in the vertical direction. It is appropriate for data that is registered to the face centers of the unstructured grid and centered on vertical layers\n",
"\n",
"To get started, we use a very simple generated `UxArray.UxDataset` that is included with Parcels."
]
Expand All @@ -282,7 +284,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we create the `Field` and `Fieldset` objects that will be used later in advancing particles. When creating a `Field` or `VectorField` object for unstructured grid data, we attach a {py:obj}`parcels.UxGrid` object and attach an `interp_method` to each object. For data that is defined on face centers, we use the `UxPiecewiseConstantFace` interpolator and for data that is defined on the face vertices, we use the `UxPiecewiseLinearNode` interpolator. In this example, we will look specifically at interpolating a tracer field that is defined by the same underlying analytical function, but is defined on both faces and vertices as separate fields."
"Next, we create the`Fieldset` object that will be used later in advancing particles. When using the `FieldSet.from_uxdataset()` method, Parcels takes care of automatically assigning the appropriate interpolator based on the coordinates of each data variable."
]
},
{
Expand All @@ -295,21 +297,7 @@
"\n",
"import parcels\n",
"\n",
"grid = parcels.UxGrid(ds.uxgrid, ds.nz, mesh=\"flat\")\n",
"\n",
"Tnode = parcels.Field(\n",
" \"T_node\",\n",
" ds[\"T_node\"],\n",
" grid,\n",
" interp_method=parcels.interpolators.UxPiecewiseLinearNode,\n",
")\n",
"Tface = parcels.Field(\n",
" \"T_face\",\n",
" ds[\"T_face\"],\n",
" grid,\n",
" interp_method=parcels.interpolators.UxPiecewiseConstantFace,\n",
")\n",
"fieldset = parcels.FieldSet([Tnode, Tface])"
"fieldset = parcels.FieldSet.from_uxdataset(ds, mesh=\"flat\")"
]
},
{
Expand Down Expand Up @@ -342,7 +330,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we can create a `ParticleSet` for each interpolation experiment. In one of the `ParticleSet` objects we use the `SampleTracer_Node` kernel to showcase interpolating with the `UxPiecewiseLinearNode` interpolator for node-registered data. In the other, we use the `SampleTracer_Face` to showcase interpolating with the `UxPiecewiseConstantFace` interpolator for face-registered data."
"Now, we can create a `ParticleSet` for each interpolation experiment. In one of the `ParticleSet` objects we use the `SampleTracer_Node` kernel to showcase interpolating with the `UxLinearNodeLinearZF` interpolator for node-registered data. In the other, we use the `SampleTracer_Face` to showcase interpolating with the `UxConstantFaceConstantZC` interpolator for face-registered data."
]
},
{
Expand Down Expand Up @@ -496,7 +484,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "test-notebooks",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -510,7 +498,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
"version": "3.12.11"
}
},
"nbformat": 4,
Expand Down
10 changes: 5 additions & 5 deletions docs/user_guide/examples/tutorial_nestedgrids.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@
" \"face_polygon\": (\n",
" (\n",
" \"time\",\n",
" \"nz\",\n",
" \"zf\",\n",
" \"n_face\",\n",
" ),\n",
" face_poly[np.newaxis, np.newaxis, :],\n",
Expand All @@ -325,7 +325,7 @@
" },\n",
" coords={\n",
" \"time\": np.array([np.timedelta64(0, \"ns\")]),\n",
" \"nz\": np.array([0]),\n",
" \"zf\": np.array([0]),\n",
" \"n_node\": np.arange(n_node),\n",
" \"n_face\": np.arange(n_face),\n",
" },\n",
Expand All @@ -338,8 +338,8 @@
" \"GridID\",\n",
" uxda,\n",
" # TODO note that here we need to use mesh=\"flat\" otherwise the hashing doesn't work. See https://github.com/Parcels-code/Parcels/pull/2439#discussion_r2627664010\n",
" parcels.UxGrid(uxda.uxgrid, z=uxda[\"nz\"], mesh=\"flat\"),\n",
" interp_method=parcels.interpolators.UxPiecewiseConstantFace,\n",
" parcels.UxGrid(uxda.uxgrid, z=uxda[\"zf\"], mesh=\"flat\"),\n",
" interp_method=parcels.interpolators.UxConstantFaceConstantZC,\n",
")\n",
"fieldset = parcels.FieldSet([GridID])"
]
Expand Down Expand Up @@ -559,7 +559,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "docs",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand Down
10 changes: 5 additions & 5 deletions docs/user_guide/examples_v3/tutorial_stommel_uxarray.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"\n",
"In Parcels, grid searching is conducted with respect to the faces. In other words, when a grid index `ei` is provided to an interpolation method, this refers the face index `fi` at vertical layer `zi` (when unraveled). Within the interpolation method, the `field.grid.uxgrid.face_node_connectivity` attribute can be used to obtain the node indices that surround the face. Using these connectivity tables is necessary for properly indexing node registered data.\n",
"\n",
"For the example Stommel gyre dataset in this tutorial, the `u` and `v` velocity components are face registered (similar to FESOM). Parcels includes a nearest neighbor interpolator for face registered unstructured grid data through `Parcels.application_kernels.interpolation.UxPiecewiseConstantFace`. Below, we create the `Field`s `U` and `V` and associate them with the `UxGrid` we created previously and this interpolation method."
"For the example Stommel gyre dataset in this tutorial, the `u` and `v` velocity components are face registered (similar to FESOM). Parcels includes a nearest neighbor interpolator for face registered unstructured grid data through `Parcels.application_kernels.interpolation.UxConstantFaceConstantZC`. Below, we create the `Field`s `U` and `V` and associate them with the `UxGrid` we created previously and this interpolation method."
]
},
{
Expand All @@ -121,26 +121,26 @@
"metadata": {},
"outputs": [],
"source": [
"from parcels.application_kernels.interpolation import UxPiecewiseConstantFace\n",
"from parcels.application_kernels.interpolation import UxConstantFaceConstantZC\n",
"from parcels.field import Field\n",
"\n",
"U = Field(\n",
" name=\"U\",\n",
" data=ds.U,\n",
" grid=grid,\n",
" interp_method=UxPiecewiseConstantFace,\n",
" interp_method=UxConstantFaceConstantZC,\n",
")\n",
"V = Field(\n",
" name=\"V\",\n",
" data=ds.V,\n",
" grid=grid,\n",
" interp_method=UxPiecewiseConstantFace,\n",
" interp_method=UxConstantFaceConstantZC,\n",
")\n",
"P = Field(\n",
" name=\"P\",\n",
" data=ds.p,\n",
" grid=grid,\n",
" interp_method=UxPiecewiseConstantFace,\n",
" interp_method=UxConstantFaceConstantZC,\n",
")"
]
},
Expand Down
34 changes: 8 additions & 26 deletions src/parcels/_core/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ class Field:
Notes
-----
The xarray.DataArray or uxarray.UxDataArray object contains the field data and metadata.

* dims: (time, [nz1 | nz], [face_lat | node_lat | edge_lat], [face_lon | node_lon | edge_lon])
* attrs: (location, mesh, mesh)
* dims: (time, [zc | zf], [face_lat | node_lat | edge_lat], [face_lon | node_lon | edge_lon])
* attrs: (location, mesh)

When using a xarray.DataArray object:

Expand Down Expand Up @@ -177,10 +176,10 @@ def zdim(self):
if type(self.data) is xr.DataArray:
return self.grid.zdim
else:
if "nz1" in self.data.dims:
return self.data.sizes["nz1"]
elif "nz" in self.data.dims:
return self.data.sizes["nz"]
if "zc" in self.data.dims:
return self.data.sizes["zc"]
elif "zf" in self.data.dims:
return self.data.sizes["zf"]
else:
return 0

Expand Down Expand Up @@ -403,9 +402,9 @@ def _assert_valid_uxdataarray(data: ux.UxDataArray):
uxarray.UxDataArray object.
"""
# Validate dimensions
if not ("nz1" in data.dims or "nz" in data.dims):
if not ("zc" in data.dims or "zf" in data.dims):
raise ValueError(
"Field is missing a 'nz1' or 'nz' dimension in the field's metadata. "
"Field is missing a 'zc' or 'zf' dimension in the field's metadata. "
"This attribute is required for xarray.DataArray objects."
)

Expand All @@ -424,23 +423,6 @@ def _assert_valid_uxdataarray(data: ux.UxDataArray):
"This attribute is required for xarray.DataArray objects."
)

_assert_valid_uxgrid(data.uxgrid)


def _assert_valid_uxgrid(grid):
"""Verifies that all the required attributes are present in the uxarray.UxDataArray.UxGrid object."""
if "Conventions" not in grid.attrs.keys():
raise ValueError(
"Field is missing a 'Conventions' attribute in the field's metadata. "
"This attribute is required for uxarray.UxDataArray objects."
)
if grid.attrs["Conventions"] != "UGRID-1.0":
raise ValueError(
"Field has a 'Conventions' attribute that is not 'UGRID-1.0'. "
"This attribute is required for uxarray.UxDataArray objects."
"See https://ugrid-conventions.github.io/ugrid-conventions/ for more information."
)


def _assert_compatible_combination(data: xr.DataArray | ux.UxDataArray, grid: ux.Grid | XGrid):
if isinstance(data, ux.UxDataArray):
Expand Down
Loading
Loading