Source code for uncertainpy.models.neuron_model

from __future__ import absolute_import, division, print_function, unicode_literals

import os

import numpy as np
import importlib

from .model import Model
from ..utils.logger import setup_module_logger, get_logger


[docs]class NeuronModel(Model): """ Class for Neuron simulator models. Loads a Neuron simulation, runs it, and measures the voltage in the soma. Parameters ---------- file : str, optional Filename of the Neuron model. Default is ``"mosinit.hoc"``. path : str, optional Path to the Neuron model. If None, the file is considered to be in the current folder. Default is "". stimulus_start : {int, float, None}, optional The start time of any stimulus given to the neuron model. This is added to the info dictionary. If None, no stimulus_start is added to the info dictionary. Default is None. stimulus_end : {int, float, None}, optional The end time of any stimulus given to the neuron model. This is added to the info dictionary. If None, no stimulus_end is added to the info dictionary. Default is None. interpolate : bool, optional True if the model is irregular, meaning it has a varying number of return values between different model evaluations, and an interpolation of the results is performed. Default is False. name : {None, str}, optional Name of the model, if None the model gets the name of the current class. Default is None. ignore : bool, optional Ignore the model results when calculating uncertainties, which means the uncertainty is not calculated for the model. Default is False. run : {None, callable}, optional A function that implements the model. See the ``run`` method for requirements of the function. Default is None. record_from : {str}, optional Name of the section in the NEURON model where voltage should be recorded. Default is ``"soma"``. labels : list, optional A list of label names for the axes when plotting the model. On the form ``["x-axis", "y-axis", "z-axis"]``, with the number of axes that is correct for the model output. Default is ``["Time (ms)", "Membrane potential (mv)"]``. suppress_graphics : bool, optional Suppress all graphics created by the Neuron model. Default is True. logger_level : {"info", "debug", "warning", "error", "critical", None}, optional Set the threshold for the logging level. Logging messages less severe than this level is ignored. If None, no logging to file is performed Default logger level is "info". info : dict, optional Dictionary added to info. Default is an empty dictionary. **model_kwargs Any number of arguments passed to the model function when it is run. Attributes ---------- run : uncertainpy.models.Model.run labels : list A list of label names for the axes when plotting the model. On the form ``["x-axis", "y-axis", "z-axis"]``, with the number of axes that is correct for the model output. interpolate : bool True if the model is irregular, meaning it has a varying number of return values between different model evaluations, and an interpolation of the results is performed. Default is False. suppress_graphics : bool Suppress all graphics created by the model. ignore : bool Ignore the model results when calculating uncertainties, which means the uncertainty is not calculated for the model. The model results are still postprocessed if a postprocessing is implemented. Default is False. Raises ------ RuntimeError If no section with name ``soma`` is found in the Neuron model. Notes ----- Measures the voltage in the section with name ``soma``. """ def __init__(self, file="mosinit.hoc", path="", interpolate=True, stimulus_start=None, stimulus_end=None, name=None, ignore=False, run=None, record_from="soma", labels=["Time (ms)", "Membrane potential (mV)"], suppress_graphics=True, logger_level="info", info={}, **model_kwargs): super(NeuronModel, self).__init__(interpolate=interpolate, ignore=ignore, labels=labels, suppress_graphics=suppress_graphics, **model_kwargs) self.file = file self.path = path self.info = info if stimulus_end: self.info["stimulus_end"] = stimulus_end if stimulus_start: self.info["stimulus_start"] = stimulus_start if run is not None: self.run = run if name: self.name = name self.time = None self.V = None self.rec_section = record_from setup_module_logger(class_instance=self, level=logger_level)
[docs] def load_neuron(self, path, file): """ Import neuron and a neuron simulation file. Parameters ---------- file : str Filename of the Neuron model. must be a ``.hoc`` file. path : str Path to the Neuron model. Returns ------- h : Neuron object Neurons h object. Raises ------ ImportError If neuron is not installed. """ current_dir = os.getcwd() os.chdir(path) try: import neuron except ImportError: raise ImportError("NeuronModel requires: neuron") h = neuron.h h.load_file(0, file.encode()) os.chdir(current_dir) return h
[docs] def load_python(self, path, file, name): """ Import a Python neuron simulation located in function in `path`/`file` with name `name`. Parameters ---------- file : str Filename of the Neuron model. must be a ``.hoc`` file. path : str Path to the Neuron model. name : str Name of the run function. Returns ------- model : a run function A python function imported from `path`/`file` with name `name`. See also -------- uncertainpy.models.Model.run : Requirements for the model run function. """ current_dir = os.getcwd() if path: os.chdir(path) file = file.strip(".py") module_path = os.path.join(path, file) module_path = module_path.strip(os.sep) module_name = module_path.replace(os.sep, ".") module = importlib.import_module(module_name) model = getattr(module, name) os.chdir(current_dir) return model
# Be really careful with these. Need to make sure that all references to # neuron are inside this class def _record(self, ref_data): """ Record data from a neuron simulation. """ data = self.h.Vector() data.record(getattr(self.h, ref_data)) return data def _to_array(self, hocObject): """ Convert a Neuron Vector object to an array. Parameters ---------- hocObject : A Neuron Vector object. A Neuron Vector object to convert to an array. Returns ------- array : array The converted array. """ array = np.zeros(int(round(hocObject.size()))) hocObject.to_python(array) return array def _record_v(self): """ Record voltage in the requested compartment. Raises ------ RuntimeError If no section with name ``self.compartment`` is found in the Neuron model. """ # Check if the requested compartment is defined in the model and proceed # only if it is found. All this processing is case insensitive. section_names = [s.name().lower() for s in self.h.allsec()] if self.rec_section.lower() not in section_names: raise RuntimeError( "No section with name {c} found in {n}. Unable to record.".format( c=self.rec_section, n=self.name)) compartment_ind = section_names.index(self.rec_section.lower()) section = list(self.h.allsec())[compartment_ind] self.h("objref voltage_soma") self.h("voltage_soma = new Vector()") self.h.voltage_soma.record(section(0.5)._ref_v) # Final check to make sure NEURON accepted the commands. if not hasattr(self.h, "voltage_soma"): raise RuntimeError( "No section with name {c} found in {n}. Unable to record.".format( c=self.rec_section, n=self.name)) def _record_t(self): """ Record time values """ if self.time is None: self.time = self._record("_ref_t") @Model.run.setter def run(self, new_run): """ Load, either from a NEURON or Python file, and run a Neuron simulation and return the model result. Parameters ---------- **parameters : A number of named arguments (name=value). The parameters of the model which are either set in Neuron or given as arguments to the Python run function. Returns ------- time : array Time values of the model. values : array Voltage of the neuron. Note that `values` must either be regular (have the same number of points for different parameters) or be able to be interpolated. info : dictionary A dictionary with information needed by features. ``"stimulus_start"`` and ``"stimulus_end"`` are returned in the info dictionary if they are given as parameters to ``NeuronModel``. If a info dictionary is returned by the model function it is updated with ``"stimulus_start"`` and ``"stimulus_end"`` if they are given as parameters to ``NeuronModel``. Notes ----- The Python neuron simulation is located in a function in `path`/`file` and name `name`. At least `file` and `name` must be given. A NEURON simulation is located in a ``.hoc`` file and returns the model voltage in soma. Efel features require ``"stimulus_start"`` and ``"stimulus_end"`` as keys, while spiking_features require ``stimulus_start"``. See also -------- uncertainpy.models.Model.run : Requirements for the model run function. """ Model.run.fset(self, new_run) def _run(self, **parameters): if self.file.endswith(".hoc"): result = self.run_neuron(**parameters) elif self.file.endswith(".py"): result = self.run_python(**parameters) else: raise ValueError("Unknown fileformat on file: {}".format(self.file)) return result
[docs] def run_neuron(self, **parameters): """ Load and run a Neuron simulation from a ``.hoc`` file and return the model voltage in soma. Parameters ---------- **parameters : A number of named arguments (name=value). The parameters of the model which are set in Neuron. Returns ------- time : array Time values of the model. values : array Voltage of the neuron. Note that `values` must either be regular (have the same number of points for different parameters) or be able to be interpolated. info : dictionary A dictionary with information needed by features. Efel features require ``"stimulus_start"`` and ``"stimulus_end"`` as keys, while spiking_features require ``stimulus_start"``. info : dictionary A dictionary with information needed by features. ``"stimulus_start"`` and ``"stimulus_end"`` are returned in the info dictionary if they are given as parameters to ``NeuronModel``. Notes ----- Efel features require ``"stimulus_start"`` and ``"stimulus_end"`` as keys, while spiking_features require ``stimulus_start"``. See also -------- uncertainpy.models.Model.run : Requirements for the model run function. """ self.h = self.load_neuron(self.path, self.file) self.set_parameters(parameters) self._record_t() self._record_v() self.h.run() values = np.array(self.h.voltage_soma.to_python()) time = self._to_array(self.time) return time, values, self.info
[docs] def run_python(self, **parameters): """ Load and run a Python function that contains a Neuron simulation and return the model result. The Python neuron simulation is located in a function in `path`/`file` and name `name`. Parameters ---------- **parameters : A number of named arguments (name=value). The parameters of the model which are sent to the Python function. Returns ------- time : array Time values of the model. values : array Voltage of the neuron. Note that `values` must either be regular (have the same number of points for different parameters) or be able to be interpolated. info : dictionary A dictionary with information needed by features. If a info dictionary is returned by the model function it is updated with ``"stimulus_start"`` and ``"stimulus_end"`` if they are given as parameters to ``NeuronModel``. If a info dictionary is not returned, a info dictionary is added as the third return argument. Notes ----- Efel features require ``"stimulus_start"`` and ``"stimulus_end"`` as keys, while spiking_features require ``stimulus_start"``. See also -------- uncertainpy.models.Model.run : Requirements for the model run function. """ model = self.load_python(self.path, self.file, self.name) result = model(**parameters) result = list(result) # Update info dict if it exists. # Info from the model are prioritized if len(result) == 3 and isinstance(result[2], dict): tmp_info = self.info.copy() tmp_info.update(result[2]) result[2] = tmp_info # Add info if no dict is present elif len(result) == 2: time, values = result result = (time, values, self.info) return result
[docs] def set_parameters(self, parameters): """ Set parameters in the neuron model. Parameters ---------- parameters : dict A dictionary with parameter names as keys and the parameter value as value. """ for parameter in parameters: self.h(parameter + " = " + str(parameters[parameter]))
[docs] def postprocess(self, time, values, info): """ Postprocessing of the time and results from the Neuron model is generally not needed. The direct model result except the info is returned. Parameters ---------- time : array_like Time values of the Neuron model. values : array_like Voltage of the neuron. info : dict Dictionary with information needed by features. Returns ------- time : array_like Time values of the Neuron model. values : array_like Voltage of the neuron. """ return time, values