From ac6e6364bb557d32b7c9600e1bcf26117fc2ab24 Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 15:31:37 -0500 Subject: [PATCH 1/9] ADD: ZDR bias calculations from Radtraq --- pyart/correct/__init__.py | 2 +- pyart/correct/bias_and_noise.py | 51 +++++++++++++++++ pyart/correct/phase_proc.py | 77 +++++++++++++++++++++++--- pyart/retrieve/spectra_calculations.py | 2 +- tests/correct/test_correct_bias.py | 20 ++++++- 5 files changed, 140 insertions(+), 12 deletions(-) diff --git a/pyart/correct/__init__.py b/pyart/correct/__init__.py index caa3ac75b9..c25c203e11 100644 --- a/pyart/correct/__init__.py +++ b/pyart/correct/__init__.py @@ -8,7 +8,7 @@ from .attenuation import calculate_attenuation # noqa from .attenuation import calculate_attenuation_philinear # noqa from .attenuation import calculate_attenuation_zphi # noqa -from .bias_and_noise import correct_bias, correct_noise_rhohv # noqa +from .bias_and_noise import correct_bias, correct_noise_rhohv, calc_zdr_offset # noqa from .dealias import dealias_fourdd # noqa from .despeckle import despeckle_field, find_objects # noqa from .phase_proc import phase_proc_lp, phase_proc_lp_gf # noqa diff --git a/pyart/correct/bias_and_noise.py b/pyart/correct/bias_and_noise.py index 03bf7a3161..f5226204ee 100755 --- a/pyart/correct/bias_and_noise.py +++ b/pyart/correct/bias_and_noise.py @@ -137,3 +137,54 @@ def correct_bias(radar, bias=0.0, field_name=None): corr_field["data"] = corr_field_data return corr_field + +def calc_zdr_offset(radar, gatefilter=None, height_range=None, zdr_var=None): + """ + Function for calculating the ZDR bias from a VPT scan. + + Parameters + ---------- + radar : PyART radar object + Radar object with radar data + gatefilter: PyART GateFilter + Gatefilter for filtering out data for calculating ZDR bias + height_range: tuple + The minimum and maximum elevations for the scan. + zdr_var: string or None + The name of the ZDR variable. Set to None to have PyART try to determine this automatically. + + Returns + ------- + obj : dict + The mean vertical profiles of each radar moment are extracted along with the ZDR bias. + + """ + if height_range is None: + height_range = (0, 100000.) + + if zdr_var is None: + zdr_var = get_field_name("differential_reflectivity") + + height_mask = np.logical_and(radar.range["data"] >= height_range[0], + radar.range["data"] <= height_range[1]) + + mask = gatefilter.gate_included + Zdr = radar.fields[zdr_var]["data"] + if isinstance(Zdr, np.ma.MaskedArray): + Zdr = Zdr.filled(np.nan) + Zdr = np.where(mask == True, Zdr, np.nan) + bias = np.nanmean(Zdr[:, height_mask]) + results = { + 'bias': bias, + 'profile_zdr': np.nanmean(Zdr[:, height_mask], axis=0), + 'range': radar.range["data"][height_mask], + } + for k in radar.fields.keys(): + if k != "range": + field_data = radar.fields[k]["data"].astype(float) + if isinstance(field_data, np.ma.MaskedArray): + field_data = field_data.filled(np.nan) + + field_data = np.where(mask == True, field_data, np.nan) + results['profile_' + k] = np.nanmean(field_data[:, :], axis=0) + return results \ No newline at end of file diff --git a/pyart/correct/phase_proc.py b/pyart/correct/phase_proc.py index 27b6901f1c..fe98b9a12c 100644 --- a/pyart/correct/phase_proc.py +++ b/pyart/correct/phase_proc.py @@ -169,6 +169,56 @@ def det_process_range(radar, sweep, fzl, doc=10): ray_end = radar.sweep_end_ray_index["data"][sweep] + 1 return gate_end, ray_start, ray_end +def det_fzl_mask_rhi(radar, sweep, fzl, doc=10): + """ + Determine the processing mask for an RHI. + + The procedure will return an array of weights for the LP code + for all of the points to be included in the processing. + + Parameters + ---------- + radar : Radar + Radar object from which ranges will be determined. + sweep : int + Sweep (0 indexed) for which to determine processing ranges. + fzl : float + Maximum altitude in meters. The determined range will not include + gates which are above this limit. + doc : int, optional + Minimum number of gates which will be excluded from the determined + range. + + Returns + ------- + gate_end : int + Index of last gate below `fzl` and satisfying the `doc` parameter. + ray_start : int + Ray index which defines the start of the region. + ray_end : int + Ray index which defined the end of the region. + weights : float array + Array of weights where all gates below the freezing level are 1 and + are 0 above. + """ + ranges = radar.range["data"] + elevation = radar.elevation["data"] + radar_height = radar.altitude["data"] + gate_end = 0 + ray_start = radar.sweep_start_ray_index["data"][sweep] + ray_end = radar.sweep_end_ray_index["data"][sweep] + 1 + for j in range(ray_start, ray_end): + gate_end = max([gate_end, fzl_index(fzl, ranges, elevation[j], radar_height)]) + if doc is not None: + gate_end = min(gate_end, len(ranges) - doc) + else: + gate_end = min(gate_end, len(ranges)) + + radar_z = radar.gate_z["data"] + radar_height + radar_z = radar_z[:, :gate_end] + weights = np.where(radar_z <= fzl, 1., 0.) + return gate_end, ray_start, ray_end, weights + def snr(line, wl=11): """Return the signal to noise ratio after smoothing.""" @@ -1169,9 +1219,15 @@ def phase_proc_lp( for sweep in range(len(radar.sweep_start_ray_index["data"])): if debug: print("Doing ", sweep) - end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=15) - start_gate = 0 + if radar.scan_type == 'ppi' or radar.scan_type == "sector": + end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=15) + start_gate = 0 + weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) + else: + end_gate, start_ray, end_ray, weights = det_fzl_mask_rhi( + radar, sweep, fzl, doc=15) + A_Matrix = construct_A_matrix( len(radar.range["data"][start_gate:end_gate]), St_Gorlv_differential_5pts ) @@ -1183,9 +1239,7 @@ def phase_proc_lp( dweight=self_const, coef=coef, ) - - weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) - + nw = np.bmat([weights, np.zeros(weights.shape)]) if LP_solver == "pyglpk": @@ -1385,7 +1439,16 @@ def phase_proc_lp_gf( if debug: print("Doing ", sweep) - end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=doc) + if radar.scan_type == 'ppi' or radar.scan_type == "sector": + end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=15) + start_gate = 0 + weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) + else: + start_gate = 0 + end_gate, start_ray, end_ray, weights = det_fzl_mask_rhi( + radar, sweep, fzl, doc=15) + phidp_mod[start_ray:end_ray, start_gate:end_gate] = np.where( + weights == 1, phidp_mod[start_ray:end_ray, start_gate:end_gate], min_phidp) start_gate = 0 @@ -1408,8 +1471,6 @@ def phase_proc_lp_gf( coef=coef, ) - weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) - nw = np.bmat([weights, np.zeros(weights.shape)]) if LP_solver == "pyglpk": diff --git a/pyart/retrieve/spectra_calculations.py b/pyart/retrieve/spectra_calculations.py index 9a00707fa7..e88ff0c8b3 100644 --- a/pyart/retrieve/spectra_calculations.py +++ b/pyart/retrieve/spectra_calculations.py @@ -79,7 +79,7 @@ def spectra_moments(radar): return field_list -def dealias_spectra(the_spectra, vel_bins, wavelength, left_limit, right_limit): +def dealias_spectra(the_spectra, vel_bins, wavelength): """Dealias a spectra. Parameters diff --git a/tests/correct/test_correct_bias.py b/tests/correct/test_correct_bias.py index 9ab077749e..9c489b7c97 100644 --- a/tests/correct/test_correct_bias.py +++ b/tests/correct/test_correct_bias.py @@ -1,10 +1,11 @@ """ Unit tests for bias and noise module. """ import pytest -from numpy.testing import assert_allclose - import pyart +from open_radar_data import DATASETS +import numpy as np +from numpy.testing import assert_allclose radar = pyart.io.read(pyart.testing.NEXRAD_ARCHIVE_MSG31_FILE) @@ -24,3 +25,18 @@ def test_correct_bias(): bias = 0 field_name = "foo" pytest.raises(KeyError, pyart.correct.correct_bias, radar, bias, field_name) + +def test_calc_zdr_offset(): + xsapr_test_file = DATASETS.fetch('sgpxsaprcfrvptI4.a1.20200205.100827.nc') + ds = pyart.io.read(xsapr_test_file) + gatefilter = pyart.filters.GateFilter(ds) + gatefilter.exclude_below('cross_correlation_ratio_hv', 0.995) + gatefilter.exclude_above('cross_correlation_ratio_hv', 1) + gatefilter.exclude_below('reflectivity', 10) + gatefilter.exclude_above('reflectivity', 30) + + results = pyart.correct.calc_zdr_offset(ds, zdr_var='differential_reflectivity', gatefilter=gatefilter, + height_range=(1000, 3000)) + np.testing.assert_almost_equal(results['bias'], 2.69, decimal=2) + print(results['profile_reflectivity'][1:16]) + np.testing.assert_almost_equal(results['profile_reflectivity'][15], 14.37, decimal=2) From 145e98c2616839e66236c0535a546be40e104c4a Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 15:32:13 -0500 Subject: [PATCH 2/9] ADD: Example for gallery --- examples/correct/plot_zdr_check.py | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/correct/plot_zdr_check.py diff --git a/examples/correct/plot_zdr_check.py b/examples/correct/plot_zdr_check.py new file mode 100644 index 0000000000..84328d89aa --- /dev/null +++ b/examples/correct/plot_zdr_check.py @@ -0,0 +1,47 @@ +""" +ZDR Bias Calculation +--------------------- + +This example shows how to calculate the ZDR bias from VPT/Birdbath scans. +The technique here uses a vertically pointing scan in regions of light rain. +In these regions, raindrops should be approximately spherical and therefore their +ZDR near zero. Therefore, we want the average ZDR in these regions. +This code applies :math:`Z_{e}` and :math:`rho_{hv}` thresholds to the ZDR +bias calculation to ensure that we are taking the average ZDR in light rain. + +""" + +import matplotlib.pyplot as plt +import pyart +from open_radar_data import DATASETS + + + +# Read in example data +filename = DATASETS.fetch('sgpxsaprcfrvptI4.a1.20200205.100827.nc') +ds = pyart.io.read(filename) + +# Set up a typical filter for ZDR bias calculation in birdbath scan +# Light rain and RhoHV near 1 ensures that raindrops are close to spherical +# Therefore ZDR should be zero in these regions +gatefilter = pyart.filters.GateFilter(ds) +gatefilter.exclude_below('cross_correlation_ratio_hv', 0.995) +gatefilter.exclude_above('cross_correlation_ratio_hv', 1) +gatefilter.exclude_below('reflectivity', 10) +gatefilter.exclude_above('reflectivity', 30) + +results = pyart.correct.calc_zdr_offset(ds, zdr_var='differential_reflectivity', gatefilter=gatefilter, + height_range=(1000, 3000)) + +print('Zdr Bias: ' + '%.2f' % results['bias']) + +fig, ax = plt.subplots(1, 3, figsize=(8, 5)) +ax[0].plot(results['profile_zdr'], results['range']) +ax[0].set_ylabel('Range (m)') +ax[0].set_xlabel('Zdr (dB)') +ax[1].plot(results['profile_reflectivity'], results['range']) +ax[1].set_xlabel('Zh (dBZ)') +ax[2].plot(results['profile_cross_correlation_ratio_hv'], results['range']) +ax[2].set_xlabel('RhoHV ()') +fig.tight_layout() +plt.show() From 83627edbf32f5219cb57da4aacfa84879640c5c6 Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 16:11:28 -0500 Subject: [PATCH 3/9] ADD: ZDR bias calculations --- examples/correct/plot_zdr_check.py | 39 ++++++++++++++++-------------- pyart/correct/bias_and_noise.py | 35 +++++++++++++++------------ 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/examples/correct/plot_zdr_check.py b/examples/correct/plot_zdr_check.py index 84328d89aa..df98780e0c 100644 --- a/examples/correct/plot_zdr_check.py +++ b/examples/correct/plot_zdr_check.py @@ -6,42 +6,45 @@ The technique here uses a vertically pointing scan in regions of light rain. In these regions, raindrops should be approximately spherical and therefore their ZDR near zero. Therefore, we want the average ZDR in these regions. -This code applies :math:`Z_{e}` and :math:`rho_{hv}` thresholds to the ZDR +This code applies reflectivity and cross correlation ratio-based thresholds to the ZDR bias calculation to ensure that we are taking the average ZDR in light rain. """ import matplotlib.pyplot as plt -import pyart from open_radar_data import DATASETS - +import pyart # Read in example data -filename = DATASETS.fetch('sgpxsaprcfrvptI4.a1.20200205.100827.nc') +filename = DATASETS.fetch("sgpxsaprcfrvptI4.a1.20200205.100827.nc") ds = pyart.io.read(filename) # Set up a typical filter for ZDR bias calculation in birdbath scan # Light rain and RhoHV near 1 ensures that raindrops are close to spherical # Therefore ZDR should be zero in these regions gatefilter = pyart.filters.GateFilter(ds) -gatefilter.exclude_below('cross_correlation_ratio_hv', 0.995) -gatefilter.exclude_above('cross_correlation_ratio_hv', 1) -gatefilter.exclude_below('reflectivity', 10) -gatefilter.exclude_above('reflectivity', 30) +gatefilter.exclude_below("cross_correlation_ratio_hv", 0.995) +gatefilter.exclude_above("cross_correlation_ratio_hv", 1) +gatefilter.exclude_below("reflectivity", 10) +gatefilter.exclude_above("reflectivity", 30) -results = pyart.correct.calc_zdr_offset(ds, zdr_var='differential_reflectivity', gatefilter=gatefilter, - height_range=(1000, 3000)) +results = pyart.correct.calc_zdr_offset( + ds, + zdr_var="differential_reflectivity", + gatefilter=gatefilter, + height_range=(1000, 3000), +) -print('Zdr Bias: ' + '%.2f' % results['bias']) +print("Zdr Bias: " + "{:.2f}".format(results["bias"])) fig, ax = plt.subplots(1, 3, figsize=(8, 5)) -ax[0].plot(results['profile_zdr'], results['range']) -ax[0].set_ylabel('Range (m)') -ax[0].set_xlabel('Zdr (dB)') -ax[1].plot(results['profile_reflectivity'], results['range']) -ax[1].set_xlabel('Zh (dBZ)') -ax[2].plot(results['profile_cross_correlation_ratio_hv'], results['range']) -ax[2].set_xlabel('RhoHV ()') +ax[0].plot(results["profile_zdr"], results["range"]) +ax[0].set_ylabel("Range (m)") +ax[0].set_xlabel("Zdr (dB)") +ax[1].plot(results["profile_reflectivity"], results["range"]) +ax[1].set_xlabel("Zh (dBZ)") +ax[2].plot(results["profile_cross_correlation_ratio_hv"], results["range"]) +ax[2].set_xlabel("RhoHV ()") fig.tight_layout() plt.show() diff --git a/pyart/correct/bias_and_noise.py b/pyart/correct/bias_and_noise.py index f5226204ee..b16815ab63 100755 --- a/pyart/correct/bias_and_noise.py +++ b/pyart/correct/bias_and_noise.py @@ -138,6 +138,7 @@ def correct_bias(radar, bias=0.0, field_name=None): return corr_field + def calc_zdr_offset(radar, gatefilter=None, height_range=None, zdr_var=None): """ Function for calculating the ZDR bias from a VPT scan. @@ -148,11 +149,11 @@ def calc_zdr_offset(radar, gatefilter=None, height_range=None, zdr_var=None): Radar object with radar data gatefilter: PyART GateFilter Gatefilter for filtering out data for calculating ZDR bias - height_range: tuple - The minimum and maximum elevations for the scan. + height_range: tuple + The minimum and maximum heights in meters for the scan. zdr_var: string or None The name of the ZDR variable. Set to None to have PyART try to determine this automatically. - + Returns ------- obj : dict @@ -160,31 +161,35 @@ def calc_zdr_offset(radar, gatefilter=None, height_range=None, zdr_var=None): """ if height_range is None: - height_range = (0, 100000.) + height_range = (0, 100000.0) if zdr_var is None: zdr_var = get_field_name("differential_reflectivity") - height_mask = np.logical_and(radar.range["data"] >= height_range[0], - radar.range["data"] <= height_range[1]) - + height_mask = np.logical_and( + radar.range["data"] >= height_range[0], radar.range["data"] <= height_range[1] + ) + mask = gatefilter.gate_included Zdr = radar.fields[zdr_var]["data"] if isinstance(Zdr, np.ma.MaskedArray): Zdr = Zdr.filled(np.nan) - Zdr = np.where(mask == True, Zdr, np.nan) + Zdr = np.where(mask, Zdr, np.nan) bias = np.nanmean(Zdr[:, height_mask]) + height_mask_tiled = np.tile(height_mask, (radar.nrays, 1)) + Zdr = np.where(height_mask_tiled, Zdr, np.nan) results = { - 'bias': bias, - 'profile_zdr': np.nanmean(Zdr[:, height_mask], axis=0), - 'range': radar.range["data"][height_mask], + "bias": bias, + "profile_zdr": np.nanmean(Zdr[:, :], axis=0), + "range": radar.range["data"], } for k in radar.fields.keys(): if k != "range": field_data = radar.fields[k]["data"].astype(float) if isinstance(field_data, np.ma.MaskedArray): field_data = field_data.filled(np.nan) - - field_data = np.where(mask == True, field_data, np.nan) - results['profile_' + k] = np.nanmean(field_data[:, :], axis=0) - return results \ No newline at end of file + + field_data = np.where(mask, field_data, np.nan) + field_data = np.where(height_mask_tiled, field_data, np.nan) + results["profile_" + k] = np.nanmean(field_data[:, :], axis=0) + return results From ef8ebff68001db8b6160c8d23629c5a792908a9b Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 16:18:59 -0500 Subject: [PATCH 4/9] FIX: Revert back for spectra_calculations.py --- pyart/retrieve/spectra_calculations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyart/retrieve/spectra_calculations.py b/pyart/retrieve/spectra_calculations.py index e88ff0c8b3..9a00707fa7 100644 --- a/pyart/retrieve/spectra_calculations.py +++ b/pyart/retrieve/spectra_calculations.py @@ -79,7 +79,7 @@ def spectra_moments(radar): return field_list -def dealias_spectra(the_spectra, vel_bins, wavelength): +def dealias_spectra(the_spectra, vel_bins, wavelength, left_limit, right_limit): """Dealias a spectra. Parameters From fb9393282ee7324791c34209ae90d14c5fcbc5a0 Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 16:30:34 -0500 Subject: [PATCH 5/9] FIX: Restore phase proc from main branch --- pyart/correct/phase_proc.py | 77 ++++--------------------------------- 1 file changed, 8 insertions(+), 69 deletions(-) diff --git a/pyart/correct/phase_proc.py b/pyart/correct/phase_proc.py index fe98b9a12c..27b6901f1c 100644 --- a/pyart/correct/phase_proc.py +++ b/pyart/correct/phase_proc.py @@ -169,56 +169,6 @@ def det_process_range(radar, sweep, fzl, doc=10): ray_end = radar.sweep_end_ray_index["data"][sweep] + 1 return gate_end, ray_start, ray_end -def det_fzl_mask_rhi(radar, sweep, fzl, doc=10): - """ - Determine the processing mask for an RHI. - - The procedure will return an array of weights for the LP code - for all of the points to be included in the processing. - - Parameters - ---------- - radar : Radar - Radar object from which ranges will be determined. - sweep : int - Sweep (0 indexed) for which to determine processing ranges. - fzl : float - Maximum altitude in meters. The determined range will not include - gates which are above this limit. - doc : int, optional - Minimum number of gates which will be excluded from the determined - range. - - Returns - ------- - gate_end : int - Index of last gate below `fzl` and satisfying the `doc` parameter. - ray_start : int - Ray index which defines the start of the region. - ray_end : int - Ray index which defined the end of the region. - weights : float array - Array of weights where all gates below the freezing level are 1 and - are 0 above. - """ - ranges = radar.range["data"] - elevation = radar.elevation["data"] - radar_height = radar.altitude["data"] - gate_end = 0 - ray_start = radar.sweep_start_ray_index["data"][sweep] - ray_end = radar.sweep_end_ray_index["data"][sweep] + 1 - for j in range(ray_start, ray_end): - gate_end = max([gate_end, fzl_index(fzl, ranges, elevation[j], radar_height)]) - if doc is not None: - gate_end = min(gate_end, len(ranges) - doc) - else: - gate_end = min(gate_end, len(ranges)) - - radar_z = radar.gate_z["data"] + radar_height - radar_z = radar_z[:, :gate_end] - weights = np.where(radar_z <= fzl, 1., 0.) - return gate_end, ray_start, ray_end, weights - def snr(line, wl=11): """Return the signal to noise ratio after smoothing.""" @@ -1219,15 +1169,9 @@ def phase_proc_lp( for sweep in range(len(radar.sweep_start_ray_index["data"])): if debug: print("Doing ", sweep) - if radar.scan_type == 'ppi' or radar.scan_type == "sector": - end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=15) - start_gate = 0 - weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) - else: - end_gate, start_ray, end_ray, weights = det_fzl_mask_rhi( - radar, sweep, fzl, doc=15) + end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=15) + start_gate = 0 - A_Matrix = construct_A_matrix( len(radar.range["data"][start_gate:end_gate]), St_Gorlv_differential_5pts ) @@ -1239,7 +1183,9 @@ def phase_proc_lp( dweight=self_const, coef=coef, ) - + + weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) + nw = np.bmat([weights, np.zeros(weights.shape)]) if LP_solver == "pyglpk": @@ -1439,16 +1385,7 @@ def phase_proc_lp_gf( if debug: print("Doing ", sweep) - if radar.scan_type == 'ppi' or radar.scan_type == "sector": - end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=15) - start_gate = 0 - weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) - else: - start_gate = 0 - end_gate, start_ray, end_ray, weights = det_fzl_mask_rhi( - radar, sweep, fzl, doc=15) - phidp_mod[start_ray:end_ray, start_gate:end_gate] = np.where( - weights == 1, phidp_mod[start_ray:end_ray, start_gate:end_gate], min_phidp) + end_gate, start_ray, end_ray = det_process_range(radar, sweep, fzl, doc=doc) start_gate = 0 @@ -1471,6 +1408,8 @@ def phase_proc_lp_gf( coef=coef, ) + weights = np.ones(phidp_mod[start_ray:end_ray, start_gate:end_gate].shape) + nw = np.bmat([weights, np.zeros(weights.shape)]) if LP_solver == "pyglpk": From eb32fb507b9a0b25b82154a027b1ac3a667199ad Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 16:33:52 -0500 Subject: [PATCH 6/9] STY: Black and ruff changes. --- pyart/correct/bias_and_noise.py | 2 ++ tests/correct/test_correct_bias.py | 28 ++++++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/pyart/correct/bias_and_noise.py b/pyart/correct/bias_and_noise.py index 99aeae3c93..4e84b29433 100755 --- a/pyart/correct/bias_and_noise.py +++ b/pyart/correct/bias_and_noise.py @@ -2,6 +2,7 @@ Corrects polarimetric variables for noise """ + import warnings import dask @@ -199,6 +200,7 @@ def calc_zdr_offset(radar, gatefilter=None, height_range=None, zdr_var=None): results["profile_" + k] = np.nanmean(field_data[:, :], axis=0) return results + def calc_cloud_mask( radar, field, diff --git a/tests/correct/test_correct_bias.py b/tests/correct/test_correct_bias.py index dad96a60a5..aec10fa576 100644 --- a/tests/correct/test_correct_bias.py +++ b/tests/correct/test_correct_bias.py @@ -3,11 +3,11 @@ import dask import numpy as np import pytest -import pyart - from numpy.testing import assert_allclose, assert_almost_equal, assert_array_equal from open_radar_data import DATASETS +import pyart + radar = pyart.io.read(pyart.testing.NEXRAD_ARCHIVE_MSG31_FILE) kazr_file = DATASETS.fetch("sgpkazrgeC1.a1.20190529.000002.cdf") radar_kazr = pyart.aux_io.read_kazr(kazr_file) @@ -32,18 +32,22 @@ def test_correct_bias(): def test_calc_zdr_offset(): - xsapr_test_file = DATASETS.fetch('sgpxsaprcfrvptI4.a1.20200205.100827.nc') + xsapr_test_file = DATASETS.fetch("sgpxsaprcfrvptI4.a1.20200205.100827.nc") ds = pyart.io.read(xsapr_test_file) gatefilter = pyart.filters.GateFilter(ds) - gatefilter.exclude_below('cross_correlation_ratio_hv', 0.995) - gatefilter.exclude_above('cross_correlation_ratio_hv', 1) - gatefilter.exclude_below('reflectivity', 10) - gatefilter.exclude_above('reflectivity', 30) - - results = pyart.correct.calc_zdr_offset(ds, zdr_var='differential_reflectivity', gatefilter=gatefilter, - height_range=(1000, 3000)) - assert_almost_equal(results['bias'], 2.69, decimal=2) - assert_almost_equal(results['profile_reflectivity'][15], 14.37, decimal=2) + gatefilter.exclude_below("cross_correlation_ratio_hv", 0.995) + gatefilter.exclude_above("cross_correlation_ratio_hv", 1) + gatefilter.exclude_below("reflectivity", 10) + gatefilter.exclude_above("reflectivity", 30) + + results = pyart.correct.calc_zdr_offset( + ds, + zdr_var="differential_reflectivity", + gatefilter=gatefilter, + height_range=(1000, 3000), + ) + assert_almost_equal(results["bias"], 2.69, decimal=2) + assert_almost_equal(results["profile_reflectivity"][15], 14.37, decimal=2) def test_calc_noise_floor(): From a295412470e387ba7708a75c90a1f736f1b12643 Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 17:38:23 -0500 Subject: [PATCH 7/9] FIX: Duplicate entries in __init__ and obj to radar --- pyart/correct/__init__.py | 2 +- pyart/correct/bias_and_noise.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyart/correct/__init__.py b/pyart/correct/__init__.py index 1a64e9c945..7b050057ad 100644 --- a/pyart/correct/__init__.py +++ b/pyart/correct/__init__.py @@ -8,7 +8,7 @@ from .attenuation import calculate_attenuation # noqa from .attenuation import calculate_attenuation_philinear # noqa from .attenuation import calculate_attenuation_zphi # noqa -from .bias_and_noise import correct_bias, correct_noise_rhohv, calc_zdr_offset # noqa +from .bias_and_noise import calc_zdr_offset # noqa from .bias_and_noise import calc_cloud_mask, calc_noise_floor, correct_bias # noqa from .bias_and_noise import ( correct_noise_rhohv, # noqa diff --git a/pyart/correct/bias_and_noise.py b/pyart/correct/bias_and_noise.py index 4e84b29433..866a290cc9 100755 --- a/pyart/correct/bias_and_noise.py +++ b/pyart/correct/bias_and_noise.py @@ -162,7 +162,7 @@ def calc_zdr_offset(radar, gatefilter=None, height_range=None, zdr_var=None): Returns ------- - obj : dict + profiles : dict The mean vertical profiles of each radar moment are extracted along with the ZDR bias. """ From 8d3890b87488062d3cf976a34024212a5bcafece Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 17:40:55 -0500 Subject: [PATCH 8/9] FIX: Reinsert calc_bias --- pyart/correct/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyart/correct/__init__.py b/pyart/correct/__init__.py index 7b050057ad..b36ec12163 100644 --- a/pyart/correct/__init__.py +++ b/pyart/correct/__init__.py @@ -8,7 +8,7 @@ from .attenuation import calculate_attenuation # noqa from .attenuation import calculate_attenuation_philinear # noqa from .attenuation import calculate_attenuation_zphi # noqa -from .bias_and_noise import calc_zdr_offset # noqa +from .bias_and_noise import correct_bias, calc_zdr_offset # noqa from .bias_and_noise import calc_cloud_mask, calc_noise_floor, correct_bias # noqa from .bias_and_noise import ( correct_noise_rhohv, # noqa From 717b03fe4e9319a8f3b91bc484a3e379d466c24e Mon Sep 17 00:00:00 2001 From: Bobby Jackson Date: Thu, 29 Aug 2024 17:45:21 -0500 Subject: [PATCH 9/9] FIX: Never mind, there were two calc_biases --- pyart/correct/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyart/correct/__init__.py b/pyart/correct/__init__.py index b36ec12163..7b050057ad 100644 --- a/pyart/correct/__init__.py +++ b/pyart/correct/__init__.py @@ -8,7 +8,7 @@ from .attenuation import calculate_attenuation # noqa from .attenuation import calculate_attenuation_philinear # noqa from .attenuation import calculate_attenuation_zphi # noqa -from .bias_and_noise import correct_bias, calc_zdr_offset # noqa +from .bias_and_noise import calc_zdr_offset # noqa from .bias_and_noise import calc_cloud_mask, calc_noise_floor, correct_bias # noqa from .bias_and_noise import ( correct_noise_rhohv, # noqa