Examples¶
Neuron Models¶
Example - Adaptive Exponential Integrate and Fire¶
from __future__ import division
from nineml import units as un
from nineml import abstraction as al, user as ul
def create_adaptive_exponential():
"""
Adaptive exponential integrate-and-fire neuron as described in
A. Destexhe, J COmput Neurosci 27: 493--506 (2009)
Author B. Kriener (Jan 2011)
## neuron model: aeIF
## variables:
## V: membrane potential
## w: adaptation variable
## parameters:
## C_m # specific membrane capacitance [muF/cm**2]
## g_L # leak conductance [mS/cm**2]
## E_L # resting potential [mV]
## Delta # steepness of exponential approach to threshold [mV]
## V_T # spike threshold [mV]
## S # membrane area [mum**2]
## trefractory # refractory time [ms]
## tspike # spike time [ms]
## tau_w # adaptation time constant
## a, b # adaptation parameters [muS, nA]
"""
aeIF = al.Dynamics(
name="AdaptiveExpIntegrateAndFire",
parameters=[
al.Parameter('C_m', un.capacitance),
al.Parameter('g_L', un.conductance),
al.Parameter('E_L', un.voltage),
al.Parameter('Delta', un.voltage),
al.Parameter('V_T', un.voltage),
al.Parameter('S'),
al.Parameter('trefractory', un.time),
al.Parameter('tspike', un.time),
al.Parameter('tau_w', un.time),
al.Parameter('a', un.dimensionless / un.voltage),
al.Parameter('b')],
state_variables=[
al.StateVariable('V', un.voltage),
al.StateVariable('w')],
regimes=[
al.Regime(
name="subthresholdregime",
time_derivatives=[
"dV/dt = -g_L*(V-E_L)/C_m + Isyn/C_m + g_L*Delta*exp((V-V_T)/Delta-w/S)/C_m", # @IgnorePep8
"dw/dt = (a*(V-E_L)-w)/tau_w", ],
transitions=al.On("V > V_T",
do=["V = E_L", "w = w + b",
al.OutputEvent('spikeoutput')],
to="refractoryregime")),
al.Regime(
name="refractoryregime",
transitions=al.On("t>=tspike+trefractory",
to="subthresholdregime"))],
analog_ports=[al.AnalogReducePort("Isyn", un.current, operator="+")])
return aeIF
def parameterise_adaptive_exponential(definition=None):
if definition is None:
definition = create_adaptive_exponential()
comp = ul.DynamicsProperties(
name='SampleAdaptiveExpIntegrateAndFire',
definition=definition,
properties=[ul.Property('C_m', 1 * un.pF),
ul.Property('g_L', 0.1 * un.nS),
ul.Property('E_L', -65 * un.mV),
ul.Property('Delta', 1 * un.mV),
ul.Property('V_T', -58 * un.mV),
ul.Property('S', 0.1),
ul.Property('tspike', 0.5 * un.ms),
ul.Property('trefractory', 0.25 * un.ms),
ul.Property('tau_w', 4 * un.ms),
ul.Property('a', 1 * un.per_mV),
ul.Property('b', 2)],
initial_values=[ul.Initial('V', -70 * un.mV),
ul.Initial('w', 0.1 * un.mV)])
return comp
Example - Hodgkin-Huxley¶
from __future__ import division
from past.utils import old_div
from nineml import abstraction as al, user as ul, Document
from nineml import units as un
from nineml.xml import E, etree
def create_hodgkin_huxley():
"""A Hodgkin-Huxley single neuron model.
Written by Andrew Davison.
See http://phobos.incf.ki.se/src_rst/
examples/examples_al_python.html#example-hh
"""
aliases = [
"q10 := 3.0**((celsius - qfactor)/tendegrees)", # temperature correction factor @IgnorePep8
"m_alpha := m_alpha_A*(V-m_alpha_V0)/(exp(-(V-m_alpha_V0)/m_alpha_K) - 1.0)", # @IgnorePep8
"m_beta := m_beta_A*exp(-(V-m_beta_V0)/m_beta_K)",
"mtau := 1.0/(q10*(m_alpha + m_beta))",
"minf := m_alpha/(m_alpha + m_beta)",
"h_alpha := h_alpha_A*exp(-(V-h_alpha_V0)/h_alpha_K)",
"h_beta := h_beta_A/(exp(-(V-h_beta_V0)/h_beta_K) + 1.0)",
"htau := 1.0/(q10*(h_alpha + h_beta))",
"hinf := h_alpha/(h_alpha + h_beta)",
"n_alpha := n_alpha_A*(V-n_alpha_V0)/(exp(-(V-n_alpha_V0)/n_alpha_K) - 1.0)", # @IgnorePep8
"n_beta := n_beta_A*exp(-(V-n_beta_V0)/n_beta_K)",
"ntau := 1.0/(q10*(n_alpha + n_beta))",
"ninf := n_alpha/(n_alpha + n_beta)",
"gna := gnabar*m*m*m*h",
"gk := gkbar*n*n*n*n",
"ina := gna*(ena - V)",
"ik := gk*(ek - V)",
"il := gl*(el - V )"]
hh_regime = al.Regime(
"dn/dt = (ninf-n)/ntau",
"dm/dt = (minf-m)/mtau",
"dh/dt = (hinf-h)/htau",
"dV/dt = (ina + ik + il + isyn)/C",
transitions=al.On("V > v_threshold", do=al.SpikeOutputEvent())
)
state_variables = [
al.StateVariable('V', un.voltage),
al.StateVariable('m', un.dimensionless),
al.StateVariable('n', un.dimensionless),
al.StateVariable('h', un.dimensionless)]
# the rest are not "parameters" but aliases, assigned vars, state vars,
# indep vars, analog_analog_ports, etc.
parameters = [
al.Parameter('el', un.voltage),
al.Parameter('C', un.capacitance),
al.Parameter('ek', un.voltage),
al.Parameter('ena', un.voltage),
al.Parameter('gkbar', un.conductance),
al.Parameter('gnabar', un.conductance),
al.Parameter('v_threshold', un.voltage),
al.Parameter('gl', un.conductance),
al.Parameter('celsius', un.temperature),
al.Parameter('qfactor', un.temperature),
al.Parameter('tendegrees', un.temperature),
al.Parameter('m_alpha_A', old_div(un.dimensionless, (un.time * un.voltage))),
al.Parameter('m_alpha_V0', un.voltage),
al.Parameter('m_alpha_K', un.voltage),
al.Parameter('m_beta_A', old_div(un.dimensionless, un.time)),
al.Parameter('m_beta_V0', un.voltage),
al.Parameter('m_beta_K', un.voltage),
al.Parameter('h_alpha_A', old_div(un.dimensionless, un.time)),
al.Parameter('h_alpha_V0', un.voltage),
al.Parameter('h_alpha_K', un.voltage),
al.Parameter('h_beta_A', old_div(un.dimensionless, un.time)),
al.Parameter('h_beta_V0', un.voltage),
al.Parameter('h_beta_K', un.voltage),
al.Parameter('n_alpha_A', old_div(un.dimensionless, (un.time * un.voltage))),
al.Parameter('n_alpha_V0', un.voltage),
al.Parameter('n_alpha_K', un.voltage),
al.Parameter('n_beta_A', old_div(un.dimensionless, un.time)),
al.Parameter('n_beta_V0', un.voltage),
al.Parameter('n_beta_K', un.voltage)]
analog_ports = [al.AnalogSendPort("V", un.voltage),
al.AnalogReducePort("isyn", un.current, operator="+")]
dyn = al.Dynamics("HodgkinHuxley",
parameters=parameters,
state_variables=state_variables,
regimes=(hh_regime,),
aliases=aliases,
analog_ports=analog_ports)
return dyn
def parameterise_hodgkin_huxley(definition=None):
if definition is None:
definition = create_hodgkin_huxley()
comp = ul.DynamicsProperties(
name='SampleHodgkinHuxley',
definition=create_hodgkin_huxley(),
properties=[ul.Property('C', 1.0 * un.pF),
ul.Property('celsius', 20.0 * un.degC),
ul.Property('ek', -90 * un.mV),
ul.Property('el', -65 * un.mV),
ul.Property('ena', 80 * un.mV),
ul.Property('gkbar', 30.0 * un.nS),
ul.Property('gl', 0.3 * un.nS),
ul.Property('gnabar', 130.0 * un.nS),
ul.Property('v_threshold', -40.0 * un.mV),
ul.Property('qfactor', 6.3 * un.degC),
ul.Property('tendegrees', 10.0 * un.degC),
ul.Property('m_alpha_A', -0.1,
old_div(un.unitless, (un.ms * un.mV))),
ul.Property('m_alpha_V0', -40.0 * un.mV),
ul.Property('m_alpha_K', 10.0 * un.mV),
ul.Property('m_beta_A', 4.0 * un.per_ms),
ul.Property('m_beta_V0', -65.0 * un.mV),
ul.Property('m_beta_K', 18.0 * un.mV),
ul.Property('h_alpha_A', 0.07 * un.per_ms),
ul.Property('h_alpha_V0', -65.0 * un.mV),
ul.Property('h_alpha_K', 20.0 * un.mV),
ul.Property('h_beta_A', 1.0 * un.per_ms),
ul.Property('h_beta_V0', -35.0 * un.mV),
ul.Property('h_beta_K', 10.0 * un.mV),
ul.Property('n_alpha_A', -0.01,
old_div(un.unitless, (un.ms * un.mV))),
ul.Property('n_alpha_V0', -55.0 * un.mV),
ul.Property('n_alpha_K', 10.0 * un.mV),
ul.Property('n_beta_A', 0.125 * un.per_ms),
ul.Property('n_beta_V0', -65.0 * un.mV),
ul.Property('n_beta_K', 80.0 * un.mV)],
initial_values=[ul.Initial('V', -70 * un.mV),
ul.Initial('m', 0.1),
ul.Initial('n', 0),
ul.Initial('h', 0.9)])
return comp
Example - Leaky Integrate and Fire¶
Example - Izhikevich¶
from __future__ import division
from past.utils import old_div
from nineml import units as un
from nineml import abstraction as al, user as ul, Document
from nineml.xml import etree, E
def create_izhikevich():
subthreshold_regime = al.Regime(
name="subthreshold_regime",
time_derivatives=[
"dV/dt = alpha*V*V + beta*V + zeta - U + Isyn / C_m",
"dU/dt = a*(b*V - U)", ],
transitions=[al.On("V > theta",
do=["V = c",
"U = U+ d",
al.OutputEvent('spike')],
to='subthreshold_regime')]
)
ports = [al.AnalogSendPort("V", un.voltage),
al.AnalogReducePort("Isyn", un.current, operator="+")]
parameters = [
al.Parameter('theta', un.voltage),
al.Parameter('a', un.per_time),
al.Parameter('b', un.per_time),
al.Parameter('c', un.voltage),
al.Parameter('d', old_div(un.voltage, un.time)),
al.Parameter('C_m', un.capacitance),
al.Parameter('alpha', old_div(un.dimensionless, (un.voltage * un.time))),
al.Parameter('beta', un.per_time),
al.Parameter('zeta', old_div(un.voltage, un.time))]
state_variables = [
al.StateVariable('V', un.voltage),
al.StateVariable('U', old_div(un.voltage, un.time))]
c1 = al.Dynamics(
name="Izhikevich",
parameters=parameters,
state_variables=state_variables,
regimes=[subthreshold_regime],
analog_ports=ports
)
return c1
def create_izhikevich_fast_spiking():
"""
Load Fast spiking Izhikevich XML definition from file and parse into
Abstraction Layer of Python API.
"""
izhi_fs = al.Dynamics(
name='IzhikevichFastSpiking',
parameters=[
al.Parameter('a', un.per_time),
al.Parameter('b', old_div(un.conductance, (un.voltage ** 2))),
al.Parameter('c', un.voltage),
al.Parameter('k', old_div(un.conductance, un.voltage)),
al.Parameter('Vr', un.voltage),
al.Parameter('Vt', un.voltage),
al.Parameter('Vb', un.voltage),
al.Parameter('Vpeak', un.voltage),
al.Parameter('Cm', un.capacitance)],
analog_ports=[
al.AnalogReducePort('iSyn', un.current, operator="+"),
al.AnalogSendPort('U', un.current),
al.AnalogSendPort('V', un.voltage)],
event_ports=[
al.EventSendPort("spikeOutput")],
state_variables=[
al.StateVariable('V', un.voltage),
al.StateVariable('U', un.current)],
regimes=[
al.Regime(
'dU/dt = a * (b * pow(V - Vb, 3) - U)',
'dV/dt = V_deriv',
transitions=[
al.On('V > Vpeak',
do=['V = c', al.OutputEvent('spikeOutput')],
to='subthreshold')],
name="subthreshold"),
al.Regime(
'dU/dt = - U * a',
'dV/dt = V_deriv',
transitions=[al.On('V > Vb', to="subthreshold")],
name="subVb")],
aliases=["V_deriv := (k * (V - Vr) * (V - Vt) - U + iSyn) / Cm"]) # @IgnorePep8
return izhi_fs
def parameterise_izhikevich(definition=None):
if definition is None:
definition = create_izhikevich()
comp = ul.DynamicsProperties(
name='SampleIzhikevich',
definition=create_izhikevich(),
properties=[ul.Property('a', 0.2 * un.per_ms),
ul.Property('b', 0.025 * un.per_ms),
ul.Property('c', -75 * un.mV),
ul.Property('d', 0.2 * un.mV / un.ms),
ul.Property('theta', -50 * un.mV),
ul.Property('alpha', 0.04 * un.unitless / (un.mV * un.ms)),
ul.Property('beta', 5 * un.per_ms),
ul.Property('zeta', 140.0 * un.mV / un.ms),
ul.Property('C_m', 1.0 * un.pF)],
initial_values=[ul.Initial('V', -70 * un.mV),
ul.Initial('U', -1.625 * un.mV / un.ms)])
return comp
def parameterise_izhikevich_fast_spiking(definition=None):
if definition is None:
definition = create_izhikevich_fast_spiking()
comp = ul.DynamicsProperties(
name='SampleIzhikevichFastSpiking',
definition=create_izhikevich_fast_spiking(),
properties=[ul.Property('a', 0.2 * un.per_ms),
ul.Property('b', 0.025 * un.nS / un.mV ** 2),
ul.Property('c', -45 * un.mV),
ul.Property('k', 1 * un.nS / un.mV),
ul.Property('Vpeak', 25 * un.mV),
ul.Property('Vb', -55 * un.mV),
ul.Property('Cm', 20 * un.pF),
ul.Property('Vr', -55 * un.mV),
ul.Property('Vt', -40 * un.mV)],
initial_values=[ul.Initial('V', -70 * un.mV),
ul.Initial('U', -1.625 * un.mV / un.ms)])
return comp
Plasticity Models¶
Example - Static¶
from __future__ import print_function
from nineml import units as un, user as ul, abstraction as al, Document
from nineml.xml import etree, E
def create_static():
dyn = al.Dynamics(
name="Static",
aliases=["fixed_weight := weight"],
regimes=[
al.Regime(name="default")],
analog_ports=[al.AnalogSendPort("fixed_weight", dimension=un.current)],
parameters=[al.Parameter('weight', dimension=un.current)])
return dyn
def parameterise_static():
comp = ul.DynamicsProperties(
name='SampleAlpha',
definition=create_static(),
properties=[ul.Property('weight', 10.0 * un.nA)])
return comp
if __name__ == '__main__':
import argparse
try:
import ninemlcatalog
catalog_path = 'plasticity/Static'
except ImportError:
ninemlcatalog = None
parser = argparse.ArgumentParser()
parser.add_argument('--mode', type=str, default='print',
help=("The mode to run this script, can be 'print', "
"'compare' or 'save', which correspond to "
"printing the models, comparing the models with "
"the version in the catalog, or overwriting the "
"version in the catalog with this version "
"respectively"))
args = parser.parse_args()
if args.mode == 'print':
document = Document()
print(etree.tostring(
E.NineML(
create_static().to_xml(document),
parameterise_static().to_xml(document)),
encoding="UTF-8", pretty_print=True, xml_declaration=True))
elif args.mode == 'compare':
if ninemlcatalog is None:
raise Exception(
"NineML catalog is not installed")
local_version = create_static()
catalog_version = ninemlcatalog.load(catalog_path,
local_version.name)
mismatch = local_version.find_mismatch(catalog_version)
if mismatch:
print ("Local version differs from catalog version:\n{}"
.format(mismatch))
else:
print("Local version matches catalog version")
elif args.mode == 'save':
if ninemlcatalog is None:
raise Exception(
"NineML catalog is not installed")
dynamics = create_static()
ninemlcatalog.save(dynamics, catalog_path, dynamics.name)
params = parameterise_static(
ninemlcatalog.load(catalog_path, dynamics.name))
ninemlcatalog.save(params, catalog_path, params.name)
print("Saved '{}' and '{}' to catalog".format(dynamics.name,
params.name))
Example - Guetig Spike-timing Dependent Plasticity (STDP)¶
from nineml import units as un, user as ul, abstraction as al
def create_stdp_guetig():
dyn = al.Dynamics(
name="StdpGuetig",
parameters=[
al.Parameter(name='tauLTP', dimension=un.time),
al.Parameter(name='aLTD', dimension=un.dimensionless),
al.Parameter(name='wmax', dimension=un.dimensionless),
al.Parameter(name='muLTP', dimension=un.dimensionless),
al.Parameter(name='tauLTD', dimension=un.time),
al.Parameter(name='aLTP', dimension=un.dimensionless)],
analog_ports=[
al.AnalogReceivePort(dimension=un.dimensionless, name="w"),
al.AnalogSendPort(dimension=un.dimensionless, name="wsyn")],
event_ports=[
al.EventReceivePort(name="incoming_spike")],
state_variables=[
al.StateVariable(name='tlast_post', dimension=un.time),
al.StateVariable(name='tlast_pre', dimension=un.time),
al.StateVariable(name='deltaw', dimension=un.dimensionless),
al.StateVariable(name='interval', dimension=un.time),
al.StateVariable(name='M', dimension=un.dimensionless),
al.StateVariable(name='P', dimension=un.dimensionless),
al.StateVariable(name='wsyn', dimension=un.dimensionless)],
regimes=[
al.Regime(
name="sole",
al.On('incoming_spike',
target_regime="sole",
do=[
al.StateAssignment(
'tlast_post',
'((w >= 0) ? ( tlast_post ) : ( t ))'),
al.StateAssignment(
'tlast_pre',
'((w >= 0) ? ( t ) : ( tlast_pre ))'),
al.StateAssignment(
'deltaw',
'((w >= 0) ? '
'( 0.0 ) : '
'( P*pow(wmax - wsyn, muLTP) * '
'exp(-interval/tauLTP) + deltaw ))'),
al.StateAssignment(
'interval',
'((w >= 0) ? ( -t + tlast_post ) : '
'( t - tlast_pre ))'),
al.StateAssignment(
'M',
'((w >= 0) ? ( M ) : '
'( M*exp((-t + tlast_post)/tauLTD) - aLTD ))'),
al.StateAssignment(
'P',
'((w >= 0) ? '
'( P*exp((-t + tlast_pre)/tauLTP) + aLTP ) : '
'( P ))'),
al.StateAssignment(
'wsyn', '((w >= 0) ? ( deltaw + wsyn ) : '
'( wsyn ))')]))])
return dyn
def parameterise_stdp_guetig():
comp = ul.DynamicsProperties(
name='SampleAlpha',
definition=create_stdp_guetig(),
properties=[])
return comp
Network Models¶
Example - Brunel¶
# encoding: utf-8
"""
Network model from
Brunel, N. (2000) J. Comput. Neurosci. 8: 183-208
expressed in NineML using the Python API
Author: Andrew P. Davison, UNIC, CNRS
June 2014
Edited by Thomas G. Close, October 2015
"""
from __future__ import division
from nineml.user import (
DynamicsProperties, Population, RandomDistributionProperties,
Projection, ConnectionRuleProperties, AnalogPortConnection,
EventPortConnection, Network, Selection, Concatenate)
from nineml.units import ms, mV, nA, unitless, Hz, Mohm
import ninemlcatalog
def create_brunel(g, eta, name=None):
"""
Build a NineML representation of the Brunel (2000) network model.
Arguments:
g: relative strength of inhibitory synapses
eta: nu_ext / nu_thresh
Returns:
a nineml user layer Model object
"""
# Meta-parameters
order = 1000 # scales the size of the network
Ne = 4 * order # number of excitatory neurons
Ni = 1 * order # number of inhibitory neurons
epsilon = 0.1 # connection probability
Ce = int(epsilon * Ne) # number of excitatory synapses per neuron
Ci = int(epsilon * Ni) # number of inhibitory synapses per neuron
Cext = Ce # effective number of external synapses per neuron
delay = 1.5 # (ms) global delay for all neurons in the group
J = 0.1 # (mV) EPSP size
Jeff = 24.0 * J # (nA) synaptic weight
Je = Jeff # excitatory weights
Ji = -g * Je # inhibitory weights
Jext = Je # external weights
theta = 20.0 # firing thresholds
tau = 20.0 # membrane time constant
tau_syn = 0.1 # synapse time constant
# nu_thresh = theta / (Je * Ce * tau * exp(1.0) * tau_syn) # threshold rate
nu_thresh = theta / (J * Ce * tau)
nu_ext = eta * nu_thresh # external rate per synapse
input_rate = 1000.0 * nu_ext * Cext # mean input spiking rate
# Parameters
neuron_parameters = dict(tau=tau * ms,
v_threshold=theta * mV,
refractory_period=2.0 * ms,
v_reset=10.0 * mV,
R=1.5 * Mohm) # units??
psr_parameters = dict(tau=tau_syn * ms)
# Initial Values
v_init = RandomDistributionProperties(
"uniform_rest_to_threshold",
ninemlcatalog.load("randomdistribution/Uniform",
'UniformDistribution'),
{'minimum': (0.0, unitless),
'maximum': (theta, unitless)})
# v_init = 0.0
neuron_initial_values = {"v": (v_init * mV),
"refractory_end": (0.0 * ms)}
synapse_initial_values = {"a": (0.0 * nA), "b": (0.0 * nA)}
tpoisson_init = RandomDistributionProperties(
"exponential_beta",
ninemlcatalog.load('randomdistribution/Exponential',
'ExponentialDistribution'),
{"rate": (1000.0 / input_rate * unitless)})
# tpoisson_init = 5.0
# Dynamics components
celltype = DynamicsProperties(
"nrn",
ninemlcatalog.load('neuron/LeakyIntegrateAndFire',
'LeakyIntegrateAndFire'),
neuron_parameters, initial_values=neuron_initial_values)
ext_stim = DynamicsProperties(
"stim",
ninemlcatalog.load('input/Poisson', 'Poisson'),
dict(rate=(input_rate, Hz)),
initial_values={"t_next": (tpoisson_init, ms)})
psr = DynamicsProperties(
"syn",
ninemlcatalog.load('postsynapticresponse/Alpha', 'Alpha'),
psr_parameters,
initial_values=synapse_initial_values)
# Connecion rules
one_to_one_class = ninemlcatalog.load(
'/connectionrule/OneToOne', 'OneToOne')
random_fan_in_class = ninemlcatalog.load(
'/connectionrule/RandomFanIn', 'RandomFanIn')
# Populations
exc_cells = Population("Exc", Ne, celltype, positions=None)
inh_cells = Population("Inh", Ni, celltype, positions=None)
external = Population("Ext", Ne + Ni, ext_stim, positions=None)
# Selections
all_cells = Selection(
"All", Concatenate((exc_cells, inh_cells)))
# Projections
input_prj = Projection(
"External", external, all_cells,
connection_rule_properties=ConnectionRuleProperties(
"OneToOne", one_to_one_class),
response=psr,
plasticity=DynamicsProperties(
"ExternalPlasticity",
ninemlcatalog.load("plasticity/Static", 'Static'),
properties={"weight": (Jext, nA)}),
port_connections=[
EventPortConnection(
'pre', 'response', 'spike_output', 'spike'),
AnalogPortConnection(
"plasticity", "response", "fixed_weight", "weight"),
AnalogPortConnection(
"response", "destination", "i_synaptic", "i_synaptic")],
delay=(delay, ms))
exc_prj = Projection(
"Excitation", exc_cells, all_cells,
connection_rule_properties=ConnectionRuleProperties(
"RandomExc", random_fan_in_class, {"number": (Ce * unitless)}),
response=psr,
plasticity=DynamicsProperties(
"ExcitatoryPlasticity",
ninemlcatalog.load("plasticity/Static", 'Static'),
properties={"weight": (Je, nA)}),
port_connections=[
EventPortConnection(
'pre', 'response', 'spike_output', 'spike'),
AnalogPortConnection(
"plasticity", "response", "fixed_weight", "weight"),
AnalogPortConnection(
"response", "destination", "i_synaptic", "i_synaptic")],
delay=(delay, ms))
inh_prj = Projection(
"Inhibition", inh_cells, all_cells,
connection_rule_properties=ConnectionRuleProperties(
"RandomInh", random_fan_in_class, {"number": (Ci * unitless)}),
response=psr,
plasticity=DynamicsProperties(
"InhibitoryPlasticity",
ninemlcatalog.load("plasticity/Static", 'Static'),
properties={"weight": (Ji, nA)}),
port_connections=[
EventPortConnection(
'pre', 'response', 'spike_output', 'spike'),
AnalogPortConnection(
"plasticity", "response", "fixed_weight", "weight"),
AnalogPortConnection(
"response", "destination", "i_synaptic", "i_synaptic")],
delay=(delay, ms))
# Save to document in NineML Catalog
network = Network(name if name else "BrunelNetwork")
network.add(exc_cells, inh_cells, external, all_cells, input_prj, exc_prj,
inh_prj)
return network