Repository: PMEAL/OpenPNM

Issue:
Models that return conduit data should return Nt by 3 instead of a dict
Because it's more concise...

Discussion:

Patch:
diff --git a/openpnm/core/_base2.py b/openpnm/core/_base2.py
index 94c40516d..f2f2e9a13 100644
--- a/openpnm/core/_base2.py
+++ b/openpnm/core/_base2.py
@@ -402,12 +402,35 @@ class Base2(dict):
             values = from_neighbor_throats(target=self, prop='throat.'+prop, mode=mode)
         return values
 
-    def get_conduit_data(self, propname, mode='mean'):
+    def get_conduit_data(self, propname):
+        r"""
+        Fetches an Nt-by-3 array of the request property in the form of
+        [pore1, throat, pore2].
+
+        Parameters
+        ----------
+        propname : str
+            The dictionary key of the property to fetch.
+
+        Returns
+        -------
+        data : ndarray
+            An Nt-by-3 array with each column containing the requrested data
+            for pore1, throat, and pore2 respectively.
+
+        """
+        # If requested data is already in the form of conduit data, return it
+        if propname in self.keys():
+            vals = self[propname]
+            if (vals.ndim == 2) and (vals.shape[1] == self.Nt):
+                return vals
         poreprop = 'pore.' + propname.split('.', 1)[-1]
         throatprop = 'throat.' + propname.split('.', 1)[-1]
         conns = self.network.conns
         try:
             T = self[throatprop]
+            if T.ndim > 1:
+                raise Exception(f'{throatprop} must be a single column wide')
         except KeyError:
             T = np.ones([self.Nt, ], dtype=float)*np.nan
         try:
diff --git a/openpnm/io/__init__.py b/openpnm/io/__init__.py
index 3acf869b5..e8ad5d332 100644
--- a/openpnm/io/__init__.py
+++ b/openpnm/io/__init__.py
@@ -18,7 +18,7 @@ from ._marock import network_from_marock
 from ._porespy import network_from_porespy
 from ._paraview import project_to_paraview
 from ._networkx import network_to_networkx, network_from_networkx
-from ._statoil import network_to_statoil, network_from_statoil
+from ._statoil import network_from_statoil  # , network_to_statoil
 from ._pergeos import network_to_pergeos, network_from_pergeos
 from ._jsongraph import network_to_jsongraph, network_from_jsongraph
 from ._stl import network_to_stl
diff --git a/openpnm/models/geometry/conduit_lengths/_funcs.py b/openpnm/models/geometry/conduit_lengths/_funcs.py
index 7ab4748a1..574a1a63d 100644
--- a/openpnm/models/geometry/conduit_lengths/_funcs.py
+++ b/openpnm/models/geometry/conduit_lengths/_funcs.py
@@ -36,7 +36,7 @@ def spheres_and_cylinders(
     Returns
     -------
     lengths : ndarray
-        Array (Nt by 3) containing conduit length values for each element
+        Array (Nt by 3) containing conduit values for each element
         of the pore-throat-pore conduits. The array is formatted as
         ``[pore1, throat, pore2]``.
 
diff --git a/openpnm/models/geometry/diffusive_size_factors/_funcs.py b/openpnm/models/geometry/diffusive_size_factors/_funcs.py
index c55be330c..4cb81b672 100644
--- a/openpnm/models/geometry/diffusive_size_factors/_funcs.py
+++ b/openpnm/models/geometry/diffusive_size_factors/_funcs.py
@@ -39,9 +39,10 @@ def spheres_and_cylinders(
 
     Returns
     -------
-    size_factors : dict
-        A dictionary containing the diffusive size factors, which can be
-        accessed via the dict keys 'pore1', 'pore2', and 'throat'.
+    size_factors : ndarray
+        Array (Nt by 3) containing conduit values for each element
+        of the pore-throat-pore conduits. The array is formatted as
+        ``[pore1, throat, pore2]``.
 
     Notes
     -----
@@ -70,7 +71,8 @@ def spheres_and_cylinders(
     F2 = 2 / (D2 * _np.pi) * _np.arctanh(2 * L2 / D2)
     Ft = Lt / (_np.pi / 4 * Dt ** 2)
 
-    return {"pore1": 1 / F1, "throat": 1 / Ft, "pore2": 1 / F2}
+    vals = _np.vstack([1/F1, 1/Ft, 1/F2]).T
+    return vals
 
 
 @docstr.dedent
@@ -111,7 +113,8 @@ def circles_and_rectangles(
     F2 = 0.5 * _np.arcsin(2 * L2 / D2)
     Ft = Lt / Dt
 
-    return {"pore1": 1 / F1, "throat": 1 / Ft, "pore2": 1 / F2}
+    vals = _np.vstack([1/F1, 1/Ft, 1/F2]).T
+    return vals
 
 
 @docstr.dedent
@@ -152,7 +155,8 @@ def cones_and_cylinders(
     F2 = 4 * L2 / (D2 * Dt * _np.pi)
     Ft = Lt / (_np.pi * Dt**2 / 4)
 
-    return {"pore1": 1 / F1, "throat": 1 / Ft, "pore2": 1 / F2}
+    vals = _np.vstack([1/F1, 1/Ft, 1/F2]).T
+    return vals
 
 
 @docstr.dedent
@@ -199,7 +203,8 @@ def trapezoids_and_rectangles(
     mask = _np.isclose(D2, Dt)
     F2[mask] = (L2 / D2)[mask]
 
-    return {"pore1": 1 / F1, "throat": 1 / Ft, "pore2": 1 / F2}
+    vals = _np.vstack([1/F1, 1/Ft, 1/F2]).T
+    return vals
 
 
 def pyramids_and_cuboids(
@@ -239,7 +244,8 @@ def pyramids_and_cuboids(
     F2 = L2 / (D2 * Dt)
     Ft = Lt / Dt**2
 
-    return {"pore1": 1 / F1, "throat": 1 / Ft, "pore2": 1 / F2}
+    vals = _np.vstack([1/F1, 1/Ft, 1/F2]).T
+    return vals
 
 
 @docstr.dedent
@@ -286,7 +292,8 @@ def cubes_and_cuboids(
     F2 = L2 / D2**2
     Ft = Lt / Dt**2
 
-    return {"pore1": 1 / F1, "throat": 1 / Ft, "pore2": 1 / F2}
+    vals = _np.vstack([1/F1, 1/Ft, 1/F2]).T
+    return vals
 
 
 @docstr.dedent
@@ -333,7 +340,8 @@ def squares_and_rectangles(
     F2 = L2 / D2
     Ft = Lt / Dt
 
-    return {"pore1": 1 / F1, "throat": 1 / Ft, "pore2": 1 / F2}
+    vals = _np.vstack([1/F1, 1/Ft, 1/F2]).T
+    return vals
 
 
 def intersecting_cones(
@@ -472,4 +480,5 @@ def ncylinders_in_series(
     F2 = 1 / _np.sum(1 / gtemp, axis=1)
     Ft = (_np.pi * (Dt / 2)**2 / (Lt)).T
 
-    return {"pore1": F1, "throat": Ft, "pore2": F2}
+    vals = _np.vstack([F1, Ft, F2]).T
+    return vals
diff --git a/openpnm/models/geometry/hydraulic_size_factors/_funcs.py b/openpnm/models/geometry/hydraulic_size_factors/_funcs.py
index d6a19dd3d..f5bf558a5 100644
--- a/openpnm/models/geometry/hydraulic_size_factors/_funcs.py
+++ b/openpnm/models/geometry/hydraulic_size_factors/_funcs.py
@@ -39,9 +39,10 @@ def spheres_and_cylinders(
 
     Returns
     -------
-    size_factors : dict
-        A dictionary containing the hydraulic size factors, which can be
-        accessed via the dict keys 'pore1', 'pore2', and 'throat'.
+    size_factors : ndarray
+        Array (Nt by 3) containing conduit values for each element
+        of the pore-throat-pore conduits. The array is formatted as
+        ``[pore1, throat, pore2]``.
 
     Notes
     -----
@@ -82,7 +83,7 @@ def spheres_and_cylinders(
     St = 1 / (16 * _np.pi**2 * It * Ft)
     S2 = 1 / (16 * _np.pi**2 * I2 * F2)
 
-    return {"pore1": S1, "throat": St, "pore2": S2}
+    return _np.vstack([S1, St, S2]).T
 
 
 @docstr.dedent
@@ -123,7 +124,7 @@ def circles_and_rectangles(
     # S is 1 / (12 * F)
     S1, St, S2 = [1 / (Fi * 12) for Fi in [F1, Ft, F2]]
 
-    return {"pore1": S1, "throat": St, "pore2": S2}
+    return _np.vstack([S1, St, S2]).T
 
 
 @docstr.dedent
@@ -169,7 +170,7 @@ def cones_and_cylinders(
     St = 1 / (16 * _np.pi**2 * It * Ft)
     S2 = 1 / (16 * _np.pi**2 * I2 * F2)
 
-    return {"pore1": S1, "throat": St, "pore2": S2}
+    return _np.vstack([S1, St, S2]).T
 
 
 @docstr.dedent
@@ -213,7 +214,7 @@ def trapezoids_and_rectangles(
     # S is 1 / (12 * F)
     S1, St, S2 = [1 / (Fi * 12) for Fi in [F1, Ft, F2]]
 
-    return {"pore1": S1, "throat": St, "pore2": S2}
+    return _np.vstack([S1, St, S2]).T
 
 
 @docstr.dedent
@@ -259,7 +260,7 @@ def pyramids_and_cuboids(
     St = 1 / (16 * _np.pi**2 * It * Ft)
     S2 = 1 / (16 * _np.pi**2 * I2 * F2)
 
-    return {"pore1": S1, "throat": St, "pore2": S2}
+    return _np.vstack([S1, St, S2]).T
 
 
 @docstr.dedent
@@ -311,7 +312,7 @@ def cubes_and_cuboids(
     St = 1 / (16 * _np.pi**2 * It * Ft)
     S2 = 1 / (16 * _np.pi**2 * I2 * F2)
 
-    return {"pore1": S1, "throat": St, "pore2": S2}
+    return _np.vstack([S1, St, S2]).T
 
 
 @docstr.dedent
@@ -361,7 +362,7 @@ def squares_and_rectangles(
     # S is 1 / (12 * F)
     S1, St, S2 = [1 / (Fi * 12) for Fi in [F1, Ft, F2]]
 
-    return {"pore1": S1, "throat": St, "pore2": S2}
+    return _np.vstack([S1, St, S2]).T
 
 
 @docstr.dedent
@@ -423,6 +424,7 @@ def intersecting_trapezoids(
     """
     raise NotImplementedError
 
+
 @docstr.dedent
 def intersecting_pyramids(
     target,
@@ -496,4 +498,4 @@ def ncylinders_in_series(
     F2 = 1 / _np.sum(1 / gtemp, axis=1)
     Ft = (_np.pi * (Dt / 2) ** 4 / (8 * Lt)).T
 
-    return {"pore1": F1, "throat": Ft, "pore2": F2}
+    return _np.vstack([F1, Ft, F2]).T
diff --git a/openpnm/models/physics/_utils.py b/openpnm/models/physics/_utils.py
index f2ab278bd..38834e48a 100644
--- a/openpnm/models/physics/_utils.py
+++ b/openpnm/models/physics/_utils.py
@@ -1,6 +1,14 @@
 r"""
 Pore-scale models for calculating the conductance of conduits.
 """
+from numpy import vstack
+
+
+__all__ = [
+    '_poisson_conductance',
+    '_get_key_props',
+]
+
 
 def _poisson_conductance(target,
                          pore_conductivity=None,
@@ -44,8 +52,8 @@ def _poisson_conductance(target,
     D1, D2 = phase[pore_conductivity][cn].T
     # If individual size factors for conduit constiuents are known
     SF = network[size_factors]
-    if isinstance(SF, dict):
-        F1, Ft, F2 = SF.values()
+    if SF.ndim == 2:
+        F1, Ft, F2 = SF.T
         g1 = D1 * F1[throats]
         gt = Dt * Ft[throats]
         g2 = D2 * F2[throats]
diff --git a/openpnm/models/physics/diffusive_conductance/_funcs.py b/openpnm/models/physics/diffusive_conductance/_funcs.py
index 2fecc08a4..6ead90d3f 100644
--- a/openpnm/models/physics/diffusive_conductance/_funcs.py
+++ b/openpnm/models/physics/diffusive_conductance/_funcs.py
@@ -192,13 +192,14 @@ def taylor_aris_diffusion(target,
     Pe2 = u2 * ((4 * A2 / _np.pi) ** 0.5) / D2
     Pet = ut * ((4 * At / _np.pi) ** 0.5) / Dt
 
-    # Calculate diffusive conductance
-    if isinstance(F, dict):
-        g1 = D1 * (1 + Pe1**2 / 192) * F["pore1"][throats]
-        gt = Dt * (1 + Pet**2 / 192) * F["throat"][throats]
-        g2 = D2 * (1 + Pe2**2 / 192) * F["pore2"][throats]
-        return 1 / (1/g1 + 1/gt + 1/g2)
-    return Dt * (1 + Pet**2 / 192) * F[throats]
+    if F.ndim > 1:
+        g1 = D1 * (1 + Pe1**2 / 192) * F[throats, 0]
+        gt = Dt * (1 + Pet**2 / 192) * F[throats, 1]
+        g2 = D2 * (1 + Pe2**2 / 192) * F[throats, 2]
+        gtot = 1 / (1/g1 + 1/gt + 1/g2)
+    else:
+        gtot = Dt * (1 + Pet**2 / 192) * F[throats]
+    return gtot
 
 
 @_doctxt
@@ -233,7 +234,13 @@ def multiphase_diffusion(target,
     """
     network = target.network
     cn = network.conns
-    F1, Ft, F2 = network[size_factors].values()
+    SF = network[size_factors]
+    if isinstance(SF, dict):
+        F1, Ft, F2 = SF.values()
+    elif SF.ndim > 1:
+        F1, Ft, F2 = SF.T
+    else:
+        F1, Ft, F2 = _np.inf, SF, _np.inf
 
     # Fetch model parameters
     D1, D2 = target[pore_diffusivity][cn].T
diff --git a/openpnm/models/physics/hydraulic_conductance/_funcs.py b/openpnm/models/physics/hydraulic_conductance/_funcs.py
index 47fb77411..32cdc781f 100644
--- a/openpnm/models/physics/hydraulic_conductance/_funcs.py
+++ b/openpnm/models/physics/hydraulic_conductance/_funcs.py
@@ -36,19 +36,23 @@ def generic_hydraulic(
 
     """
     network = target.network
-    throats = target.throats()
-    conns = network.conns[throats]
+    conns = network.conns
     phase = target
-    F = network[size_factors]
     mu1, mu2 = phase[pore_viscosity][conns].T
-    mut = phase[throat_viscosity][throats]
+    mut = phase[throat_viscosity]
 
-    if isinstance(F, dict):
-        g1 = F["pore1"][throats] / mu1
-        gt = F["throat"][throats] / mut
-        g2 = F["pore2"][throats] / mu2
-        return 1 / (1/g1 + 1/gt + 1/g2)
-    return F[throats] / mut
+    SF = network[size_factors]
+    if isinstance(SF, dict):  # Legacy approach
+        F1, Ft, F2 = SF.values()
+    elif SF.ndim > 1:  # Nt-by-3 array
+        F1, Ft, F2 = SF.T
+    else:  # Nt array, like from network extraction predictions
+        F1, Ft, F2 = _np.inf, SF, _np.inf
+
+    g1 = F1 / mu1
+    gt = Ft / mut
+    g2 = F2 / mu2
+    return 1 / (1/g1 + 1/gt + 1/g2)
 
 
 @_doctxt
@@ -145,9 +149,9 @@ def hagen_poiseuille_power_law(
     # Fetch model parameters
     A1, A2 = network[pore_area][cn].T
     At = network[throat_area][throats]
-    L1 = network[conduit_lengths + ".pore1"][throats]
-    L2 = network[conduit_lengths + ".pore2"][throats]
-    Lt = network[conduit_lengths + ".throat"][throats]
+    L1 = network[conduit_lengths][throats, 0]
+    L2 = network[conduit_lengths][throats, 1]
+    Lt = network[conduit_lengths][throats, 2]
     P = phase[pore_pressure]
     t_prop = 'throat.'+pore_pressure.split('.', 1)[-1]
     Pt = phase.interpolate_data(propname=t_prop)[throats]
@@ -179,9 +183,9 @@ def hagen_poiseuille_power_law(
 
     F = network[size_factors]
     if isinstance(F, dict):
-        g1 = F[f"{size_factors}.pore1"][throats] / mu1
-        gt = F[f"{size_factors}.throat"][throats] / mut
-        g2 = F[f"{size_factors}.pore2"][throats] / mu2
+        g1 = F[f"{size_factors}"][throats, 0] / mu1
+        gt = F[f"{size_factors}"][throats, 1] / mut
+        g2 = F[f"{size_factors}"][throats, 2] / mu2
         return 1 / (1 / g1 + 1 / gt + 1 / g2)
     return F[throats] / mut
 
@@ -270,9 +274,7 @@ def valvatne_blunt(
     mu_t = target[throat_viscosity]
 
     # Fetch model parameters
-    L1 = network[conduit_lengths + ".pore1"]
-    Lt = network[conduit_lengths + ".throat"]
-    L2 = network[conduit_lengths + ".pore2"]
+    L1, Lt, L2 = network[conduit_lengths].T
     Gp = network[pore_shape_factor]
     Gt = network[throat_shape_factor]
     Ap = network[pore_area]
diff --git a/openpnm/models/physics/ionic_conductance/_funcs.py b/openpnm/models/physics/ionic_conductance/_funcs.py
index 66dd58a65..ca63a2f98 100644
--- a/openpnm/models/physics/ionic_conductance/_funcs.py
+++ b/openpnm/models/physics/ionic_conductance/_funcs.py
@@ -123,8 +123,8 @@ def electroneutrality(
 
     # Apply size factors and calculate the final conductance
     if isinstance(SF, dict):
-        g1 *= SF[f"{size_factors}.pore1"][throats]
-        gt *= SF[f"{size_factors}.throat"][throats]
-        g2 *= SF[f"{size_factors}.pore2"][throats]
+        g1 *= SF[f"{size_factors}"][throats, 0]
+        gt *= SF[f"{size_factors}"][throats, 1]
+        g2 *= SF[f"{size_factors}"][throats, 2]
         return 1 / (1/g1 + 1/gt + 1/g2)
     return gt * SF


Test patch:
diff --git a/tests/unit/core/BaseTest.py b/tests/unit/core/BaseTest.py
index b7bc3d142..5cc34858f 100644
--- a/tests/unit/core/BaseTest.py
+++ b/tests/unit/core/BaseTest.py
@@ -729,11 +729,6 @@ class BaseTest:
     #     assert a.size == self.geo.Nt
     #     assert np.isclose(a.mean(), 0.5)
 
-    # def test_get_no_matches(self):
-    #     self.geo.pop('pore.blah', None)
-    #     with pytest.raises(KeyError):
-    #         _ = self.geo['pore.blah']
-
     def test_get_string(self):
         a = self.net.get('pore.coords')
         assert a.shape == (self.net.Np, 3)
@@ -747,123 +742,6 @@ class BaseTest:
         assert 'bar' in d.keys()
         assert 'baz' in d.keys()
 
-    # def test_subdict_getitem_on_network_from_one_geometry(self):
-    #     pn = op.network.Cubic(shape=[5, 5, 5])
-    #     pn['pore.foo.bar'] = 1
-    #     pn['pore.foo.baz'] = 2
-    #     geo = op.geometry.GenericGeometry(network=pn, pores=pn.Ps,
-    #                                       throats=pn.Ts)
-    #     d = geo['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-
-    # def test_subdict_getitem_on_network_from_two_geometries(self):
-    #     pn = op.network.Cubic(shape=[5, 5, 5])
-    #     pn['pore.foo.bar'] = 1
-    #     pn['pore.foo.baz'] = 2
-    #     geo1 = op.geometry.GenericGeometry(network=pn,
-    #                                        pores=pn.Ps[:75],
-    #                                        throats=pn.Ts[:75])
-    #     geo2 = op.geometry.GenericGeometry(network=pn,
-    #                                        pores=pn.Ps[75:],
-    #                                        throats=pn.Ts[75:])
-    #     d = geo1['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-    #     assert d['pore.foo.bar'].size == geo1.Np
-    #     assert d['pore.foo.baz'].size == geo1.Np
-    #     d = geo2['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-    #     assert d['pore.foo.bar'].size == geo2.Np
-    #     assert d['pore.foo.baz'].size == geo2.Np
-
-    # def test_subdict_getitem_on_phase_from_phase(self):
-    #     pn = op.network.Cubic(shape=[5, 5, 5])
-    #     air = op.phase.Phase(network=pn)
-    #     air['pore.foo.bar'] = 1
-    #     air['pore.foo.baz'] = 2
-    #     d = air['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-
-    # def test_subdict_getitem_on_phase_from_one_physics(self):
-    #     pn = op.network.Cubic(shape=[5, 5, 5])
-    #     geo = op.geometry.GenericGeometry(network=pn, pores=pn.Ps,
-    #                                       throats=pn.Ts)
-    #     air = op.phase.Phase(network=pn)
-    #     phys = op.physics.GenericPhysics(network=pn, phase=air, geometry=geo)
-    #     air['pore.foo.bar'] = 1
-    #     air['pore.foo.baz'] = 2
-    #     d = phys['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-
-    # def test_subdict_getitem_on_phase_from_two_physics(self):
-    #     pn = op.network.Cubic(shape=[5, 5, 5])
-    #     geo1 = op.geometry.GenericGeometry(network=pn,
-    #                                        pores=pn.Ps[:75],
-    #                                        throats=pn.Ts[:75])
-    #     geo2 = op.geometry.GenericGeometry(network=pn,
-    #                                        pores=pn.Ps[75:],
-    #                                        throats=pn.Ts[75:])
-    #     air = op.phase.Phase(network=pn)
-    #     phys1 = op.physics.GenericPhysics(network=pn, phase=air, geometry=geo1)
-    #     phys2 = op.physics.GenericPhysics(network=pn, phase=air, geometry=geo2)
-    #     air['pore.foo.bar'] = 1
-    #     air['pore.foo.baz'] = 2
-
-    #     d = phys1['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-    #     assert d['pore.foo.bar'].size == geo1.Np
-    #     assert d['pore.foo.baz'].size == geo1.Np
-    #     d = phys2['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-    #     assert d['pore.foo.bar'].size == geo2.Np
-    #     assert d['pore.foo.baz'].size == geo2.Np
-
-    # def test_subdict_getitem_on_one_geometry(self):
-    #     pn = op.network.Cubic(shape=[5, 5, 5])
-    #     geo = op.geometry.GenericGeometry(network=pn, pores=pn.Ps,
-    #                                       throats=pn.Ts)
-    #     geo['pore.foo.bar'] = 1
-    #     geo['pore.foo.baz'] = 2
-    #     d = pn['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-
-    # def test_subdict_getitem_on_two_geometries(self):
-    #     pn = op.network.Cubic(shape=[5, 5, 5])
-    #     geo1 = op.geometry.GenericGeometry(network=pn,
-    #                                        pores=pn.Ps[:75],
-    #                                        throats=pn.Ts[:75])
-    #     geo2 = op.geometry.GenericGeometry(network=pn,
-    #                                        pores=pn.Ps[75:],
-    #                                        throats=pn.Ts[75:])
-    #     geo1['pore.foo.bar'] = 1
-    #     geo1['pore.foo.baz'] = 2
-    #     d = pn['pore.foo']
-    #     assert len(d) == 2
-    #     assert 'pore.foo.bar' in d.keys()
-    #     assert 'pore.foo.baz' in d.keys()
-    #     assert np.any(np.isnan(d['pore.foo.bar']))
-    #     assert np.any(np.isnan(d['pore.foo.baz']))
-    #     geo2['pore.foo.bar'] = 1
-    #     geo2['pore.foo.baz'] = 2
-    #     d = pn['pore.foo']
-    #     assert np.all(~np.isnan(d['pore.foo.bar']))
-    #     assert np.all(~np.isnan(d['pore.foo.baz']))
-
     def test_subdict_lookup_errors(self):
         pn = op.network.Cubic(shape=[5, 5, 5])
         pn['pore.foo.bar'] = 1
@@ -952,30 +830,6 @@ class BaseTest:
         with pytest.raises(KeyError):
             pn.get_conduit_data('blah')
 
-    # def test_get_conduit_data_different_props(self):
-    #     pn = op.network.Cubic(shape=[3, 3, 3])
-    #     pn['pore.diameter'] = 2.0
-    #     pn['throat.volume'] = 1.0
-    #     a = pn.get_conduit_data(poreprop='pore.diameter',
-    #                             throatprop='throat.volume')
-    #     assert np.all(a.shape == (54, 3))
-    #     assert np.all(a[:, 1] == 1.0)
-    #     assert np.all(a[:, 0] == 2.0)
-    #     assert np.all(a[:, 2] == 2.0)
-
-    # def test_del_nested_dicts(self):
-    #     pn = op.network.Cubic(shape=[3, 3, 3])
-    #     geo = op.geometry.SpheresAndCylinders(network=pn,
-    #                                           pores=pn.Ps,
-    #                                           throats=pn.Ts)
-    #     assert 'throat.hydraulic_size_factors.pore1' in geo.keys()
-    #     del geo['throat.hydraulic_size_factors']
-    #     assert 'throat.hydraulic_size_factors.pore1' not in geo.keys()
-    #     with pytest.raises(KeyError):
-    #         geo['throat.hydraulic_size_factors']
-    #     with pytest.raises(KeyError):
-    #         del geo['pore.blah']
-
 
 if __name__ == '__main__':
 
diff --git a/tests/unit/models/geometry/ConduitDiffusiveSizeFactorsTest.py b/tests/unit/models/geometry/ConduitDiffusiveSizeFactorsTest.py
index 1677cd228..eab5a6d0e 100644
--- a/tests/unit/models/geometry/ConduitDiffusiveSizeFactorsTest.py
+++ b/tests/unit/models/geometry/ConduitDiffusiveSizeFactorsTest.py
@@ -14,7 +14,10 @@ class ConduitDiffusiveSizeFactorsTest:
         self.air.regenerate_models()
 
     def test_spheres_and_cylinders(self):
-        S_actual = mods.spheres_and_cylinders(self.net)
+        SF = mods.spheres_and_cylinders(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.93875728, 0.97459088]),
             'throat': array([1.25663706e+14, 4.05813214e-01]),
@@ -24,7 +27,10 @@ class ConduitDiffusiveSizeFactorsTest:
             assert_allclose(v, S_desired[k])
 
     def test_circles_and_rectangles(self):
-        S_actual = mods.circles_and_rectangles(self.net)
+        SF = mods.circles_and_rectangles(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([1.53390798, 1.80140852]),
             'throat': array([4.00000000e+14, 1.29174358e+00]),
@@ -34,17 +40,23 @@ class ConduitDiffusiveSizeFactorsTest:
             assert_allclose(v, S_desired[k])
 
     def test_cones_and_cylinders(self):
-        S_actual = mods.cones_and_cylinders(self.net)
+        SF = mods.cones_and_cylinders(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.65138854, 0.62831853]),
             'throat': array([1.25663706e+14, 6.28318531e-01]),
-            'pore2': array([0.6712008 , 0.62831853])
+            'pore2': array([0.6712008, 0.62831853])
         }
         for k, v in S_actual.items():
             assert_allclose(v, S_desired[k])
 
     def test_trapezoids_and_rectangles(self):
-        S_actual = mods.trapezoids_and_rectangles(self.net)
+        SF = mods.trapezoids_and_rectangles(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([1.25821405, 1.37016859]),
             'throat': array([4.e+14, 2.e+00]),
@@ -54,7 +66,10 @@ class ConduitDiffusiveSizeFactorsTest:
             assert_allclose(v, S_desired[k])
 
     def test_pyramids_and_cuboids(self):
-        S_actual = mods.pyramids_and_cuboids(self.net)
+        SF = mods.pyramids_and_cuboids(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.82937365, 0.8]),
             'throat': array([1.6e+14, 8.0e-01]),
@@ -64,7 +79,10 @@ class ConduitDiffusiveSizeFactorsTest:
             assert_allclose(v, S_desired[k])
 
     def test_cubes_and_cuboids(self):
-        S_actual = mods.cubes_and_cuboids(self.net)
+        SF = mods.cubes_and_cuboids(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([2.4, 1.8]),
             'throat': array([1.6e+14, 8.0e-01]),
@@ -74,7 +92,10 @@ class ConduitDiffusiveSizeFactorsTest:
             assert_allclose(v, S_desired[k])
 
     def test_squares_and_rectangles(self):
-        S_actual = mods.squares_and_rectangles(self.net)
+        SF = mods.squares_and_rectangles(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([2., 2.]),
             'throat': array([4.e+14, 2.e+00]),
@@ -84,11 +105,14 @@ class ConduitDiffusiveSizeFactorsTest:
             assert_allclose(v, S_desired[k])
 
     def test_ncylinders_in_series(self):
-        S_actual = mods.ncylinders_in_series(self.net)
+        SF = mods.ncylinders_in_series(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.49260457, 0.77443401]),
             'throat': array([1.25663706e+14, 4.05813214e-01]),
-            'pore2': array([0.563723  , 0.84600371])
+            'pore2': array([0.563723, 0.84600371])
         }
         for k, v in S_actual.items():
             assert_allclose(v, S_desired[k])
diff --git a/tests/unit/models/geometry/ConduitHydraulicSizeFactorsTest.py b/tests/unit/models/geometry/ConduitHydraulicSizeFactorsTest.py
index 3c46171f9..eb68e0cd4 100644
--- a/tests/unit/models/geometry/ConduitHydraulicSizeFactorsTest.py
+++ b/tests/unit/models/geometry/ConduitHydraulicSizeFactorsTest.py
@@ -14,7 +14,10 @@ class ConduitHydraulicSizeFactorsTest:
         self.net["pore.diameter"] = [1.2, 0.9, 0.7]
 
     def test_spheres_and_cylinders(self):
-        S_actual = mods.spheres_and_cylinders(self.net)
+        SF = mods.spheres_and_cylinders(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.01068901, 0.01195694]),
             'throat': array([6.28318531e+11, 2.02906607e-03]),
@@ -24,7 +27,10 @@ class ConduitHydraulicSizeFactorsTest:
             assert_allclose(v, S_desired[k], rtol=1e-5)
 
     def test_circles_and_rectangles(self):
-        S_actual = mods.circles_and_rectangles(self.net)
+        SF = mods.circles_and_rectangles(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.06563123, 0.06697876]),
             'throat': array([5.33333333e+12, 1.72232477e-02]),
@@ -34,7 +40,10 @@ class ConduitHydraulicSizeFactorsTest:
             assert_allclose(v, S_desired[k], rtol=1e-5)
 
     def test_cones_and_cylinders(self):
-        S_actual = mods.cones_and_cylinders(self.net)
+        SF = mods.cones_and_cylinders(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.00676442, 0.0057399]),
             'throat': array([6.28318531e+11, 3.14159265e-03]),
@@ -44,7 +53,10 @@ class ConduitHydraulicSizeFactorsTest:
             assert_allclose(v, S_desired[k], rtol=1e-5)
 
     def test_trapezoids_and_rectangles(self):
-        S_actual = mods.trapezoids_and_rectangles(self.net)
+        SF = mods.trapezoids_and_rectangles(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.04146868, 0.03692308]),
             'throat': array([5.33333333e+12, 2.66666667e-02]),
@@ -54,7 +66,10 @@ class ConduitHydraulicSizeFactorsTest:
             assert_allclose(v, S_desired[k], rtol=1e-5)
 
     def test_pyramids_and_cuboids(self):
-        S_actual = mods.pyramids_and_cuboids(self.net)
+        SF = mods.pyramids_and_cuboids(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.01047182, 0.00888579]),
             'throat': array([9.72683363e+11, 4.86341681e-03]),
@@ -64,7 +79,10 @@ class ConduitHydraulicSizeFactorsTest:
             assert_allclose(v, S_desired[k], rtol=1e-5)
 
     def test_cubes_and_cuboids(self):
-        S_actual = mods.cubes_and_cuboids(self.net)
+        SF = mods.cubes_and_cuboids(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
             'pore1': array([0.13131225, 0.05539736]),
             'throat': array([9.72683363e+11, 4.86341681e-03]),
@@ -74,19 +92,25 @@ class ConduitHydraulicSizeFactorsTest:
             assert_allclose(v, S_desired[k], rtol=1e-5)
 
     def test_squares_and_rectangles(self):
-        S_actual = mods.squares_and_rectangles(self.net)
+        SF = mods.squares_and_rectangles(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
-            'pore1': array([0.24 , 0.135]),
+            'pore1': array([0.24, 0.135]),
             'throat': array([5.33333333e+12, 2.66666667e-02]),
-            'pore2': array([0.151875  , 0.08166667])
+            'pore2': array([0.151875, 0.08166667])
         }
         for k, v in S_actual.items():
             assert_allclose(v, S_desired[k], rtol=1e-5)
 
     def test_ncylinders_in_series(self):
-        S_actual = mods.ncylinders_in_series(self.net)
+        SF = mods.ncylinders_in_series(self.net)
+        S_actual = {'pore1': SF[:, 0],
+                    'throat': SF[:, 1],
+                    'pore2': SF[:, 2]}
         S_desired = {
-            'pore1': array([0.0020471 , 0.00612218]),
+            'pore1': array([0.0020471, 0.00612218]),
             'throat': array([6.28318531e+11, 2.02906607e-03]),
             'pore2': array([0.00261812, 0.00661558])
         }
diff --git a/tests/unit/models/physics/DiffusiveConductanceTest.py b/tests/unit/models/physics/DiffusiveConductanceTest.py
index 62fedb116..5a114bc0d 100644
--- a/tests/unit/models/physics/DiffusiveConductanceTest.py
+++ b/tests/unit/models/physics/DiffusiveConductanceTest.py
@@ -15,10 +15,10 @@ class DiffusiveConductanceTest:
         self.phase['pore.diffusivity'] = 1.3
         self.phase['pore.molecular_weight'] = 0.029
         self.phase['pore.temperature'] = 345.0
-        self.size_factors_dict = {"pore1": 0.123, "throat": 0.981, "pore2": 0.551}
+        self.size_factors = np.ones([self.net.Nt, 3])*(0.123, 0.981, 0.551)
 
     def test_generic_diffusive_size_factors_as_dict(self):
-        self.net['throat.diffusive_size_factors'] = self.size_factors_dict
+        self.net['throat.diffusive_size_factors'] = self.size_factors
         mod = op.models.physics.diffusive_conductance.generic_diffusive
         self.phase.add_model(propname='throat.diffusive_conductance', model=mod)
         self.phase.regenerate_models()
@@ -54,7 +54,7 @@ class DiffusiveConductanceTest:
         # assert len(phase['throat.diffusive_conductance']) == 5
 
     def test_ordinary_diffusion_size_factors_given_as_dict(self):
-        self.net['throat.diffusive_size_factors'] = self.size_factors_dict
+        self.net['throat.diffusive_size_factors'] = self.size_factors
         mod = op.models.physics.diffusive_conductance.ordinary_diffusion
         self.phase.add_model(propname='throat.diffusive_conductance', model=mod)
         self.phase.regenerate_models()
@@ -72,7 +72,7 @@ class DiffusiveConductanceTest:
         del self.net["throat.diffusive_size_factors"]
 
     def test_mixed_diffusion(self):
-        self.net['throat.diffusive_size_factors'] = self.size_factors_dict
+        self.net['throat.diffusive_size_factors'] = self.size_factors
         mod = op.models.physics.diffusive_conductance.mixed_diffusion
         self.phase.add_model(propname='throat.diffusive_conductance', model=mod)
         self.phase.regenerate_models()
@@ -106,7 +106,7 @@ class DiffusiveConductanceTest:
     #     assert_allclose(g.mean(), 7.64303956e-7, rtol=1e-5)
 
     def test_taylor_aris_diffusion(self):
-        self.net['throat.diffusive_size_factors'] = self.size_factors_dict
+        self.net['throat.diffusive_size_factors'] = self.size_factors
         self.phase['pore.pressure'] = np.linspace(0, 20, self.net.Np)
         self.phase['throat.hydraulic_conductance'] = 1
         mod = op.models.physics.diffusive_conductance.taylor_aris_diffusion
diff --git a/tests/unit/models/physics/ElectricalConductanceTest.py b/tests/unit/models/physics/ElectricalConductanceTest.py
index 88b29af1b..d8e373876 100644
--- a/tests/unit/models/physics/ElectricalConductanceTest.py
+++ b/tests/unit/models/physics/ElectricalConductanceTest.py
@@ -9,9 +9,8 @@ class ElectricalConductanceTest:
         self.net = op.network.Cubic(shape=[4, 4, 4])
         self.net['pore.diameter'] = 1.0
         self.net['throat.diameter'] = 0.5
-        self.net['throat.diffusive_size_factors'] = {
-            "pore1": 0.123, "throat": 0.981, "pore2": 0.551
-        }
+        self.net['throat.diffusive_size_factors'] = \
+            np.ones([self.net.Nt, 3])*(0.123, 0.981, 0.551)
         self.phase = op.phase.Phase(network=self.net)
         self.phase['pore.electrical_conductivity'] = 1.0
 
diff --git a/tests/unit/models/physics/HydraulicConductanceTest.py b/tests/unit/models/physics/HydraulicConductanceTest.py
index e9e7fef81..21a9a58d5 100644
--- a/tests/unit/models/physics/HydraulicConductanceTest.py
+++ b/tests/unit/models/physics/HydraulicConductanceTest.py
@@ -1,5 +1,5 @@
 import openpnm as op
-import numpy as _np
+import numpy as np
 from numpy.testing import assert_allclose
 
 
@@ -13,14 +13,14 @@ class HydraulicConductanceTest:
         self.net['throat.cross_sectional_area'] = 0.5
         self.phase = op.phase.Phase(network=self.net)
         self.phase['pore.viscosity'] = 1e-5
-        self.size_factors_dict = {"pore1": 0.123, "throat": 0.981, "pore2": 0.551}
+        self.size_factors = np.ones([self.net.Nt, 3])*(0.123, 0.981, 0.551)
 
     def teardown_class(self):
         mgr = op.Workspace()
         mgr.clear()
 
     def test_generic_hydraulic_size_factors_as_dict(self):
-        self.net['throat.hydraulic_size_factors'] = self.size_factors_dict
+        self.net['throat.hydraulic_size_factors'] = self.size_factors
         mod = op.models.physics.hydraulic_conductance.generic_hydraulic
         self.phase.add_model(propname='throat.g_hydraulic_conductance', model=mod)
         self.phase.regenerate_models()
@@ -38,18 +38,16 @@ class HydraulicConductanceTest:
         # del self.phase['throat.g_hydraulic_conductance']
 
     def test_hagen_poiseuille(self):
-        self.net['throat.hydraulic_size_factors'] = self.size_factors_dict
+        self.net['throat.hydraulic_size_factors'] = self.size_factors
         mod = op.models.physics.hydraulic_conductance.hagen_poiseuille
         self.phase.add_model(propname='throat.hydraulic_conductance', model=mod)
         actual = self.phase['throat.hydraulic_conductance'].mean()
         assert_allclose(actual, desired=9120.483231751232)
 
     def test_valvatne_blunt(self):
-        self.net['throat.conduit_lengths.pore1'] = 0.15
-        self.net['throat.conduit_lengths.throat'] = 0.2
-        self.net['throat.conduit_lengths.pore2'] = 0.26
-        self.net['pore.shape_factor'] = _np.ones(self.net.Np) * 0.15
-        self.net['throat.shape_factor'] = _np.ones(self.net.Nt) * 0.15
+        self.net['throat.conduit_lengths'] = np.ones([self.net.Nt, 3])*(0.15, 0.2, 0.26)
+        self.net['pore.shape_factor'] = np.ones(self.net.Np) * 0.15
+        self.net['throat.shape_factor'] = np.ones(self.net.Nt) * 0.15
         mod = op.models.physics.hydraulic_conductance.valvatne_blunt
         self.phase.add_model(propname='throat.valvatne_conductance', model=mod)
         actual = self.phase['throat.valvatne_conductance'].mean()
diff --git a/tests/unit/models/physics/IonicConductanceTest.py b/tests/unit/models/physics/IonicConductanceTest.py
index d0a4b1ca2..93b6c59c9 100644
--- a/tests/unit/models/physics/IonicConductanceTest.py
+++ b/tests/unit/models/physics/IonicConductanceTest.py
@@ -13,9 +13,8 @@ class IonicConductanceTest:
         self.net['throat.cross_sectional_area'] = 1.0
         self.net['pore.volume'] = 1.0
         self.net['throat.volume'] = 1.0
-        self.net["throat.diffusive_size_factors"] = {
-            "pore1": 0.123, "throat": 0.981, "pore2": 0.551
-        }
+        self.net['throat.diffusive_size_factors'] = \
+            np.ones([self.net.Nt, 3])*(0.123, 0.981, 0.551)
         self.phase = op.phase.Phase(network=self.net)
         self.phase['pore.permittivity'] = 78.0
 
diff --git a/tests/unit/models/physics/ThermalConductanceTest.py b/tests/unit/models/physics/ThermalConductanceTest.py
index 6b10d0aa9..11b415b35 100644
--- a/tests/unit/models/physics/ThermalConductanceTest.py
+++ b/tests/unit/models/physics/ThermalConductanceTest.py
@@ -1,4 +1,5 @@
 import openpnm as op
+import numpy as np
 from numpy.testing import assert_allclose
 
 
@@ -6,9 +7,8 @@ class ThermalConductanceTest:
 
     def setup_class(self):
         self.net = op.network.Cubic(shape=[4, 4, 4])
-        self.net['throat.diffusive_size_factors'] = {
-            "pore1": 0.4, "throat": 0.2, "pore2": 0.3
-        }
+        self.net['throat.diffusive_size_factors'] = \
+            np.ones([self.net.Nt, 3])*(0.4, 0.2, 0.3)
         self.phase = op.phase.Phase(network=self.net)
         self.phase['pore.thermal_conductivity'] = 0.5