Repository: pybamm-team/PyBaMM (python)

Issue:
processed variable error when t,x,or r outside of range
make `ProcessedVariable` throw an error if you try and call outside of the solution time and/or space

Pull request description:
Issue 570 processed var warning
# Description

Add warning if processed variable is called outside range
Fixes #570 

## Type of change

Please add a line in the relevant section of [CHANGELOG.md](https://github.com/pybamm-team/PyBaMM/blob/master/CHANGELOG.md) to document the change (include PR #) - note reverse order of PR #s.

- [x] New feature (non-breaking change which adds functionality)
- [ ] Optimization (back-end change that speeds up the code)
- [ ] Bug fix (non-breaking change which fixes an issue)


# Key checklist:

- [ ] No style issues: `$ flake8`
- [ ] All tests pass: `$ python run-tests.py --unit`
- [ ] The documentation builds: `$ cd docs` and then `$ make clean; make html`

You can run all three at once, using `$ python run-tests.py --quick`.

## Further checks:

- [ ] Code is commented, particularly in hard-to-understand areas
- [ ] Tests added that prove fix is effective or that feature works


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90e4841d8..9252176e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
 
 ## Bug fixes
 
+-   Add warning if `ProcessedVariable` is called outisde its interpolation range ([#681](https://github.com/pybamm-team/PyBaMM/pull/681))
 -   Improve the way `ProcessedVariable` objects are created in higher dimensions ([#581](https://github.com/pybamm-team/PyBaMM/pull/581))
 
 # [v0.1.0](https://github.com/pybamm-team/PyBaMM/tree/v0.1.0) - 2019-10-08
diff --git a/pybamm/__init__.py b/pybamm/__init__.py
index 04e9c0840..b6872b51e 100644
--- a/pybamm/__init__.py
+++ b/pybamm/__init__.py
@@ -25,7 +25,7 @@ def _load_version_int():
 __version_int__ = _load_version_int()
 __version__ = ".".join([str(x) for x in __version_int__])
 if sys.version_info[0] < 3:
-    del (x)  # Before Python3, list comprehension iterators leaked
+    del x  # Before Python3, list comprehension iterators leaked
 
 #
 # Expose PyBaMM version
diff --git a/pybamm/logger.py b/pybamm/logger.py
index abee0fd86..27853fb29 100644
--- a/pybamm/logger.py
+++ b/pybamm/logger.py
@@ -3,6 +3,11 @@
 #
 import logging
 
+
+def set_logging_level(level):
+    logger.setLevel(level)
+
+
 format = (
     "%(asctime)s - [%(levelname)s] %(module)s.%(funcName)s(%(lineno)d): "
     + "%(message)s"
@@ -12,7 +17,5 @@ logging.Formatter(datefmt="%Y-%m-%d %H:%M:%S", fmt="%(asctime)s.%(msecs)03d")
 
 # Create a custom logger
 logger = logging.getLogger(__name__)
+set_logging_level("WARNING")
 
-
-def set_logging_level(level):
-    logger.setLevel(level)
diff --git a/pybamm/processed_variable.py b/pybamm/processed_variable.py
index 3a41872e8..a4db4a646 100644
--- a/pybamm/processed_variable.py
+++ b/pybamm/processed_variable.py
@@ -391,19 +391,24 @@ class ProcessedVariable(object):
             fill_value=np.nan,
         )
 
-    def __call__(self, t=None, x=None, r=None, y=None, z=None):
+    def __call__(self, t=None, x=None, r=None, y=None, z=None, warn=True):
         """
         Evaluate the variable at arbitrary t (and x, r, y and/or z), using interpolation
         """
         if self.dimensions == 1:
-            return self._interpolation_function(t)
+            out = self._interpolation_function(t)
         elif self.dimensions == 2:
             if t is None:
-                return self._interpolation_function(y, z)
+                out = self._interpolation_function(y, z)
             else:
-                return self.call_2D(t, x, r, z)
+                out = self.call_2D(t, x, r, z)
         elif self.dimensions == 3:
-            return self.call_3D(t, x, r, y, z)
+            out = self.call_3D(t, x, r, y, z)
+        if warn is True and np.isnan(out).any():
+            pybamm.logger.warning(
+                "Calling variable outside interpolation range (returns 'nan')"
+            )
+        return out
 
     def call_2D(self, t, x, r, z):
         "Evaluate a 2D variable"
diff --git a/pybamm/quick_plot.py b/pybamm/quick_plot.py
index 29caf2b8d..b2470f0ac 100644
--- a/pybamm/quick_plot.py
+++ b/pybamm/quick_plot.py
@@ -320,7 +320,9 @@ class QuickPlot(object):
                             spatial_scale = self.spatial_scales[spatial_var_name]
                         self.plots[key][i][j], = ax.plot(
                             spatial_var_value * spatial_scale,
-                            variable(t, **{spatial_var_name: spatial_var_value}),
+                            variable(
+                                t, **{spatial_var_name: spatial_var_value}, warn=False
+                            ),
                             lw=2,
                             color=colors[i],
                             linestyle=linestyles[j],
@@ -333,7 +335,7 @@ class QuickPlot(object):
                         full_t = self.ts[i]
                         self.plots[key][i][j], = ax.plot(
                             full_t * self.time_scale,
-                            variable(full_t),
+                            variable(full_t, warn=False),
                             lw=2,
                             color=colors[i],
                             linestyle=linestyles[j],
@@ -394,7 +396,9 @@ class QuickPlot(object):
                     for j, variable in enumerate(variable_lists):
                         plot[i][j].set_ydata(
                             variable(
-                                t_dimensionless, **{spatial_var_name: spatial_var_value}
+                                t_dimensionless,
+                                **{spatial_var_name: spatial_var_value},
+                                warn=False
                             )
                         )
             else:


Test patch:
diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py
index 192701f99..effbbf073 100644
--- a/tests/unit/test_logger.py
+++ b/tests/unit/test_logger.py
@@ -8,11 +8,11 @@ import unittest
 class TestLogger(unittest.TestCase):
     def test_logger(self):
         logger = pybamm.logger
-        self.assertEqual(logger.level, 0)
+        self.assertEqual(logger.level, 30)
         pybamm.set_logging_level("INFO")
         self.assertEqual(logger.level, 20)
-        pybamm.set_logging_level("WARNING")
-        self.assertEqual(logger.level, 30)
+        pybamm.set_logging_level("ERROR")
+        self.assertEqual(logger.level, 40)
 
 
 if __name__ == "__main__":
diff --git a/tests/unit/test_processed_variable.py b/tests/unit/test_processed_variable.py
index bd9f9cd0a..a891fdbc6 100644
--- a/tests/unit/test_processed_variable.py
+++ b/tests/unit/test_processed_variable.py
@@ -195,6 +195,11 @@ class TestProcessedVariable(unittest.TestCase):
         np.testing.assert_array_equal(processed_eqn(t_sol), t_sol * y_sol[0])
         np.testing.assert_array_almost_equal(processed_eqn(0.5), 0.5 * 2.5)
 
+        # Suppress warning for this test
+        pybamm.set_logging_level("ERROR")
+        np.testing.assert_array_equal(processed_eqn(2), np.nan)
+        pybamm.set_logging_level("WARNING")
+
     def test_processed_var_2D_interpolation(self):
         t = pybamm.t
         var = pybamm.Variable("var", domain=["negative electrode", "separator"])