def test_group_variable_set_conditional_copy_to_host(): G = NeuronGroup(1, 'v : 1') # uses group_variable_set_conditional template G.v['i < 1'] = '50' # connect template runs on host, requiring G.v on host after the group_variable_set # template call above (this tests that data is copied from device to host) S = Synapses(G, G) S.connect(condition='v_pre == 50') run(0 * second) assert len(S) == 1, len(S)
def mk_sencircuit(task_info): """ Creates balanced network representing sensory circuit. returns: groups, synapses, subgroups groups and synapses have to be added to the "Network" in order to run the simulation subgroups is used for establishing connections between the sensory and integration circuit; do not add subgroups to the "Network" psr following the published Brian1 code in DB model from Wimmer et al. 2015 - brain2 code - implementation runs in cpp_standalone mode, compatible with SNEP """ # ------------------------------------- # Sensory circuit parameters # ------------------------------------- # populations N_E = task_info['sen']['populations']['N_E'] # total number of E neurons sub = task_info['sen']['populations']['sub'] # fraction corresponding to subpops 1,2 N_E1 = int(N_E * sub) # size of exc subpops that responds to the stimuli N_I = task_info['sen']['populations']['N_I'] # total number of I neurons N_X = task_info['sen']['populations']['N_X'] # size of external pop # local recurrent connections eps = task_info['sen']['connectivity']['eps'] # connection probability for EE, EI, IE and II w_p = task_info['sen']['connectivity']['w_p'] # relative synaptic strength within pop E1 and E2 w_m = 2 - w_p # relative synaptic strength across pop E1 and E2 gEE = task_info['sen']['connectivity']['gEE'] # weight of EE synapses, prev: 0.7589*nS gEI = task_info['sen']['connectivity']['gEI'] # weight of EI synapses, prev: 1.5179*nS gIE = task_info['sen']['connectivity']['gIE'] # weight of IE synapses, prev: 12.6491*nS gII = task_info['sen']['connectivity']['gII'] # weight of II synapses gmax = task_info['sen']['connectivity']['gmax'] # maximum synaptic weight dE = '0.5*ms + rand()*1.0*ms' # range of transmission delays of E synapses, (0.5:1.5) dI = '0.1*ms + rand()*0.8*ms' # range of transmission delays of I synapses, (0.1:0.9) # external connections epsX = task_info['sen']['connectivity']['epsX'] # connection probability for ext synapses alphaX = task_info['sen']['connectivity']['alphaX'] # 0: global input, 1: local input gXE = task_info['sen']['connectivity']['gXE'] # weight of ext to E synapses gXI = task_info['sen']['connectivity']['gXI'] # weight of ext to I synapses dX = '0.5*ms + rand()*1.0*ms' # range of transmission delays of X synapses, (0.5:1.5) # neuron models CmE = task_info['sen']['neuron']['CmE'] # membrane capacitance of E neurons CmI = task_info['sen']['neuron']['CmI'] # membrane capacitance of I neurons gleakE = task_info['sen']['neuron']['gleakE'] # leak conductance of E neurons gleakI = task_info['sen']['neuron']['gleakI'] # leak conductance of I neurons Vl = task_info['sen']['neuron']['Vl'] # resting potential Vt = task_info['sen']['neuron']['Vt'] # spiking threshold Vr = task_info['sen']['neuron']['Vr'] # reset potential tau_refE = task_info['sen']['neuron']['tau_refE'] # absolute refractory period of E neurons tau_refI = task_info['sen']['neuron']['tau_refI'] # absolute refractory period of I neurons nu_ext = task_info['sen']['neuron']['nu_ext'] # rate of external Poisson neurons, prev: 12.5*Hz # synapse models VrevE = task_info['sen']['synapse']['VrevE'] # reversal potential for E synapses VrevI = task_info['sen']['synapse']['VrevI'] # reversal potential for I synapses tau_decay = task_info['sen']['synapse']['tau_decay'] # decay constants of AMPA and GABA conductances tau_rise = task_info['sen']['synapse']['tau_rise'] # rise constants of AMPA and GABA conductances # namespace with params paramsen = {'gEE': gEE, 'gEI': gEI, 'gIE': gIE, 'gII': gII, 'gmax': gmax, 'gXE': gXE, 'gXI': gXI, 'gleakE': gleakE, 'gleakI': gleakI, 'CmE': CmE, 'CmI': CmI, 'Vl': Vl, 'Vt': Vt, 'Vr': Vr, 'VrevE': VrevE, 'VrevI': VrevI, 'tau_decay': tau_decay, 'tau_rise': tau_rise, 'w_p': w_p, 'w_m': w_m, 'sub': sub, 'eps': eps, 'epsX': epsX, 'alphaX': alphaX} # numerical integration method nummethod = task_info['simulation']['nummethod'] # ------------------------------------- # Set up the model and connections # ------------------------------------- # neuron equations eqsE = ''' dV/dt = (-g_ea*(V-VrevE) - g_i*(V-VrevI) - (V-Vl)) / tau + I/Cm : volt (unless refractory) dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dg_i/dt = (-g_i + x_i) / tau_decay : 1 dx_i/dt = -x_i / tau_rise : 1 tau = CmE/gleakE : second Cm = CmE : farad I = Irec(t, i) : amp ''' eqsI = ''' dV/dt = (-g_ea*(V-VrevE) - g_i*(V-VrevI) - (V-Vl)) / tau + I/Cm : volt (unless refractory) dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dg_i/dt = (-g_i + x_i) / tau_decay : 1 dx_i/dt = -x_i / tau_rise : 1 tau = CmI/gleakI : second Cm = CmI : farad I : amp ''' # neuron groups senE = NeuronGroup(N_E, model=eqsE, method=nummethod, threshold='V>=Vt', reset='V=Vr', refractory=tau_refE, namespace=paramsen, name='senE') senE1 = senE[:N_E1] senE2 = senE[N_E1:] senI = NeuronGroup(N_I, model=eqsI, method=nummethod, threshold='V>=Vt', reset='V=Vr', refractory=tau_refI, namespace=paramsen, name='senI') # synapses # weight according the different subgroups condsame = '(i<N_pre*sub and j<N_post*sub) or (i>=N_pre*sub and j>=N_post*sub)' conddiff = '(i<N_pre*sub and j>=N_post*sub) or (i>=N_pre*sub and j<N_post*sub)' # AMPA: exc --> exc synSESE = Synapses(senE, senE, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=paramsen, name='synSESE') synSESE.connect(p='eps') synSESE.w[condsame] = 'w_p * gEE/gleakE * (1 + randn()*0.5)' synSESE.w[conddiff] = 'w_m * gEE/gleakE * (1 + randn()*0.5)' synSESE.delay = dE # AMPA: exc --> inh synSESI = Synapses(senE, senI, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=paramsen, name='synSESI') synSESI.connect(p='eps') synSESI.w = 'gEI/gleakI * (1 + randn()*0.5)' synSESI.delay = dE # GABA: inh --> exc synSISE = Synapses(senI, senE, model='w : 1', method=nummethod, on_pre='''x_i += w w = clip(w, 0, gmax)''', namespace=paramsen, name='synSISE') synSISE.connect(p='eps') synSISE.w = 'gIE/gleakE * (1 + randn()*0.5)' synSISE.delay = dI # GABA: inh --> inh synSISI = Synapses(senI, senI, model='w : 1', method=nummethod, on_pre='''x_i += w w = clip(w, 0, gmax)''', namespace=paramsen, name='synSISI') synSISI.connect(p='eps') synSISI.w = 'gII/gleakI * (1 + randn()*0.5)' synSISI.delay = dI # external inputs and synapses extS = PoissonGroup(N_X, rates=nu_ext) synSXSE = Synapses(extS, senE, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=paramsen, name='synSXSE') synSXSE.connect(condition=condsame, p='epsX * (1 + alphaX)') synSXSE.connect(condition=conddiff, p='epsX * (1 - alphaX)') synSXSE.w = 'gXE/gleakE * (1 + randn()*0.5)' synSXSE.delay = dX synSXSI = Synapses(extS, senI, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=paramsen, name='synSXSI') synSXSI.connect(p='epsX') synSXSI.w = 'gXI/gleakI * (1 + randn()*0.5)' synSXSI.delay = dX # variables to return groups = {'SE': senE, 'SI': senI, 'SX': extS} subgroups = {'SE1': senE1, 'SE2': senE2} synapses = {'synSESE': synSESE, 'synSESI': synSESI, 'synSISE': synSISE, 'synSISI': synSISI, 'synSXSI': synSXSI, 'synSXSE': synSXSE} return groups, synapses, subgroups
def mk_sencircuit_2cplastic(task_info): """ Creates balanced network representing sensory circuit with 2c model in the excitatory neurons. returns: groups, synapses, subgroups groups and synapses have to be added to the "Network" in order to run the simulation subgroups is used for establishing connections between the sensory and integration circuit; do not add subgroups to the "Network" psr following the published Brian1 code in DB model from Wimmer et al. 2015 - brain2 code - two-compartmental model following Naud & Sprekeler 2018 - implementation runs in cpp_standalone mode, compatible with SNEP """ from numpy import log as np_log # ------------------------------------- # Sensory circuit parameters # ------------------------------------- # populations N_E = task_info['sen']['populations']['N_E'] # total number of E neurons sub = task_info['sen']['populations']['sub'] # fraction corresponding to subpops 1,2 N_E1 = int(N_E * sub) # size of exc subpops that responds to the stimuli N_I = task_info['sen']['populations']['N_I'] # total number of I neurons N_X = task_info['sen']['populations']['N_X'] # size of external pop # local recurrent connections eps = task_info['sen']['connectivity']['eps'] # connection probability for EE, EI, IE and II w_p = task_info['sen']['connectivity']['w_p'] # relative synaptic strength within pop E1 and E2 w_m = 2 - w_p # relative synaptic strength across pop E1 and E2 gEEs = task_info['sen']['2c']['gEEs'] # weight of EE synapses, prev: 0.7589*nS gEI = task_info['sen']['connectivity']['gEI'] # weight of EI synapses, prev: 1.5179*nS gIEs = task_info['sen']['2c']['gIEs'] # weight of IE synapses, prev: 12.6491*nS gII = task_info['sen']['connectivity']['gII'] # weight of II synapses gmax = task_info['sen']['connectivity']['gmax'] # maximum synaptic weight dE = '0.5*ms + rand()*1.0*ms' # range of transmission delays of E synapses, (0.5:1.5) dI = '0.1*ms + rand()*0.8*ms' # range of transmission delays of I synapses, (0.1:0.9) # external connections epsX = task_info['sen']['connectivity']['epsX'] # connection probability for ext synapses alphaX = task_info['sen']['connectivity']['alphaX'] # 0: global input, 1: local input gXEs = task_info['sen']['2c']['gXEs'] # weight of ext to E synapses of soma gXI = task_info['sen']['connectivity']['gXI'] # weight of ext to I synapses dX = '0.5*ms + rand()*1.0*ms' # range of transmission delays of X synapses, (0.5:1.5) # neuron model CmI = task_info['sen']['neuron']['CmI'] # membrane capacitance of I neurons gleakI = task_info['sen']['neuron']['gleakI'] # leak conductance of I neurons Vl = task_info['sen']['neuron']['Vl'] # reversal potential Vt = task_info['sen']['neuron']['Vt'] # threshold potential Vr = task_info['sen']['neuron']['Vr'] # reset potential, only for inh tau_refI = task_info['sen']['neuron']['tau_refI'] # absolute refractory period of I neurons nu_ext = task_info['sen']['neuron']['nu_ext'] # rate of external Poisson neurons, prev: 12.5*Hz # soma taus = task_info['sen']['2c']['taus'] # timescale of membrane potential Cms = task_info['sen']['2c']['Cms'] # capacitance gleakEs = Cms/taus tauws = task_info['sen']['2c']['tauws'] # timescale of recovery ("slow") variable bws = task_info['sen']['2c']['bws'] # strength of spike-triggered facilitation (bws < 0) gCas = task_info['sen']['2c']['gCas'] # strenght of forward calcium spike propagation tau_refE = task_info['sen']['2c']['tau_refE'] # refractory period # dendrite taud = task_info['sen']['2c']['taud'] Cmd = task_info['sen']['2c']['Cmd'] gleakEd = Cmd/taud tauwd = task_info['sen']['2c']['tauwd'] # timescale of recovery ("slow") variable awd = task_info['sen']['2c']['awd'] # stregth of subthreshold facilitations (awd < 0) gCad = task_info['sen']['2c']['gCad'] # strength of local regenerative activity bpA = task_info['sen']['2c']['bpA'] # strength of backpropagation activity (c variable) k1 = task_info['sen']['2c']['k1'] # rectangular kernel for backpropagating activity k2 = task_info['sen']['2c']['k2'] # if t in [0.5, 2.0] we'll have backpropagating current muOUs = task_info['sen']['2c']['muOUs'] # OU parameters for background noise of soma #muOUd = task_info['sen']['2c']['muOUd'] # OU parameters for background noise of dendrites sigmaOU = task_info['sen']['2c']['sigmaOU'] tauOU = task_info['sen']['2c']['tauOU'] # synapse models VrevE = task_info['sen']['synapse']['VrevE'] # reversal potential for E synapses VrevI = task_info['sen']['synapse']['VrevI'] # reversal potential for I synapses in inh tau_decay = task_info['sen']['synapse']['tau_decay'] # decay constant of AMPA, GABA tau_rise = task_info['sen']['synapse']['tau_rise'] # rise constant of AMPA, GABA for inh VrevIsd = task_info['sen']['synapse']['VrevIsd'] # rev potential for I synapses in soma, dend # plasticity in dendrites eta0 = task_info['sen']['2c']['eta0'] tauB = task_info['sen']['2c']['tauB'] targetB = task_info['targetB'] B0 = tauB*targetB tau_update = task_info['sen']['2c']['tau_update'] eta = eta0 * tau_update / tauB validburst = task_info['sen']['2c']['validburst'] # if tau_burst = 4*ms, at 16 ms stopburst = 0.0183 min_burst_stop = task_info['sen']['2c']['min_burst_stop'] # thus, we will set it at critrefburst = 0.02 tau_burst = -validburst / np_log(min_burst_stop) * second param2c = {'gEE': gEEs, 'gEI': gEI, 'gIE': gIEs, 'gII': gII, 'gmax': gmax, 'gXEs': gXEs, 'gXI': gXI, 'gleakEs': gleakEs, 'gleakEd': gleakEd, 'gleakI': gleakI, 'Cms': Cms, 'Cmd': Cmd, 'CmI': CmI, 'Vl': Vl, 'Vt': Vt, 'Vr': Vr, 'VrevE': VrevE, 'VrevIsd': VrevIsd, 'VrevI': VrevI, 'taus': taus, 'taud': taud, 'tau_refE': tau_refE, 'tau_refI': tau_refI, 'tau_decay': tau_decay, 'tau_rise': tau_rise, 'tau_ws': tauws, 'tau_wd': tauwd, 'bws': bws, 'awd': awd, 'gCas': gCas, 'gCad': gCad, 'bpA': bpA, 'k1': k1, 'k2': k2, 'muOUs': muOUs, 'tauOU': tauOU, 'sigmaOU': sigmaOU, 'w_p': w_p, 'w_m': w_m, 'sub': sub, 'eps': eps, 'epsX': epsX, 'alphaX': alphaX, 'eta': eta, 'B0': B0, 'tauB': tauB, 'tau_burst': tau_burst, 'min_burst_stop': min_burst_stop} # numerical integration method nummethod = task_info['simulation']['nummethod'] # ------------------------------------- # Set up model and connections # ------------------------------------- # neuron equations eqss = ''' dV/dt = (-g_ea*(V-VrevE) -g_i*(V-VrevIsd) -(V-Vl))/tau + (gCas/(1+exp(-(V_d/mV + 38)/6)) + w_s + I)/Cm : volt (unless refractory) dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dg_i/dt = (-g_i + x_i) / tau_decay : 1 dx_i/dt = -x_i / tau_rise : 1 dw_s/dt = -w_s / tau_ws : amp tau = taus : second Cm = Cms : farad I = Irec(t, i) : amp V_d : volt (linked) B : 1 (linked) burst_start : 1 (linked) burst_stop : 1 (linked) muOUd : amp (linked) ''' # dIbg/dt = (muOUs - Ibg) / tauOU + (sigmaOU * xi) / sqrt(tauOU / 2) : amp --> they have I_Ext eqsd = ''' dV_d/dt = (-g_ea*(V_d-VrevE) -(V_d-Vl))/tau + (gCad/(1+exp(-(V_d/mV + 38)/6)) + w_d + K + Ibg)/Cm : volt dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dw_d/dt = (-w_d + awd*(V_d - Vl))/tau_wd : amp dIbg/dt = (muOUd - Ibg) / tauOU + (sigmaOU * xi) / sqrt(tauOU / 2) : amp K = bpA * (((t-lastspike_soma) >= k1) * ((t-lastspike_soma) <= k2)) : amp dB/dt = -B / tauB : 1 dburst_start/dt = -burst_start / tau_burst : 1 (unless refractory) dburst_stop/dt = -burst_stop / tau_burst : 1 tau = taud : second Cm = Cmd : farad muOUd : amp lastspike_soma : second (linked) ''' eqsI = ''' dV/dt = (-g_ea*(V-VrevE) -g_i*(V-VrevI) -(V-Vl))/tau + I/Cm : volt (unless refractory) dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dg_i/dt = (-g_i + x_i) / tau_decay : 1 dx_i/dt = -x_i / tau_rise : 1 tau = CmI/gleakI : second Cm = CmI : farad I : amp ''' # neuron groups soma = NeuronGroup(N_E, model=eqss, method=nummethod, threshold='V>=Vt', reset='''V = Vl w_s += bws burst_start += 1 burst_stop = 1''', refractory=tau_refE, namespace=param2c, name='soma') dend = NeuronGroup(N_E, model=eqsd, method=nummethod, threshold='burst_start > 1 + min_burst_stop', reset='''B += 1 burst_start = 0''', refractory='burst_stop >= min_burst_stop', namespace=param2c, name='dend') senI = NeuronGroup(N_I, model=eqsI, method=nummethod, threshold='V>=Vt', reset='V=Vr', refractory=tau_refI, namespace=param2c, name='senI') # linked variables soma.V_d = linked_var(dend, 'V_d') soma.B = linked_var(dend, 'B') soma.burst_start = linked_var(dend, 'burst_start') soma.burst_stop = linked_var(dend, 'burst_stop') soma.muOUd = linked_var(dend, 'muOUd') dend.lastspike_soma = linked_var(soma, 'lastspike') # subgroups soma1 = soma[:N_E1] dend1 = dend[:N_E1] soma2 = soma[N_E1:] dend2 = dend[N_E1:] # update muOUd with plasticity rule dend1.muOUd = '-50*pA - rand()*100*pA' # random initialisation of weights -50:-150 pA dend1.run_regularly('muOUd = clip(muOUd - eta * (B - B0), -100*amp, 0)', dt=tau_update) # TODO: check the target vs burst rate convergence # TODO: try tau_B = 50,000 sec, but mayb\e this is not the case because you do reach the target # synapses # weight according the different subgroups condsame = '(i<N_pre*sub and j<N_post*sub) or (i>=N_pre*sub and j>=N_post*sub)' conddiff = '(i<N_pre*sub and j>=N_post*sub) or (i>=N_pre*sub and j<N_post*sub)' # AMPA: exc --> exc synSESE = Synapses(soma, soma, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSESE') synSESE.connect(p='eps') synSESE.w[condsame] = 'w_p * gEE/gleakEs * (1 + randn()*0.5)' synSESE.w[conddiff] = 'w_m * gEE/gleakEs * (1 + randn()*0.5)' synSESE.delay = dE # AMPA: exc --> inh synSESI = Synapses(soma, senI, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSESI') synSESI.connect(p='eps') synSESI.w = 'gEI/gleakI * (1 + randn()*0.5)' synSESI.delay = dE # GABA: inh --> exc synSISE = Synapses(senI, soma, model='w : 1', method=nummethod, on_pre='''x_i += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSISE') synSISE.connect(p='eps') synSISE.w = 'gIE/gleakEs * (1 + randn()*0.5)' synSISE.delay = dI # GABA: inh --> inh synSISI = Synapses(senI, senI, model='w : 1', method=nummethod, on_pre='''x_i += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSISI') synSISI.connect(p='eps') synSISI.w = 'gII/gleakI * (1 + randn()*0.5)' synSISI.delay = dI # external inputs and synapses extS = PoissonGroup(N_X, rates=nu_ext) synSXSEs = Synapses(extS, soma, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSXSEs') synSXSEs.connect(condition=condsame, p='epsX * (1 + alphaX)') synSXSEs.connect(condition=conddiff, p='epsX * (1 - alphaX)') synSXSEs.w = 'gXEs/gleakEs * (1 + randn()*0.5)' synSXSEs.delay = dX synSXSI = Synapses(extS, senI, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSXSI') synSXSI.connect(p='epsX') synSXSI.w = 'gXI/gleakI * (1 + randn()*0.5)' synSXSI.delay = dX # external inputs to dendrites mimicking decision circuit subDE = 240 rateDE = 40*Hz # TODO: lower rate --> 40 or 30 d = 1*ms wDS = 0.06 XDE = PoissonGroup(subDE, rates=rateDE) synXDEdend = Synapses(XDE, dend1, model='w : 1', method=nummethod, delay=d, on_pre='x_ea += w', namespace=param2c, name='synXDEdend') synXDEdend.connect(p=0.2) synXDEdend.w = 'wDS' # variables to return groups = {'soma': soma, 'dend': dend, 'SI': senI, 'SX': extS, 'XDE': XDE} subgroups = {'soma1': soma1, 'soma2': soma2, 'dend1': dend1, 'dend2': dend2} synapses = {'synSESE': synSESE, 'synSESI': synSESI, 'synSISE': synSISE, 'synSISI': synSISI, 'synSXSI': synSXSI, 'synSXSEs': synSXSEs, 'synXDEdend': synXDEdend} return groups, synapses, subgroups
def mk_sencircuit_2c(task_info): """ Creates balanced network representing sensory circuit with 2c model in the excitatory neurons. returns: groups, synapses, subgroups groups and synapses have to be added to the "Network" in order to run the simulation subgroups is used for establishing connections between the sensory and integration circuit; do not add subgroups to the "Network" psr following the published Brian1 code in DB model from Wimmer et al. 2015 - brain2 code - two-compartmental model following Naud & Sprekeler 2018 - implementation runs in cpp_standalone mode, compatible with SNEP """ # ------------------------------------- # Sensory circuit parameters # ------------------------------------- # populations N_E = task_info['sen']['populations']['N_E'] # total number of E neurons sub = task_info['sen']['populations']['sub'] # fraction corresponding to subpops 1,2 N_E1 = int(N_E * sub) # size of exc subpops that responds to the stimuli N_I = task_info['sen']['populations']['N_I'] # total number of I neurons N_X = task_info['sen']['populations']['N_X'] # size of external pop # local recurrent connections eps = task_info['sen']['connectivity']['eps'] # connection probability for EE, EI, IE and II w_p = task_info['sen']['connectivity']['w_p'] # relative synaptic strength within pop E1 and E2 w_m = 2 - w_p # relative synaptic strength across pop E1 and E2 gEEs = task_info['sen']['2c']['gEEs'] # weight of EE synapses, prev: 0.7589*nS gEI = task_info['sen']['connectivity']['gEI'] # weight of EI synapses, prev: 1.5179*nS gIEs = task_info['sen']['2c']['gIEs'] # weight of IE synapses, prev: 12.6491*nS gII = task_info['sen']['connectivity']['gII'] # weight of II synapses gmax = task_info['sen']['connectivity']['gmax'] # maximum synaptic weight dE = '0.5*ms + rand()*1.0*ms' # range of transmission delays of E synapses, (0.5:1.5) dI = '0.1*ms + rand()*0.8*ms' # range of transmission delays of I synapses, (0.1:0.9) # external connections epsX = task_info['sen']['connectivity']['epsX'] # connection probability for ext synapses alphaX = task_info['sen']['connectivity']['alphaX'] # 0: global input, 1: local input gXEs = task_info['sen']['2c']['gXEs'] # weight of ext to E synapses of soma gXI = task_info['sen']['connectivity']['gXI'] # weight of ext to I synapses dX = '0.5*ms + rand()*1.0*ms' # range of transmission delays of X synapses, (0.5:1.5) # neuron model CmI = task_info['sen']['neuron']['CmI'] # membrane capacitance of I neurons gleakI = task_info['sen']['neuron']['gleakI'] # leak conductance of I neurons Vl = task_info['sen']['neuron']['Vl'] # reversal potential Vt = task_info['sen']['neuron']['Vt'] # threshold potential Vr = task_info['sen']['neuron']['Vr'] # reset potential, only for inh tau_refI = task_info['sen']['neuron']['tau_refI'] # absolute refractory period of I neurons nu_ext = task_info['sen']['neuron']['nu_ext'] # rate of external Poisson neurons, prev: 12.5*Hz # soma taus = task_info['sen']['2c']['taus'] # timescale of membrane potential Cms = task_info['sen']['2c']['Cms'] # capacitance gleakEs = Cms/taus tauws = task_info['sen']['2c']['tauws'] # timescale of recovery ("slow") variable bws = task_info['sen']['2c']['bws'] # strength of spike-triggered facilitation (bws < 0) gCas = task_info['sen']['2c']['gCas'] # strenght of forward calcium spike propagation tau_refE = task_info['sen']['2c']['tau_refE'] # refractory period # dendrite taud = task_info['sen']['2c']['taud'] Cmd = task_info['sen']['2c']['Cmd'] gleakEd = Cmd/taud tauwd = task_info['sen']['2c']['tauwd'] # timescale of recovery ("slow") variable awd = task_info['sen']['2c']['awd'] # stregth of subthreshold facilitations (awd < 0) gCad = task_info['sen']['2c']['gCad'] # strength of local regenerative activity bpA = task_info['sen']['2c']['bpA'] # strength of backpropagation activity (c variable) k1 = task_info['sen']['2c']['k1'] # rectangular kernel for backpropagating activity k2 = task_info['sen']['2c']['k2'] # if t in [0.5, 2.0] we'll have backpropagating current muOUd = task_info['sen']['2c']['muOUd'] # OU parameters for background noise of dendrites sigmaOU = task_info['sen']['2c']['sigmaOU'] tauOU = task_info['sen']['2c']['tauOU'] # synapse models VrevE = task_info['sen']['synapse']['VrevE'] # reversal potential for E synapses VrevI = task_info['sen']['synapse']['VrevI'] # reversal potential for I synapses in inh tau_decay = task_info['sen']['synapse']['tau_decay'] # decay constant of AMPA, GABA tau_rise = task_info['sen']['synapse']['tau_rise'] # rise constant of AMPA, GABA for inh VrevIsd = task_info['sen']['synapse']['VrevIsd'] # rev potential for I synapses in soma, dend #tau_decayE = task_info['sen']['synapse']['tau_decaysd'] # rise constants of AMPA conductances # in Wimmer are decayE = decayI = 5, Naud decayE = 1, decayI = 5 ! # TODO: try both approaches and decide which one to use. param2c = {'gEE': gEEs, 'gEI': gEI, 'gIE': gIEs, 'gII': gII, 'gmax': gmax, 'gXEs': gXEs, 'gXI': gXI, 'gleakEs': gleakEs, 'gleakEd': gleakEd, 'gleakI': gleakI, 'Cms': Cms, 'Cmd': Cmd, 'CmI': CmI, 'Vl': Vl, 'Vt': Vt, 'Vr': Vr, 'VrevE': VrevE, 'VrevIsd': VrevIsd, 'VrevI': VrevI, 'taus': taus, 'taud': taud, 'tau_refE': tau_refE, 'tau_refI': tau_refI, 'tau_decay': tau_decay, 'tau_rise': tau_rise, 'tau_ws': tauws, 'tau_wd': tauwd, 'bws': bws, 'awd': awd, 'gCas': gCas, 'gCad': gCad, 'bpA': bpA, 'k1': k1, 'k2': k2, 'muOUd': muOUd, 'tauOU': tauOU, 'sigmaOU': sigmaOU, 'w_p': w_p, 'w_m': w_m, 'sub': sub, 'eps': eps, 'epsX': epsX, 'alphaX': alphaX} # numerical integration method nummethod = task_info['simulation']['nummethod'] # ------------------------------------- # Set up model and connections # ------------------------------------- # neuron equations eqss = ''' dV/dt = (-g_ea*(V-VrevE) -g_i*(V-VrevIsd) -(V-Vl))/tau + (gCas/(1+exp(-(V_d/mV + 38)/6)) + w_s + I)/Cm : volt (unless refractory) dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dg_i/dt = (-g_i + x_i) / tau_decay : 1 dx_i/dt = -x_i / tau_rise : 1 dw_s/dt = -w_s / tau_ws : amp tau = taus : second Cm = Cms : farad I = Irec(t, i) : amp V_d : volt (linked) ''' eqsd = ''' dV_d/dt = (-g_ea*(V_d-VrevE) -(V_d-Vl))/tau + (gCad/(1+exp(-(V_d/mV + 38)/6)) + w_d + K + Ibg)/Cm : volt dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dw_d/dt = (-w_d + awd*(V_d - Vl))/tau_wd : amp dIbg/dt = (muOUd - Ibg) / tauOU + (sigmaOU * xi) / sqrt(tauOU / 2) : amp K = bpA * (((t-lastspike_soma) >= k1) * ((t-lastspike_soma) <= k2)) : amp tau = taud : second Cm = Cmd : farad muOUd : amp lastspike_soma : second (linked) ''' eqsI = ''' dV/dt = (-g_ea*(V-VrevE) -g_i*(V-VrevI) -(V-Vl))/tau + I/Cm : volt (unless refractory) dg_ea/dt = (-g_ea + x_ea) / tau_decay : 1 dx_ea/dt = -x_ea / tau_rise : 1 dg_i/dt = (-g_i + x_i) / tau_decay : 1 dx_i/dt = -x_i / tau_rise : 1 tau = CmI/gleakI : second Cm = CmI : farad I : amp ''' # neuron groups soma = NeuronGroup(N_E, model=eqss, method=nummethod, threshold='V>=Vt', reset='''V = Vl w_s += bws''', refractory=tau_refE, namespace=param2c, name='soma') dend = NeuronGroup(N_E, model=eqsd, method=nummethod, namespace=param2c, name='dend') senI = NeuronGroup(N_I, model=eqsI, method=nummethod, threshold='V>=Vt', reset='V=Vr', refractory=tau_refI, namespace=param2c, name='senI') # linked variables soma.V_d = linked_var(dend, 'V_d') dend.lastspike_soma = linked_var(soma, 'lastspike') # subgroups soma1 = soma[:N_E1] dend1 = dend[:N_E1] soma2 = soma[N_E1:] dend2 = dend[N_E1:] # synapses # weight according the different subgroups condsame = '(i<N_pre*sub and j<N_post*sub) or (i>=N_pre*sub and j>=N_post*sub)' conddiff = '(i<N_pre*sub and j>=N_post*sub) or (i>=N_pre*sub and j<N_post*sub)' # AMPA: exc --> exc synSESE = Synapses(soma, soma, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSESE') synSESE.connect(p='eps') synSESE.w[condsame] = 'w_p * gEE/gleakEs * (1 + randn()*0.5)' synSESE.w[conddiff] = 'w_m * gEE/gleakEs * (1 + randn()*0.5)' synSESE.delay = dE # AMPA: exc --> inh synSESI = Synapses(soma, senI, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSESI') synSESI.connect(p='eps') synSESI.w = 'gEI/gleakI * (1 + randn()*0.5)' synSESI.delay = dE # GABA: inh --> exc synSISE = Synapses(senI, soma, model='w : 1', method=nummethod, on_pre='''x_i += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSISE') synSISE.connect(p='eps') synSISE.w = 'gIE/gleakEs * (1 + randn()*0.5)' synSISE.delay = dI # GABA: inh --> inh synSISI = Synapses(senI, senI, model='w : 1', method=nummethod, on_pre='''x_i += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSISI') synSISI.connect(p='eps') synSISI.w = 'gII/gleakI * (1 + randn()*0.5)' synSISI.delay = dI # external inputs and synapses extS = PoissonGroup(N_X, rates=nu_ext) synSXSEs = Synapses(extS, soma, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSXSEs') synSXSEs.connect(condition=condsame, p='epsX * (1 + alphaX)') synSXSEs.connect(condition=conddiff, p='epsX * (1 - alphaX)') synSXSEs.w = 'gXEs/gleakEs * (1 + randn()*0.5)' synSXSEs.delay = dX synSXSI = Synapses(extS, senI, model='w : 1', method=nummethod, on_pre='''x_ea += w w = clip(w, 0, gmax)''', namespace=param2c, name='synSXSI') synSXSI.connect(p='epsX') synSXSI.w = 'gXI/gleakI * (1 + randn()*0.5)' synSXSI.delay = dX # variables to return groups = {'soma': soma, 'dend': dend, 'SI': senI, 'SX': extS} subgroups = {'soma1': soma1, 'soma2': soma2, 'dend1': dend1, 'dend2': dend2} synapses = {'synSESE': synSESE, 'synSESI': synSESI, 'synSISE': synSISE, 'synSISI': synSISI, 'synSXSI': synSXSI, 'synSXSEs': synSXSEs} return groups, synapses, subgroups
def mk_intcircuit(task_info): """ Creates the 'winner-takes-all' network described in Wang 2002. returns: groups, synapses, update_nmda, subgroups groups, synapses and update_nmda have to be added to the "Network" in order to run the simulation subgroups is used for establishing connections between the sensory and integration circuit; do not add subgroups to the "Network" psr following the published Brian1 code in DB model from Wimmer et al. 2015 - brian2 code - PoissonInput for external connections - no more network_operations - implementation runs in cpp_standalone mode, compatible with SNEP """ # ------------------------------------- # Decision circuit parameters # ------------------------------------- # populations N_E = task_info['dec']['populations'][ 'N_E'] # number of exc neurons (1600) N_I = task_info['dec']['populations']['N_I'] # number of inh neurons (400) sub = task_info['dec']['populations'][ 'sub'] # fraction of stim-selective exc neurons N_D1 = int(N_E * sub) # size of exc pop D1 N_D2 = N_D1 # size of exc pop D2 N_D3 = int(N_E * (1 - 2 * sub)) # size of exc pop D3, the rest # local recurrent connections w_p = task_info['dec']['connectivity'][ 'w_p'] # relative synaptic strength of synapses within pop D1 and D2 w_m = 1 - sub * (w_p - 1) / ( 1 - sub) # relative synaptic strength of synapses across pop D1 and D2 gEEa = task_info['dec']['connectivity'][ 'gEEa'] # AMPA weight of EE synapses gEEn = task_info['dec']['connectivity'][ 'gEEn'] # NMDA weight of EE synapses gEIa = task_info['dec']['connectivity'][ 'gEIa'] # AMPA weight of EI synapses gEIn = task_info['dec']['connectivity'][ 'gEIn'] # NMDA weight of EI synapses gIE = task_info['dec']['connectivity'][ 'gIE'] # GABA weight of IE synapses, vs 1.3*nS from before gII = task_info['dec']['connectivity']['gII'] # GABA weight of II synapses d = task_info['dec']['connectivity'][ 'delay'] # transmission delays of E synapses # external connections gXE = task_info['dec']['connectivity'][ 'gXE'] # weight of XE (ext to exc) synapses gXI = task_info['dec']['connectivity'][ 'gXI'] # weight of XI (ext to inh) synapses # neuron models CmE = task_info['dec']['neuron'][ 'CmE'] # membrane capacitance of E neurons CmI = task_info['dec']['neuron'][ 'CmI'] # membrane capacitance of I neurons gleakE = task_info['dec']['neuron'][ 'gleakE'] # leak conductance of E neurons gleakI = task_info['dec']['neuron'][ 'gleakI'] # leak conductance of I neurons Vl = task_info['dec']['neuron']['Vl'] # resting potential Vt = task_info['dec']['neuron']['Vt'] # spiking threshold Vr = task_info['dec']['neuron']['Vr'] # reset potential tau_refE = task_info['dec']['neuron'][ 'tau_refE'] # absolute refractory period of E neurons tau_refI = task_info['dec']['neuron'][ 'tau_refI'] # absolute refractory period of I neurons nu_ext = task_info['dec']['neuron'][ 'nu_ext'] # firing rate of ext Poisson input to D1 and D2 nu_ext1 = task_info['dec']['neuron'][ 'nu_ext1'] # firing rate of ext Poisson input to D3 and DI # synapse models VrevE = task_info['dec']['synapse'][ 'VrevE'] # reversal potential for E synapses VrevI = task_info['dec']['synapse'][ 'VrevI'] # reversal potential for I synapses tau_ampa = task_info['dec']['synapse'][ 'tau_ampa'] # decay constant of AMPA conductances tau_gaba = task_info['dec']['synapse'][ 'tau_gaba'] # decay constant of GABA conductances tau_nmda_d = task_info['dec']['synapse'][ 'tau_nmda_d'] # decay constant of NMDA conductances tau_nmda_r = task_info['dec']['synapse'][ 'tau_nmda_r'] # rise constant of NMDA conductances alpha_nmda = task_info['dec']['synapse'][ 'alpha_nmda'] # saturation constant of NMDA conductances # namespace with params paramint = { 'w_p': w_p, 'w_m': w_m, 'gEEa': gEEa, 'gEEn': gEEn, 'gEIa': gEIa, 'gEIn': gEIn, 'gIE': gIE, 'gII': gII, 'gXE': gXE, 'gXI': gXI, 'gleakE': gleakE, 'gleakI': gleakI, 'Vl': Vl, 'Vt': Vt, 'Vr': Vr, 'VrevE': VrevE, 'VrevI': VrevI, 'tau_ampa': tau_ampa, 'tau_gaba': tau_gaba, 'tau_nmda_d': tau_nmda_d, 'tau_nmda_r': tau_nmda_r, 'alpha_nmda': alpha_nmda, 'sub': sub, 'CmE': CmE, 'CmI': CmI } # numerical integration method nummethod = task_info['simulation']['nummethod'] # ------------------------------------- # Set up the model and connections # ------------------------------------- # neuron equations eqsE = ''' dV/dt = (-g_ea*(V-VrevE) - g_ent*(V-VrevE)/(1+exp(-V/mV*0.062)/3.57) - g_i*(V-VrevI) - (V-Vl)) / tau : volt (unless refractory) dg_ea/dt = -g_ea / tau_ampa : 1 dg_i/dt = -g_i / tau_gaba : 1 dg_en/dt = -g_en / tau_nmda_d + alpha_nmda * x_en *(1-g_en) : 1 dx_en/dt = -x_en / tau_nmda_r : 1 g_ent : 1 tau = CmE/gleakE : second label : integer (constant) ''' eqsI = ''' dV/dt = (-g_ea*(V-VrevE) - g_entI*(V-VrevE)/(1+exp(-V/mV*0.062)/3.57) - g_i*(V-VrevI) - (V-Vl)) / tau : volt (unless refractory) dg_ea/dt = -g_ea/tau_ampa : 1 dg_i/dt = -g_i/tau_gaba : 1 g_entI = w_nmda * g_ent : 1 g_ent : 1 (linked) w_nmda : 1 tau = CmI/gleakI : second ''' # setup of integration circuit decE = NeuronGroup(N_E, model=eqsE, method=nummethod, threshold='V>=Vt', reset='V=Vr', refractory=tau_refE, namespace=paramint, name='decE') decE1 = decE[:N_D1] decE2 = decE[N_D1:N_D1 + N_D2] decE3 = decE[-N_D3:] decE1.label = 1 decE2.label = 2 decE3.label = 3 decI = NeuronGroup(N_I, model=eqsI, method=nummethod, threshold='V>=Vt', reset='V=Vr', refractory=tau_refI, namespace=paramint, name='decI') # weight according the different subgroups condsame = '(label_pre == label_post and label_pre != 3)' conddiff = '(label_pre != label_post and label_pre != 3) or (label_pre == 3 and label_post != 3)' condrest = '(label_post == 3)' # NMDA: exc --> exc eqsNMDA = ''' g_ent_post = w_nmda * g_en_pre : 1 (summed) w_nmda : 1 (constant) w : 1 (constant) ''' synDEDEn = Synapses(decE, decE, model=eqsNMDA, method=nummethod, on_pre='x_en += w', delay=d, namespace=paramint, name='synDEDEn') synDEDEn.connect() synDEDEn.w['i == j'] = 1 synDEDEn.w['i != j'] = 0 synDEDEn.w_nmda[condsame] = 'w_p * gEEn/gleakE' synDEDEn.w_nmda[conddiff] = 'w_m * gEEn/gleakE' synDEDEn.w_nmda[condrest] = 'gEEn/gleakE' # NMDA: exc --> inh decI.w_nmda = '(gEIn/gleakI) / (gEEn/gleakE)' decI.g_ent = linked_var(decE3, 'g_ent', index=range(N_I)) # AMPA: exc --> exc synDEDEa = Synapses(decE, decE, model='w : 1', method=nummethod, on_pre='g_ea += w', delay=d, namespace=paramint, name='synDEDEa') synDEDEa.connect() synDEDEa.w[condsame] = 'w_p * gEEa/gleakE' synDEDEa.w[conddiff] = 'w_m * gEEa/gleakE' synDEDEa.w[condrest] = 'gEEa/gleakE' # AMPA: exc --> inh synDEDIa = Synapses(decE, decI, model='w : 1', method=nummethod, on_pre='g_ea += w', delay=d, namespace=paramint, name='synDEDIa') synDEDIa.connect() synDEDIa.w = 'gEIa/gleakI' # GABA: inh --> exc synDIDE = Synapses(decI, decE, model='w : 1', method=nummethod, on_pre='g_i += w', delay=d, namespace=paramint, name='synDIDE') synDIDE.connect() synDIDE.w = 'gIE/gleakE' # GABA: inh --> inh synDIDI = Synapses(decI, decI, model='w : 1', method=nummethod, on_pre='g_i += w', delay=d, namespace=paramint, name='synDIDI') synDIDI.connect() synDIDI.w = 'gII/gleakI' # external inputs and connections extE = PoissonInput(decE[:N_D1 + N_D2], 'g_ea', N=1, rate=nu_ext1, weight='gXE/gleakE') extE3 = PoissonInput(decE3, 'g_ea', N=1, rate=nu_ext, weight='gXE/gleakE') extI = PoissonInput(decI, 'g_ea', N=1, rate=nu_ext, weight='gXI/gleakI') # variables to return groups = {'DE': decE, 'DI': decI, 'DX': extE, 'DX3': extE3, 'DXI': extI} subgroups = {'DE1': decE1, 'DE2': decE2, 'DE3': decE3} synapses = { 'synDEDEn': synDEDEn, 'synDEDEa': synDEDEa, 'synDEDIa': synDEDIa, 'synDIDE': synDIDE, 'synDIDI': synDIDI } # 'synDEDIn': synDEDIn, return groups, synapses, subgroups
def run_task_hierarchical(task_info, taskdir, tempdir): # imports from brian2 import defaultclock, set_device, seed, TimedArray, Network, profiling_summary from brian2.monitors import SpikeMonitor, PopulationRateMonitor, StateMonitor from brian2.synapses import Synapses from brian2.core.magic import start_scope from brian2.units import second, ms, amp from integration_circuit import mk_intcircuit from sensory_circuit import mk_sencircuit, mk_sencircuit_2c, mk_sencircuit_2cplastic from burstQuant import spks2neurometric from scipy import interpolate # if you want to put something in the taskdir, you must create it first os.mkdir(taskdir) print(taskdir) # parallel code and flag to start set_device('cpp_standalone', directory=tempdir) #prefs.devices.cpp_standalone.openmp_threads = max_tasks start_scope() # simulation parameters seedcon = task_info['simulation']['seedcon'] runtime = task_info['simulation']['runtime'] runtime_ = runtime / second settletime = task_info['simulation']['settletime'] settletime_ = settletime / second stimon = task_info['simulation']['stimon'] stimoff = task_info['simulation']['stimoff'] stimoff_ = stimoff / second stimdur = stimoff - stimon smoothwin = task_info['simulation']['smoothwin'] nummethod = task_info['simulation']['nummethod'] # ------------------------------------- # Construct hierarchical network # ------------------------------------- # set connection seed seed( seedcon ) # set specific seed to test the same network, this way we also have the same synapses! # decision circuit Dgroups, Dsynapses, Dsubgroups = mk_intcircuit(task_info) decE = Dgroups['DE'] decI = Dgroups['DI'] decE1 = Dsubgroups['DE1'] decE2 = Dsubgroups['DE2'] # sensory circuit, ff and fb connections eps = 0.2 # connection probability d = 1 * ms # transmission delays of E synapses if task_info['simulation']['2cmodel']: if task_info['simulation']['plasticdend']: # plasticity rule in dendrites --> FB synapses will be removed from the network! Sgroups, Ssynapses, Ssubgroups = mk_sencircuit_2cplastic(task_info) else: # 2c model (Naud) Sgroups, Ssynapses, Ssubgroups = mk_sencircuit_2c(task_info) senE = Sgroups['soma'] dend = Sgroups['dend'] senI = Sgroups['SI'] senE1 = Ssubgroups['soma1'] senE2 = Ssubgroups['soma2'] dend1 = Ssubgroups['dend1'] dend2 = Ssubgroups['dend2'] # FB wDS = 0.003 # synaptic weight of FB synapses, 0.0668 nS when scaled by gleakE of sencircuit_2c synDE1SE1 = Synapses(decE1, dend1, model='w : 1', method=nummethod, on_pre='x_ea += w', delay=d) synDE2SE2 = Synapses(decE2, dend2, model='w : 1', method=nummethod, on_pre='x_ea += w', delay=d) else: # normal sensory circuit (Wimmer) Sgroups, Ssynapses, Ssubgroups = mk_sencircuit(task_info) senE = Sgroups['SE'] senI = Sgroups['SI'] senE1 = Ssubgroups['SE1'] senE2 = Ssubgroups['SE2'] # FB wDS = 0.004 # synaptic weight of FB synapses, 0.0668 nS when scaled by gleakE of sencircuit synDE1SE1 = Synapses(decE1, senE1, model='w : 1', method=nummethod, on_pre='x_ea += w', delay=d) synDE2SE2 = Synapses(decE2, senE2, model='w : 1', method=nummethod, on_pre='x_ea += w', delay=d) # feedforward synapses from sensory to integration wSD = 0.0036 # synaptic weight of FF synapses, 0.09 nS when scaled by gleakE of intcircuit synSE1DE1 = Synapses(senE1, decE1, model='w : 1', method=nummethod, on_pre='g_ea += w', delay=d) synSE1DE1.connect(p='eps') synSE1DE1.w = 'wSD' synSE2DE2 = Synapses(senE2, decE2, model='w : 1', method=nummethod, on_pre='g_ea += w', delay=d) synSE2DE2.connect(p='eps') synSE2DE2.w = 'wSD' # feedback synapses from integration to sensory b_fb = task_info['bfb'] # feedback strength, between 0 and 6 wDS *= b_fb # synaptic weight of FB synapses, 0.0668 nS when scaled by gleakE of sencircuit synDE1SE1.connect(p='eps') synDE1SE1.w = 'wDS' synDE2SE2.connect(p='eps') synDE2SE2.w = 'wDS' # ------------------------------------- # Create stimuli # ------------------------------------- if task_info['stimulus']['replicate']: # replicated stimuli across iters() np.random.seed(task_info['seed']) # numpy seed for OU process else: # every trials has different stimuli np.random.seed() # Note that in standalone we need to specify np seed because it's not taken care with Brian's seed() function! if task_info['simulation']['2cmodel']: I0 = task_info['stimulus']['I0s'] last_muOUd = np.loadtxt("last_muOUd.csv") # save the mean else: I0 = task_info['stimulus'][ 'I0'] # mean input current for zero-coherence stim c = task_info['c'] # stim coherence (between 0 and 1) mu1 = task_info['stimulus'][ 'mu1'] # av. additional input current to senE1 at highest coherence (c=1) mu2 = task_info['stimulus'][ 'mu2'] # av. additional input current to senE2 at highest coherence (c=1) sigma = task_info['stimulus'][ 'sigma'] # amplitude of temporal modulations of stim sigmastim = 0.212 * sigma # std of modulation of stim inputs sigmaind = 0.212 * sigma # std of modulations in individual inputs taustim = task_info['stimulus'][ 'taustim'] # correlation time constant of Ornstein-Uhlenbeck process # generate stim from OU process N_stim = int(senE1.__len__()) z1, z2, zk1, zk2 = generate_stim(N_stim, stimdur, taustim) # stim2exc i1 = I0 * (1 + c * mu1 + sigmastim * z1 + sigmaind * zk1) i2 = I0 * (1 + c * mu2 + sigmastim * z2 + sigmaind * zk2) stim_dt = 1 * ms i1t = np.concatenate((np.zeros((int(stimon / ms), N_stim)), i1.T, np.zeros((int( (runtime - stimoff) / stim_dt), N_stim))), axis=0) i2t = np.concatenate((np.zeros((int(stimon / ms), N_stim)), i2.T, np.zeros((int( (runtime - stimoff) / stim_dt), N_stim))), axis=0) Irec = TimedArray(np.concatenate((i1t, i2t), axis=1) * amp, dt=stim_dt) # ------------------------------------- # Simulation # ------------------------------------- # set initial conditions (different for evert trial) seed() decE.g_ea = '0.2 * rand()' decI.g_ea = '0.2 * rand()' decE.V = '-52*mV + 2*mV * rand()' decI.V = '-52*mV + 2*mV * rand()' # random initialization near 0, prevent an early decision! senE.g_ea = '0.05 * (1 + 0.2*rand())' senI.g_ea = '0.05 * (1 + 0.2*rand())' senE.V = '-52*mV + 2*mV*rand()' # random initialization near Vt, avoid initial bump! senI.V = '-52*mV + 2*mV*rand()' if task_info['simulation']['2cmodel']: dend.g_ea = '0.05 * (1 + 0.2*rand())' dend.V_d = '-72*mV + 2*mV*rand()' dend.muOUd = np.tile(last_muOUd, 2) * amp # create monitors rateDE1 = PopulationRateMonitor(decE1) rateDE2 = PopulationRateMonitor(decE2) rateSE1 = PopulationRateMonitor(senE1) rateSE2 = PopulationRateMonitor(senE2) subSE = int(senE1.__len__()) spksSE = SpikeMonitor(senE[subSE - 100:subSE + 100]) # last 100 of SE1 and first 100 of SE2 # construct network net = Network(Dgroups.values(), Dsynapses.values(), Sgroups.values(), Ssynapses.values(), synSE1DE1, synSE2DE2, synDE1SE1, synDE2SE2, rateDE1, rateDE2, rateSE1, rateSE2, spksSE, name='hierarchicalnet') # create more monitors for plot if task_info['simulation']['pltfig1']: # inh rateDI = PopulationRateMonitor(decI) rateSI = PopulationRateMonitor(senI) # spk monitors subDE = int(decE1.__len__() * 2) spksDE = SpikeMonitor(decE[:subDE]) spksSE = SpikeMonitor(senE) # state mons no more, just the arrays stim1 = i1t.T stim2 = i2t.T stimtime = np.linspace(0, runtime_, stim1.shape[1]) # construct network net = Network(Dgroups.values(), Dsynapses.values(), Sgroups.values(), Ssynapses.values(), synSE1DE1, synSE2DE2, synDE1SE1, synDE2SE2, spksDE, rateDE1, rateDE2, rateDI, spksSE, rateSE1, rateSE2, rateSI, name='hierarchicalnet') if task_info['simulation']['plasticdend']: # create state monitor to follow muOUd and add it to the networks dend_mon = StateMonitor(dend1, variables=['muOUd', 'Ibg', 'g_ea', 'B'], record=True, dt=1 * ms) net.add(dend_mon) # remove FB synapses! net.remove([synDE1SE1, synDE2SE2, Dsynapses.values()]) print( " FB synapses and synapses of decision circuit are ignored in this simulation!" ) # run hierarchical net net.run(runtime, report='stdout', profile=True) print(profiling_summary(net=net, show=10)) # nice plots on cluster if task_info['simulation']['pltfig1']: plot_fig1b([ rateDE1, rateDE2, rateDI, spksDE, rateSE1, rateSE2, rateSI, spksSE, stim1, stim2, stimtime ], smoothwin, taskdir) # ------------------------------------- # Burst quantification # ------------------------------------- events = np.zeros(1) bursts = np.zeros(1) singles = np.zeros(1) spikes = np.zeros(1) last_muOUd = np.zeros(1) # neurometric params dt = spksSE.clock.dt validburst = task_info['sen']['2c']['validburst'] smoothwin_ = smoothwin / second if task_info['simulation']['burstanalysis']: if task_info['simulation']['2cmodel']: last_muOUd = np.array(dend_mon.muOUd[:, -int(1e3):].mean(axis=1)) if task_info['simulation']['plasticdend']: # calculate neurometric info per population events, bursts, singles, spikes, isis = spks2neurometric( spksSE, runtime, settletime, validburst, smoothwin=smoothwin_, raster=False) # plot & save weigths after convergence eta0 = task_info['sen']['2c']['eta0'] tauB = task_info['sen']['2c']['tauB'] targetB = task_info['targetB'] B0 = tauB * targetB tau_update = task_info['sen']['2c']['tau_update'] eta = eta0 * tau_update / tauB plot_weights(dend_mon, events, bursts, spikes, [targetB, B0, eta, tauB, tau_update, smoothwin_], taskdir) plot_rasters(spksSE, bursts, targetB, isis, runtime_, taskdir) else: # calculate neurometric per neuron events, bursts, singles, spikes, isis = spks2neurometric( spksSE, runtime, settletime, validburst, smoothwin=smoothwin_, raster=True) plot_neurometric(events, bursts, spikes, stim1, stim2, stimtime, (settletime_, runtime_), taskdir, smoothwin_) plot_isis(isis, bursts, events, (settletime_, runtime_), taskdir) # ------------------------------------- # Choice selection # ------------------------------------- # population rates and downsample originaltime = rateDE1.t / second interptime = np.linspace(0, originaltime[-1], originaltime[-1] * 100) # every 10 ms fDE1 = interpolate.interp1d( originaltime, rateDE1.smooth_rate(window='flat', width=smoothwin)) fDE2 = interpolate.interp1d( originaltime, rateDE2.smooth_rate(window='flat', width=smoothwin)) fSE1 = interpolate.interp1d( originaltime, rateSE1.smooth_rate(window='flat', width=smoothwin)) fSE2 = interpolate.interp1d( originaltime, rateSE2.smooth_rate(window='flat', width=smoothwin)) rateDE = np.array([f(interptime) for f in [fDE1, fDE2]]) rateSE = np.array([f(interptime) for f in [fSE1, fSE2]]) # select the last half second of the stimulus newdt = runtime_ / rateDE.shape[1] settletimeidx = int(settletime_ / newdt) dec_ival = np.array([(stimoff_ - 0.5) / newdt, stimoff_ / newdt], dtype=int) who_wins = rateDE[:, dec_ival[0]:dec_ival[1]].mean(axis=1) # divide trls into preferred and non-preferred pref_msk = np.argmax(who_wins) poprates_dec = np.array([rateDE[pref_msk], rateDE[~pref_msk]]) # 0: pref, 1: npref poprates_sen = np.array([rateSE[pref_msk], rateSE[~pref_msk]]) results = { 'raw_data': { 'poprates_dec': poprates_dec[:, settletimeidx:], 'poprates_sen': poprates_sen[:, settletimeidx:], 'pref_msk': np.array([pref_msk]), 'last_muOUd': last_muOUd }, 'sim_state': np.zeros(1), 'computed': { 'events': events, 'bursts': bursts, 'singles': singles, 'spikes': spikes, 'isis': np.array(isis) } } return results