Repository: pybamm-team/PyBaMM (python)

Issue:
Parameter processing for geometry
**Describe the bug**
In the case where your model has no parameters you still need to define an empty pybamm.ParameterValues() and process the geometry.

**To Reproduce**
Steps to reproduce the behaviour:
1. Go to 'training_workshop/exercise2_solving_a_pde.py'
2. Comment line 53 out
3. Run the code

**Expected behaviour**
I get the following error:
```
Traceback (most recent call last):
  File "examples/workshop_exercises/exercise2_solving_a_pde.py", line 58, in <module>
    mesh = pybamm.Mesh(geometry, submesh_types, var_pts)
  File "/home/ferran/PyBaMM/pybamm/meshes/meshes.py", line 87, in __init__
    geometry[domain]["primary"], submesh_pts[domain]
  File "/home/ferran/PyBaMM/pybamm/meshes/submeshes.py", line 49, in __init__
    edges = np.linspace(spatial_lims["min"], spatial_lims["max"], npts + 1)
  File "<__array_function__ internals>", line 6, in linspace
  File "/home/ferran/PyBaMM/env/lib/python3.6/site-packages/numpy/core/function_base.py", line 138, in linspace
    dt = result_type(start, stop, float(num))
  File "<__array_function__ internals>", line 6, in result_type
TypeError: data type not understood

```


Pull request description:
Issue 568 no parameters
# Description

Fixes #568 

the `ParameterValues` member function `process_geometry` executes all the expressions in the provided geometry, but this fails in the case where the geometry does not have any parameters, and therefore should not need to be processed by `ParameterValues`. This causes problems in the mesh creation (in `Mesh.__init__()`), which assumes that all the expressions have been evaluated. 

I've moved the evaluation of the expressions to `Mesh.__init__()`.

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)


# Key checklist:

- [x] No style issues: `$ flake8`
- [x] All tests pass: `$ python run-tests.py --unit`
- [x] 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: 

- [x] Code is commented, particularly in hard-to-understand areas
- [x] Tests added that prove fix is effective or that feature works
- [x] Any dependent changes have been merged and published in downstream modules


Patch:
diff --git a/pybamm/meshes/meshes.py b/pybamm/meshes/meshes.py
index 933544132..4b144f33a 100644
--- a/pybamm/meshes/meshes.py
+++ b/pybamm/meshes/meshes.py
@@ -72,6 +72,27 @@ class Mesh(dict):
             if domain not in ["negative electrode", "separator", "positive electrode"]:
                 self.domain_order.append(domain)
 
+        # evaluate any expressions in geometry
+        for domain in geometry:
+            for prim_sec_tabs, variables in geometry[domain].items():
+                # process tab information if using 2D current collectors
+                if prim_sec_tabs == "tabs":
+                    for tab, position_size in variables.items():
+                        for position_size, sym in position_size.items():
+                            if isinstance(sym, pybamm.Symbol):
+                                sym_eval = sym.evaluate()
+                                geometry[domain][prim_sec_tabs][tab][
+                                    position_size
+                                ] = sym_eval
+                else:
+                    for spatial_variable, spatial_limits in variables.items():
+                        for lim, sym in spatial_limits.items():
+                            if isinstance(sym, pybamm.Symbol):
+                                sym_eval = sym.evaluate()
+                                geometry[domain][prim_sec_tabs][spatial_variable][
+                                    lim
+                                ] = sym_eval
+
         # Create submeshes
         for domain in geometry:
             # need to pass tab information if primary domian is 2D current collector
diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py
index 9b84f2730..115dae34c 100644
--- a/pybamm/parameters/parameter_values.py
+++ b/pybamm/parameters/parameter_values.py
@@ -178,7 +178,7 @@ class ParameterValues(dict):
 
     def process_geometry(self, geometry):
         """
-        Assign parameter values to a geometry (inplace), *and* evaluate.
+        Assign parameter values to a geometry (inplace).
 
         Parameters
         ----------
@@ -191,17 +191,15 @@ class ParameterValues(dict):
                 if prim_sec_tabs == "tabs":
                     for tab, position_size in variables.items():
                         for position_size, sym in position_size.items():
-                            sym_eval = self.process_symbol(sym).evaluate()
                             geometry[domain][prim_sec_tabs][tab][
                                 position_size
-                            ] = sym_eval
+                            ] = self.process_symbol(sym)
                 else:
                     for spatial_variable, spatial_limits in variables.items():
                         for lim, sym in spatial_limits.items():
-                            sym_eval = self.process_symbol(sym).evaluate()
                             geometry[domain][prim_sec_tabs][spatial_variable][
                                 lim
-                            ] = sym_eval
+                            ] = self.process_symbol(sym)
 
     def process_symbol(self, symbol):
         """Walk through the symbol and replace any Parameter with a Value.


Test patch:
diff --git a/tests/unit/test_meshes/test_meshes.py b/tests/unit/test_meshes/test_meshes.py
index 4e442ebd7..52fafc776 100644
--- a/tests/unit/test_meshes/test_meshes.py
+++ b/tests/unit/test_meshes/test_meshes.py
@@ -7,6 +7,35 @@ import unittest
 
 
 class TestMesh(unittest.TestCase):
+    def test_mesh_creation_no_parameters(self):
+        r = pybamm.SpatialVariable(
+            "r", domain=["negative particle"], coord_sys="spherical polar"
+        )
+
+        geometry = {
+            "negative particle": {
+                "primary": {r: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}
+            }
+        }
+
+        submesh_types = {"negative particle": pybamm.Uniform1DSubMesh}
+        var_pts = {r: 20}
+        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)
+
+        # create mesh
+        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)
+
+        # check boundary locations
+        self.assertEqual(mesh["negative particle"][0].edges[0], 0)
+        self.assertEqual(mesh["negative particle"][0].edges[-1], 1)
+
+        # check number of edges and nodes
+        self.assertEqual(len(mesh["negative particle"][0].nodes), var_pts[r])
+        self.assertEqual(
+            len(mesh["negative particle"][0].edges),
+            len(mesh["negative particle"][0].nodes) + 1
+        )
+
     def test_mesh_creation(self):
         param = pybamm.ParameterValues(
             base_parameters={
diff --git a/tests/unit/test_meshes/test_scikit_fem_submesh.py b/tests/unit/test_meshes/test_scikit_fem_submesh.py
index 73c4e7041..540cdac9b 100644
--- a/tests/unit/test_meshes/test_scikit_fem_submesh.py
+++ b/tests/unit/test_meshes/test_scikit_fem_submesh.py
@@ -76,7 +76,8 @@ class TestScikitFiniteElement2DSubMesh(unittest.TestCase):
 
         var = pybamm.standard_spatial_vars
         var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.y: 10, var.z: 10}
-        with self.assertRaises(TypeError):
+        # there are parameters in the variables that need to be processed
+        with self.assertRaises(NotImplementedError):
             pybamm.Mesh(geometry, submesh_types, var_pts)
 
         lims = {var.x_n: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}