Repository: PMEAL/OpenPNM
Pull request #1695 (2020-10-13 01:16:05)

Enhance grid
A few improvements to the grid attr of the Project


Patch:
diff --git a/openpnm/utils/Grid.py b/openpnm/utils/Grid.py
index 6efac2f95..2d9d79988 100644
--- a/openpnm/utils/Grid.py
+++ b/openpnm/utils/Grid.py
@@ -3,13 +3,13 @@ import terminaltables as tt
 
 class Tableist():
 
-    def __init__(self, rows=1, cols=1, blank='---', style='single'):
+    def __init__(self, rows=1, cols=1, blank='---', style='ascii'):
         super().__init__()
         self.blank = blank
         header = [blank for i in range(cols)]
         self._grid = tt.AsciiTable([])
         _ = [self._grid.table_data.append(header.copy()) for _ in range(rows)]
-        self.style = style
+        self._style = style
 
     def __getitem__(self, row):
         if isinstance(row, slice):  # If slice, convert to list
@@ -79,6 +79,26 @@ class Tableist():
         for c in range(self.ncols):
             self._grid.table_data[row][c] = vals[c]
 
+    def set_row_and_col(self, row, col, val):
+        r"""
+
+        """
+        header = self.get_row(0)
+        index = self.get_col(0)
+        try:
+            col_num = header._grid.table_data[0].index(col)
+        except:
+            self.add_col()
+            self[0][-1] = col
+            col_num = -1
+        try:
+            row_num = index._grid.table_data.index([row])
+        except:
+            self.add_row()
+            self[-1][0] = row
+            row_num = -1
+        self[row_num][col_num] = val
+
     def _set_style(self, style):
         if hasattr(self, '_grid'):
             data = self._grid.table_data
diff --git a/openpnm/utils/Project.py b/openpnm/utils/Project.py
index 013fc49bd..d4423ce2d 100644
--- a/openpnm/utils/Project.py
+++ b/openpnm/utils/Project.py
@@ -41,7 +41,6 @@ class Project(list):
         self.settings = SettingsDict()
         ws[name] = self  # Register self with workspace
         self.settings['_uuid'] = str(uuid.uuid4())
-        self.comments = 'Using OpenPNM ' + openpnm.__version__
 
     def extend(self, obj):
         r"""
@@ -622,19 +621,6 @@ class Project(list):
     def _get_objects_by_type(self, objtype):
         return {item.name: item for item in self if item._isa(objtype)}
 
-    def _set_comments(self, string):
-        if hasattr(self, '_comments') is False:
-            self._comments = {}
-        self._comments[time.strftime('%c')] = string
-
-    def _get_comments(self):
-        if hasattr(self, '_comments') is False:
-            self._comments = {}
-        for key in list(self._comments.keys()):
-            print(key, ': ', self._comments[key])
-
-    comments = property(fget=_get_comments, fset=_set_comments)
-
     def __str__(self):
         s = []
         hr = '―'*78
@@ -931,61 +917,57 @@ class Project(list):
             else:
                 obj.regenerate_models()
 
-    def _generate_grid(self, astype='table'):
+    def _generate_grid(self):
         r"""
         """
-        from pandas import DataFrame as df
-
-        geoms = self.geometries().keys()
-        phases = [p.name for p in self.phases().values()
-                  if not hasattr(p, 'mixture')]
-        grid = df(index=geoms, columns=phases)
-        for r in grid.index:
-            for c in grid.columns:
-                phys = self.find_physics(phase=self[c], geometry=self[r])
-                if phys is not None:
-                    grid.loc[r][c] = phys.name
-                else:
-                    grid.loc[r][c] = '---'
-        if astype == 'pandas':
-            pass
-        elif astype == 'dict':
-            grid = grid.to_dict()
-        elif astype == 'table':
-            from terminaltables import SingleTable
-            headings = [self.network.name] + list(grid.keys())
-            g = [headings]
-            for row in list(grid.index):
-                g.append([row] + list(grid.loc[row]))
-            grid = SingleTable(g)
-            grid.title = 'Project: ' + self.name
-            grid.padding_left = 3
-            grid.padding_right = 3
-            grid.justify_columns = {col: 'center' for col in enumerate(headings)}
+        grid = ProjectGrid()
+        # Create first/index column of grid
+        rows = [self.network.name] + list(self.geometries().keys())
+        grid.add_row(num=len(rows) - 1)
+        grid.set_col(0, rows)
+        # Creatle first/header row of grid
+        cols = list(self.phases().keys())
+        grid.add_col(num=len(cols))
+        grid.set_row(0, vals=[self.network.name] + cols)
+        # Now add physics objects to grid, adding new columns/rows as needed.
+        miss = 0
+        for p in self.physics().values():
+            try:
+                row = self.find_geometry(p)
+                try:
+                    col = self.find_phase(p)
+                    grid.set_row_and_col(row=row.name, col=col.name, val=p.name)
+                except Exception:
+                    miss += 1
+                    grid.set_row_and_col(row=row.name, col='?'*miss, val=p.name)
+            except:
+                try:
+                    col = self.find_phase(p)
+                    miss += 1
+                    grid.set_row_and_col(row='?'*miss, col=col.name, val=p.name)
+                except Exception:
+                    miss += 1
+                    grid.set_row_and_col(row='?'*miss, col='?'*miss, val=p.name)
+        # See if any pores/throats are not assigned and add blank row
+        if len(self.geometries()) > 0:
+            h = self.check_geometry_health()
+            if (len(h['undefined_pores']) > 0) or (len(h['undefined_throats']) > 0):
+                grid.add_row()
         return grid
 
-    @property
-    def grid(self):
-        grid = self._generate_grid(astype='table')
-        obj = ProjectGrid()
-        obj._grid = grid
-        return obj
+    def _get_grid(self):
+        if not hasattr(self, '_grid'):
+            grid = self._generate_grid()
+            self._grid = grid
+        else:  # Update current grid with new data, to save formats and settings
+            grid = self._generate_grid()
+            self._grid._grid.table_data = grid._grid.table_data
+        return self._grid
 
-    def get_grid(self, astype):
-        r"""
-        Retrieves a copy of the grid data in the specified format
-
-        Parameters
-        ----------
-        astype : str
-            Can be 'dict', 'table', or 'pandas'
+    def _set_grid(self, grid):
+        self._grid = grid
 
-        Returns
-        -------
-        grid
-            The grid data in the specified format
-        """
-        return self._generate_grid(astype=astype)
+    grid = property(fget=_get_grid, fset=_set_grid)
 
 
 class ProjectGrid(Tableist):


Test patch:
diff --git a/tests/unit/utils/GridTest.py b/tests/unit/utils/GridTest.py
index f16bd82ac..58c8aed82 100644
--- a/tests/unit/utils/GridTest.py
+++ b/tests/unit/utils/GridTest.py
@@ -49,6 +49,14 @@ class GridTest:
         g.drop_row(3)
         assert g.shape == (3, 3)
 
+    def test_add_row_and_col_at_given_positions(self):
+        self.setup_class()
+        g = self.proj.grid
+        g.add_row(1)
+        assert g[1] == ['---', '---', '---']
+        g.add_col(1)
+        assert g[:][1] == ['---', '---', '---', '---']
+
     def test_nrows_ncols(self):
         self.setup_class()
         g = self.proj.grid
@@ -109,6 +117,21 @@ class GridTest:
         b = g.get_row('geo_01')
         assert a._grid.table_data == b._grid.table_data
 
+    def test_set_row_and_col(self):
+        self.setup_class()
+        g = self.proj.grid
+        g.set_row_and_col(row='x', col='z', val='z')
+        assert g[-1][-1] == 'z'
+        g.set_row_and_col(row='x', col='z', val='zz')
+        assert g[-1][-1] == 'zz'
+
+    def test_style_change(self):
+        self.setup_class()
+        g = self.proj.grid
+        assert g.style == 'ascii'
+        g.style = 'double'
+        assert g.style == 'double'
+
 
 if __name__ == '__main__':
 
diff --git a/tests/unit/utils/ProjectTest.py b/tests/unit/utils/ProjectTest.py
index 51fedd7df..ca206a2f8 100644
--- a/tests/unit/utils/ProjectTest.py
+++ b/tests/unit/utils/ProjectTest.py
@@ -51,20 +51,6 @@ class ProjectTest:
         assert proj.name in self.ws.keys()
         assert old_name not in self.ws.keys()
 
-    def test_grid_printing(self):
-        d = self.proj.get_grid(astype='dict')
-        assert d == {
-            'phase_01': {'geo_01': 'phys_01', 'geo_02': 'phys_02'},
-            'phase_02': {'geo_01': 'phys_03', 'geo_02': 'phys_04'}}
-
-        s = '┌Project: proj_01───────────┬──────────────┐\n' \
-            '│   net_01   │   phase_01   │   phase_02   │\n' \
-            '├────────────┼──────────────┼──────────────┤\n' \
-            '│   geo_01   │   phys_01    │   phys_03    │\n' \
-            '│   geo_02   │   phys_02    │   phys_04    │\n' \
-            '└────────────┴──────────────┴──────────────┘\n'
-        assert print(self.proj.grid) == print(s)
-
     def test_grid_access(self):
         g = self.proj.grid
         with pytest.raises(ValueError):
@@ -350,11 +336,6 @@ class ProjectTest:
         b = self.proj[a.name]
         assert a is b
 
-    def test_comments(self):
-        proj = self.proj
-        proj.comments = 'test comment'
-        assert 'test comment' in proj._comments.values()
-
     def test_print(self):
         proj = self.proj
         s = proj.__str__()