Skip to content

Conversation

@fluidnumerics-joe
Copy link
Contributor

@fluidnumerics-joe fluidnumerics-joe commented Jan 7, 2026

This PR adds FieldSet.from_icon to support easy loading of data from the ICON model. Resolves #2425
In the process of adding this support, the following additional changes were made

  • Unstructured grid Interpolation scheme naming convention has been updated to follow Ux<lateral type><face|node|edge><vertical type><ZF | ZC> where <lateral type> is the type of interpolation applied in the lateral directions (e.g. "Constant" or "Linear") and <vertical type> is the type of interpolation applied in the vertical direction . The choice of face, node, or edge indicates where data is registered laterally and the choice of ZF or ZC indicates where data is registered vertically.
  • Additional default interpolation schemes were added to support the data placement in the sample provided by a Parcels community member mentioned in Add support for ICON model output #2425
  • Add correctness tests for additional interpolation kernels. This will be accomplished using constant, bilinear, and trilinear functions to prove exactness of the provided interpolation methods (no convergence testing will be conducted in this PR).
  • Changed the 2d triangle area to a signed area to prevent false positives that were found in new tests with generic icon data
  • Changed unstructured generic data types to fp64 to reduce floating point errors in barycentric interpolation for assessing exactness of interpolation schemes
  • Updated relevant notebooks with information on new interpolation methods.

`zc` refers to the vertical center and `zf` refers to the vertical
interface

I've also relaxed the requirement that the Conventions attribute be
defined; having this convention defined in the uxdataarray doesn't imply
compliance with a given convention..
New interpolator naming convention for unstructured grids will follow
Ux<lateral type><face|node|edge><vertical type><ZF | ZC> where
lateral type is the type of interpolation applied in the lateral
directions (e.g. "Constant" or "Linear") and vertical type is the type
of interpolation applied in the vertical direction .

The choice of face, node, or edge indicates where data is registered
laterally and the choice of ZF or ZC indicates where data is registered
vertically.
fluidnumerics-joe and others added 11 commits January 8, 2026 14:33
Still sorting out an issue with the linear node constant z interpolator
Also adjusted the test function for barycentric interpolation to an
affine function of lat and lon (f=a*lon + b*lat); Affine functions are
exact for barycentric interpolation while product (f=a*lon*lat) are not
exact since the second derivative (the leading truncation error) is
non-zero.
Signed areas in 2-D help ensure that we don't have false positives.
Since uxarray ensures consistent winding direction among elements, this
is a safe change to make that also helps prevent edge cases of finding
points in a cell that are not actually in the cell.
I suspect a library under the hood (a uxarray dependency) changed
causing a change in the output of the delaunay triangulation. Note that
delaunay triangulations are not unique (there is more than one possible
triangulation possible).
@fluidnumerics-joe fluidnumerics-joe changed the title [DRAFT] Feature/from icon Feature/from icon Jan 9, 2026
@fluidnumerics-joe fluidnumerics-joe marked this pull request as ready for review January 9, 2026 00:49
Copy link
Member

@erikvansebille erikvansebille left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice PR; looks great! A few small comments/suggestions below


def from_fesom2(ds: ux.UxDataset):
"""Create a FieldSet from a FESOM2 uxarray.UxDataset.
def from_uxdataset(ds: ux.UxDataset, mesh: str = "spherical"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call this from_ux_conventions(), to stay aligned with the from_sgrid_conventions() for Xgrid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll leave that up to you and @VeckoTheGecko what you want to call this.

When writing this, I chose this name because a UxDataset object is used to create the fieldset. Aside from vertical grid variable names (which are not part of UGrid convention), a UxDataset implicitly abides by the UGrid conventions.


return FieldSet(list(fields.values()))

def from_fesom2(ds: ux.UxDataset, mesh: str = "spherical"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine for now, but this code could;d later be moved to the convert class, when @VeckoTheGecko is done with his PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agreed


return FieldSet.from_uxdataset(ds, mesh=mesh)

def from_icon(ds: ux.UxDataset, mesh: str = "spherical"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also go to the convert class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I think a follow up PR here would be useful. I'm going to look at metadata, per @VeckoTheGecko 's suggestion. I have thoughts on this after reading through the UGrid conventions, but I'll save that for another issue

Comment on lines +627 to +629
logger.warning(
f"Interpolator not found for UxDataArray {da.name} with spatial dimensions {da_spatial_dims}. Setting default interpolator to ZeroInterpolator"
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I like this choice of ZeroInterpolator as default. If users don't pay attention to this warning, they will end up with zeros for all the fields, which will surprise them a lot

What about simply raising an error when we can't select an Interpolator? With some suggestions how users could fix it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this too.

There's another set of possible field placements that we don't currently have default interpolators for. If folks are using ICON on native locations the lateral velocity field components would be on edge centers (and would be oriented across edge normals).

I would want to allow folks who want to start there to be able to use the from_icon method and not error out. Perhaps they're looking to provide their own interpolator.

If users don't pay attention to warnings, then I suppose it's part of the learning process?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, fair enough that a warning is apt. But would the original return None then not be a better solution, since that will at least break any pset.execute()? Or does returning None here already throw errors in the fieldset creation?



def UxPiecewiseConstantFace(
def UxConstantFaceConstantZC(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not in this PR< but should we soon(ish) start to separate all the interpolators into multiple files? (under a directory interpolators/)

Because this file will become very large...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so.

Comment on lines -21 to +22
"UxPiecewiseConstantFace",
"UxPiecewiseLinearNode",
"UxConstantFaceConstantZC",
"UxLinearNodeLinearZF",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also include the two others? SO that you have all four Ux* interpolators here?

Comment on lines +189 to +194
ds = ds.rename(
{
"nz": "zf", # Vertical Interface
"nz1": "zc", # Vertical Center
}
).set_index(zf="zf", zc="zc")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be done in the datasets_unstructured["fesom2_square_delaunay_uniform_z_coordinate"] itself? is there a reason to change these dimensions here in the test?

Copy link
Contributor Author

@fluidnumerics-joe fluidnumerics-joe Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is to mimic what it would look like coming from fesom2 in the generic dataset

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, I could have one of the generic datasets come in with the expected vertical grid names, and have separate equivalents for FESOM2 and ICON. In the test_field.py tests, we could just use the generic dataset that uses the expected vertical coordinate names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would then not use any of the fesom or icon data in test_field.. the model specific generics would then be tested in the relevant field set and particleset tests we have

Comment on lines +241 to +248
ds = datasets_unstructured["stommel_gyre_delaunay"].copy(deep=True)
ds = ds.rename(
{
"nz": "zf", # Vertical Interface
"nz1": "zc", # Vertical Center
}
).set_index(zf="zf", zc="zc")
grid = UxGrid(ds.uxgrid, z=ds.coords["zf"], mesh="flat")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as comment above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same response as above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Add support for ICON model output

3 participants