From 299d0f7b96fd6c41914a1b006dbcc6d18b370c84 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" <sanjay.ankur@gmail.com> Date: Tue, 14 Jan 2025 17:19:46 +0000 Subject: [PATCH 1/4] feat(utils): replace undetermined gates with standard ones Wherever possible. Fixes #205 --- neuroml/utils.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/neuroml/utils.py b/neuroml/utils.py index af26761..1406531 100644 --- a/neuroml/utils.py +++ b/neuroml/utils.py @@ -472,6 +472,63 @@ def fix_external_morphs_biophys_in_cell( return newdoc +def create_new_typed_gate(gate): + """Convert an undetermined gate to a "determined" gate + + :param gate: gate object of GateHHUndetermined type + :returns: new gate object, or None if the gate is not of a standard type + """ + gates_name_map = { + "gateHHrates": "GateHHRates", + "gateHHratesTau": "GateHHRatesTau", + "gateHHratesInf": "GateHHRatesInf", + "gateHHratesTauInf": "GateHHRatesTauInf", + "gateHHtauInf": "GateHHTauInf", + "gateHHInstantaneous": "GateHHInstantaneous", + "gateFractional": "GateFractional", + "gateKS": "GateKS", + } + gate_type = getattr(gate, "type", None) + if gate_type: + try: + gate_class_type = gates_name_map[gate_type] + # if it isn't in our dict, it's non standard + except KeyError: + return None + + new_gate = component_factory(component_type=gate_class_type, validate=False) + print(gate.__dict__) + new_gate.__dict__.update(gate.__dict__) + return new_gate + + +def move_undetermined_gates_to_typed(nml2_doc): + """Replace gates of GateHHUndetermined type with their standard + counterparts where possible. + + Note that this modifies the passed NeuroMLDocument object in-place. + + :param nml2_doc: NeuroMLDocument object + :returns: None + + """ + all_channels = ( + list(nml2_doc.ion_channel_hhs.__iter__()) + + list(nml2_doc.ion_channel.__iter__()) + + list(nml2_doc.ion_channel_v_shifts.__iter__()) + ) + for achannel in all_channels: + determined_gates = [] + undetermined_gates = getattr(achannel, "gates", []) + for gate in undetermined_gates: + new_typed_gate = create_new_typed_gate(gate) + if new_typed_gate: + achannel.add(new_typed_gate) + determined_gates.append(gate) + for d_gate in determined_gates: + undetermined_gates.remove(d_gate) + + def main(): if len(sys.argv) != 2: print("Please specify the name of the NeuroML2 file...") From 91269dbbe31efa77831398f75810b1b64a05e492 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" <sanjay.ankur@gmail.com> Date: Tue, 14 Jan 2025 17:21:12 +0000 Subject: [PATCH 2/4] feat(loader): move undetermined gates to standard ones --- neuroml/loaders.py | 1 + 1 file changed, 1 insertion(+) diff --git a/neuroml/loaders.py b/neuroml/loaders.py index 863ea5f..eb8d1f4 100644 --- a/neuroml/loaders.py +++ b/neuroml/loaders.py @@ -49,6 +49,7 @@ def __nml2_doc(cls, file_name: str) -> neuroml.NeuroMLDocument: if supressGeneratedsWarnings: warnings.simplefilter("ignore") nml2_doc = nmlparse(file_name, silence=True) + utils.move_undetermined_gates_to_typed(nml2_doc) if supressGeneratedsWarnings: warnings.resetwarnings() except Exception as e: From 42424f3b48c4629e8a16f8f332fd07c787eab115 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" <sanjay.ankur@gmail.com> Date: Tue, 14 Jan 2025 17:30:35 +0000 Subject: [PATCH 3/4] feat(utils): improve type hints, docs --- neuroml/utils.py | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/neuroml/utils.py b/neuroml/utils.py index 1406531..f7bbff9 100644 --- a/neuroml/utils.py +++ b/neuroml/utils.py @@ -15,7 +15,20 @@ import networkx import neuroml.nml.nml as schema -from neuroml import BiophysicalProperties, Morphology, NeuroMLDocument +from neuroml import ( + BiophysicalProperties, + GateFractional, + GateHHInstantaneous, + GateHHRates, + GateHHRatesInf, + GateHHRatesTau, + GateHHRatesTauInf, + GateHHTauInf, + GateHHUndetermined, + GateKS, + Morphology, + NeuroMLDocument, +) from . import loaders @@ -472,10 +485,24 @@ def fix_external_morphs_biophys_in_cell( return newdoc -def create_new_typed_gate(gate): +def create_new_typed_gate( + gate: GateHHUndetermined, +) -> Optional[ + Union[ + GateHHRates, + GateHHRatesTau, + GateHHRatesInf, + GateHHRatesTauInf, + GateHHTauInf, + GateHHInstantaneous, + GateFractional, + GateKS, + ] +]: """Convert an undetermined gate to a "determined" gate :param gate: gate object of GateHHUndetermined type + :type gate: GateHHUndetermined :returns: new gate object, or None if the gate is not of a standard type """ gates_name_map = { @@ -501,17 +528,26 @@ def create_new_typed_gate(gate): new_gate.__dict__.update(gate.__dict__) return new_gate + return None -def move_undetermined_gates_to_typed(nml2_doc): + +def move_undetermined_gates_to_typed(nml2_doc: NeuroMLDocument): """Replace gates of GateHHUndetermined type with their standard counterparts where possible. Note that this modifies the passed NeuroMLDocument object in-place. + If `nml2_doc` is not a NeuroMLDocument, this function does nothing and + simply returns None. + :param nml2_doc: NeuroMLDocument object + :type nml2_doc: NeuroMLDocument :returns: None """ + if not isinstance(nml2_doc, NeuroMLDocument): + return None + all_channels = ( list(nml2_doc.ion_channel_hhs.__iter__()) + list(nml2_doc.ion_channel.__iter__()) From 2e38e82ba5191e500b5e8e2d064f8cc5b0d0eb7b Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" <sanjay.ankur@gmail.com> Date: Tue, 14 Jan 2025 17:30:52 +0000 Subject: [PATCH 4/4] feat(loader): do gate tweaking after document is correctly read --- neuroml/loaders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neuroml/loaders.py b/neuroml/loaders.py index eb8d1f4..7df336b 100644 --- a/neuroml/loaders.py +++ b/neuroml/loaders.py @@ -49,12 +49,12 @@ def __nml2_doc(cls, file_name: str) -> neuroml.NeuroMLDocument: if supressGeneratedsWarnings: warnings.simplefilter("ignore") nml2_doc = nmlparse(file_name, silence=True) - utils.move_undetermined_gates_to_typed(nml2_doc) if supressGeneratedsWarnings: warnings.resetwarnings() except Exception as e: raise Exception("Not a valid NeuroML 2 doc (%s): %s" % (file_name, e), e) + utils.move_undetermined_gates_to_typed(nml2_doc) return nml2_doc