Using non-standard/native cell and synapse models¶
Standard models are neuron/synapse models that are available in at least two of the simulation engines supported by PyNN. Non-standard models, then, work only with a single simulator. We also call these “native” models.
With native models, we lose full simulator-independence. However, for people who work mainly with a single simulator, native models allow them to use PyNN’s high-level API for building and instrumenting networks but with a broader range of neuron and synapse models. This is also often a useful intermediate step in converting a native network model to PyNN.
Using native NEST models¶
To use a NEST neuron model with PyNN, we wrap the NEST model with a PyNN
NativeCellType
class, e.g.:
>>> from pyNN.nest import native_cell_type, Population, run, setup
>>> setup()
>>> ht_neuron = native_cell_type('ht_neuron')
>>> poisson = native_cell_type('poisson_generator')
>>> p1 = Population(10, ht_neuron, {'Tau_m': 20.0})
>>> p2 = Population(1, poisson, {'rate': 200.0})
We can now initialize state variables, set/get parameter values, and record from these neurons as from standard cells:
>>> p1.get('Tau_m')
[20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0]
>>> p1.get('Tau_theta')
[2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
>>> p1.get('C_m')
NonExistentParameterError: C_m (valid parameters for ht_neuron are:
AMPA_E_rev, AMPA_Tau_1, AMPA_Tau_2, AMPA_g_peak, E_K, E_Na, GABA_A_E_rev,
GABA_A_Tau_1, GABA_A_Tau_2, GABA_A_g_peak, GABA_B_E_rev, GABA_B_Tau_1,
GABA_B_Tau_2, GABA_B_g_peak, KNa_E_rev, KNa_g_peak, NMDA_E_rev, NMDA_Sact,
NMDA_Tau_1, NMDA_Tau_2, NMDA_Vact, NMDA_g_peak, NaP_E_rev, NaP_g_peak,
T_E_rev, T_g_peak, Tau_m, Tau_spike, Tau_theta, Theta_eq, g_KL, g_NaL,
h_E_rev, h_g_peak, spike_duration)
>>> p1.initialize('V_m', -70.0)
>>> p1.initialize('Theta', -50.0)
Note that the API for recording is somewhat clumsy for native models, and will be improved in the next PyNN release:
>>> p1._record('V_m')
>>> run(250.0)
>>> id, t, v = p1.recorders['V_m'].get().T
To connect populations of native cells, you need to know the available synaptic receptor types:
>>> ht_neuron.synapse_types
{'AMPA': 1, 'GABA_A': 3, 'GABA_B': 4, 'NMDA': 2}
>>> from pyNN.nest import Projection, AllToAllConnector
>>> connector = AllToAllConnector()
>>> prj_ampa = Projection(p2, p1, connector, target='AMPA')
>>> prj_nmda = Projection(p2, p1, connector, target='NMDA')
To use a NEST STDP model with PyNN, we use the NativeSynapseDynamics
class:
>>> from pyNN.nest import NativeSynapseDynamics
>>> stdp = NativeSynapseDynamics("stdp_synapse", {'Wmax': 50.0, 'lambda': 0.015})
>>> prj_plastic = Projection(p1, p1, connector, target='AMPA', synapse_dynamics=stdp)
Using native NEURON models¶
A native NEURON cell model is described using a Python class (which may wrap a Hoc template). For this class to work with PyNN, there are a small number of requirements:
the
__init__()
method should take just**parameters
as its argument.instances should have attributes:
source
: a reference to the membrane potential which will bemonitored for spike emission, e.g.
self.soma(0.5)._ref_v
source_section
: the HocSection
in whichsource
is located.
parameter_names
: a tuple of the names of attributes/properties ofthe class that correspond to parameters of the model.
traces
: an empty dict, used for recording.
recording_time
: should beFalse
initially.there must be
memb_init()
method, taking no arguments.
Here is an example, which uses the nrnutils package for conciseness:
from nrnutils import Mechanism, Section
class SimpleNeuron(object):
def __init__(self, **parameters):
hh = Mechanism('hh', gl=parameters['g_leak'], el=-65,
gnabar=parameters['gnabar'], gkbar=parameters['gkbar'])
self.soma = Section(L=30, diam=30, mechanisms=[hh])
self.soma.add_synapse('ampa', 'Exp2Syn', e=0.0, tau1=0.1, tau2=5.0)
# needed for PyNN
self.source_section = self.soma
self.source = self.soma(0.5)._ref_v
self.parameter_names = ('g_leak', 'gnabar', 'gkbar')
self.traces = {}
self.recording_time = False
def _set_gnabar(self, value):
for seg in self.soma:
seg.hh.gnabar = value
def _get_gnabar(self):
return self.soma(0.5).hh.gnabar
gnabar = property(fget=_get_gnabar, fset=_set_gnabar)
# ... gkbar and g_leak properties defined similarly
def memb_init(self):
for seg in self.soma:
seg.v = self.v_init
For each cell model, you must also define a cell type:
class SimpleNeuronType(NativeCellType):
default_parameters = {'g_leak': 0.0002, 'gkbar': 0.036, 'gnabar': 0.12}
default_initial_values = {'v': -65.0}
recordable = ['soma(0.5).v', 'soma(0.5).ina']
model = SimpleNeuron
The requirement to explicitly list all variables you might wish to record in the
recordable
attribute is a temporary inconvenience, which will be removed in
a future version.
It is now straightforward to use this cell type in PyNN:
>>> from pyNN.neuron import setup, run, Population, Projection, AllToAllConnector
>>> setup()
>>> p1 = Population(10, SimpleNeuronType, {'g_leak': 0.0003})
>>> p1._record('soma(0.5).ina')
>>> prj = Projection(p1, p1, AllToAllConnector(), target='soma.ampa')
>>> run(100.0)
>>> id, t, ina = p1.recorders['soma(0.5).ina'].get().T