Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor functions that include running isolated simulations [vcs: #minor] #149

Merged
merged 37 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
541ce2c
move NumpyEncoder to utils
anilbey Mar 8, 2024
728d1bd
move Singleton to utils
anilbey Mar 8, 2024
8c310c2
update docstrings of tools and utils modules
anilbey Mar 8, 2024
dbc3c71
move verbosity setting to verbosity module
anilbey Mar 8, 2024
4ad96cb
update search_threshold_current
anilbey Mar 8, 2024
aa5d338
delete detect_threshold_current
anilbey Mar 8, 2024
d2bb57a
add future annotations
anilbey Mar 8, 2024
b8b4a51
remove calculate_SS_voltage_replay
anilbey Mar 8, 2024
6ed1b03
remove search_hyp_current_replay functions
anilbey Mar 8, 2024
dc89def
use context manager for pools
anilbey Mar 9, 2024
78a0a8d
control all multiprocessing through IsolatedProcess class
anilbey Mar 9, 2024
9160ce3
add checks for object id in test_setting_rngmodel
anilbey Mar 11, 2024
9c93adb
reduce RNGSettings' dependency on CircuitAccess to SimulationConfig
anilbey Mar 11, 2024
f237e7a
use get_instance in RNGSettings Singleton
anilbey Mar 11, 2024
5e52bd7
update example notebook
anilbey Mar 11, 2024
b436cc0
uv==0.1.16
anilbey Mar 12, 2024
49ce9a0
tox-uv 1.4.0
anilbey Mar 12, 2024
a9da14b
decouple Synapse from cell.rng_settings
anilbey Mar 12, 2024
eb44d29
decouple injector from cell.rng_settings
anilbey Mar 12, 2024
ee18aef
delete cell.rng_settings in test_add_replay_relative_shotnoise
anilbey Mar 12, 2024
0bc2d30
delete cell.rng_settings in test_inject_current_clamp_via_shotnoise_s…
anilbey Mar 12, 2024
f4c2ea4
delete cell.rng_settings in test_get_noise_step_rand
anilbey Mar 12, 2024
6f4b792
decouple add_replay_minis from cell.rng_settings
anilbey Mar 12, 2024
1e039fa
avoid syncing neuron params for synapse ionchannel stimulus minis seeds
anilbey Mar 12, 2024
5995e99
delete cell.rng_settings in remaining test_injector
anilbey Mar 12, 2024
afa5a07
update example notebook not to access rng_settings
anilbey Mar 12, 2024
9a2dbf1
move seed initiations to init from set_seeds
anilbey Mar 12, 2024
dacb169
decouple Cell from RNGSettings
anilbey Mar 12, 2024
d4bf50b
remove tox-uv
anilbey Mar 12, 2024
2e77cbd
delete Cell.morphology_path attribute
anilbey Mar 12, 2024
1496b68
update Cell's init docstring
anilbey Mar 12, 2024
824c849
update docstrings in template.py
anilbey Mar 12, 2024
af5d591
require 4 template dependent arguments in NeuronTemplate
anilbey Mar 12, 2024
7f1be39
remove emodel_properties attribute from Cell
anilbey Mar 12, 2024
b629e38
gather template loading code together
anilbey Mar 12, 2024
380ebf5
update CHANGELOG
anilbey Mar 13, 2024
e9f3e60
add back images on singlecell.ipynb
anilbey Mar 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ jobs:
- name: Install dependencies
run: |
pip install tox-gh-actions
pip install tox-uv
- name: Run tox
run: |
tox
Expand All @@ -48,7 +47,6 @@ jobs:
run: |
python -m pip install --upgrade pip setuptools
pip install tox-gh-actions
pip install tox-uv
- name: Run tox
run: |
tox -e lint
Expand All @@ -65,7 +63,6 @@ jobs:
run: |
python -m pip install --upgrade pip setuptools
pip install tox-gh-actions
pip install tox-uv
- name: Run tox
run: |
tox -e examples
Expand All @@ -82,7 +79,6 @@ jobs:
run: |
python -m pip install --upgrade pip setuptools
pip install tox-gh-actions
pip install tox-uv
- name: Run tox
run: |
tox -e docs
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ Changelog
2.4.0
------

* Decouple Cell and Synapse from RNGSettings
* Have a single way of isolating processes via IsolatedProcess
* Implement: Add missing unit tests for tools functions #76
* Remove redundancies in tools.py
* RNGSettings.get_instance() replaces constructor

2.3.2
------

* Add StimulusFactory enabling Python generated Stimulus creation
* Stimulus creation through StimulusFactory is decoupled from the Cell object
* Cell.add_step and Cell.add_ramp use StimulusFactory
Expand Down
1 change: 1 addition & 0 deletions bluecellulab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from .importer import * # NOQA
from .tools import * # NOQA
from .verbosity import *
from .cell import Cell, create_ball_stick # NOQA
from .connection import Connection # NOQA
from .plotwindow import PlotWindow # NOQA
Expand Down
87 changes: 37 additions & 50 deletions bluecellulab/cell/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,48 +61,47 @@ def __init__(self,
cell_id: Optional[CellId] = None,
record_dt: Optional[float] = None,
template_format: str = "v5",
emodel_properties: Optional[EmodelProperties] = None,
rng_settings: Optional[RNGSettings] = None) -> None:
emodel_properties: Optional[EmodelProperties] = None) -> None:
"""Initializes a Cell object.

Args:
template_path: Full path to hoc template file.
template_path: Path to hoc template file.
morphology_path: Path to morphology file.
gid: ID of the cell, used in RNG seeds. Defaults to 0.
cell_id: ID of the cell, used in RNG seeds.
record_dt: Timestep for the recordings.
If not provided, a default is used. Defaults to None.
template_format: Cell template format such as 'v5'
or 'v6_air_scaler'. Defaults to "v5".
emodel_properties: Properties such as
threshold_current, holding_current. Defaults to None.
rng_settings: Random number generation setting
object used by the Cell. Defaults to None.
template_format: Cell template format such as 'v5' or 'v6_air_scaler'.
emodel_properties: Template specific emodel properties.
"""
super().__init__()
if cell_id is None:
cell_id = CellId("", Cell.last_id)
Cell.last_id += 1
self.cell_id = cell_id
# Persistent objects, like clamps, that exist as long
# as the object exists
self.persistent: list[HocObjectType] = []

self.morphology_path = morphology_path

# Load the template
neuron_template = NeuronTemplate(template_path, morphology_path)
neuron_template = NeuronTemplate(template_path, morphology_path, template_format, emodel_properties)
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.cell = neuron_template.get_cell(self.cell_id.id)
if template_format == 'v6':
if emodel_properties is None:
raise BluecellulabError('EmodelProperties must be provided for v6 template')
self.hypamp: float | None = emodel_properties.holding_current
self.threshold: float | None = emodel_properties.threshold_current
else:
try:
self.hypamp = self.cell.getHypAmp()
except AttributeError:
self.hypamp = None

try:
self.threshold = self.cell.getThreshold()
except AttributeError:
self.threshold = None
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()

if rng_settings is None:
self.rng_settings = RNGSettings("Random123") # SONATA value
else:
self.rng_settings = rng_settings

self.recordings: dict[str, HocObjectType] = {}
self.synapses: dict[SynapseID, Synapse] = {}
self.connections: dict[SynapseID, bluecellulab.Connection] = {}
Expand All @@ -121,30 +120,17 @@ def __init__(self,
self.delayed_weights = queue.PriorityQueue() # type: ignore
self.psections, self.secname_to_psection = init_psections(public_hoc_cell(self.cell))

self.emodel_properties = emodel_properties
if template_format == 'v6':
if self.emodel_properties is None:
raise BluecellulabError('EmodelProperties must be provided for v6 template')
self.hypamp: float | None = self.emodel_properties.holding_current
self.threshold: float | None = self.emodel_properties.threshold_current
else:
try:
self.hypamp = self.cell.getHypAmp()
except AttributeError:
self.hypamp = None

try:
self.threshold = self.cell.getThreshold()
except AttributeError:
self.threshold = None

# Keep track of when a cell is made passive by make_passive()
# Used to know when re_init_rng() can be executed
self.is_made_passive = False

neuron.h.pop_section() # Undoing soma push
self.sonata_proxy: Optional[SonataProxy] = None

# Persistent objects, like clamps, that exist as long
# as the object exists
self.persistent: list[HocObjectType] = []

@property
def somatic(self) -> list[NeuronSection]:
return list(public_hoc_cell(self.cell).somatic)
Expand Down Expand Up @@ -486,7 +472,6 @@ def add_replay_minis(self,

sid = synapse_id[1]

base_seed = self.rng_settings.base_seed
weight = syn_description[SynapseProperty.G_SYNX]
# numpy int to int
post_sec_id = int(syn_description[SynapseProperty.POST_SECTION_ID])
Expand Down Expand Up @@ -526,9 +511,10 @@ def add_replay_minis(self,
# NC_SPONTMINI
self.syn_mini_netcons[synapse_id].weight[nc_type_param] = 1

if self.rng_settings.mode == 'Random123':
rng_settings = RNGSettings.get_instance()
if rng_settings.mode == 'Random123':
seed2 = source_popid * 65536 + target_popid \
+ self.rng_settings.minis_seed
+ rng_settings.minis_seed
self.ips[synapse_id].setRNGs(
sid + 200,
self.cell_id.id + 250,
Expand All @@ -543,25 +529,26 @@ def add_replay_minis(self,
uniformrng = neuron.h.Random()
self.persistent.append(uniformrng)

if self.rng_settings.mode == 'Compatibility':
base_seed = rng_settings.base_seed
if rng_settings.mode == 'Compatibility':
exp_seed1 = sid * 100000 + 200
exp_seed2 = self.cell_id.id + 250 + base_seed + \
self.rng_settings.minis_seed
rng_settings.minis_seed
uniform_seed1 = sid * 100000 + 300
uniform_seed2 = self.cell_id.id + 250 + base_seed + \
self.rng_settings.minis_seed
elif self.rng_settings.mode == "UpdatedMCell":
rng_settings.minis_seed
elif rng_settings.mode == "UpdatedMCell":
exp_seed1 = sid * 1000 + 200
exp_seed2 = source_popid * 16777216 + self.cell_id.id + 250 + \
base_seed + \
self.rng_settings.minis_seed
rng_settings.minis_seed
uniform_seed1 = sid * 1000 + 300
uniform_seed2 = source_popid * 16777216 + self.cell_id.id + 250 \
+ base_seed + \
self.rng_settings.minis_seed
rng_settings.minis_seed
else:
raise ValueError(
f"Cell: Unknown rng mode: {self.rng_settings.mode}")
f"Cell: Unknown rng mode: {rng_settings.mode}")

exprng.MCellRan4(exp_seed1, exp_seed2)
exprng.negexp(1.0)
Expand Down
24 changes: 14 additions & 10 deletions bluecellulab/cell/injector.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
get_relative_shotnoise_params,
)
from bluecellulab.exceptions import BluecellulabError
from bluecellulab.rngsettings import RNGSettings
from bluecellulab.stimulus.circuit_stimulus_definitions import (
ClampMode,
Hyperpolarizing,
Expand Down Expand Up @@ -191,20 +192,21 @@ def add_voltage_clamp(

def _get_noise_step_rand(self, noisestim_count):
"""Return rng for noise step stimulus."""
if self.rng_settings.mode == "Compatibility":
rng_settings = RNGSettings.get_instance()
if rng_settings.mode == "Compatibility":
rng = neuron.h.Random(self.cell_id.id + noisestim_count)
elif self.rng_settings.mode == "UpdatedMCell":
elif rng_settings.mode == "UpdatedMCell":
rng = neuron.h.Random()
rng.MCellRan4(
noisestim_count * 10000 + 100,
self.rng_settings.base_seed +
self.rng_settings.stimulus_seed +
rng_settings.base_seed +
rng_settings.stimulus_seed +
self.cell_id.id * 1000)
elif self.rng_settings.mode == "Random123":
elif rng_settings.mode == "Random123":
rng = neuron.h.Random()
rng.Random123(
noisestim_count + 100,
self.rng_settings.stimulus_seed + 500,
rng_settings.stimulus_seed + 500,
self.cell_id.id + 300)

self.persistent.append(rng)
Expand Down Expand Up @@ -268,9 +270,10 @@ def add_replay_relativelinear(self, stimulus):

def _get_ornstein_uhlenbeck_rand(self, stim_count, seed):
"""Return rng for ornstein_uhlenbeck simulation."""
if self.rng_settings.mode == "Random123":
rng_settings = RNGSettings.get_instance()
if rng_settings.mode == "Random123":
seed1 = stim_count + 2997 # stimulus block
seed2 = self.rng_settings.stimulus_seed + 291204 # stimulus type
seed2 = rng_settings.stimulus_seed + 291204 # stimulus type
seed3 = self.cell_id.id + 123 if seed is None else seed # GID
logger.debug("Using ornstein_uhlenbeck process seeds %d %d %d" %
(seed1, seed2, seed3))
Expand All @@ -284,9 +287,10 @@ def _get_ornstein_uhlenbeck_rand(self, stim_count, seed):

def _get_shotnoise_step_rand(self, shotnoise_stim_count, seed=None):
"""Return rng for shot noise step stimulus."""
if self.rng_settings.mode == "Random123":
rng_settings = RNGSettings.get_instance()
if rng_settings.mode == "Random123":
seed1 = shotnoise_stim_count + 2997
seed2 = self.rng_settings.stimulus_seed + 19216
seed2 = rng_settings.stimulus_seed + 19216
seed3 = self.cell_id.id + 123 if seed is None else seed
logger.debug("Using shot noise seeds %d %d %d" %
(seed1, seed2, seed3))
Expand Down
Loading