Skip to content

Commit

Permalink
Merge branch 'main' into zedwick/subset_inverse_indices
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronzedwick authored Jan 2, 2025
2 parents 86cf568 + 7c4f3e1 commit fb173e5
Show file tree
Hide file tree
Showing 34 changed files with 4,390 additions and 6,054 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:

- name: Upload code coverage to Codecov
if: github.repository == 'UXARRAY/uxarray'
uses: codecov/codecov-action@v5.1.1
uses: codecov/codecov-action@v5.1.2
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.8.3
rev: v0.8.4
hooks:
# Run the linter.
- id: ruff
Expand Down
23 changes: 16 additions & 7 deletions benchmarks/mpas_ocean.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def time_inverse_distance_weighted_remapping(self):

class HoleEdgeIndices(DatasetBenchmark):
def time_construct_hole_edge_indices(self, resolution):
ux.grid.geometry._construct_hole_edge_indices(self.uxds.uxgrid.edge_face_connectivity)
ux.grid.geometry._construct_boundary_edge_indices(self.uxds.uxgrid.edge_face_connectivity)


class DualMesh(DatasetBenchmark):
Expand Down Expand Up @@ -167,10 +167,19 @@ def time_check_norm(self, resolution):
from uxarray.grid.validation import _check_normalization
_check_normalization(self.uxgrid)

class CrossSection:
param_names = DatasetBenchmark.param_names + ['lat_step']
params = DatasetBenchmark.params + [[1, 2, 4]]

class CrossSections(DatasetBenchmark):
param_names = DatasetBenchmark.param_names + ['n_lat']
params = DatasetBenchmark.params + [[1, 2, 4, 8]]
def time_constant_lat_fast(self, resolution, n_lat):
for lat in np.linspace(-89, 89, n_lat):
self.uxds.uxgrid.constant_latitude_cross_section(lat, method='fast')
def setup(self, resolution, lat_step):
self.uxgrid = ux.open_grid(file_path_dict[resolution][0])
self.uxgrid.normalize_cartesian_coordinates()
self.lats = np.arange(-45, 45, lat_step)
_ = self.uxgrid.bounds

def teardown(self, resolution, lat_step):
del self.uxgrid

def time_const_lat(self, resolution, lat_step):
for lat in self.lats:
self.uxgrid.cross_section.constant_latitude(lat)
179 changes: 81 additions & 98 deletions test/test_api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import os
from unittest import TestCase
from pathlib import Path
import numpy.testing as nt

import uxarray as ux
import xarray as xr
import numpy as np
import pytest

try:
import constants
Expand All @@ -14,126 +12,111 @@

current_path = Path(os.path.dirname(os.path.realpath(__file__)))

geoflow_data_path = current_path / "meshfiles" / "ugrid" / "geoflow-small"
gridfile_geoflow = current_path / "meshfiles" / "ugrid" / "geoflow-small" / "grid.nc"
geoflow_data_v1 = geoflow_data_path / "v1.nc"
geoflow_data_v2 = geoflow_data_path / "v2.nc"
geoflow_data_v3 = geoflow_data_path / "v3.nc"

class TestAPI(TestCase):
geoflow_data_path = current_path / "meshfiles" / "ugrid" / "geoflow-small"
gridfile_geoflow = current_path / "meshfiles" / "ugrid" / "geoflow-small" / "grid.nc"
geoflow_data_v1 = geoflow_data_path / "v1.nc"
geoflow_data_v2 = geoflow_data_path / "v2.nc"
geoflow_data_v3 = geoflow_data_path / "v3.nc"

gridfile_ne30 = current_path / "meshfiles" / "ugrid" / "outCSne30" / "outCSne30.ug"
dsfile_var2_ne30 = current_path / "meshfiles" / "ugrid" / "outCSne30" / "outCSne30_var2.nc"
dsfiles_mf_ne30 = str(
current_path) + "/meshfiles/ugrid/outCSne30/outCSne30_*.nc"

def test_open_geoflow_dataset(self):
"""Loads a single dataset with its grid topology file using uxarray's
open_dataset call."""
gridfile_ne30 = current_path / "meshfiles" / "ugrid" / "outCSne30" / "outCSne30.ug"
dsfile_var2_ne30 = current_path / "meshfiles" / "ugrid" / "outCSne30" / "outCSne30_var2.nc"
dsfiles_mf_ne30 = str(current_path) + "/meshfiles/ugrid/outCSne30/outCSne30_*.nc"

# Paths to Data Variable files
data_paths = [
self.geoflow_data_v1, self.geoflow_data_v2, self.geoflow_data_v3
]
def test_open_geoflow_dataset():
"""Loads a single dataset with its grid topology file using uxarray's
open_dataset call."""

uxds_v1 = ux.open_dataset(self.gridfile_geoflow, data_paths[0])
# Paths to Data Variable files
data_paths = [
geoflow_data_v1, geoflow_data_v2, geoflow_data_v3
]

# Ideally uxds_v1.uxgrid should NOT be None
with self.assertRaises(AssertionError):
nt.assert_equal(uxds_v1.uxgrid, None)
uxds_v1 = ux.open_dataset(gridfile_geoflow, data_paths[0])

def test_open_dataset(self):
"""Loads a single dataset with its grid topology file using uxarray's
open_dataset call."""
# Ideally uxds_v1.uxgrid should NOT be None
nt.assert_equal(uxds_v1.uxgrid is not None, True)

uxds_var2_ne30 = ux.open_dataset(self.gridfile_ne30,
self.dsfile_var2_ne30)
def test_open_dataset():
"""Loads a single dataset with its grid topology file using uxarray's
open_dataset call."""

nt.assert_equal(uxds_var2_ne30.uxgrid.node_lon.size,
constants.NNODES_outCSne30)
nt.assert_equal(len(uxds_var2_ne30.uxgrid._ds.data_vars),
constants.DATAVARS_outCSne30)
nt.assert_equal(uxds_var2_ne30.source_datasets,
str(self.dsfile_var2_ne30))
uxds_var2_ne30 = ux.open_dataset(gridfile_ne30, dsfile_var2_ne30)

def test_open_mf_dataset(self):
"""Loads multiple datasets with their grid topology file using
uxarray's open_dataset call."""
nt.assert_equal(uxds_var2_ne30.uxgrid.node_lon.size, constants.NNODES_outCSne30)
nt.assert_equal(len(uxds_var2_ne30.uxgrid._ds.data_vars), constants.DATAVARS_outCSne30)
nt.assert_equal(uxds_var2_ne30.source_datasets, str(dsfile_var2_ne30))

uxds_mf_ne30 = ux.open_mfdataset(self.gridfile_ne30,
self.dsfiles_mf_ne30)
def test_open_mf_dataset():
"""Loads multiple datasets with their grid topology file using
uxarray's open_dataset call."""

nt.assert_equal(uxds_mf_ne30.uxgrid.node_lon.size,
constants.NNODES_outCSne30)
nt.assert_equal(len(uxds_mf_ne30.uxgrid._ds.data_vars),
constants.DATAVARS_outCSne30)
uxds_mf_ne30 = ux.open_mfdataset(gridfile_ne30, dsfiles_mf_ne30)

nt.assert_equal(uxds_mf_ne30.source_datasets, self.dsfiles_mf_ne30)
nt.assert_equal(uxds_mf_ne30.uxgrid.node_lon.size, constants.NNODES_outCSne30)
nt.assert_equal(len(uxds_mf_ne30.uxgrid._ds.data_vars), constants.DATAVARS_outCSne30)
nt.assert_equal(uxds_mf_ne30.source_datasets, dsfiles_mf_ne30)

def test_open_grid(self):
"""Loads only a grid topology file using uxarray's open_grid call."""
uxgrid = ux.open_grid(self.gridfile_geoflow)
def test_open_grid():
"""Loads only a grid topology file using uxarray's open_grid call."""
uxgrid = ux.open_grid(gridfile_geoflow)

nt.assert_almost_equal(uxgrid.calculate_total_face_area(),
constants.MESH30_AREA,
decimal=3)
nt.assert_almost_equal(uxgrid.calculate_total_face_area(), constants.MESH30_AREA, decimal=3)

def test_copy_dataset(self):
"""Loads a single dataset with its grid topology file using uxarray's
open_dataset call and make a copy of the object."""
def test_copy_dataset():
"""Loads a single dataset with its grid topology file using uxarray's
open_dataset call and make a copy of the object."""

uxds_var2_ne30 = ux.open_dataset(self.gridfile_ne30,
self.dsfile_var2_ne30)
uxds_var2_ne30 = ux.open_dataset(gridfile_ne30, dsfile_var2_ne30)

# make a shallow and deep copy of the dataset object
uxds_var2_ne30_copy_deep = uxds_var2_ne30.copy(deep=True)
uxds_var2_ne30_copy = uxds_var2_ne30.copy(deep=False)
# make a shallow and deep copy of the dataset object
uxds_var2_ne30_copy_deep = uxds_var2_ne30.copy(deep=True)
uxds_var2_ne30_copy = uxds_var2_ne30.copy(deep=False)

# Ideally uxds_var2_ne30_copy.uxgrid should NOT be None
with self.assertRaises(AssertionError):
nt.assert_equal(uxds_var2_ne30_copy.uxgrid, None)
# Ideally uxds_var2_ne30_copy.uxgrid should NOT be None
nt.assert_equal(uxds_var2_ne30_copy.uxgrid is not None, True)

# Check that the copy is a shallow copy
assert (uxds_var2_ne30_copy.uxgrid is uxds_var2_ne30.uxgrid)
assert (uxds_var2_ne30_copy.uxgrid == uxds_var2_ne30.uxgrid)
# Check that the copy is a shallow copy
assert uxds_var2_ne30_copy.uxgrid is uxds_var2_ne30.uxgrid
assert uxds_var2_ne30_copy.uxgrid == uxds_var2_ne30.uxgrid

# Check that the deep copy is a deep copy
assert (uxds_var2_ne30_copy_deep.uxgrid == uxds_var2_ne30.uxgrid)
assert (uxds_var2_ne30_copy_deep.uxgrid is not uxds_var2_ne30.uxgrid)
# Check that the deep copy is a deep copy
assert uxds_var2_ne30_copy_deep.uxgrid == uxds_var2_ne30.uxgrid
assert uxds_var2_ne30_copy_deep.uxgrid is not uxds_var2_ne30.uxgrid

def test_copy_dataarray(self):
"""Loads an unstructured grid and data using uxarray's open_dataset
call and make a copy of the dataarray object."""
def test_copy_dataarray():
"""Loads an unstructured grid and data using uxarray's open_dataset
call and make a copy of the dataarray object."""

# Paths to Data Variable files
data_paths = [
self.geoflow_data_v1, self.geoflow_data_v2, self.geoflow_data_v3
]
# Paths to Data Variable files
data_paths = [
geoflow_data_v1, geoflow_data_v2, geoflow_data_v3
]

uxds_v1 = ux.open_dataset(self.gridfile_geoflow, data_paths[0])
uxds_v1 = ux.open_dataset(gridfile_geoflow, data_paths[0])

# get the uxdataarray object
v1_uxdata_array = uxds_v1['v1']
# get the uxdataarray object
v1_uxdata_array = uxds_v1['v1']

# make a shallow and deep copy of the dataarray object
v1_uxdata_array_copy_deep = v1_uxdata_array.copy(deep=True)
v1_uxdata_array_copy = v1_uxdata_array.copy(deep=False)
# make a shallow and deep copy of the dataarray object
v1_uxdata_array_copy_deep = v1_uxdata_array.copy(deep=True)
v1_uxdata_array_copy = v1_uxdata_array.copy(deep=False)

# Check that the copy is a shallow copy
assert (v1_uxdata_array_copy.uxgrid is v1_uxdata_array.uxgrid)
assert (v1_uxdata_array_copy.uxgrid == v1_uxdata_array.uxgrid)
# Check that the copy is a shallow copy
assert v1_uxdata_array_copy.uxgrid is v1_uxdata_array.uxgrid
assert v1_uxdata_array_copy.uxgrid == v1_uxdata_array.uxgrid

# Check that the deep copy is a deep copy
assert (v1_uxdata_array_copy_deep.uxgrid == v1_uxdata_array.uxgrid)
assert (v1_uxdata_array_copy_deep.uxgrid is not v1_uxdata_array.uxgrid)
# Check that the deep copy is a deep copy
assert v1_uxdata_array_copy_deep.uxgrid == v1_uxdata_array.uxgrid
assert v1_uxdata_array_copy_deep.uxgrid is not v1_uxdata_array.uxgrid

def test_open_dataset_grid_kwargs(self):
"""Drops ``Mesh2_face_nodes`` from the inputted grid file using
``grid_kwargs``"""
def test_open_dataset_grid_kwargs():
"""Drops ``Mesh2_face_nodes`` from the inputted grid file using
``grid_kwargs``"""

with self.assertRaises(ValueError):
# attempt to open a dataset after dropping face nodes should raise a KeyError
uxds = ux.open_dataset(
self.gridfile_ne30,
self.dsfile_var2_ne30,
grid_kwargs={"drop_variables": "Mesh2_face_nodes"})
with pytest.raises(ValueError):
# attempt to open a dataset after dropping face nodes should raise a KeyError
uxds = ux.open_dataset(
gridfile_ne30,
dsfile_var2_ne30,
grid_kwargs={"drop_variables": "Mesh2_face_nodes"}
)
Loading

0 comments on commit fb173e5

Please sign in to comment.