proj_to_vtk  breaks when drainage and/or invasion algorithms present
As mentioned in #2659 the io function is looking for a soln attribute on the algorithms and not finding it.  Also I think it's looking for a quantity key in the settings.  Basically the io function is assuming that only transport algorithms are present.  

Actually, I'm wondering why it's looking for algorithms at all...I think these functions only output the network and phases?
diff --git a/openpnm/algorithms/_drainage.py b/openpnm/algorithms/_drainage.py
index ae916be01..02d32acbd 100644
--- a/openpnm/algorithms/_drainage.py
+++ b/openpnm/algorithms/_drainage.py
@@ -34,7 +34,6 @@ class DrainageSettings:
 
     """
     phase = ''
-    quantity = 'pressure'
     throat_entry_pressure = 'throat.entry_pressure'
     pore_volume = 'pore.volume'
     throat_volume = 'throat.volume'
diff --git a/openpnm/utils/_misc.py b/openpnm/utils/_misc.py
index 2e91962f6..b658cfa31 100644
--- a/openpnm/utils/_misc.py
+++ b/openpnm/utils/_misc.py
@@ -601,10 +601,10 @@ def is_transient(algorithms):
         algorithms = [algorithms]
     # return True if any algorithm is transient
     for alg in algorithms:
-        quantity = alg.settings['quantity']
-        soln_type = type(alg.soln[quantity])
-        if 'TransientSolution' in str(soln_type):
-            return True
+        if hasattr(alg, 'soln'):
+            soln_type = type(alg.soln[alg.settings['quantity']])
+            if 'TransientSolution' in str(soln_type):
+                return True
     return False
 
 
diff --git a/tests/unit/io/VTKTest.py b/tests/unit/io/VTKTest.py
index 70be456df..4a130d3fa 100644
--- a/tests/unit/io/VTKTest.py
+++ b/tests/unit/io/VTKTest.py
@@ -32,6 +32,36 @@ class VTKTest:
         assert fname.is_file()
         os.remove(fname)
 
+    def test_save_single_phase_simulation(self, tmpdir):
+        fname = Path(tmpdir, 'test_save_vtk_1.vtp')
+        pn = op.network.Cubic(shape=[2, 2, 2])
+        phase = op.phase.Phase(network=pn)
+        phase['throat.diffusive_conductance'] = 1.0
+        fd = op.algorithms.FickianDiffusion(network=pn, phase=phase)
+        fd.set_value_BC(pores=pn.pores('left'), values=1)
+        fd.set_value_BC(pores=pn.pores('right'), values=0)
+        fd.run()
+        op.io.project_to_vtk(pn.project, filename=fname)
+        assert fname.is_file()
+        os.remove(fname)
+
+    def test_save_multiphase_simulation(self, tmpdir):
+        fname = Path(tmpdir, 'test_save_vtk_1.vtp')
+        pn = op.network.Cubic(shape=[2, 2, 2])
+        phase = op.phase.Phase(network=pn)
+        phase['throat.diffusive_conductance'] = 1.0
+        phase['throat.entry_pressure'] = np.random.rand(pn.Nt)
+        fd = op.algorithms.FickianDiffusion(network=pn, phase=phase)
+        fd.set_value_BC(pores=pn.pores('left'), values=1)
+        fd.set_value_BC(pores=pn.pores('right'), values=0)
+        fd.run()
+        drn = op.algorithms.Drainage(network=pn, phase=phase)
+        drn.set_inlet_BC(pores=pn.pores('left'))
+        drn.run()
+        op.io.project_to_vtk(pn.project, filename=fname)
+        assert fname.is_file()
+        os.remove(fname)
+
 
 if __name__ == '__main__':
     import py
['openpnm/utils/_misc.py', 'tests/unit/io/VTKTest.py', 'openpnm/algorithms/_drainage.py']