Repository: tinosulzer/PyBaMM

Issue:
Convert Geometry Keys to Variables
Convert the keys in the Geometry class from strings (e.g. "x") to pybamm independent variables

Discussion:

Patch:
diff --git a/pybamm/discretisations/meshes.py b/pybamm/discretisations/meshes.py
index 49a51303..cbc267d9 100644
--- a/pybamm/discretisations/meshes.py
+++ b/pybamm/discretisations/meshes.py
@@ -7,7 +7,14 @@ from __future__ import print_function, unicode_literals
 import numpy as np
 import pybamm
 
-KNOWN_DOMAINS = ["negative electrode", "separator", "positive electrode", "test"]
+KNOWN_DOMAINS = [
+    "negative electrode",
+    "separator",
+    "positive electrode",
+    "test",
+    "negative particle",
+    "positive particle",
+]
 
 
 class Mesh(dict):
diff --git a/pybamm/geometry/geometry.py b/pybamm/geometry/geometry.py
index 62a3e2f8..8b47ee8c 100644
--- a/pybamm/geometry/geometry.py
+++ b/pybamm/geometry/geometry.py
@@ -25,12 +25,14 @@ class Geometry(dict):
 class Geometry1DMacro(Geometry):
     def __init__(self, custom_geometry={}):
         super().__init__()
+        whole_cell = ["negative electrode", "separator", "positive electrode"]
+        x = pybamm.IndependentVariable("x", whole_cell)
         ln = pybamm.standard_parameters.ln
         ls = pybamm.standard_parameters.ls
 
-        self["negative electrode"] = {"x": {"min": pybamm.Scalar(0), "max": ln}}
-        self["separator"] = {"x": {"min": ln, "max": ln + ls}}
-        self["positive electrode"] = {"x": {"min": ln + ls, "max": pybamm.Scalar(1)}}
+        self["negative electrode"] = {x: {"min": pybamm.Scalar(0), "max": ln}}
+        self["separator"] = {x: {"min": ln, "max": ln + ls}}
+        self["positive electrode"] = {x: {"min": ln + ls, "max": pybamm.Scalar(1)}}
 
         # update with custom geometry if non empty
         self.update(custom_geometry)
@@ -40,11 +42,13 @@ class Geometry1DMicro(Geometry):
     def __init__(self, custom_geometry={}):
         super().__init__()
 
+        r = pybamm.IndependentVariable("r", ["negative particle", "positive particle"])
+
         self["negative particle"] = {
-            "r": {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}
+            r: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}
         }
         self["positive particle"] = {
-            "r": {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}
+            r: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}
         }
         # update with custom geometry if non empty
         self.update(custom_geometry)
@@ -64,11 +68,16 @@ class Geometry3DMacro(Geometry1DMacro):
     def __init__(self, custom_geometry={}):
         super().__init__()
 
-        y = {"min": pybamm.Scalar(0), "max": pybamm.standard_parameters.ly}
+        whole_cell = ["negative electrode", "separator", "positive electrode"]
+        y = pybamm.IndependentVariable("y", whole_cell)
+        z = pybamm.IndependentVariable("z", whole_cell)
+
+        y_lim = {"min": pybamm.Scalar(0), "max": pybamm.standard_parameters.ly}
 
-        z = {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}
+        z_lim = {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}
 
-        for domain in self["macro"]:
-            self["macro"][domain]["y"] = y
-            self["macro"][domain]["z"] = z
+        MACRO_DOMAINS = ["negative electrode", "separator", "positive electrode"]
+        for domain in MACRO_DOMAINS:
+            self[domain][y] = y_lim
+            self[domain][z] = z_lim
         self.update(custom_geometry)
diff --git a/pybamm/parameters/standard_parameters.py b/pybamm/parameters/standard_parameters.py
index efa65d97..d7117f46 100644
--- a/pybamm/parameters/standard_parameters.py
+++ b/pybamm/parameters/standard_parameters.py
@@ -82,6 +82,10 @@ Ls = Parameter("Ls")
 Lp = Parameter("Lp")
 Lx = Ln + Ls + Lp
 
+# 3D Geometry
+Ly = Parameter("Ly")
+Lz = Parameter("Lz")
+
 # Microscale Geometry
 R_n = Parameter("R_n")
 R_p = Parameter("R_p")
@@ -119,6 +123,8 @@ cp0_dimensional = Parameter("cp0")  # Initial li concentration in pos electrode
 ln = Ln / Lx
 ls = Ls / Lx
 lp = Lp / Lx
+ly = Ly / Lz
+lz = Lz / Lz
 
 # Microscale Geometry
 epsilon_n = Parameter("epsilon_n")  # Electrolyte volume fraction in neg electrode


Test patch:
diff --git a/tests/test_geometry/test_geometry.py b/tests/test_geometry/test_geometry.py
index e8df45e0..cf7236ea 100644
--- a/tests/test_geometry/test_geometry.py
+++ b/tests/test_geometry/test_geometry.py
@@ -2,19 +2,78 @@
 # Tests for the base model class
 #
 import pybamm
+import unittest
 
 
-class TestGeometry:
+class TestGeometry1DMacro(unittest.TestCase):
     def test_add_custom_geometry(self):
+        geometry = pybamm.Geometry1DMacro()
+        whole_cell = ["negative electrode", "separator", "positive electrode"]
+        x = pybamm.IndependentVariable("x", whole_cell)
         custom_geometry = {
             "negative electrode": {
-                "x": {"min": pybamm.Scalar(1), "max": pybamm.Scalar(2)}
+                x: {"min": pybamm.Scalar(1), "max": pybamm.Scalar(2)}
+            }
+        }
+        geometry.update(custom_geometry)
+        self.assertEqual(
+            geometry["negative electrode"], custom_geometry["negative electrode"]
+        )
+
+    def test_geometry_keys(self):
+        geometry = pybamm.Geometry1DMacro()
+        for spatial_vars in geometry.values():
+            all(
+                self.assertIsInstance(spatial_var, pybamm.IndependentVariable)
+                for spatial_var in spatial_vars.keys()
+            )
+
+
+class TestGeometry1DMicro(unittest.TestCase):
+    def test_add_custom_geometry(self):
+        geometry = pybamm.Geometry1DMicro()
+        whole_cell = ["negative electrode", "separator", "positive electrode"]
+        x = pybamm.IndependentVariable("x", whole_cell)
+        custom_geometry = {
+            "negative electrode": {
+                x: {"min": pybamm.Scalar(1), "max": pybamm.Scalar(2)}
+            }
+        }
+        geometry.update(custom_geometry)
+
+        self.assertEqual(
+            geometry["negative electrode"], custom_geometry["negative electrode"]
+        )
+
+    def test_geometry_keys(self):
+        geometry = pybamm.Geometry1DMicro()
+        for spatial_vars in geometry.values():
+            all(
+                self.assertIsInstance(spatial_var, pybamm.IndependentVariable)
+                for spatial_var in spatial_vars.keys()
+            )
+
+
+class TestGeometry3DMacro(unittest.TestCase):
+    def test_add_custom_geometry(self):
+        geometry = pybamm.Geometry3DMacro()
+        whole_cell = ["negative electrode", "separator", "positive electrode"]
+        x = pybamm.IndependentVariable("x", whole_cell)
+        custom_geometry = {
+            "negative electrode": {
+                x: {"min": pybamm.Scalar(1), "max": pybamm.Scalar(2)}
             }
         }
-        geometry = pybamm.Geometry1DMacro(custom_geometry)
 
+        geometry.update(custom_geometry)
         self.assertEqual(
             geometry["negative electrode"], custom_geometry["negative electrode"]
         )
 
-    # process geometry test conducted within TestParameterValues
+    def test_geometry_keys(self):
+        geometry = pybamm.Geometry3DMacro()
+        for spatial_vars in geometry.values():
+            all(
+                self.assertIsInstance(spatial_var, pybamm.IndependentVariable)
+                for spatial_var in spatial_vars.keys()
+            )