def make_new_synapse(syn_name, postcomp, syn_name_full, nml_params): ## if channel does not exist in library load it from xml file if not moose.exists("/library/" + syn_name): cmlR = ChannelML(nml_params) model_filename = syn_name + ".xml" model_path = utils.find_first_file(model_filename, nml_params["model_dir"]) if model_path is not None: cmlR.readChannelMLFromFile(model_path) else: raise IOError( "For mechanism {0}: files {1} not found under {2}.".format( mechanismname, model_filename, self.model_dir ) ) ## deep copies the library SynChan and SynHandler ## to instances under postcomp named as <arg3> synid = moose.copy(moose.element("/library/" + syn_name), postcomp, syn_name_full) # synhandlerid = moose.copy(moose.element('/library/'+syn_name+'/handler'), postcomp,syn_name_full+'/handler') This line was a bug: double handler synhandler = moose.element(synid.path + "/handler") syn = moose.SynChan(synid) synhandler = moose.element(synid.path + "/handler") # returns SimpleSynHandler or STDPSynHandler ## connect the SimpleSynHandler or the STDPSynHandler to the SynChan (double exp) moose.connect(synhandler, "activationOut", syn, "activation") # mgblock connections if required childmgblock = moose_utils.get_child_Mstring(syn, "mgblockStr") #### connect the post compartment to the synapse if childmgblock.value == "True": # If NMDA synapse based on mgblock, connect to mgblock mgblock = moose.Mg_block(syn.path + "/mgblock") moose.connect(postcomp, "channel", mgblock, "channel") else: # if SynChan or even NMDAChan, connect normally moose.connect(postcomp, "channel", syn, "channel")
def make_new_synapse(syn_name, postcomp, syn_name_full, nml_params): ## if channel does not exist in library load it from xml file if not moose.exists('/library/' + syn_name): cmlR = ChannelML(nml_params) model_filename = syn_name + '.xml' model_path = utils.find_first_file(model_filename, nml_params['model_dir']) if model_path is not None: cmlR.readChannelMLFromFile(model_path) else: raise IOError( 'For mechanism {0}: files {1} not found under {2}.'.format( syn_name, model_filename, nml_params['model_dir'])) ## deep copies the library SynChan and SynHandler ## to instances under postcomp named as <arg3> synid = moose.copy(moose.element('/library/' + syn_name), postcomp, syn_name_full) #synhandlerid = moose.copy(moose.element('/library/'+syn_name+'/handler'), postcomp,syn_name_full+'/handler') This line was a bug: double handler synhandler = moose.element(synid.path + '/handler') syn = moose.SynChan(synid) synhandler = moose.element( synid.path + '/handler') # returns SimpleSynHandler or STDPSynHandler ## connect the SimpleSynHandler or the STDPSynHandler to the SynChan (double exp) moose.connect(synhandler, 'activationOut', syn, 'activation') # mgblock connections if required childmgblock = mu.get_child_Mstring(syn, 'mgblockStr') #### connect the post compartment to the synapse if childmgblock.value == 'True': # If NMDA synapse based on mgblock, connect to mgblock mgblock = moose.Mg_block(syn.path + '/mgblock') moose.connect(postcomp, "channel", mgblock, "channel") else: # if SynChan or even NMDAChan, connect normally moose.connect(postcomp, "channel", syn, "channel")
def makeNewSynapse(self, synName, postcomp, synNameFull): '''This function creates a new synapses onto postcomp. SpikeGen is spikeGenerator (presynaptic). SpikeGen connects to SynChan, a synaptic channel which connects to post-synaptic compartment. SpikeGen models the pre-synaptic events. ''' synPath = "%s/%s" % (self.libraryPath, synName) utils.dump("SYNAPSE" , "Creating {} with path {} onto compartment {}".format( synName , synPath , postcomp.path ) ) # if channel does not exist in library load it from xml file if not moose.exists(synPath): utils.dump("SYNAPSE" , "Synaptic Channel {} does not exists. {}".format( synPath, "Loading is from XML file" ) ) cmlR = ChannelML.ChannelML(self.nml_params) cmlR.readChannelMLFromFile(synName+'.xml') # deep copies the library synapse to an instance under postcomp named as # <arg3> if config.disbleCopyingOfObject: utils.dump("WARN" , "Copying existing SynChan ({}) to {}".format( synPath , postcomp ) ) synid = moose.copy(moose.Neutral(synPath), postcomp, synNameFull) else: synid = synPath syn = moose.SynChan(synid) syn = self.configureSynChan(syn, synParams={}) childmgblock = utils.get_child_Mstring(syn,'mgblock') # connect the post compartment to the synapse # If NMDA synapse based on mgblock, connect to mgblock if childmgblock.value == 'True': mgblock = moose.Mg_block(syn.path+'/mgblock') self.connectWrapper(postcomp, "channel", mgblock, "channel") # if SynChan or even NMDAChan, connect normally else: self.connectWrapper(postcomp,"channel", syn, "channel")
def make_new_synapse(self, syn_name, postcomp, syn_name_full): ## if channel does not exist in library load it from xml file if not moose.exists('/library/'+syn_name): cmlR = ChannelML(self.nml_params) cmlR.readChannelMLFromFile(syn_name+'.xml') ## deep copies the library synapse to an instance under postcomp named as <arg3> synid = moose.copy(moose.Neutral('/library/'+syn_name),postcomp,syn_name_full) syn = moose.SynChan(synid) childmgblock = utils.get_child_Mstring(syn,'mgblock') #### connect the post compartment to the synapse if childmgblock.value=='True': # If NMDA synapse based on mgblock, connect to mgblock mgblock = moose.Mg_block(syn.path+'/mgblock') moose.connect(postcomp,"channel", mgblock, "channel") else: # if SynChan or even NMDAChan, connect normally moose.connect(postcomp,"channel", syn, "channel")
def makeNewSynapse(self, synName, postcomp, synNameFull): '''This function creates a new synapses onto postcomp. SpikeGen is spikeGenerator (presynaptic). SpikeGen connects to SynChan, a synaptic channel which connects to post-synaptic compartment. SpikeGen models the pre-synaptic events. ''' synPath = "%s/%s" % (self.libraryPath, synName) utils.dump( "SYNAPSE", "Creating {} with path {} onto compartment {}".format( synName, synPath, postcomp.path)) # if channel does not exist in library load it from xml file if not moose.exists(synPath): utils.dump( "SYNAPSE", "Synaptic Channel {} does not exists. {}".format( synPath, "Loading is from XML file")) cmlR = ChannelML.ChannelML(self.nml_params) cmlR.readChannelMLFromFile(synName + '.xml') # deep copies the library synapse to an instance under postcomp named as # <arg3> if config.disbleCopyingOfObject: utils.dump( "WARN", "Copying existing SynChan ({}) to {}".format( synPath, postcomp)) synid = moose.copy(moose.Neutral(synPath), postcomp, synNameFull) else: synid = synPath syn = moose.SynChan(synid) syn = self.configureSynChan(syn, synParams={}) childmgblock = utils.get_child_Mstring(syn, 'mgblock') # connect the post compartment to the synapse # If NMDA synapse based on mgblock, connect to mgblock if childmgblock.value == 'True': mgblock = moose.Mg_block(syn.path + '/mgblock') self.connectWrapper(postcomp, "channel", mgblock, "channel") # if SynChan or even NMDAChan, connect normally else: self.connectWrapper(postcomp, "channel", syn, "channel")
def set_compartment_param(self, compartment, name, value, mechanismname): """ Set the param for the compartment depending on name and mechanismname. """ if name == 'CM': compartment.Cm = value*math.pi*compartment.diameter*compartment.length elif name == 'RM': compartment.Rm = value/(math.pi*compartment.diameter*compartment.length) elif name == 'RA': compartment.Ra = value*compartment.length/(math.pi*(compartment.diameter/2.0)**2) elif name == 'Em': compartment.Em = value elif name == 'initVm': compartment.initVm = value elif name == 'inject': # this reader converts to SI _logger.info("Comparment %s inject %s A." % (compartment.name, value)) compartment.inject = value elif name == 'v_reset': compartment.vReset = value # compartment is a moose.LIF instance (intfire) elif name == 'threshold': compartment.thresh = value # compartment is a moose.LIF instance (intfire) elif name == 't_refrac': compartment.refractoryPeriod = value # compartment is a moose.LIF instance (intfire) elif name == 'g_refrac': _logger.info("SORRY, current moose.LIF doesn't support g_refrac.") elif mechanismname is 'synapse': # synapse being added to the compartment ## these are potential locations, we do not actually make synapses, ## unless the user has explicitly asked for it if self.createPotentialSynapses: syn_name = value if not moose.exists(compartment.path+'/'+syn_name): make_new_synapse(syn_name, compartment, syn_name, self.nml_params) ## I assume below that compartment name has _segid at its end segid = compartment.name.split('_')[-1] # get segment id from compartment name self.segDict[segid][5].append(value) elif mechanismname is 'spikegen': # spikegen being added to the compartment ## these are potential locations, we do not actually make the spikegens. ## spikegens for different synapses can have different thresholds, ## hence include synapse_type in its name ## value contains name of synapse i.e. synapse_type #spikegen = moose.SpikeGen(compartment.path+'/'+value+'_spikegen') #moose.connect(compartment,"VmSrc",spikegen,"Vm") pass ## previous were mechanism that don't need a ChannelML definition ## including integrate_and_fire (I ignore the ChannelML definition) ## thus integrate_and_fire mechanism default values cannot be used ## i.e. nothing needed in /library, but below mechanisms need. elif mechanismname is not None: ## if mechanism is not present in compartment, deep copy from library ## all mechanisms have been loaded into the library earlier if not moose.exists(compartment.path+'/'+mechanismname): neutralObj = moose.element("/library/"+mechanismname) # gives error if not present if 'CaConc' == neutralObj.className: # Ion concentration pool libcaconc = moose.CaConc("/library/"+mechanismname) ## deep copies the library caconc under the compartment caconc = moose.copy(libcaconc,compartment,mechanismname) caconc = moose.CaConc(caconc) ## CaConc connections are made later using connect_CaConc() ## Later, when calling connect_CaConc, ## B is set for caconc based on thickness of Ca shell and compartment l and dia ## OR based on the Mstring phi under CaConc path. channel = None elif 'HHChannel2D' == neutralObj.className : ## HHChannel2D libchannel = moose.HHChannel2D("/library/"+mechanismname) ## deep copies the library channel under the compartment channel = moose.copy(libchannel,compartment,mechanismname) channel = moose.HHChannel2D(channel) moose.connect(channel,'channel',compartment,'channel') elif 'HHChannel' == neutralObj.className : ## HHChannel libchannel = moose.HHChannel("/library/"+mechanismname) ## deep copies the library channel under the compartment channel = moose.copy(libchannel,compartment,mechanismname) channel = moose.HHChannel(channel) moose.connect(channel,'channel',compartment,'channel') ## if mechanism is present in compartment, just wrap it else: neutralObj = moose.element(compartment.path+'/'+mechanismname) if 'CaConc' == neutralObj.className: # Ion concentration pool caconc = moose.CaConc(compartment.path+'/'+mechanismname) # wraps existing channel channel = None elif 'HHChannel2D' == neutralObj.className : ## HHChannel2D channel = moose.HHChannel2D(compartment.path+'/'+mechanismname) # wraps existing channel elif 'HHChannel' == neutralObj.className : ## HHChannel channel = moose.HHChannel(compartment.path+'/'+mechanismname) # wraps existing channel if name == 'Gbar': if channel is None: # if CaConc, neuroConstruct uses gbar for thickness or phi ## If child Mstring 'phi' is present, set gbar as phi ## BUT, value has been multiplied by Gfactor as a Gbar, ## SI or physiological not known here, ## ignoring Gbar for CaConc, instead of passing units here child = moose_utils.get_child_Mstring(caconc,'phi') if child is not None: #child.value = value pass else: #caconc.thick = value pass else: # if ion channel, usual Gbar channel.Gbar = value*math.pi*compartment.diameter*compartment.length elif name == 'Ek': channel.Ek = value elif name == 'thick': # thick seems to be NEURON's extension to NeuroML level 2. caconc.thick = value ## JUST THIS WILL NOT DO - HAVE TO SET B based on this thick! ## Later, when calling connect_CaConc, ## B is set for caconc based on thickness of Ca shell and compartment l and dia. ## OR based on the Mstring phi under CaConc path. if neuroml_utils.neuroml_debug: _logger.info("Setting %s for comparment %s to %s" % (name, compartment.path, value))
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 connect(self, syn_name, pre_path, post_path, weight, threshold, delay): postcomp = moose.Compartment(post_path) ## We usually try to reuse an existing SynChan & SynHandler - ## event based SynHandlers have an array of weights and delays and can represent multiple synapses, ## so a new element of the weights and delays array is created ## every time a 'synapse' message connects to the SynHandler (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('/library/' + syn_name) gradedchild = utils.get_child_Mstring(libsyn, 'graded') if libsyn.className == 'KinSynChan' or gradedchild.value == 'True': # create a new synapse syn_name_full = syn_name + '_' + utils.underscorize(pre_path) make_new_synapse(syn_name, postcomp, syn_name_full, self.nml_params) else: ## if syn doesn't exist in this compartment, create it syn_name_full = syn_name if not moose.exists(post_path + '/' + syn_name_full): make_new_synapse(syn_name, postcomp, syn_name_full, self.nml_params) ## moose.element is a function that checks if path exists, ## and returns the correct object, here SynChan syn = moose.element( post_path + '/' + syn_name_full) # wrap the SynChan in this compartment synhandler = moose.element(post_path + '/' + syn_name_full + '/handler') # wrap the SynHandler gradedchild = utils.get_child_Mstring(syn, 'graded') #### weights are set at the end according to whether the synapse is graded or event-based #### If graded, connect pre-comp Vm to the table which is connected to SynChan's activation #### If event-based, connect spikegen/timetable's spikeOut to Simple/STDP SynHandler's addSpike ## I rely on second term below not being evaluated if first term is None; ## otherwise None.value gives error. if gradedchild is not None and gradedchild.value == 'True': # graded synapse interpol = moose.element(syn.path + "/graded_table") #### always connect source to input - else 'cannot create message' error. precomp = moose.Compartment(pre_path) moose.connect(precomp, "VmOut", interpol, "input") try: tau_table = moose.element(syn.path + '/tau_table') tau_table_present = True except ValueError: tau_table_present = False # if tau_table is not found, don't connect it if tau_table_present: moose.connect(precomp, 'VmOut', tau_table, 'input') ## 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 else: # Event based synapse ## synapse could be connected to either spikegen at pre-compartment OR to a file! if 'file' not in pre_path: ## element() can return either Compartment() or IzhikevichNrn(), ## since it queries and wraps the actual object precomp = moose.element(pre_path) ## if spikegen for this synapse doesn't exist in this compartment, create it ## spikegens for different synapse_types can have different thresholds ## but an integrate and fire spikegen supercedes all other spikegens if 'IF' in precomp.className: # intfire LIF spikegen = precomp # LIF has a spikeOut message else: if not moose.exists(pre_path + '/' + syn_name + '_spikegen'): ## create new spikegen spikegen = moose.SpikeGen(pre_path + '/' + syn_name + '_spikegen') ## connect the compartment Vm to the spikegen moose.connect(precomp, "VmOut", spikegen, "Vm") ## spikegens for different synapse_types can have different thresholds spikegen.threshold = threshold spikegen.edgeTriggered = 1 # This ensures that spike is generated only on leading edge. ## 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 existing or newly created spikegen in this compartment spikegen = moose.SpikeGen(pre_path + '/' + syn_name + '_spikegen') ## connect the spikegen to the SynHandler ## note that you need to use Synapse (auto-created) under SynHandler ## to get/set weights , addSpike-s etc. ## wrap Synapse element by moose.Synapse(synhandler.path+'/synapse') or synhandler.synapse ## Synpase is an array element, first add to it, to addSpike-s, get/set weights, etc. synhandler.numSynapses += 1 ## see Demos/snippets/synapse.py for an example of ## how to connect multiple SpikeGens to the same SynChan m = moose.connect(spikegen, 'spikeOut', synhandler.synapse[-1], 'addSpike', 'Single') 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 ## pre_path is 'file[+<glomnum>]_<filenum1>[_<filenum2>...]' i.e. glomnum could be present ## hack for my (Aditya's) OB model to use files in NeuroML, should not affect others filesplit = pre_path.split('+') if len(filesplit) == 2: glomsplit = filesplit[1].split('_', 1) glomstr = '_' + glomsplit[0] filenums = glomsplit[1] else: glomstr = '' filenums = pre_path.split('_', 1)[1] tt_path = postcomp.path + '/' + syn_name_full + 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_filenums = moose.Mstring(tt_path + '/fileNumbers') tt_filenums.value = 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. ## wrap Synapse element by moose.Synapse(synhandler.path+'/synapse') or synhandler.synapse ## Synpase is an array element, first add to it, to addSpike-s, get/set weights, etc. synhandler.numSynapses += 1 m = moose.connect(tt, "eventOut", synhandler.synapse[-1], "addSpike", "Single") else: ## if it exists, append file number to the field 'fileNumbers' ## append filenumbers from 'file[+<glomnum>]_<filenumber1>[_<filenumber2>...]' tt_filenums = moose.Mstring(tt_path + '/fileNumbers') tt_filenums.value += '_' + 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 SynHandler ## to get/set weights , addSpike-s etc. ## wrap Synpase element by moose.Synapse(synhandler.path+'/synapse') or synhandler.synapse synhandler.synapse[-1].weight = weight synhandler.synapse[-1].delay = delay # seconds
def connect(self, syn_name, pre_path, post_path, weight, threshold, delay): postcomp = moose.Compartment(post_path) ## We usually try to reuse an existing SynChan & SynHandler - ## event based SynHandlers have an array of weights and delays and can represent multiple synapses, ## so a new element of the weights and delays array is created ## every time a 'synapse' message connects to the SynHandler (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('/library/'+syn_name) gradedchild = utils.get_child_Mstring(libsyn,'graded') if libsyn.className == 'KinSynChan' or gradedchild.value == 'True': # create a new synapse syn_name_full = syn_name+'_'+utils.underscorize(pre_path) make_new_synapse(syn_name, postcomp, syn_name_full, self.nml_params) else: ## if syn doesn't exist in this compartment, create it syn_name_full = syn_name if not moose.exists(post_path+'/'+syn_name_full): make_new_synapse(syn_name, postcomp, syn_name_full, self.nml_params) ## moose.element is a function that checks if path exists, ## and returns the correct object, here SynChan syn = moose.element(post_path+'/'+syn_name_full) # wrap the SynChan in this compartment synhandler = moose.element(post_path+'/'+syn_name_full+'/handler') # wrap the SynHandler gradedchild = utils.get_child_Mstring(syn,'graded') #### weights are set at the end according to whether the synapse is graded or event-based #### If graded, connect pre-comp Vm to the table which is connected to SynChan's activation #### If event-based, connect spikegen/timetable's spikeOut to Simple/STDP SynHandler's addSpike ## I rely on second term below not being evaluated if first term is None; ## otherwise None.value gives error. if gradedchild is not None and gradedchild.value=='True': # graded synapse interpol = moose.element(syn.path+"/graded_table") #### always connect source to input - else 'cannot create message' error. precomp = moose.Compartment(pre_path) moose.connect(precomp,"VmOut",interpol,"input") try: tau_table = moose.element(syn.path+'/tau_table') tau_table_present = True except ValueError: tau_table_present = False # if tau_table is not found, don't connect it if tau_table_present: moose.connect(precomp,'VmOut',tau_table,'input') ## 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 else: # Event based synapse ## synapse could be connected to either spikegen at pre-compartment OR to a file! if 'file' not in pre_path: ## element() can return either Compartment() or IzhikevichNrn(), ## since it queries and wraps the actual object precomp = moose.element(pre_path) ## if spikegen for this synapse doesn't exist in this compartment, create it ## spikegens for different synapse_types can have different thresholds ## but an integrate and fire spikegen supercedes all other spikegens if 'IF' in precomp.className: # intfire LIF spikegen = precomp # LIF has a spikeOut message else: if not moose.exists(pre_path+'/'+syn_name+'_spikegen'): ## create new spikegen spikegen = moose.SpikeGen(pre_path+'/'+syn_name+'_spikegen') ## connect the compartment Vm to the spikegen moose.connect(precomp,"VmOut",spikegen,"Vm") ## spikegens for different synapse_types can have different thresholds spikegen.threshold = threshold spikegen.edgeTriggered = 1 # This ensures that spike is generated only on leading edge. ## 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 existing or newly created spikegen in this compartment spikegen = moose.SpikeGen(pre_path+'/'+syn_name+'_spikegen') ## connect the spikegen to the SynHandler ## note that you need to use Synapse (auto-created) under SynHandler ## to get/set weights , addSpike-s etc. ## wrap Synapse element by moose.Synapse(synhandler.path+'/synapse') or synhandler.synapse ## Synpase is an array element, first add to it, to addSpike-s, get/set weights, etc. synhandler.numSynapses += 1 ## see Demos/snippets/synapse.py for an example of ## how to connect multiple SpikeGens to the same SynChan m = moose.connect(spikegen, 'spikeOut', synhandler.synapse[-1], 'addSpike', 'Single') 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 ## pre_path is 'file[+<glomnum>]_<filenum1>[_<filenum2>...]' i.e. glomnum could be present ## hack for my (Aditya's) OB model to use files in NeuroML, should not affect others filesplit = pre_path.split('+') if len(filesplit) == 2: glomsplit = filesplit[1].split('_',1) glomstr = '_'+glomsplit[0] filenums = glomsplit[1] else: glomstr = '' filenums = pre_path.split('_',1)[1] tt_path = postcomp.path+'/'+syn_name_full+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_filenums = moose.Mstring(tt_path+'/fileNumbers') tt_filenums.value = 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. ## wrap Synapse element by moose.Synapse(synhandler.path+'/synapse') or synhandler.synapse ## Synpase is an array element, first add to it, to addSpike-s, get/set weights, etc. synhandler.numSynapses += 1 m = moose.connect(tt,"eventOut",synhandler.synapse[-1],"addSpike","Single") else: ## if it exists, append file number to the field 'fileNumbers' ## append filenumbers from 'file[+<glomnum>]_<filenumber1>[_<filenumber2>...]' tt_filenums = moose.Mstring(tt_path+'/fileNumbers') tt_filenums.value += '_' + 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 SynHandler ## to get/set weights , addSpike-s etc. ## wrap Synpase element by moose.Synapse(synhandler.path+'/synapse') or synhandler.synapse synhandler.synapse[-1].weight = weight synhandler.synapse[-1].delay = delay # seconds
def set_compartment_param(self, compartment, name, value, mechanismname): """ Set the param for the compartment depending on name and mechanismname. """ if name == 'CM': compartment.Cm = value * math.pi * compartment.diameter * compartment.length elif name == 'RM': compartment.Rm = value / (math.pi * compartment.diameter * compartment.length) elif name == 'RA': compartment.Ra = value * compartment.length / ( math.pi * (compartment.diameter / 2.0)**2) elif name == 'Em': compartment.Em = value elif name == 'initVm': compartment.initVm = value elif name == 'inject': # this reader converts to SI _logger.info("Comparment %s inject %s A." % (compartment.name, value)) compartment.inject = value elif name == 'v_reset': compartment.vReset = value # compartment is a moose.LIF instance (intfire) elif name == 'threshold': compartment.thresh = value # compartment is a moose.LIF instance (intfire) elif name == 't_refrac': compartment.refractoryPeriod = value # compartment is a moose.LIF instance (intfire) elif name == 'g_refrac': _logger.info("SORRY, current moose.LIF doesn't support g_refrac.") elif mechanismname is 'synapse': # synapse being added to the compartment ## these are potential locations, we do not actually make synapses, ## unless the user has explicitly asked for it if self.createPotentialSynapses: syn_name = value if not moose.exists(compartment.path + '/' + syn_name): make_new_synapse(syn_name, compartment, syn_name, self.nml_params) ## I assume below that compartment name has _segid at its end segid = compartment.name.split('_')[ -1] # get segment id from compartment name self.segDict[segid][5].append(value) elif mechanismname is 'spikegen': # spikegen being added to the compartment ## these are potential locations, we do not actually make the spikegens. ## spikegens for different synapses can have different thresholds, ## hence include synapse_type in its name ## value contains name of synapse i.e. synapse_type #spikegen = moose.SpikeGen(compartment.path+'/'+value+'_spikegen') #moose.connect(compartment,"VmSrc",spikegen,"Vm") pass ## previous were mechanism that don't need a ChannelML definition ## including integrate_and_fire (I ignore the ChannelML definition) ## thus integrate_and_fire mechanism default values cannot be used ## i.e. nothing needed in /library, but below mechanisms need. elif mechanismname is not None: ## if mechanism is not present in compartment, deep copy from library ## all mechanisms have been loaded into the library earlier if not moose.exists(compartment.path + '/' + mechanismname): neutralObj = moose.element( "/library/" + mechanismname) # gives error if not present if 'CaConc' == neutralObj.className: # Ion concentration pool libcaconc = moose.CaConc("/library/" + mechanismname) ## deep copies the library caconc under the compartment caconc = moose.copy(libcaconc, compartment, mechanismname) caconc = moose.CaConc(caconc) ## CaConc connections are made later using connect_CaConc() ## Later, when calling connect_CaConc, ## B is set for caconc based on thickness of Ca shell and compartment l and dia ## OR based on the Mstring phi under CaConc path. channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D libchannel = moose.HHChannel2D("/library/" + mechanismname) ## deep copies the library channel under the compartment channel = moose.copy(libchannel, compartment, mechanismname) channel = moose.HHChannel2D(channel) moose.connect(channel, 'channel', compartment, 'channel') elif 'HHChannel' == neutralObj.className: ## HHChannel libchannel = moose.HHChannel("/library/" + mechanismname) ## deep copies the library channel under the compartment channel = moose.copy(libchannel, compartment, mechanismname) channel = moose.HHChannel(channel) moose.connect(channel, 'channel', compartment, 'channel') ## if mechanism is present in compartment, just wrap it else: neutralObj = moose.Neutral(compartment.path + '/' + mechanismname) if 'CaConc' == neutralObj.className: # Ion concentration pool caconc = moose.CaConc( compartment.path + '/' + mechanismname) # wraps existing channel channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D channel = moose.HHChannel2D( compartment.path + '/' + mechanismname) # wraps existing channel elif 'HHChannel' == neutralObj.className: ## HHChannel channel = moose.HHChannel( compartment.path + '/' + mechanismname) # wraps existing channel if name == 'Gbar': if channel is None: # if CaConc, neuroConstruct uses gbar for thickness or phi ## If child Mstring 'phi' is present, set gbar as phi ## BUT, value has been multiplied by Gfactor as a Gbar, ## SI or physiological not known here, ## ignoring Gbar for CaConc, instead of passing units here child = moose_utils.get_child_Mstring(caconc, 'phi') if child is not None: #child.value = value pass else: #caconc.thick = value pass else: # if ion channel, usual Gbar channel.Gbar = value * math.pi * compartment.diameter * compartment.length elif name == 'Ek': channel.Ek = value elif name == 'thick': # thick seems to be NEURON's extension to NeuroML level 2. caconc.thick = value ## JUST THIS WILL NOT DO - HAVE TO SET B based on this thick! ## Later, when calling connect_CaConc, ## B is set for caconc based on thickness of Ca shell and compartment l and dia. ## OR based on the Mstring phi under CaConc path. if neuroml_utils.neuroml_debug: _logger.info("Setting %s for comparment %s to %s" % (name, compartment.path, value))
def set_compartment_param(self, compartment, name, value, mechName): """ Set the param for the compartment depending on name and mechName. """ if name == 'CM': compartment.Cm = value *math.pi*compartment.diameter*compartment.length elif name == 'RM': compartment.Rm = value/(math.pi*compartment.diameter*compartment.length) elif name == 'RA': compartment.Ra = value * compartment.length / \ (math.pi*(compartment.diameter/2.0)**2) elif name == 'Em': compartment.Em = value elif name == 'initVm': compartment.initVm = value elif name == 'inject': msg = " {0} inject {1} A.".format(compartment.name, value) debug.printDebug("INFO", msg) compartment.inject = value elif mechName is 'synapse': # synapse being added to the compartment # these are potential locations, we do not actually make synapses. # I assume below that compartment name has _segid at its end # get segment id from compartment name segid = moose_methods.getCompartmentId(compartment.name) self.segDict[segid][5].append(value) # spikegen being added to the compartment elif mechName is 'spikegen': # these are potential locations, we do not actually make the # spikegens. spikegens for different synapses can have different # thresholds, hence include synapse_type in its name value contains # name of synapse i.e. synapse_type #spikegen = moose.SpikeGen(compartment.path+'/'+value+'_spikegen') #moose.connect(compartment,"VmSrc",spikegen,"Vm") pass elif mechName is not None: # if mechanism is not present in compartment, deep copy from library if not moose.exists(compartment.path+'/'+mechName): # if channel does not exist in library load it from xml file if not moose.exists(self.libraryPath+"/"+mechName): cmlR = ChannelML(self.nml_params) model_filename = mechName+'.xml' model_path = neuroml_utils.find_first_file( model_filename , self.model_dir ) if model_path is not None: cmlR.readChannelMLFromFile(model_path) else: msg = 'Mechanism {0}: files {1} not found under {2}'\ .format( mechName , model_filename , self.model_dir ) debug.printDebug("ERROR" , msg , frame = inspect.currentframe() ) sys.exit(0) neutralObj = moose.Neutral(self.libraryPath+"/"+mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: libcaconc = moose.CaConc(self.libraryPath+"/"+mechName) # deep copies the library caconc under the compartment caconc = moose.copy(libcaconc,compartment,mechName) caconc = moose.CaConc(caconc) # CaConc connections are made later using connect_CaConc() # Later, when calling connect_CaConc, B is set for caconc # based on thickness of Ca shell and compartment l and dia # OR based on the Mstring phi under CaConc path. channel = None elif 'HHChannel2D' == neutralObj.className : ## HHChannel2D libchannel = moose.HHChannel2D(self.libraryPath+"/"+mechName) ## deep copies the library channel under the compartment channel = moose.copy(libchannel,compartment,mechName) channel = moose.HHChannel2D(channel) moose.connect(channel,'channel',compartment,'channel') elif 'HHChannel' == neutralObj.className : ## HHChannel libchannel = moose.HHChannel(self.libraryPath+"/"+mechName) # deep copies the library channel under the compartment channel = moose.copy(libchannel,compartment,mechName) channel = moose.HHChannel(channel) moose.connect(channel,'channel',compartment,'channel') # if mechanism is present in compartment, just wrap it else: neutralObj = moose.Neutral(compartment.path+'/'+mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: # wraps existing channel caconc = moose.CaConc(compartment.path+'/'+mechName) channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D # wraps existing channel channel = moose.HHChannel2D(compartment.path+'/'+mechName) elif 'HHChannel' == neutralObj.className : ## HHChannel # wraps existing channel channel = moose.HHChannel(compartment.path+'/'+mechName) if name == 'Gbar': # if CaConc, neuroConstruct uses gbar for thickness or phi if channel is None: # If child Mstring 'phi' is present, set gbar as phi BUT, # value has been multiplied by Gfactor as a Gbar, SI or # physiological not known here, ignoring Gbar for CaConc, # instead of passing units here child = moose_utils.get_child_Mstring(caconc,'phi') if child is not None: #child.value = value pass else: #caconc.thick = value pass else: # if ion channel, usual Gbar channel.Gbar = value * math.pi * compartment.diameter \ * compartment.length elif name == 'Ek': channel.Ek = value # thick seems to be NEURON's extension to NeuroML level 2. elif name == 'thick': # JUST THIS WILL NOT DO - HAVE TO SET B based on this thick! caconc.thick = value # Later, when calling connect_CaConc, B is set for caconc based # on thickness of Ca shell and compartment l and dia. OR based # on the Mstring phi under CaConc path. if neuroml_utils.neuroml_debug: msg = "Setting {0} for {1} value {2}".format(name, compartment.path , value ) debug.printDebug("DEBUG", msg, frame=inspect.currentframe())
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 connect(self, syn_name, pre_path, post_path, weight, threshold, delay): 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('/library/'+syn_name) gradedchild = utils.get_child_Mstring(libsyn,'graded') if libsyn.className == 'KinSynChan' or gradedchild.value == 'True': # create a new synapse syn_name_full = syn_name+'_'+utils.underscorize(pre_path) self.make_new_synapse(syn_name, postcomp, syn_name_full) else: ##### BUG BUG BUG in MOOSE: ##### Subhasis said addSpike below always adds to the first element in syn.synapse ##### So here, create a new SynChan everytime. syn_name_full = syn_name+'_'+utils.underscorize(pre_path) self.make_new_synapse(syn_name, postcomp, syn_name_full) ##### Once above bug is resolved in MOOSE, revert to below: ### if syn doesn't exist in this compartment, create it #syn_name_full = syn_name #if not moose.exists(post_path+'/'+syn_name_full): # self.make_new_synapse(syn_name, postcomp, syn_name_full) syn = moose.SynChan(post_path+'/'+syn_name_full) # wrap the synapse in this compartment 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 if gradedchild.value=='True': # graded synapse table = moose.Table(syn.path+"/graded_table") #### always connect source to input - else 'cannot create message' error. precomp = moose.Compartment(pre_path) moose.connect(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 else: # Event based synapse ## synapse could be connected to spikegen at pre-compartment OR a file! if 'file' not in pre_path: precomp = moose.Compartment(pre_path) ## 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(pre_path+'/'+syn_name+'_spikegen'): spikegen = moose.SpikeGen(pre_path+'/'+syn_name+'_spikegen') ## connect the compartment Vm to the spikegen moose.connect(precomp,"VmOut",spikegen,"Vm") ## spikegens for different synapse_types can have different thresholds spikegen.threshold = threshold spikegen.edgeTriggered = 1 # This ensures that spike is generated only on leading edge. #spikegen.refractT = 0.25e-3 ## usually events are raised at every time step that Vm > Threshold, can set either edgeTriggered as above or refractT spikegen = moose.SpikeGen(pre_path+'/'+syn_name+'_spikegen') # wrap the spikegen in this compartment ## 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.synapse.num += 1 ##### BUG BUG BUG in MOOSE: ##### Subhasis said addSpike always adds to the first element in syn.synapse ##### Create a new synapse above everytime moose.connect(spikegen,"event",syn.synapse[-1],"addSpike") 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 ## pre_path is 'file[+<glomnum>]_<filenum1>[_<filenum2>...]' i.e. glomnum could be present filesplit = pre_path.split('+') if len(filesplit) == 2: glomsplit = filesplit[1].split('_',1) glomstr = '_'+glomsplit[0] filenums = glomsplit[1] else: glomstr = '' filenums = pre_path.split('_',1)[1] tt_path = postcomp.path+'/'+syn_name_full+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.synapse.num += 1 ##### BUG BUG BUG in MOOSE: ##### Subhasis said addSpike always adds to the first element in syn.synapse ##### Create a new synapse above everytime m = moose.connect(tt,"event",syn.synapse[-1],"addSpike") else: # if it exists, append file number to the field 'fileNumbers' tt = moose.TimeTable(tt_path) # append filenumbers from 'file[+<glomnum>]_<filenumber1>[_<filenumber2>...]' filenums = 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 set_compartment_param(self, compartment, name, value, mechName): """ Set the param for the compartment depending on name and mechName. """ if name == 'CM': compartment.Cm = value * math.pi * compartment.diameter * compartment.length elif name == 'RM': compartment.Rm = value / (math.pi * compartment.diameter * compartment.length) elif name == 'RA': compartment.Ra = value * compartment.length / \ (math.pi*(compartment.diameter/2.0)**2) elif name == 'Em': compartment.Em = value elif name == 'initVm': compartment.initVm = value elif name == 'inject': msg = " {0} inject {1} A.".format(compartment.name, value) debug.printDebug("INFO", msg) compartment.inject = value elif mechName is 'synapse': # synapse being added to the compartment # these are potential locations, we do not actually make synapses. # I assume below that compartment name has _segid at its end # get segment id from compartment name segid = moose_methods.getCompartmentId(compartment.name) self.segDict[segid][5].append(value) # spikegen being added to the compartment elif mechName is 'spikegen': # these are potential locations, we do not actually make the # spikegens. spikegens for different synapses can have different # thresholds, hence include synapse_type in its name value contains # name of synapse i.e. synapse_type #spikegen = moose.SpikeGen(compartment.path+'/'+value+'_spikegen') #moose.connect(compartment,"VmSrc",spikegen,"Vm") pass elif mechName is not None: # if mechanism is not present in compartment, deep copy from library if not moose.exists(compartment.path + '/' + mechName): # if channel does not exist in library load it from xml file if not moose.exists(self.libraryPath + "/" + mechName): cmlR = ChannelML(self.nml_params) model_filename = mechName + '.xml' model_path = neuroml_utils.find_first_file( model_filename, self.model_dir) if model_path is not None: cmlR.readChannelMLFromFile(model_path) else: msg = 'Mechanism {0}: files {1} not found under {2}'\ .format( mechName , model_filename , self.model_dir ) debug.printDebug("ERROR", msg, frame=inspect.currentframe()) sys.exit(0) neutralObj = moose.Neutral(self.libraryPath + "/" + mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: libcaconc = moose.CaConc(self.libraryPath + "/" + mechName) # deep copies the library caconc under the compartment caconc = moose.copy(libcaconc, compartment, mechName) caconc = moose.CaConc(caconc) # CaConc connections are made later using connect_CaConc() # Later, when calling connect_CaConc, B is set for caconc # based on thickness of Ca shell and compartment l and dia # OR based on the Mstring phi under CaConc path. channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D libchannel = moose.HHChannel2D(self.libraryPath + "/" + mechName) ## deep copies the library channel under the compartment channel = moose.copy(libchannel, compartment, mechName) channel = moose.HHChannel2D(channel) moose.connect(channel, 'channel', compartment, 'channel') elif 'HHChannel' == neutralObj.className: ## HHChannel libchannel = moose.HHChannel(self.libraryPath + "/" + mechName) # deep copies the library channel under the compartment channel = moose.copy(libchannel, compartment, mechName) channel = moose.HHChannel(channel) moose.connect(channel, 'channel', compartment, 'channel') # if mechanism is present in compartment, just wrap it else: neutralObj = moose.Neutral(compartment.path + '/' + mechName) # Ion concentration pool if 'CaConc' == neutralObj.className: # wraps existing channel caconc = moose.CaConc(compartment.path + '/' + mechName) channel = None elif 'HHChannel2D' == neutralObj.className: ## HHChannel2D # wraps existing channel channel = moose.HHChannel2D(compartment.path + '/' + mechName) elif 'HHChannel' == neutralObj.className: ## HHChannel # wraps existing channel channel = moose.HHChannel(compartment.path + '/' + mechName) if name == 'Gbar': # if CaConc, neuroConstruct uses gbar for thickness or phi if channel is None: # If child Mstring 'phi' is present, set gbar as phi BUT, # value has been multiplied by Gfactor as a Gbar, SI or # physiological not known here, ignoring Gbar for CaConc, # instead of passing units here child = moose_utils.get_child_Mstring(caconc, 'phi') if child is not None: #child.value = value pass else: #caconc.thick = value pass else: # if ion channel, usual Gbar channel.Gbar = value * math.pi * compartment.diameter \ * compartment.length elif name == 'Ek': channel.Ek = value # thick seems to be NEURON's extension to NeuroML level 2. elif name == 'thick': # JUST THIS WILL NOT DO - HAVE TO SET B based on this thick! caconc.thick = value # Later, when calling connect_CaConc, B is set for caconc based # on thickness of Ca shell and compartment l and dia. OR based # on the Mstring phi under CaConc path. if neuroml_utils.neuroml_debug: msg = "Setting {0} for {1} value {2}".format( name, compartment.path, value) debug.printDebug("DEBUG", msg, frame=inspect.currentframe())