From 2e62e8df9e48df587ab4c0dd9455e297b3e39fc1 Mon Sep 17 00:00:00 2001 From: Alfonso Ladino Date: Tue, 19 Nov 2024 14:08:01 -0600 Subject: [PATCH 01/13] fixing IndexError when opening nexrad Split Cut Mode file --- xradar/io/backends/nexrad_level2.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index 4434bf49..2a5737d1 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1591,8 +1591,6 @@ def open_nexradlevel2_datatree( """ from xarray.core.treenode import NodePath - sweeps = [] - if isinstance(sweep, str): sweep = NodePath(sweep).name sweeps = [sweep] @@ -1610,6 +1608,13 @@ def open_nexradlevel2_datatree( else: with NEXRADLevel2File(filename_or_obj, loaddata=False) as nex: nsweeps = nex.msg_5["number_elevation_cuts"] + # Check if duplicated sweeps ("split cut mode") + n_sweeps = len(nex.msg_31_data_header) + title = None + if nsweeps > n_sweeps: + nsweeps = n_sweeps + title = "Split Cut Mode scanning strategy" + sweeps = [f"sweep_{i}" for i in range(nsweeps)] sweep_dict = open_sweeps_as_dict( @@ -1631,6 +1636,8 @@ def open_nexradlevel2_datatree( ) ls_ds: list[xr.Dataset] = [sweep_dict[sweep] for sweep in sweep_dict.keys()] ls_ds.insert(0, xr.Dataset()) + if title: + ls_ds[1].attrs["title"] = title dtree: dict = { "/": _assign_root(ls_ds), "/radar_parameters": _get_subgroup(ls_ds, radar_parameters_subgroup), From dc847a20fccf5e9dbe274442a1b53546a06ee727 Mon Sep 17 00:00:00 2001 From: Alfonso Ladino Date: Tue, 19 Nov 2024 14:20:03 -0600 Subject: [PATCH 02/13] fixing error with pytest --- xradar/io/backends/nexrad_level2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index 2a5737d1..d9a333d0 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1590,6 +1590,7 @@ def open_nexradlevel2_datatree( An `xarray.DataTree` representing the radar data organized by sweeps. """ from xarray.core.treenode import NodePath + title = None if isinstance(sweep, str): sweep = NodePath(sweep).name @@ -1610,7 +1611,6 @@ def open_nexradlevel2_datatree( nsweeps = nex.msg_5["number_elevation_cuts"] # Check if duplicated sweeps ("split cut mode") n_sweeps = len(nex.msg_31_data_header) - title = None if nsweeps > n_sweeps: nsweeps = n_sweeps title = "Split Cut Mode scanning strategy" From 33265181b82a23206892f47f3af9678ffe1dece6 Mon Sep 17 00:00:00 2001 From: Alfonso Ladino Date: Tue, 19 Nov 2024 14:22:20 -0600 Subject: [PATCH 03/13] running pre-commit --- xradar/io/backends/nexrad_level2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index d9a333d0..6e138a11 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1590,8 +1590,8 @@ def open_nexradlevel2_datatree( An `xarray.DataTree` representing the radar data organized by sweeps. """ from xarray.core.treenode import NodePath - title = None + title = None if isinstance(sweep, str): sweep = NodePath(sweep).name sweeps = [sweep] From 39348317adb89ffc0c51615113715740aaa899d0 Mon Sep 17 00:00:00 2001 From: Alfonso Ladino Date: Tue, 19 Nov 2024 14:25:52 -0600 Subject: [PATCH 04/13] running pre-commit --- xradar/io/backends/nexrad_level2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index 6e138a11..f81b85df 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1592,6 +1592,7 @@ def open_nexradlevel2_datatree( from xarray.core.treenode import NodePath title = None + if isinstance(sweep, str): sweep = NodePath(sweep).name sweeps = [sweep] From f5f2af3b186ba4ccc15f27dba2781a9a966a6928 Mon Sep 17 00:00:00 2001 From: Alfonso Ladino Date: Mon, 25 Nov 2024 08:39:03 -0600 Subject: [PATCH 05/13] Update xradar/io/backends/nexrad_level2.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kai Mühlbauer --- xradar/io/backends/nexrad_level2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index f81b85df..f4887bac 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1637,7 +1637,7 @@ def open_nexradlevel2_datatree( ) ls_ds: list[xr.Dataset] = [sweep_dict[sweep] for sweep in sweep_dict.keys()] ls_ds.insert(0, xr.Dataset()) - if title: + if title is not None: ls_ds[1].attrs["title"] = title dtree: dict = { "/": _assign_root(ls_ds), From cc30a989b0383a1d5b4b3a1af65f3481a1353ee4 Mon Sep 17 00:00:00 2001 From: aladinor Date: Tue, 26 Nov 2024 11:35:48 -0600 Subject: [PATCH 06/13] adding split cut mode to comment in the global/root attributes --- xradar/io/backends/common.py | 3 +++ xradar/io/backends/nexrad_level2.py | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/xradar/io/backends/common.py b/xradar/io/backends/common.py index aa91a961..642dcac5 100644 --- a/xradar/io/backends/common.py +++ b/xradar/io/backends/common.py @@ -126,6 +126,7 @@ def _assign_root(sweeps): attrs = {} attrs["Conventions"] = sweeps[0].attrs.get("Conventions", "None") attrs["instrument_name"] = sweeps[0].attrs.get("instrument_name", "None") + comment = sweeps[0].attrs.get("comment", None) attrs.update( { "version": "None", @@ -137,6 +138,8 @@ def _assign_root(sweeps): "comment": "im/exported using xradar", } ) + if comment is not None: + attrs["comment"] = attrs["comment"] + ",\n" + comment root = root.assign_attrs(attrs) # todo: pull in only CF attributes root = root.assign_attrs(sweeps[1].attrs) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index f4887bac..18cad50a 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1591,7 +1591,7 @@ def open_nexradlevel2_datatree( """ from xarray.core.treenode import NodePath - title = None + comment = None if isinstance(sweep, str): sweep = NodePath(sweep).name @@ -1614,7 +1614,7 @@ def open_nexradlevel2_datatree( n_sweeps = len(nex.msg_31_data_header) if nsweeps > n_sweeps: nsweeps = n_sweeps - title = "Split Cut Mode scanning strategy" + comment = "Split Cut Mode scanning strategy" sweeps = [f"sweep_{i}" for i in range(nsweeps)] @@ -1637,8 +1637,8 @@ def open_nexradlevel2_datatree( ) ls_ds: list[xr.Dataset] = [sweep_dict[sweep] for sweep in sweep_dict.keys()] ls_ds.insert(0, xr.Dataset()) - if title is not None: - ls_ds[1].attrs["title"] = title + if comment is not None: + ls_ds[0].attrs["comment"] = comment dtree: dict = { "/": _assign_root(ls_ds), "/radar_parameters": _get_subgroup(ls_ds, radar_parameters_subgroup), From bea6af3c796f07f7ac1a61d9319bbe95e4a35c10 Mon Sep 17 00:00:00 2001 From: aladinor Date: Tue, 26 Nov 2024 11:46:24 -0600 Subject: [PATCH 07/13] attemp to fix lint and style checks errors --- examples/notebooks/HaloPhotonics.ipynb | 4 ++-- examples/notebooks/conftest.py | 2 +- xradar/io/backends/hpl.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/notebooks/HaloPhotonics.ipynb b/examples/notebooks/HaloPhotonics.ipynb index c508f193..727b09cf 100644 --- a/examples/notebooks/HaloPhotonics.ipynb +++ b/examples/notebooks/HaloPhotonics.ipynb @@ -67,7 +67,7 @@ "source": [ "fig, ax = plt.subplots(3, 3, figsize=(12, 10))\n", "for sweep in range(9):\n", - " sweep_ds = xd.georeference.get_x_y_z(ds[\"sweep_%d\" % sweep].ds)\n", + " sweep_ds = xd.georeference.get_x_y_z(ds[f\"sweep_{sweep}\"].ds)\n", " sweep_ds = sweep_ds.set_coords([\"x\", \"y\", \"z\", \"time\", \"range\"])\n", " sweep_ds[\"mean_doppler_velocity\"].plot(\n", " x=\"x\", y=\"y\", ax=ax[int(sweep / 3), sweep % 3]\n", @@ -97,7 +97,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.4" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/examples/notebooks/conftest.py b/examples/notebooks/conftest.py index 0e4369ce..5638bc8c 100644 --- a/examples/notebooks/conftest.py +++ b/examples/notebooks/conftest.py @@ -30,7 +30,7 @@ def collect(self): yield NotebookItem.from_parent(self, name=os.path.basename(f)) def setup(self): - kernel = "python%d" % sys.version_info[0] + kernel = f"python{sys.version_info[0]}" self.exproc = ExecutePreprocessor(kernel_name=kernel, timeout=600) diff --git a/xradar/io/backends/hpl.py b/xradar/io/backends/hpl.py index 4197a00c..d7515d47 100644 --- a/xradar/io/backends/hpl.py +++ b/xradar/io/backends/hpl.py @@ -373,7 +373,7 @@ def __init__(self, filename, **kwargs): sweep_dict[k] = data_unsorted[k][time_inds] else: sweep_dict[k] = data_unsorted[k] - self._data["sweep_%d" % i] = sweep_dict + self._data[f"sweep_{i}"] = sweep_dict self._data["sweep_number"] = data_unsorted["sweep_number"] self._data["fixed_angle"] = data_unsorted["fixed_angle"] From 26c2992348e613e6032d017ce7cb8544abb51966 Mon Sep 17 00:00:00 2001 From: Alfonso Ladino Date: Thu, 28 Nov 2024 07:59:48 -0600 Subject: [PATCH 08/13] documenting changes in history.md files --- docs/history.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/history.md b/docs/history.md index 802eda27..051d0170 100644 --- a/docs/history.md +++ b/docs/history.md @@ -6,6 +6,7 @@ * FIX: Improving performance of `open_nexradlevel2_datatree` function and adding tests for `sweep` parameter. ({issue}`239`) ({pull}`240`) by [@aladinor](https://github.com/aladinor) * FIX: Keeping attributes at each variable when using `open_nexradlevel2_datatree`. ({issue}`241`) ({pull}`242`) by [@aladinor](https://github.com/aladinor) * FIX: Correctly read transition rays in RHI scans ({issue}`247`) ({pull}`250`) by [@rcjackson](https://github.com/rcjackson) +* FIX: Correctly open NEXRAD files when split cut mode is enable ({issue} `245`) ({pull}`246`) by [@aladinor](https://github.com/aladinor) ## 0.8.0 (2024-11-04) From 50b677178310a1da29f0c61ee898090e58a7a128 Mon Sep 17 00:00:00 2001 From: aladinor Date: Mon, 10 Feb 2025 17:47:49 -0600 Subject: [PATCH 09/13] getting ride of split cut mode comment --- xradar/io/backends/common.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/xradar/io/backends/common.py b/xradar/io/backends/common.py index 642dcac5..aa91a961 100644 --- a/xradar/io/backends/common.py +++ b/xradar/io/backends/common.py @@ -126,7 +126,6 @@ def _assign_root(sweeps): attrs = {} attrs["Conventions"] = sweeps[0].attrs.get("Conventions", "None") attrs["instrument_name"] = sweeps[0].attrs.get("instrument_name", "None") - comment = sweeps[0].attrs.get("comment", None) attrs.update( { "version": "None", @@ -138,8 +137,6 @@ def _assign_root(sweeps): "comment": "im/exported using xradar", } ) - if comment is not None: - attrs["comment"] = attrs["comment"] + ",\n" + comment root = root.assign_attrs(attrs) # todo: pull in only CF attributes root = root.assign_attrs(sweeps[1].attrs) From 44e02db33b95e6818681deba70b1a36cccbcde6f Mon Sep 17 00:00:00 2001 From: aladinor Date: Mon, 10 Feb 2025 17:48:04 -0600 Subject: [PATCH 10/13] getting ride of split cut mode comment --- xradar/io/backends/nexrad_level2.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index 18cad50a..9f05a84d 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1591,8 +1591,6 @@ def open_nexradlevel2_datatree( """ from xarray.core.treenode import NodePath - comment = None - if isinstance(sweep, str): sweep = NodePath(sweep).name sweeps = [sweep] @@ -1609,12 +1607,15 @@ def open_nexradlevel2_datatree( ) else: with NEXRADLevel2File(filename_or_obj, loaddata=False) as nex: + # Expected number of elevation cuts from the VCP definition nsweeps = nex.msg_5["number_elevation_cuts"] - # Check if duplicated sweeps ("split cut mode") + # Actual number of sweeps recorded in the file n_sweeps = len(nex.msg_31_data_header) + # Check for AVSET mode: If AVSET was active, the actual number of sweeps (n_sweeps) + # will be fewer than the expected number (nsweeps), as higher elevations were skipped. if nsweeps > n_sweeps: + # Adjust nsweeps to the actual number of recorded sweeps nsweeps = n_sweeps - comment = "Split Cut Mode scanning strategy" sweeps = [f"sweep_{i}" for i in range(nsweeps)] @@ -1637,8 +1638,6 @@ def open_nexradlevel2_datatree( ) ls_ds: list[xr.Dataset] = [sweep_dict[sweep] for sweep in sweep_dict.keys()] ls_ds.insert(0, xr.Dataset()) - if comment is not None: - ls_ds[0].attrs["comment"] = comment dtree: dict = { "/": _assign_root(ls_ds), "/radar_parameters": _get_subgroup(ls_ds, radar_parameters_subgroup), From 016f8553793fbd15f6cccdaf0aaa39f81d0fb206 Mon Sep 17 00:00:00 2001 From: aladinor Date: Mon, 10 Feb 2025 17:59:57 -0600 Subject: [PATCH 11/13] fixing conflitcs --- xradar/io/backends/nexrad_level2.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index 9a594c6a..a22969e8 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1693,7 +1693,7 @@ def open_nexradlevel2_datatree( An `xarray.DataTree` representing the radar data organized by sweeps. """ from xarray.core.treenode import NodePath - + if isinstance(sweep, str): sweep = NodePath(sweep).name sweeps = [sweep] @@ -1742,8 +1742,6 @@ def open_nexradlevel2_datatree( ) ls_ds: list[xr.Dataset] = [sweep_dict[sweep] for sweep in sweep_dict.keys()] ls_ds.insert(0, xr.Dataset()) - if comment is not None: - ls_ds[0].attrs["comment"] = comment dtree: dict = { "/": _assign_root(ls_ds), "/radar_parameters": _get_subgroup(ls_ds, radar_parameters_subgroup), From fca354a203fee7e068ec621b97b5a1762e92e528 Mon Sep 17 00:00:00 2001 From: aladinor Date: Mon, 10 Feb 2025 18:11:15 -0600 Subject: [PATCH 12/13] removing empty space --- xradar/io/backends/common.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xradar/io/backends/common.py b/xradar/io/backends/common.py index 7f2372a2..7b7c904c 100644 --- a/xradar/io/backends/common.py +++ b/xradar/io/backends/common.py @@ -260,7 +260,6 @@ def _get_required_root_dataset(ls_ds, optional=True): # merging both the created and the variables within each dataset root = xr.merge([root, _vars], compat="override") - attrs = root.attrs.keys() remove_attrs = set(attrs) ^ set(required_global_attrs) if optional: From a8fd94228b7b7c2073250c0ee364abf46698d2e5 Mon Sep 17 00:00:00 2001 From: aladinor Date: Fri, 14 Feb 2025 10:32:28 -0600 Subject: [PATCH 13/13] adding AVSET docummentation --- xradar/io/backends/nexrad_level2.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/xradar/io/backends/nexrad_level2.py b/xradar/io/backends/nexrad_level2.py index a22969e8..c068b41a 100644 --- a/xradar/io/backends/nexrad_level2.py +++ b/xradar/io/backends/nexrad_level2.py @@ -1711,16 +1711,18 @@ def open_nexradlevel2_datatree( else: with NEXRADLevel2File(filename_or_obj, loaddata=False) as nex: # Expected number of elevation cuts from the VCP definition - nsweeps = nex.msg_5["number_elevation_cuts"] + exp_sweeps = nex.msg_5["number_elevation_cuts"] # Actual number of sweeps recorded in the file - n_sweeps = len(nex.msg_31_data_header) - # Check for AVSET mode: If AVSET was active, the actual number of sweeps (n_sweeps) - # will be fewer than the expected number (nsweeps), as higher elevations were skipped. - if nsweeps > n_sweeps: + act_sweeps = len(nex.msg_31_data_header) + # Check for AVSET mode: If AVSET was active, the actual number of sweeps (act_sweeps) + # will be fewer than the expected number (exp_sweeps), as higher elevations were skipped. + # More info https://www.test.roc.noaa.gov/radar-techniques/avset.php + # https://www.test.roc.noaa.gov/public-documents/engineering-branch/new-technology/misc/avset/AVSET_AMS_RADAR_CONF_Final.pdf + if exp_sweeps > act_sweeps: # Adjust nsweeps to the actual number of recorded sweeps - nsweeps = n_sweeps + exp_sweeps = act_sweeps - sweeps = [f"sweep_{i}" for i in range(nsweeps)] + sweeps = [f"sweep_{i}" for i in range(act_sweeps)] sweep_dict = open_sweeps_as_dict( filename_or_obj=filename_or_obj,