NNGT/doc/examples/random_balanced.py

202 lines
5.8 KiB
Python

# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2015-2023 Tanguy Fardet
# SPDX-License-Identifier: GPL-3.0-or-later
# doc/examples/random_balanced.py
"""
Use NNGT to analyze NEST-simulated activity of a random balanced network.
"""
import os
import numpy as np
from scipy.special import lambertw
import nngt
import nngt.generation as ng
'''
Simulation parameters
'''
num_omp = int(os.environ.get("OMP", 8))
nngt.set_config("omp", num_omp)
nngt.set_config("seeds", [10 + i for i in range(num_omp)])
dt = 0.1 # the resolution in ms
simtime = 1000. # Simulation time in ms
delay = 1.5 # synaptic delay in ms
g = 4.0 # ratio inhibitory weight/excitatory weight
eta = 2.0 # external rate relative to threshold rate
epsilon = 0.1 # connection probability
'''
Tools
'''
def ComputePSPnorm(tauMem, CMem, tauSyn):
a = (tauMem / tauSyn)
b = (1.0 / tauSyn - 1.0 / tauMem)
# time of maximum
t_max = 1.0 / b * (-lambertw(-np.exp(-1.0 / a) / a, -1) - 1.0 / a)
t_max = np.real(t_max)
# maximum of PSP for current of unit amplitude
return (np.exp(1.0) / (tauSyn * CMem * b) *
((np.exp(-t_max / tauMem) - np.exp(-t_max / tauSyn)) / b -
t_max * np.exp(-t_max / tauSyn)))
'''
Network parameters
'''
order = 1000
NE = 4 * order # number of excitatory neurons
NI = 1 * order # number of inhibitory neurons
N_neurons = NE + NI # number of neurons in total
N_rec = 50 # record from 50 neurons
CE = int(epsilon * NE) # number of excitatory synapses per neuron
CI = int(epsilon * NI) # number of inhibitory synapses per neuron
C_tot = int(CI + CE) # total number of synapses per neuron
tauSyn = 0.5 # synaptic time constant in ms
tauMem = 20. # time constant of membrane potential in ms
CMem = 250. # capacitance of membrane in in pF
theta = 20. # membrane threshold potential in mV
neuron_params = {"C_m": CMem,
"tau_m": tauMem,
"tau_syn_ex": tauSyn,
"tau_syn_in": tauSyn,
"t_ref": 2.0,
"E_L": 0.0,
"V_reset": 0.0,
"V_m": 0.0,
"V_th": theta}
J_unit = ComputePSPnorm(tauMem, CMem, tauSyn)
J = 0.8 # postsynaptic amplitude in mV
J_ex = J / J_unit # amplitude of excitatory postsynaptic current
J_in = g * J_ex # amplitude of inhibitory postsynaptic current
nu_th = (theta * CMem) / (J_ex * CE * np.e * tauMem * tauSyn)
nu_ex = eta * nu_th
p_rate = 400. * nu_ex * CE
'''
Create the population and network
'''
pop = nngt.NeuralPop.exc_and_inhib(
N_neurons, en_model="iaf_psc_alpha", en_param=neuron_params,
in_model="iaf_psc_alpha", in_param=neuron_params)
net = nngt.Network(population=pop)
ng.connect_groups(net, pop, "excitatory", "gaussian_degree", degree_type="in",
avg=CE, std=0.1*CE, weights=J_ex, delays=delay)
ng.connect_groups(net, pop, "inhibitory", "gaussian_degree", degree_type="in",
avg=CI, std=0.1*CI, weights=J_in, delays=delay)
'''
Tools to analyze the activity
'''
def coefficient_of_variation(spikes):
from scipy.stats import variation
times = np.array(spikes["times"])
nrns = np.array(spikes["senders"])
return np.nanmean([variation(np.diff(times[nrns == i]))
for i in np.unique(nrns)])
def cross_correlation(spikes, time, numbins=1000):
times = np.array(spikes["times"])
nrns = np.array(spikes["senders"])
a = [np.histogram(times[nrns == x], numbins, range=[0, time])[0]
for x in np.unique(nrns)]
c = np.cov(a)
std = np.sqrt(np.diag(c))
c = np.divide(c, std[:,np.newaxis])
c = np.divide(c, std[:,np.newaxis].T)
return np.nanmean(c)
'''
Send the network to NEST, set noise and randomize parameters
'''
if nngt.get_config('with_nest'):
import nngt.simulation as ns
from nngt.analysis import get_spikes
import nest
print_time = bool(os.environ.get("PYNEST_QUIET", False))
nest.ResetKernel()
nest.SetKernelStatus({"resolution": dt, "print_time": print_time,
"overwrite_files": True, 'local_num_threads': 4})
gids = net.to_nest()
pg = ns.set_poisson_input(gids, rate=p_rate,
syn_spec={"weight": J_ex, "delay": delay})
recorders, records = ns.monitor_groups(
["excitatory", "inhibitory"], network=net)
nest.Simulate(simtime)
if nngt.get_config('with_plot'):
ideg = net.get_degrees("in", edge_type="inhibitory")
edeg = net.get_degrees("in", edge_type="excitatory")
# plot the basic activity
ns.plot_activity(
recorders, records, network=net, show=False)
# sort by firing rate
ns.plot_activity(
recorders, records, network=net, sort="firing_rate", show=False)
# by in-degree (not working)
ns.plot_activity(
recorders, records, network=net, sort="in-degree", show=False)
# k_e - k_i (good)
ns.plot_activity(
recorders, records, network=net, sort=edeg-ideg, show=True)
# then show correlations
exc_nodes = pop["excitatory"].ids
inh_nodes = pop["inhibitory"].ids
nngt.plot.correlation_to_attribute(
net, (edeg-ideg)[exc_nodes], "firing_rate", nodes=exc_nodes,
show=False)
nngt.plot.correlation_to_attribute(
net, (edeg-ideg)[inh_nodes], "firing_rate", nodes=inh_nodes,
show=True)
# print the CV and CC
data_exc = get_spikes(recorders[0], astype="np")
data_inh = get_spikes(recorders[1], astype="np")
spikes = {
"senders": list(data_exc[:, 0]) + list(data_inh[:, 0]),
"times": list(data_exc[:, 1]) + list(data_inh[:, 1]),
}
print(coefficient_of_variation(spikes),
cross_correlation(spikes, simtime))