From b0a523281be0e24b5f4d7d02fb2c39fcdfa08748 Mon Sep 17 00:00:00 2001 From: Ken Kehoe Date: Wed, 31 Jan 2024 12:47:26 -0700 Subject: [PATCH] Unit conversion warning (#795) * Ignoring statement for flake8 * Ignoring statement for flake8 * Adding keyword options to notify user when the unit conversion has a problem. * Removing old unused code. --- act/io/hysplit.py | 2 +- act/utils/data_utils.py | 16 ++++++++++++++-- examples/plotting/plot_scatter.py | 2 +- tests/utils/test_data_utils.py | 25 ++++++++++++++++++++++--- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/act/io/hysplit.py b/act/io/hysplit.py index f0c410d0eb..5c0c2fd6aa 100644 --- a/act/io/hysplit.py +++ b/act/io/hysplit.py @@ -78,7 +78,7 @@ def read_hysplit(filename, base_year=2000): for variable in data[1:]: var_list.append(variable) input_df = pd.read_csv( - filename, sep='\s+', index_col=False, names=var_list, skiprows=12) + filename, sep='\s+', index_col=False, names=var_list, skiprows=12) # noqa W605 input_df['year'] = base_year + input_df['year'] input_df['time'] = pd.to_datetime(input_df[["year", "month", "day", "hour", "minute"]], format='%y%m%d%H%M') diff --git a/act/utils/data_utils.py b/act/utils/data_utils.py index 5d499338dc..184aac92ed 100644 --- a/act/utils/data_utils.py +++ b/act/utils/data_utils.py @@ -35,7 +35,8 @@ def __init__(self, ds): self._ds = ds def change_units( - self, variables=None, desired_unit=None, skip_variables=None, skip_standard=True + self, variables=None, desired_unit=None, skip_variables=None, skip_standard=True, + verbose=False, raise_error=False ): """ Parameters @@ -51,6 +52,13 @@ def change_units( Flag indicating the QC variables that will not need changing are skipped. Makes the processing faster when processing all variables in dataset. + verbose : boolean + Option to print statement when an attempted conversion fails. Set to False + as default because many units strings are not udunits complient and when + trying to convert all varialbes of a type of units (eg temperature) the code + can print a lot of unecessary information. + raise_error : boolean + Raise an error if conversion is not successful. Returns ------- @@ -102,7 +110,11 @@ def change_units( pint.errors.UndefinedUnitError, np.core._exceptions.UFuncTypeError, ): - continue + if raise_error: + raise ValueError(f"Unable to convert '{var_name}' to units of '{desired_unit}'.") + elif verbose: + print(f"\n Unable to convert '{var_name}' to units of '{desired_unit}'. " + f"Skipping unit converstion for '{var_name}'.\n") return self._ds diff --git a/examples/plotting/plot_scatter.py b/examples/plotting/plot_scatter.py index dd9202f05d..698f47373f 100644 --- a/examples/plotting/plot_scatter.py +++ b/examples/plotting/plot_scatter.py @@ -31,7 +31,7 @@ 'ground_speed', m_field='ambient_temp', marker='x', - cbar_label='Ambient Temperature ($^\circ$C)' + cbar_label='Ambient Temperature ($^\circ$C)' # noqa W605 ) # Set the range of the field on the x-axis diff --git a/tests/utils/test_data_utils.py b/tests/utils/test_data_utils.py index bf10076164..ec1a0a920e 100644 --- a/tests/utils/test_data_utils.py +++ b/tests/utils/test_data_utils.py @@ -4,6 +4,8 @@ import pytest import xarray as xr from numpy.testing import assert_almost_equal +from contextlib import redirect_stdout +from io import StringIO import act from act.utils.data_utils import DatastreamParserARM as DatastreamParser @@ -93,10 +95,8 @@ def test_convert_units(): data = act.utils.data_utils.convert_units(r_data, 'K', 'C') assert np.ceil(data[0]) == 12 - try: + with np.testing.assert_raises(ValueError): ds.utils.change_units() - except ValueError as error: - assert str(error) == "Need to provide 'desired_unit' keyword for .change_units() method" desired_unit = 'degF' skip_vars = [ii for ii in ds.data_vars if ii.startswith('qc_')] @@ -138,6 +138,25 @@ def test_convert_units(): ds.close() del ds + # Test if exception or print statement is issued when an error occurs with units string + ds = act.io.arm.read_arm_netcdf(act.tests.sample_files.EXAMPLE_EBBR1) + with np.testing.assert_raises(ValueError): + ds.utils.change_units('home_signal_15', 'not_a_real_unit_string', raise_error=True) + + with np.testing.assert_raises(ValueError): + ds.utils.change_units('not_a_real_variable_name', 'degC', raise_error=True) + + f = StringIO() + var_name = 'home_signal_15' + unit = 'not_a_real_unit_string' + with redirect_stdout(f): + ds.utils.change_units('home_signal_15', 'not_a_real_unit_string', verbose=True) + s = f.getvalue() + assert s.strip() == f"Unable to convert '{var_name}' to units of '{unit}'. Skipping unit converstion for '{var_name}'." + + ds.close() + del ds + def test_ts_weighted_average(): ds = act.io.arm.read_arm_netcdf(act.tests.sample_files.EXAMPLE_MET_WILDCARD)