def get_monitors(pop, nr_monitored, N):
     nr_monitored = min(nr_monitored, (N))
     idx_monitored_neurons = [
         int(math.ceil(k)) for k in np.linspace(0, N - 1, nr_monitored + 2)
     ][1:-1]  # sample(range(N), nr_monitored)
     rate_monitor = PopulationRateMonitor(pop)
     spike_monitor = SpikeMonitor(pop, record=idx_monitored_neurons)
     voltage_monitor = StateMonitor(pop, "v", dt=1 * ms,
                                    record=0)  #idx_monitored_neurons)
     # synapse_monitor = StateMonitor(pop, "stp", dt=10*ms, record=pop[int(np.ceil(N/2)),:]) #N_excitatory/2,:])
     synapse_monitor = StateMonitor(
         syn_excit2excit,
         "stp",
         dt=10 * ms,
         record=syn_excit2excit[stim1_center_idx, :])  #N_excitatory/2,:])
     return rate_monitor, spike_monitor, voltage_monitor, idx_monitored_neurons, synapse_monitor
Beispiel #2
0
 def get_monitors(pop, monitored_subset_size):
     monitored_subset_size = min(monitored_subset_size, pop.N)
     idx_monitored_neurons = sample(range(pop.N), monitored_subset_size)
     rate_monitor = PopulationRateMonitor(pop)
     spike_monitor = SpikeMonitor(pop, record=idx_monitored_neurons)
     voltage_monitor = StateMonitor(pop, "v", record=idx_monitored_neurons)
     return rate_monitor, spike_monitor, voltage_monitor, idx_monitored_neurons
 def get_monitors(pop, nr_monitored, N):
     nr_monitored = min(nr_monitored, (N))
     idx_monitored_neurons = [int(math.ceil(k))
          for k in np.linspace(0, N - 1, nr_monitored + 2)][1:-1]  # sample(range(N), nr_monitored)
     spike_monitor   = SpikeMonitor(pop, record=idx_monitored_neurons)
     synapse_monitor = StateMonitor(syn_excit2excit, "stp", record=syn_excit2excit[stim1_center_idx, stim1_center_idx-10:stim1_center_idx+10], dt=1*ms)
     return spike_monitor, synapse_monitor, idx_monitored_neurons
 def get_monitors(pop, nr_monitored, N):
     nr_monitored = min(nr_monitored, (N))
     idx_monitored_neurons = \
         [int(math.ceil(k))
          for k in numpy.linspace(0, N - 1, nr_monitored + 2)][1:-1]  # sample(range(N), nr_monitored)
     rate_monitor = PopulationRateMonitor(pop)
     # record= some_list is not supported? :-(
     spike_monitor = SpikeMonitor(pop, record=idx_monitored_neurons)
     voltage_monitor = StateMonitor(pop, "v", record=idx_monitored_neurons)
     return rate_monitor, spike_monitor, voltage_monitor, idx_monitored_neurons
Beispiel #5
0
    def get_monitors(pop, monitored_subset_size):
        """
        Internal helper.
        Args:
            pop:
            monitored_subset_size:

        Returns:

        """
        monitored_subset_size = min(monitored_subset_size, pop.N)
        idx_monitored_neurons = sample(range(pop.N), monitored_subset_size)
        rate_monitor = PopulationRateMonitor(pop)
        # record parameter: record=idx_monitored_neurons is not supported???
        spike_monitor = SpikeMonitor(pop, record=idx_monitored_neurons)
        voltage_monitor = StateMonitor(pop, "v", record=idx_monitored_neurons)
        return rate_monitor, spike_monitor, voltage_monitor, idx_monitored_neurons
Beispiel #6
0
def simulate_brunel_network(
        N_Excit=5000,
        N_Inhib=None,
        N_extern=N_POISSON_INPUT,
        connection_probability=CONNECTION_PROBABILITY_EPSILON,
        w0=SYNAPTIC_WEIGHT_W0,
        g=RELATIVE_INHIBITORY_STRENGTH_G,
        synaptic_delay=SYNAPTIC_DELAY,
        poisson_input_rate=POISSON_INPUT_RATE,
        w_external=None,
        v_rest=V_REST,
        v_reset=V_RESET,
        firing_threshold=FIRING_THRESHOLD,
        membrane_time_scale=MEMBRANE_TIME_SCALE,
        abs_refractory_period=ABSOLUTE_REFRACTORY_PERIOD,
        monitored_subset_size=100,
        random_vm_init=False,
        sim_time=100.*b2.ms):
    """
    Fully parametrized implementation of a sparsely connected network of LIF neurons (Brunel 2000)

    Args:
        N_Excit (int): Size of the excitatory popluation
        N_Inhib (int): optional. Size of the inhibitory population.
            If not set (=None), N_Inhib is set to N_excit/4.
        N_extern (int): optional. Number of presynaptic excitatory poisson neurons. Note: if set to a value,
            this number does NOT depend on N_Excit and NOT depend on connection_probability (this is different
            from the book and paper. Only if N_extern is set to 'None', then N_extern is computed as
            N_Excit*connection_probability.
        connection_probability (float): probability to connect to any of the (N_Excit+N_Inhib) neurons
            CE = connection_probability*N_Excit
            CI = connection_probability*N_Inhib
            Cexternal = N_extern
        w0 (float): Synaptic strength J
        g (float): relative importance of inhibition. J_exc = w0. J_inhib = -g*w0
        synaptic_delay (Quantity): Delay between presynaptic spike and postsynaptic increase of v_m
        poisson_input_rate (Quantity): Poisson rate of the external population
        w_external (float): optional. Synaptic weight of the excitatory external poisson neurons onto all
            neurons in the network. Default is None, in that case w_external is set to w0, which is the
            standard value in the book and in the paper Brunel2000.
            The purpose of this parameter is to see the effect of external input in the
            absence of network feedback(setting w0 to 0mV and w_external>0).
        v_rest (Quantity): Resting potential
        v_reset (Quantity): Reset potential
        firing_threshold (Quantity): Spike threshold
        membrane_time_scale (Quantity): tau_m
        abs_refractory_period (Quantity): absolute refractory period, tau_ref
        monitored_subset_size (int): nr of neurons for which a VoltageMonitor is recording Vm
        random_vm_init (bool): if true, the membrane voltage of each neuron is initialized with a
            random value drawn from Uniform(v_rest, firing_threshold)
        sim_time (Quantity): Simulation time

    Returns:
        (rate_monitor, spike_monitor, voltage_monitor, idx_monitored_neurons)
        PopulationRateMonitor: Rate Monitor
        SpikeMonitor: SpikeMonitor for ALL (N_Excit+N_Inhib) neurons
        StateMonitor: membrane voltage for a selected subset of neurons
        list: index of monitored neurons. length = monitored_subset_size
    """
    if N_Inhib is None:
        N_Inhib = int(N_Excit/4)
    if N_extern is None:
        N_extern = int(N_Excit*connection_probability)
    if w_external is None:
        w_external = w0

    J_excit = w0
    J_inhib = -g*w0

    lif_dynamics = """
    dv/dt = -(v-v_rest) / membrane_time_scale : volt (unless refractory)"""

    network = NeuronGroup(
        N_Excit+N_Inhib, model=lif_dynamics,
        threshold="v>firing_threshold", reset="v=v_reset", refractory=abs_refractory_period,
        method="linear")
    if random_vm_init:
        network.v = random.uniform(v_rest/b2.mV, high=firing_threshold/b2.mV, size=(N_Excit+N_Inhib))*b2.mV
    else:
        network.v = v_rest
    excitatory_population = network[:N_Excit]
    inhibitory_population = network[N_Excit:]

    exc_synapses = Synapses(excitatory_population, target=network, on_pre="v += J_excit", delay=synaptic_delay)
    exc_synapses.connect(p=connection_probability)

    inhib_synapses = Synapses(inhibitory_population, target=network, on_pre="v += J_inhib", delay=synaptic_delay)
    inhib_synapses.connect(p=connection_probability)

    external_poisson_input = PoissonInput(target=network, target_var="v", N=N_extern,
                                          rate=poisson_input_rate, weight=w_external)

    # collect data of a subset of neurons:
    monitored_subset_size = min(monitored_subset_size, (N_Excit+N_Inhib))
    idx_monitored_neurons = sample(range(N_Excit+N_Inhib), monitored_subset_size)
    rate_monitor = PopulationRateMonitor(network)
    # record= some_list is not supported? :-(
    spike_monitor = SpikeMonitor(network, record=idx_monitored_neurons)
    voltage_monitor = StateMonitor(network, "v", record=idx_monitored_neurons)

    b2.run(sim_time)
    return rate_monitor, spike_monitor, voltage_monitor, idx_monitored_neurons
def simulate_wm(
        N_excitatory=2048, N_inhibitory=512,
        N_extern_poisson=1000, poisson_firing_rate=1.8 * Hz, 
        sigma_weight_profile=14.4, Jpos_excit2excit=1.63,
        stimulus1_center_deg=180, stimulus2_center_deg=235, 
        stimulus_width_deg=60., stimulus_strength=0.07 * namp,
        t_stimulus1_start=1000 * ms, t_stimulus2_start=6000 * ms,
        t_stimulus_duration=600 * ms,
        t_delay1=3000 * ms, t_delay2=3000 * ms, 
        t_iti_duration=300 * ms, sim_time=5000. * ms,
        monitored_subset_size=1024, nmdarEI=1.0, nmdarEE=1.0):
    """
    Args:
        N_excitatory (int): Size of the excitatory population
        N_inhibitory (int): Size of the inhibitory population
        weight_scaling_factor (float): weight prefactor. When increasing the size of the populations,
            the synaptic weights have to be decreased. Using the default values, we have
            N_excitatory*weight_scaling_factor = 2048 and N_inhibitory*weight_scaling_factor=512
        N_extern_poisson (int): Size of the external input population (Poisson input)
        poisson_firing_rate (Quantity): Firing rate of the external population
        sigma_weight_profile (float): standard deviation of the gaussian input profile in
            the excitatory population.
        Jpos_excit2excit (float): Strength of the recurrent input within the excitatory population.
            Jneg_excit2excit is computed from sigma_weight_profile, Jpos_excit2excit and the normalization
            condition.
        stimulus_center_deg (float): Center of the stimulus in [0, 360]
        stimulus_width_deg (float): width of the stimulus. All neurons in
            stimulus_center_deg +- (stimulus_width_deg/2) receive the same input current
        stimulus_strength (Quantity): Input current to the neurons at stimulus_center_deg +- (stimulus_width_deg/2)
        t_stimulus_start (Quantity): time when the input stimulus is turned on
        t_stimulus_duration (Quantity): duration of the stimulus.
        monitored_subset_size (int): nr of neurons for which a Spike- and Voltage monitor is registered.
        sim_time (Quantity): simulation time
    Returns:
       results (tuple):
       rate_monitor_excit (Brian2 PopulationRateMonitor for the excitatory population),
        spike_monitor_excit, voltage_monitor_excit, idx_monitored_neurons_excit,\
        rate_monitor_inhib, spike_monitor_inhib, voltage_monitor_inhib, idx_monitored_neurons_inhib,\
        weight_profile_45 (The weights profile for the neuron with preferred direction = 45deg).
    """

    global par

    print par

    devices.device.seed(os.getpid())
    # specify the excitatory pyramidal cells:
    Cm_excit                    = 0.5 * nF  # membrane capacitance of excitatory neurons
    G_leak_excit                = 25.0 * nS  # leak conductance
    E_leak_excit                = -70.0 * mV  # reversal potential
    v_firing_threshold_excit    = -50.0 * mV  # spike condition
    v_reset_excit               = -60.0 * mV  # reset voltage after spike
    t_abs_refract_excit         = 2.0 * ms  # absolute refractory period

    # specify the weight profile in the recurrent population
    # std-dev of the gaussian weight profile around the prefered direction
    # sigma_weight_profile = 12.0  # std-dev of the gaussian weight profile around the prefered direction
    # Jneg_excit2excit = 0

    # specify the inhibitory interneurons:
    Cm_inhib                    = 0.2 * nF
    G_leak_inhib                = 20.0 * nS
    E_leak_inhib                = -70.0 * mV
    v_firing_threshold_inhib    = -50.0 * mV
    v_reset_inhib               = -60.0 * mV
    t_abs_refract_inhib         = 1.0 * ms

    # specify the AMPA synapses
    E_AMPA      = 0.0 * mV
    tau_AMPA    = 2.0 * ms

    # specify the GABA synapses
    E_GABA      = -70.0 * mV
    tau_GABA    = 10.0 * ms

    # specify the NMDA synapses
    E_NMDA      = 0.0 * mV
    tau_NMDA_s  = 100.0 * ms 
    tau_NMDA_x  = 2.0 * ms
    alpha_NMDA  = 0.5 * kHz

    weight_scaling_factor = 2048./N_excitatory

    # projections from the external population
    G_extern2inhib  = 2.38 * nS
    G_extern2excit  = 3.1 * nS

    # projectsions from the inhibitory populations
    G_inhib2inhib   = weight_scaling_factor * 1.024 * nS
    G_inhib2excit   = weight_scaling_factor * 1.336 * nS

    # projections from the excitatory population NMDA
    G_excit2excit   = nmdarEE*weight_scaling_factor * 0.28 * nS #nmda+ampa
    G_excit2inhib   = nmdarEI*weight_scaling_factor * 0.212 * nS  # nmda+ampa

    # recurrent AMPA
    G_excit2excitA  = weight_scaling_factor * 1.* 0.251 * nS  #ampa
    GEEA            = G_excit2excitA/G_extern2excit
    G_excit2inhibA  = weight_scaling_factor * 0.192 * nS  #ampa
    GEIA            = G_excit2inhibA/G_extern2inhib

    # STDP
    taupre      = 20 * ms
    taupost     = 20 * ms
    wmax        = 2. #1.1
    Apre        = 0.00035 #0.00025 #set to zero to deactivate STDP # 0.02 
    Apost       = Apre #-Apre *taupre/taupost*1.03 #1.4 #negative for LTD, positive for LTP
    stp_decay   = 0.04#25 #0.025
#    Apost      = Apre *taupre/taupost #negative for LTD, positive for LTP

    # compute the simulus index
    stim1_center_idx = int(round(N_excitatory / 360. * stimulus1_center_deg))
    stim1_width_idx  = int(round(N_excitatory / 360. * stimulus_width_deg / 2.))
    stim1_target_idx = [idx % N_excitatory
                       for idx in
                       range(stim1_center_idx - stim1_width_idx, stim1_center_idx + stim1_width_idx + 1)]

    stim2_center_idx = int(round(N_excitatory / 360. * stimulus2_center_deg))
    stim2_width_idx  = int(round(N_excitatory / 360. * stimulus_width_deg / 2.))
    stim2_target_idx = [idx % N_excitatory
                       for idx in
                       range(stim2_center_idx - stim2_width_idx, stim2_center_idx + stim2_width_idx + 1)]

    # precompute the weight profile for the recurrent population
    tmp                     = math.sqrt(2. * math.pi) * sigma_weight_profile * erf(180. / math.sqrt(2.) / sigma_weight_profile) / 360.
    Jneg_excit2excit        = (1. - Jpos_excit2excit * tmp) / (1. - tmp)
    presyn_weight_kernel    = [(Jneg_excit2excit + (Jpos_excit2excit - Jneg_excit2excit) *
                               math.exp(-.5 * (360. * min(nj, N_excitatory - nj) / N_excitatory) ** 2 / sigma_weight_profile ** 2))
                               for nj in 
                               range(N_excitatory)]
    fft_presyn_weight_kernel = rfft(presyn_weight_kernel)

    # define the inhibitory population
    a = 0.062/mV
    inhib_lif_dynamics = """
        s_NMDA_total : 1  # the post synaptic sum of s. compare with s_NMDA_presyn
        dv/dt = (
        - G_leak_inhib * (v-E_leak_inhib)
        - G_extern2inhib * s_AMPA * (v-E_AMPA)
        - G_inhib2inhib * s_GABA * (v-E_GABA)
        - G_excit2inhib * s_NMDA_total * (v-E_NMDA)/(1.0+1.0*exp(-a*v)/3.57)
        )/Cm_inhib : volt (unless refractory)
        ds_AMPA/dt = -s_AMPA/tau_AMPA : 1
        ds_GABA/dt = -s_GABA/tau_GABA : 1
    """

    inhib_pop = NeuronGroup(
        N_inhibitory, model=inhib_lif_dynamics,
        threshold="v>v_firing_threshold_inhib", reset="v=v_reset_inhib", refractory=t_abs_refract_inhib,
        method="rk2")
    # initialize with random voltages:
    inhib_pop.v     = np.random.uniform(v_reset_inhib / mV, high=v_firing_threshold_inhib / mV,
                                       size=N_inhibitory) * mV
    # set the connections: inhib2inhib
    syn_inhib2inhib = Synapses(inhib_pop, target=inhib_pop, on_pre="s_GABA += 1.0", delay=0.0 * ms)
    syn_inhib2inhib.connect(condition="i!=j", p=1.0)

    # set the connections: extern2inhib
    input_ext2inhib = PoissonInput(target=inhib_pop, target_var="s_AMPA",
                                   N=N_extern_poisson, rate=poisson_firing_rate, weight=1.0)

    # specify the excitatory population:
    
    excit_lif_dynamics = """
        I_stim : amp
        s_NMDA_total : 1  # the post synaptic sum of s. compare with s_NMDA_presyn
        Ix = (- G_extern2excit * s_AMPA * (v-E_AMPA))/G_leak_excit :volt
        Ie = (- G_excit2excit * s_NMDA_total * (v-E_NMDA)/(1.0+1.0*exp(-a*v)/3.57))/G_leak_excit : volt
        Ii = (- G_inhib2excit * s_GABA * (v-E_GABA))/G_leak_excit :volt
        Irec = Ix + Ie + Ii : volt
        dv/dt = (
        - G_leak_excit * (v-E_leak_excit)
        + G_leak_excit*Irec
        + I_stim 
        )/Cm_excit : volt (unless refractory)
        ds_AMPA/dt = -s_AMPA/tau_AMPA : 1
        ds_GABA/dt = -s_GABA/tau_GABA : 1
        ds_NMDA/dt = -s_NMDA/tau_NMDA_s + alpha_NMDA * x * (1-s_NMDA) : 1
        dx/dt = -x/tau_NMDA_x : 1
    """

    excit_pop = NeuronGroup(N_excitatory, model=excit_lif_dynamics,
                            threshold="v>v_firing_threshold_excit", reset="v=v_reset_excit",
                            refractory=t_abs_refract_excit, method="rk2")
    # initialize with random voltages:
    excit_pop.v = np.random.uniform(v_reset_excit / mV, high=v_firing_threshold_excit / mV,
                                       size=N_excitatory) * mV
    excit_pop.I_stim = 0. * namp
    # set the connections: extern2excit
    input_ext2excit = PoissonInput(target=excit_pop, target_var="s_AMPA",
                                   N=N_extern_poisson, rate=poisson_firing_rate, weight=1.0)

    # set the connections: inhibitory to excitatory
    syn_inhib2excit = Synapses(inhib_pop, excit_pop, on_pre="s_GABA += 1.0")
    syn_inhib2excit.connect(p=1.0)

    # set the connections: excitatory to inhibitory NMDA connections
    syn_excit2inhib = Synapses(excit_pop, inhib_pop,
                               model="s_NMDA_total_post = s_NMDA_pre : 1 (summed)", method="rk2")
    syn_excit2inhib.connect(p=1.0)

    # # set the connections: UNSTRUCTURED excitatory to excitatory
    # syn_excit2excit = Synapses(excit_pop, excit_pop,
    #        model= "s_NMDA_total_post = s_NMDA_pre : 1 (summed)", method="rk2")
    # syn_excit2excit.connect(condition="i!=j", p=1.)

    # set the STRUCTURED recurrent AMPA input
    # equations for weights, trace decay
    synapse_eqs = '''
    w : 1
    stp : 1
    dapre/dt = -apre/ taupre : 1 (event-driven)
    dapost/dt = -apost / taupost : 1 (event-driven)
    '''

    # equations for presynaptic spike
    eqs_pre = '''
    s_AMPA_post += w*stp
    x_pre += (1.0/N_excitatory)*stp
    apre += Apre
    stp = clip(stp + apost - stp_decay * (stp - 1.), 0, wmax)
    '''

    # equations for postsynaptic spike
    eqs_post = '''
    apost += Apost
    stp = clip(stp + apre, 0, wmax)
    '''

    syn_excit2excit = Synapses(excit_pop, excit_pop, synapse_eqs, on_pre=eqs_pre, on_post=eqs_post)
    syn_excit2excit.connect(condition='i!=j', p=1.0)
    syn_excit2excit.stp=1.0
    syn_excit2excit.w['abs(i-j)<N_excitatory/2'] = 'GEEA *(Jneg_excit2excit + (Jpos_excit2excit - Jneg_excit2excit) * exp(-.5 * (360. * abs(i-j) / N_excitatory) ** 2 / sigma_weight_profile ** 2))'
    syn_excit2excit.w['abs(i-j)>=N_excitatory/2'] = 'GEEA *(Jneg_excit2excit + (Jpos_excit2excit - Jneg_excit2excit) * exp(-.5 * (360. * (N_excitatory - abs(i-j)) / N_excitatory) ** 2 / sigma_weight_profile ** 2))'

    syn_excit2inhibA = Synapses(excit_pop, inhib_pop, model="w : 1", on_pre="s_AMPA_post += w")
    syn_excit2inhibA.connect(p=1.0)
    syn_excit2inhibA.w = GEIA


    # set the STRUCTURED recurrent NMDA input. use a network_operation
    @network_operation()
    def update_nmda_sum():
        fft_s_NMDA = rfft(excit_pop.s_NMDA)
        fft_s_NMDA_total = np.multiply(fft_presyn_weight_kernel, fft_s_NMDA)
        s_NMDA_tot = irfft(fft_s_NMDA_total,N_excitatory)
        excit_pop.s_NMDA_total_ = s_NMDA_tot

    @network_operation(dt=100 * ms)
    def time_counter(t):
        print(t)

    @network_operation(dt=1 * ms)
    def stimulate_network(t):
        if t >= t_stimulus1_start and t < t_stimulus1_start+t_stimulus_duration:
            excit_pop.I_stim[stim1_target_idx] = stimulus_strength
        elif t >= t_stimulus1_start+t_stimulus_duration and t < t_stimulus1_start+t_stimulus_duration+t_delay1:
            excit_pop.I_stim = 0. * namp
        elif t >= t_stimulus1_start+t_stimulus_duration+t_delay1 and t < t_stimulus1_start+t_stimulus_duration+t_delay1+t_stimulus_duration:
            excit_pop.I_stim = -1.*stimulus_strength
        elif t >= t_stimulus2_start-t_iti_duration and t < t_stimulus2_start:
            excit_pop.I_stim = 0. * namp
        elif t >= t_stimulus2_start and t < t_stimulus2_start+t_stimulus_duration:
            excit_pop.I_stim[stim2_target_idx] = stimulus_strength
        else:
            excit_pop.I_stim = 0. * namp

    def get_monitors(pop, nr_monitored, N):
        nr_monitored = min(nr_monitored, (N))
        idx_monitored_neurons = [int(math.ceil(k))
             for k in np.linspace(0, N - 1, nr_monitored + 2)][1:-1]  # sample(range(N), nr_monitored)
        spike_monitor   = SpikeMonitor(pop, record=idx_monitored_neurons)
        synapse_monitor = StateMonitor(syn_excit2excit, "stp", record=syn_excit2excit[stim1_center_idx, stim1_center_idx-10:stim1_center_idx+10], dt=1*ms)
        return spike_monitor, synapse_monitor, idx_monitored_neurons

    # collect data of a subset of neurons:
    spike_monitor_excit, synapse_monitor_excit, idx_monitored_neurons_excit = get_monitors(excit_pop, monitored_subset_size, N_excitatory)
    spike_monitor_inhib, synapse_monitor_inhib, idx_monitored_neurons_inhib = get_monitors(inhib_pop, monitored_subset_size, N_inhibitory)
    run(sim_time-200*ms)
    
    currRec=StateMonitor(excit_pop, 'Irec', record=True, when='start')
    currRecx=StateMonitor(excit_pop, 'Ix', record=True, when='start')
    currRece=StateMonitor(excit_pop, 'Ie', record=True, when='start')
    currReci=StateMonitor(excit_pop, 'Ii', record=True, when='start')
    
    run(200*ms)

    return spike_monitor_excit, synapse_monitor_excit, idx_monitored_neurons_excit, currRec, spike_monitor_inhib, currRecx, currRece, currReci
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