@@ -96,15 +96,107 @@ def test_grid_with_holes():
9696 assert grid_without_holes .global_sphere_coverage
9797
9898
99- def test_grid_to_xarray ():
100- """Reads a ugrid file and encodes it as `xarray.Dataset` in various types."""
101- grid_CSne30 .to_xarray ("UGRID" )
102- grid_RLL1deg .to_xarray ("UGRID" )
103- grid_RLL10deg_CSne4 .to_xarray ("UGRID" )
104-
105- grid_CSne30 .to_xarray ("Exodus" )
106- grid_RLL1deg .to_xarray ("Exodus" )
107- grid_RLL10deg_CSne4 .to_xarray ("Exodus" )
99+ def test_grid_ugrid_exodus_roundtrip ():
100+ """Test round-trip serialization of grid objects through UGRID and Exodus xarray formats.
101+
102+ Validates that grid objects can be successfully converted to xarray.Dataset
103+ objects in both UGRID and Exodus formats, serialized to disk, and reloaded
104+ while maintaining numerical accuracy and topological integrity.
105+
106+ The test verifies:
107+ - Successful conversion to UGRID and Exodus xarray formats
108+ - File I/O round-trip consistency
109+ - Preservation of face-node connectivity (exact)
110+ - Preservation of node coordinates (within numerical tolerance)
111+
112+ Raises:
113+ AssertionError: If any round-trip validation fails
114+ """
115+
116+ # Convert grids to xarray.Dataset objects in different formats
117+ ugrid_datasets = {
118+ 'CSne30' : grid_CSne30 .to_xarray ("UGRID" ),
119+ 'RLL1deg' : grid_RLL1deg .to_xarray ("UGRID" ),
120+ 'RLL10deg_CSne4' : grid_RLL10deg_CSne4 .to_xarray ("UGRID" )
121+ }
122+
123+ exodus_datasets = {
124+ 'CSne30' : grid_CSne30 .to_xarray ("Exodus" ),
125+ 'RLL1deg' : grid_RLL1deg .to_xarray ("Exodus" ),
126+ 'RLL10deg_CSne4' : grid_RLL10deg_CSne4 .to_xarray ("Exodus" )
127+ }
128+
129+ # Define test cases with corresponding grid objects
130+ test_grids = {
131+ 'CSne30' : grid_CSne30 ,
132+ 'RLL1deg' : grid_RLL1deg ,
133+ 'RLL10deg_CSne4' : grid_RLL10deg_CSne4
134+ }
135+
136+ # Perform round-trip validation for each grid type
137+ test_files = []
138+
139+ for grid_name in test_grids .keys ():
140+ ugrid_dataset = ugrid_datasets [grid_name ]
141+ exodus_dataset = exodus_datasets [grid_name ]
142+ original_grid = test_grids [grid_name ]
143+
144+ # Define output file paths
145+ ugrid_filepath = f"test_ugrid_{ grid_name } .nc"
146+ exodus_filepath = f"test_exodus_{ grid_name } .exo"
147+
148+ # Serialize datasets to disk
149+ ugrid_dataset .to_netcdf (ugrid_filepath )
150+ exodus_dataset .to_netcdf (exodus_filepath )
151+
152+ # Reload grids from serialized files
153+ reloaded_ugrid = ux .open_grid (ugrid_filepath )
154+ reloaded_exodus = ux .open_grid (exodus_filepath )
155+
156+ # Validate topological consistency (face-node connectivity)
157+ # Integer connectivity arrays must be exactly preserved
158+ np .testing .assert_array_equal (
159+ original_grid .face_node_connectivity .values ,
160+ reloaded_ugrid .face_node_connectivity .values ,
161+ err_msg = f"UGRID face connectivity mismatch for { grid_name } "
162+ )
163+ np .testing .assert_array_equal (
164+ original_grid .face_node_connectivity .values ,
165+ reloaded_exodus .face_node_connectivity .values ,
166+ err_msg = f"Exodus face connectivity mismatch for { grid_name } "
167+ )
168+
169+ # Validate coordinate consistency with numerical tolerance
170+ # Coordinate transformations and I/O precision may introduce minor differences
171+ np .testing .assert_allclose (
172+ original_grid .node_lon .values ,
173+ reloaded_ugrid .node_lon .values ,
174+ err_msg = f"UGRID longitude mismatch for { grid_name } " ,
175+ rtol = ERROR_TOLERANCE
176+ )
177+ np .testing .assert_allclose (
178+ original_grid .node_lon .values ,
179+ reloaded_exodus .node_lon .values ,
180+ err_msg = f"Exodus longitude mismatch for { grid_name } " ,
181+ rtol = ERROR_TOLERANCE
182+ )
183+ np .testing .assert_allclose (
184+ original_grid .node_lat .values ,
185+ reloaded_ugrid .node_lat .values ,
186+ err_msg = f"UGRID latitude mismatch for { grid_name } " ,
187+ rtol = ERROR_TOLERANCE
188+ )
189+ np .testing .assert_allclose (
190+ original_grid .node_lat .values ,
191+ reloaded_exodus .node_lat .values ,
192+ err_msg = f"Exodus latitude mismatch for { grid_name } " ,
193+ rtol = ERROR_TOLERANCE
194+ )
195+
196+ # Clean up temporary test files
197+ for filepath in test_files :
198+ if os .path .exists (filepath ):
199+ os .remove (filepath )
108200
109201
110202def test_grid_init_verts ():
0 commit comments