def make_cable(self, L, diam, segname='cable', cm=1, Ra=150, Rm=2800, Vrest=-65., nseg=None): '''make a cable with specified distributed properties (approximate a sphere by setting diam=L= x)''' cable = h.Section(name=segname, cell=self) cable.L = L #micro-m cable.diam = diam # micro-m cable.cm = cm # picofarads/cm^2 cable.Ra = Ra # megaOhms/cm^2 if nseg is None: # use d_lambda rule to get good guess of best number of segments cable.nseg = int( L) #50*(int((L/(0.1*h.lambda_f(100))+.999)/2.)*2 + 1) elif nseg is "d_lambda": cable.nseg = int((L / (0.1 * h.lambda_f(100)) + .999) / 2.) * 2 + 1 else: cable.nseg = nseg cable.insert('pas') cable.g_pas = 1 / Rm # picoSiemens/cm^2 cable.e_pas = Vrest # milliVolts self.segments[segname] = cable
def set_nsegs(self, frequency=1000, d_lambda=0.1): ''' Set the number of segments for section according to the d_lambda rule for a given input frequency''' for sec in self.sec_list: sec.nseg = int( (sec.L / (d_lambda * h.lambda_f(frequency, sec=sec)) + .9) / 2) * 2 + 1
def geom_nseg(section,f=100): """ Python version of the same function as on p.123 of The Neuron Book """ L=section.L h.load_func('lambda_f') nseg=int((L/(0.1*h.lambda_f(f,sec=section))+0.9)/2)*2+1 return nseg
def set_nsegs(self, frequency=1000, d_lambda=0.1): ''' Set the number of segments for section according to the d_lambda rule for a given input frequency Inputs: frequency: [1000]: AC frequency for method 'lambda_f' d_lambda: [0.1]: parameter for d_lambda rule ''' self.total_nseg = 0 for sec in self.sec_list: sec.nseg = int( (sec.L / (d_lambda * h.lambda_f(frequency, sec=sec)) + .999) / 2) * 2 + 1 self.total_nseg += sec.nseg
def _makeSection(self, factorlambda=1., pprint=False): compartment = neuron.h.Section(name=str(self.index)) compartment.push() # create the compartment if self.index == 1: compartment.diam = 2. * self.R # um (NEURON takes diam=2*r) compartment.L = 2. * self.R # um (to get correct surface) compartment.nseg = 1 else: compartment.diam = 2. * self.R # section radius [um] (NEURON takes diam = 2*r) compartment.L = self.L # section length [um] # set number of segments if type(factorlambda) == float: # nseg according to NEURON bookint compartment.nseg = int(( (compartment.L / (0.1 * h.lambda_f(100.)) + 0.9) / 2.) * 2. + 1.) * int(factorlambda) else: compartment.nseg = factorlambda # set parameters compartment.cm = self.c_m # uF/cm^2 compartment.Ra = self.r_a * 1e6 # MOhm*cm --> Ohm*cm # insert membrane currents for key, current in self.currents.items(): if current[0] > 1e-10: compartment.insert(mechname[key]) for seg in compartment: exec('seg.' + mechname[key] + '.g = ' + str(current[0]) + '*1e-6') # uS/cm^2 --> S/cm^2 exec('seg.' + mechname[key] + '.e = ' + str(current[1])) # mV # insert concentration mechanisms for ion, params in self.concmechs.items(): compartment.insert(mechname[ion]) for seg in compartment: for param, value in params.items(): exec('seg.' + mechname[ion] + '.' + param + ' = ' + str(value)) h.pop_section() if pprint: print(self) print(('>>> compartment length = %.2f um' % compartment.L)) print(('>>> compartment diam = %.2f um' % compartment.diam)) print(('>>> compartment nseg = ' + str(compartment.nseg))) return compartment
def create_cell(name, mechparams=None, Ra=None, calc_nseg=False, filename=None): """Make a copy of the GGN and insert mechanisms based on mechparams. mechparams: dict of dicts containing parameters for mechanisms. Each entry should be name: { param: value, param: value, ...} Other than name, the param keys depend on the mechanism definition. For example, the predefined passive mechanism has name `pas` and it defines g and e as parameters. The corresponding dict entry will be `'pas': {'g': 2.5e-4, 'e'=-65.0}` for inserting passive conductance with density 2.5e-4 S/cm2 on each compartment and the reversal potential -65 mV. """ if not hasattr(h, name): if filename is None: raise Exception('Cell not preloaded. Specify template filename') h.xopen(filename) cell = eval('h.{}()'.format(name)) if mechparams is None: mechparams = {} print(mechparams) mech_dict = ephys.create_mechs(mechparams) insert_mechanisms(cell, mech_dict.values()) if (Ra is not None) or calc_nseg: cell.soma.push() ordered_tree = h.SectionList() ordered_tree.wholetree() h.pop_section() if not isinstance(Ra, float): # Assume pint.UnitRegistry().Quantity Ra = ephys.Q_(Ra).to('ohm*cm').m for sec in ordered_tree: sec.push() if Ra is not None: sec.Ra = Ra # lambda_f = np.sqrt(sec.diam/(4 * sec.Ra * sec.g_pas)) # nseg = int(10 * sec.L / lambda_dc + 0.5) nseg = int((sec.L / (0.1 * h.lambda_f(100)) + 0.999) / 2) * 2 + 1 sec.nseg = nseg h.pop_section() return cell
def _make_section(node, index, sections, **kwargs): compartment = neuron.h.Section(name=str(index)) # NEW NRN SECTION # assume three point soma if node.get_index() not in [1, 2, 3]: pPos = node.get_parent_node().get_content()['p3d'] cPos = node.get_content()['p3d'] compartment.push() h.pt3dadd(float(pPos.x), float(pPos.y), float(pPos.z), float(pPos.radius)) h.pt3dadd(float(cPos.x), float(cPos.y), float(cPos.z), float(cPos.radius)) # nseg according to NEURON book compartment.nseg = int(((compartment.L / (0.1 * h.lambda_f(100)) + 0.9) / 2) * 2 + 1) # passive properties compartment.cm = kwargs['cm'] if 'cm' in kwargs else 0.9 compartment.Ra = kwargs['ra'] if 'ra' in kwargs else 200 compartment.insert('pas') compartment.e_pas = kwargs['e_pas'] if 'e_pas' in kwargs else -65 compartment.g_pas = kwargs[ 'g_pas'] if 'g_pas' in kwargs else 1.0 / 25000 h.pop_section() compartment.connect(sections.get(node.get_parent_node().get_index()),\ 1,0) return compartment else: if node.get_index() == 1: # root of SWC tree = soma cPos = node.get_content()['p3d'] compartment.push() compartment.diam = rs #cPos.radius compartment.L = rs #cPos.radius # passive properties compartment.cm = kwargs['cm'] if 'cm' in kwargs else 0.9 compartment.Ra = kwargs['ra'] if 'ra' in kwargs else 200 compartment.insert('pas') compartment.e_pas = kwargs['e_pas'] if 'e_pas' in kwargs else -65 compartment.g_pas = kwargs[ 'g_pas'] if 'g_pas' in kwargs else 1.0 / 25000 h.pop_section() #self._soma = compartment return compartment
def set_nsegs(self): """ Set number of segments per section according to the lambda-rule, or according to maximum length of segments """ d_lambda = 0.1 frequency = 100 for sec in self.allseclist: sec.nseg = int( (sec.L / (d_lambda * h.lambda_f(frequency, sec=sec)) + .9) / 2) * 2 + 1 if self.verbose: print("set nsegs using lambda-rule with frequency %i." % frequency) self.totnsegs = self.calc_totnsegs()
def __init__(self, hocfile, sec_id): """ Arguments: hocfile -- hoc file containing a hoc template with CA3 morphology sec_id -- index of the dendrite section containing the synapse """ h.load_file( hocfile ) mycell = h.CA3PCTopology() self.soma = mycell.soma self.dend = mycell.dend self.allsec = h.SectionList() self.allsec.wholetree(sec = self.soma) for sec in self.allsec: try: get_nseg( mysec = sec) # check if distance is zero! except ZeroDivisionError: print("Duplicate 3D coordinate in "), sec.name() # insert passive properties sec.insert('pas') sec.cm = 1 # in microF/cm**2 sec.Ra = 194 # in Ohms*cm sec.g_pas = 1/164e3 # in Ohms*cm**2 # apply lambda rule (Hines & Carnevale, 2001) AC_length = h.lambda_f(100, sec = sec) sec.nseg = int((sec.L/(0.1*AC_length)+0.999)/2)*2 + 1 # 3 segments for spatial grid of the soma self.soma.nseg = 3 # apply my custom spatial discretization to the dendrite/s # that contains the putative synaptic/s contact/s if sec_id>0: for i in sec_id: synsec = self.dend[i] synsec.nseg = get_nseg(mysec = synsec) else: synsec = self.dend[sec_id] synsec.nseg = get_nseg(mysec = synsec)
def _make_section(node,index,sections,**kwargs) : compartment = neuron.h.Section(name=str(index)) # NEW NRN SECTION # assume three point soma if node.get_index() not in [1,2,3] : pPos = node.get_parent_node().get_content()['p3d'] cPos = node.get_content()['p3d'] compartment.push() h.pt3dadd(float(pPos.x),float(pPos.y),float(pPos.z),float(pPos.radius)) h.pt3dadd(float(cPos.x),float(cPos.y),float(cPos.z),float(cPos.radius)) # nseg according to NEURON book compartment.nseg =int(((compartment.L/(0.1*h.lambda_f(100))+0.9)/2)*2+1) # passive properties compartment.cm = kwargs['cm'] if 'cm' in kwargs else 0.9 compartment.Ra = kwargs['ra'] if 'ra' in kwargs else 200 compartment.insert('pas') compartment.e_pas = kwargs['e_pas'] if 'e_pas' in kwargs else -65 compartment.g_pas = kwargs['g_pas'] if 'g_pas' in kwargs else 1.0/25000 h.pop_section() compartment.connect(sections.get(node.get_parent_node().get_index()),\ 1,0) return compartment else : if node.get_index() == 1 : # root of SWC tree = soma cPos = node.get_content()['p3d'] compartment.push() compartment.diam=rs#cPos.radius compartment.L=rs#cPos.radius # passive properties compartment.cm = kwargs['cm'] if 'cm' in kwargs else 0.9 compartment.Ra = kwargs['ra'] if 'ra' in kwargs else 200 compartment.insert('pas') compartment.e_pas = kwargs['e_pas'] if 'e_pas' in kwargs else -65 compartment.g_pas = kwargs['g_pas'] if 'g_pas' in kwargs else 1.0/25000 h.pop_section() #self._soma = compartment return compartment
def geom_nseg(self): for sec in self.all: sec.nseg = int((sec.L/(0.1*h.lambda_f(100)) + .9)/2.)*2 + 1
def geom_nseg(self): ''' Calculates numder of segments in section ''' for sec in self.all: sec.nseg = int((sec.L / (0.1 * h.lambda_f(100)) + .9) / 2.) * 2 + 1
def load_morphology(self): # load the tree structure that represents the morphology self.tree = btmorph.STree2() self.tree.read_SWC_tree_from_file(self.swc_filename,types=range(10)) if self.min_distance > 0.: # simplify the morphology total = len(self.tree.get_nodes()) removed = [] sys.stdout.write('Simplifying the morphology... ') sys.stdout.flush() simplify_tree(self.tree.root, self.min_distance, (SWC_types['soma'],SWC_types['axon']), removed) sys.stdout.write('removed %d nodes out of %d.\n' % (len(removed),total)) self.simplified_swc_filename = '.'.join(self.swc_filename.split('.')[:-1]) + \ '_simplified_%g_um.swc' % self.min_distance self.tree.write_SWC_tree_to_file(self.simplified_swc_filename) # all the sections, indexed by the corresponding index in the SWC file self.sections = {} # a list of all the sections that make up the soma self.soma = [] # a list of all the sections that make up the axon self.axon = [] # a list of all the sections that make up the basal dendrites self.basal = [] # a list of all the sections that make up the apical dendrites self.apical = [] # parse the tree! for node in self.tree: if node is self.tree.root: continue section = h.Section(name='sec_{0}'.format(node.index)) swc_type = node.content['p3d'].type if swc_type == SWC_types['soma']: section.cm = self.Cm['soma'] section.Ra = self.Ra['soma'] self.soma.append(section) elif swc_type == SWC_types['axon']: section.cm = self.Cm['axon'] section.Ra = self.Ra['axon'] self.axon.append(section) elif swc_type == SWC_types['basal']: section.cm = self.Cm['dend'] section.Ra = self.Ra['dend'] self.basal.append(section) elif swc_type == SWC_types['apical']: section.cm = self.Cm['dend'] section.Ra = self.Ra['dend'] self.apical.append(section) if not node.parent is None: pPos = node.parent.content['p3d'] cPos = node.content['p3d'] c_xyz = cPos.xyz p_xyz = pPos.xyz h.pt3dclear(sec=section) h.pt3dadd(float(p_xyz[0]),float(p_xyz[1]),float(p_xyz[2]),float(pPos.radius),sec=section) h.pt3dadd(float(c_xyz[0]),float(c_xyz[1]),float(c_xyz[2]),float(cPos.radius),sec=section) # nseg according to NEURON book; too high in general... section.nseg = int((section.L/(0.1*h.lambda_f(100))+0.9)/2)*2 + 1 try: section.connect(self.sections[node.parent.index],1,0) except: if not section is self.soma[0]: section.connect(self.soma[0],1,0) self.sections[node.index] = section
def calc_shunt_level_steady(synapses=None, sections=None, g='g'): """ Shunt Level Calculation from Gidon, A., & Segev, I. (2012). Principles Governing the Operation of Synaptic Inhibition in Dendrites. Neuron, 75(2), 330–341. https://doi.org/10.1016/j.neuron.2012.05.015 Method calls 'calcZ(WHERE)' method in 'usefulFns.hoc' to calculate impedance (after accessing relevant section) https://www.neuron.yale.edu/neuron/static/new_doc/analysis/programmatic/impedance.html for each synapse at location i Set origin for calculations to synapse location i (this is a specific synapse on a section) for each location d along sections calculate voltage attenuation (Impedance.ratio(d)) from i to d calculate input resistance (Impedance.input(d)) at d for each location d along sections Set origin for calculations to location d calculate voltage attenuation (Impedance.ratio(i)) from d to i calculate input resistance (Impedance.input(i)) at i calculate shunt level for synapse at location i Symbols according to table in paper X,(Xi) Electrotonic distance (in units of the space constant, l) from origin (to location i); (dimensionless). L Electrotonic length (in units of l) of a dendritic branch; (dimensionless). V Steady membrane potentials, as a deviation from the resting potential; (volt). Ri Input resistance at location i;(U). DRi Change in Ri due to synaptic conductance perturbation; (U). gi Steady synaptic conductance perturbation at location i; (S). SL Shunt level; (0%SL%1; dimensionless). SLi Shunt level DRi / Ri due to activation of single or multiple conductance perturbations; (0%SL%1; dimensionless). Ri,j Transfer resistance between location i and location j;(U). SLi,j Attenuation of SL (SLj/ SLi) for a single conductance perturbation at location i;(0%SLi,j%1; dimensionless). Ai,j Voltage attenuation, Vj/Vi, for current perturbation at location i;(0%Ai,j%1; dimensionless). p Dendritic-to-somatic conductance ratio; (G dendrite/G soma; dimensionless). RN Input resistance at X = 0 for a semi-infinite cable; (U). B Cable boundary condition; (G dendrite/GN; dimensionless) In equations, i = input location and d = other location DRd = Rd - Rd* = (gi x (Ri,d)^2)/(1+ gi x Ri) Equation 4 Ri,d = Rd,i = Ri x Ai,d = Rd x Ad,i Equation 5 SLd = DRd / Rd = [(gi x Ri)/(1 + gi x Ri)] x Ai,d x Ad,i SLi,d = SLd,i = Ai,d x Ad,i :rtype: pd.DataFrame """ # create DataFrame labels = [ ] # list of tuples (synapse label, secname, loc) where loc in range [0:1] for syn in synapses: for sec in sections: labels += [(syn['label'], sec.hname(), seg.x) for seg in sec] index = pd.MultiIndex.from_tuples(labels, names=['synapse', 'section', 'loc']) Adi = settings.Adi Aid = settings.Aid Ri = settings.Ri Rd = settings.Rd gi = settings.gi um = settings.um columns = [um, "distance(id)", "distance(di)", Aid, Adi, Ri, Rd, gi] df = pd.DataFrame(columns=columns, index=index) logger.debug("{:2s} {:13s} {:2s} {:10s} {:2s} {:6s} {}".format( "i", "synapse_label", "x", "section.hname()", "d", "seg.x", "section.x")) for syn_index, syn in enumerate(synapses): if 'object' not in syn or syn['object'] is None: # steady state g_i = syn['g'] i = syn['loc'] synapse_label = syn['label'] else: # transient synapses g_i = getattr(syn['object'], g) i = syn['object'].get_loc() synapse_label = syn['label'] sec_ref = h.SectionRef(sec=syn['sec']) # h.calcZ(sec_ref, i) # for sec_index, sec in enumerate(sections): # for seg_index, seg in enumerate(sec): # logger.debug( # "{:2d} {:13s} {:2d} {:10s} {:2d} {:.5f} {:3.2f}um".format(syn_index, synapse_label, sec_index, # sec.hname(), seg_index, seg.x, # seg.x * sec.L)) # d = seg.x # df.loc[(synapse_label, sec.hname(), d), # ("um", "$g_i$")] = seg.x * sec.L, g_i # distance_id_h = h.distance(d, sec=sec) # # retrieve impedance results # attenuation_id_h = h.zz.ratio(d, sec=sec) # input_resistance_d_h = h.zz.input(d, sec=sec) # df.loc[(synapse_label, sec.hname(), d), # assign column values (below) to row (this line) # ("distance(id)", "$A_{i,d}$", "$R_d$")] = distance_id_h, attenuation_id_h, input_resistance_d_h calc_z(syn['sec'], i) for sec_index, sec in enumerate(sections): for seg_index, seg in enumerate(sec): logger.debug( "{:2d} {:13s} {:2d} {:10s} {:2d} {:.5f} {:3.2f}um".format( syn_index, synapse_label, sec_index, sec.hname(), seg_index, seg.x, seg.x * sec.L)) d = seg.x df.loc[(synapse_label, sec.hname(), d), (um, gi)] = seg.x * sec.L, g_i # distance_id_h, attenuation_id_h, input_resistance_d_h = df.loc[(synapse_label, sec.hname(), d), # ("distance(id)", "$A_{i,d}$", "$R_d$")] distance_id = h.distance(d, sec=sec) # retrieve impedance results attenuation_id = zz.ratio(d, sec=sec) input_resistance_d = zz.input( d, sec=sec) * 1e6 # convert from MOhm to Ohm # assert distance_id_h == distance_id, "{} != {}".format(distance_id_h,distance_id) # assert attenuation_id_h == attenuation_id, "{} != {}".format(attenuation_id_h,attenuation_id) # assert input_resistance_d_h == input_resistance_d, "{} != {}".format(input_resistance_d_h,input_resistance_d) df.loc[(synapse_label, sec.hname(), d), # assign column values (below) to row (this line) ("distance(id)", Aid, Rd)] = distance_id, attenuation_id, input_resistance_d for sec_index, sec in enumerate(sections): sec_ref = h.SectionRef(sec=sec) L = h.lambda_f(h.freq) logger.debug("Space constant L = {}".format(L)) for seg_index, seg in enumerate(sec): logger.debug( "{:2d} {:13s} {:2d} {:10s} {:2d} {:.5f} {:3.2f}um".format( syn_index, synapse_label, sec_index, sec.hname(), seg_index, seg.x, seg.x * sec.L)) d = seg.x # new impedance calculation # h.calcZ(sec_ref, d) # distance_di_h = h.distance(i, sec=syn['sec']) # # retrieve impedance results # attenuation_di_h = h.zz.ratio(i, sec=syn['sec']) # input_resistance_i_h = h.zz.input(i, sec=syn['sec']) calc_z(sec, d) distance_di = h.distance(i, sec=syn['sec']) # retrieve impedance results attenuation_di = zz.ratio(i, sec=syn['sec']) input_resistance_i = zz.input( i, sec=syn['sec']) * 1e6 # convert from MOhm to Ohm df.loc[(synapse_label, sec.hname(), d), ("distance(di)", Adi, Ri)] = distance_di, attenuation_di, input_resistance_i # assert distance_di_h == distance_di, "{} != {}".format(distance_di_h,distance_di) # assert round(attenuation_di_h,5) == round(attenuation_di,5), "{} != {}".format(attenuation_di_h,attenuation_di) # assert input_resistance_i_h == input_resistance_i, "{} != {}".format(input_resistance_i_h,input_resistance_i) # df.loc[(synapse_label, sec.hname(), d), # ("distance(di)", "$A_{d,i}$", "$R_i$")] = distance_di_h, attenuation_di_h, input_resistance_i_h # does a vector/matrix operation so SL is calculated for every d R_i, A_id, A_di, R_d = df.loc[(synapse_label, sec.hname()), (Ri, Aid, Adi, Rd)].values.T df.loc[(synapse_label, sec.hname()), settings.Adi + " alt"] = R_i * A_id / R_d SLd = settings.SLd df.loc[(synapse_label, sec.hname()), SLd] = ((g_i * R_i) / (1 + g_i * R_i)) * A_id * A_di return df
def biophysics( self, Ra=190, cm=0.9, gnabar=0.035, gkbar=0.009, gl=0.0001, vshift=-14.0, #0.0 el=-65.0, egk=-90.0, ): ''' The values for gnabar, gkbar and gl are the default values from the mod file 'hh_wbm from Jonas's 2001/2? paper. I have added vshift to the mod file ''' self.leak_reversal = el for sec in self.sec_list: sec.Ra = 170 sec.cm = 0.9 # run the lamda rule having set Ra and cm frequency = 1000 d_lambda = 0.1 for sec in self.sec_list: sec.nseg = int( (sec.L / (d_lambda * h.lambda_f(frequency, sec=sec)) + .9) / 2) * 2 + 1 # set origin for distance measurement origin = h.distance(0, 0.0, sec=self.root) segment_count = 1 distances_from_root = [] for sec in self.dendrites: for seg in sec: dist = h.distance( seg.x, sec=sec ) # x is the soma(0.5) proerty. location in a section distances_from_root.append(dist) border_threshold = np.max(distances_from_root) if self.verbose: #print 'Biophysics method reporting in: ' #print 'Max dendrite distance from soma = ',np.max(distances_from_root) #print 'Border threshold (1/3 max), set at: ', border_threshold/3 for section in self.sec_list: print(section.nseg, 'segments in ', section.name()) # having calculated distances, insert conductances. for sec in self.dendrites: sec.insert('hh_wbm') for seg in sec: dist = h.distance(seg.x, sec=sec) if dist >= border_threshold: seg.hh_wbm.gnabar = gnabar / 2 seg.hh_wbm.gkbar = gkbar seg.hh_wbm.gl = gl / 10 seg.hh_wbm.el = el seg.hh_wbm.egk = egk seg.hh_wbm.vshift = vshift else: seg.hh_wbm.gnabar = gnabar seg.hh_wbm.gkbar = gkbar seg.hh_wbm.gl = gl seg.hh_wbm.el = el seg.hh_wbm.egk = egk seg.hh_wbm.vshift = vshift segment_count += 1 segment_count = 1 for sec in self.soma: sec.insert('hh_wbm') for seg in sec: seg.hh_wbm.gnabar = gnabar * 5 seg.hh_wbm.gkbar = gkbar seg.hh_wbm.gl = gl seg.hh_wbm.el = el seg.hh_wbm.egk = egk seg.hh_wbm.vshift = vshift
def compute_nseg(self): for sec in h.allsec(): sec.nseg = int((sec.L/(0.1*h.lambda_f(100,sec=sec))+0.9)/2)*2 + 1 if DEBUG: print('%s has %d segments.' % (h.secname(sec=sec),sec.nseg))