Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Development

* MNT: Refactor the CfRadial1 writer for code quality ahead of v1.0 — descriptive helper names (``_main_info_mapper`` → ``_extract_root_dataset``, ``_variable_mapper`` → ``_combine_sweeps``, ``_calib_mapper`` → ``_map_radar_calibration``, ``_sweep_info_mapper`` → ``_collect_sweep_metadata``), clearer locals, fix the ``calibs`` bool/variable name collision, robust ``history`` attribute and missing-``elevation`` handling, and a shared ``_build_cfradial1_dataset`` reused by ``xradar.transform.to_cfradial1`` to remove duplication ({issue}`379`) by [@syedhamidali](https://github.com/syedhamidali)
* FIX: ``open_nexradlevel2_datatree`` decodes volumes with interior sweep-index gaps end-to-end — translate sweep label → compact position in ``NexradLevel2Store.open_store_coordinates`` so the per-sweep entrypoint stops positionally indexing the compacted ``msg_31_header`` (follow-up to {pull}`362`) ({issue}`366`, {pull}`374`) by [@aladinor](https://github.com/aladinor)
* FIX: ensure `to_cfradial2` correctly selects the default storage engine when none is provided, ({pull}`378`) by [@chfer](https://github.com/chfer)
* MNT: Add ``cfradial1_sgp_file`` session fixture and refactor 8 tests in ``test_util.py``/``test_accessors.py`` to share it instead of inlining ``DATASETS.fetch("sample_sgp_data.nc")``. Fixture returns the filename so each test opens its own DataTree, avoiding cross-test mutation ({issue}`346`, {pull}`347`) by [@aladinor](https://github.com/aladinor)
Expand Down
42 changes: 40 additions & 2 deletions tests/io/test_cfradial1.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


import numpy as np
import pytest
import xarray as xr
from open_radar_data import DATASETS

Expand Down Expand Up @@ -120,7 +121,7 @@ def test_cfradial1_export_helper_metadata_and_indices():

def test_cfradial1_export_helper_empty_sweep_info_and_time_fallback():
empty = xr.DataTree.from_dict({"/": xr.Dataset()})
sweep_info = cf1_export._sweep_info_mapper(empty)
sweep_info = cf1_export._collect_sweep_metadata(empty)
assert "sweep_number" in sweep_info
assert np.isnan(sweep_info["sweep_number"].values[0])

Expand All @@ -142,6 +143,43 @@ def test_cfradial1_export_helper_empty_sweep_info_and_time_fallback():
},
)
dtree = xr.DataTree.from_dict({"/": xr.Dataset(), "/sweep_0": sweep})
mapped = cf1_export._variable_mapper(dtree)
mapped = cf1_export._combine_sweeps(dtree)
assert "DBZ" in mapped
assert mapped["DBZ"].dims == ("time", "range")


def test_cfradial1_export_auto_filename(tmp_path, monkeypatch):
filename = DATASETS.fetch("cfrad.20080604_002217_000_SPOL_v36_SUR.nc")
dtree = xd.io.open_cfradial1_datatree(filename)

# filename=None derives the name from instrument_name + first timestamp
monkeypatch.chdir(tmp_path)
xd.io.to_cfradial1(dtree.copy(), filename=None, calibs=True)

written = list(tmp_path.glob("cfrad1_*.nc"))
assert len(written) == 1
assert written[0].name.startswith("cfrad1_")


def test_cfradial1_export_requires_dtree():
with pytest.raises(ValueError, match="must be a radar"):
xd.io.to_cfradial1(None)


def test_cfradial1_export_sweep_indices_missing_elevation():
dtree = xr.DataTree.from_dict(
{
"/": xr.Dataset(),
"/sweep_0": xr.Dataset(
coords={"elevation": ("azimuth", np.array([0.5, 0.5], dtype="float32"))}
),
"/sweep_1": xr.Dataset(), # no elevation coordinate -> skipped with warning
}
)

with pytest.warns(UserWarning, match="no 'elevation'"):
out = cf1_export.calculate_sweep_indices(dtree)

# only the valid sweep contributes a ray-index entry
assert out["sweep_start_ray_index"].size == 1
assert out["sweep_end_ray_index"].size == 1
Loading
Loading