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)
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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