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

from nineml import abstraction as al, user as ul, Document
from nineml import units as un
from nineml.xml import etree, E


def create_leaky_integrate_and_fire():
    dyn = al.Dynamics(
        name='LeakyIntegrateAndFire',
        regimes=[
            al.Regime('dv/dt = (i_synaptic*R - v)/tau',
                      transitions=[al.On('v > v_threshold',
                                         do=[al.OutputEvent('spike_output'),
                                             al.StateAssignment(
                                                 'refractory_end',
                                                 't + refractory_period'),
                                             al.StateAssignment('v',
                                                                'v_reset')],
                                         to='refractory')],
                      name='subthreshold'),
            al.Regime(transitions=[al.On('t > refractory_end',
                                   to='subthreshold')],
                      name='refractory')],
        state_variables=[al.StateVariable('v', dimension=un.voltage),
                         al.StateVariable('refractory_end',
                                          dimension=un.time)],
        parameters=[al.Parameter('R', un.resistance),
                    al.Parameter('refractory_period', un.time),
                    al.Parameter('v_reset', un.voltage),
                    al.Parameter('v_threshold', un.voltage),
                    al.Parameter('tau', un.time)],
        analog_ports=[al.AnalogReducePort('i_synaptic', un.current,
                                          operator='+'),
                      al.AnalogSendPort('refractory_end', un.time),
                      al.AnalogSendPort('v', un.voltage)])

    return dyn


def parameterise_leaky_integrate_and_fire(definition=None):
    if definition is None:
        definition = create_leaky_integrate_and_fire()
    comp = ul.DynamicsProperties(
        name='SampleLeakyIntegrateAndFire',
        definition=create_leaky_integrate_and_fire(),
        properties=[ul.Property('tau', 20.0 * un.ms),
                    ul.Property('v_threshold', 20.0 * un.mV),
                    ul.Property('refractory_period', 2.0 * un.ms),
                    ul.Property('v_reset', 10.0 * un.mV),
                    ul.Property('R', 1.5 * un.Mohm)],
        initial_values=[ul.Initial('V', -70 * un.mV)])
    return comp

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

Post-synaptic Response Models

Example - Alpha

from nineml import units as un, user as ul, abstraction as al, Document
from nineml.xml import etree, E


def create_alpha():
    dyn = al.Dynamics(
        name="Alpha",
        aliases=["Isyn := A"],
        regimes=[
            al.Regime(
                name="default",
                time_derivatives=[
                    "dA/dt = (B - A)/tau",  # TGC 4/15 changed from "B - A/tau_syn" as dimensions didn't add up @IgnorePep8
                    "dB/dt = -B/tau"],
                transitions=al.On('spike',
                                  do=["B = B + q"]))],
        state_variables=[
            al.StateVariable('A', dimension=un.current),
            al.StateVariable('B', dimension=un.current),
        ],
        analog_ports=[al.AnalogSendPort("Isyn", dimension=un.current),
                      al.AnalogSendPort("A", dimension=un.current),
                      al.AnalogSendPort("B", dimension=un.current),
                      al.AnalogReceivePort("q", dimension=un.current)],
        parameters=[al.Parameter('tau', dimension=un.time)])
    return dyn


def parameterise_alpha():

    comp = ul.DynamicsProperties(
        name='SampleAlpha',
        definition=create_alpha(),
        properties=[ul.Property('tau', 20.0 * un.ms)],
        initial_values=[ul.Initial('a', 0.0 * un.pA),
                        ul.Initial('b', 0.0 * un.pA)])
    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