From 6657a4f0902a4547abddaf1a8d3b923507eca83c Mon Sep 17 00:00:00 2001 From: Ivan Raikov Date: Mon, 25 Mar 2024 14:35:05 -0700 Subject: [PATCH] further fixes to support for reduced cell models --- .pre-commit-config.yaml | 4 +- pyproject.toml | 2 +- src/miv_simulator/cells.py | 63 +++++++++----- src/miv_simulator/clamps/cell.py | 20 +---- src/miv_simulator/network.py | 132 ++++++++++++------------------ src/miv_simulator/synapses.py | 7 +- src/miv_simulator/utils/neuron.py | 7 +- 7 files changed, 112 insertions(+), 123 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d19d9c8..335d4fc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,13 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: check-json - id: end-of-file-fixer - id: requirements-txt-fixer - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 24.3.0 hooks: - id: black additional_dependencies: ["click==8.0.4"] diff --git a/pyproject.toml b/pyproject.toml index b376157..6fb4c17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "miv-simulator" -version = "0.0.3" +version = "0.0.4" description = "Mind-in-Vitro simulator" readme = "README.md" authors = [] diff --git a/src/miv_simulator/cells.py b/src/miv_simulator/cells.py index f952934..057e4de 100644 --- a/src/miv_simulator/cells.py +++ b/src/miv_simulator/cells.py @@ -315,7 +315,6 @@ def __init__( self.random.seed(self.gid) self.spike_detector = None self.spike_onset_delay = 0.0 - self.is_reduced = True if not isinstance(cell_config, BRKconfig): raise RuntimeError( "BRKneuron: argument cell_attrs must be of type BRKconfig" @@ -422,6 +421,10 @@ def ais(self): def hillock(self): return self.nodes["hillock"] + @property + def is_reduced(self): + return True + class PRneuron: """ @@ -458,7 +461,6 @@ def __init__( self.random.seed(self.gid) self.spike_detector = None self.spike_onset_delay = 0.0 - self.is_reduced = True if not isinstance(cell_config, PRconfig): raise RuntimeError( "PRneuron: argument cell_attrs must be of type PRconfig" @@ -558,6 +560,10 @@ def ais(self): def hillock(self): return self.nodes["hillock"] + @property + def is_reduced(self): + return True + class SCneuron: """ @@ -611,7 +617,6 @@ def __init__( self.random.seed(self.gid) self.spike_detector = None self.spike_onset_delay = 0.0 - self.is_reduced = True SC_nrn = h.SC_nrn() @@ -678,6 +683,10 @@ def ais(self) -> List[Any]: def hillock(self): return self.nodes["hillock"] + @property + def is_reduced(self): + return True + class BiophysCell: """ @@ -951,20 +960,18 @@ def import_morphology_from_hoc( sec_info_dict = {} root_sec = None for sec_type, sec_index_list in default_hoc_sec_lists.items(): - hoc_sec_attr_name = sec_type + hoc_sec_attr_name = f"{sec_type}_list" if not hasattr(hoc_cell, hoc_sec_attr_name): - hoc_sec_attr_name = f"{sec_type}_list" + hoc_sec_attr_name = sec_type if hasattr(hoc_cell, hoc_sec_attr_name) and ( getattr(hoc_cell, hoc_sec_attr_name) is not None ): sec_list = list(getattr(hoc_cell, hoc_sec_attr_name)) + hoc_obj = getattr(hoc_cell, hoc_sec_attr_name) if hasattr(hoc_cell, sec_index_list): sec_indexes = list(getattr(hoc_cell, sec_index_list)) else: - raise AttributeError( - "import_morphology_from_hoc: %s is not an attribute of the hoc cell" - % sec_index_list - ) + sec_indexes = list(range(len(sec_list))) if sec_type == "soma": root_sec = sec_list[0] for sec, index in zip(sec_list, sec_indexes): @@ -1779,9 +1786,9 @@ def init_circuit_context( cell_weights_dict, ) in cell_weights_iter: assert cell_weights_gid == gid - cell_weights_dicts[ - weights_namespace - ] = cell_weights_dict + cell_weights_dicts[weights_namespace] = ( + cell_weights_dict + ) else: raise RuntimeError( @@ -1810,12 +1817,14 @@ def init_circuit_context( syn_name, zip_longest( weights_syn_ids, - [ - {"weight": Promise(expr_closure, [x])} - for x in weights_values - ] - if expr_closure - else [{"weight": x} for x in weights_values], + ( + [ + {"weight": Promise(expr_closure, [x])} + for x in weights_values + ] + if expr_closure + else [{"weight": x} for x in weights_values] + ), ), multiple=multiple_weights, append=append_weights, @@ -2086,11 +2095,16 @@ def make_biophys_cell( ) _, tree_dict = next(tree_attr_iter) + hoc_cell = make_hoc_cell( + env, population_name, gid, neurotree_dict=tree_dict + ) + cell = BiophysCell( + env=env, gid=gid, population_name=population_name, + hoc_cell=hoc_cell, neurotree_dict=tree_dict, - env=env, mech_file_path=mech_file_path, mech_dict=mech_dict, ) @@ -2502,3 +2516,14 @@ def record_cell( recs.append(rec) return recs + + +default_reduced_cell_constructors = { + "pr_nrn": make_PR_cell, + "brk_nrn": make_BRK_cell, + "sc_nrn": make_SC_cell, +} + + +def get_reduced_cell_constructor(template_name): + return default_reduced_cell_constructors.get(template_name.lower(), None) diff --git a/src/miv_simulator/clamps/cell.py b/src/miv_simulator/clamps/cell.py index d106359..b70a556 100644 --- a/src/miv_simulator/clamps/cell.py +++ b/src/miv_simulator/clamps/cell.py @@ -111,23 +111,11 @@ def init_biophys_cell( else: correct_for_spines_flag = False + reduced_cons = cells.get_reduced_cell_constructor(template_name) + ## Load cell gid and its synaptic attributes and connection data - if template_name.lower() == "pr_nrn": - cell = cells.make_PR_cell( - env, - pop_name, - gid, - tree_dict=cell_dict.get("morph", None), - synapses_dict=cell_dict.get("synapse", None), - connection_graph=cell_dict.get("connectivity", None), - weight_dict=cell_dict.get("weight", None), - mech_dict=mech_dict, - load_synapses=True, - load_weights=load_weights, - load_edges=load_connections, - ) - elif template_name.lower() == "sc_nrn": - cell = cells.make_SC_cell( + if reduced_cons is not None: + cell = reduced_cons( env, pop_name, gid, diff --git a/src/miv_simulator/network.py b/src/miv_simulator/network.py index 4ea9fdf..b677440 100644 --- a/src/miv_simulator/network.py +++ b/src/miv_simulator/network.py @@ -321,19 +321,21 @@ def connect_cells(env: Env) -> None: syn_name, zip_longest( weights_syn_ids, - [ - { - "weight": Promise( - expr_closure, [x] - ) - } - for x in weights_values - ] - if expr_closure - else [ - {"weight": x} - for x in weights_values - ], + ( + [ + { + "weight": Promise( + expr_closure, [x] + ) + } + for x in weights_values + ] + if expr_closure + else [ + {"weight": x} + for x in weights_values + ] + ), ), multiple=multiple_weights, append=append_weights, @@ -386,9 +388,9 @@ def connect_cells(env: Env) -> None: lambda edgeset: presyn_input_sources.update(edgeset[1][0]), edge_iter, ) - env.microcircuit_input_sources[ - presyn_name - ] = presyn_input_sources + env.microcircuit_input_sources[presyn_name] = ( + presyn_input_sources + ) else: syn_edge_iter = edge_iter syn_attrs.init_edge_attrs_from_iter( @@ -466,9 +468,11 @@ def connect_cells(env: Env) -> None: env, gid, postsyn_name, - cell=postsyn_cell.hoc_cell - if hasattr(postsyn_cell, "hoc_cell") - else postsyn_cell, + cell=( + postsyn_cell.hoc_cell + if hasattr(postsyn_cell, "hoc_cell") + else postsyn_cell + ), unique=unique, insert=True, insert_netcons=True, @@ -679,19 +683,21 @@ def connect_cell_selection(env): syn_name, zip_longest( weights_syn_ids, - [ - { - "weight": Promise( - expr_closure, [x] - ) - } - for x in weights_values - ] - if expr_closure - else [ - {"weight": x} - for x in weights_values - ], + ( + [ + { + "weight": Promise( + expr_closure, [x] + ) + } + for x in weights_values + ] + if expr_closure + else [ + {"weight": x} + for x in weights_values + ] + ), ), multiple=multiple_weights, append=append_weights, @@ -733,9 +739,9 @@ def connect_cell_selection(env): syn_attrs.init_edge_attrs_from_iter( postsyn_name, presyn_name, a, syn_edge_iter ) - env.microcircuit_input_sources[ - presyn_name - ] = presyn_input_sources + env.microcircuit_input_sources[presyn_name] = ( + presyn_input_sources + ) del graph[postsyn_name][presyn_name] first_gid = None @@ -956,10 +962,7 @@ def make_cells(env: Env) -> None: f"*** Mechanism file for population {pop_name} is {mech_file_path}" ) - is_BRK = template_name.lower() == "brk_nrn" - is_PR = template_name.lower() == "pr_nrn" - is_SC = template_name.lower() == "sc_nrn" - is_reduced = is_BRK or is_PR or is_SC + reduced_cons = cells.get_reduced_cell_constructor(template_name) num_cells = 0 if (pop_name in env.cell_attribute_info) and ( @@ -991,16 +994,8 @@ def make_cells(env: Env) -> None: if first_gid is None: first_gid = gid - if is_SC: - cell = cells.make_SC_cell( - gid=gid, pop_name=pop_name, env=env, mech_dict=mech_dict - ) - elif is_PR: - cell = cells.make_PR_cell( - gid=gid, pop_name=pop_name, env=env, mech_dict=mech_dict - ) - elif is_BRK: - cell = cells.make_BRK_cell( + if reduced_cons: + cell = reduced_cons( gid=gid, pop_name=pop_name, env=env, mech_dict=mech_dict ) else: @@ -1025,7 +1020,7 @@ def make_cells(env: Env) -> None: f"*** make_cells: population: {pop_name}; gid: {gid}; loaded biophysics from path: {mech_file_path}" ) - if is_reduced: + if reduced_cons is not None: soma_xyz = cells.get_soma_xyz(tree, env.SWC_Types) cell.position(soma_xyz[0], soma_xyz[1], soma_xyz[2]) if rank == 0 and first_gid == gid: @@ -1084,16 +1079,8 @@ def make_cells(env: Env) -> None: cell_z = cell_coords[z_index][0] cell = None - if is_SC: - cell = cells.make_SC_cell( - gid=gid, pop_name=pop_name, env=env, mech_dict=mech_dict - ) - elif is_PR: - cell = cells.make_PR_cell( - gid=gid, pop_name=pop_name, env=env, mech_dict=mech_dict - ) - elif is_BRK: - cell = cells.make_BRK_cell( + if reduced_cons: + cell = reduced_cons( gid=gid, pop_name=pop_name, env=env, mech_dict=mech_dict ) else: @@ -1180,10 +1167,7 @@ def make_cell_selection(env): else: mech_dict = None - is_BRK = template_name.lower() == "brk_nrn" - is_PR = template_name.lower() == "pr_nrn" - is_SC = template_name.lower() == "sc_nrn" - is_reduced = is_BRK or is_PR or is_SC + reduced_cons = cells.get_reduced_cell_constructor(template_name) num_cells = 0 if (pop_name in env.cell_attribute_info) and ( @@ -1206,22 +1190,8 @@ def make_cell_selection(env): if first_gid == None: first_gid = gid - if is_SC: - cell = cells.make_SC_cell( - gid=gid, - pop_name=pop_name, - env=env, - param_dict=mech_dict, - ) - elif is_PR: - cell = cells.make_PR_cell( - gid=gid, - pop_name=pop_name, - env=env, - param_dict=mech_dict, - ) - elif is_BRK: - cell = cells.make_BRK_cell( + if reduced_cons is not None: + cell = reduced_cons( gid=gid, pop_name=pop_name, env=env, @@ -1248,7 +1218,7 @@ def make_cell_selection(env): f"*** make_cell_selection: population: {pop_name}; gid: {gid}; loaded biophysics from path: {mech_file_path}" ) - if is_reduced: + if reduced_cons is not None: soma_xyz = cells.get_soma_xyz(tree, env.SWC_Types) cell.position(soma_xyz[0], soma_xyz[1], soma_xyz[2]) diff --git a/src/miv_simulator/synapses.py b/src/miv_simulator/synapses.py index 9542b26..08ab13a 100644 --- a/src/miv_simulator/synapses.py +++ b/src/miv_simulator/synapses.py @@ -1666,7 +1666,9 @@ def insert_hoc_cell_syns( py_sections = [sec for sec in cell.sections] is_reduced = False if hasattr(cell, "is_reduced"): - is_reduced = cell.is_reduced + is_reduced = cell.is_reduced() + if isinstance(is_reduced, float): + is_reduced = is_reduced > 0.0 cell_soma = None cell_dendrite = None @@ -1674,7 +1676,7 @@ def insert_hoc_cell_syns( if is_reduced: for swc_type_name in env.SWC_Types: for layer_name in env.layers: - swc_layer_key = f"{swc_type_name}_{layer_name}" + swc_layer_key = f"{swc_type_name}_{layer_name}_list" sec_list = getattr(cell, swc_layer_key, None) if sec_list is not None: reduced_section_dict[swc_layer_key] = list(sec_list) @@ -1716,7 +1718,6 @@ def insert_hoc_cell_syns( current_sec_list = reduced_section_dict.get(sec_list_key, None) sec_pos = 0.0 sec_dx = 0.0 - logger.info(f"current_sec_list = {current_sec_list}") if current_sec_list is not None: if sec_pos >= 1: sec = current_sec_list.pop(0) diff --git a/src/miv_simulator/utils/neuron.py b/src/miv_simulator/utils/neuron.py index 8298690..9c2f0b1 100644 --- a/src/miv_simulator/utils/neuron.py +++ b/src/miv_simulator/utils/neuron.py @@ -613,8 +613,13 @@ def make_rec( "make_rec: either sec and loc or ps must be specified" ) section_index = None + sections = [] + if hasattr(cell, "sections"): + sections = list(cell.sections) + elif hasattr(cell, "all"): + sections = list(cell.all) if sec is not None: - for i, this_section in enumerate(cell.sections): + for i, this_section in enumerate(sections): if this_section == sec: section_index = i break