Skip to content

Commit

Permalink
Merge branch 'main' into network-plot
Browse files Browse the repository at this point in the history
Conflicts:
	bluecellulab/cell/core.py
	tests/test_cell/test_core.py
  • Loading branch information
ilkilic committed Nov 22, 2023
2 parents 0693ee6 + 87edf75 commit 0b29cad
Show file tree
Hide file tree
Showing 15 changed files with 237 additions and 132 deletions.
14 changes: 14 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "monthly"
commit-message:
# Prefix all commit messages with "CI(dependabot): "
prefix: "CI(dependabot): "
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Fetch the tag, if any. If not tagged, create a patch tag
uses: anothrNick/github-tag-action@1.64.0
uses: anothrNick/github-tag-action@1.67.0
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
id: tag
env:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
python-version: ["3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
Expand All @@ -35,7 +35,7 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
Expand All @@ -51,7 +51,7 @@ jobs:
examples:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
Expand All @@ -67,7 +67,7 @@ jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
Expand Down
120 changes: 46 additions & 74 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 @@ -90,8 +90,7 @@ 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, self.cell_id.id, 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()
Expand All @@ -118,11 +117,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 @@ -181,7 +180,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 @@ -262,7 +261,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 All @@ -286,16 +285,24 @@ def make_passive(self) -> None:
self.is_made_passive = True

def enable_ttx(self) -> None:
"""Add TTX to the bath (i.e. block the Na channels)."""
if hasattr(self.cell.getCell(), 'enable_ttx'):
self.cell.getCell().enable_ttx()
"""Add TTX to the environment (i.e. block the Na channels).
Enable TTX by inserting TTXDynamicsSwitch and setting ttxo to
1.0
"""
if hasattr(public_hoc_cell(self.cell), 'enable_ttx'):
public_hoc_cell(self.cell).enable_ttx()
else:
self._default_enable_ttx()

def disable_ttx(self) -> None:
"""Add TTX to the bath (i.e. block the Na channels)."""
if hasattr(self.cell.getCell(), 'disable_ttx'):
self.cell.getCell().disable_ttx()
"""Remove TTX from the environment (i.e. unblock the Na channels).
Disable TTX by inserting TTXDynamicsSwitch and setting ttxo to
1e-14
"""
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 @@ -406,14 +413,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 @@ -474,7 +481,7 @@ def pre_gid_synapse_ids(self, pre_gid: int) -> list[SynapseID]:
syn_id_list.append(syn_id)
return syn_id_list

def create_netcon_spikedetector(self, target, location: str, threshold: float = -30.0):
def create_netcon_spikedetector(self, target: HocObjectType, location: str, threshold: float = -30.0) -> HocObjectType:
"""Add and return a spikedetector.
This is a NetCon that detects spike in the current cell, and that
Expand All @@ -486,21 +493,23 @@ def create_netcon_spikedetector(self, target, location: str, threshold: float =
threshold: spike detection threshold
Returns: Neuron netcon object
Raises:
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 Exception("Spike detection location must be soma or AIS")
raise ValueError("Spike detection location must be soma or AIS")
netcon = bluecellulab.neuron.h.NetCon(source, target, sec=sec)
netcon.threshold = threshold

return netcon

def start_recording_spikes(self, target, location: str, threshold: float = -30):
def start_recording_spikes(self, target: HocObjectType, location: str, threshold: float = -30) -> None:
"""Start recording spikes in the current cell.
Args:
Expand Down Expand Up @@ -635,48 +644,17 @@ def add_replay_minis(self,
self.ips[synapse_id].setTbins(tbins_vec)
self.ips[synapse_id].setRate(rate_vec)

def locate_bapsite(self, seclist_name, distance):
"""Return the location of the BAP site.
Parameters
----------
seclist_name : str
SectionList to search in
distance : float
Distance from soma
Returns
-------
list of sections at the specified distance from the soma
"""
return [x for x in self.cell.getCell().locateBAPSite(seclist_name,
distance)]

def get_childrensections(self, parentsection):
"""Get the children section of a neuron section.
Returns
-------
list of sections : child sections of the specified parent section
"""
def get_childrensections(self, parentsection: HocObjectType) -> list[HocObjectType]:
"""Get the children section of a neuron section."""
number_children = neuron.h.SectionRef(sec=parentsection).nchild()
children = []
for index in range(0, int(number_children)):
children.append(neuron.h.SectionRef(sec=self.soma).child[index])
return children

@staticmethod
def get_parentsection(childsection):
"""Get the parent section of a neuron section.
Returns
-------
section : parent section of the specified child section
"""
def get_parentsection(childsection: HocObjectType) -> HocObjectType:
"""Get the parent section of a neuron section."""
return neuron.h.SectionRef(sec=childsection).parent

def addAxialCurrentRecordings(self, section):
Expand Down Expand Up @@ -704,14 +682,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 @@ -840,8 +818,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 All @@ -854,11 +832,5 @@ def delete(self):
for persistent_object in self.persistent:
del persistent_object

@property
def hsynapses(self):
"""Contains a dictionary of all the hoc synapses in the cell with as
key the gid."""
return {gid: synapse.hsynapse for (gid, synapse) in self.synapses.items()}

def __del__(self):
self.delete()
4 changes: 3 additions & 1 deletion bluecellulab/cell/injector.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ def add_replay_noise(
def add_replay_hypamp(self, stimulus: Hyperpolarizing):
"""Inject hypamp for the replay."""
tstim = bluecellulab.neuron.h.TStim(0.5, sec=self.soma) # type: ignore
amp = self.hypamp # type: ignore
if self.hypamp is None: # type: ignore
raise BluecellulabError("Cell.hypamp must be set for hypamp stimulus")
amp: float = self.hypamp # type: ignore
tstim.pulse(stimulus.delay, stimulus.duration, amp)
self.persistent.append(tstim) # type: ignore
return tstim
Expand Down
4 changes: 3 additions & 1 deletion bluecellulab/cell/serialized_sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
"""Module that allows morphology sections to be accessed from an array by
index."""

import logging
import warnings
import neuron
from bluecellulab.type_aliases import HocObjectType


logger = logging.getLogger(__name__)
warnings.filterwarnings("once", category=UserWarning, module=__name__)


Expand All @@ -31,7 +33,7 @@ def __init__(self, cell: HocObjectType) -> None:
for index, sec in enumerate(cell.all, start=1):
v_value = sec(0.0001).v
if v_value >= n:
print(f"{sec.name()} v(1)={sec(1).v} n3d()={sec.n3d()}")
logging.debug(f"{sec.name()} v(1)={sec(1).v} n3d()={sec.n3d()}")
raise ValueError("Error: failure in mk2_isec2sec()")

if v_value < 0:
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
2 changes: 1 addition & 1 deletion bluecellulab/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def info_dict(self):
connection_dict = {}

connection_dict['pre_cell_id'] = self.post_synapse.pre_gid
connection_dict['post_cell_id'] = self.post_synapse.post_gid
connection_dict['post_cell_id'] = self.post_synapse.post_cell_id.id
connection_dict['post_synapse_id'] = self.post_synapse.syn_id.sid

connection_dict['post_netcon'] = {}
Expand Down
9 changes: 7 additions & 2 deletions bluecellulab/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@
# limitations under the License.
"""Main importer of bluecellulab."""

import logging
import os
from types import ModuleType
import pkg_resources

import neuron

from bluecellulab.exceptions import BluecellulabError


logger = logging.getLogger(__name__)


def import_mod_lib(neuron: ModuleType) -> str:
"""Import mod files."""
res = ""
Expand Down Expand Up @@ -62,8 +67,8 @@ def import_neurodamus(neuron: ModuleType) -> None:

def print_header(neuron: ModuleType, mod_lib_path: str) -> None:
"""Print bluecellulab header to stdout."""
print("Imported NEURON from: %s" % neuron.__file__)
print('Mod lib: ', mod_lib_path)
logger.info(f"Imported NEURON from: {neuron.__file__}")
logger.info(f"Mod lib: {mod_lib_path}")


mod_lib_paths = import_mod_lib(neuron)
Expand Down
Loading

0 comments on commit 0b29cad

Please sign in to comment.