def connectUsingSynChan(self, synName, prePath, post_path , weight, threshold, delay ): """ Connect two compartments using SynChan """ postcomp = moose.Compartment(post_path) # We usually try to reuse an existing SynChan - event based SynChans # have an array of weights and delays and can represent multiple # synapses i.e. a new element of the weights and delays array is # created every time a 'synapse' message connects to the SynChan (from # 'event' of spikegen) BUT for a graded synapse with a lookup table # output connected to 'activation' message, not to 'synapse' message, we # make a new synapse everytime ALSO for a saturating synapse i.e. # KinSynChan, we always make a new synapse as KinSynChan is not meant to # represent multiple synapses libsyn = moose.SynChan(self.libraryPath+'/'+synName) gradedchild = utils.get_child_Mstring(libsyn, 'graded') # create a new synapse if libsyn.className == 'KinSynChan' or gradedchild.value == 'True': synNameFull = moose_methods.moosePath(synName , utils.underscorize(prePath) ) synObj = self.makeNewSynapse(synName, postcomp, synNameFull) else: # See debug/bugs for more details. # NOTE: Change the debug/bugs to enable/disable this bug. if bugs.BUG_NetworkML_500: utils.dump("INFO" , "See the code. There might be a bug here" , frame = inspect.currentframe() ) synNameFull = moose_methods.moosePath(synName , utils.underscorize(prePath) ) synObj = self.makeNewSynapse(synName, postcomp, synNameFull) else: # If the above bug is fixed. synNameFull = synName if not moose.exists(post_path+'/'+synNameFull): synObj = self.makeNewSynapse(synName, postcomp, synNameFull) # wrap the synapse in this compartment synPath = moose_methods.moosePath(post_path, synNameFull) syn = moose.SynChan(synPath) gradedchild = utils.get_child_Mstring(syn, 'graded') # weights are set at the end according to whether the synapse is graded # or event-based # connect pre-comp Vm (if graded) OR spikegen/timetable (if event-based) # to the synapse # graded synapse if gradedchild.value=='True': table = moose.Table(syn.path+"/graded_table") # always connect source to input - else 'cannot create message' # error. precomp = moose.Compartment(prePath) self.connectWrapper(precomp, "VmOut", table, "msgInput") # since there is no weight field for a graded synapse # (no 'synapse' message connected), # I set the Gbar to weight*Gbar syn.Gbar = weight * syn.Gbar # Event based synapse else: # synapse could be connected to spikegen at pre-compartment OR a # file! if 'file' not in prePath: precomp = moose.Compartment(prePath) if not moose.exists(prePath+'/IaF_spikegen'): # if spikegen for this synapse doesn't exist in this # compartment, create it spikegens for different synapse_types # can have different thresholds if not moose.exists(prePath+'/'+synName+'_spikegen'): spikegen = moose.SpikeGen(prePath+'/'+synName+'_spikegen') # spikegens for different synapse_types can have different # thresholds spikegen.threshold = threshold # This ensures that spike is generated only on leading edge. spikegen.edgeTriggered = 1 # usually events are raised at every time step that Vm > # Threshold, can set either edgeTriggered as above or # refractT #spikegen.refractT = 0.25e-3 # wrap the spikegen in this compartment spikegen = moose.SpikeGen(prePath+'/'+synName+'_spikegen') else: spikegen = moose.SpikeGen(prePath+'/IaF_spikegen') # connect the spikegen to the synapse note that you need to use # Synapse (auto-created) under SynChan to get/set weights , # addSpike-s etc. can get the Synapse element by # moose.Synapse(syn.path+'/synapse') or syn.synapse Synpase is # an array element, first add to it, to addSpike-s, get/set # weights, etc. syn.numSynapses += 1 m = self.connectSynapse(spikegen, syn) else: # if connected to a file, create a timetable, # put in a field specifying the connected filenumbers to this segment, # and leave it for simulation-time connection ## prePath is 'file[+<glomnum>]_<filenum1>[_<filenum2>...]' i.e. glomnum could be present filesplit = prePath.split('+') if len(filesplit) == 2: glomsplit = filesplit[1].split('_', 1) glomstr = '_'+glomsplit[0] filenums = glomsplit[1] else: glomstr = '' filenums = prePath.split('_', 1)[1] tt_path = postcomp.path+'/'+synNameFull+glomstr+'_tt' if not moose.exists(tt_path): # if timetable for this synapse doesn't exist in this # compartment, create it, and add the field 'fileNumbers' tt = moose.TimeTable(tt_path) tt.addField('fileNumbers') tt.setField('fileNumbers',filenums) # Be careful to connect the timetable only once while # creating it as below: note that you need to use Synapse # (auto-created) under SynChan to get/set weights , # addSpike-s etc. can get the Synapse element by # moose.Synapse(syn.path+'/synapse') or syn.synapse Synpase # is an array element, first add to it, to addSpike-s, # get/set weights, etc. syn.numSynapses += 1 m = self.connectSynapse(spikegen, syn.synapse) else: # if it exists, append file number to the field 'fileNumbers' tt = moose.TimeTable(tt_path) # append filenumbers from # 'file[+<glomnum>]_<filenumber1>[_<filenumber2>...]' filenums = moose_methods.moosePath(tt.getField('fileNumbers') , filenums) tt.setField('fileNumbers', filenums) # syn.Gbar remains the same, but we play with the weight which is a # factor to Gbar The delay and weight can be set only after # connecting a spike event generator. delay and weight are arrays: # multiple event messages can be connected to a single synapse first # argument below is the array index, we connect to the latest # synapse created above But KinSynChan ignores weight of the # synapse, so set the Gbar for it if libsyn.className == 'KinSynChan': syn.Gbar = weight*syn.Gbar else: # note that you need to use Synapse (auto-created) under SynChan # to get/set weights , addSpike-s etc. can get the Synpase # element by moose.Synapse(syn.path+'/synapse') or syn.synapse syn.synapse[-1].weight = weight syn.synapse[-1].delay = delay # seconds
def connectUsingSynChan(self, synName, prePath, post_path, weight, threshold, delay): """ Connect two compartments using SynChan """ postcomp = moose.Compartment(post_path) # We usually try to reuse an existing SynChan - event based SynChans # have an array of weights and delays and can represent multiple # synapses i.e. a new element of the weights and delays array is # created every time a 'synapse' message connects to the SynChan (from # 'event' of spikegen) BUT for a graded synapse with a lookup table # output connected to 'activation' message, not to 'synapse' message, we # make a new synapse everytime ALSO for a saturating synapse i.e. # KinSynChan, we always make a new synapse as KinSynChan is not meant to # represent multiple synapses libsyn = moose.SynChan(self.libraryPath + '/' + synName) gradedchild = utils.get_child_Mstring(libsyn, 'graded') # create a new synapse if libsyn.className == 'KinSynChan' or gradedchild.value == 'True': synNameFull = moose_methods.moosePath(synName, utils.underscorize(prePath)) synObj = self.makeNewSynapse(synName, postcomp, synNameFull) else: # See debug/bugs for more details. # NOTE: Change the debug/bugs to enable/disable this bug. if bugs.BUG_NetworkML_500: utils.dump("INFO", "See the code. There might be a bug here", frame=inspect.currentframe()) synNameFull = moose_methods.moosePath( synName, utils.underscorize(prePath)) synObj = self.makeNewSynapse(synName, postcomp, synNameFull) else: # If the above bug is fixed. synNameFull = synName if not moose.exists(post_path + '/' + synNameFull): synObj = self.makeNewSynapse(synName, postcomp, synNameFull) # wrap the synapse in this compartment synPath = moose_methods.moosePath(post_path, synNameFull) syn = moose.SynChan(synPath) gradedchild = utils.get_child_Mstring(syn, 'graded') # weights are set at the end according to whether the synapse is graded # or event-based # connect pre-comp Vm (if graded) OR spikegen/timetable (if event-based) # to the synapse # graded synapse if gradedchild.value == 'True': table = moose.Table(syn.path + "/graded_table") # always connect source to input - else 'cannot create message' # error. precomp = moose.Compartment(prePath) self.connectWrapper(precomp, "VmOut", table, "msgInput") # since there is no weight field for a graded synapse # (no 'synapse' message connected), # I set the Gbar to weight*Gbar syn.Gbar = weight * syn.Gbar # Event based synapse else: # synapse could be connected to spikegen at pre-compartment OR a # file! if 'file' not in prePath: precomp = moose.Compartment(prePath) if not moose.exists(prePath + '/IaF_spikegen'): # if spikegen for this synapse doesn't exist in this # compartment, create it spikegens for different synapse_types # can have different thresholds if not moose.exists(prePath + '/' + synName + '_spikegen'): spikegen = moose.SpikeGen(prePath + '/' + synName + '_spikegen') # spikegens for different synapse_types can have different # thresholds spikegen.threshold = threshold # This ensures that spike is generated only on leading edge. spikegen.edgeTriggered = 1 # usually events are raised at every time step that Vm > # Threshold, can set either edgeTriggered as above or # refractT #spikegen.refractT = 0.25e-3 # wrap the spikegen in this compartment spikegen = moose.SpikeGen(prePath + '/' + synName + '_spikegen') else: spikegen = moose.SpikeGen(prePath + '/IaF_spikegen') # connect the spikegen to the synapse note that you need to use # Synapse (auto-created) under SynChan to get/set weights , # addSpike-s etc. can get the Synapse element by # moose.Synapse(syn.path+'/synapse') or syn.synapse Synpase is # an array element, first add to it, to addSpike-s, get/set # weights, etc. syn.numSynapses += 1 m = self.connectSynapse(spikegen, syn) else: # if connected to a file, create a timetable, # put in a field specifying the connected filenumbers to this segment, # and leave it for simulation-time connection ## prePath is 'file[+<glomnum>]_<filenum1>[_<filenum2>...]' i.e. glomnum could be present filesplit = prePath.split('+') if len(filesplit) == 2: glomsplit = filesplit[1].split('_', 1) glomstr = '_' + glomsplit[0] filenums = glomsplit[1] else: glomstr = '' filenums = prePath.split('_', 1)[1] tt_path = postcomp.path + '/' + synNameFull + glomstr + '_tt' if not moose.exists(tt_path): # if timetable for this synapse doesn't exist in this # compartment, create it, and add the field 'fileNumbers' tt = moose.TimeTable(tt_path) tt.addField('fileNumbers') tt.setField('fileNumbers', filenums) # Be careful to connect the timetable only once while # creating it as below: note that you need to use Synapse # (auto-created) under SynChan to get/set weights , # addSpike-s etc. can get the Synapse element by # moose.Synapse(syn.path+'/synapse') or syn.synapse Synpase # is an array element, first add to it, to addSpike-s, # get/set weights, etc. syn.numSynapses += 1 m = self.connectSynapse(spikegen, syn.synapse) else: # if it exists, append file number to the field 'fileNumbers' tt = moose.TimeTable(tt_path) # append filenumbers from # 'file[+<glomnum>]_<filenumber1>[_<filenumber2>...]' filenums = moose_methods.moosePath( tt.getField('fileNumbers'), filenums) tt.setField('fileNumbers', filenums) # syn.Gbar remains the same, but we play with the weight which is a # factor to Gbar The delay and weight can be set only after # connecting a spike event generator. delay and weight are arrays: # multiple event messages can be connected to a single synapse first # argument below is the array index, we connect to the latest # synapse created above But KinSynChan ignores weight of the # synapse, so set the Gbar for it if libsyn.className == 'KinSynChan': syn.Gbar = weight * syn.Gbar else: # note that you need to use Synapse (auto-created) under SynChan # to get/set weights , addSpike-s etc. can get the Synpase # element by moose.Synapse(syn.path+'/synapse') or syn.synapse syn.synapse[-1].weight = weight syn.synapse[-1].delay = delay # seconds
def addSegment(self, cellName, segnum, segment): """ Adding segment to cell. """ run_dia = 0.0 running_comp = None running_dia_nums = 0 segmentname = segment.attrib['name'] debug.printDebug("DEBUG" , "Adding segment {} in cell {}".format(segmentname, cellName) ) # cable is an optional attribute. WARNING: Here I assume it is always # present. cableid = segment.attrib['cable'] segmentid = segment.attrib['id'] # Old cableid still running, hence don't start a new compartment, skip # to next segment. if cableid == self.running_cableid: self.cellDictBySegmentId[cellName][1][segmentid] = running_comp proximal = segment.find('./{'+self.mml+'}proximal') if proximal is not None: run_dia += float(proximal.attrib["diameter"])*self.length_factor running_dia_nums += 1 distal = segment.find('./{'+self.mml+'}distal') if distal is not None: run_dia += float(distal.attrib["diameter"])*self.length_factor running_dia_nums += 1 # new cableid starts, hence start a new compartment; also finish # previous / last compartment. else: # Create a new compartment, the moose "hsolve" method assumes # compartments to be asymmetric compartments and symmetrizes them # but that is not what we want when translating from Neuron # which has only symcompartments -- so be careful! # just segmentname is NOT unique - eg: mitral bbmit exported from # NEURON. mooseCompname = moose_methods.moosePath(segmentname, segmentid) mooseComppath = self.mooseCell.path + '/' + mooseCompname mooseComp = moose.Compartment(mooseComppath) self.cellDictBySegmentId[cellName][1][segmentid] = mooseComp # Cables are grouped and densities set for cablegroups. Hence I # need to refer to segment according to which cable they belong # to.. self.cellDictByCableId[cellName][1][cableid] = mooseComp self.running_cableid = cableid running_segid = segmentid running_comp = mooseComp run_dia = 0.0 running_dia_nums = 0 if 'parent' in segment.attrib: # I assume the parent is created before the child so that I can # immediately # connect the child. parentid = segment.attrib['parent'] parent = self.cellDictBySegmentId[cellName][1][parentid] # It is always assumed that axial of parent is connected to # raxial of moosesegment THIS IS WHAT GENESIS readcell() # DOES!!! UNLIKE NEURON! THIS IS IRRESPECTIVE OF WHETHER # PROXIMAL x,y,z OF PARENT = PROXIMAL x,y,z OF CHILD. THIS IS # ALSO IRRESPECTIVE OF fraction_along_parent SPECIFIED IN # CABLE! THUS THERE WILL BE NUMERICAL DIFFERENCES BETWEEN # MOOSE/GENESIS and NEURON. moosesegment sends Ra and Vm to # parent, parent sends only Vm actually for symmetric # compartment, both parent and moosesegment require each # other's Ra/2, but axial and raxial just serve to distinguish # ends. moose.connect(parent, 'axial', mooseComp, 'raxial') else: parent = None proximal = segment.find('./{'+self.mml+'}proximal') if proximal is None: # If proximal tag is not present, then parent attribute MUST be # present in the segment tag! if proximal is not present, then # by default the distal end of the parent is the proximal end # of the child mooseComp.x0 = parent.x mooseComp.y0 = parent.y mooseComp.z0 = parent.z else: mooseComp.x0 = float(proximal.attrib["x"])*self.length_factor mooseComp.y0 = float(proximal.attrib["y"])*self.length_factor mooseComp.z0 = float(proximal.attrib["z"])*self.length_factor run_dia += float(proximal.attrib["diameter"])*self.length_factor running_dia_nums += 1 distal = segment.find('./{'+self.mml+'}distal') if distal is not None: run_dia += float(distal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 # finished creating new compartment Update the end position, # diameter and length, and segDict of this comp/cable/section with # each segment that is part of this cable (assumes contiguous # segments in xml). This ensures that we don't have to do any # 'closing ceremonies', if a new cable is encoutered in next # iteration. if distal is not None: running_comp.x = float(distal.attrib["x"])*self.length_factor running_comp.y = float(distal.attrib["y"])*self.length_factor running_comp.z = float(distal.attrib["z"])*self.length_factor # Set the compartment diameter as the average diameter of all the # segments in this section running_comp.diameter = run_dia / float(running_dia_nums) # Set the compartment length running_comp.length = math.sqrt( (running_comp.x-running_comp.x0)**2+\ (running_comp.y-running_comp.y0)**2+\ (running_comp.z-running_comp.z0)**2 ) # NeuroML specs say that if (x0,y0,z0)=(x,y,z), then round # compartment e.g. soma. In Moose set length = dia to give same # surface area as sphere of dia. if running_comp.length == 0.0: running_comp.length = running_comp.diameter # Set the segDict the empty list at the end below will get # populated with the potential synapses on this segment, in # function set_compartment_param(..) self.segDict[running_segid] = [ running_comp.name , (running_comp.x0 , running_comp.y0 , running_comp.z0) , (running_comp.x,running_comp.y,running_comp.z) , running_comp.diameter , running_comp.length , [] ] if neuroml_utils.neuroml_debug: debug.printDebug( "STEP" , "Set up compartment/section %s" % running_comp.name )
def addSegment(self, cellName, segnum, segment): """ Adding segment to cell. """ run_dia = 0.0 running_comp = None running_dia_nums = 0 segmentname = segment.attrib['name'] debug.printDebug( "DEBUG", "Adding segment {} in cell {}".format(segmentname, cellName)) # cable is an optional attribute. WARNING: Here I assume it is always # present. cableid = segment.attrib['cable'] segmentid = segment.attrib['id'] # Old cableid still running, hence don't start a new compartment, skip # to next segment. if cableid == self.running_cableid: self.cellDictBySegmentId[cellName][1][segmentid] = running_comp proximal = segment.find('./{' + self.mml + '}proximal') if proximal is not None: run_dia += float( proximal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 distal = segment.find('./{' + self.mml + '}distal') if distal is not None: run_dia += float( distal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 # new cableid starts, hence start a new compartment; also finish # previous / last compartment. else: # Create a new compartment, the moose "hsolve" method assumes # compartments to be asymmetric compartments and symmetrizes them # but that is not what we want when translating from Neuron # which has only symcompartments -- so be careful! # just segmentname is NOT unique - eg: mitral bbmit exported from # NEURON. mooseCompname = moose_methods.moosePath(segmentname, segmentid) mooseComppath = self.mooseCell.path + '/' + mooseCompname mooseComp = moose.Compartment(mooseComppath) self.cellDictBySegmentId[cellName][1][segmentid] = mooseComp # Cables are grouped and densities set for cablegroups. Hence I # need to refer to segment according to which cable they belong # to.. self.cellDictByCableId[cellName][1][cableid] = mooseComp self.running_cableid = cableid running_segid = segmentid running_comp = mooseComp run_dia = 0.0 running_dia_nums = 0 if 'parent' in segment.attrib: # I assume the parent is created before the child so that I can # immediately # connect the child. parentid = segment.attrib['parent'] parent = self.cellDictBySegmentId[cellName][1][parentid] # It is always assumed that axial of parent is connected to # raxial of moosesegment THIS IS WHAT GENESIS readcell() # DOES!!! UNLIKE NEURON! THIS IS IRRESPECTIVE OF WHETHER # PROXIMAL x,y,z OF PARENT = PROXIMAL x,y,z OF CHILD. THIS IS # ALSO IRRESPECTIVE OF fraction_along_parent SPECIFIED IN # CABLE! THUS THERE WILL BE NUMERICAL DIFFERENCES BETWEEN # MOOSE/GENESIS and NEURON. moosesegment sends Ra and Vm to # parent, parent sends only Vm actually for symmetric # compartment, both parent and moosesegment require each # other's Ra/2, but axial and raxial just serve to distinguish # ends. moose.connect(parent, 'axial', mooseComp, 'raxial') else: parent = None proximal = segment.find('./{' + self.mml + '}proximal') if proximal is None: # If proximal tag is not present, then parent attribute MUST be # present in the segment tag! if proximal is not present, then # by default the distal end of the parent is the proximal end # of the child mooseComp.x0 = parent.x mooseComp.y0 = parent.y mooseComp.z0 = parent.z else: mooseComp.x0 = float(proximal.attrib["x"]) * self.length_factor mooseComp.y0 = float(proximal.attrib["y"]) * self.length_factor mooseComp.z0 = float(proximal.attrib["z"]) * self.length_factor run_dia += float( proximal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 distal = segment.find('./{' + self.mml + '}distal') if distal is not None: run_dia += float( distal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 # finished creating new compartment Update the end position, # diameter and length, and segDict of this comp/cable/section with # each segment that is part of this cable (assumes contiguous # segments in xml). This ensures that we don't have to do any # 'closing ceremonies', if a new cable is encoutered in next # iteration. if distal is not None: running_comp.x = float(distal.attrib["x"]) * self.length_factor running_comp.y = float(distal.attrib["y"]) * self.length_factor running_comp.z = float(distal.attrib["z"]) * self.length_factor # Set the compartment diameter as the average diameter of all the # segments in this section running_comp.diameter = run_dia / float(running_dia_nums) # Set the compartment length running_comp.length = math.sqrt( (running_comp.x-running_comp.x0)**2+\ (running_comp.y-running_comp.y0)**2+\ (running_comp.z-running_comp.z0)**2 ) # NeuroML specs say that if (x0,y0,z0)=(x,y,z), then round # compartment e.g. soma. In Moose set length = dia to give same # surface area as sphere of dia. if running_comp.length == 0.0: running_comp.length = running_comp.diameter # Set the segDict the empty list at the end below will get # populated with the potential synapses on this segment, in # function set_compartment_param(..) self.segDict[running_segid] = [ running_comp.name, (running_comp.x0, running_comp.y0, running_comp.z0), (running_comp.x, running_comp.y, running_comp.z), running_comp.diameter, running_comp.length, [] ] if neuroml_utils.neuroml_debug: debug.printDebug( "STEP", "Set up compartment/section %s" % running_comp.name)