Skip to content

Commit

Permalink
access public hoc templates with getCell or CellRef
Browse files Browse the repository at this point in the history
  • Loading branch information
anilbey committed Nov 1, 2023
1 parent d7261e4 commit a86cd4e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 35 deletions.
55 changes: 27 additions & 28 deletions bluecellulab/cell/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from bluecellulab.cell.section_distance import EuclideanSectionDistance
from bluecellulab.cell.sonata_proxy import SonataProxy
from bluecellulab.cell.serialized_sections import SerializedSections
from bluecellulab.cell.template import NeuronTemplate
from bluecellulab.cell.template import NeuronTemplate, public_hoc_cell
from bluecellulab.circuit.config.sections import Conditions
from bluecellulab.circuit import EmodelProperties, SynapseProperty
from bluecellulab.circuit.node_id import CellId
Expand Down Expand Up @@ -84,16 +84,15 @@ def __init__(self,
neuron_template = NeuronTemplate(template_path, morphology_path)
self.template_id = neuron_template.template_name # useful to map NEURON and python objects
self.cell = neuron_template.get_cell(template_format, gid, emodel_properties)

self.soma = self.cell.getCell().soma[0]
self.soma = public_hoc_cell(self.cell).soma[0]
# WARNING: this finitialize 'must' be here, otherwhise the
# diameters of the loaded morph are wrong
neuron.h.finitialize()

self.cellname = neuron.h.secname(sec=self.soma).split(".")[0]

# Set the gid of the cell
self.cell.getCell().gid = gid
public_hoc_cell(self.cell).gid = gid
self.gid = gid

if rng_settings is None:
Expand All @@ -113,11 +112,11 @@ def __init__(self,
# time recording needs this push
self.soma.push()
self.hocname = neuron.h.secname(sec=self.soma).split(".")[0]
self.somatic = [x for x in self.cell.getCell().somatic]
self.basal = [x for x in self.cell.getCell().basal] # dend is same as basal
self.apical = [x for x in self.cell.getCell().apical]
self.axonal = [x for x in self.cell.getCell().axonal]
self.all = [x for x in self.cell.getCell().all]
self.somatic = [x for x in public_hoc_cell(self.cell).somatic]
self.basal = [x for x in public_hoc_cell(self.cell).basal] # dend is same as basal
self.apical = [x for x in public_hoc_cell(self.cell).apical]
self.axonal = [x for x in public_hoc_cell(self.cell).axonal]
self.all = [x for x in public_hoc_cell(self.cell).all]
self.record_dt = record_dt
self.add_recordings(['self.soma(0.5)._ref_v', 'neuron.h._ref_t'],
dt=self.record_dt)
Expand Down Expand Up @@ -176,7 +175,7 @@ def init_psections(self) -> None:

# section are not serialized yet, do it now
if self.serialized is None:
self.serialized = SerializedSections(self.cell.getCell())
self.serialized = SerializedSections(public_hoc_cell(self.cell))

for isec in self.serialized.isec2sec:
hsection = self.get_hsection(isec)
Expand Down Expand Up @@ -257,7 +256,7 @@ def get_hsection(self, section_id: int | float) -> NeuronSection:
section_id = int(section_id)
# section are not serialized yet, do it now
if self.serialized is None:
self.serialized = SerializedSections(self.cell.getCell())
self.serialized = SerializedSections(public_hoc_cell(self.cell))

try:
sec_ref = self.serialized.isec2sec[section_id]
Expand Down Expand Up @@ -286,8 +285,8 @@ def enable_ttx(self) -> None:
Enable TTX by inserting TTXDynamicsSwitch and setting ttxo to
1.0
"""
if hasattr(self.cell.getCell(), 'enable_ttx'):
self.cell.getCell().enable_ttx()
if hasattr(public_hoc_cell(self.cell), 'enable_ttx'):
public_hoc_cell(self.cell).enable_ttx()
else:
self._default_enable_ttx()

Expand All @@ -297,8 +296,8 @@ def disable_ttx(self) -> None:
Disable TTX by inserting TTXDynamicsSwitch and setting ttxo to
1e-14
"""
if hasattr(self.cell.getCell(), 'disable_ttx'):
self.cell.getCell().disable_ttx()
if hasattr(public_hoc_cell(self.cell), 'disable_ttx'):
public_hoc_cell(self.cell).disable_ttx()
else:
self._default_disable_ttx()

Expand Down Expand Up @@ -409,14 +408,14 @@ def get_voltage_recording(

def add_allsections_voltagerecordings(self):
"""Add a voltage recording to every section of the cell."""
all_sections = self.cell.getCell().all
all_sections = public_hoc_cell(self.cell).all
for section in all_sections:
self.add_voltage_recording(section, segx=0.5, dt=self.record_dt)

def get_allsections_voltagerecordings(self) -> dict[str, np.ndarray]:
"""Get all the voltage recordings from all the sections."""
all_section_voltages = {}
all_sections = self.cell.getCell().all
all_sections = public_hoc_cell(self.cell).all
for section in all_sections:
recording = self.get_voltage_recording(section, segx=0.5)
all_section_voltages[section.name()] = recording
Expand Down Expand Up @@ -494,11 +493,11 @@ def create_netcon_spikedetector(self, target: HocObjectType, location: str, thre
ValueError: If the spike detection location is not 'soma' or 'AIS'.
"""
if location == "soma":
sec = self.cell.getCell().soma[0]
source = self.cell.getCell().soma[0](1)._ref_v
sec = public_hoc_cell(self.cell).soma[0]
source = public_hoc_cell(self.cell).soma[0](1)._ref_v
elif location == "AIS":
sec = self.cell.getCell().axon[1]
source = self.cell.getCell().axon[1](0.5)._ref_v
sec = public_hoc_cell(self.cell).axon[1]
source = public_hoc_cell(self.cell).axon[1](0.5)._ref_v
else:
raise ValueError("Spike detection location must be soma or AIS")
netcon = bluecellulab.neuron.h.NetCon(source, target, sec=sec)
Expand Down Expand Up @@ -678,14 +677,14 @@ def somatic_branches(self):
if "dend" in secname:
dendnumber = int(
secname.split("dend")[1].split("[")[1].split("]")[0])
secnumber = int(self.cell.getCell().nSecAxonalOrig +
self.cell.getCell().nSecSoma + dendnumber)
secnumber = int(public_hoc_cell(self.cell).nSecAxonalOrig +
public_hoc_cell(self.cell).nSecSoma + dendnumber)
elif "apic" in secname:
apicnumber = int(secname.split(
"apic")[1].split("[")[1].split("]")[0])
secnumber = int(self.cell.getCell().nSecAxonalOrig +
self.cell.getCell().nSecSoma +
self.cell.getCell().nSecBasal + apicnumber)
secnumber = int(public_hoc_cell(self.cell).nSecAxonalOrig +
public_hoc_cell(self.cell).nSecSoma +
public_hoc_cell(self.cell).nSecBasal + apicnumber)
logger.info((apicnumber, secnumber))
else:
raise Exception(
Expand Down Expand Up @@ -814,8 +813,8 @@ def delete(self):
"""Delete the cell."""
self.delete_plottable()
if hasattr(self, 'cell') and self.cell is not None:
if self.cell.getCell() is not None and hasattr(self.cell.getCell(), 'clear'):
self.cell.getCell().clear()
if public_hoc_cell(self.cell) is not None and hasattr(public_hoc_cell(self.cell), 'clear'):
public_hoc_cell(self.cell).clear()

self.connections = None
self.synapses = None
Expand Down
11 changes: 11 additions & 0 deletions bluecellulab/cell/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
logger = logging.getLogger(__name__)


def public_hoc_cell(cell: HocObjectType) -> HocObjectType:
"""Retrieve the hoc cell to access public hoc functions/attributes."""
if hasattr(cell, "getCell"):
return cell.getCell()
elif hasattr(cell, "CellRef"):
return cell.CellRef
else:
raise BluecellulabError("""Public cell properties cannot be accessed
from the hoc model. Either getCell() or CellRef needs to be provided""")


class NeuronTemplate:
"""NeuronTemplate representation."""

Expand Down
55 changes: 48 additions & 7 deletions tests/test_cell/test_template.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
"""Unit tests for template.py module."""

from pathlib import Path
from unittest.mock import Mock

import pytest

from bluecellulab.cell.template import NeuronTemplate
from bluecellulab.cell.template import NeuronTemplate, public_hoc_cell
from bluecellulab.circuit.circuit_access import EmodelProperties
from bluecellulab.exceptions import BluecellulabError


parent_dir = Path(__file__).resolve().parent.parent

hoc_path = (
hipp_hoc_path = (
parent_dir
/ "examples"
/ "hippocampus_opt_cell_template"
/ "electrophysiology"
/ "cell.hoc"
)
morph_path = (
hipp_morph_path = (
parent_dir / "examples" / "hippocampus_opt_cell_template" / "morphology" / "cell.asc"
)

v6_hoc_path = (
parent_dir / "examples" / "circuit_sonata_quick_scx" / "components" / "hoc" / "cADpyr_L2TPC.hoc"
)

v6_morph_path = (
parent_dir / "examples" / "circuit_sonata_quick_scx" / "components" / "morphologies" / "asc" / "rr110330_C3_idA.asc"
)


def test_get_cell_with_bluepyopt_template():
"""Unit test for the get_cell method with bluepyopt_template."""
template = NeuronTemplate(hoc_path, morph_path)
template = NeuronTemplate(hipp_hoc_path, hipp_morph_path)
cell = template.get_cell("bluepyopt", None, None)
assert cell.hname() == f"bACnoljp_bluecellulab_{(hex(id(template)))}[0]"

Expand All @@ -33,8 +44,38 @@ def test_neuron_template_init():
missing_file = "missing_file"

with pytest.raises(FileNotFoundError):
NeuronTemplate(missing_file, morph_path)
NeuronTemplate(missing_file, hipp_morph_path)
with pytest.raises(FileNotFoundError):
NeuronTemplate(hoc_path, missing_file)
NeuronTemplate(hipp_hoc_path, missing_file)

NeuronTemplate(hipp_hoc_path, hipp_morph_path)


def test_public_hoc_cell_bluepyopt_template():
"""Unit test for public_hoc_cell."""
template = NeuronTemplate(hipp_hoc_path, hipp_morph_path)
cell = template.get_cell("bluepyopt", None, None)
hoc_public = public_hoc_cell(cell)
assert hoc_public.gid == 0.0


def test_public_hoc_cell_v6_template():
"""Unit test for public_hoc_cell."""
template = NeuronTemplate(v6_hoc_path, v6_morph_path)
emodel_properties = EmodelProperties(
threshold_current=1.1433533430099487,
holding_current=1.4146618843078613,
ais_scaler=1.4561502933502197,
soma_scaler=1.0
)
cell = template.get_cell("v6_adapted", 5, emodel_properties)
hoc_public = public_hoc_cell(cell)
assert hoc_public.gid == 5.0


NeuronTemplate(hoc_path, morph_path)
def test_public_hoc_cell_failure():
"""Unit test for public_hoc_cell when neither getCell nor CellRef is provided."""
cell_without_getCell_or_CellRef = Mock(spec=[]) # spec=[] ensures no attributes exist
with pytest.raises(BluecellulabError) as excinfo:
public_hoc_cell(cell_without_getCell_or_CellRef)
assert "Public cell properties cannot be accessed" in str(excinfo.value)

0 comments on commit a86cd4e

Please sign in to comment.