Repository: pmeal/openpnm
Issue: topotools.dimensionality sometimes treats 1D networks as 2D

Although extremely rare, it's still a bug. It's even hard to reproduce, but I had this problem when I was doing manual coordinate manipulations for the CL project. 

```python
import openpnm as op

net = op.network.Cubic([1, 1, 5], spacing=1.2345678e-20)
net["pore.coords"][0, 0] = net["pore.coords"][:, 0].mean()
dims = op.topotools.dimensionality(net)
print(dims)
>>> [True False  True]
```

Changed files:
openpnm/topotools/topotools.py, tests/unit/topotools/TopotoolsTest.py

diff --git a/openpnm/topotools/topotools.py b/openpnm/topotools/topotools.py
index 54d885cd6..05e8744fc 100644
--- a/openpnm/topotools/topotools.py
+++ b/openpnm/topotools/topotools.py
@@ -551,10 +551,12 @@ def dimensionality(network):
     Returns an 3-by-1 array containing ``True`` for each axis that contains
     multiple values, indicating that the pores are spatially distributed
     in that direction.
+
     """
     xyz = network["pore.coords"]
-    xyz_unique = [np.unique(xyz[:, i]) for i in range(3)]
-    return np.array([elem.size != 1 for elem in xyz_unique])
+    eps = np.finfo(float).resolution
+    dims_unique = [not np.allclose(xk, xk.mean(), atol=0, rtol=eps) for xk in xyz.T]
+    return np.array(dims_unique)
 
 
 def clone_pores(network, pores, labels=['clone'], mode='parents'):
diff --git a/tests/unit/topotools/TopotoolsTest.py b/tests/unit/topotools/TopotoolsTest.py
index e67dcbc15..b2972f8a3 100644
--- a/tests/unit/topotools/TopotoolsTest.py
+++ b/tests/unit/topotools/TopotoolsTest.py
@@ -177,7 +177,7 @@ class TopotoolsTest:
         pn2['pore.coords'] += [0, 0, 3]
         pn2['pore.net_02'] = True
         pn2['throat.net_02'] = True
-        geo = op.geometry.StickAndBall(network=pn, pores=pn.Ps, throats=pn.Ts)
+        op.geometry.StickAndBall(network=pn, pores=pn.Ps, throats=pn.Ts)
         geo2 = op.geometry.StickAndBall(network=pn2, pores=pn2.Ps, throats=pn2.Ts)
         geo2['pore.test_vals'] = 1.5
         op.topotools.merge_networks(network=pn, donor=pn2)
@@ -355,30 +355,30 @@ class TopotoolsTest:
         Lc = 1e-4
         pn = op.network.Cubic(shape=[Nx, Ny, Nz], spacing=Lc)
         pn2 = op.network.Cubic(shape=[Nx, Ny, Nz], spacing=Lc)
-        pn2['pore.coords'] += [Lc*Nx, 0, 0]
+        pn2['pore.coords'] += [Lc * Nx, 0, 0]
         op.topotools.stitch(network=pn, donor=pn2,
                             P_network=pn.pores('back'), P_donor=pn2.pores('front'),
                             method='radius', len_max=0,
                             label_stitches=['test', 'test2'])
-        assert pn.Nt == (pn2.Nt*2)
+        assert pn.Nt == (pn2.Nt * 2)
 
     def test_stitch_10_connections(self):
         Nx, Ny, Nz = (10, 10, 1)
         Lc = 1e-4
         pn = op.network.Cubic(shape=[Nx, Ny, Nz], spacing=Lc)
         pn2 = op.network.Cubic(shape=[Nx, Ny, Nz], spacing=Lc)
-        pn2['pore.coords'] += [Lc*Nx, 0, 0]
+        pn2['pore.coords'] += [Lc * Nx, 0, 0]
         op.topotools.stitch(network=pn, donor=pn2,
                             P_network=pn.pores('back'), P_donor=pn2.pores('front'),
                             label_stitches=['test', 'test2'])
-        assert pn.Nt == (pn2.Nt*2 + 10)
+        assert pn.Nt == (pn2.Nt * 2 + 10)
 
     def test_stitch_with_multiple_labels(self):
         Nx, Ny, Nz = (10, 10, 1)
         Lc = 1e-4
         pn = op.network.Cubic(shape=[Nx, Ny, Nz], spacing=Lc)
         pn2 = op.network.Cubic(shape=[Nx, Ny, Nz], spacing=Lc)
-        pn2['pore.coords'] += [Lc*Nx, 0, 0]
+        pn2['pore.coords'] += [Lc * Nx, 0, 0]
         op.topotools.stitch(network=pn, donor=pn2,
                             P_network=pn.pores('back'), P_donor=pn2.pores('front'),
                             label_stitches=['test', 'test2'])
@@ -388,16 +388,16 @@ class TopotoolsTest:
     def test_stitch_repeatedly(self):
         pn = op.network.Cubic(shape=[10, 10, 1], spacing=1e-4)
         pn2 = op.network.Cubic(shape=[10, 10, 1], spacing=1e-4)
-        pn2['pore.coords'] += [1e-4*10, 0, 0]
+        pn2['pore.coords'] += [1e-4 * 10, 0, 0]
         pn3 = op.network.Cubic(shape=[10, 10, 1], spacing=1e-4)
-        pn3['pore.coords'] += [1e-4*20, 0, 0]
+        pn3['pore.coords'] += [1e-4 * 20, 0, 0]
         op.topotools.stitch(network=pn, donor=pn2,
                             P_network=pn.pores('back'), P_donor=pn2.pores('front'),
                             method='nearest')
         op.topotools.stitch(network=pn, donor=pn3,
                             P_network=pn.pores('back'), P_donor=pn2.pores('front'),
                             method='nearest')
-        assert pn.Nt == (pn2.Nt*3 + 20)
+        assert pn.Nt == (pn2.Nt * 3 + 20)
 
     def test_dimensionality(self):
         # 3D network
@@ -409,7 +409,8 @@ class TopotoolsTest:
         dims = op.topotools.dimensionality(pn)
         assert np.allclose(dims, np.array([True, False, True]))
         # 1D network
-        pn = op.network.Cubic(shape=[1, 1, 5])
+        pn = op.network.Cubic(shape=[1, 1, 5], spacing=1.2345e-30)
+        pn["pore.coords"][0, 0] = pn["pore.coords"][0, :].mean()
         dims = op.topotools.dimensionality(pn)
         assert np.allclose(dims, np.array([False, False, True]))