Пример #1
0
 def test_init(self):
     import io
     from contextlib import redirect_stdout
     f = io.StringIO()
     with redirect_stdout(f):
         comp = Compartment("init",
                            pkcc2=0,
                            z=-0.85,
                            cli=0.015292947537423218,
                            ki=0.023836660428807395,
                            nai=0.1135388427892471)
         self.assertEqual("Compartment {} not osmo-neutral\n".format(comp),
                          f.getvalue())
     with self.assertRaises(Exception):
         comp = Compartment("init", pkcc2=0, z=-0.01, nai=50e-3, ki=80e-3)
     # with redirect_stdout(f):
     #     comp = Compartment("init", pkcc2=0, z=-0.01, nai=50e-3, ki=80e-3)
     #     self.assertNotEqual("Compartment {} not osmo-neutral\n".format(comp), f.getvalue())
     with self.assertRaises(ZeroDivisionError):
         Compartment("init", pkcc2=0, z=-0)
     with self.assertRaises(ZeroDivisionError):
         Compartment("init", pkcc2=0, z=-1)
     try:
         Compartment("init", pkcc2=0, z=-1, cli=1e-3)
     except ZeroDivisionError:
         self.fail("unexpected ZeroDivisionError error")
Пример #2
0
    def setUp(self):
        try:
            self.sim = simulator.Simulator(False)
        except RuntimeError:
            self.sim = simulator.Simulator.get_instance()

        self.comp = Compartment("comp")
 def test_ohm_diffusion_compartments_complex(self, **kwargs):
     """
     Test diffusion between compartments with only Ohm's law taken into account.
     A normal Compartment (as opposed to SimpleCompartment) is used calculate V accurately
     """
     self.comp = Compartment("c1", z=-0.85,
                             cli=0.005175478364339566, ki=0.111358641523315191,
                             nai=0.025519187764070129)  # corrected values
     self.comp2 = self.comp.copy("c2")
     self.d = OhmDiffusion(self.comp, self.comp2, self.ions)
     self.run_diffusion(100, False, block_after=False, **kwargs)
    def test_run(self):
        """
        RESULTS:
        run from 0 until 10 with time step of 0.001
        time taken for update interval of 0.01: 279.67880415916443
        time taken for update interval of 0.1: 22.88223671913147
        time taken for update interval of 1: 3.0911498069763184
        time taken for update interval of 2: 1.8190715312957764
        time taken for update interval of 5: 1.2316815853118896
        time taken for update interval of 10: 0.944373607635498
        time taken for update interval of 20: 0.9291894435882568
        """

        self.sim.dispose()
        self.sim = Simulator(_gui=True)
        comp = Compartment("soma")

        v = self.sim.gui().add_graph()
        v.add_voltage(comp, line_style='k')  # black
        stop = 5
        l = [0.1, 1, 2, 5, 10, 20]
        l.reverse()
        for pui in l:
            t_before = time.time()
            self.sim.run(stop=stop,
                         plot_update_interval=pui,
                         data_collect_interval=0.1,
                         block_after=False)
            print("time taken for update interval of {}: {}".format(
                pui,
                time.time() - t_before))
        pass
Пример #5
0
    def __init__(self, id, seats_left, seats_right, rows, length_of_row,
                 row_entry_size, compartment_size, compartment_length):

        if id == 1:
            # Bombardier CS100
            seats_left = 2
            seats_right = 3
            rows = 25
            length_of_row = 0.787
            row_entry_size = (2 / 5) * 0.787
            compartment_size = 3
            compartment_length = 1.35
        elif id == 2:
            # Airbus A320-200
            seats_left = 3
            seats_right = 3
            rows = 30
            length_of_row = 0.787
            row_entry_size = (2 / 5) * 0.787
            compartment_size = 5
            compartment_length = 2.2
        elif id == 3:
            # Plane from paper
            seats_left = 3
            seats_right = 3
            rows = 23
            length_of_row = 0.813
            row_entry_size = (2 / 5) * 0.813
            compartment_size = 3
            compartment_length = 1.35

        #else create custom plane
        row_entry_size = Simulation.meter_to_space_unit(row_entry_size)
        length_of_row = Simulation.meter_to_space_unit(length_of_row)
        compartment_length = Simulation.meter_to_space_unit(compartment_length)
        self.seatsLeft = seats_left
        self.seatsRight = seats_right
        self.seat_occupance = np.full((rows, seats_left + seats_right),
                                      0,
                                      dtype=int)
        self.rows = rows
        self.length = rows * length_of_row
        self.aisle = Aisle(self, length_of_row, row_entry_size)
        self.compartments = []
        self.compartment_length = compartment_length
        self.actors = None
        self.length_of_row = length_of_row
        self.compartment_size = compartment_size

        # initialize compartments
        self.nr_compartments = math.ceil(self.length / compartment_length)
        for i in range(0, self.nr_compartments):
            self.compartments.append(
                Compartment(compartment_size * 2, i * compartment_length,
                            min(self.length - 1,
                                (i + 1) * compartment_length)))
 def setUp(self):
     self.sim = simulator.Simulator.get_instance()
     self.comp = SimpleCompartment("c1", pkcc2=0, z=-0.85,
                                   cli=0.005175478364339566, ki=0.111358641523315191, nai=0.025519187764070129)
     self.comp2 = self.comp.copy("c2")
     # get a reasonable negative voltage (V=--0.06892)
     self.comp.cli += 2e-7
     self.comp2.cli += 2e-7
     self.ion = "cli"
     D = 1  # == 10-5 * cm2/s
     self.D = D * 1e-7  # um2 to dm2 (D in dm2/s)
     self.ions = {"cli": self.D}
     self.gui = False
Пример #7
0
    def __init__(self, Name, Parent=None, Description=""):
        daeModel.__init__(self, Name, Parent, Description)

        self.F = Compartment("Feed", self)
        self.M = Membrane("Membrane", self)
        self.S = Support("Support", self)
        self.P = Compartment("Permeate", self)

        self.Nc = daeDomain("Nc", self, unit(), "Number of components")
        self.z = daeDomain("z", self, unit(), "Axial domain")

        self.Tref = daeParameter("T_ref", K, self, "")
        self.Pref = daeParameter("P_ref", Pa, self, "")
        self.Tfeed = daeParameter("T_feed", K, self, "Feed temperature")

        self.Purity_feed = daeVariable("Purity_feed", fraction_t, self, "",
                                       [self.Nc])
        self.Purity_permeate = daeVariable("Purity_permeate", fraction_t, self,
                                           "", [self.Nc])
        self.Recovery_feed = daeVariable("Recovery_feed", recovery_t, self, "",
                                         [self.Nc])
        self.Selectivity = daeVariable("Selectivity", selectivity_t, self, "",
                                       [self.Nc, self.Nc, self.z])

        self.Phigh = daeVariable("P_high", pressure_t, self, "", [])
        self.Plow = daeVariable("P_low", pressure_t, self, "", [])

        self.MembraneArea = daeVariable("MembraneArea", area_t, self, "", [])
        self.MembraneThickness = daeVariable("MembraneThickness", length_t,
                                             self, "", [])
        self.SupportThickness = daeVariable("SupportThickness", length_t, self,
                                            "", [])

        self.Qfeed_stp = daeVariable("Qfeed_stp", volume_flowrate_t, self, "",
                                     [])
        self.Qsweep_stp = daeVariable("Qsweep_stp", volume_flowrate_t, self,
                                      "", [])
    def test_one_is_two(self):
        """
        Changing to the same values of all (2) compartments is the same as changing as if it were compartment
        """
        self.compBase = Compartment("c1", length=10e-5, pkcc2=0, z=-0.85,
                                    cli=0.015292947537423218,
                                    ki=0.023836660428807395,
                                    nai=0.1135388427892471)

        self.comp = Compartment("c1", length=5e-5, pkcc2=0, z=-0.85,
                                cli=0.015292947537423218,
                                ki=0.023836660428807395,
                                nai=0.1135388427892471)
        self.comp2 = self.comp.copy("c2")
        # set diffusion value
        cli_D = 2.03
        cli_D *= 1e-7  # um2 to dm2 (D in dm2/s)
        ki_D = 1.96
        ki_D *= 1e-7  # um2 to dm2 (D in dm2/s)
        nai_D = 1.33
        nai_D *= 1e-7
        # create diffusion connection
        diffusion_object = Diffusion(self.comp, self.comp2, ions={'cli': cli_D, 'ki': ki_D, 'nai': nai_D})

        self.assertEqual(self.compBase.cli, self.comp.cli)

        self.sim.run(stop=100, dt=0.001, block_after=False)

        self.assertEqual(self.compBase.cli, self.comp.cli)
        self.assertEqual(self.comp.cli, self.comp2.cli)

        self.compBase.gx = self.comp.gx = self.comp2.gx = 1e-8

        self.sim.run(continuefor=1, dt=1e-6, block_after=False)

        self.assertEqual(self.compBase.cli, self.comp.cli)
        self.assertEqual(self.comp.cli, self.comp2.cli)
 def test_register_compartment(self):
     comp = Compartment("comp")
     # Compartment auto-added to __object_list
     self.assertListEqual(self.sim.object_list(), [comp])
     # Dispose and create a new Simulator
     self.sim.dispose()
     self.sim = Simulator()
     self.sim.register_compartment(comp)
     self.assertListEqual(self.sim.object_list(), [comp])
     with self.assertRaises(TypeError):
         self.sim.register_compartment("Compartment")
     with self.assertRaises(TypeError):
         self.sim.register_compartment(True)
     with self.assertRaises(TypeError):
         self.sim.register_compartment(1)
     with self.assertRaises(TypeError):
         self.sim.register_compartment(0.1)
def checkpara(kcc2=1e-8, z=-0.85):
    ti = [[], [], [], [], []]
    T = [-8.0, -7.0, -6.0, -5.5, -5.0, -4.5, -4, -3.5, -3.0, -2.0]
    sim = Simulator()

    for k in T:
        q = 10 ** (k) / F
        comp = Compartment("soma with pump rate 1e" + str(k) + "/F", pkcc2=kcc2, z=z, p=q)
        time.clock()
        sim.run(continuefor=1000, plot_update_interval=5000,block_after=False)
        ti[0].append(comp.V)
        ti[1].append(comp.ki)
        ti[2].append(comp.nai)
        ti[3].append(comp.cli)
        ti[4].append(comp.xi)

    para = zplm(z, kcc2, oso)

    return T, ti, para
Пример #11
0
class TestCompartment(TestCase):
    def setUp(self):
        try:
            self.sim = simulator.Simulator(False)
        except RuntimeError:
            self.sim = simulator.Simulator.get_instance()

        self.comp = Compartment("comp")

    def test_init(self):
        import io
        from contextlib import redirect_stdout
        f = io.StringIO()
        with redirect_stdout(f):
            comp = Compartment("init",
                               pkcc2=0,
                               z=-0.85,
                               cli=0.015292947537423218,
                               ki=0.023836660428807395,
                               nai=0.1135388427892471)
            self.assertEqual("Compartment {} not osmo-neutral\n".format(comp),
                             f.getvalue())
        with self.assertRaises(Exception):
            comp = Compartment("init", pkcc2=0, z=-0.01, nai=50e-3, ki=80e-3)
        # with redirect_stdout(f):
        #     comp = Compartment("init", pkcc2=0, z=-0.01, nai=50e-3, ki=80e-3)
        #     self.assertNotEqual("Compartment {} not osmo-neutral\n".format(comp), f.getvalue())
        with self.assertRaises(ZeroDivisionError):
            Compartment("init", pkcc2=0, z=-0)
        with self.assertRaises(ZeroDivisionError):
            Compartment("init", pkcc2=0, z=-1)
        try:
            Compartment("init", pkcc2=0, z=-1, cli=1e-3)
        except ZeroDivisionError:
            self.fail("unexpected ZeroDivisionError error")

    def test_step(self):
        with self.assertRaises(ValueError):
            self.comp.step(None)
        prev_V = self.comp.V
        self.comp.step(self.sim.time())
        self.assertNotEqual(prev_V, self.comp.V)
        # check update list populated by step
        self.assertIsNot(self.sim._Simulator__update_list, [])

    def test_update_values(self):
        # compartment not at equilibrium in setUp, so changes occur 'naturally'
        prev_cli = self.comp.cli
        self.comp.update_values()
        self.assertNotEqual(prev_cli, self.comp.cli)

    def test_copy(self):

        copy = self.comp.copy(self.comp.name)
        # change only thing that should be different
        copy.unique_id = self.comp.unique_id
        self.assertEqual(self.comp.__dict__, copy.__dict__)

    def test_deepcopy(self):
        from copy import deepcopy
        import time
        # have the system sleep so copy is not created too close to original comp
        time.sleep(0.1)
        copy = self.comp.deepcopy(self.comp.name)
        self.assertNotEqual(self.comp.unique_id, copy.unique_id)
        # change only thing that should be different
        copy.unique_id = self.comp.unique_id
        self.assertEqual(self.comp.__dict__, copy.__dict__)
        self.assertEqual(deepcopy(self.comp).__dict__, self.comp.__dict__)

    def test_stable_state(self, ion='cli', gui=True):
        sim = self.sim
        comp = self.comp
        comp2 = self.comp.copy(self.comp.name)

        print("before run:\nion: \t{}:{} \t {}:{}".format(
            comp.name, round(comp[ion], 5), comp2.name, round(comp2[ion], 5)))
        print("\n  V: \t{}:{} \t {}:{}".format(comp.name, round(comp.V, 5),
                                               comp2.name, round(comp2.V, 5)))
        self.assertEqual(round(comp[ion], 5), round(comp2[ion], 5))
        sim.run(stop=200, plot_update_interval=50, dt=0.001)
        # value of V fixed
        print("after run:\nion: \t{}:{} \t {}:{}".format(
            comp.name, round(comp[ion], 5), comp2.name, round(comp2[ion], 5)))
        print("\n  V: \t{}:{} \t {}:{}".format(comp.name, round(comp.V, 5),
                                               comp2.name, round(comp2.V, 5)))
        self.assertEqual(round(comp[ion], 5), round(comp2[ion], 5))

        increase_amount = 1e-2
        comp.cli += increase_amount
        # comp.ki += increase_amount
        # slow_increase(1., increase_amount, comp, ["cli"],dt=0.001)
        if gui:
            g = sim.gui().add_graph()
            g.add_ion_conc(comp, ion, line_style='g')  # green
            v = sim.gui().add_graph()
            v.add_voltage(comp, line_style='k')
        print("value changed\nbefore run:\n\t{}:{} \t {}:{}".format(
            comp.name, round(comp[ion], 5), comp2.name, round(comp2[ion], 5)))
        # self.assertNotEqual(round(comp[ion], 5), round(comp2[ion], 5))

        # g.ax.set_ylim([comp.cli,comp.cli+increase_amount])
        # v.ax.set_ylim([comp.V-0.02,comp.V+0.02])

        sim.run(continuefor=10, dt=0.001, block_after=False)

        sim.run(continuefor=0.001, dt=0.001, block_after=gui, print_time=False)
        print("after run:\n\t{}:{} \t {}:{}".format(comp.name,
                                                    round(comp[ion], 5),
                                                    comp2.name,
                                                    round(comp2[ion], 5)))
        self.assertEqual(round(comp[ion], 5), round(comp2[ion], 5))
Пример #12
0
 def _reconstruct(self):
     """
     Internal function. 
     Restructures data and establishes appropriate internal linking. 
     Data is re-order, removing 'holes' in the ID sequence so that 
     each object ID corresponds to its position in node list. 
     Dictionaries mapping IDs to objects are no longer necessary.
     Trees are (re)calculated
     Parent-child indices are recalculated 
     A new compartment list is created
     """
     remap = {}
     # everything defaults to root. this way if a parent was deleted
     #   the child will become a new root
     for i in range(len(self.node_list)):
         remap[i] = -1
     # map old old node numbers to new ones. reset n to the new ID
     #   and put node in new list
     new_id = 0
     tmp_list = []
     for node in self.node_list:
         if node is not None:
             remap[node.n] = new_id
             node.n = new_id
             tmp_list.append(node)
             new_id += 1
     # use map to reset parent values. copy objs to new list
     for node in tmp_list:
         if node.parent >= 0:
             node.parent = remap[node.parent]
     # replace node list with newly created node list
     self._node_list = tmp_list
     # reconstruct parent/child relationship links
     ############################
     # node list is complete and sequential so don't need index
     #   to resolve relationships
     # for each node, reset children array
     # for each node, add self to parent's child list
     for node in self._node_list:
         node.children = []
         node.compartment = -1
     for node in self._node_list:
         if node.parent >= 0:
             self._node_list[node.parent].children.append(node.n)
     # update tree lists
     self._separate_trees()
     # verify that each node ID is the same as its position in the
     #   node list
     for i in range(len(self.node_list)):
         if i != self.node(i).n:
             raise RuntimeError(
                 "Internal error detected -- node list not properly formed")
     # construct compartment list
     #   (a compartment spans the distance between two nodes)
     self._compartment_list = []
     for node in self.node_list:
         node.compartment_id = -1
     for node in self.node_list:
         for child_id in node.children:
             endpoint = self.node(child_id)
             compartment = Compartment(node, endpoint)
             endpoint.compartment_id = len(self._compartment_list)
             self._compartment_list.append(compartment)
Пример #13
0
class MembraneUnit(daeModel):
    def __init__(self, Name, Parent=None, Description=""):
        daeModel.__init__(self, Name, Parent, Description)

        self.F = Compartment("Feed", self)
        self.M = Membrane("Membrane", self)
        self.S = Support("Support", self)
        self.P = Compartment("Permeate", self)

        self.Nc = daeDomain("Nc", self, unit(), "Number of components")
        self.z = daeDomain("z", self, unit(), "Axial domain")

        self.Tref = daeParameter("T_ref", K, self, "")
        self.Pref = daeParameter("P_ref", Pa, self, "")
        self.Tfeed = daeParameter("T_feed", K, self, "Feed temperature")

        self.Purity_feed = daeVariable("Purity_feed", fraction_t, self, "",
                                       [self.Nc])
        self.Purity_permeate = daeVariable("Purity_permeate", fraction_t, self,
                                           "", [self.Nc])
        self.Recovery_feed = daeVariable("Recovery_feed", recovery_t, self, "",
                                         [self.Nc])
        self.Selectivity = daeVariable("Selectivity", selectivity_t, self, "",
                                       [self.Nc, self.Nc, self.z])

        self.Phigh = daeVariable("P_high", pressure_t, self, "", [])
        self.Plow = daeVariable("P_low", pressure_t, self, "", [])

        self.MembraneArea = daeVariable("MembraneArea", area_t, self, "", [])
        self.MembraneThickness = daeVariable("MembraneThickness", length_t,
                                             self, "", [])
        self.SupportThickness = daeVariable("SupportThickness", length_t, self,
                                            "", [])

        self.Qfeed_stp = daeVariable("Qfeed_stp", volume_flowrate_t, self, "",
                                     [])
        self.Qsweep_stp = daeVariable("Qsweep_stp", volume_flowrate_t, self,
                                      "", [])

    def DeclareEquations(self):
        daeModel.DeclareEquations(self)

        eq = self.CreateEquation("Recovery_feed")
        i = eq.DistributeOnDomain(self.Nc, eClosedClosed, 'i')
        eq.Residual = self.Recovery_feed(i) * (
            self.F.Cin(i) * self.F.Qin()) - self.F.Qout() * self.F.Cout(i)

        eq = self.CreateEquation("Purity_feed")
        i = eq.DistributeOnDomain(self.Nc, eClosedClosed, 'i')
        eq.Residual = self.Purity_feed(i) - self.F.Xout(i)

        eq = self.CreateEquation("Purity_permeate")
        i = eq.DistributeOnDomain(self.Nc, eClosedClosed, 'i')
        eq.Residual = self.Purity_permeate(i) - self.P.Xout(i)

        eq = self.CreateEquation("Selectivity")
        i = eq.DistributeOnDomain(self.Nc, eClosedClosed, 'i')
        j = eq.DistributeOnDomain(self.Nc, eClosedClosed, 'j')
        z = eq.DistributeOnDomain(self.z, eClosedClosed)
        eq.Residual = self.Selectivity(i, j, z) * (self.F.X(i, z) * self.P.X(
            j, z)) - (self.P.X(i, z) * self.F.X(j, z))

        # Fluxes at the Feed-Membrane, Membrane-Support,
        # Support-Retentate compartments are equal
        eq = self.CreateEquation("Feed_Flux")
        i = eq.DistributeOnDomain(self.F.Nc, eClosedClosed, 'i')
        z = eq.DistributeOnDomain(self.F.z, eClosedClosed)
        eq.Residual = self.F.Flux(i, z) - self.M.Flux(i, z)

        eq = self.CreateEquation("Support_Flux")
        i = eq.DistributeOnDomain(self.F.Nc, eClosedClosed, 'i')
        z = eq.DistributeOnDomain(self.F.z, eClosedClosed)
        eq.Residual = self.S.Flux(i, z) - self.M.Flux(i, z)

        eq = self.CreateEquation("Permeate_Flux")
        i = eq.DistributeOnDomain(self.F.Nc, eClosedClosed, 'i')
        z = eq.DistributeOnDomain(self.F.z, eClosedClosed)
        eq.Residual = self.P.Flux(i, z) + self.S.Flux(i, z)

        # Gas mole fraction at the Feed-Membrane, and Membrane-Support,
        # Support-Retentate compartments
        eq = self.CreateEquation("Membrane_Xinlet")
        i = eq.DistributeOnDomain(self.F.Nc, eClosedClosed, 'i')
        z = eq.DistributeOnDomain(self.F.z, eClosedClosed)
        eq.Residual = self.F.X(i, z) - self.M.Xinlet(i, z)

        eq = self.CreateEquation("Support_Xinlet")
        i = eq.DistributeOnDomain(self.F.Nc, eClosedClosed, 'i')
        z = eq.DistributeOnDomain(self.F.z, eClosedClosed)
        eq.Residual = self.S.Xinlet(i, z) - self.M.Xoutlet(i, z)

        eq = self.CreateEquation("Permeate_X")
        i = eq.DistributeOnDomain(self.F.Nc, eClosedClosed, 'i')
        z = eq.DistributeOnDomain(self.F.z, eClosedClosed)
        eq.Residual = self.P.X(i, z) - self.S.Xoutlet(i, z)

        # Pressures at the Feed-Membrane, and Membrane-Support,
        # Support-Retentate compartments are equal
        eq = self.CreateEquation("Membrane_Pinlet")
        z = eq.DistributeOnDomain(self.F.z, eClosedClosed)
        eq.Residual = self.F.P(z) - self.M.Pinlet(z)

        eq = self.CreateEquation("Support_Pinlet")
        z = eq.DistributeOnDomain(self.S.z, eClosedClosed)
        eq.Residual = self.S.Pinlet(z) - self.M.Poutlet(z)

        eq = self.CreateEquation("Support_Poutlet")
        z = eq.DistributeOnDomain(self.P.z, eClosedClosed)
        eq.Residual = self.P.P(z) - self.S.Poutlet(z)

        # Temperatures at the Feed-Membrane, and Membrane-Support,
        # Support-Retentate compartments are equal
        eq = self.CreateEquation("Feed_T")
        eq.Residual = self.F.T() - self.Tfeed()

        eq = self.CreateEquation("Membrane_T")
        eq.Residual = self.M.T() - self.Tfeed()

        eq = self.CreateEquation("Support_S")
        eq.Residual = self.S.T() - self.Tfeed()

        eq = self.CreateEquation("Permeate_T")
        eq.Residual = self.P.T() - self.Tfeed()
def grow(nr=3, textra=10):
    print("growing via anions")
    sim = Simulator().get_instance()
    gui = sim.gui()
    dt = 0.001  # s

    comp = []
    comp.append(
        Compartment("initial growth cone",
                    z=-0.85,
                    cli=0.00433925284075134,
                    ki=0.1109567493822927,
                    nai=0.0255226350779378,
                    length=5e-5,
                    radius=default_radius_short))

    # steady state
    sim.run(stop=100,
            dt=0.001,
            plot_update_interval=500,
            data_collect_interval=5,
            block_after=False)

    # set diffusion value
    cli_D = 2.03
    cli_D *= 1e-7  # cm2 to dm2 (D in dm2/s)
    ki_D = 1.96
    ki_D *= 1e-7  # cm2 to dm2 (D in dm2/s)
    nai_D = 1.33
    nai_D *= 1e-7

    #another compartment
    comp.append(comp[0].copy("compartment 1"))
    comp[1].L = 10e-5
    comp[1].w = np.pi * comp[1].r**2 * comp[1].L
    diffusion_object = [
        Diffusion(comp[0],
                  comp[1],
                  ions={
                      'cli': cli_D,
                      'ki': ki_D,
                      'nai': nai_D
                  })
    ]

    # heatmap incorporating compartment heights
    sc = 1e5
    htplot = Colormap("dendrite", comp[0].w + comp[1].w, comp)
    totalht, init_vals = htplot.smallheatmap(comp,
                                             sc,
                                             int(htplot.totalh * sc),
                                             all=0,
                                             init_val=None)

    # plot
    voltage_reversal_graph_comp = gui.add_graph() \
        .add_ion_conc(comp[0], "ecl", line_style='g', y_units_scale=1000, y_plot_units='mV') \
        .add_ion_conc(comp[0], "ek", line_style='b', y_units_scale=1000, y_plot_units='mV') \
        .add_voltage(comp[0], line_style='k', y_units_scale=1000, y_plot_units='mV')

    volume_graph = gui.add_graph()
    volume_graph.add_var(volume_graph.time,
                         "time",
                         htplot,
                         "comp0w",
                         line_style='k')
    volume_graph.add_var(volume_graph.time,
                         "time",
                         htplot,
                         "totalh",
                         line_style='b')

    sim.run(continuefor=1,
            dt=dt * 0.001,
            plot_update_interval=0.5,
            data_collect_interval=textra / 16)

    # growth
    for i in range(nr):
        htplot.smallheatmap(comp,
                            sc,
                            totalht,
                            all=0,
                            init_val=init_vals,
                            name='graphs/grow_done' + str(i) + '.eps')
        comp[0].gx = 1

        # stop at certain length
        while comp[0].L < 15e-5:
            print("Fluxing compartment's length: " + str(comp[0].L))
            sim.run(continuefor=0.5,
                    dt=dt * 0.001,
                    plot_update_interval=0.25,
                    data_collect_interval=textra / 16)
            if 9.9e-5 < comp[0].L < 10.3e-5:
                htplot.smallheatmap(comp,
                                    sc,
                                    totalht,
                                    all=0,
                                    init_val=init_vals,
                                    name='graphs/grow_interim' + str(i) +
                                    '.eps')
        comp[0].gx = 0
        print_concentrations(comp, str(i))

        # split compartments
        comp.insert(0, comp[0].copy("compartment " + str(i)))
        comp[1].L -= 5e-5
        comp[0].L = 5e-5
        comp[0].w = np.pi * comp[0].r**2 * comp[0].L
        comp[1].w = np.pi * comp[1].r**2 * comp[1].L

        print_concentrations(comp, str(i))

        # update total height
        htplot.comp = comp

        # update diffusion
        diffusion_object.append(
            Diffusion(comp[0],
                      comp[1],
                      ions={
                          'cli': cli_D,
                          'ki': ki_D,
                          'nai': nai_D
                      }))

        for a in comp:
            print(a.name)

        for j in diffusion_object:
            print(j.name)

        sim.run(continuefor=10,
                dt=dt * 0.001,
                plot_update_interval=5,
                data_collect_interval=textra / 16)

    htplot.smallheatmap(comp,
                        sc,
                        totalht,
                        all=1,
                        init_val=init_vals,
                        name='graphs/grow_end.eps')
    sim.run(continuefor=4,
            dt=dt * 0.001,
            plot_update_interval=2,
            data_collect_interval=0.5)
    htplot.smallheatmap(comp,
                        sc,
                        totalht,
                        all=1,
                        init_val=init_vals,
                        name='graphs/grow_end.eps')

    return sim, gui
class TestDiffusion(TestCase):
    def setUp(self):
        self.sim = simulator.Simulator.get_instance()
        self.comp = SimpleCompartment("c1", pkcc2=0, z=-0.85,
                                      cli=0.005175478364339566, ki=0.111358641523315191, nai=0.025519187764070129)
        self.comp2 = self.comp.copy("c2")
        # get a reasonable negative voltage (V=--0.06892)
        self.comp.cli += 2e-7
        self.comp2.cli += 2e-7
        self.ion = "cli"
        D = 1  # == 10-5 * cm2/s
        self.D = D * 1e-7  # um2 to dm2 (D in dm2/s)
        self.ions = {"cli": self.D}
        self.gui = False

    def run_diffusion(self, time_stop=10, gui=False, block_after=False):
        """
        Helper method for unit tests
        """
        sim = self.sim
        comp = self.comp
        comp2 = self.comp2
        ion = self.ion
        print("before run:\nion: \t{}:{} \t {}:{}".format(comp.name, round(comp[ion], 5), comp2.name,
                                                          round(comp2[ion], 5)))
        print("\n  V: \t{}:{} \t {}:{}".format(comp.name, round(comp.V, 5), comp2.name, round(comp2.V, 5)))
        self.assertEqual(round(comp[ion], 5), round(comp2[ion], 5))
        sim.run(stop=10, dt=0.001)
        # value of V fixed
        print("after run:\nion: \t{}:{} \t {}:{}".format(comp.name, round(comp[ion], 5), comp2.name,
                                                         round(comp2[ion], 5)))
        print("\n  V: \t{}:{} \t {}:{}".format(comp.name, round(comp.V, 5), comp2.name, round(comp2.V, 5)))
        self.assertEqual(round(comp[ion], 5), round(comp2[ion], 5))


        increase_amount = 1e-2
        # comp.cli += increase_amount
        # comp.ki += increase_amount
        slow_increase(1., increase_amount, comp, ["cli"],dt=0.0001)

        if gui or self.gui:
            g = sim.gui().add_graph()
            g.add_ion_conc(comp2, self.ion, line_style='--g')  # green
            g.add_ion_conc(comp, self.ion, line_style='g')  # green
            v = sim.gui().add_graph()
            v.add_voltage(comp2, line_style='--k')  # black
            v.add_voltage(comp, line_style='k')
            # g.ax.set_ylim([comp.cli,comp.cli+increase_amount])
            # v.ax.set_ylim([comp.V-0.02,comp.V+0.02])

        print("value changed\nbefore run:\n\t{}:{} \t {}:{}".format(comp.name, round(comp[ion], 5), comp2.name,
                                                                    round(comp2[ion], 5)))
        # self.assertNotEqual(round(comp[ion], 5), round(comp2[ion], 5))


        sim.run(continuefor=time_stop, dt=0.001, block_after=False)

        sim.run(continuefor=0.001, dt=0.001, block_after=block_after, print_time=False)
        print("after run:\n\t{}:{} \t {}:{}".format(comp.name, round(comp[ion], 5), comp2.name, round(comp2[ion], 5)))
        self.assertEqual(round(comp[ion], 5), round(comp2[ion], 5))

    def test_diffusion_compartments(self, **kwargs):
        self.d = Diffusion(self.comp, self.comp2, self.ions)
        self.run_diffusion(300, False, **kwargs)

    def test_fick_diffusion_compartments(self, **kwargs):
        self.d = FickDiffusion(self.comp, self.comp2, self.ions)
        self.run_diffusion(200, False, **kwargs)

    def test_ohm_diffusion_compartments(self, **kwargs):
        """
        Test diffusion between compartments with only Ohm's law taken into account.
        """
        self.d = OhmDiffusion(self.comp, self.comp2, self.ions)
        self.run_diffusion(10, False, block_after=False, **kwargs)

    def test_ohm_diffusion_compartments_complex(self, **kwargs):
        """
        Test diffusion between compartments with only Ohm's law taken into account.
        A normal Compartment (as opposed to SimpleCompartment) is used calculate V accurately
        """
        self.comp = Compartment("c1", z=-0.85,
                                cli=0.005175478364339566, ki=0.111358641523315191,
                                nai=0.025519187764070129)  # corrected values
        self.comp2 = self.comp.copy("c2")
        self.d = OhmDiffusion(self.comp, self.comp2, self.ions)
        self.run_diffusion(100, False, block_after=False, **kwargs)

    def test_multi(self):
        self.setUp()
        self.test_diffusion_compartments()
        self.setUp()
        self.test_fick_diffusion_compartments()
        self.setUp()
        self.test_ohm_diffusion_compartments()

    def test_one_is_two(self):
        """
        Changing to the same values of all (2) compartments is the same as changing as if it were compartment
        """
        self.compBase = Compartment("c1", length=10e-5, pkcc2=0, z=-0.85,
                                    cli=0.015292947537423218,
                                    ki=0.023836660428807395,
                                    nai=0.1135388427892471)

        self.comp = Compartment("c1", length=5e-5, pkcc2=0, z=-0.85,
                                cli=0.015292947537423218,
                                ki=0.023836660428807395,
                                nai=0.1135388427892471)
        self.comp2 = self.comp.copy("c2")
        # set diffusion value
        cli_D = 2.03
        cli_D *= 1e-7  # um2 to dm2 (D in dm2/s)
        ki_D = 1.96
        ki_D *= 1e-7  # um2 to dm2 (D in dm2/s)
        nai_D = 1.33
        nai_D *= 1e-7
        # create diffusion connection
        diffusion_object = Diffusion(self.comp, self.comp2, ions={'cli': cli_D, 'ki': ki_D, 'nai': nai_D})

        self.assertEqual(self.compBase.cli, self.comp.cli)

        self.sim.run(stop=100, dt=0.001, block_after=False)

        self.assertEqual(self.compBase.cli, self.comp.cli)
        self.assertEqual(self.comp.cli, self.comp2.cli)

        self.compBase.gx = self.comp.gx = self.comp2.gx = 1e-8

        self.sim.run(continuefor=1, dt=1e-6, block_after=False)

        self.assertEqual(self.compBase.cli, self.comp.cli)
        self.assertEqual(self.comp.cli, self.comp2.cli)

    def test_middle(self):
        """
        Changing middle compartment, affects outer compartments by the same amount
        """
        # TODO: why does 'Compartment' fail the test (presumable an anion issue causing different steady-state cli)
        self.compBase = SimpleCompartment("c1", pkcc2=1e-8, z=-0.85)
        self.comp = self.compBase.copy("left")
        self.comp2 = self.comp.copy("right")

        # set diffusion value
        cli_D = 2.03
        cli_D *= 1e-7  # um2 to dm2 (D in dm2/ss)
        ki_D = 1.96
        ki_D *= 1e-7  # um2 to dm2 (D in dm2/s)
        nai_D = 1.33
        nai_D *= 1e-7
        # create diffusion connection
        diffusion_object = Diffusion(self.comp, self.comp2, ions={'cli': cli_D, 'ki': ki_D, 'nai': nai_D})
        diffusion_object = Diffusion(self.comp2, self.compBase, ions={'cli': cli_D, 'ki': ki_D, 'nai': nai_D})

        self.sim.run(stop=100, dt=0.001, block_after=False)

        self.compBase.gx = 1e-8
        self.sim.run(continuefor=1, dt=1e-6, block_after=False)
        self.assertEqual(self.comp.cli, self.comp2.cli)

        self.compBase.gx = 0e-8
        self.sim.run(continuefor=1, dt=1e-6, block_after=False)
        self.assertEqual(self.comp.cli, self.comp2.cli)

    def test_mols(self):
        self.compBase = SimpleCompartment("c1", pkcc2=1e-8, z=-0.85,
                                          cli=0.015292947537423218,
                                          ki=0.023836660428807395,
                                          nai=0.1135388427892471)

        self.comp = self.compBase.copy("left")
        self.comp2 = self.comp.copy("right")
        self.compSingle = SimpleCompartment("cs", pkcc2=1e-8, z=-0.85,
                                            cli=0.015292947537423218,
                                            ki=0.023836660428807395,
                                            nai=0.1135388427892471,
                                            length=3 * default_length)
        # set diffusion value
        cli_D = 2.03
        cli_D *= 1e-7  # um2 to dm2 (D in dm2/s)
        ki_D = 1.96
        ki_D *= 1e-7  # um2 to dm2 (D in dm2/s)
        nai_D = 1.33
        nai_D *= 1e-7
        # create diffusion connection
        diffusion_object = Diffusion(self.comp, self.compBase, ions={'cli': cli_D, 'ki': ki_D, 'nai': nai_D})
        diffusion_object = Diffusion(self.comp2, self.compBase, ions={'cli': cli_D, 'ki': ki_D, 'nai': nai_D})

        self.sim.run(stop=100, dt=0.001, block_after=False)

        self.compBase.gx = 1e-8
        self.compSingle.gx = 1e-8
        self.sim.run(continuefor=1, dt=1e-6, block_after=False)

        xmol_3 = self.compBase.mols(self.compBase.xi) + self.comp.mols(self.comp.xi) + self.comp2.mols(self.comp2.xi)
        xmol_single = self.compSingle.mols(self.compSingle.xi)
        self.assertAlmostEqual(xmol_3, xmol_single)

        cmol_3 = self.compBase.mols(self.compBase.cli) + self.comp.mols(self.comp.cli) + self.comp2.mols(self.comp2.cli)
        cmol_single = self.compSingle.mols(self.compSingle.cli)
        self.assertAlmostEqual(cmol_3, cmol_single)
Пример #16
0
 def _reconstruct(self):
     """
     Internal function. 
     Restructures data and establishes appropriate internal linking. 
     Data is re-numbered, removing 'holes' in the ID sequence so that 
     each object ID corresponds to its position in node list. 
     Data is also reordered, if necessary, so that parents always have 
     a lower node ID than children.
     Dictionaries mapping IDs to objects are no longer necessary.
     Trees are (re)calculated
     Parent-child indices are recalculated 
     A new compartment list is created
     """
     ################################################################
     # remove holes from data and make sure IDs are sequential
     #
     ################################
     # initialize state
     remap = {}
     # everything defaults to root. this way if a parent was deleted
     #   the child will become a new root
     for i in range(len(self.node_list)):
         remap[i] = -1
     ################################
     # map old node numbers to new ones. reset n to the new ID
     #   and put node in new list
     new_id = 0
     tmp_list = []
     for node in self.node_list:
         if node is not None:
             remap[node.n] = new_id
             node.n = new_id
             tmp_list.append(node)
             new_id += 1
     # use map to reset parent values. copy objs to new list
     for node in tmp_list:
         if node.parent >= 0:
             node.parent = remap[node.parent]
     # replace node list with newly created node list
     self._node_list = tmp_list
     ################################
     # reconstruct parent/child relationship links
     #
     # node list is complete and sequential so don't need index
     #   to resolve relationships
     # for each node, reset children array
     # for each node, add self to parent's child list
     for node in self._node_list:
         node.children = []
         node.compartment = -1
     for node in self._node_list:
         if node.parent >= 0:
             par = self._node_list[node.parent]
             if par.n != node.parent:
                 raise Exception()
             par.children.append(node.n)
     ################################################################
     # restructure graph so that parents have lower IDs than children
     # this is necessary for segment algorithm. the entire morphology
     #   class was built with the assumption that parents are lower
     #   than children in IDs, so this may be a hidden dependency
     #   elsewhere too
     #
     # only perform re-organization if it's necessary though
     need_to_reorder = False
     for node in self.node_list:
         if node.parent >= node.n:
             need_to_reorder = True
             break
     if need_to_reorder:
         # restructure trees, starting at roots
         # for each root, add to new node list, then recursively add nodes
         #   children
         # creates a temporary element in node object ('new_idx') to 
         #   store new position
         parent_first_list = []
         for node in self.node_list:
             # roots are now at start of node list
             if node.parent < 0:
                 # recursively add children to list
                 self.add_node_and_children_(node, parent_first_list)
         # rebuild parent-child relations using temporary storage
         #   in nodes
         for node in self.node_list:
             for i in range(len(node.children)):
                 old_idx = node.children[i]
                 node.children[i] = self.node(old_idx).new_idx
             old_idx = node.parent
             if old_idx >= 0:
                 node.parent = self.node(old_idx).new_idx
             node.n = node.new_idx
         for node in self.node_list:
             del node.new_idx
         self._node_list = parent_first_list
     ################################################################
     # sanity check
     # verify that each node ID is the same as its position in the
     #   node list
     for i in range(len(self.node_list)):
         if i != self.node(i).n:
             raise RuntimeError("Internal error detected -- node list not properly formed")
     ################################################################
     # reinitialize other data structures
     #
     ################################
     # update tree lists
     self._separate_trees()
     ################################
     # construct compartment list
     #   (a compartment spans the distance between two nodes)
     self._compartment_list = []
     for node in self.node_list:
         node.compartment_id = -1
     for node in self.node_list:
         for child_id in node.children:
             endpoint = self.node(child_id)
             compartment = Compartment(node, endpoint)
             endpoint.compartment_id = len(self._compartment_list)
             self._compartment_list.append(compartment)
     ################################
     # build segment lists
     self._create_segments()
def main(cli_D=2.03,
         new_gx=0e-8,
         anion_flux=False,
         default_xz=-0.85,
         jkccup=1e-12,
         nrcomps=2,
         dz=1e-7,
         textra=100,
         say='',
         stretch=False):
    """
    cli_D # um2/s
    :return: sim, gui: it is useful to return these objects for access after simulation
    """
    print("main")
    sim = Simulator().get_instance()
    gui = sim.gui()
    dt = 0.001  # s

    length = 10e-5

    comp = Compartment("reference",
                       z=-0.85,
                       cli=0.0052,
                       ki=0.0123,
                       nai=0.014,
                       length=length,
                       radius=default_radius_short,
                       stretch_w=stretch)

    # copies left
    compl = comp.copy("dendrite left")

    # copies right
    compr = []
    compr.append(comp.copy("dendrite right " + str(1)))
    for i in range(nrcomps):
        compr.append(comp.copy("dendrite right " + str(i + 2)))

    # find steady-state values of ions
    sim.run(stop=100,
            dt=0.001,
            plot_update_interval=50,
            data_collect_interval=5,
            block_after=False)

    # set diffusion value
    cli_D *= 1e-7  # cm2 to dm2 (D in dm2/s)
    ki_D = 1.96
    ki_D *= 1e-7  # cm2 to dm2 (D in dm2/s)
    nai_D = 1.33
    nai_D *= 1e-7
    diffusion_object = []

    # connect with Diffusion
    diffusion_object.append(
        Diffusion(compl, comp, ions={
            'cli': cli_D,
            'ki': ki_D,
            'nai': nai_D
        }))
    diffusion_object.append(
        Diffusion(comp,
                  compr[0],
                  ions={
                      'cli': cli_D,
                      'ki': ki_D,
                      'nai': nai_D
                  }))
    for i in range(nrcomps):
        diffusion_object.append(
            Diffusion(compr[i],
                      compr[i + 1],
                      ions={
                          'cli': cli_D,
                          'ki': ki_D,
                          'nai': nai_D
                      }))

    # heatmap incorporating compartment heights
    sc = 1e7
    htplot = Colormap("cmap", 0, compr)
    totalht, initvals = htplot.heatmap(compl,
                                       comp,
                                       compr,
                                       sc,
                                       0,
                                       all=1,
                                       init_vals=None)
    htplot.heatmap(compl, comp, compr, sc, totalht, all=1, init_vals=initvals)

    voltage_reversal_graph_comp = gui.add_graph() \
        .add_ion_conc(comp, "ecl", line_style='g', y_units_scale=1000, y_plot_units='mV') \
        .add_ion_conc(comp, "ek", line_style='b', y_units_scale=1000, y_plot_units='mV') \
        .add_voltage(comp, line_style='k', y_units_scale=1000, y_plot_units='mV')

    voltage_reversal_graph_compr = gui.add_graph() \
        .add_ion_conc(compr[-1], "ecl", line_style='g', y_units_scale=1000, y_plot_units='mV') \
        .add_ion_conc(compr[-1], "ek", line_style='b', y_units_scale=1000, y_plot_units='mV') \
        .add_voltage(compr[-1], line_style='k', y_units_scale=1000, y_plot_units='mV')

    voltage_reversal_graph_compl = gui.add_graph() \
        .add_ion_conc(compl, "ecl", line_style='g', y_units_scale=1000, y_plot_units='mV') \
        .add_ion_conc(compl, "ek", line_style='b', y_units_scale=1000, y_plot_units='mV') \
        .add_voltage(compl, line_style='k', y_units_scale=1000, y_plot_units='mV')

    voltage_reversal_graph_compr1 = gui.add_graph() \
        .add_ion_conc(compr[0], "ecl", line_style='g', y_units_scale=1000, y_plot_units='mV') \
        .add_ion_conc(compr[0], "ek", line_style='b', y_units_scale=1000, y_plot_units='mV') \
        .add_voltage(compr[0], line_style='k', y_units_scale=1000, y_plot_units='mV')

    # run simulation with diffusion
    sim.run(continuefor=10,
            dt=dt,
            plot_update_interval=5,
            data_collect_interval=1)
    print(datetime.datetime.now())
    print_concentrations(
        [comp, compl, compr[-1]],
        title="Ion concentrations given diffusion between compartments")

    htplot.heatmap(compl, comp, compr, sc, totalht, all=1, init_vals=initvals)

    # (optionally) change anion conductance
    prev_comp_gx = comp.gx
    comp.gx = new_gx
    comp.dz = dz

    voltage_reversal_graph_comp.save(say + 'reference.eps')

    if dz != 0:
        z_graph = gui.add_graph() \
            .add_ion_conc(comp, "z", line_style='m')

    if comp.gx > 0:
        x_graph = gui.add_graph() \
            .add_ion_conc(comp, "absox", line_style='m') \
            .add_ion_conc(compl, "absox", line_style=':m') \
            .add_ion_conc(compr[0], "absox", line_style='m--')

    # (optionally) change anion flux
    if anion_flux:
        comp.xz = default_xz
        comp.xmz = (comp.z * comp.xi - comp.xz * comp.xi_temp) / comp.xm
        print('Anion flux with fixed anions having net charge', comp.xmz,
              'while a proportion of', (1 - comp.ratio),
              'of all impermeants are temporarily mobile anions of charge',
              comp.xz)

    z_graph = gui.add_graph() \
        .add_ion_conc(comp, "z", line_style='m')

    # (optionally) change kcc2
    prev_comp_pkcc2 = comp.pkcc2
    if jkccup is not None:
        comp.jkccup = jkccup
        g_graph = gui.add_graph() \
            .add_ion_conc(comp, "pkcc2", line_style='k')

    vol_graph = gui.add_graph() \
        .add_ion_conc(comp, "w", line_style='b') \
        .add_ion_conc(compl, "w", line_style=':b') \
        .add_ion_conc(compr[0], "w", line_style='b--')

    sim.run(continuefor=textra,
            dt=dt * 0.001,
            plot_update_interval=textra / 32,
            data_collect_interval=textra / 32)
    print(datetime.datetime.now())
    print_concentrations(
        [comp, compl, compr[-1]],
        title="Ion concentrations during event from the dendritic compartment")
    # heatmap incorporating compartment heights
    htplot.heatmap(compl,
                   comp,
                   compr,
                   sc,
                   totalht,
                   all=1,
                   init_vals=initvals,
                   title=[
                       say + 'all_halfway_df.eps', say + 'all_halfway_ecl.eps',
                       say + 'all_halfway_vm.eps'
                   ])

    voltage_reversal_graph_comp.save(say + 'reference.eps')

    sim.run(continuefor=textra,
            dt=dt * 0.001,
            plot_update_interval=textra / 2,
            data_collect_interval=textra / 16)
    print(datetime.datetime.now())
    print_concentrations(
        [comp, compl, compr[-1]],
        title=
        "Ion concentrations immediately after event from the dendritic compartment"
    )
    # heatmap incorporating compartment heights
    htplot.heatmap(compl, comp, compr, sc, totalht, all=1, init_vals=initvals)

    comp.gx = prev_comp_gx
    comp.jkccup = 0
    comp.dz = 0

    voltage_reversal_graph_comp.save(say + 'reference.eps')

    sim.run(continuefor=textra * 1,
            dt=dt * 0.001,
            plot_update_interval=textra / 2,
            data_collect_interval=textra / 4)
    print(datetime.datetime.now())
    print_concentrations([comp, compl, compr[-1]],
                         title="Ion concentrations at almost steady state")

    htplot.heatmap(compl,
                   comp,
                   compr,
                   sc,
                   totalht,
                   all=1,
                   init_vals=initvals,
                   title=[
                       say + 'all_end_df.eps', say + 'all_end_ecl.eps',
                       say + 'all_end_vm.eps'
                   ])
    voltage_reversal_graph_comp.save(say + 'reference.eps')

    sim.run(continuefor=textra * 1,
            dt=dt * 0.001,
            plot_update_interval=textra / 2,
            data_collect_interval=textra / 4)
    print(datetime.datetime.now())
    print_concentrations([comp, compl, compr[-1]],
                         title="Ion concentrations at steady state")

    # heatmap incorporating compartment heights
    htplot.heatmap(compl,
                   comp,
                   compr,
                   sc,
                   totalht,
                   all=1,
                   init_vals=initvals,
                   title=[
                       say + 'all_end_df.eps', say + 'all_end_ecl.eps',
                       say + 'all_end_vm.eps'
                   ])
    voltage_reversal_graph_comp.save(say + 'reference.eps')

    sim.run(continuefor=textra * 2,
            dt=dt * 0.001,
            plot_update_interval=textra / 2,
            data_collect_interval=textra / 4)
    print(datetime.datetime.now())
    print_concentrations([comp, compl, compr[-1]],
                         title="Ion concentrations at steady state")

    # heatmap incorporating compartment heights
    htplot.heatmap(compl,
                   comp,
                   compr,
                   sc,
                   totalht,
                   all=1,
                   init_vals=initvals,
                   title=[
                       say + 'all_end_df.eps', say + 'all_end_ecl.eps',
                       say + 'all_end_vm.eps'
                   ])
    voltage_reversal_graph_comp.save(say + 'reference.eps')

    sim.run(continuefor=textra * 2,
            dt=dt * 0.001,
            plot_update_interval=textra / 2,
            data_collect_interval=textra / 4)
    print(datetime.datetime.now())
    print_concentrations([comp, compl, compr[-1]],
                         title="Ion concentrations at steady state")

    # heatmap incorporating compartment heights
    htplot.heatmap(compl,
                   comp,
                   compr,
                   sc,
                   totalht,
                   all=1,
                   init_vals=initvals,
                   title=[
                       say + 'all_end_df.eps', say + 'all_end_ecl.eps',
                       say + 'all_end_vm.eps'
                   ])
    voltage_reversal_graph_comp.save(say + 'reference.eps')

    sim.run(continuefor=textra * 2,
            dt=dt * 0.001,
            plot_update_interval=textra / 2,
            data_collect_interval=textra / 4)
    print(datetime.datetime.now())
    print_concentrations([comp, compl, compr[-1]],
                         title="Ion concentrations at steady state")

    # heatmap incorporating compartment heights
    htplot.heatmap(compl,
                   comp,
                   compr,
                   sc,
                   totalht,
                   all=1,
                   init_vals=initvals,
                   title=[
                       say + 'all_end_df.eps', say + 'all_end_ecl.eps',
                       say + 'all_end_vm.eps'
                   ])
    voltage_reversal_graph_comp.save(say + 'reference.eps')

    return sim, gui