class TestCompartmentTree(): def loadTTree(self): """ Load the T-tree morphology in memory 6--5--4--7--8 | | 1 """ fname = os.path.join(MORPHOLOGIES_PATH_PREFIX, 'Tsovtree.swc') self.tree = SOVTree(fname, types=[1, 3, 4]) self.tree.fitLeakCurrent(-75., 10.) self.tree.setCompTree() # do SOV calculation self.tree.calcSOVEquations() def testTreeDerivation(self): self.loadTTree() # locations locs_soma = [(1, 0.5)] locs_prox = [(4, 0.2)] locs_bifur = [(4, 1.0)] locs_dist_nobifur = [(6., 0.5), (8., 0.5)] locs_dist_bifur = [(4, 1.0), (6., 0.5), (8., 0.5)] locs_dist_nroot = [(4, 1.0), (4, 0.5), (6., 0.5), (8., 0.5)] # test structures with pytest.raises(KeyError): self.tree.createCompartmentTree('set0') # test root (is soma) in set self.tree.storeLocs(locs_dist_bifur + locs_soma, 'set0') ctree = self.tree.createCompartmentTree('set0') assert ctree[0].loc_ind == 3 assert ctree[1].loc_ind == 0 cloc_inds = [cn.loc_ind for cn in ctree[1].child_nodes] assert 1 in cloc_inds and 2 in cloc_inds # test soma not in set (but common root) self.tree.storeLocs(locs_dist_bifur, 'set1') ctree = self.tree.createCompartmentTree('set1') assert ctree[0].loc_ind == 0 cloc_inds = [cn.loc_ind for cn in ctree[0].child_nodes] assert 1 in cloc_inds and 2 in cloc_inds # test soma not in set and no common root self.tree.storeLocs(locs_dist_nobifur, 'set2') with pytest.warns(UserWarning): ctree = self.tree.createCompartmentTree('set2') assert self.tree.getLocs('set2')[0] == (4, 1.) cloc_inds = [cn.loc_ind for cn in ctree[0].child_nodes] assert 1 in cloc_inds and 2 in cloc_inds # test 2 locs on common root self.tree.storeLocs(locs_dist_nroot, 'set3') ctree = self.tree.createCompartmentTree('set3') assert ctree[0].loc_ind == 1 assert ctree[1].loc_ind == 0 def testFitting(self): self.loadTTree() # locations locs_soma = [(1, 0.5)] locs_prox = [(4, 0.2)] locs_bifur = [(4, 1.0)] locs_dist_nobifur = [(6., 0.5), (8., 0.5)] locs_dist_bifur = [(4, 1.0), (6., 0.5), (8., 0.5)] # store the locations self.tree.storeLocs(locs_soma + locs_prox, 'prox') self.tree.storeLocs(locs_soma + locs_bifur, 'bifur') self.tree.storeLocs(locs_soma + locs_dist_nobifur, 'dist_nobifur') self.tree.storeLocs(locs_soma + locs_dist_bifur, 'dist_bifur') # derive steady state impedance matrices z_mat_prox = self.tree.calcImpedanceMatrix(locarg='prox') z_mat_bifur = self.tree.calcImpedanceMatrix(locarg='bifur') z_mat_dist_nobifur = self.tree.calcImpedanceMatrix( locarg='dist_nobifur') z_mat_dist_bifur = self.tree.calcImpedanceMatrix(locarg='dist_bifur') # create the tree structures ctree_prox = self.tree.createCompartmentTree('prox') ctree_bifur = self.tree.createCompartmentTree('bifur') ctree_dist_nobifur = self.tree.createCompartmentTree('dist_nobifur') ctree_dist_bifur = self.tree.createCompartmentTree('dist_bifur') # test the tree structures assert len(ctree_prox) == len(locs_prox) + 1 assert len(ctree_bifur) == len(locs_bifur) + 1 assert len(ctree_dist_nobifur) == len(locs_dist_nobifur) + 1 assert len(ctree_dist_bifur) == len(locs_dist_bifur) + 1 # fit the steady state models ctree_prox.computeGMC(z_mat_prox) ctree_bifur.computeGMC(z_mat_bifur) ctree_dist_nobifur.computeGMC(z_mat_dist_nobifur) ctree_dist_bifur.computeGMC(z_mat_dist_bifur) # compute the fitted impedance matrices z_fit_prox = ctree_prox.calcImpedanceMatrix() z_fit_bifur = ctree_bifur.calcImpedanceMatrix() z_fit_dist_nobifur = ctree_dist_nobifur.calcImpedanceMatrix() z_fit_dist_bifur = ctree_dist_bifur.calcImpedanceMatrix() # test correctness assert np.allclose(z_fit_prox, z_mat_prox, atol=0.5) assert np.allclose(z_fit_bifur, z_mat_bifur, atol=0.5) assert not np.allclose( z_fit_dist_nobifur, z_mat_dist_nobifur, atol=0.5) assert np.allclose(z_fit_dist_bifur, z_mat_dist_bifur, atol=0.5) def testReordering(self): self.loadTTree() # test reordering locs_dist_badorder = [(1., 0.5), (8., 0.5), (4, 1.0)] self.tree.storeLocs(locs_dist_badorder, 'badorder') z_mat_badorder = self.tree.calcImpedanceMatrix(locarg='badorder') ctree_badorder = self.tree.createCompartmentTree('badorder') # check if location indices are assigned correctly assert [node.loc_ind for node in ctree_badorder] == [0, 2, 1] # check if reordering works z_mat_reordered = ctree_badorder._preprocessZMatArg(z_mat_badorder) assert np.allclose(z_mat_reordered, z_mat_badorder[:, [0, 2, 1]][[0, 2, 1], :]) # check if fitting is correct ctree_badorder.computeGMC(z_mat_badorder) z_fit_badorder = ctree_badorder.calcImpedanceMatrix() assert np.allclose(z_mat_badorder, z_fit_badorder, atol=0.5) assert not np.allclose(z_mat_reordered, z_fit_badorder) # test if equivalent locs are returned correctly locs_equiv = ctree_badorder.getEquivalentLocs() assert all([ loc == loc_ for loc, loc_ in zip(locs_equiv, [(0, .5), (2, .5), (1, .5)]) ]) def loadBallAndStick(self): self.greens_tree = GreensTree(file_n=os.path.join( MORPHOLOGIES_PATH_PREFIX, 'ball_and_stick.swc')) self.greens_tree.setPhysiology(0.8, 100. / 1e6) self.greens_tree.setLeakCurrent(100., -75.) self.greens_tree.setCompTree() # set the impedances self.freqs = np.array([0.]) * 1j self.greens_tree.setImpedance(self.freqs) # create sov tree self.sov_tree = self.greens_tree.__copy__(new_tree=SOVTree()) self.sov_tree.calcSOVEquations(maxspace_freq=50.) def testLocationMapping(self, n_loc=20): self.loadBallAndStick() # define locations xvals = np.linspace(0., 1., n_loc + 1)[1:] locs_1 = [(1, 0.5)] + [(4, x) for x in xvals] locs_2 = [(1, 0.5)] + [(4, x) for x in xvals][::-1] locs_3 = [(4, x) for x in xvals] + [(1, 0.5)] # create compartment trees ctree_1 = self.greens_tree.createCompartmentTree(locs_1) ctree_2 = self.greens_tree.createCompartmentTree(locs_2) ctree_3 = self.greens_tree.createCompartmentTree(locs_3) # test location indices locinds_1 = np.array([node.loc_ind for node in ctree_1]) locinds_2 = np.array([node.loc_ind for node in ctree_2]) locinds_3 = np.array([node.loc_ind for node in ctree_3]) # check consecutive assert np.allclose(locinds_1[:-1], locinds_1[1:] - 1) # check permutation assert np.allclose(locinds_1[1:], locinds_2[1:][::-1]) assert np.allclose(locinds_1[:-1], locinds_3[1:]) def testGSSFit(self, n_loc=20): self.loadBallAndStick() # define locations xvals = np.linspace(0., 1., n_loc + 1)[1:] locs_1 = [(1, 0.5)] + [(4, x) for x in xvals] locs_2 = [(1, 0.5)] + [(4, x) for x in xvals][::-1] locs_3 = [(4, x) for x in xvals] + [(1, 0.5)] locs_4 = random.sample(locs_1, k=len(locs_1)) # calculate impedance matrices z_mat_1 = self.greens_tree.calcImpedanceMatrix(locs_1)[0].real z_mat_2 = self.greens_tree.calcImpedanceMatrix(locs_2)[0].real z_mat_3 = self.greens_tree.calcImpedanceMatrix(locs_3)[0].real z_mat_4 = self.greens_tree.calcImpedanceMatrix(locs_4)[0].real # create compartment trees ctree_1 = self.greens_tree.createCompartmentTree(locs_1) ctree_2 = self.greens_tree.createCompartmentTree(locs_2) ctree_3 = self.greens_tree.createCompartmentTree(locs_3) ctree_4 = self.greens_tree.createCompartmentTree(locs_4) # fit g_m and g_c ctree_1.computeGMC(z_mat_1, channel_names=['L']) ctree_2.computeGMC(z_mat_2, channel_names=['L']) ctree_3.computeGMC(z_mat_3, channel_names=['L']) ctree_4.computeGMC(z_mat_4, channel_names=['L']) # compare both models assert str(ctree_1) == str(ctree_2) assert str(ctree_1) == str(ctree_3) assert str(ctree_1) == str(ctree_4) # compare impedance matrices z_fit_1 = ctree_1.calcImpedanceMatrix(self.freqs) z_fit_2 = ctree_2.calcImpedanceMatrix(self.freqs) z_fit_3 = ctree_3.calcImpedanceMatrix(self.freqs) z_fit_4 = ctree_4.calcImpedanceMatrix(self.freqs) assert np.allclose(z_fit_1, z_mat_1, atol=1e-8) assert np.allclose(z_fit_2, z_mat_2, atol=1e-8) assert np.allclose(z_fit_3, z_mat_3, atol=1e-8) assert np.allclose(z_fit_4, z_mat_4, atol=1e-8) assert np.allclose(z_fit_1, ctree_2.calcImpedanceMatrix(indexing='tree')) assert np.allclose(z_fit_1, ctree_3.calcImpedanceMatrix(indexing='tree')) assert np.allclose(z_fit_1, ctree_4.calcImpedanceMatrix(indexing='tree')) def testCFit(self, n_loc=20): self.loadBallAndStick() # define locations xvals = np.linspace(0., 1., n_loc + 1)[1:] locs = [(1, 0.5)] + [(4, x) for x in xvals] # create compartment tree ctree = self.greens_tree.createCompartmentTree(locs) # steady state fit z_mat = self.greens_tree.calcImpedanceMatrix(locs)[0].real ctree.computeGMC(z_mat) # get SOV constants for capacitance fit alphas, phimat, importance = self.sov_tree.getImportantModes( locarg=locs, sort_type='importance', eps=1e-12, return_importance=True) # fit the capacitances from SOV time-scales ctree.computeC(-alphas[0:1].real * 1e3, phimat[0:1, :].real, weights=importance[0:1]) # check if equal to membrane time scale nds = [self.greens_tree[loc[0]] for loc in locs] taus_orig = np.array([n.c_m / n.currents['L'][0] for n in nds]) taus_fit = np.array([n.ca / n.currents['L'][0] for n in ctree]) assert np.allclose(taus_orig, taus_fit) # fit capacitances with experimental vector fit for n in ctree: n.ca = 1. self.greens_tree.setImpedance(freqs=ke.create_logspace_freqarray()) z_mat = self.greens_tree.calcImpedanceMatrix(locs) # run the vector fit ctree.computeCVF(self.greens_tree.freqs, z_mat) taus_fit2 = np.array([n.ca / n.currents['L'][0] for n in ctree]) assert np.allclose(taus_orig, taus_fit2, atol=.3) def fitBallAndStick(self, n_loc=20): self.loadBallAndStick() # define locations xvals = np.linspace(0., 1., n_loc + 1)[1:] np.random.shuffle(xvals) locs = [(1, 0.5)] + [(4, x) for x in xvals] # create compartment tree ctree = self.greens_tree.createCompartmentTree(locs) # steady state fit z_mat = self.greens_tree.calcImpedanceMatrix(locs)[0].real ctree.computeGMC(z_mat) # get SOV constants for capacitance fit alphas, phimat, importance = self.sov_tree.getImportantModes( locarg=locs, sort_type='importance', eps=1e-12, return_importance=True) # fit the capacitances from SOV time-scales ctree.computeC(-alphas[0:1].real * 1e3, phimat[0:1, :].real, weights=importance[0:1]) self.ctree = ctree def testPasFunctionality(self, n_loc=10): self.fitBallAndStick(n_loc=n_loc) # test equilibrium potential setting e_eq = -75. + np.random.randint(10, size=n_loc + 1) # with tree indexing self.ctree.setEEq(e_eq, indexing='tree') assert np.allclose(e_eq, np.array([n.e_eq for n in self.ctree])) assert np.allclose(e_eq, self.ctree.getEEq(indexing='tree')) assert not np.allclose(e_eq, self.ctree.getEEq(indexing='locs')) # with loc indexing self.ctree.setEEq(e_eq, indexing='locs') assert not np.allclose(e_eq, np.array([n.e_eq for n in self.ctree])) assert not np.allclose(e_eq, self.ctree.getEEq(indexing='tree')) assert np.allclose(e_eq, self.ctree.getEEq(indexing='locs')) # conductance matrices gm1 = self.ctree.calcConductanceMatrix(indexing='locs') gm2 = self.ctree.calcSystemMatrix(indexing='locs', channel_names=['L'], with_ca=True, use_conc=False) gm3 = self.ctree.calcSystemMatrix(indexing='locs', channel_names=['L'], with_ca=False, use_conc=False) gm4 = self.ctree.calcSystemMatrix(indexing='locs', channel_names=['L'], with_ca=False, use_conc=True) gm5 = self.ctree.calcSystemMatrix(indexing='locs', with_ca=False, use_conc=True) gm6 = self.ctree.calcSystemMatrix(indexing='tree', with_ca=False, use_conc=True) assert np.allclose(gm1, gm2) assert np.allclose(gm1, gm3) assert np.allclose(gm1, gm4) assert np.allclose(gm1, gm5) assert not np.allclose(gm1, gm6) # eigenvalues alphas, phimat, phimat_inv = self.ctree.calcEigenvalues() ca_vec = np.array([1. / node.ca for node in self.ctree]) * 1e-3 assert np.allclose(np.dot(phimat, phimat_inv), np.diag(ca_vec)) assert np.allclose( np.array([n.ca / n.currents['L'][0] for n in self.ctree]), np.ones(len(self.ctree)) * np.max(1e-3 / np.abs(alphas))) def loadBall(self): self.greens_tree = GreensTree( file_n=os.path.join(MORPHOLOGIES_PATH_PREFIX, 'ball.swc')) # capacitance and axial resistance self.greens_tree.setPhysiology(0.8, 100. / 1e6) # ion channels k_chan = channelcollection.Kv3_1() self.greens_tree.addCurrent(k_chan, 0.766 * 1e6, -85.) na_chan = channelcollection.Na_Ta() self.greens_tree.addCurrent(na_chan, 1.71 * 1e6, 50.) # fit leak current self.greens_tree.fitLeakCurrent(-75., 10.) # set computational tree self.greens_tree.setCompTree() # set the impedances self.freqs = np.array([0.]) self.greens_tree.setImpedance(self.freqs) # create sov tree self.sov_tree = self.greens_tree.__copy__(new_tree=SOVTree()) self.sov_tree.calcSOVEquations(maxspace_freq=100.) def testChannelFit(self): self.loadBall() locs = [(1, 0.5)] e_eqs = [-75., -55., -35., -15.] # create compartment tree ctree = self.greens_tree.createCompartmentTree(locs) ctree.addCurrent(channelcollection.Na_Ta(), 50.) ctree.addCurrent(channelcollection.Kv3_1(), -85.) # create tree with only leak greens_tree_pas = self.greens_tree.__copy__() greens_tree_pas[1].currents = {'L': greens_tree_pas[1].currents['L']} greens_tree_pas.setCompTree() greens_tree_pas.setImpedance(self.freqs) # compute the passive impedance matrix z_mat_pas = greens_tree_pas.calcImpedanceMatrix(locs)[0] # create tree with only potassium greens_tree_k = self.greens_tree.__copy__() greens_tree_k[1].currents = {key: val for key, val in greens_tree_k[1].currents.items() \ if key != 'Na_Ta'} # compute potassium impedance matrices z_mats_k = [] for e_eq in e_eqs: greens_tree_k.setEEq(e_eq) greens_tree_k.setCompTree() greens_tree_k.setImpedance(self.freqs) z_mats_k.append(greens_tree_k.calcImpedanceMatrix(locs)) # create tree with only sodium greens_tree_na = self.greens_tree.__copy__() greens_tree_na[1].currents = {key: val for key, val in greens_tree_na[1].currents.items() \ if key != 'Kv3_1'} # create state variable expansion points svs = [] e_eqs_ = [] na_chan = greens_tree_na.channel_storage['Na_Ta'] for e_eq1 in e_eqs: sv1 = na_chan.computeVarinf(e_eq1) for e_eq2 in e_eqs: e_eqs_.append(e_eq2) sv2 = na_chan.computeVarinf(e_eq2) svs.append({'m': sv2['m'], 'h': sv1['h']}) # compute sodium impedance matrices z_mats_na = [] for ii, sv in enumerate(svs): greens_tree_na.setEEq(e_eqs[ii % len(e_eqs)]) greens_tree_na[1].setExpansionPoint('Na_Ta', sv) greens_tree_na.setCompTree() greens_tree_na.setImpedance(self.freqs) z_mats_na.append(greens_tree_na.calcImpedanceMatrix(locs)) # compute combined impedance matrices z_mats_comb = [] for e_eq in e_eqs: self.greens_tree.setEEq(e_eq) self.greens_tree.setCompTree() self.greens_tree.setImpedance(self.freqs) z_mats_comb.append(self.greens_tree.calcImpedanceMatrix(locs)) # passive fit ctree.computeGMC(z_mat_pas) # get SOV constants for capacitance fit sov_tree = greens_tree_pas.__copy__(new_tree=SOVTree()) sov_tree.setCompTree() sov_tree.calcSOVEquations() alphas, phimat, importance = sov_tree.getImportantModes( locarg=locs, sort_type='importance', eps=1e-12, return_importance=True) # fit the capacitances from SOV time-scales ctree.computeC(-alphas[0:1].real * 1e3, phimat[0:1, :].real, weights=importance[0:1]) ctree1 = copy.deepcopy(ctree) ctree2 = copy.deepcopy(ctree) ctree3 = copy.deepcopy(ctree) ctree4 = copy.deepcopy(ctree) # fit paradigm 1 --> separate impedance matrices and separate fits # potassium channel fit for z_mat_k, e_eq in zip(z_mats_k, e_eqs): ctree1.computeGSingleChanFromImpedance('Kv3_1', z_mat_k, e_eq, self.freqs, other_channel_names=['L']) ctree1.runFit() # sodium channel fit for z_mat_na, e_eq, sv in zip(z_mats_na, e_eqs_, svs): ctree1.computeGSingleChanFromImpedance('Na_Ta', z_mat_na, e_eq, self.freqs, sv=sv, other_channel_names=['L']) ctree1.runFit() # fit paradigm 2 --> separate impedance matrices, same fit for z_mat_k, e_eq in zip(z_mats_k, e_eqs): ctree2.computeGSingleChanFromImpedance( 'Kv3_1', z_mat_k, e_eq, self.freqs, all_channel_names=['Kv3_1', 'Na_Ta']) for z_mat_na, e_eq, sv in zip(z_mats_na, e_eqs_, svs): ctree2.computeGSingleChanFromImpedance( 'Na_Ta', z_mat_na, e_eq, self.freqs, sv=sv, all_channel_names=['Kv3_1', 'Na_Ta']) ctree2.runFit() # fit paradigm 3 --> same impedance matrices for z_mat_comb, e_eq in zip(z_mats_comb, e_eqs): ctree3.computeGChanFromImpedance(['Kv3_1', 'Na_Ta'], z_mat_comb, e_eq, self.freqs) ctree3.runFit() # fit paradigm 4 --> fit incrementally for z_mat_na, e_eq, sv in zip(z_mats_na, e_eqs_, svs): ctree4.computeGSingleChanFromImpedance('Na_Ta', z_mat_na, e_eq, self.freqs, sv=sv) ctree4.runFit() for z_mat_comb, e_eq in zip(z_mats_comb, e_eqs): ctree4.computeGSingleChanFromImpedance( 'Kv3_1', z_mat_comb, e_eq, self.freqs, other_channel_names=['Na_Ta', 'L']) ctree4.runFit() # test if correct keys = ['L', 'Na_Ta', 'Kv3_1'] # soma surface (cm) for total conductance calculation a_soma = 4. * np.pi * (self.greens_tree[1].R * 1e-4)**2 conds = np.array( [self.greens_tree[1].currents[key][0] * a_soma for key in keys]) # compartment models conductances cconds1 = np.array([ctree1[0].currents[key][0] for key in keys]) cconds2 = np.array([ctree2[0].currents[key][0] for key in keys]) cconds3 = np.array([ctree3[0].currents[key][0] for key in keys]) cconds4 = np.array([ctree4[0].currents[key][0] for key in keys]) assert np.allclose(conds, cconds1) assert np.allclose(conds, cconds2) assert np.allclose(conds, cconds3) assert np.allclose(conds, cconds4) # rename for further testing ctree = ctree1 # frequency array ft = ke.FourrierTools(np.linspace(0., 50., 100)) freqs = ft.s # compute impedance matrix v_h = -42. # original self.greens_tree.setEEq(v_h) self.greens_tree.setCompTree() self.greens_tree.setImpedance(freqs) z_mat_orig = self.greens_tree.calcImpedanceMatrix([(1., .5)]) # potassium greens_tree_k.setEEq(v_h) greens_tree_k.setCompTree() greens_tree_k.setImpedance(freqs) z_mat_k = greens_tree_k.calcImpedanceMatrix([(1, .5)]) # sodium greens_tree_na.removeExpansionPoints() greens_tree_na.setEEq(v_h) greens_tree_na.setCompTree() greens_tree_na.setImpedance(freqs) z_mat_na = greens_tree_na.calcImpedanceMatrix([(1, .5)]) # passive greens_tree_pas.setCompTree() greens_tree_pas.setImpedance(freqs) z_mat_pas = greens_tree_pas.calcImpedanceMatrix([(1, .5)]) # reduced impedance matrices ctree.removeExpansionPoints() ctree.setEEq(v_h) z_mat_fit = ctree.calcImpedanceMatrix(freqs=freqs) z_mat_fit_k = ctree.calcImpedanceMatrix(channel_names=['L', 'Kv3_1'], freqs=freqs) z_mat_fit_na = ctree.calcImpedanceMatrix(channel_names=['L', 'Na_Ta'], freqs=freqs) z_mat_fit_pas = ctree.calcImpedanceMatrix(channel_names=['L'], freqs=freqs) assert np.allclose(z_mat_orig, z_mat_fit) assert np.allclose(z_mat_k, z_mat_fit_k) assert np.allclose(z_mat_na, z_mat_fit_na) assert np.allclose(z_mat_pas, z_mat_fit_pas) # test total current, conductance sv = svs[-1] p_open = sv['m']**3 * sv['h'] # with p_open given g1 = ctree[0].getGTot(ctree.channel_storage, channel_names=['L', 'Na_Ta'], p_open_channels={'Na_Ta': p_open}) i1 = ctree[0].getGTot(ctree.channel_storage, channel_names=['L', 'Na_Ta'], p_open_channels={'Na_Ta': p_open}) # with expansion point given ctree.setExpansionPoints({'Na_Ta': sv}) g2 = ctree[0].getGTot(ctree.channel_storage, channel_names=['L', 'Na_Ta']) i2 = ctree[0].getGTot(ctree.channel_storage, channel_names=['L', 'Na_Ta']) # with e_eq given g3 = ctree[0].getGTot(ctree.channel_storage, v=e_eqs[-1], channel_names=['L', 'Na_Ta']) i3 = ctree[0].getGTot(ctree.channel_storage, v=e_eqs[-1], channel_names=['L', 'Na_Ta']) # with e_eq stored ctree.setEEq(e_eqs[-1]) g4 = ctree[0].getGTot(ctree.channel_storage, channel_names=['L', 'Na_Ta']) i4 = ctree[0].getGTot(ctree.channel_storage, channel_names=['L', 'Na_Ta']) # check if correct assert np.abs(g1 - g2) < 1e-10 assert np.abs(g1 - g3) < 1e-10 assert np.abs(g1 - g4) < 1e-10 assert np.abs(i1 - i2) < 1e-10 assert np.abs(i1 - i3) < 1e-10 assert np.abs(i1 - i4) < 1e-10 # compare current, conductance g_ = ctree[0].getGTot(ctree.channel_storage, channel_names=['Na_Ta']) i_ = ctree[0].getITot(ctree.channel_storage, channel_names=['Na_Ta']) assert np.abs(g_ * (e_eqs[-1] - ctree[0].currents['Na_Ta'][1]) - i_) < 1e-10 # test leak fitting self.greens_tree.setEEq(-75.) self.greens_tree.setCompTree() ctree.setEEq(-75.) ctree.removeExpansionPoints() ctree.fitEL() assert np.abs(ctree[0].currents['L'][1] - self.greens_tree[1].currents['L'][1]) < 1e-10
class TestNeuron(): def loadTTreePassive(self): """ Load the T-tree morphology in memory with passive conductance 6--5--4--7--8 | | 1 """ v_eq = -75. self.dt = 0.025 self.tmax = 100. # for frequency derivation self.ft = ke.FourrierTools(np.arange(0., self.tmax, self.dt)) # load the morphology fname = os.path.join(MORPHOLOGIES_PATH_PREFIX, 'Tsovtree.swc') self.greenstree = GreensTree(fname, types=[1, 3, 4]) self.greenstree.fitLeakCurrent(v_eq, 10.) self.greenstree.setCompTree() self.greenstree.setImpedance(self.ft.s) # copy greenstree parameters into NEURON simulation tree self.neurontree = NeuronSimTree(dt=self.dt, t_calibrate=10., v_init=v_eq, factor_lambda=25.) self.greenstree.__copy__(self.neurontree) self.neurontree.treetype = 'computational' def loadTTreeActive(self): """ Load the T-tree morphology in memory with h-current 6--5--4--7--8 | | 1 """ v_eq = -75. self.dt = 0.1 self.tmax = 100. # for frequency derivation self.ft = ke.FourrierTools(np.arange(0., self.tmax, self.dt)) # load the morphology h_chan = channelcollection.h() fname = os.path.join(MORPHOLOGIES_PATH_PREFIX, 'Tsovtree.swc') self.greenstree = GreensTree(fname, types=[1, 3, 4]) self.greenstree.addCurrent(h_chan, 50., -43.) self.greenstree.fitLeakCurrent(v_eq, 10.) self.greenstree.setCompTree() self.greenstree.setImpedance(self.ft.s) # copy greenstree parameters into NEURON simulation tree self.neurontree = NeuronSimTree(dt=self.dt, t_calibrate=10., v_init=v_eq, factor_lambda=25.) self.greenstree.__copy__(self.neurontree) self.neurontree.treetype = 'computational' def loadTTreeTestChannel(self): """ Load the T-tree morphology in memory with h-current 6--5--4--7--8 | | 1 """ v_eq = -75. self.dt = 0.025 self.tmax = 100. # for frequency derivation self.ft = ke.FourrierTools(np.arange(0., self.tmax, self.dt)) # load the morphology test_chan = channelcollection.TestChannel2() fname = os.path.join(MORPHOLOGIES_PATH_PREFIX, 'Tsovtree.swc') self.greenstree = GreensTree(fname, types=[1, 3, 4]) self.greenstree.addCurrent(test_chan, 50., -23.) self.greenstree.fitLeakCurrent(v_eq, 10.) self.greenstree.setCompTree() self.greenstree.setImpedance(self.ft.s) # copy greenstree parameters into NEURON simulation tree self.neurontree = NeuronSimTree(dt=self.dt, t_calibrate=100., v_init=v_eq, factor_lambda=25.) self.greenstree.__copy__(self.neurontree) self.neurontree.treetype = 'computational' def loadTTreeTestChannelSoma(self): """ Load the T-tree morphology in memory with h-current 6--5--4--7--8 | | 1 """ v_eq = -75. self.dt = 0.025 self.tmax = 100. # for frequency derivation self.ft = ke.FourrierTools(np.arange(0., self.tmax, self.dt)) # load the morphology test_chan = channelcollection.TestChannel2() fname = os.path.join(MORPHOLOGIES_PATH_PREFIX, 'Tsovtree.swc') self.greenstree = GreensTree(fname, types=[1, 3, 4]) self.greenstree.addCurrent(test_chan, 50., 23., node_arg=[self.greenstree[1]]) self.greenstree.fitLeakCurrent(v_eq, 10.) self.greenstree.setCompTree() self.greenstree.setImpedance(self.ft.s) # copy greenstree parameters into NEURON simulation tree self.neurontree = NeuronSimTree(dt=self.dt, t_calibrate=100., v_init=v_eq, factor_lambda=25.) self.greenstree.__copy__(self.neurontree) self.neurontree.treetype = 'computational' def testPassive(self, pplot=False): self.loadTTreePassive() # set of locations locs = [(1, .5), (4, .5), (4, 1.), (5, .5), (6, .5), (7, .5), (8, .5)] # compute impedance matrix with Green's function zf_mat_gf = self.greenstree.calcImpedanceMatrix(locs) z_mat_gf = zf_mat_gf[self.ft.ind_0s].real # convert impedance matrix to time domain zk_mat_gf = np.zeros((len(self.ft.t), len(locs), len(locs))) for (ii, jj) in itertools.product(list(range(len(locs))), list(range(len(locs)))): zk_mat_gf[:, ii, jj] = self.ft.ftInv(zf_mat_gf[:, ii, jj])[1].real * 1e-3 # test the steady state impedance matrix z_mat_neuron = self.neurontree.calcImpedanceMatrix(locs) assert np.allclose(z_mat_gf, z_mat_neuron, atol=1.) # test the temporal matrix tk, zk_mat_neuron = self.neurontree.calcImpedanceKernelMatrix(locs) assert np.allclose(zk_mat_gf[int(2. / self.dt):, :, :], zk_mat_neuron[int(2. / self.dt):, :, :], atol=.2) if pplot: # plot kernels pl.figure() cc = 0 for ii in range(len(locs)): jj = 0 while jj <= ii: pl.plot(tk, zk_mat_neuron[:, ii, jj], c=colours[cc % len(colours)]) pl.plot(tk, zk_mat_gf[:, ii, jj], ls='--', lw=2, c=colours[cc % len(colours)]) cc += 1 jj += 1 pl.show() def testActive(self, pplot=False): self.loadTTreeActive() # set of locations locs = [(1, .5), (4, .5), (6, .5), (7, .5), (8, .5)] # compute impedance matrix with Green's function zf_mat_gf = self.greenstree.calcImpedanceMatrix(locs) z_mat_gf = zf_mat_gf[self.ft.ind_0s].real # convert impedance matrix to time domain zk_mat_gf = np.zeros((len(self.ft.t), len(locs), len(locs))) for (ii, jj) in itertools.product(list(range(len(locs))), list(range(len(locs)))): zk_mat_gf[:, ii, jj] = self.ft.ftInv(zf_mat_gf[:, ii, jj])[1].real * 1e-3 # test the steady state impedance matrix z_mat_neuron = self.neurontree.calcImpedanceMatrix(locs, t_dur=500.) assert np.allclose(z_mat_gf, z_mat_neuron, atol=5.) # test the temporal matrix tk, zk_mat_neuron = self.neurontree.calcImpedanceKernelMatrix(locs) assert np.allclose(zk_mat_gf[int(2. / self.dt):, :, :], zk_mat_neuron[int(2. / self.dt):, :, :], atol=.5) if pplot: # plot kernels pl.figure() cc = 0 for ii in range(len(locs)): jj = 0 while jj <= ii: pl.plot(tk, zk_mat_neuron[:, ii, jj], c=colours[cc % len(colours)]) pl.plot(tk, zk_mat_gf[:, ii, jj], ls='--', lw=2, c=colours[cc % len(colours)]) cc += 1 jj += 1 pl.show() def testChannelRecording(self): self.loadTTreeTestChannel() # set of locations locs = [(1, .5), (4, .5), (4, 1.), (5, .5), (6, .5), (7, .5), (8, .5)] # create simulation tree self.neurontree.initModel(t_calibrate=10., factor_lambda=10.) self.neurontree.storeLocs(locs, name='rec locs') # run test simulation res = self.neurontree.run(1., record_from_channels=True) # check if results are stored correctly assert set(res['chan']['TestChannel2'].keys()) == { 'a00', 'a01', 'a10', 'a11', 'p_open' } # check if values are correct assert np.allclose(res['chan']['TestChannel2']['a00'], .3) assert np.allclose(res['chan']['TestChannel2']['a01'], .5) assert np.allclose(res['chan']['TestChannel2']['a10'], .4) assert np.allclose(res['chan']['TestChannel2']['a11'], .6) assert np.allclose(res['chan']['TestChannel2']['p_open'], .9 * .3**3 * .5**2 + .1 * .4**2 * .6**1) # check if shape is correct n_loc, n_step = len(locs), len(res['t']) assert res['chan']['TestChannel2']['a00'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['a01'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['a10'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['a11'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['p_open'].shape == (n_loc, n_step) # channel only at soma self.loadTTreeTestChannelSoma() # create simulation tree self.neurontree.initModel(t_calibrate=100., factor_lambda=10.) self.neurontree.storeLocs(locs, name='rec locs') # run test simulation res = self.neurontree.run(10., record_from_channels=True) # check if results are stored correctly assert set(res['chan']['TestChannel2'].keys()) == { 'a00', 'a01', 'a10', 'a11', 'p_open' } # check if values are correct assert np.allclose(res['chan']['TestChannel2']['a00'][0, :], .3) assert np.allclose(res['chan']['TestChannel2']['a01'][0, :], .5) assert np.allclose(res['chan']['TestChannel2']['a10'][0, :], .4) assert np.allclose(res['chan']['TestChannel2']['a11'][0, :], .6) assert np.allclose(res['chan']['TestChannel2']['p_open'][0, :], .9 * .3**3 * .5**2 + .1 * .4**2 * .6**1) assert np.allclose(res['chan']['TestChannel2']['a00'][1:, :], 0.) assert np.allclose(res['chan']['TestChannel2']['a01'][1:, :], 0.) assert np.allclose(res['chan']['TestChannel2']['a10'][1:, :], 0.) assert np.allclose(res['chan']['TestChannel2']['a11'][1:, :], 0.) assert np.allclose(res['chan']['TestChannel2']['p_open'][1:, :], 0.) # check if shape is correct n_loc, n_step = len(locs), len(res['t']) assert res['chan']['TestChannel2']['a00'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['a01'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['a10'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['a11'].shape == (n_loc, n_step) assert res['chan']['TestChannel2']['p_open'].shape == (n_loc, n_step)
class TestCNET(): def createPointNeurons(self, v_eq=-75.): self.v_eq = v_eq self.dt = .025 gh, eh = 50., -43. h_chan = channelcollection.h() self.greens_tree = GreensTree( file_n=os.path.join(MORPHOLOGIES_PATH_PREFIX, 'ball.swc')) self.greens_tree.setPhysiology(1., 100. / 1e6) self.greens_tree.addCurrent(h_chan, gh, eh) self.greens_tree.fitLeakCurrent(v_eq, 10.) self.greens_tree.setEEq(v_eq) self.greens_tree_pas = self.greens_tree.__copy__(new_tree=GreensTree()) self.greens_tree_pas.asPassiveMembrane() self.sim_tree = self.greens_tree.__copy__(new_tree=NeuronSimTree()) # set the impedances self.greens_tree_pas.setCompTree() self.freqs = np.array([0.]) self.greens_tree_pas.setImpedance(self.freqs) # create sov tree self.sov_tree = self.greens_tree_pas.__copy__(new_tree=SOVTree()) self.sov_tree.calcSOVEquations(maxspace_freq=50.) z_inp = self.greens_tree_pas.calcZF((1, .5), (1, .5))[0] alphas, gammas = self.sov_tree.getSOVMatrices(locarg=[(1., .5)]) # create NET node_0 = NETNode(0, [0], [0], z_kernel=(alphas, gammas[:, 0]**2)) net_py = NET() net_py.setRoot(node_0) # check if correct assert np.abs(gammas[0, 0]**2 / np.abs(alphas[0]) - z_inp) < 1e-10 assert np.abs(node_0.z_bar - z_inp) < 1e-10 # to initialize neuron tree self.sim_tree.initModel(dt=self.dt) # add ion channel to NET simulator a_soma = 4. * np.pi * (self.sim_tree[1].R * 1e-4)**2 self.cnet = netsim.NETSim(net_py, v_eq=self.v_eq) hchan = channelcollection.h() self.cnet.addChannel(hchan, 0, gh * a_soma, eh) # add the synapse # to neuron tree self.sim_tree.addDoubleExpSynapse((1, .5), .2, 3., 0.) self.sim_tree.setSpikeTrain(0, 0.001, [5.]) # to net sim self.cnet.addSynapse(0, { 'tau_r': .2, 'tau_d': 3., 'e_r': 0. }, g_max=0.001) self.cnet.setSpikeTimes(0, [5. + self.dt]) def createTree(self, reinitialize=1, v_eq=-75.): """ Create simple NET structure 2 3 | | | | ---1--- | | 0 | """ self.v_eq = v_eq loc_ind = np.array([0, 1, 2]) # kernel constants alphas = 1. / np.array([.5, 8.]) gammas = np.array([-1., 1.]) alphas_ = 1. / np.array([1.]) gammas_ = np.array([1.]) # nodes node_0 = NETNode(0, [0, 1, 2], [], z_kernel=(alphas, gammas)) node_1 = NETNode(1, [0, 1, 2], [0], z_kernel=(alphas_, gammas_)) node_2 = NETNode(2, [1], [1], z_kernel=(alphas_, gammas_)) node_3 = NETNode(3, [2], [2], z_kernel=(alphas_, gammas_)) # add nodes to tree net_py = NET() net_py.setRoot(node_0) net_py.addNodeWithParent(node_1, node_0) net_py.addNodeWithParent(node_2, node_1) net_py.addNodeWithParent(node_3, node_1) # store self.net_py = net_py self.cnet = netsim.NETSim(net_py, v_eq=self.v_eq) def createTree2(self, reinitialize=1, add_lin=True, v_eq=-75.): """ Create simple NET structure 3 4 | | | | ---2--- 1 | | | ---0--- | """ self.v_eq = v_eq loc_ind = np.array([0, 1, 2]) # kernel constants alphas = 1. / np.array([1.]) gammas = np.array([1.]) # nodes node_0 = NETNode(0, [0, 1, 2], [], z_kernel=(alphas, gammas)) node_1 = NETNode(1, [0], [0], z_kernel=(alphas, gammas)) node_2 = NETNode(2, [1, 2], [], z_kernel=(alphas, gammas)) node_3 = NETNode(3, [1], [1], z_kernel=(alphas, gammas)) node_4 = NETNode(4, [2], [2], z_kernel=(alphas, gammas)) # add nodes to tree net_py = NET() net_py.setRoot(node_0) net_py.addNodeWithParent(node_1, node_0) net_py.addNodeWithParent(node_2, node_0) net_py.addNodeWithParent(node_3, node_2) net_py.addNodeWithParent(node_4, node_2) # linear terms alphas = 1. / np.array([1.]) gammas = np.array([1.]) self.lin_terms = { 1: Kernel((alphas, gammas)), 2: Kernel((alphas, gammas)) } if add_lin else {} # store self.net_py = net_py self.cnet = netsim.NETSim(net_py, lin_terms=self.lin_terms, v_eq=self.v_eq) def createTree3(self, reinitialize=1, add_lin=True, v_eq=-75.): """ Create simple NET structure 6 4 5 | | | | | | | 2 ---3--- | | | | ---1--- | | | 0------ | """ self.v_eq = v_eq # kernel constants alphas = 1. / np.array([1.]) gammas = np.array([1.]) # nodes node_0 = NETNode(0, [0, 1, 2, 3], [], z_kernel=(alphas, gammas)) node_1 = NETNode(1, [0, 1, 2], [], z_kernel=(alphas, gammas)) node_2 = NETNode(2, [0], [0], z_kernel=(alphas, gammas)) node_3 = NETNode(3, [1, 2], [], z_kernel=(alphas, gammas)) node_4 = NETNode(4, [1], [1], z_kernel=(alphas, gammas)) node_5 = NETNode(5, [2], [2], z_kernel=(alphas, gammas)) node_6 = NETNode(6, [3], [3], z_kernel=(alphas, gammas)) # add nodes to tree net_py = NET() net_py.setRoot(node_0) net_py.addNodeWithParent(node_1, node_0) net_py.addNodeWithParent(node_2, node_1) net_py.addNodeWithParent(node_3, node_1) net_py.addNodeWithParent(node_4, node_3) net_py.addNodeWithParent(node_5, node_3) net_py.addNodeWithParent(node_6, node_0) # linear terms alphas = 1. / np.array([1.]) gammas = np.array([1.]) self.lin_terms = { 1: Kernel((alphas, gammas)), 2: Kernel((alphas, gammas)), 3: Kernel((alphas, gammas)) } if add_lin else {} # store self.net_py = net_py self.cnet = netsim.NETSim(net_py, lin_terms=self.lin_terms) def testIOFunctions(self): self.createTree() # storing and reading voltages from node voltage vnode = np.array([8., 10., 12., 14.]) self.cnet.setVNodeFromVNode(vnode) vnode_back1 = self.cnet.getVNode() vnode_back2 = np.zeros(4) self.cnet.addVNodeToArr(vnode_back2) assert np.allclose(vnode_back1, vnode) assert np.allclose(vnode_back2, vnode) vloc_back1 = self.cnet.getVLoc() vloc_back2 = np.zeros(3) self.cnet.addVLocToArr(vloc_back2) assert np.allclose(vloc_back1, np.array([18., 30., 32.]) + self.v_eq) assert np.allclose(vloc_back2, np.array([18., 30., 32.]) + self.v_eq) with pytest.raises(ValueError): self.cnet.setVNodeFromVNode(np.zeros(3)) with pytest.raises(ValueError): self.cnet.addVNodeToArr(np.zeros(3)) with pytest.raises(ValueError): self.cnet.setVNodeFromVLoc(np.zeros(4)) with pytest.raises(ValueError): self.cnet.addVLocToArr(np.zeros(4)) # storing and reading voltages from location voltage vloc = np.array([12., 14., 16.]) + self.v_eq self.cnet.setVNodeFromVLoc(vloc) vnode_back1 = self.cnet.getVNode() vnode_back2 = np.zeros(4) self.cnet.addVNodeToArr(vnode_back2) assert np.allclose(vnode_back1, np.array([0., 12., 2., 4.])) assert np.allclose(vnode_back2, np.array([0., 12., 2., 4.])) vloc_back1 = self.cnet.getVLoc() vloc_back2 = np.zeros(3) self.cnet.addVLocToArr(vloc_back2) assert np.allclose(vloc_back1, vloc) assert np.allclose(vloc_back2, vloc) with pytest.raises(ValueError): self.cnet.setVNodeFromVNode(np.zeros(3)) with pytest.raises(ValueError): self.cnet.addVNodeToArr(np.zeros(3)) with pytest.raises(ValueError): self.cnet.setVNodeFromVLoc(np.zeros(4)) with pytest.raises(ValueError): self.cnet.addVLocToArr(np.zeros(4)) def testSolver(self): self.createTree() netp = self.net_py # test if single AMPA synapse agrees with analytical solution # add synapse self.cnet.addSynapse(1, "AMPA") g_syn = 1. g_list = [np.array([]), np.array([g_syn]), np.array([])] # solve numerically v_loc = self.cnet.solveNewton(g_list) v_node = self.cnet.getVNode() # solve analytically g_rescale = g_syn / (1. + netp[2].z_bar * g_syn) z_0plus1 = netp[0].z_bar + netp[1].z_bar v_0plus1 = z_0plus1 * g_rescale / (1. + z_0plus1 * g_rescale) * \ (0. - self.v_eq) v_2 = netp[2].z_bar * g_rescale * (0. - self.v_eq - v_0plus1) # test if both solutions agree assert np.abs(v_node[0] + v_node[1] - v_0plus1) < 1e-9 assert np.abs(v_node[2] - v_2) < 1e-9 assert np.abs(v_node[3] - 0.0) < 1e-9 assert np.abs(v_loc[0] - self.v_eq - v_0plus1) < 1e-9 assert np.abs(v_loc[1] - self.v_eq - v_0plus1 - v_2) < 1e-9 assert np.abs(v_loc[2] - self.v_eq - v_0plus1) < 1e-9 # test if AMPA and GABA synapses agree with analytical solution # add synapse self.cnet.addSynapse(2, "GABA") g_exc = 1. g_inh = 1. g_list = [np.array([]), np.array([g_exc]), np.array([g_inh])] # solve numerically v_loc = self.cnet.solveNewton(g_list) v_node = self.cnet.getVNode() # solve analytically g_exc_ = g_exc / (1. + netp[2].z_bar * g_exc) g_inh_ = g_inh / (1. + netp[3].z_bar * g_inh) z_0plus1 = netp[0].z_bar + netp[1].z_bar v_0plus1 = z_0plus1 * g_exc_ / (1. + z_0plus1 * (g_exc_ + g_inh_)) * \ (0. - self.v_eq) + \ z_0plus1 * g_inh_ / (1. + z_0plus1 * (g_exc_ + g_inh_)) * \ (-80. - self.v_eq) v_2 = netp[2].z_bar * g_exc_ * (0. - self.v_eq - v_0plus1) v_3 = netp[3].z_bar * g_inh_ * (-80. - self.v_eq - v_0plus1) # test if both solutions agree assert np.abs(v_node[0] + v_node[1] - v_0plus1) < 1e-9 assert np.abs(v_node[2] - v_2) < 1e-9 assert np.abs(v_node[3] - v_3) < 1e-9 assert np.abs(v_loc[0] - self.v_eq - v_0plus1) < 1e-9 assert np.abs(v_loc[1] - self.v_eq - v_0plus1 - v_2) < 1e-9 assert np.abs(v_loc[2] - self.v_eq - v_0plus1 - v_3) < 1e-9 # test if NMDA synapse is solved correctly # check if removing synapse works correctly self.cnet.removeSynapseFromLoc(1, 0) self.cnet.removeSynapseFromLoc(2, 0) with pytest.raises(IndexError): self.cnet.removeSynapseFromLoc(3, 0) with pytest.raises(IndexError): self.cnet.removeSynapseFromLoc(1, 2) # create NMDA synapse self.cnet.addSynapse(1, "NMDA") # solve for low conductance g_syn_low = 1. g_list = [np.array([]), np.array([g_syn_low]), np.array([])] # solve numerically v_loc_low = self.cnet.solveNewton(g_list) v_node_low = self.cnet.getVNode() # solve for high conductance g_syn_high = 4. g_list = [np.array([]), np.array([g_syn_high]), np.array([])] # solve numerically v_loc_high = self.cnet.solveNewton(g_list) v_node_high = self.cnet.getVNode() # solve for moderate conductance g_syn_middle = 2. g_list = [np.array([]), np.array([g_syn_middle]), np.array([])] # solve numerically v_loc_middle_0 = self.cnet.solveNewton(g_list) v_node_middle_0 = self.cnet.getVNode() v_loc_middle_1 = self.cnet.solveNewton(g_list, v_0=np.array([0., 0., 0.]), v_alt=self.v_eq * np.ones(3)) v_node_middle_1 = self.cnet.getVNode() # check if correct z_sum = netp[0].z_bar + netp[1].z_bar + netp[2].z_bar checkfun = lambda vv: (0. - vv) / (1. + 0.3 * np.exp(-.1 * vv)) vv = v_loc_low[1] assert np.abs(vv - self.v_eq - z_sum * g_syn_low * checkfun(vv)) < 1e-3 vv = v_loc_high[1] assert np.abs(vv - self.v_eq - z_sum * g_syn_high * checkfun(vv)) < 1e-3 vv = v_loc_middle_0[1] assert np.abs(vv - self.v_eq - z_sum * g_syn_middle * checkfun(vv)) < 1e-3 vv = v_loc_middle_1[1] assert np.abs(vv - self.v_eq - z_sum * g_syn_middle * checkfun(vv)) < 1e-3 assert np.abs(v_loc_middle_0[1] - v_loc_middle_1[1]) > 10. def testIntegration(self): tmax = 1000. dt = 0.025 self.createTree() # add synapse and check additional synapse functions self.cnet.addSynapse(1, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(1, "AMPA+NMDA", g_max=1., nmda_ratio=5.) assert self.cnet.syn_map_py[0] == { 'loc_index': 1, 'syn_index_at_loc': 0, 'n_syn_at_loc': 1, 'g_max': [dt * 0.1] } assert self.cnet.syn_map_py[1] == { 'loc_index': 1, 'syn_index_at_loc': 1, 'n_syn_at_loc': 2, 'g_max': [1., 5.] } assert self.cnet.n_syn[1] == 3 with pytest.raises(ValueError): self.cnet.addSynapse(1, "NONSENSE") with pytest.raises(IndexError): self.cnet.addSynapse(8, "AMPA") with pytest.raises(TypeError): self.cnet.addSynapse(1, ["NONSENSE LIST"]) # check if synapse is correctly removed self.cnet.removeSynapse(1) assert len(self.cnet.syn_map_py) == 1 # add spike times self.cnet.setSpikeTimes(0, np.arange(dt / 2., tmax, dt)) # run sim res = self.cnet.runSim(tmax, dt, step_skip=1, rec_v_node=True, rec_g_syn_inds=[0]) v_loc_sim = res['v_loc'][:, -1] # solve newton v_loc_newton = self.cnet.solveNewton([res['g_syn'][0][0][-1]]) # compare assert np.allclose(v_loc_sim, v_loc_newton, atol=0.5) # do again with other synapses self.cnet.removeSynapse(0) self.cnet.addSynapse(2, "GABA", g_max=dt * 0.1) self.cnet.addSynapse(1, "AMPA", g_max=dt * 0.1) # add spike times self.cnet.setSpikeTimes(0, np.arange(dt / 2., tmax, dt)) # GABA synapse self.cnet.setSpikeTimes(1, np.arange(dt / 2., tmax, dt)) # AMPA synapse # run sim res = self.cnet.runSim(tmax, dt, step_skip=1, rec_v_node=True, rec_g_syn_inds=[0, 1]) v_loc_sim = res['v_loc'][:, -1] g_newton = [res['g_syn'][ii][0][-1] for ii in [0, 1]] # solve newton v_loc_newton = self.cnet.solveNewton(g_newton) # compare assert np.allclose(v_loc_sim, v_loc_newton, atol=0.5) # add NMDA synapse self.cnet.addSynapse(0, "AMPA+NMDA", g_max=dt * 0.1, nmda_ratio=5.) self.cnet.addSynapse(1, "AMPA+NMDA", g_max=dt * 0.1, nmda_ratio=5.) # set spiketimes for second synapse self.cnet.setSpikeTimes(3, np.arange(dt / 2., tmax, dt)) # AMPA+NMDA synapse # remove first AMPA+NMDA synapse to see if spike times are correctly re-allocated assert len(self.cnet.spike_times_py[2]) == 0 self.cnet.removeSynapse(2) for spk_tm in self.cnet.spike_times_py: assert len(spk_tm) > 0 # run sim res = self.cnet.runSim(tmax, dt, step_skip=1, rec_v_node=True, rec_g_syn_inds=[0, 1, 2]) v_loc_sim = res['v_loc'][:, -1] g_newton = [res['g_syn'][ii][0][-1] for ii in [0, 1, 2]] # solve newton v_loc_newton = self.cnet.solveNewton(g_newton) # compare assert np.allclose(v_loc_sim, v_loc_newton, atol=.5) # test whether sparse storage works ss = 33 # number of timesteps not a multiple of storage step # set spiketimes self.cnet.setSpikeTimes(0, np.array([5.])) self.cnet.setSpikeTimes(1, np.array([10.])) # run sim res1 = self.cnet.runSim(tmax, dt, step_skip=1, rec_v_node=True, rec_g_syn_inds=[0, 1, 2]) # set spiketimes self.cnet.setSpikeTimes(0, np.array([5.])) self.cnet.setSpikeTimes(1, np.array([10.])) # run sim res2 = self.cnet.runSim(tmax, dt, step_skip=ss, rec_v_node=True, rec_g_syn_inds=[0, 1, 2]) # check if results are idendtical assert len(res2['t']) == len(res2['v_loc'][0]) np.allclose(res1['v_loc'][0][ss - 1:][::ss], res2['v_loc'][0]) np.allclose(res1['v_node'][0][ss - 1:][::ss], res2['v_node'][0]) np.allclose(res1['g_syn'][0][0][ss - 1:][::ss], res2['g_syn'][0]) # test whether sparse storage works ss = 20 # number of timesteps a multiple of storage step # set spiketimes self.cnet.setSpikeTimes(0, np.array([5.])) self.cnet.setSpikeTimes(1, np.array([10.])) # run sim res1 = self.cnet.runSim(tmax, dt, step_skip=1, rec_v_node=True, rec_g_syn_inds=[0, 1, 2]) # set spiketimes self.cnet.setSpikeTimes(0, np.array([5.])) self.cnet.setSpikeTimes(1, np.array([10.])) # run sim res2 = self.cnet.runSim(tmax, dt, step_skip=ss, rec_v_node=True, rec_g_syn_inds=[0, 1, 2]) # check if results are idendtical assert len(res2['t']) == len(res2['v_loc'][0]) np.allclose(res1['v_loc'][0][ss - 1:][::ss], res2['v_loc'][0]) np.allclose(res1['v_node'][0][ss - 1:][::ss], res2['v_node'][0]) np.allclose(res1['g_syn'][0][0][ss - 1:][::ss], res2['g_syn'][0]) def testInversion(self): dt = 0.1 # tests without linear terms # test with two non-leafs that integrate soma self.createTree2(add_lin=False) # add synapses self.cnet.addSynapse(0, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(1, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(2, "AMPA", g_max=dt * 0.1) # initialize self.cnet.initialize(dt=dt, mode=1) # construct inputs g_in = self.cnet.recastInput([1., 1., 1.]) self.cnet._constructInput(np.array([self.v_eq, self.v_eq, self.v_eq]), g_in) # recursive matrix inversion self.cnet.invertMatrix() v_node = self.cnet.getVNode() # construct full matrix mat, vec = self.cnet.getMatAndVec(dt=dt) # full matrix inversion v_sol = np.linalg.solve(mat, vec) # test assert np.allclose(v_sol, v_node) # test with two non-leafs that integrate soma self.createTree3(add_lin=False) # add synapses self.cnet.addSynapse(0, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(1, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(2, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(3, "AMPA", g_max=dt * 0.1) # initialize self.cnet.initialize(dt=dt, mode=1) # construct inputs g_in = self.cnet.recastInput(np.ones(4)) self.cnet._constructInput(self.v_eq * np.ones(4), g_in) # recursive matrix inversion self.cnet.invertMatrix() v_node = self.cnet.getVNode() # construct full matrix mat, vec = self.cnet.getMatAndVec(dt=dt) # full matrix inversion v_sol = np.linalg.solve(mat, vec) # test assert np.allclose(v_sol, v_node) # tests with linear terms # test with one non-leafs that integrate soma self.createTree2(add_lin=True) # add synapses self.cnet.addSynapse(0, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(1, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(2, "AMPA", g_max=dt * 0.1) # initialize self.cnet.initialize(dt=dt, mode=1) # construct inputs g_in = self.cnet.recastInput([1., 1., 1.]) self.cnet._constructInput(np.array([self.v_eq, self.v_eq, self.v_eq]), g_in) # recursive matrix inversion self.cnet.invertMatrix() v_node = self.cnet.getVNode() # construct full matrix mat, vec = self.cnet.getMatAndVec(dt=dt) # full matrix inversion v_sol = np.linalg.solve(mat, vec) # test assert np.allclose(v_sol, v_node) # test with two non-leafs that integrate soma self.createTree3(add_lin=True) # add synapses self.cnet.addSynapse(0, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(1, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(2, "AMPA", g_max=dt * 0.1) self.cnet.addSynapse(3, "AMPA", g_max=dt * 0.1) # initialize self.cnet.initialize(dt=dt, mode=1) # construct inputs g_in = self.cnet.recastInput(np.ones(4)) self.cnet._constructInput(self.v_eq * np.ones(4), g_in) # recursive matrix inversion self.cnet.invertMatrix() v_node = self.cnet.getVNode() # construct full matrix mat, vec = self.cnet.getMatAndVec(dt=dt) # full matrix inversion v_sol = np.linalg.solve(mat, vec) # test assert np.allclose(v_sol, v_node) def testChannel(self): self.createPointNeurons() # simulate neuron and NET model res_neuron = self.sim_tree.run(100) res_net = self.cnet.runSim(100., self.dt) # test if traces equal assert np.allclose(res_neuron['v_m'][0, :-1], res_net['v_loc'][0, :], atol=.1)
class TestNeuron(): def loadTTreePassive(self): ''' Load the T-tree morphology in memory with passive conductance 6--5--4--7--8 | | 1 ''' v_eq = -75. self.dt = 0.025 self.tmax = 100. # for frequency derivation self.ft = ke.FourrierTools(np.arange(0., self.tmax, self.dt)) # load the morphology print '>>> loading T-tree <<<' fname = 'test_morphologies/Tsovtree.swc' self.greenstree = GreensTree(fname, types=[1,3,4]) self.greenstree.fitLeakCurrent(e_eq_target=v_eq, tau_m_target=10.) self.greenstree.setCompTree() self.greenstree.setImpedance(self.ft.s) # copy greenstree parameters into NEURON simulation tree self.neurontree = neurm.NeuronSimTree(dt=self.dt, t_calibrate=10., v_eq=v_eq, factor_lambda=25.) self.greenstree.__copy__(self.neurontree) self.neurontree.treetype = 'computational' def loadTTreeActive(self): ''' Load the T-tree morphology in memory with h-current 6--5--4--7--8 | | 1 ''' v_eq = -75. self.dt = 0.025 self.tmax = 100. # for frequency derivation self.ft = ke.FourrierTools(np.arange(0., self.tmax, self.dt)) # load the morphology print '>>> loading T-tree <<<' fname = 'test_morphologies/Tsovtree.swc' self.greenstree = GreensTree(fname, types=[1,3,4]) self.greenstree.addCurrent('h', 50., -43.) self.greenstree.fitLeakCurrent(e_eq_target=v_eq, tau_m_target=10.) # for node in self.greenstree: # print node.getGTot(channel_storage=self.greenstree.channel_storage) # print node.currents self.greenstree.setCompTree() self.greenstree.setImpedance(self.ft.s) # copy greenstree parameters into NEURON simulation tree self.neurontree = neurm.NeuronSimTree(dt=self.dt, t_calibrate=10., v_eq=v_eq, factor_lambda=25.) self.greenstree.__copy__(self.neurontree) self.neurontree.treetype = 'computational' def testPassive(self, pplot=False): self.loadTTreePassive() # set of locations locs = [(1, .5), (4, .5), (4, 1.), (5, .5), (6, .5), (7, .5), (8, .5)] # compute impedance matrix with Green's function zf_mat_gf = self.greenstree.calcImpedanceMatrix(locs) z_mat_gf = zf_mat_gf[self.ft.ind_0s].real # convert impedance matrix to time domain zk_mat_gf = np.zeros((len(self.ft.t), len(locs), len(locs))) for (ii, jj) in itertools.product(range(len(locs)), range(len(locs))): zk_mat_gf[:,ii,jj] = self.ft.FT_inv(zf_mat_gf[:,ii,jj])[1].real * 1e-3 # test the steady state impedance matrix z_mat_neuron = self.neurontree.calcImpedanceMatrix(locs) assert np.allclose(z_mat_gf, z_mat_neuron, atol=1.) # test the temporal matrix tk, zk_mat_neuron = self.neurontree.calcImpedanceKernelMatrix(locs) assert np.allclose(zk_mat_gf[int(2./self.dt):,:,:], zk_mat_neuron[int(2./self.dt):,:,:], atol=.2) if pplot: # plot kernels pl.figure() cc = 0 for ii in range(len(locs)): jj = 0 while jj <= ii: pl.plot(tk, zk_mat_neuron[:,ii,jj], c=colours[cc%len(colours)]) pl.plot(tk, zk_mat_gf[:,ii,jj], ls='--', lw=2, c=colours[cc%len(colours)]) cc += 1 jj += 1 pl.show() def testActive(self, pplot=False): self.loadTTreeActive() # set of locations locs = [(1, .5), (4, .5), (4, 1.), (5, .5), (6, .5), (7, .5), (8, .5)] # compute impedance matrix with Green's function zf_mat_gf = self.greenstree.calcImpedanceMatrix(locs) z_mat_gf = zf_mat_gf[self.ft.ind_0s].real # convert impedance matrix to time domain zk_mat_gf = np.zeros((len(self.ft.t), len(locs), len(locs))) for (ii, jj) in itertools.product(range(len(locs)), range(len(locs))): zk_mat_gf[:,ii,jj] = self.ft.FT_inv(zf_mat_gf[:,ii,jj])[1].real * 1e-3 # test the steady state impedance matrix z_mat_neuron = self.neurontree.calcImpedanceMatrix(locs, t_dur=1300.) print z_mat_gf print z_mat_neuron assert np.allclose(z_mat_gf, z_mat_neuron, atol=5.) # test the temporal matrix tk, zk_mat_neuron = self.neurontree.calcImpedanceKernelMatrix(locs) assert np.allclose(zk_mat_gf[int(2./self.dt):,:,:], zk_mat_neuron[int(2./self.dt):,:,:], atol=.3) if pplot: # plot kernels pl.figure() cc = 0 for ii in range(len(locs)): jj = 0 while jj <= ii: pl.plot(tk, zk_mat_neuron[:,ii,jj], c=colours[cc%len(colours)]) pl.plot(tk, zk_mat_gf[:,ii,jj], ls='--', lw=2, c=colours[cc%len(colours)]) cc += 1 jj += 1 pl.show()