Repository navigation
Uxgrid edge data interpolators #3012
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
Changes from all commits
1e3c1e7
1ff4756
f0bef68
c246eda
bd8832b
933a9e2
82a15bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,10 +13,13 @@ | |
| ) | ||
| from parcels._core.mesh import FlatMesh, SphericalMesh | ||
| from parcels._core.model import UnstructuredModelData | ||
| from parcels._datasets.unstructured.generated import sigma_coordinate_lattice_dataset | ||
| from parcels._datasets.unstructured.generated import sigma_coordinate_lattice_dataset, simple_small_delaunay | ||
| from parcels._datasets.unstructured.generic import datasets as datasets_unstructured | ||
| from parcels.interpolators import ( | ||
| UxConstantEdgeConstantZC, | ||
| UxConstantEdgeLinearZF, | ||
| UxConstantFaceConstantZC, | ||
| UxConstantFaceLinearZF, | ||
| UxLinearNodeConstantZC, | ||
| UxLinearNodeLinearZF, | ||
| ) | ||
|
|
@@ -156,6 +159,53 @@ def test_icon_evals(): | |
| assert np.allclose(fieldset.p.eval(t=tq, z=zq, y=yq, x=xq), zc * (xq + yq)) | ||
|
|
||
|
|
||
| def test_linear_edge_velocity_evals(): | ||
| ds = simple_small_delaunay() | ||
| xe = ds.uxgrid.edge_lon.values | ||
| ye = ds.uxgrid.edge_lat.values | ||
| for name, zdim, value in (("U", "zc", xe), ("V", "zc", ye), ("W", "zf", xe + ye)): | ||
| ds[name] = ux.UxDataArray( | ||
| np.full((ds.sizes["time"], ds.sizes[zdim], ds.uxgrid.n_edge), value), | ||
| dims=["time", zdim, "n_edge"], | ||
| coords={"time": ds.time, zdim: ds[zdim]}, | ||
| uxgrid=ds.uxgrid, | ||
| ) | ||
| fieldset = FieldSet.from_ugrid_conventions(ds) | ||
|
|
||
| xc = ds.uxgrid.face_lon.values | ||
| yc = ds.uxgrid.face_lat.values | ||
| zq = np.full(xc.shape, 300.0) | ||
| tq = np.zeros(xc.shape) | ||
|
|
||
| assert np.allclose(fieldset.U.eval(t=tq, z=zq, y=yc, x=xc), xc) | ||
| assert np.allclose(fieldset.V.eval(t=tq, z=zq, y=yc, x=xc), yc) | ||
| assert np.allclose(fieldset.W.eval(t=tq, z=zq, y=yc, x=xc), xc + yc) | ||
|
|
||
|
|
||
| def test_from_ugrid_conventions_selects_correct_interpolator(): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also add a test for correctness? E.g. with a simple field where you can calculate the answer by hand? So that we can make sure that the interpolator doesn't break in the future?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in 82a15bf. I also realized that none of the other UxGrid interpolators have testing for this kind of thing either. I'll open an issue on this tomorrow. |
||
| """Fields get the default interpolator that matches their vertical and lateral registration.""" | ||
| ds = convert.icon_to_ugrid(datasets_unstructured["icon_square_delaunay_uniform_z_coordinate"].copy(deep=True)) | ||
| expected_interpolators = { | ||
| ("zc", "n_face"): UxConstantFaceConstantZC, | ||
| ("zf", "n_face"): UxConstantFaceLinearZF, | ||
| ("zc", "n_node"): UxLinearNodeConstantZC, | ||
| ("zf", "n_node"): UxLinearNodeLinearZF, | ||
| ("zc", "n_edge"): UxConstantEdgeConstantZC, | ||
| ("zf", "n_edge"): UxConstantEdgeLinearZF, | ||
| } | ||
| for vertical_dim, lateral_dim in expected_interpolators: | ||
| ds[f"{lateral_dim}_{vertical_dim}"] = ux.UxDataArray( | ||
| np.ones((ds.sizes["time"], ds.sizes[vertical_dim], getattr(ds.uxgrid, lateral_dim))), | ||
| dims=["time", vertical_dim, lateral_dim], | ||
| coords={"time": ds.time, vertical_dim: ds[vertical_dim]}, | ||
| uxgrid=ds.uxgrid, | ||
| ) | ||
| fieldset = FieldSet.from_ugrid_conventions(ds) | ||
|
|
||
| for (vertical_dim, lateral_dim), expected_interpolator in expected_interpolators.items(): | ||
| assert isinstance(getattr(fieldset, f"{lateral_dim}_{vertical_dim}").interp_method, expected_interpolator) | ||
|
|
||
|
|
||
| _NESTEDGRIDS_NODES = np.array( | ||
| [ | ||
| [10.0, 15.0], | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is essentially piecewise constant ? What if I have an edge that is much shorter than the other 2 ? Is it's value as important as the others in constructing the value for the face ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that the centroid is the mean of the node locations. So this is just averaging to the centroid and then using piecewise constant. The default interpolator for
n_faceis also piecewise constant so I think this is fine for now.Long term it would be great to add more complex interpolation methods for unstructured grids, I'll open an issue on this?