======
NEURON
======

.. testsetup:: cvode

    from pyNN.neuron import *


Configuration options
=====================

Adaptive time step integration
------------------------------

The default integration method used by the :mod:`pyNN.neuron` backend uses a
fixed time step, specified by the *timestep* argument to the :func:`setup`
function.

NEURON also supports use of variable time step methods, which can improve
simulation speed:

.. testcode:: cvode

    setup(use_cvode=True)

If using *cvode*, there are two more optional parameters:

.. testcode:: cvode

    setup(use_cvode=True,
          rtol=0.001, # specify relative error tolerance
          atol=1e-4)  # specify absolute error tolerance

If not specified, the default values are *rtol = 0* and *atol = 0.001*. For full
details, see the `CVode documentation`_

.. todo:: native_rng_baseseed is added to MPI.rank to form seed for SpikeSourcePoisson, etc., but I think it would be better to add a `seed` parameter to SpikeSourcePoisson

.. todo:: Population.get_data() does not yet handle cvode properly.


Using native cell 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 :meth:`__init__` method should take just ``**parameters`` as its argument.
    - instances should have attributes:

        - :attr:`source`: a reference to the membrane potential which will be
                          monitored for spike emission, e.g. ``self.soma(0.5)._ref_v``
        - :attr:`source_section`: the Hoc :class:`Section` in which :attr:`source` is located.
        - :attr:`parameter_names`: a tuple of the names of attributes/properties of
                                   the class that correspond to parameters of the model.
        - :attr:`traces`: an empty dict, used for recording.
        - :attr:`recording_time`: should be ``False`` initially.

    - there must be a :meth:`memb_init` method, taking no arguments.

Here is an example, which uses the nrnutils_ package for conciseness:

.. testcode:: nativemodel

    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

.. testcode:: nativemodel
   :hide:

   SimpleNeuron.gkbar = 0.0
   SimpleNeuron.g_leak = 0.0


For each cell model, you must also define a cell type:

.. testcode:: nativemodel

    from pyNN.neuron import NativeCellType

    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']
        units = {'soma(0.5).v' : 'mV', 'soma(0.5).ina': 'nA'}
        receptor_types = ['soma.ampa']
        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:

.. testcode:: nativemodel

    from pyNN.neuron import setup, run, Population, Projection, AllToAllConnector, StaticSynapse
    setup()
    p1 = Population(10, SimpleNeuronType(g_leak=0.0003))
    p1.record('soma(0.5).ina')
    syn = StaticSynapse(weight=0.01, delay=0.5)
    prj = Projection(p1, p1, AllToAllConnector(), syn, receptor_type='soma.ampa')
    run(100.0)
    output = p1.get_data()


If your model relies on other NMODL mechanisms, call the
:func:`~pyNN.neuron.load_mechanisms` function with the path to the directory
containing the :file:`.mod` files.

It is also possible to use NEURON "ARTIFICIAL_CELL" models, such as :class:`IntFire1`,
 :class:`IntFire2` and :class:`IntFire4`:

.. testcode:: nativemodel

    from pyNN.neuron import setup, Population, IntFire1
    setup()
    p1 = Population(10, IntFire1(tau=10.0, refrac=2.5))
    p1.record('m')


.. _`CVode documentation`: http://www.neuron.yale.edu/neuron/static/docs/help/neuron/neuron/classes/cvode.html
.. _nrnutils: https://pypi.python.org/pypi/nrnutils/
