Skip to content

Commit 36108f3

Browse files
completion and clean up of assign_ugrid_topology
- adding a option to run (or not) the tests that require AWS access. : add --online to the pytest command to run them
1 parent 2c3f53c commit 36108f3

File tree

16 files changed

+15702
-23614
lines changed

16 files changed

+15702
-23614
lines changed
Binary file not shown.
Binary file not shown.
67.7 KB
Binary file not shown.
47.1 KB
Binary file not shown.
Binary file not shown.

docs/examples/roms-compare.ipynb

Lines changed: 52 additions & 8470 deletions
Large diffs are not rendered by default.

docs/examples/roms.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7485,7 +7485,7 @@
74857485
"name": "python",
74867486
"nbconvert_exporter": "python",
74877487
"pygments_lexer": "ipython3",
7488-
"version": "3.10.13"
7488+
"version": "3.12.3"
74897489
}
74907490
},
74917491
"nbformat": 4,

pixi.lock

Lines changed: 15337 additions & 14995 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ dependencies = [
3333
"numpy",
3434
"xarray>=2023.10.0",
3535
"cf_xarray",
36+
"cftime",
3637
"dask[complete]",
3738
"netcdf4",
3839
]
@@ -131,7 +132,7 @@ sphinx-rtd-theme = "*"
131132

132133
[tool.pixi.feature.dev.tasks]
133134
lint = "ruff check"
134-
test = "pytest tests/"
135+
test = "pytest --online tests/"
135136

136137
[tool.pixi.feature.examples.dependencies]
137138
matplotlib = "*"

tests/conftest.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# conftest: some configuration for the tests
2+
3+
import pytest
4+
5+
6+
def pytest_addoption(parser):
7+
# put a @pytest.mark.online decorator on tests that require net access
8+
parser.addoption(
9+
"--online",
10+
action="store_true", # what is this?
11+
default=False,
12+
help="run tests that access AWS resources - have to be online",
13+
)
14+
15+
16+
def pytest_configure(config):
17+
# register an additional marker
18+
config.addinivalue_line(
19+
"markers",
20+
"online: mark test to run only when online (using AWS resources)"
21+
)
22+
23+
24+
def pytest_collection_modifyitems(config, items):
25+
if not config.getoption("--online"):
26+
# --online not given in cli: skip tests that require online access
27+
skip_online = pytest.mark.skip(reason="need --online option to run")
28+
for item in items:
29+
if "online" in item.keywords:
30+
item.add_marker(skip_online)
31+
32+
33+
# # example from docs
34+
# def pytest_runtest_setup(item):
35+
# envnames = [mark.args[0] for mark in item.iter_markers(name="env")]
36+
# if envnames:
37+
# if item.config.getoption("-E") not in envnames:
38+
# pytest.skip(f"test requires env in {envnames!r}")

tests/test_grids/test_sgrid.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import fsspec
44
import numpy as np
5+
import pytest
56
import xarray as xr
67

78
import xarray_subset_grid.accessor # noqa: F401
@@ -13,10 +14,14 @@
1314
test_dir = get_test_file_dir()
1415
sample_sgrid_file = os.path.join(test_dir, 'arakawa_c_test_grid.nc')
1516

17+
@pytest.mark.online
1618
def test_polygon_subset():
1719
'''
1820
This is a basic integration test for the subsetting of a ROMS sgrid dataset using a polygon.
1921
'''
22+
if fsspec is None:
23+
raise ImportError("Must have fsspec installed to run --online tests")
24+
2025
fs = fsspec.filesystem(
2126
"reference",
2227
fo="s3://nextgen-dmac-cloud-ingest/nos/wcofs/nos.wcofs.2ds.best.nc.zarr",

tests/test_grids/test_ugrid.py

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
from pathlib import Path
66

7-
import fsspec
7+
try:
8+
import fsspec
9+
except ImportError:
10+
fsspec = None
811
import numpy as np
912
import pytest
1013
import xarray as xr
@@ -216,17 +219,13 @@
216219
int cell(nele) ;
217220
cell:standard_name = "cell number" ;
218221
cell:long_name = "Mapping to original mesh cell number" ;
219-
220-
221-
222-
223222
"""
224223

225224
# topology for TEST_FILE1
226225
grid_topology = {
227-
"node_coordinates": ("lon", "lat"),
226+
"node_coordinates": "lon lat",
228227
"face_node_connectivity": "nv",
229-
"face_coordinates": ("lonc", "latc"),
228+
"face_coordinates": "lonc latc",
230229
"face_face_connectivity": "nbe",
231230
}
232231

@@ -394,6 +393,55 @@ def test_data_vars():
394393
]
395394
)
396395

396+
def test_assign_ugrid_topology_all():
397+
"""
398+
it should use all the ones you pass in.
399+
400+
# The existing one in the file:
401+
402+
int mesh ;
403+
mesh:cf_role = "mesh_topology" ;
404+
mesh:long_name = "Topology data of 2D unstructured mesh" ;
405+
mesh:topology_dimension = 2LL ;
406+
mesh:node_coordinates = "mesh_node_lon mesh_node_lat" ;
407+
mesh:edge_node_connectivity = "mesh_edge_nodes" ;
408+
mesh:edge_coordinates = "mesh_edge_lon mesh_edge_lat" ;
409+
mesh:face_node_connectivity = "mesh_face_nodes" ;
410+
mesh:face_coordinates = "mesh_face_lon mesh_face_lat" ;
411+
mesh:face_face_connectivity = "mesh_face_links" ;
412+
mesh:boundary_node_connectivity = "mesh_boundary_nodes" ;
413+
"""
414+
415+
ds = xr.open_dataset(EXAMPLE_DATA / "small_ugrid_zero_based.nc")
416+
417+
new_attrs = {}
418+
# clear out most of the mesh variable -- transfer to new attrs
419+
mesh_attrs = ds['mesh'].attrs
420+
for key in tuple(mesh_attrs.keys()):
421+
if key not in {"cf_role", "long_name", "topology_dimension"}:
422+
new_attrs[key] = mesh_attrs.pop(key)
423+
424+
# new_attrs = {"node_coordinates": "nc",
425+
# "face_coordinates": "fc",
426+
# "edge_coordinates": "ec",
427+
# "face_node_connectivity": "fnc",
428+
# "face_face_connectivity": "ffc",
429+
# "boundary_node_connectivity": "bnc",
430+
# "face_edge_connectivity": "fec",
431+
# "edge_face_connectivity": "efc",
432+
# "edge_node_connectivity": "enc",
433+
# }
434+
435+
# ds_new = ugrid.assign_ugrid_topology(ds,
436+
# face_node_connectivity="mesh_face_nodes",
437+
# boundary_node_connectivity="bounds")
438+
439+
ds_new = ugrid.assign_ugrid_topology(ds, **new_attrs)
440+
441+
print(ds_new["mesh"].attrs)
442+
for key, value in new_attrs.items():
443+
assert ds_new["mesh"].attrs[key] == value
444+
397445

398446
def test_extra_vars():
399447
"""
@@ -466,8 +514,10 @@ def test_vertical_levels():
466514
"node",
467515
)
468516

469-
517+
@pytest.mark.online
470518
def test_3d_selector():
519+
if fsspec is None:
520+
raise ImportError("Must have fsspec installed to run --online tests")
471521
bbox = (-70, 40, -60, 55)
472522
name = "northeastUSA3d"
473523

@@ -489,7 +539,10 @@ def test_3d_selector():
489539
assert bbox_selector == loaded_selector
490540

491541

542+
@pytest.mark.online
492543
def test_2d_selector():
544+
if fsspec is None:
545+
raise ImportError("Must have fsspec installed to run --online tests")
493546
bbox = (-70, 40, -60, 50)
494547
name = "northeastUSA2d"
495548

tests/test_visualization/test_mpl_plotting.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
try:
1515
import matplotlib.pyplot as plt
1616

17-
from xarray_subset_grid.visualization.mpl_plotting import plot_ugrid
17+
from xarray_subset_grid.visualization.mpl_plotting import plot_ugrid, plot_sgrid
1818
except ImportError:
1919
pytestmark = pytest.mark.skip(reason="matplotlib is not installed")
2020

@@ -62,3 +62,21 @@ def test_plot_ugrid_start_index_1():
6262
plot_ugrid(axis, ds)
6363

6464
fig.savefig(OUTPUT_DIR / "ugrid_plot_start_index_1")
65+
66+
67+
#############
68+
# SGRID tests
69+
#############
70+
71+
def test_plot_sgrid_only_grid():
72+
import cftime
73+
ds = xr.open_dataset(EXAMPLE_DATA / "wcofs_small_subset.nc")
74+
75+
fig, axis = plt.subplots()
76+
77+
plot_sgrid(axis, ds)
78+
79+
fig.savefig(OUTPUT_DIR / "sgrid_just_plot")
80+
81+
82+

xarray_subset_grid/grids/fvcom_grid.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ def subset_bottom_level(self, ds: xr.Dataset) -> xr.Dataset:
4242
if "siglay" in ds.dims:
4343
siglay = ds["siglay"].isel(node=0)
4444
if positive_direction == "up":
45-
elevation_index = siglay.argmin().values
45+
elevation_index = siglay.argmin(axis=0).values
4646
else:
47-
elevation_index = siglay.argmax().values
47+
elevation_index = siglay.argmax(axis=0).values
4848
selections["siglay"] = elevation_index
4949
if "siglev" in ds.dims:
5050
siglev = ds["siglev"].isel(node=0)
5151
if positive_direction == "up":
52-
elevation_index = siglev.argmin().values
52+
elevation_index = siglev.argmin(axis=0).values
5353
else:
54-
elevation_index = siglev.argmax().values
54+
elevation_index = siglev.argmax(axis=0).values
5555
selections["siglev"] = elevation_index
5656

5757
return ds.isel(selections)
@@ -66,16 +66,16 @@ def subset_top_level(self, ds: xr.Dataset) -> xr.Dataset:
6666
if "siglay" in ds.dims:
6767
siglay = ds["siglay"].isel(node=0)
6868
if positive_direction == "up":
69-
elevation_index = siglay.argmax().values
69+
elevation_index = siglay.argmax(axis=0).values
7070
else:
71-
elevation_index = siglay.argmin().values
71+
elevation_index = siglay.argmin(axis=0).values
7272
selections["siglay"] = elevation_index
7373
if "siglev" in ds.dims:
7474
siglev = ds["siglev"].isel(node=0)
7575
if positive_direction == "up":
76-
elevation_index = siglev.argmax().values
76+
elevation_index = siglev.argmax(axis=0).values
7777
else:
78-
elevation_index = siglev.argmin().values
78+
elevation_index = siglev.argmin(axis=0).values
7979
selections["siglev"] = elevation_index
8080

8181
return ds.isel(selections)
@@ -96,11 +96,11 @@ def subset_vertical_level(
9696
selections = {}
9797
if "siglay" in ds.dims:
9898
siglay = ds["siglay"].isel(node=0)
99-
elevation_index = int(np.absolute(siglay - level).argmin().values)
99+
elevation_index = int(np.absolute(siglay - level).argmin(axis=0).values)
100100
selections["siglay"] = elevation_index
101101
if "siglev" in ds.dims:
102102
siglev = ds["siglev"].isel(node=0)
103-
elevation_index = int(np.absolute(siglev - level).argmin().values)
103+
elevation_index = int(np.absolute(siglev - level).argmin(axis=0).values)
104104
selections["siglev"] = elevation_index
105105

106106
return ds.isel(selections)
@@ -127,12 +127,12 @@ def subset_vertical_levels(
127127
if "siglay" in ds.dims:
128128
siglay = ds["siglay"].isel(node=0)
129129
elevation_indexes = [
130-
int(np.absolute(siglay - level).argmin().values) for level in levels
130+
int(np.absolute(siglay - level).argmin(axis=0).values) for level in levels
131131
]
132132
selections["siglay"] = slice(elevation_indexes[0], elevation_indexes[1])
133133
if "siglev" in ds.dims:
134134
siglev = ds["siglev"].isel(node=0)
135-
elevation_index = [int(np.absolute(siglev - level).argmin().values) for level in levels]
135+
elevation_index = [int(np.absolute(siglev - level).argmin(axis=0).values) for level in levels]
136136
selections["siglev"] = slice(elevation_index[0], elevation_index[1])
137137

138138
return ds.isel(selections)

0 commit comments

Comments
 (0)