Repository: ARM-DOE/ACT

Issue:
Add warning to change units when fails
Need to add warning to change units method to indicate when a problem occurs, but don't raise an error as many string units are not correct or udunits compliant.

Describe what you were trying to get done.
Tell us what happened, what went wrong, and what you expected to happen.

### What I Did

```
Paste the command(s) you ran and the output.
If there was a crash, please include the traceback here.
```



Discussion:
@kenkehoe Makes sense to me!

Resolving patch:
diff --git a/act/io/hysplit.py b/act/io/hysplit.py
--- 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
--- 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
--- 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


Test patch:
diff --git a/tests/utils/test_data_utils.py b/tests/utils/test_data_utils.py
--- 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)