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 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
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
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
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))
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)
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)
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