# encoding: utf-8
"""
nrnpython implementation of the PyNN API.
:copyright: Copyright 2006-2020 by the PyNN team, see AUTHORS.
:license: CeCILL, see LICENSE for details.
"""
import numpy
import logging
from pyNN import common
from pyNN.parameters import ArrayParameter, Sequence, ParameterSpace, simplify, LazyArray
from pyNN.standardmodels import StandardCellType
from pyNN.random import RandomDistribution
from . import simulator
from .recording import Recorder
logger = logging.getLogger("PyNN")
class PopulationMixin(object):
def _set_parameters(self, parameter_space):
"""parameter_space should contain native parameters"""
parameter_space.evaluate(mask=numpy.where(self._mask_local)[0])
for cell, parameters in zip(self, parameter_space):
for name, val in parameters.items():
setattr(cell._cell, name, val)
def _get_parameters(self, *names):
"""
return a ParameterSpace containing native parameters
"""
parameter_dict = {}
for name in names:
if name == 'spike_times': # hack
parameter_dict[name] = [Sequence(getattr(id._cell, name)) for id in self]
else:
val = numpy.array([getattr(id._cell, name) for id in self])
if isinstance(val[0], tuple) or len(val.shape) == 2:
val = numpy.array([ArrayParameter(v) for v in val])
val = LazyArray(simplify(val), shape=(self.local_size,), dtype=ArrayParameter)
parameter_dict[name] = val
else:
parameter_dict[name] = simplify(val)
parameter_dict[name] = simplify(val)
return ParameterSpace(parameter_dict, shape=(self.local_size,))
def _set_initial_value_array(self, variable, initial_values):
if initial_values.is_homogeneous:
value = initial_values.evaluate(simplify=True)
for cell in self: # only on local node
setattr(cell._cell, "%s_init" % variable, value)
else:
if isinstance(initial_values.base_value, RandomDistribution) and initial_values.base_value.rng.parallel_safe:
local_values = initial_values.evaluate()[self._mask_local]
else:
local_values = initial_values[self._mask_local]
for cell, value in zip(self, local_values):
setattr(cell._cell, "%s_init" % variable, value)
[docs]class Assembly(common.Assembly):
__doc__ = common.Assembly.__doc__
_simulator = simulator
[docs]class PopulationView(common.PopulationView, PopulationMixin):
__doc__ = common.PopulationView.__doc__
_simulator = simulator
_assembly_class = Assembly
def _get_view(self, selector, label=None):
return PopulationView(self, selector, label)
[docs]class Population(common.Population, PopulationMixin):
__doc__ = common.Population.__doc__
_simulator = simulator
_recorder_class = Recorder
_assembly_class = Assembly
def __init__(self, size, cellclass, cellparams=None, structure=None,
initial_values={}, label=None):
__doc__ = common.Population.__doc__
common.Population.__init__(self, size, cellclass, cellparams,
structure, initial_values, label)
simulator.initializer.register(self)
def _get_view(self, selector, label=None):
return PopulationView(self, selector, label)
def _create_cells(self):
"""
Create cells in NEURON using the celltype of the current Population.
"""
# this method should never be called more than once
# perhaps should check for that
self.first_id = simulator.state.gid_counter
self.last_id = simulator.state.gid_counter + self.size - 1
self.all_cells = numpy.array([id for id in range(self.first_id, self.last_id + 1)],
simulator.ID)
# mask_local is used to extract those elements from arrays that apply to the cells on the current node
# round-robin distribution of cells between nodes
self._mask_local = self.all_cells % simulator.state.num_processes == simulator.state.mpi_rank
if isinstance(self.celltype, StandardCellType):
parameter_space = self.celltype.native_parameters
else:
parameter_space = self.celltype.parameter_space
parameter_space.shape = (self.size,)
parameter_space.evaluate(mask=None)
for i, (id, is_local, params) in enumerate(zip(self.all_cells, self._mask_local, parameter_space)):
self.all_cells[i] = simulator.ID(id)
self.all_cells[i].parent = self
if is_local:
if hasattr(self.celltype, "extra_parameters"):
params.update(self.celltype.extra_parameters)
self.all_cells[i]._build_cell(self.celltype.model, params)
simulator.initializer.register(*self.all_cells[self._mask_local])
simulator.state.gid_counter += self.size
def _native_rset(self, parametername, rand_distr):
"""
'Random' set. Set the value of parametername to a value taken from
rand_distr, which should be a RandomDistribution object.
"""
assert isinstance(rand_distr.rng, NativeRNG)
rng = simulator.h.Random(rand_distr.rng.seed or 0)
native_rand_distr = getattr(rng, rand_distr.name)
rarr = [native_rand_distr(*rand_distr.parameters)] + [rng.repick() for i in range(self.all_cells.size - 1)]
self.tset(parametername, rarr)