|
6 | 6 | import xarray as xr |
7 | 7 | import pandas as pd |
8 | 8 | from pathlib import Path |
| 9 | +from uxarray.constants import ERROR_TOLERANCE |
9 | 10 |
|
10 | 11 |
|
11 | 12 | current_path = Path(os.path.dirname(os.path.realpath(__file__))) |
@@ -100,35 +101,88 @@ def test_invalid_cells(): |
100 | 101 | with pytest.raises(ValueError): |
101 | 102 | uxda = ux.UxDataset.from_healpix(xrda) |
102 | 103 |
|
103 | | -def test_healpix_to_netcdf(tmp_path): |
104 | | - """Test that HEALPix grid can be encoded as UGRID and saved to netCDF. |
105 | | - Using pytest tmp_path fixture to create a temporary file. |
| 104 | +def test_healpix_round_trip_consistency(tmp_path): |
| 105 | + """Test round-trip serialization of HEALPix grid through UGRID and Exodus formats. |
| 106 | +
|
| 107 | + Validates that HEALPix grid objects can be successfully converted to xarray.Dataset |
| 108 | + objects in both UGRID and Exodus formats, serialized to disk, and reloaded |
| 109 | + while maintaining numerical accuracy and topological integrity. |
| 110 | +
|
| 111 | + Args: |
| 112 | + tmp_path: pytest fixture providing temporary directory |
| 113 | +
|
| 114 | + Raises: |
| 115 | + AssertionError: If any round-trip validation fails |
106 | 116 | """ |
107 | 117 | # Create HEALPix grid |
108 | | - h = ux.Grid.from_healpix(zoom=3) |
| 118 | + original_grid = ux.Grid.from_healpix(zoom=3) |
109 | 119 |
|
110 | 120 | # Access node coordinates to ensure they're generated before encoding |
111 | | - _ = h.node_lon |
112 | | - _ = h.node_lat |
113 | | - |
114 | | - # Convert to different formats |
115 | | - uxa_ugrid = h.to_xarray("UGRID") |
116 | | - uxa_exodus = h.to_xarray("Exodus") |
117 | | - |
118 | | - tmp_filename_ugrid = tmp_path / "healpix_test_ugrid.nc" |
119 | | - tmp_filename_exodus = tmp_path / "healpix_test_exodus.exo" |
120 | | - |
121 | | - # Save to netCDF |
122 | | - uxa_ugrid.to_netcdf(tmp_filename_ugrid) |
123 | | - uxa_exodus.to_netcdf(tmp_filename_exodus) |
124 | | - |
125 | | - # Assertions |
126 | | - assert tmp_filename_ugrid.exists() |
127 | | - assert tmp_filename_ugrid.stat().st_size > 0 |
128 | | - assert tmp_filename_exodus.exists() |
129 | | - assert tmp_filename_exodus.stat().st_size > 0 |
130 | | - |
131 | | - loaded_grid_ugrid = ux.open_grid(tmp_filename_ugrid) |
132 | | - loaded_grid_exodus = ux.open_grid(tmp_filename_exodus) |
133 | | - assert loaded_grid_ugrid.n_face == h.n_face |
134 | | - assert loaded_grid_exodus.n_face == h.n_face |
| 121 | + _ = original_grid.node_lon |
| 122 | + _ = original_grid.node_lat |
| 123 | + |
| 124 | + # Convert to xarray.Dataset objects in different formats |
| 125 | + ugrid_dataset = original_grid.to_xarray("UGRID") |
| 126 | + exodus_dataset = original_grid.to_xarray("Exodus") |
| 127 | + |
| 128 | + # Define output file paths using tmp_path fixture |
| 129 | + ugrid_filepath = tmp_path / "healpix_test_ugrid.nc" |
| 130 | + exodus_filepath = tmp_path / "healpix_test_exodus.exo" |
| 131 | + |
| 132 | + # Serialize datasets to disk |
| 133 | + ugrid_dataset.to_netcdf(ugrid_filepath) |
| 134 | + exodus_dataset.to_netcdf(exodus_filepath) |
| 135 | + |
| 136 | + # Verify files were created successfully |
| 137 | + assert ugrid_filepath.exists() |
| 138 | + assert ugrid_filepath.stat().st_size > 0 |
| 139 | + assert exodus_filepath.exists() |
| 140 | + assert exodus_filepath.stat().st_size > 0 |
| 141 | + |
| 142 | + # Reload grids from serialized files |
| 143 | + reloaded_ugrid = ux.open_grid(ugrid_filepath) |
| 144 | + reloaded_exodus = ux.open_grid(exodus_filepath) |
| 145 | + |
| 146 | + # Validate topological consistency (face-node connectivity) |
| 147 | + # Integer connectivity arrays must be exactly preserved |
| 148 | + np.testing.assert_array_equal( |
| 149 | + original_grid.face_node_connectivity.values, |
| 150 | + reloaded_ugrid.face_node_connectivity.values, |
| 151 | + err_msg="UGRID face connectivity mismatch for HEALPix" |
| 152 | + ) |
| 153 | + np.testing.assert_array_equal( |
| 154 | + original_grid.face_node_connectivity.values, |
| 155 | + reloaded_exodus.face_node_connectivity.values, |
| 156 | + err_msg="Exodus face connectivity mismatch for HEALPix" |
| 157 | + ) |
| 158 | + |
| 159 | + # Validate coordinate consistency with numerical tolerance |
| 160 | + # Coordinate transformations and I/O precision may introduce minor differences |
| 161 | + np.testing.assert_allclose( |
| 162 | + original_grid.node_lon.values, |
| 163 | + reloaded_ugrid.node_lon.values, |
| 164 | + err_msg="UGRID longitude mismatch for HEALPix", |
| 165 | + rtol=ERROR_TOLERANCE |
| 166 | + ) |
| 167 | + np.testing.assert_allclose( |
| 168 | + original_grid.node_lon.values, |
| 169 | + reloaded_exodus.node_lon.values, |
| 170 | + err_msg="Exodus longitude mismatch for HEALPix", |
| 171 | + rtol=ERROR_TOLERANCE |
| 172 | + ) |
| 173 | + np.testing.assert_allclose( |
| 174 | + original_grid.node_lat.values, |
| 175 | + reloaded_ugrid.node_lat.values, |
| 176 | + err_msg="UGRID latitude mismatch for HEALPix", |
| 177 | + rtol=ERROR_TOLERANCE |
| 178 | + ) |
| 179 | + np.testing.assert_allclose( |
| 180 | + original_grid.node_lat.values, |
| 181 | + reloaded_exodus.node_lat.values, |
| 182 | + err_msg="Exodus latitude mismatch for HEALPix", |
| 183 | + rtol=ERROR_TOLERANCE |
| 184 | + ) |
| 185 | + |
| 186 | + # Validate grid dimensions are preserved |
| 187 | + assert reloaded_ugrid.n_face == original_grid.n_face |
| 188 | + assert reloaded_exodus.n_face == original_grid.n_face |
0 commit comments