uxarray 2026.3.0__tar.gz → 2026.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {uxarray-2026.3.0 → uxarray-2026.4.0}/PKG-INFO +1 -1
  2. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/dataset.py +20 -2
  3. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/utils.py +84 -21
  4. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray.egg-info/PKG-INFO +1 -1
  5. {uxarray-2026.3.0 → uxarray-2026.4.0}/.codecov.yml +0 -0
  6. {uxarray-2026.3.0 → uxarray-2026.4.0}/.git_archival.txt +0 -0
  7. {uxarray-2026.3.0 → uxarray-2026.4.0}/.gitattributes +0 -0
  8. {uxarray-2026.3.0 → uxarray-2026.4.0}/CITATION.cff +0 -0
  9. {uxarray-2026.3.0 → uxarray-2026.4.0}/CODE_OF_CONDUCT.md +0 -0
  10. {uxarray-2026.3.0 → uxarray-2026.4.0}/CONTRIBUTING.md +0 -0
  11. {uxarray-2026.3.0 → uxarray-2026.4.0}/INSTALLATION.md +0 -0
  12. {uxarray-2026.3.0 → uxarray-2026.4.0}/LICENSE +0 -0
  13. {uxarray-2026.3.0 → uxarray-2026.4.0}/MANIFEST.in +0 -0
  14. {uxarray-2026.3.0 → uxarray-2026.4.0}/README.md +0 -0
  15. {uxarray-2026.3.0 → uxarray-2026.4.0}/build.sh +0 -0
  16. {uxarray-2026.3.0 → uxarray-2026.4.0}/pyproject.toml +0 -0
  17. {uxarray-2026.3.0 → uxarray-2026.4.0}/setup.cfg +0 -0
  18. {uxarray-2026.3.0 → uxarray-2026.4.0}/setup.py +0 -0
  19. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/__init__.py +0 -0
  20. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/constants.py +0 -0
  21. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/conventions/__init__.py +0 -0
  22. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/conventions/descriptors.py +0 -0
  23. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/conventions/ugrid.py +0 -0
  24. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/__init__.py +0 -0
  25. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/accessors.py +0 -0
  26. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/aggregation.py +0 -0
  27. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/api.py +0 -0
  28. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/dataarray.py +0 -0
  29. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/gradient.py +0 -0
  30. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/utils.py +0 -0
  31. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/core/zonal.py +0 -0
  32. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/cross_sections/__init__.py +0 -0
  33. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/cross_sections/dataarray_accessor.py +0 -0
  34. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/cross_sections/grid_accessor.py +0 -0
  35. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/cross_sections/sample.py +0 -0
  36. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/formatting_html.py +0 -0
  37. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/__init__.py +0 -0
  38. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/arcs.py +0 -0
  39. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/area.py +0 -0
  40. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/bounds.py +0 -0
  41. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/connectivity.py +0 -0
  42. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/coordinates.py +0 -0
  43. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/dual.py +0 -0
  44. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/geometry.py +0 -0
  45. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/grid.py +0 -0
  46. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/integrate.py +0 -0
  47. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/intersections.py +0 -0
  48. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/neighbors.py +0 -0
  49. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/point_in_face.py +0 -0
  50. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/slice.py +0 -0
  51. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/utils.py +0 -0
  52. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/grid/validation.py +0 -0
  53. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/__init__.py +0 -0
  54. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_delaunay.py +0 -0
  55. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_esmf.py +0 -0
  56. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_exodus.py +0 -0
  57. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_fesom2.py +0 -0
  58. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_geopandas.py +0 -0
  59. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_geos.py +0 -0
  60. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_healpix.py +0 -0
  61. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_icon.py +0 -0
  62. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_mpas.py +0 -0
  63. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_scrip.py +0 -0
  64. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_structured.py +0 -0
  65. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_topology.py +0 -0
  66. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_ugrid.py +0 -0
  67. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_vertices.py +0 -0
  68. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/io/_voronoi.py +0 -0
  69. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/plot/__init__.py +0 -0
  70. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/plot/accessor.py +0 -0
  71. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/plot/constants.py +0 -0
  72. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/plot/matplotlib.py +0 -0
  73. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/plot/utils.py +0 -0
  74. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/remap/__init__.py +0 -0
  75. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/remap/accessor.py +0 -0
  76. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/remap/bilinear.py +0 -0
  77. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/remap/inverse_distance_weighted.py +0 -0
  78. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/remap/nearest_neighbor.py +0 -0
  79. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/remap/spatial_coords_remap.py +0 -0
  80. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/remap/utils.py +0 -0
  81. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/subset/__init__.py +0 -0
  82. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/subset/dataarray_accessor.py +0 -0
  83. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/subset/grid_accessor.py +0 -0
  84. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/utils/__init__.py +0 -0
  85. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray/utils/computing.py +0 -0
  86. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray.egg-info/SOURCES.txt +0 -0
  87. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray.egg-info/dependency_links.txt +0 -0
  88. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray.egg-info/requires.txt +0 -0
  89. {uxarray-2026.3.0 → uxarray-2026.4.0}/uxarray.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uxarray
3
- Version: 2026.3.0
3
+ Version: 2026.4.0
4
4
  Summary: Xarray extension for unstructured climate and global weather data analysis and visualization.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -90,6 +90,24 @@ class UxDataset(xr.Dataset):
90
90
  else:
91
91
  self._uxgrid = uxgrid
92
92
 
93
+ # As of xarray's 2026.4.0, `xr.Dataset(xr.Dataset)` is prohibited;
94
+ # hence this check, i.e. if we get `xr.Dataset` as input, use its `data_vars`
95
+ # as `dict` and handle `coords` and `attrs` properly as well
96
+ if args and isinstance(args[0], xr.Dataset):
97
+ ds = args[0]
98
+ # Replacee only args[0], `ds`, with `ds.data_vars` as `dict`
99
+ args = (dict(ds.data_vars),) + args[1:]
100
+ # coords not passed positionally
101
+ if len(args) < 2:
102
+ kwargs.setdefault(
103
+ "coords", dict(ds.coords)
104
+ ) # Set it as kwarg only if not explicitly provided
105
+ # attrs not passed positionally
106
+ if len(args) < 3:
107
+ kwargs.setdefault(
108
+ "attrs", ds.attrs
109
+ ) # Set it as kwarg only if not explicitly provided
110
+
93
111
  super().__init__(*args, **kwargs)
94
112
 
95
113
  # declare plotting accessor
@@ -627,9 +645,9 @@ class UxDataset(xr.Dataset):
627
645
  """
628
646
  if grid_format == "HEALPix":
629
647
  ds = self.rename_dims({"n_face": "cell"})
630
- return xr.Dataset(ds)
648
+ return xr.Dataset(ds.data_vars, coords=ds.coords, attrs=ds.attrs)
631
649
 
632
- return xr.Dataset(self)
650
+ return xr.Dataset(self.data_vars, coords=self.coords, attrs=self.attrs)
633
651
 
634
652
  def get_dual(self):
635
653
  """Compute the dual mesh for a dataset, returns a new dataset object.
@@ -7,51 +7,114 @@ from uxarray.io._mpas import _mpas_to_ugrid_dims
7
7
  from uxarray.io._ugrid import _is_ugrid, _read_ugrid
8
8
 
9
9
 
10
+ def _is_exodus(dataset: xr.Dataset) -> bool:
11
+ """Check whether a dataset looks like an Exodus mesh."""
12
+ has_packed_coords = "coord" in dataset
13
+ has_split_coords = {"coordx", "coordy"}.issubset(dataset.variables)
14
+ has_connectivity = any(
15
+ name.startswith("connect") for name in dataset.variables
16
+ ) or any("num_nod_per_el" in dim for dim in dataset.dims)
17
+
18
+ return has_connectivity and (has_packed_coords or has_split_coords)
19
+
20
+
21
+ def _is_scrip(dataset: xr.Dataset) -> bool:
22
+ """Check whether a dataset looks like an unstructured SCRIP grid."""
23
+ required_vars = {
24
+ "grid_center_lon",
25
+ "grid_center_lat",
26
+ "grid_corner_lon",
27
+ "grid_corner_lat",
28
+ }
29
+ unstructured_markers = {"grid_imask", "grid_rank", "grid_area"}
30
+
31
+ return required_vars.issubset(dataset.variables) and any(
32
+ marker in dataset for marker in unstructured_markers
33
+ )
34
+
35
+
36
+ def _is_mpas(dataset: xr.Dataset) -> bool:
37
+ """Check whether a dataset looks like an MPAS grid."""
38
+ if "verticesOnCell" not in dataset:
39
+ return False
40
+
41
+ companion_groups = (
42
+ {"nEdgesOnCell"},
43
+ {"latCell", "lonCell"},
44
+ {"latVertex", "lonVertex"},
45
+ {"xCell", "yCell", "zCell"},
46
+ {"xVertex", "yVertex", "zVertex"},
47
+ )
48
+
49
+ return any(group.issubset(dataset.variables) for group in companion_groups)
50
+
51
+
52
+ def _is_esmf(dataset: xr.Dataset) -> bool:
53
+ """Check whether a dataset looks like an ESMF mesh."""
54
+ return "maxNodePElement" in dataset.dims and "elementConn" in dataset
55
+
56
+
57
+ def _is_geos_cs(dataset: xr.Dataset) -> bool:
58
+ """Check whether a dataset looks like a GEOS cube-sphere grid."""
59
+ required_dims = {"nf", "YCdim", "XCdim"}
60
+ required_vars = {"corner_lons", "corner_lats"}
61
+
62
+ return required_dims.issubset(dataset.sizes) and required_vars.issubset(
63
+ dataset.variables
64
+ )
65
+
66
+
67
+ def _is_icon(dataset: xr.Dataset) -> bool:
68
+ """Check whether a dataset looks like an ICON grid."""
69
+ required_vars = {"vertex_of_cell", "clon", "clat", "vlon", "vlat"}
70
+ return required_vars.issubset(dataset.variables)
71
+
72
+
73
+ def _is_fesom2(dataset: xr.Dataset) -> bool:
74
+ """Check whether a dataset looks like a FESOM2 grid."""
75
+ return "triag_nodes" in dataset
76
+
77
+
10
78
  def _parse_grid_type(dataset):
11
- """Checks input and contents to determine grid type. Supports detection of
12
- UGrid, SCRIP, Exodus, ESMF, and shape file.
79
+ """Determine the grid type represented by an input dataset.
13
80
 
14
81
  Parameters
15
82
  ----------
16
83
  dataset : Xarray dataset
17
- Xarray dataset of the grid
84
+ Xarray dataset containing grid topology information.
18
85
 
19
86
  Returns
20
87
  -------
21
- mesh_type : str
22
- File type of the file, ug, exo, scrip or shp
88
+ tuple[str, str | None, str | None]
89
+ A 3-tuple of ``(mesh_type, lon_name, lat_name)``. ``mesh_type`` is one
90
+ of ``"Exodus"``, ``"Scrip"``, ``"UGRID"``, ``"MPAS"``, ``"ESMF"``,
91
+ ``"GEOS-CS"``, ``"ICON"``, ``"FESOM2"``, or ``"Structured"``. The
92
+ longitude and latitude coordinate names are only returned for structured
93
+ grids and are otherwise ``None``.
23
94
 
24
95
  Raises
25
96
  ------
26
97
  RuntimeError
27
- If invalid file type
28
- ValueError
29
- If file is not in UGRID format
98
+ If the dataset format cannot be recognized.
30
99
  """
31
100
 
32
101
  _structured, lon_name, lat_name = _is_structured(dataset)
33
102
 
34
- if "coord" in dataset:
35
- # exodus with coord or coordx
36
- mesh_type = "Exodus"
37
- elif "coordx" in dataset:
103
+ if _is_exodus(dataset):
38
104
  mesh_type = "Exodus"
39
- elif "grid_center_lon" in dataset:
40
- # scrip with grid_center_lon
105
+ elif _is_scrip(dataset):
41
106
  mesh_type = "Scrip"
42
107
  elif _is_ugrid(dataset):
43
- # ugrid topology is present
44
108
  mesh_type = "UGRID"
45
- elif "verticesOnCell" in dataset:
109
+ elif _is_mpas(dataset):
46
110
  mesh_type = "MPAS"
47
- elif "maxNodePElement" in dataset.dims:
111
+ elif _is_esmf(dataset):
48
112
  mesh_type = "ESMF"
49
- elif all(key in dataset.sizes for key in ["nf", "YCdim", "XCdim"]):
50
- # expected dimensions for a GEOS cube sphere grid
113
+ elif _is_geos_cs(dataset):
51
114
  mesh_type = "GEOS-CS"
52
- elif "vertex_of_cell" in dataset:
115
+ elif _is_icon(dataset):
53
116
  mesh_type = "ICON"
54
- elif "triag_nodes" in dataset:
117
+ elif _is_fesom2(dataset):
55
118
  mesh_type = "FESOM2"
56
119
  elif _structured:
57
120
  mesh_type = "Structured"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uxarray
3
- Version: 2026.3.0
3
+ Version: 2026.4.0
4
4
  Summary: Xarray extension for unstructured climate and global weather data analysis and visualization.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes