"""
Alpha motor neuron populations for motor output.
This module contains the population class for alpha motor neurons, which form
the final common pathway for motor control and drive muscle contraction.
"""
from pathlib import Path
from typing import Optional, Union
import numpy as np
from myogen.simulator.neuron import cells
from myogen.utils.config_loader import load_yaml_config, merge_configs
from myogen.utils.decorators import beartowertype
from myogen.utils.types import RECRUITMENT_THRESHOLDS__ARRAY
from .base import _exp_interp, _Pool
[docs]
@beartowertype
class AlphaMN__Pool(_Pool):
"""
Container for a population of alpha motor neurons.
Manages a collection of AlphaMN (alpha motor neuron) cells with different
biophysical models: ModALS or Powers2017. These cells form the final
common pathway for motor control.
Parameters
----------
n : int
Number of alpha motor neurons to create.
recruitment_thresholds__array : RECRUITMENT_THRESHOLDS__ARRAY, optional
Array of recruitment thresholds for each motor neuron, by default None.
config_file : str or Path, optional
Path to YAML configuration file containing model parameters.
If provided, parameters from this file will be used as defaults,
which can be overridden by explicitly passed parameters.
Can be a filename (searches in myogen/config/), relative path, or absolute path.
By default uses "alpha_mn_default.yaml".
model : str, optional
Motor neuron model type ("NERLab" or "Powers2017"), by default "NERLab".
mode : str, optional
Simulation mode ("active" or "passive"), by default "active".
axon_velocities : tuple[float, float], optional
Min and max axon conduction velocities (m/s), by default (50, 65).
axon_length : float, optional
Length of the axon (mm), by default 0.6.
gamma : float, optional
Neuromodulation level (a.u.), by default 0.2.
cell_index : Optional[int], optional
Specific cell index to create (creates only one cell), by default None.
lambda_factor : float, optional
Lambda factor for Powers2017 model persistent sodium scaling, by default 1.0.
initial_voltage__mV : float or list[float], optional
Initial membrane voltage (mV), by default -67.
spike_threshold__mV : float, optional
Spike detection threshold for recording motor neuron spikes, by default 50.0.
Motor neurons have large action potentials (80-100 mV) requiring higher thresholds.
Powers2017 Model Parameters (required when model="Powers2017")
--------------------------------------------------------
soma_length_range : tuple[float, float, float], optional
Soma length [min, max, curve] (um).
soma_diameter_range : tuple[float, float, float], optional
Soma diameter [min, max, curve] (um).
soma_capacitance_range : tuple[float, float, float], optional
Soma capacitance [min, max, curve] (uF/cm²).
soma_passive_conductance_range : tuple[float, float, float], optional
Soma passive conductance [min, max, curve] (S/cm²).
soma_passive_reversal_range : tuple[float, float, float], optional
Soma passive reversal potential [min, max, curve] (mV).
soma_na3rp_conductance_range : tuple[float, float, float], optional
Soma Na3RP conductance [min, max, curve] (S/cm²).
soma_naps_conductance_range : tuple[float, float, float], optional
Soma NaPS conductance [min, max, curve] (S/cm²).
soma_kdrrl_conductance_range : tuple[float, float, float], optional
Soma KDRRL conductance [min, max, curve] (S/cm²).
soma_mahp_ca_conductance_range : tuple[float, float, float], optional
Soma mAHP calcium conductance [min, max, curve] (S/cm²).
soma_mahp_k_conductance_range : tuple[float, float, float], optional
Soma mAHP potassium conductance [min, max, curve] (S/cm²).
soma_mahp_tau_range : tuple[float, float, float], optional
Soma mAHP time constant [min, max, curve] (ms).
soma_gh_conductance_range : tuple[float, float, float], optional
Soma h-current conductance [min, max, curve] (S/cm²).
dendrite_length_range : tuple[float, float, float], optional
Dendrite length [min, max, curve] (um).
dendrite_diameter_range : tuple[float, float, float], optional
Dendrite diameter [min, max, curve] (um).
dendrite_passive_conductance_range : tuple[float, float, float], optional
Dendrite passive conductance [min, max, curve] (S/cm²).
dendrite_passive_reversal_range : tuple[float, float, float], optional
Dendrite passive reversal potential [min, max, curve] (mV).
dendrite_resistance_range : tuple[float, float, float], optional
Dendrite axial resistance [min, max, curve] (Ω·cm).
dendrite_capacitance_range : tuple[float, float, float], optional
Dendrite capacitance [min, max, curve] (uF/cm²).
dendrite_gh_conductance_range : tuple[float, float, float], optional
Dendrite h-current conductance [min, max, curve] (S/cm²).
dendrite_ca_conductance_ranges : tuple[tuple[float, float, float], ...], optional
L-type Ca conductance ranges for each dendrite (4 tuples).
dendrite_ca_theta_m_range : tuple[float, float, float], optional
Ca channel activation threshold [min, max, curve] (mV).
dendrite_ca_theta_h_range : tuple[float, float, float], optional
Ca channel inactivation threshold [min, max, curve] (mV).
"""
[docs]
def __init__(
self,
n: int | None = None,
recruitment_thresholds__array: RECRUITMENT_THRESHOLDS__ARRAY | None = None,
config_file: Union[str, Path, None] = None,
model: str | None = None,
mode: str | None = None,
axon_velocities: tuple[float, float] | None = None,
axon_length: float | None = None,
gamma: float | None = None,
cell_index: Optional[int] = None,
lambda_factor: float | None = None,
initial_voltage__mV: Union[float, list[float], None] = None,
spike_threshold__mV: float | None = None,
# Powers2017 parameters
# Soma parameters
soma_length_range: tuple[float, float, float] | None = None,
soma_diameter_range: tuple[float, float, float] | None = None,
soma_capacitance_range: tuple[float, float, float] | None = None,
soma_passive_conductance_range: tuple[float, float, float] | None = None,
soma_passive_reversal_range: tuple[float, float, float] | None = None,
soma_na3rp_conductance_range: tuple[float, float, float] | None = None,
soma_naps_conductance_range: tuple[float, float, float] | None = None,
soma_kdrrl_conductance_range: tuple[float, float, float] | None = None,
soma_mahp_ca_conductance_range: tuple[float, float, float] | None = None,
soma_mahp_k_conductance_range: tuple[float, float, float] | None = None,
soma_mahp_tau_range: tuple[float, float, float] | None = None,
soma_gh_conductance_range: tuple[float, float, float] | None = None,
# Dendrite parameters
dendrite_length_range: tuple[float, float, float] | None = None,
dendrite_diameter_range: tuple[float, float, float] | None = None,
dendrite_passive_conductance_range: tuple[float, float, float] | None = None,
dendrite_passive_reversal_range: tuple[float, float, float] | None = None,
dendrite_resistance_range: tuple[float, float, float] | None = None,
dendrite_capacitance_range: tuple[float, float, float] | None = None,
dendrite_gh_conductance_range: tuple[float, float, float] | None = None,
dendrite_ca_conductance_ranges: tuple[tuple[float, float, float], ...] | None = None,
dendrite_ca_theta_m_range: tuple[float, float, float] | None = None,
dendrite_ca_theta_h_range: tuple[float, float, float] | None = None,
):
# Load configuration from YAML files with fallback mechanism
if config_file is None:
config_file = "alpha_mn_default.yaml"
try:
# Always load the default configuration first
default_config = load_yaml_config("alpha_mn_default.yaml")
if config_file == "alpha_mn_default.yaml":
config = default_config
else:
# Load the specific config file and merge with defaults
specific_config = load_yaml_config(config_file)
config = merge_configs(default_config, specific_config)
except ImportError:
# PyYAML not installed
raise ImportError(
f"PyYAML is required to load config file '{config_file}'. "
"Install it with: pip install pyyaml"
)
# Helper function to get parameter value (explicit param > config > required)
def get_param(param_value, config_key):
if param_value is not None:
return param_value
if config_key not in config:
# Debug information
available_keys = (
list(config.keys()) if isinstance(config, dict) else "config is not a dict"
)
raise ValueError(
f"Parameter '{config_key}' not found in merged config and not provided explicitly. "
f"Available top-level keys: {available_keys}. "
f"Config file used: '{config_file}'"
)
return config[config_key]
def get_nested_param(param_value, *config_keys):
"""Get parameter from nested config structure."""
if param_value is not None:
return param_value
value = config
for key in config_keys:
if isinstance(value, dict):
value = value.get(key, {})
else:
raise ValueError(
f"Parameter path {' -> '.join(config_keys)} not found in merged config and not provided explicitly. "
f"Failed at key '{key}'. Config file used: '{config_file}'"
)
if value == {} or value is None:
raise ValueError(
f"Parameter path {' -> '.join(config_keys)} not found in merged config and not provided explicitly. "
f"Config file used: '{config_file}'"
)
return value
# Set basic parameters
self.n = n
self.recruitment_thresholds__array = recruitment_thresholds__array
if self.recruitment_thresholds__array is not None:
self.n = len(self.recruitment_thresholds__array)
if self.n is None and self.recruitment_thresholds__array is None:
raise ValueError("Either n or recruitment_thresholds__array must be provided.")
self.model = get_param(model, "model")
self.mode = get_param(mode, "mode")
self.axon_velocities = get_param(axon_velocities, "axon_velocities")
self.axon_length = get_param(axon_length, "axon_length")
self.gamma = get_param(gamma, "gamma")
self.cell_index = cell_index
self.lambda_factor = get_param(lambda_factor, "lambda_factor")
# Store Powers2017 parameters
self.soma_length_range = get_nested_param(
soma_length_range, "powers2017", "soma", "length_range"
)
self.soma_diameter_range = get_nested_param(
soma_diameter_range, "powers2017", "soma", "diameter_range"
)
self.soma_capacitance_range = get_nested_param(
soma_capacitance_range, "powers2017", "soma", "capacitance_range"
)
self.soma_passive_conductance_range = get_nested_param(
soma_passive_conductance_range, "powers2017", "soma", "passive_conductance_range"
)
self.soma_passive_reversal_range = get_nested_param(
soma_passive_reversal_range, "powers2017", "soma", "passive_reversal_range"
)
self.soma_na3rp_conductance_range = get_nested_param(
soma_na3rp_conductance_range, "powers2017", "soma", "na3rp_conductance_range"
)
self.soma_naps_conductance_range = get_nested_param(
soma_naps_conductance_range, "powers2017", "soma", "naps_conductance_range"
)
self.soma_kdrrl_conductance_range = get_nested_param(
soma_kdrrl_conductance_range, "powers2017", "soma", "kdrrl_conductance_range"
)
self.soma_mahp_ca_conductance_range = get_nested_param(
soma_mahp_ca_conductance_range, "powers2017", "soma", "mahp_ca_conductance_range"
)
self.soma_mahp_k_conductance_range = get_nested_param(
soma_mahp_k_conductance_range, "powers2017", "soma", "mahp_k_conductance_range"
)
self.soma_mahp_tau_range = get_nested_param(
soma_mahp_tau_range, "powers2017", "soma", "mahp_tau_range"
)
self.soma_gh_conductance_range = get_nested_param(
soma_gh_conductance_range, "powers2017", "soma", "gh_conductance_range"
)
self.dendrite_length_range = get_nested_param(
dendrite_length_range, "powers2017", "dendrite", "length_range"
)
self.dendrite_diameter_range = get_nested_param(
dendrite_diameter_range, "powers2017", "dendrite", "diameter_range"
)
self.dendrite_passive_conductance_range = get_nested_param(
dendrite_passive_conductance_range,
"powers2017",
"dendrite",
"passive_conductance_range",
)
self.dendrite_passive_reversal_range = get_nested_param(
dendrite_passive_reversal_range, "powers2017", "dendrite", "passive_reversal_range"
)
self.dendrite_resistance_range = get_nested_param(
dendrite_resistance_range, "powers2017", "dendrite", "resistance_range"
)
self.dendrite_capacitance_range = get_nested_param(
dendrite_capacitance_range, "powers2017", "dendrite", "capacitance_range"
)
self.dendrite_gh_conductance_range = get_nested_param(
dendrite_gh_conductance_range, "powers2017", "dendrite", "gh_conductance_range"
)
self.dendrite_ca_conductance_ranges = get_nested_param(
dendrite_ca_conductance_ranges, "powers2017", "dendrite", "ca_conductance_ranges"
)
self.dendrite_ca_theta_m_range = get_nested_param(
dendrite_ca_theta_m_range, "powers2017", "dendrite", "ca_theta_m_range"
)
self.dendrite_ca_theta_h_range = get_nested_param(
dendrite_ca_theta_h_range, "powers2017", "dendrite", "ca_theta_h_range"
)
# Store NERLab napp parameters
self.napp_m_alpha_A = get_nested_param(None, "nerlab", "napp", "m_alpha_A")
self.napp_m_alpha_v_offset = get_nested_param(None, "nerlab", "napp", "m_alpha_v_offset")
self.napp_m_alpha_k = get_nested_param(None, "nerlab", "napp", "m_alpha_k")
self.napp_m_beta_A = get_nested_param(None, "nerlab", "napp", "m_beta_A")
self.napp_m_beta_v_offset = get_nested_param(None, "nerlab", "napp", "m_beta_v_offset")
self.napp_m_beta_k = get_nested_param(None, "nerlab", "napp", "m_beta_k")
self.napp_h_alpha_A = get_nested_param(None, "nerlab", "napp", "h_alpha_A")
self.napp_h_alpha_v_offset = get_nested_param(None, "nerlab", "napp", "h_alpha_v_offset")
self.napp_h_alpha_tau = get_nested_param(None, "nerlab", "napp", "h_alpha_tau")
self.napp_h_beta_A = get_nested_param(None, "nerlab", "napp", "h_beta_A")
self.napp_h_beta_v_offset = get_nested_param(None, "nerlab", "napp", "h_beta_v_offset")
self.napp_h_beta_k = get_nested_param(None, "nerlab", "napp", "h_beta_k")
self.napp_p_alpha_A = get_nested_param(None, "nerlab", "napp", "p_alpha_A")
self.napp_p_alpha_v_offset = get_nested_param(None, "nerlab", "napp", "p_alpha_v_offset")
self.napp_p_alpha_k = get_nested_param(None, "nerlab", "napp", "p_alpha_k")
self.napp_p_beta_A = get_nested_param(None, "nerlab", "napp", "p_beta_A")
self.napp_p_beta_v_offset = get_nested_param(None, "nerlab", "napp", "p_beta_v_offset")
self.napp_p_beta_k = get_nested_param(None, "nerlab", "napp", "p_beta_k")
self.napp_n_alpha_A = get_nested_param(None, "nerlab", "napp", "n_alpha_A")
self.napp_n_alpha_v_offset = get_nested_param(None, "nerlab", "napp", "n_alpha_v_offset")
self.napp_n_alpha_k = get_nested_param(None, "nerlab", "napp", "n_alpha_k")
self.napp_n_beta_A = get_nested_param(None, "nerlab", "napp", "n_beta_A")
self.napp_n_beta_v_offset = get_nested_param(None, "nerlab", "napp", "n_beta_v_offset")
self.napp_n_beta_tau = get_nested_param(None, "nerlab", "napp", "n_beta_tau")
self.napp_r_alpha_A = get_nested_param(None, "nerlab", "napp", "r_alpha_A")
self.napp_r_alpha_v_offset = get_nested_param(None, "nerlab", "napp", "r_alpha_v_offset")
self.napp_r_alpha_k = get_nested_param(None, "nerlab", "napp", "r_alpha_k")
# Store NERLab soma parameters
self.nerlab_soma_diameter_range = get_nested_param(None, "nerlab", "soma", "diameter_range")
self.nerlab_soma_gnabar_range = get_nested_param(None, "nerlab", "soma", "gnabar_range")
self.nerlab_soma_gnapbar_range = get_nested_param(None, "nerlab", "soma", "gnapbar_range")
self.nerlab_soma_gkfbar_range = get_nested_param(None, "nerlab", "soma", "gkfbar_range")
self.nerlab_soma_gksbar_range = get_nested_param(None, "nerlab", "soma", "gksbar_range")
self.nerlab_soma_mact_range = get_nested_param(None, "nerlab", "soma", "mact_range")
self.nerlab_soma_rinact_range = get_nested_param(None, "nerlab", "soma", "rinact_range")
self.nerlab_soma_gls_range = get_nested_param(None, "nerlab", "soma", "gls_range")
self.nerlab_soma_ena = get_nested_param(None, "nerlab", "soma", "ena")
self.nerlab_soma_ek = get_nested_param(None, "nerlab", "soma", "ek")
self.nerlab_soma_el_napp = get_nested_param(None, "nerlab", "soma", "el_napp")
self.nerlab_soma_vtraub_napp = get_nested_param(None, "nerlab", "soma", "vtraub_napp")
self.nerlab_soma_Ra = get_nested_param(None, "nerlab", "soma", "Ra")
self.nerlab_soma_cm = get_nested_param(None, "nerlab", "soma", "cm")
# Store NERLab dendrite parameters
self.nerlab_dendrite_diameter_range = get_nested_param(
None, "nerlab", "dendrite", "diameter_range"
)
self.nerlab_dendrite_length_range = get_nested_param(
None, "nerlab", "dendrite", "length_range"
)
self.nerlab_dendrite_gcaLbar_range = get_nested_param(
None, "nerlab", "dendrite", "gcaLbar_range"
)
self.nerlab_dendrite_vtraub_caL_range = get_nested_param(
None, "nerlab", "dendrite", "vtraub_caL_range"
)
self.nerlab_dendrite_ltau_caL_range = get_nested_param(
None, "nerlab", "dendrite", "ltau_caL_range"
)
self.nerlab_dendrite_gl_caL_range = get_nested_param(
None, "nerlab", "dendrite", "gl_caL_range"
)
self.nerlab_dendrite_Ra = get_nested_param(None, "nerlab", "dendrite", "Ra")
self.nerlab_dendrite_cm = get_nested_param(None, "nerlab", "dendrite", "cm")
self.nerlab_dendrite_ecaL = get_nested_param(None, "nerlab", "dendrite", "ecaL")
self.nerlab_dendrite_el_caL = get_nested_param(None, "nerlab", "dendrite", "el_caL")
if self.model == "NERLab":
_cells = self._create_nerlab_cells()
elif self.model == "Powers2017":
_cells = self._create_powers2017_cells()
else:
raise ValueError("Could not find the specific model for alpha MNs.")
# Get initial voltage and spike threshold from config if not provided
_initial_voltage = get_param(initial_voltage__mV, "initial_voltage__mV")
_spike_threshold = get_param(spike_threshold__mV, "spike_threshold__mV")
super().__init__(
cells=_cells,
initial_voltage__mV=_initial_voltage,
spike_threshold__mV=_spike_threshold,
)
def _create_nerlab_cells(self) -> list:
"""Create motor neurons using the NERLab model."""
def special_interp(x, y, n, curv=None, negative=None):
if negative:
# Reverse the interpolation direction
return self.recruitment_thresholds__array * (x - y) + y
else:
# Normal direction
return self.recruitment_thresholds__array * (y - x) + x
if self.recruitment_thresholds__array is None:
interpF = _exp_interp
else:
interpF = special_interp
self.t = self.n
# Soma parameters (using parameters from YAML config)
Diam_soma = interpF(
self.nerlab_soma_diameter_range[0],
self.nerlab_soma_diameter_range[1],
self.t,
curv=1.0 / self.nerlab_soma_diameter_range[2],
negative=self.nerlab_soma_diameter_range[3],
)
Gnabar = interpF(
self.nerlab_soma_gnabar_range[0],
self.nerlab_soma_gnabar_range[1],
self.t,
curv=1 / self.nerlab_soma_gnabar_range[2],
negative=self.nerlab_soma_gnabar_range[3],
)
Gnapbar = interpF(
self.nerlab_soma_gnapbar_range[0],
self.nerlab_soma_gnapbar_range[1],
self.t,
curv=1 / self.nerlab_soma_gnapbar_range[2],
negative=self.nerlab_soma_gnapbar_range[3],
)
Gkfbar = interpF(
self.nerlab_soma_gkfbar_range[0],
self.nerlab_soma_gkfbar_range[1],
self.t,
curv=1 / self.nerlab_soma_gkfbar_range[2],
negative=self.nerlab_soma_gkfbar_range[3],
)
Gksbar = interpF(
self.nerlab_soma_gksbar_range[0],
self.nerlab_soma_gksbar_range[1],
self.t,
curv=1.0 / self.nerlab_soma_gksbar_range[2],
negative=self.nerlab_soma_gksbar_range[3],
)
Mact = interpF(
self.nerlab_soma_mact_range[0],
self.nerlab_soma_mact_range[1],
self.t,
curv=1 / self.nerlab_soma_mact_range[2],
negative=self.nerlab_soma_mact_range[3],
)
Rinact = interpF(
self.nerlab_soma_rinact_range[0],
self.nerlab_soma_rinact_range[1],
self.t,
curv=1 / self.nerlab_soma_rinact_range[2],
negative=self.nerlab_soma_rinact_range[3],
)
Gls = interpF(
self.nerlab_soma_gls_range[0],
self.nerlab_soma_gls_range[1],
self.t,
curv=1 / self.nerlab_soma_gls_range[2],
negative=self.nerlab_soma_gls_range[3],
)
# Dendrite parameters
Diam_dend = interpF(
self.nerlab_dendrite_diameter_range[0],
self.nerlab_dendrite_diameter_range[1],
self.t,
curv=1.0 / self.nerlab_dendrite_diameter_range[2],
negative=self.nerlab_dendrite_diameter_range[3],
)
L_dend = interpF(
self.nerlab_dendrite_length_range[0],
self.nerlab_dendrite_length_range[1],
self.t,
curv=1.0 / self.nerlab_dendrite_length_range[2],
negative=self.nerlab_dendrite_length_range[3],
)
GcaLbar = interpF(
self.nerlab_dendrite_gcaLbar_range[0],
self.nerlab_dendrite_gcaLbar_range[1],
self.t,
curv=1 / self.nerlab_dendrite_gcaLbar_range[2],
negative=self.nerlab_dendrite_gcaLbar_range[3],
)
Vtraub_caL = interpF(
self.nerlab_dendrite_vtraub_caL_range[0],
self.nerlab_dendrite_vtraub_caL_range[1],
self.t,
curv=1 / self.nerlab_dendrite_vtraub_caL_range[2],
negative=self.nerlab_dendrite_vtraub_caL_range[3],
)
LTAU_caL = interpF(
self.nerlab_dendrite_ltau_caL_range[0],
self.nerlab_dendrite_ltau_caL_range[1],
self.t,
curv=1 / self.nerlab_dendrite_ltau_caL_range[2],
negative=self.nerlab_dendrite_ltau_caL_range[3],
)
Gl_caL = interpF(
self.nerlab_dendrite_gl_caL_range[0],
self.nerlab_dendrite_gl_caL_range[1],
self.t,
curv=1 / self.nerlab_dendrite_gl_caL_range[2],
negative=self.nerlab_dendrite_gl_caL_range[3],
)
vcon = np.linspace(self.axon_velocities[0], self.axon_velocities[1], self.n)
# Determine cell creation range
if self.cell_index is not None:
init, end = self.cell_index, self.cell_index + 1
else:
init, end = 0, self.n
_cells = []
for i in range(init, end):
cell = cells.AlphaMN(
segments__count=1,
mode=self.mode,
dendrites__count=1,
model=self.model,
class__ID=self.cell_index,
pool__ID=i,
)
# Convert to quantities for create_axon
import quantities as pq
cell.create_axon(
length__m=self.axon_length * pq.m,
conduction_velocity__m_per_s=vcon[i] * pq.m / pq.s,
)
# Soma biophysical parameters
cell.soma.L = Diam_soma[i]
cell.soma.diam = Diam_soma[i]
cell.soma.ena = self.nerlab_soma_ena
cell.soma.ek = self.nerlab_soma_ek
cell.soma.el_napp = self.nerlab_soma_el_napp
cell.soma.vtraub_napp = self.nerlab_soma_vtraub_napp
cell.soma.Ra = self.nerlab_soma_Ra
cell.soma.cm = self.nerlab_soma_cm
cell.soma.gl_napp = Gls[i]
cell.soma.gnabar_napp = Gnabar[i]
cell.soma.gnapbar_napp = Gnapbar[i]
cell.soma.gkfbar_napp = Gkfbar[i]
cell.soma.gksbar_napp = Gksbar[i]
cell.soma.mact_napp = Mact[i]
cell.soma.rinact_napp = Rinact[i]
# Set napp alpha and beta parameters from config
# These parameters control the kinetics of sodium and potassium channels
cell.soma.m_alpha_A_napp = self.napp_m_alpha_A
cell.soma.m_alpha_v_offset_napp = self.napp_m_alpha_v_offset
cell.soma.m_alpha_k_napp = self.napp_m_alpha_k
cell.soma.m_beta_A_napp = self.napp_m_beta_A
cell.soma.m_beta_v_offset_napp = self.napp_m_beta_v_offset
cell.soma.m_beta_k_napp = self.napp_m_beta_k
cell.soma.h_alpha_A_napp = self.napp_h_alpha_A
cell.soma.h_alpha_v_offset_napp = self.napp_h_alpha_v_offset
cell.soma.h_alpha_tau_napp = self.napp_h_alpha_tau
cell.soma.h_beta_A_napp = self.napp_h_beta_A
cell.soma.h_beta_v_offset_napp = self.napp_h_beta_v_offset
cell.soma.h_beta_k_napp = self.napp_h_beta_k
cell.soma.p_alpha_A_napp = self.napp_p_alpha_A
cell.soma.p_alpha_v_offset_napp = self.napp_p_alpha_v_offset
cell.soma.p_alpha_k_napp = self.napp_p_alpha_k
cell.soma.p_beta_A_napp = self.napp_p_beta_A
cell.soma.p_beta_v_offset_napp = self.napp_p_beta_v_offset
cell.soma.p_beta_k_napp = self.napp_p_beta_k
cell.soma.n_alpha_A_napp = self.napp_n_alpha_A
cell.soma.n_alpha_v_offset_napp = self.napp_n_alpha_v_offset
cell.soma.n_alpha_k_napp = self.napp_n_alpha_k
cell.soma.n_beta_A_napp = self.napp_n_beta_A
cell.soma.n_beta_v_offset_napp = self.napp_n_beta_v_offset
cell.soma.n_beta_tau_napp = self.napp_n_beta_tau
cell.soma.r_alpha_A_napp = self.napp_r_alpha_A
cell.soma.r_alpha_v_offset_napp = self.napp_r_alpha_v_offset
cell.soma.r_alpha_k_napp = self.napp_r_alpha_k
# Dendrite parameters
cell.dend[0].Ra = self.nerlab_dendrite_Ra
cell.dend[0].cm = self.nerlab_dendrite_cm
cell.dend[0].L = L_dend[i]
cell.dend[0].diam = Diam_dend[i]
cell.dend[0].ecaL = self.nerlab_dendrite_ecaL
cell.dend[0].gama_caL = self.gamma
cell.dend[0].gcaLbar_caL = GcaLbar[i]
cell.dend[0].vtraub_caL = Vtraub_caL[i]
cell.dend[0].Ltau_caL = LTAU_caL[i]
cell.dend[0].gl_caL = Gl_caL[i]
cell.dend[0].el_caL = self.nerlab_dendrite_el_caL
_cells.append(cell)
return _cells
def _create_powers2017_cells(self) -> list:
"""Create motor neurons using the Powers2017 model."""
if self.recruitment_thresholds__array is None:
interpF = lambda x, y, z: _exp_interp(first=x, last=y, n=self.n, curv=z)
else:
interpF = lambda x, y, _: self.recruitment_thresholds__array * (y - x) + x
# Geometry parameters
sL = interpF(*self.soma_length_range)
sdiam = interpF(*self.soma_diameter_range)
scm = interpF(*self.soma_capacitance_range)
# Biophysics parameters
sg_pas = interpF(*self.soma_passive_conductance_range)
se_pas = interpF(*self.soma_passive_reversal_range)
sgbar_na3rp = interpF(*self.soma_na3rp_conductance_range)
sgbar_naps = interpF(*self.soma_naps_conductance_range)
sgMax_kdrRL = interpF(*self.soma_kdrrl_conductance_range)
sgcamax_mAHP = interpF(*self.soma_mahp_ca_conductance_range)
sgkcamax_mAHP = interpF(*self.soma_mahp_k_conductance_range)
staur_mAHP = interpF(*self.soma_mahp_tau_range)
sghbar_gh = interpF(*self.soma_gh_conductance_range)
# Dendrite parameters
dL = interpF(*self.dendrite_length_range)
ddiam = interpF(*self.dendrite_diameter_range)
dg_pas = interpF(*self.dendrite_passive_conductance_range)
de_pas = interpF(*self.dendrite_passive_reversal_range)
dRa = interpF(*self.dendrite_resistance_range)
dcm = interpF(*self.dendrite_capacitance_range)
dghbar_gh = interpF(*self.dendrite_gh_conductance_range)
# L-type calcium channels for each dendrite
d_ca_conductances = [interpF(*ca_range) for ca_range in self.dendrite_ca_conductance_ranges]
dtheta_m_L_Ca_inact = interpF(*self.dendrite_ca_theta_m_range)
dtheta_h_L_Ca_inact = interpF(*self.dendrite_ca_theta_h_range)
vcon = np.linspace(*self.axon_velocities, self.n)
if self.cell_index is not None:
init, end = self.cell_index, self.cell_index + 1
else:
init, end = 0, self.n
_cells = []
for i in range(init, end):
cell = cells.AlphaMN(
segments__count=1,
mode=self.mode,
dendrites__count=4,
model=self.model,
class__ID=self.cell_index,
pool__ID=i,
)
# Set soma parameters
cell.soma.L = sL[i]
cell.soma.diam = sdiam[i]
# Convert to quantities for create_axon
import quantities as pq
cell.create_axon(
length__m=self.axon_length * pq.m,
conduction_velocity__m_per_s=vcon[i] * pq.m / pq.s,
)
cell.soma.g_pas = sg_pas[i]
cell.soma.e_pas = se_pas[i]
cell.soma.cm = scm[i]
cell.soma.gbar_na3rp = sgbar_na3rp[i]
cell.soma.gbar_naps = sgbar_naps[i] * self.lambda_factor
cell.soma.gMax_kdrRL = sgMax_kdrRL[i]
cell.soma.gcamax_mAHP = sgcamax_mAHP[i]
cell.soma.gkcamax_mAHP = sgkcamax_mAHP[i]
cell.soma.tau_mAHP = staur_mAHP[i]
cell.soma.ghbar_gh = sghbar_gh[i]
# Set dendrite parameters
for j, d in enumerate(cell.dend):
d.L = dL[i]
d.diam = ddiam[i]
d.g_pas = dg_pas[i]
d.e_pas = de_pas[i]
d.Ra = dRa[i]
d.cm = dcm[i]
d.ghbar_gh = dghbar_gh[i]
if self.mode == "active":
d.gcabar_L_Ca_inact = d_ca_conductances[j][i] * self.gamma
d.theta_m_L_Ca_inact = dtheta_m_L_Ca_inact[i]
d.theta_h_L_Ca_inact = dtheta_h_L_Ca_inact[i]
_cells.append(cell)
return _cells