def _setup_network(self): """Sets up the network (_init_network is enough)""" self.network = moose.LIF('network', self.N) moose.le('/network') self.network.vec.Em = self.el self.network.vec.thresh = self.vt self.network.vec.refractoryPeriod = self.refrT self.network.vec.Rm = self.Rm self.network.vec.vReset = self.vr self.network.vec.Cm = self.Cm self.network.vec.inject = self.Iinject
def _setup_network(self): """Sets up the network (_init_network is enough)""" self.network = moose.LIF( 'network', self.N ); moose.le( '/network' ) self.network.vec.Em = self.el self.network.vec.thresh = self.vt self.network.vec.refractoryPeriod = self.refrT self.network.vec.Rm = self.Rm self.network.vec.vReset = self.vr self.network.vec.Cm = self.Cm if not noiseInj: self.network.vec.inject = self.Iinject else: ## inject a constant + noisy current ## values are set in self.simulate() self.noiseTables = moose.StimulusTable('noiseTables',self.N) moose.connect( self.noiseTables, 'output', \ self.network, 'setInject', 'OneToOne')
def setupmodel(modelpath, iaf_Rm, iaf_Cm, pulse_interval): """Create a LeakyIaF neuron under `modelpath` and a synaptic channel (SynChan) in it. Create a spike generator stimulated by a pulse generator to give input to the synapse. """ model_container = moose.Neutral(modelpath) data_container = moose.Neutral(datapath) iaf = moose.LIF('%s/iaf' % (modelpath)) iaf.Rm = iaf_Rm iaf.Cm = iaf_Cm iaf.initVm = -0.070 iaf.Em = -0.065 #iaf.Vreset = -0.070 iaf.thresh = -0.055 # iaf.refractoryPeriod = 0.005 syn = moose.SynChan('%s/syn' % (iaf.path)) synh = moose.SimpleSynHandler(syn.path + '/synh') moose.connect(synh, 'activationOut', syn, 'activation') synh.synapse.num = 1 synh.synapse[0].delay = 0.01 syn.Ek = 0.0 syn.Gbar = 1.0 moose.connect(syn, 'channel', iaf, 'channel') moose.connect(iaf, 'VmOut', syn, 'Vm') sg = moose.SpikeGen('%s/spike' % (modelpath)) sg.threshold = 0.1 moose.connect(sg, 'spikeOut', synh.synapse[0], 'addSpike') pg = moose.PulseGen('%s/pulse' % (modelpath)) pg.delay[0] = pulse_interval pg.width[0] = 1e-3 pg.level[0] = 0.5 moose.connect(pg, 'output', sg, 'Vm') return { 'model': model_container, 'iaf': iaf, 'synchan': syn, 'spikegen': sg, 'pulsegen': pg }
# ########################################### ## Leaky integrate and fire neuron Vrest = -65e-3 # V # resting potential Vt_base = -45e-3 # V # threshold Vreset = -55e-3 # V # in current steps, Vreset is same as pedestal R = 1e8 # Ohm tau = 10e-3 # s refrT = 2e-3 # s # ########################################### # Initialize neuron group # ########################################### ## two neurons: index 0 will be presynaptic, 1 will be postsynaptic network = moose.LIF('network', 2) moose.le('/network') network.vec.Em = Vrest network.vec.thresh = Vt_base network.vec.refractoryPeriod = refrT network.vec.Rm = R network.vec.vReset = Vreset network.vec.Cm = tau / R network.vec.inject = 0. network.vec.initVm = Vrest ############################################# # Ca Plasticity parameters: synapses (not for ExcInhNetBase) ############################################# ### Cortical slice values -- Table Suppl 2 in Graupner & Brunel 2012
def test_GB2012_STDP(): """ Simulate a pseudo-STDP protocol and plot the STDP kernel that emerges from Ca plasticity of Graupner and Brunel 2012. Author: Aditya Gilra, NCBS, Bangalore, October, 2014. """ # ########################################### # Neuron models # ########################################### ## Leaky integrate and fire neuron Vrest = -65e-3 # V # resting potential Vt_base = -45e-3 # V # threshold Vreset = -55e-3 # V # in current steps, Vreset is same as pedestal R = 1e8 # Ohm tau = 10e-3 # s refrT = 2e-3 # s # ########################################### # Initialize neuron group # ########################################### ## two neurons: index 0 will be presynaptic, 1 will be postsynaptic network = moose.LIF('network', 2) moose.le('/network') network.vec.Em = Vrest network.vec.thresh = Vt_base network.vec.refractoryPeriod = refrT network.vec.Rm = R network.vec.vReset = Vreset network.vec.Cm = tau / R network.vec.inject = 0. network.vec.initVm = Vrest tauCa = 20e-3 tauSyn = 150.0 CaPre = 1.0 CaPost = 2.0 delayD = 13.7e-3 thetaD = 1.0 thetaP = 1.3 gammaD = 200.0 gammaP = 321.808 J = 5e-3 # V weight = 0.5 bistable = True syn = moose.GraupnerBrunel2012CaPlasticitySynHandler('/network/syn') syn.numSynapses = 1 moose.connect(syn, 'activationOut', network.vec[1], 'activation') # synapse from presynaptic neuron moose.connect(network.vec[0], 'spikeOut', syn.synapse[0], 'addSpike') # post-synaptic spikes also needed for STDP moose.connect(network.vec[1], 'spikeOut', syn, 'addPostSpike') syn.synapse[0].delay = 0.0 syn.synapse[0].weight = weight syn.CaInit = 0.0 syn.tauCa = tauCa syn.tauSyn = tauSyn syn.CaPre = CaPre syn.CaPost = CaPost syn.delayD = delayD syn.thetaD = thetaD syn.thetaP = thetaP syn.gammaD = gammaD syn.gammaP = gammaP syn.weightScale = J syn.weightMax = 1.0 syn.weightMin = 0. syn.noisy = True syn.noiseSD = 1.3333 syn.bistable = bistable # ########################################### # Setting up tables # ########################################### Vms = moose.Table('/plotVms', 2) moose.connect(network, 'VmOut', Vms, 'input', 'OneToOne') spikes = moose.Table('/plotSpikes', 2) moose.connect(network, 'spikeOut', spikes, 'input', 'OneToOne') CaTable = moose.Table('/plotCa', 1) moose.connect(CaTable, 'requestOut', syn, 'getCa') WtTable = moose.Table('/plotWeight', 1) moose.connect(WtTable, 'requestOut', syn.synapse[0], 'getWeight') dt = 1e-3 moose.useClock(0, '/network/syn', 'process') moose.useClock(1, '/network', 'process') moose.useClock(2, '/plotSpikes', 'process') moose.useClock(3, '/plotVms', 'process') moose.useClock(3, '/plotCa', 'process') moose.useClock(3, '/plotWeight', 'process') moose.setClock(0, dt) moose.setClock(1, dt) moose.setClock(2, dt) moose.setClock(3, dt) moose.setClock(9, dt) moose.reinit() # function to make the aPlus and aMinus settle to equilibrium values settletime = 10e-3 # s def reset_settle(): """ Call this between every pre-post pair to reset the neurons and make them settle to rest. """ syn.synapse[0].weight = weight syn.Ca = 0.0 moose.start(settletime) # Ca gets a jump at pre-spike+delayD # So this event can occur during settletime # So set Ca and weight once more after settletime syn.synapse[0].weight = weight syn.Ca = 0.0 # function to inject a sharp current pulse to make neuron spike # immediately at a given time step def make_neuron_spike(nrnidx, I=1e-7, duration=1e-3): """ Inject a brief current pulse to make a neuron spike """ network.vec[nrnidx].inject = I moose.start(duration) network.vec[nrnidx].inject = 0. dwlist_neg = [] ddt = 10e-3 # s # since CaPlasticitySynHandler is event based # multiple pairs are needed for Ca to be registered above threshold # Values from Fig 2, last line of legend numpairs = 60 # number of spike parts per deltat t_between_pairs = 1.0 # time between each spike pair t_extent = 100e-3 # s # STDP kernel extent, # t_extent > t_between_pairs/2 inverts pre-post pairing! # dt = tpost - tpre # negative dt corresponds to post before pre print('-----------------------------------------------') for deltat in np.arange(t_extent, 0.0, -ddt): reset_settle() for i in range(numpairs): # post neuron spike make_neuron_spike(1) moose.start(deltat) # pre neuron spike after deltat make_neuron_spike(0) moose.start( t_between_pairs) # weight changes after pre-spike+delayD # must run for at least delayD after pre-spike dw = (syn.synapse[0].weight - weight) / weight print(('post before pre, dt = %1.3f s, dw/w = %1.3f' % (-deltat, dw))) dwlist_neg.append(dw) print('-----------------------------------------------') # positive dt corresponds to pre before post dwlist_pos = [] for deltat in np.arange(ddt, t_extent + ddt, ddt): reset_settle() for i in range(numpairs): # pre neuron spike make_neuron_spike(0) moose.start(deltat) # post neuron spike after deltat make_neuron_spike(1) moose.start(t_between_pairs) dw = (syn.synapse[0].weight - weight) / weight print(('pre before post, dt = %1.3f s, dw/w = %1.3f' % (deltat, dw))) dwlist_pos.append(dw) Vmseries0 = Vms.vec[0].vector numsteps = len(Vmseries0) for t in spikes.vec[0].vector: Vmseries0[int(t / dt) - 1] = 30e-3 # V Vmseries1 = Vms.vec[1].vector for t in spikes.vec[1].vector: Vmseries1[int(t / dt) - 1] = 30e-3 # V timeseries = np.linspace(0., 200 * numsteps * dt, numsteps) # STDP curve up, sp = np.mean(dwlist_pos), np.std(dwlist_pos) un, sn = np.mean(dwlist_neg), np.std(dwlist_neg) expected = [ 0.32476025611655324, 0.22658173497286094, 0.02706212384326734, -0.2176119329016457, -0.17349820098625146, -0.049000627347906, 0.10942145078777199, 0.015381955378225953, 0.004742824127517586, -0.12298343312253879 ] assert np.isclose( dwlist_pos[1:], expected[1:]).all(), "Got %s \nexpected %s" % (dwlist_pos, expected) expected = [ -0.07871282492831622, 0.11915009122888964, -0.028510348966579557, 0.11812233585111875, 0.05098143255634335, -0.2303047508248669, 0.18033418630802123, -0.019377885225611347, -0.06038610826728241, 0.06575882890278106 ] assert np.isclose( dwlist_neg[1:], expected[1:]).all(), "Got %s\nexpected %s" % (dwlist_neg, expected) got = (up, sp) expNew = (0.014485615086785508, 0.16206703949072981) assert np.isclose( got, expNew).all(), 'Expected: %s, Got: %s' % (str(expNew), str(got))
def makeGlobalBalanceNetwork(): stim = moose.RandSpike('/model/stim', params['numInputs']) inhib = moose.LIF('/model/inhib', params['numInhib']) insyn = moose.SimpleSynHandler(inhib.path + '/syns', params['numInhib']) moose.connect(insyn, 'activationOut', inhib, 'activation', 'OneToOne') output = moose.LIF('/model/output', params['numOutput']) outsyn = moose.SimpleSynHandler(output.path + '/syns', params['numOutput']) moose.connect(outsyn, 'activationOut', output, 'activation', 'OneToOne') outInhSyn = moose.SimpleSynHandler(output.path + '/inhsyns', params['numOutput']) moose.connect(outInhSyn, 'activationOut', output, 'activation', 'OneToOne') iv = moose.vec(insyn.path + '/synapse') ov = moose.vec(outsyn.path + '/synapse') oiv = moose.vec(outInhSyn.path + '/synapse') assert len(iv) == 0 assert len(ov) == 0 assert len(oiv) == 0 temp = moose.connect(stim, 'spikeOut', iv, 'addSpike', 'Sparse') inhibMatrix = moose.element(temp) inhibMatrix.setRandomConnectivity(params['stimToInhProb'], params['stimToInhSeed']) cl = inhibMatrix.connectionList # This can change when random-number generator changes. # This was before we used c++11 <random> to generate random numbers. This # test has changes on Tuesday 31 July 2018 11:12:35 AM IST # expectedCl = [ 1,4,13,13,26,42,52,56,80,82,95,97,4,9,0,9,4,8,0,6,1,6,6,7] expectedCl = [0, 6, 47, 50, 56, 67, 98, 2, 0, 3, 5, 4, 8, 3] assert list(cl) == expectedCl, "Expected %s, got %s" % (expectedCl, cl) temp = moose.connect(stim, 'spikeOut', ov, 'addSpike', 'Sparse') excMatrix = moose.element(temp) excMatrix.setRandomConnectivity(params['stimToOutProb'], params['stimToOutSeed']) temp = moose.connect(inhib, 'spikeOut', oiv, 'addSpike', 'Sparse') negFFMatrix = moose.element(temp) negFFMatrix.setRandomConnectivity(params['inhToOutProb'], params['inhToOutSeed']) # print("ConnMtxEntries: ", inhibMatrix.numEntries, excMatrix.numEntries, negFFMatrix.numEntries) got = (inhibMatrix.numEntries, excMatrix.numEntries, negFFMatrix.numEntries) expected = (7, 62, 55) assert expected == got, "Expected %s, Got %s" % (expected, got) cl = negFFMatrix.connectionList numInhSyns = [] niv = 0 nov = 0 noiv = 0 for i in moose.vec(insyn): niv += i.synapse.num numInhSyns.append(i.synapse.num) if i.synapse.num > 0: i.synapse.weight = params['wtStimToInh'] # expected = [2,1,0,0,2,0,3,1,1,2] expected = [1, 0, 1, 2, 1, 1, 0, 0, 1, 0] assert numInhSyns == expected, "Expected %s, got %s" % (expected, numInhSyns) for i in moose.vec(outsyn): print('111', i) nov += i.synapse.num if i.synapse.num > 0: i.synapse.weight = params['wtStimToOut'] for i in moose.vec(outInhSyn): noiv += i.synapse.num #print i.synapse.num if i.synapse.num > 0: i.synapse.weight = params['wtInhToOut'] print("SUMS: ", sum(iv.numField), sum(ov.numField), sum(oiv.numField)) assert [1, 64, 25] == [sum(iv.numField), sum(ov.numField), sum(oiv.numField)] print("SUMS2: ", niv, nov, noiv) assert [7, 62, 55] == [niv, nov, noiv] print("SUMS3: ", sum(insyn.vec.numSynapses), sum(outsyn.vec.numSynapses), sum(outInhSyn.vec.numSynapses)) assert [7, 62, 55] == [ sum(insyn.vec.numSynapses), sum(outsyn.vec.numSynapses), sum(outInhSyn.vec.numSynapses) ] # print(oiv.numField) # print(insyn.vec[1].synapse.num) # print(insyn.vec.numSynapses) # print(sum( insyn.vec.numSynapses )) # niv = iv.numSynapses # ov = iv.numSynapses sv = moose.vec(stim) sv.rate = params['randInputRate'] sv.refractT = params['randRefractTime'] #moose.showfield( sv[7] ) inhib.vec.thresh = params['inhibThresh'] inhib.vec.Rm = params['Rm'] inhib.vec.Cm = params['Cm'] inhib.vec.vReset = params['inhVreset'] inhib.vec.refractoryPeriod = params['inhibRefractTime'] output.vec.thresh = params['outputThresh'] output.vec.Rm = params['Rm'] output.vec.Cm = params['Cm'] output.vec.refractoryPeriod = params['outputRefractTime'] otab = moose.Table('/model/otab', params['numOutput']) moose.connect(otab, 'requestOut', output, 'getVm', 'OneToOne') itab = moose.Table('/model/itab', params['numInhib']) moose.connect(itab, 'requestOut', inhib, 'getVm', 'OneToOne') return inhib, output
def readMorphML(self, cell, params={}, lengthUnits="micrometer"): """ returns cellDict = { cellname: (segDict, cableDict) } # note: single cell only where segDict = { segid1 : [ segname,(proximalx,proximaly,proximalz), (distalx,distaly,distalz),diameter,length,[potential_syn1, ... ] ] , ... } segname is "<name>_<segid>" because 1) guarantees uniqueness, & 2) later scripts obtain segid from the compartment's name! and cableDict = { cablegroupname : [campartment1name, compartment2name, ... ], ... }. params is dict which can contain, combineSegments and/or createPotentialSynapses, both boolean. """ if lengthUnits in ['micrometer', 'micron']: self.length_factor = 1e-6 else: self.length_factor = 1.0 cellname = cell.attrib["name"] moose.Neutral( '/library') # creates /library in MOOSE tree; elif present, wraps _logger.info("Loading cell %s into /library ." % cellname) #~ moosecell = moose.Cell('/library/'+cellname) #using moose Neuron class - in previous version 'Cell' class Chaitanya moosecell = moose.Neuron('/library/' + cellname) self.cellDictBySegmentId[cellname] = [moosecell, {}] self.cellDictByCableId[cellname] = [moosecell, {}] self.segDict = {} if 'combineSegments' in params: self.combineSegments = params['combineSegments'] else: self.combineSegments = False if 'createPotentialSynapses' in params: self.createPotentialSynapses = params['createPotentialSynapses'] else: self.createPotentialSynapses = False _logger.info("readMorphML using combineSegments = %s" % self.combineSegments) ############################################### #### load cablegroups into a dictionary self.cablegroupsDict = {} self.cablegroupsInhomoparamsDict = {} ## Two ways of specifying cablegroups in neuroml 1.x ## <cablegroup>s with list of <cable>s cablegroups = cell.findall(".//{" + self.mml + "}cablegroup") for cablegroup in cablegroups: cablegroupname = cablegroup.attrib['name'] self.cablegroupsDict[cablegroupname] = [] self.cablegroupsInhomoparamsDict[cablegroupname] = [] for cable in cablegroup.findall(".//{" + self.mml + "}cable"): cableid = cable.attrib['id'] self.cablegroupsDict[cablegroupname].append(cableid) # parse inhomogenous_params for inhomogeneous_param in cablegroup.findall( ".//{" + self.mml + "}inhomogeneous_param"): metric = inhomogeneous_param.find(".//{" + self.mml + "}metric") if metric.text == 'Path Length from root': inhomoparamname = inhomogeneous_param.attrib['name'] inhomoparamvar = inhomogeneous_param.attrib['variable'] self.cablegroupsInhomoparamsDict[cablegroupname].append(\ (inhomoparamname,inhomoparamvar)) else: _logger.warning('Only "Path Length from root" metric is ' ' supported currently, ignoring %s ' % metric.text) ## <cable>s with list of <meta:group>s cables = cell.findall(".//{" + self.mml + "}cable") for cable in cables: cableid = cable.attrib['id'] cablegroups = cable.findall(".//{" + self.meta + "}group") for cablegroup in cablegroups: cablegroupname = cablegroup.text if cablegroupname in self.cablegroupsDict: self.cablegroupsDict[cablegroupname].append(cableid) else: self.cablegroupsDict[cablegroupname] = [cableid] ################################################### ## load all mechanisms in this cell into /library for later copying ## set which compartments have integrate_and_fire mechanism self.intFireCableIds = { } # dict with keys as Compartments/cableIds which are IntFire # with mechanismnames as values for mechanism in cell.findall(".//{" + self.bio + "}mechanism"): mechanismname = mechanism.attrib["name"] passive = False if "passive_conductance" in mechanism.attrib: if mechanism.attrib['passive_conductance'] in [ "true", 'True', 'TRUE' ]: passive = True if not passive: ## if channel does not exist in library load it from xml file if not moose.exists("/library/" + mechanismname): _logger.info("Loading mechanism %s into library." % mechanismname) cmlR = ChannelML(self.nml_params) model_filename = mechanismname + '.xml' model_path = neuroml_utils.find_first_file( model_filename, self.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)) ## set those compartments to be LIF for which ## any integrate_and_fire parameter is set if not moose.exists("/library/" + mechanismname): _logger.warn("Mechanism doesn't exist: %s " % mechanismname) moose.le('/library') moosemech = moose.element("/library/" + mechanismname) if moose.exists(moosemech.path + "/integrate_and_fire"): mooseIaF = moose.element( moosemech.path + "/integrate_and_fire") # Mstring if mooseIaF.value in ['true', 'True', 'TRUE']: mech_params = mechanism.findall(".//{" + self.bio + "}parameter") for parameter in mech_params: parametername = parameter.attrib['name'] ## check for the integrate_and_fire parameters if parametername in [ 'threshold', 't_refrac', 'v_reset', 'g_refrac' ]: for group in parameter.findall(".//{" + self.bio + "}group"): cablegroupname = group.text if cablegroupname == 'all': self.intFireCableIds = { 'all': mechanismname } break else: for cableid in self.cablegroupsDict[ cablegroupname]: ## only one intfire mechanism is allowed in a cable ## the last one parsed will override others self.intFireCableIds[ cableid] = mechanismname if 'all' in self.intFireCableIds: break ############################################################ #### load morphology and connections between compartments ## Many neurons exported from NEURON have multiple segments in a section ## If self.combineSegments = True, ## then combine those segments into one Compartment / section ## for combining, assume segments of a compartment/section are in increasing order ## and assume all segments of a compartment/section have the same cableid ## findall() returns elements in document order: running_cableid = '' running_segid = '' running_comp = None running_diameter = 0.0 running_dia_nums = 0 segments = cell.findall(".//{" + self.mml + "}segment") segmentstotal = len(segments) for segnum, segment in enumerate(segments): segmentname = segment.attrib['name'] ## cable is an optional attribute. WARNING: Here I assume it is always present. cableid = segment.attrib['cable'] segmentid = segment.attrib['id'] ## if old cableid still running AND self.combineSegments == True, ## then don't start a new compartment, skip to next segment if cableid == running_cableid and self.combineSegments: self.cellDictBySegmentId[cellname][1][segmentid] = running_comp proximal = segment.find('./{' + self.mml + '}proximal') if proximal is not None: running_diameter += float( proximal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 distal = segment.find('./{' + self.mml + '}distal') if distal is not None: running_diameter += float( distal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 ## if (self.combineSegments and new cableid starts) or if not self.combineSegments, ## then start a new 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! ## Check if integrate_and_fire mechanism is present, ## if so use LIF instead of Compartment moosecompname = segmentname + '_' + segmentid # just segmentname is NOT unique # eg: mitral bbmit exported from NEURON moosecomppath = moosecell.path + '/' + moosecompname mechanismname = None if 'all' in self.intFireCableIds: mechanismname = self.intFireCableIds['all'] if cableid in self.intFireCableIds: mechanismname = self.intFireCableIds[cableid] if mechanismname is not None: # this cableid is an intfire ## create LIF (subclass of Compartment) and set to default values moosecomp = moose.LIF(moosecomppath) moosechannel = moose.Neutral('/library/' + mechanismname) moosechannelval = moose.Mstring(moosechannel.path + '/vReset') moosecomp.vReset = moosechannelval.value moosechannelval = moose.Mstring(moosechannel.path + '/thresh') moosecomp.thresh = moosechannelval.value moosechannelval = moose.Mstring(moosechannel.path + '/refracT') moosecomp.refractoryPeriod = moosechannelval.value ## refracG is currently not supported by moose.LIF ## when you implement it, check if refracG or g_refrac ## is a conductance density or a conductance, I think the former #moosechannelval = moose.Mstring(moosechannel.path+'/refracG') else: moosecomp = moose.Compartment(moosecomppath) self.cellDictBySegmentId[cellname][1][segmentid] = moosecomp ## cables are grouped and mechanism densities are set for cablegroups later. ## hence I will need to refer to segment according to which cable it belongs to. ## if combineSegments is False, there can be multiple segments per cable, ## so make array of compartments for cellDictByCableId[cellname][1][cableid] if cableid in self.cellDictByCableId[cellname][1]: self.cellDictByCableId[cellname][1][cableid].append( moosecomp) else: self.cellDictByCableId[cellname][1][cableid] = [moosecomp] running_cableid = cableid running_segid = segmentid running_comp = moosecomp running_diameter = 0.0 running_dia_nums = 0 if 'parent' in segment.attrib: parentid = segment.attrib[ 'parent'] # I assume the parent is created before the child # so that I can immediately connect the child. 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 running_diameter += float( proximal.attrib["diameter"]) * self.length_factor running_dia_nums += 1 distal = segment.find('./{' + self.mml + '}distal') if distal is not None: running_diameter += 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 = running_diameter / 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: _logger.info('Set up compartment/section %s' % running_comp.name) ############################################### #### load biophysics into the compartments biophysics = cell.find(".//{" + self.neuroml + "}biophysics") if biophysics is not None: ## see pg 219 (sec 13.2) of Book of Genesis for Physiological Units if biophysics.attrib["units"] == 'Physiological Units': CMfactor = 1e-2 # F/m^2 from microF/cm^2 Cfactor = 1e-6 # F from microF RAfactor = 1e1 # Ohm*m from KOhm*cm RMfactor = 1e-1 # Ohm*m^2 from KOhm*cm^2 Rfactor = 1e-3 # Ohm from KOhm Efactor = 1e-3 # V from mV Gfactor = 1e1 # S/m^2 from mS/cm^2 Ifactor = 1e-6 # A from microA Tfactor = 1e-3 # s from ms else: CMfactor = 1.0 Cfactor = 1.0 RAfactor = 1.0 RMfactor = 1.0 Rfactor = 1.0 Efactor = 1.0 Gfactor = 1.0 Ifactor = 1.0 Tfactor = 1.0 spec_capacitance = cell.find(".//{" + self.bio + "}spec_capacitance") for parameter in spec_capacitance.findall(".//{" + self.bio + "}parameter"): self.set_group_compartment_param(cell, cellname, parameter,\ 'CM', float(parameter.attrib["value"])*CMfactor, self.bio) spec_axial_resitance = cell.find(".//{" + self.bio + "}spec_axial_resistance") for parameter in spec_axial_resitance.findall(".//{" + self.bio + "}parameter"): self.set_group_compartment_param(cell, cellname, parameter,\ 'RA', float(parameter.attrib["value"])*RAfactor, self.bio) init_memb_potential = cell.find(".//{" + self.bio + "}init_memb_potential") for parameter in init_memb_potential.findall(".//{" + self.bio + "}parameter"): self.set_group_compartment_param(cell, cellname, parameter,\ 'initVm', float(parameter.attrib["value"])*Efactor, self.bio) chan_distrib = [ ] # the list for moose to parse inhomogeneous params (filled below) for mechanism in cell.findall(".//{" + self.bio + "}mechanism"): mechanismname = mechanism.attrib["name"] passive = False if "passive_conductance" in mechanism.attrib: if mechanism.attrib['passive_conductance'] in [ "true", 'True', 'TRUE' ]: passive = True _logger.info("Loading mechanism %s " % mechanismname) ## ONLY creates channel if at least one parameter (like gmax) is specified in the xml ## Neuroml does not allow you to specify all default values. ## However, granule cell example in neuroconstruct has Ca ion pool without ## a parameter, applying default values to all compartments! mech_params = mechanism.findall(".//{" + self.bio + "}parameter") ## if no params, apply all default values to all compartments if len(mech_params) == 0: for compartment_list in self.cellDictByCableId[cellname][ 1].values(): for compartment in compartment_list: self.set_compartment_param(compartment, None, 'default', mechanismname) ## if params are present, apply params to specified cable/compartment groups for parameter in mech_params: parametername = parameter.attrib['name'] if passive: if parametername in ['gmax']: self.set_group_compartment_param(cell, cellname, parameter,\ 'RM', RMfactor*1.0/float(parameter.attrib["value"]), self.bio) elif parametername in ['e', 'erev']: self.set_group_compartment_param(cell, cellname, parameter,\ 'Em', Efactor*float(parameter.attrib["value"]), self.bio) elif parametername in ['inject']: self.set_group_compartment_param(cell, cellname, parameter,\ 'inject', Ifactor*float(parameter.attrib["value"]), self.bio) else: _logger.warning([ "Yo programmer of MorphML! You didn't", " implement parameter %s " % parametername, " in mechanism %s " % mechanismname ]) else: if parametername in ['gmax']: gmaxval = float( eval(parameter.attrib["value"], {"__builtins__": None}, {})) self.set_group_compartment_param(cell, cellname, parameter,\ 'Gbar', Gfactor*gmaxval, self.bio, mechanismname) elif parametername in ['e', 'erev']: self.set_group_compartment_param(cell, cellname, parameter,\ 'Ek', Efactor*float(parameter.attrib["value"]), self.bio, mechanismname) elif parametername in [ 'depth' ]: # has to be type Ion Concentration! self.set_group_compartment_param(cell, cellname, parameter,\ 'thick', self.length_factor*float(parameter.attrib["value"]),\ self.bio, mechanismname) elif parametername in ['v_reset']: self.set_group_compartment_param(cell, cellname, parameter,\ 'v_reset', Efactor*float(parameter.attrib["value"]),\ self.bio, mechanismname) elif parametername in ['threshold']: self.set_group_compartment_param(cell, cellname, parameter,\ 'threshold', Efactor*float(parameter.attrib["value"]),\ self.bio, mechanismname) elif parametername in ['t_refrac']: self.set_group_compartment_param(cell, cellname, parameter,\ 't_refrac', Tfactor*float(parameter.attrib["value"]),\ self.bio, mechanismname) else: _logger.warning([ "Yo programmer of MorphML import! You didn't", " implement parameter %s " % parametername, " in mechanism %s " % mechanismname ]) ## variable parameters: ## varying with: ## p, g, L, len, dia ## p: path distance from soma, measured along dendrite, in metres. ## g: geometrical distance from soma, in metres. ## L: electrotonic distance (# of lambdas) from soma, along dend. No units. ## len: length of compartment, in metres. ## dia: for diameter of compartment, in metres. var_params = mechanism.findall(".//{" + self.bio + "}variable_parameter") if len(var_params) > 0: ## if variable params are present ## and use MOOSE to apply the variable formula for parameter in var_params: parametername = parameter.attrib['name'] cablegroupstr4moose = "" ## the neuroml spec says there should be a single group in a variable_parameter ## of course user can always have multiple variable_parameter tags, ## if user wants multiple groups conforming to neuroml specs. group = parameter.find(".//{" + self.bio + "}group") cablegroupname = group.text if cablegroupname == 'all': cablegroupstr4moose = "#" else: for cableid in self.cablegroupsDict[ cablegroupname]: for compartment in self.cellDictByCableId[ cellname][1][cableid]: cablegroupstr4moose += "#" + compartment.name + "#," if cablegroupstr4moose[-1] == ',': cablegroupstr4moose = cablegroupstr4moose[: -1] # remove last comma inhomo_value = parameter.find(".//{" + self.bio + "}inhomogeneous_value") inhomo_value_name = inhomo_value.attrib['param_name'] inhomo_value_value = inhomo_value.attrib['value'] if parametername == 'gmax': inhomo_eqn = '(' + inhomo_value_value + ')*' + str( Gfactor) # careful about physiol vs SI units else: inhomo_eqn = inhomo_value_value _logger.warning( 'Physiol. vs SI units translation not' ' implemented for parameter ' + parametername + 'in channel ' + mechanismname) + '. Use SI units' 'or ask for implementation.' chan_distrib.extend( (mechanismname, cablegroupstr4moose, parametername, inhomo_eqn, "")) # use extend, not append, moose wants it this way ## get mooose to parse the variable parameter gmax channel distributions #pu.info("Some channel parameters distributed as per "+str(chan_distrib)) moosecell.channelDistribution = chan_distrib #### Connect the Ca pools and channels #### Am connecting these at the very end so that all channels and pools have been created #### Note: this function is in moose.utils not moose.neuroml.utils ! for compartment_list in self.cellDictByCableId[cellname][1].values( ): moose_utils.connect_CaConc(compartment_list,\ self.temperature+neuroml_utils.ZeroCKelvin) # temperature should be in Kelvin for Nernst ########################################################## #### load connectivity / synapses into the compartments connectivity = cell.find(".//{" + self.neuroml + "}connectivity") if connectivity is not None: for potential_syn_loc in cell.findall(".//{" + self.nml + "}potential_syn_loc"): if 'synapse_direction' in potential_syn_loc.attrib: if potential_syn_loc.attrib['synapse_direction'] in [ 'post', 'preAndOrPost' ]: self.set_group_compartment_param(cell, cellname, potential_syn_loc,\ 'synapse_type', potential_syn_loc.attrib['synapse_type'],\ self.nml, mechanismname='synapse') if potential_syn_loc.attrib['synapse_direction'] in [ 'pre', 'preAndOrPost' ]: self.set_group_compartment_param(cell, cellname, potential_syn_loc,\ 'spikegen_type', potential_syn_loc.attrib['synapse_type'],\ self.nml, mechanismname='spikegen') ########################################################## #### annotate each compartment with the cablegroups it belongs to self.cableDict = {} for cablegroupname in self.cablegroupsDict: comp_list = [] for cableid in self.cablegroupsDict[cablegroupname]: for compartment in self.cellDictByCableId[cellname][1][ cableid]: cableStringPath = compartment.path + '/cable_groups' cableString = moose.Mstring(cableStringPath) if cableString.value == '': cableString.value += cablegroupname else: cableString.value += ',' + cablegroupname comp_list.append(compartment.name) self.cableDict[cablegroupname] = comp_list _logger.info("Finished loading into library, cell: %s " % cellname) return {cellname: (self.segDict, self.cableDict)}
def setupModel(): ''' Set up two LIF neurons and connect them by an STDPSynHandler. Set up some tables, and reinit MOOSE before simulation. ''' # ########################################### # Initialize neuron group # ########################################### ## two neurons: index 0 will be presynaptic, 1 will be postsynaptic network = moose.LIF('network', 2) moose.le('/network') network.vec.Em = Vrest network.vec.thresh = Vt_base network.vec.refractoryPeriod = refrT network.vec.Rm = R network.vec.vReset = Vreset network.vec.Cm = tau / R network.vec.inject = 0. network.vec.initVm = Vrest # ########################################### # Synaptic model: STDP at each pre and post spike # ########################################### # Values approx from figure in Scholarpedia article (following Bi and Poo 1998): # Jesper Sjoestroem and Wulfram Gerstner (2010) Spike-timing dependent plasticity. # Scholarpedia, 5(2):1362., revision #137369 tauPlus = 10e-3 # s # Apre time constant tauMinus = 10e-3 # s # Apost time constant aPlus0 = 1.0 # at pre, Apre += Apre0 aMinus0 = 0.25 # at post, Apost += Apost0 weight = 5e-3 # V # delta function synapse, adds to Vm syn = moose.STDPSynHandler('/network/syn') syn.numSynapses = 1 # 1 synapse # many pre-synaptic inputs can connect to a synapse # synapse onto postsynaptic neuron moose.connect(syn, 'activationOut', network.vec[1], 'activation') # synapse from presynaptic neuron moose.connect(network.vec[0], 'spikeOut', syn.synapse[0], 'addSpike') # post-synaptic spikes also needed for STDP moose.connect(network.vec[1], 'spikeOut', syn, 'addPostSpike') syn.synapse[0].delay = 0.0 syn.synapse[0].weight = weight # V syn.aPlus0 = aPlus0 * weight # on every pre-spike, aPlus gets this jump # aMinus0 includes learning rate # on every pre-spike, aMinus is added to weight syn.tauPlus = tauPlus syn.aMinus0 = -aMinus0 * weight # on every post-spike, aMinus gets this jump # aMinus0 includes learning rate # on every post-spike, aPlus is added to weight syn.tauMinus = tauMinus syn.weightMax = 2 * weight # bounds on the weight syn.weightMin = 0. # ########################################### # Setting up tables # ########################################### Vms = moose.Table('/plotVms', 2) moose.connect(network, 'VmOut', Vms, 'input', 'OneToOne') spikes = moose.Table('/plotSpikes', 2) moose.connect(network, 'spikeOut', spikes, 'input', 'OneToOne') # ########################################### # Simulate the STDP curve with spaced pre-post spike pairs # ########################################### dt = 0.5e-5 # s # moose simulation moose.useClock(0, '/network/syn', 'process') moose.useClock(1, '/network', 'process') moose.useClock(2, '/plotSpikes', 'process') moose.useClock(3, '/plotVms', 'process') moose.setClock(0, dt) moose.setClock(1, dt) moose.setClock(2, dt) moose.setClock(3, dt) moose.setClock(9, dt) moose.reinit()
def make_network(): size = 1024 dt = 0.2 runsteps = 50 delayMin = 0 delayMax = 4 weightMax = 1 Vmax = 1.0 thresh = 0.4 refractoryPeriod = 0.4 tau = 0.5 connectionProbability = 0.01 random.seed( 123 ) nprand.seed( 456 ) t0 = time.time() network = moose.LIF( 'network', size ); syns = moose.SimpleSynHandler( '/network/syns', size ); moose.connect( syns, 'activationOut', network, 'activation', 'OneToOne' ) moose.le( '/network' ) syns.vec.numSynapses = [1] * size sv = moose.vec( '/network/syns/synapse' ) print(('before connect t = ', time.time() - t0)) mid = moose.connect( network, 'spikeOut', sv, 'addSpike', 'Sparse') print(('after connect t = ', time.time() - t0)) #print mid.destFields m2 = moose.element( mid ) m2.setRandomConnectivity( connectionProbability, 5489 ) print(('after setting connectivity, t = ', time.time() - t0)) #network.vec.Vm = [(Vmax*random.random()) for r in range(size)] network.vec.Vm = nprand.rand( size ) * Vmax network.vec.thresh = thresh network.vec.refractoryPeriod = refractoryPeriod network.vec.Rm = 1e10 network.vec.Cm = 5e-9 numSynVec = syns.vec.numSynapses print(('Middle of setup, t = ', time.time() - t0)) numTotSyn = sum( numSynVec ) print((numSynVec.size, ', tot = ', numTotSyn, ', numSynVec = ', numSynVec)) for item in syns.vec: sh = moose.element( item ) sh.synapse.delay = delayMin + (delayMax - delayMin ) * nprand.rand( len( sh.synapse ) ) #sh.synapse.delay = [ (delayMin + random.random() * (delayMax - delayMin ) for r in range( len( sh.synapse ) ) ] sh.synapse.weight = nprand.rand( len( sh.synapse ) ) * weightMax print(('after setup, t = ', time.time() - t0)) numStats = 100 stats = moose.SpikeStats( '/stats', numStats ) stats.vec.windowLength = 1 # timesteps to put together. plots = moose.Table( '/plot', numStats ) convergence = size / numStats for i in range( numStats ): for j in range( size/numStats ): k = i * convergence + j moose.connect( network.vec[k], 'spikeOut', stats.vec[i], 'addSpike' ) moose.connect( plots, 'requestOut', stats, 'getMean', 'OneToOne' ) #moose.useClock( 0, '/network/syns,/network', 'process' ) moose.useClock( 0, '/network/syns', 'process' ) moose.useClock( 1, '/network', 'process' ) moose.useClock( 2, '/stats', 'process' ) moose.useClock( 3, '/plot', 'process' ) moose.setClock( 0, dt ) moose.setClock( 1, dt ) moose.setClock( 2, dt ) moose.setClock( 3, dt ) moose.setClock( 9, dt ) t1 = time.time() moose.reinit() print(('reinit time t = ', time.time() - t1)) network.vec.Vm = nprand.rand( size ) * Vmax print(('setting Vm , t = ', time.time() - t1)) t1 = time.time() print('starting') moose.start(runsteps * dt) print(('runtime, t = ', time.time() - t1)) print((network.vec.Vm[99:103], network.vec.Vm[900:903])) t = [i * dt for i in range( plots.vec[0].vector.size )] i = 0 for p in plots.vec: pylab.plot( t, p.vector, label=str( i) ) i += 1 pylab.xlabel( "Time (s)" ) pylab.ylabel( "Rate (Hz)" ) pylab.legend() pylab.show()
def makeGlobalBalanceNetwork(): stim = moose.RandSpike('/model/stim', params['numInputs']) inhib = moose.LIF('/model/inhib', params['numInhib']) insyn = moose.SimpleSynHandler(inhib.path + '/syns', params['numInhib']) moose.connect(insyn, 'activationOut', inhib, 'activation', 'OneToOne') output = moose.LIF('/model/output', params['numOutput']) outsyn = moose.SimpleSynHandler(output.path + '/syns', params['numOutput']) moose.connect(outsyn, 'activationOut', output, 'activation', 'OneToOne') outInhSyn = moose.SimpleSynHandler(output.path + '/inhsyns', params['numOutput']) moose.connect(outInhSyn, 'activationOut', output, 'activation', 'OneToOne') iv = moose.vec(insyn.path + '/synapse') ov = moose.vec(outsyn.path + '/synapse') oiv = moose.vec(outInhSyn.path + '/synapse') temp = moose.connect(stim, 'spikeOut', iv, 'addSpike', 'Sparse') inhibMatrix = moose.element(temp) inhibMatrix.setRandomConnectivity(params['stimToInhProb'], params['stimToInhSeed']) cl = inhibMatrix.connectionList expectedCl = [ 1, 4, 13, 13, 26, 42, 52, 56, 80, 82, 95, 97, 4, 9, 0, 9, 4, 8, 0, 6, 1, 6, 6, 7 ] assert list(cl) == expectedCl, "Expected %s, got %s" % (expectedCl, cl) temp = moose.connect(stim, 'spikeOut', ov, 'addSpike', 'Sparse') excMatrix = moose.element(temp) excMatrix.setRandomConnectivity(params['stimToOutProb'], params['stimToOutSeed']) temp = moose.connect(inhib, 'spikeOut', oiv, 'addSpike', 'Sparse') negFFMatrix = moose.element(temp) negFFMatrix.setRandomConnectivity(params['inhToOutProb'], params['inhToOutSeed']) # print("ConnMtxEntries: ", inhibMatrix.numEntries, excMatrix.numEntries, negFFMatrix.numEntries) assert (12, 57, 48) == (inhibMatrix.numEntries, excMatrix.numEntries, negFFMatrix.numEntries) cl = negFFMatrix.connectionList numInhSyns = [] niv = 0 nov = 0 noiv = 0 for i in moose.vec(insyn): niv += i.synapse.num numInhSyns.append(i.synapse.num) if i.synapse.num > 0: i.synapse.weight = params['wtStimToInh'] assert numInhSyns == [2, 1, 0, 0, 2, 0, 3, 1, 1, 2] for i in moose.vec(outsyn): nov += i.synapse.num if i.synapse.num > 0: i.synapse.weight = params['wtStimToOut'] for i in moose.vec(outInhSyn): noiv += i.synapse.num #print i.synapse.num if i.synapse.num > 0: i.synapse.weight = params['wtInhToOut'] # print("SUMS: ", sum( iv.numField ), sum( ov.numField ), sum( oiv.numField )) assert [4, 49, 9] == [sum(iv.numField), sum(ov.numField), sum(oiv.numField)] # print("SUMS2: ", niv, nov, noiv) assert [12, 57, 48] == [niv, nov, noiv] # print("SUMS3: ", sum( insyn.vec.numSynapses ), sum( outsyn.vec.numSynapses ), sum( outInhSyn.vec.numSynapses )) assert [12, 57, 48] == [ sum(insyn.vec.numSynapses), sum(outsyn.vec.numSynapses), sum(outInhSyn.vec.numSynapses) ] # print(oiv.numField) # print(insyn.vec[1].synapse.num) # print(insyn.vec.numSynapses) # print(sum( insyn.vec.numSynapses )) # niv = iv.numSynapses # ov = iv.numSynapses sv = moose.vec(stim) sv.rate = params['randInputRate'] sv.refractT = params['randRefractTime'] #moose.showfield( sv[7] ) inhib.vec.thresh = params['inhibThresh'] inhib.vec.Rm = params['Rm'] inhib.vec.Cm = params['Cm'] inhib.vec.vReset = params['inhVreset'] inhib.vec.refractoryPeriod = params['inhibRefractTime'] output.vec.thresh = params['outputThresh'] output.vec.Rm = params['Rm'] output.vec.Cm = params['Cm'] output.vec.refractoryPeriod = params['outputRefractTime'] otab = moose.Table('/model/otab', params['numOutput']) moose.connect(otab, 'requestOut', output, 'getVm', 'OneToOne') itab = moose.Table('/model/itab', params['numInhib']) moose.connect(itab, 'requestOut', inhib, 'getVm', 'OneToOne') return inhib, output
def main(): """ Simulate a pseudo-STDP protocol and plot the STDP kernel that emerges from Ca plasticity of Graupner and Brunel 2012. Author: Aditya Gilra, NCBS, Bangalore, October, 2014. """ # ########################################### # Neuron models # ########################################### ## Leaky integrate and fire neuron Vrest = -65e-3 # V # resting potential Vt_base = -45e-3 # V # threshold Vreset = -55e-3 # V # in current steps, Vreset is same as pedestal R = 1e8 # Ohm tau = 10e-3 # s refrT = 2e-3 # s # ########################################### # Initialize neuron group # ########################################### ## two neurons: index 0 will be presynaptic, 1 will be postsynaptic network = moose.LIF('network', 2) moose.le('/network') network.vec.Em = Vrest network.vec.thresh = Vt_base network.vec.refractoryPeriod = refrT network.vec.Rm = R network.vec.vReset = Vreset network.vec.Cm = tau / R network.vec.inject = 0. network.vec.initVm = Vrest ############################################# # Ca Plasticity parameters: synapses (not for ExcInhNetBase) ############################################# ### Cortical slice values -- Table Suppl 2 in Graupner & Brunel 2012 ### Also used in Higgins et al 2014 #tauCa = 22.6936e-3 # s # Ca decay time scale #tauSyn = 346.3615 # s # synaptic plasticity time scale ### in vitro values in Higgins et al 2014, faster plasticity #CaPre = 0.56175 # mM #CaPost = 1.2964 # mM ### in vivo values in Higgins et al 2014, slower plasticity ##CaPre = 0.33705 # mM ##CaPost = 0.74378 # mM #delayD = 4.6098e-3 # s # CaPre is added to Ca after this delay ## proxy for rise-time of NMDA #thetaD = 1.0 # mM # depression threshold for Ca #thetaP = 1.3 # mM # potentiation threshold for Ca #gammaD = 331.909 # factor for depression term #gammaP = 725.085 # factor for potentiation term #J = 5e-3 # V # delta function synapse, adds to Vm #weight = 0.43 # initial synaptic weight ## gammaP/(gammaP+gammaD) = eq weight w/o noise ## see eqn (22), noiseSD also appears ## but doesn't work here, ## weights away from 0.4 - 0.5 screw up the STDP rule!! #bistable = True # if bistable is True, use bistable potential for weights #noisy = False # use noisy weight updates given by noiseSD #noiseSD = 3.3501 # if noisy, use noiseSD (3.3501 from Higgins et al 2014) ######################################## ## DP STDP curve (Fig 2C) values -- Table Suppl 1 in Graupner & Brunel 2012 tauCa = 20e-3 # s # Ca decay time scale tauSyn = 150.0 # s # synaptic plasticity time scale CaPre = 1.0 # arb CaPost = 2.0 # arb delayD = 13.7e-3 # s # CaPre is added to Ca after this delay # proxy for rise-time of NMDA thetaD = 1.0 # mM # depression threshold for Ca thetaP = 1.3 # mM # potentiation threshold for Ca gammaD = 200.0 # factor for depression term gammaP = 321.808 # factor for potentiation term J = 5e-3 # V # delta function synapse, adds to Vm weight = 0.5 # initial synaptic weight # gammaP/(gammaP+gammaD) = eq weight w/o noise # see eqn (22), noiseSD also appears # but doesn't work here, # weights away from 0.4 - 0.5 screw up the STDP rule!! bistable = True # if bistable is True, use bistable potential for weights noisy = False # use noisy weight updates given by noiseSD noiseSD = 2.8284 # if noisy, use noiseSD (3.3501 in Higgins et al 2014) ########################################## syn = moose.GraupnerBrunel2012CaPlasticitySynHandler('/network/syn') syn.numSynapses = 1 # 1 synapse # many pre-synaptic inputs can connect to a synapse # synapse onto postsynaptic neuron moose.connect(syn, 'activationOut', network.vec[1], 'activation') # synapse from presynaptic neuron moose.connect(network.vec[0], 'spikeOut', syn.synapse[0], 'addSpike') # post-synaptic spikes also needed for STDP moose.connect(network.vec[1], 'spikeOut', syn, 'addPostSpike') syn.synapse[0].delay = 0.0 syn.synapse[0].weight = weight syn.CaInit = 0.0 syn.tauCa = tauCa syn.tauSyn = tauSyn syn.CaPre = CaPre syn.CaPost = CaPost syn.delayD = delayD syn.thetaD = thetaD syn.thetaP = thetaP syn.gammaD = gammaD syn.gammaP = gammaP syn.weightScale = J # weight ~1, weightScale ~ J # weight*weightScale is activation, # i.e. delta-fn added to postsynaptic Vm syn.weightMax = 1.0 # bounds on the weight syn.weightMin = 0. syn.noisy = noisy syn.noiseSD = noiseSD syn.bistable = bistable # ########################################### # Setting up tables # ########################################### Vms = moose.Table('/plotVms', 2) moose.connect(network, 'VmOut', Vms, 'input', 'OneToOne') spikes = moose.Table('/plotSpikes', 2) moose.connect(network, 'spikeOut', spikes, 'input', 'OneToOne') CaTable = moose.Table('/plotCa', 1) moose.connect(CaTable, 'requestOut', syn, 'getCa') WtTable = moose.Table('/plotWeight', 1) moose.connect(WtTable, 'requestOut', syn.synapse[0], 'getWeight') # ########################################### # Simulate the STDP curve with spaced pre-post spike pairs # ########################################### dt = 1e-3 # s # moose simulation moose.useClock(0, '/network/syn', 'process') moose.useClock(1, '/network', 'process') moose.useClock(2, '/plotSpikes', 'process') moose.useClock(3, '/plotVms', 'process') moose.useClock(3, '/plotCa', 'process') moose.useClock(3, '/plotWeight', 'process') moose.setClock(0, dt) moose.setClock(1, dt) moose.setClock(2, dt) moose.setClock(3, dt) moose.setClock(9, dt) moose.reinit() # function to make the aPlus and aMinus settle to equilibrium values settletime = 100e-3 # s def reset_settle(): """ Call this between every pre-post pair to reset the neurons and make them settle to rest. """ syn.synapse[0].weight = weight syn.Ca = 0.0 moose.start(settletime) # Ca gets a jump at pre-spike+delayD # So this event can occur during settletime # So set Ca and weight once more after settletime syn.synapse[0].weight = weight syn.Ca = 0.0 # function to inject a sharp current pulse to make neuron spike # immediately at a given time step def make_neuron_spike(nrnidx, I=1e-7, duration=1e-3): """ Inject a brief current pulse to make a neuron spike """ network.vec[nrnidx].inject = I moose.start(duration) network.vec[nrnidx].inject = 0. dwlist_neg = [] ddt = 2e-3 # s # since CaPlasticitySynHandler is event based # multiple pairs are needed for Ca to be registered above threshold # Values from Fig 2, last line of legend numpairs = 60 # number of spike parts per deltat t_between_pairs = 1.0 # time between each spike pair t_extent = 100e-3 # s # STDP kernel extent, # t_extent > t_between_pairs/2 inverts pre-post pairing! # dt = tpost - tpre # negative dt corresponds to post before pre print('-----------------------------------------------') for deltat in arange(t_extent, 0.0, -ddt): reset_settle() for i in range(numpairs): # post neuron spike make_neuron_spike(1) moose.start(deltat) # pre neuron spike after deltat make_neuron_spike(0) moose.start( t_between_pairs) # weight changes after pre-spike+delayD # must run for at least delayD after pre-spike dw = (syn.synapse[0].weight - weight) / weight print(('post before pre, dt = %1.3f s, dw/w = %1.3f' % (-deltat, dw))) dwlist_neg.append(dw) print('-----------------------------------------------') # positive dt corresponds to pre before post dwlist_pos = [] for deltat in arange(ddt, t_extent + ddt, ddt): reset_settle() for i in range(numpairs): # pre neuron spike make_neuron_spike(0) moose.start(deltat) # post neuron spike after deltat make_neuron_spike(1) moose.start(t_between_pairs) dw = (syn.synapse[0].weight - weight) / weight print(('pre before post, dt = %1.3f s, dw/w = %1.3f' % (deltat, dw))) dwlist_pos.append(dw) print('-----------------------------------------------') print(('Each of the above pre-post pairs was repeated',\ numpairs,'times, with',t_between_pairs,'s between pairs.')) print() print('Due to event based updates, Ca decays suddenly at events:') print('pre-spike, pre-spike + delayD, and post-spike;') print('apart from the usual CaPre and CaPost jumps at') print('pre-spike + delayD and post-spike respectively.') print( 'Because of the event based update, multiple pre-post pairs are used.') print() print('If you reduce the t_between_pairs,') print( ' you\'ll see potentiation for the LTD part without using any triplet rule!' ) print() print("If you turn on noise, the weights fluctuate too much,") print(" not sure if there's a bug in my noise implementation.") print('-----------------------------------------------') # ########################################### # Plot the simulated Vm-s and STDP curve # ########################################### # insert spikes so that Vm reset doesn't look weird Vmseries0 = Vms.vec[0].vector numsteps = len(Vmseries0) for t in spikes.vec[0].vector: Vmseries0[int(t / dt) - 1] = 30e-3 # V Vmseries1 = Vms.vec[1].vector for t in spikes.vec[1].vector: Vmseries1[int(t / dt) - 1] = 30e-3 # V timeseries = linspace(0., 1000 * numsteps * dt, numsteps) # Voltage plots figure(facecolor='w') plot(timeseries, Vmseries0, color='r') # pre neuron's vm plot(timeseries, Vmseries1, color='b') # post neuron's vm xlabel('time (ms)') ylabel('Vm (V)') title("pre (r) and post (b) neurons' Vm") # Ca plots for the synapse figure(facecolor='w') plot(timeseries, CaTable.vector[:len(timeseries)], color='r') plot((timeseries[0],timeseries[-1]),(thetaP,thetaP),color='k',\ linestyle='dashed',label='pot thresh') plot((timeseries[0],timeseries[-1]),(thetaD,thetaD),color='b',\ linestyle='dashed',label='dep thresh') legend() xlabel('time (ms)') ylabel('Ca (arb)') title("Ca conc in the synapse") # Weight plots for the synapse figure(facecolor='w') plot(timeseries, WtTable.vector[:len(timeseries)], color='r') xlabel('time (ms)') ylabel('Efficacy') title("Efficacy of the synapse") # STDP curve fig = figure(facecolor='w') ax = fig.add_subplot(111) ax.plot(arange(-t_extent, 0, ddt) * 1000, array(dwlist_neg), '.-r') ax.plot( arange(ddt, (t_extent + ddt), ddt) * 1000, array(dwlist_pos), '.-b') xmin, xmax = ax.get_xlim() ymin, ymax = ax.get_ylim() ax.set_xticks([xmin, 0, xmax]) ax.set_yticks([ymin, 0, ymax]) ax.plot((0, 0), (ymin, ymax), linestyle='dashed', color='k') ax.plot((xmin, xmax), (0, 0), linestyle='dashed', color='k') ax.set_xlabel('$t_{post}-t_{pre}$ (ms)') ax.set_ylabel('$\Delta w / w$') fig.tight_layout() #fig.subplots_adjust(hspace=0.3,wspace=0.5) # use after tight_layout() show()