Balanced random network based on Brunel N (2000) Dynamics of sparsely connected networks of excitatory and inhibitory spiking neurons. J Comput Neurosci 8:183-208.ΒΆ

Based on:

Brunel N (2000) Dynamics of sparsely connected networks of excitatory and inhibitory spiking neurons. J Comput Neurosci 8:183-208 [ PubMed]

"""
Conversion of the Brunel network implemented in nest-1.0.13/examples/brunel.sli
to use PyNN.

Brunel N (2000) Dynamics of sparsely connected networks of excitatory and inhibitory spiking neurons. J Comput Neurosci 8:183-208

Andrew Davison, UNIC, CNRS
May 2006



"""

from pyNN.utility import get_script_args, Timer

simulator_name = get_script_args(1)[0]  
exec("from pyNN.%s import *" % simulator_name)

from pyNN.random import NumpyRNG, RandomDistribution

timer = Timer()

# === Define parameters ========================================================

downscale   = 50      # scale number of neurons down by this factor
                      # scale synaptic weights up by this factor to
                      # obtain similar dynamics independent of size
order       = 50000  # determines size of network:
                      # 4*order excitatory neurons
                      # 1*order inhibitory neurons
Nrec        = 50      # number of neurons to record from, per population
epsilon     = 0.1     # connectivity: proportion of neurons each neuron projects to
    
# Parameters determining model dynamics, cf Brunel (2000), Figs 7, 8 and Table 1
# here: Case C, asynchronous irregular firing, ~35 Hz
eta         = 2.0     # rel rate of external input
g           = 5.0     # rel strength of inhibitory synapses
J           = 0.1     # synaptic weight [mV]
delay       = 1.5     # synaptic delay, all connections [ms]  

# single neuron parameters
tauMem      = 20.0    # neuron membrane time constant [ms]
tauSyn      = 0.1     # synaptic time constant [ms]
tauRef      = 2.0     # refractory time [ms]
U0          = 0.0     # resting potential [mV]
theta       = 20.0    # threshold 

# simulation-related parameters  
simtime     = 100.0   # simulation time [ms] 
dt          = 0.1     # simulation step length [ms]   

# seed for random generator used when building connections
connectseed = 12345789   
use_RandomArray = True # use Python rng rather than NEST rng

# seed for random generator(s) used during simulation
kernelseed  = 43210987      
  
# === Calculate derived parameters =============================================

# scaling: compute effective order and synaptic strength
order_eff = int(float(order)/downscale)
J_eff     = J*downscale
  
# compute neuron numbers
NE = int(4*order_eff)  # number of excitatory neurons
NI = int(1*order_eff)  # number of inhibitory neurons
N  = NI + NE           # total number of neurons

# compute synapse numbers
CE   = int(epsilon*NE)  # number of excitatory synapses on neuron
CI   = int(epsilon*NI)  # number of inhibitory synapses on neuron
C    = CE + CI          # total number of internal synapses per n.   
Cext = CE               # number of external synapses on neuron  

# synaptic weights, scaled for alpha functions, such that
# for constant membrane potential, charge J would be deposited
fudge = 0.00041363506632638 # ensures dV = J at V=0  
  
# excitatory weight: JE = J_eff / tauSyn * fudge
JE = (J_eff/tauSyn)*fudge 
  
# inhibitory weight: JI = - g * JE
JI = -g*JE  
  
# threshold, external, and Poisson generator rates:
nu_thresh = theta/(J_eff*CE*tauMem)
nu_ext    = eta*nu_thresh     # external rate per synapse
p_rate    = 1000*nu_ext*Cext  # external input rate per neuron (Hz)
                                    
# number of synapses---just so we know
Nsyn = (C+1)*N + 2*Nrec  # number of neurons * (internal synapses + 1 synapse from PoissonGenerator) + 2synapses" to spike detectors

# put cell parameters into a dict
cell_params = {'tau_m'      : tauMem,
               'tau_syn_E'  : tauSyn,
               'tau_syn_I'  : tauSyn,
               'tau_refrac' : tauRef,
               'v_rest'     : U0,
               'v_reset'    : U0,
               'v_thresh'   : theta,
               'cm'         : 0.001}     # (nF)

# === Build the network ========================================================

# clear all existing network elements and set resolution and limits on delays.
# For NEST, limits must be set BEFORE connecting any elements

#extra = {'threads' : 2}
extra = {}

rank = setup(timestep=dt, max_delay=delay, **extra)
np = num_processes()
import socket
host_name = socket.gethostname()
print "Host #%d is on %s" % (rank+1, host_name)

if extra.has_key('threads'):
    print "%d Initialising the simulator with %d threads..." %(rank, extra['threads'])
else:
    print "%d Initialising the simulator with single thread..." %(rank)

# Small function to display information only on node 1
def nprint(s):
    if (rank == 0):
        print s

timer.start() # start timer on construction    

print "%d Setting up random number generator" %rank
rng = NumpyRNG(kernelseed, parallel_safe=True)

print "%d Creating excitatory population with %d neurons." % (rank, NE)
E_net = Population(NE, IF_curr_alpha, cell_params, label="E_net")

print "%d Creating inhibitory population with %d neurons." % (rank, NI)
I_net = Population(NI, IF_curr_alpha, cell_params, label="I_net")

print "%d Initialising membrane potential to random values between %g mV and %g mV." % (rank, U0, theta)
uniformDistr = RandomDistribution('uniform', [U0, theta], rng)
E_net.initialize('v', uniformDistr)
I_net.initialize('v', uniformDistr)

print "%d Creating excitatory Poisson generator with rate %g spikes/s." % (rank, p_rate)
expoisson = Population(NE, SpikeSourcePoisson, {'rate': p_rate}, "expoisson")

print "%d Creating inhibitory Poisson generator with the same rate." % rank
inpoisson = Population(NI, SpikeSourcePoisson, {'rate': p_rate}, "inpoisson")

# Record spikes
print "%d Setting up recording in excitatory population." % rank
E_net.record(Nrec)
E_net[[0, 1]].record_v()

print "%d Setting up recording in inhibitory population." % rank
I_net.record(Nrec)
I_net[[0, 1]].record_v()

E_Connector = FixedProbabilityConnector(epsilon, weights=JE, delays=delay, verbose=True)
I_Connector = FixedProbabilityConnector(epsilon, weights=JI, delays=delay, verbose=True)
ext_Connector = OneToOneConnector(weights=JE, delays=dt, verbose=True)

print "%d Connecting excitatory population with connection probability %g, weight %g nA and delay %g ms." % (rank, epsilon, JE, delay)
E_to_E = Projection(E_net, E_net, E_Connector, rng=rng, target="excitatory")
print "E --> E\t\t", len(E_to_E), "connections"
I_to_E = Projection(I_net, E_net, I_Connector, rng=rng, target="inhibitory")
print "I --> E\t\t", len(I_to_E), "connections"
input_to_E = Projection(expoisson, E_net, ext_Connector, target="excitatory")
print "input --> E\t", len(input_to_E), "connections"

print "%d Connecting inhibitory population with connection probability %g, weight %g nA and delay %g ms." % (rank, epsilon, JI, delay)
E_to_I = Projection(E_net, I_net, E_Connector, rng=rng, target="excitatory")
print "E --> I\t\t", len(E_to_I), "connections"
I_to_I = Projection(I_net, I_net, I_Connector, rng=rng, target="inhibitory")
print "I --> I\t\t", len(I_to_I), "connections"
input_to_I = Projection(inpoisson, I_net, ext_Connector, target="excitatory")
print "input --> I\t", len(input_to_I), "connections"

# read out time used for building
buildCPUTime = timer.elapsedTime()
# === Run simulation ===========================================================

# run, measure computer time
timer.start() # start timer on construction
print "%d Running simulation for %g ms." % (rank, simtime)
run(simtime)
simCPUTime = timer.elapsedTime()

print "%d Writing data to file." % rank
exfilename  = "Results/Brunel_exc_np%d_%s.ras" % (np, simulator_name) # output file for excit. population  
infilename  = "Results/Brunel_inh_np%d_%s.ras" % (np, simulator_name) # output file for inhib. population  
vexfilename = "Results/Brunel_exc_np%d_%s.v"   % (np, simulator_name) # output file for membrane potential traces
vinfilename = "Results/Brunel_inh_np%d_%s.v"   % (np, simulator_name) # output file for membrane potential traces

# write data to file
E_net.printSpikes(exfilename)
I_net.printSpikes(infilename)
E_net[[0, 1]].print_v(vexfilename)
I_net[[0, 1]].print_v(vinfilename)

E_rate = E_net.meanSpikeCount()*1000.0/simtime
I_rate = I_net.meanSpikeCount()*1000.0/simtime

# write a short report
nprint("\n--- Brunel Network Simulation ---")
nprint("Nodes              : %d" % np)
nprint("Number of Neurons  : %d" % N)
nprint("Number of Synapses : %d" % Nsyn)
nprint("Input firing rate  : %g" % p_rate)
nprint("Excitatory weight  : %g" % JE)
nprint("Inhibitory weight  : %g" % JI)
nprint("Excitatory rate    : %g Hz" % E_rate)
nprint("Inhibitory rate    : %g Hz" % I_rate)
nprint("Build time         : %g s" % buildCPUTime)   
nprint("Simulation time    : %g s" % simCPUTime)
  
# === Clean up and quit ========================================================

end()