From 8b7448019055757d6699738ae603956ab6051195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaquier=20Aur=C3=A9lien=20Tristan?= Date: Mon, 17 Jun 2024 09:42:26 +0200 Subject: [PATCH 1/6] allow non-specific currents not starting with 'i' Change-Id: I5bbc6a583b1afec2d23a0c86fb464808958b5467 --- bluepyemodel/access_point/access_point.py | 5 +++-- bluepyemodel/tools/mechanisms.py | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/bluepyemodel/access_point/access_point.py b/bluepyemodel/access_point/access_point.py index 554b816f..42cc5a9b 100644 --- a/bluepyemodel/access_point/access_point.py +++ b/bluepyemodel/access_point/access_point.py @@ -284,9 +284,10 @@ def get_ion_currents_concentrations(self): mechs = self.get_available_mechanisms() if mechs is None: return None, None - ion_currents = list(chain.from_iterable([mech.get_current() for mech in mechs])) + # use list(set(...)) to only keep unique occurences + ion_currents = list(set(chain.from_iterable([mech.get_current() for mech in mechs]))) ionic_concentrations = list( - chain.from_iterable([mech.ionic_concentrations for mech in mechs]) + set(chain.from_iterable([mech.ionic_concentrations for mech in mechs])) ) # append i_pas which is present by default ion_currents.append("i_pas") diff --git a/bluepyemodel/tools/mechanisms.py b/bluepyemodel/tools/mechanisms.py index 44091430..ad0e3e8c 100644 --- a/bluepyemodel/tools/mechanisms.py +++ b/bluepyemodel/tools/mechanisms.py @@ -129,8 +129,10 @@ def get_mechanism_currents(mech_file): ionic_concentrations.append(ion_var_name) elif "NONSPECIFIC_CURRENT" in line: var_name = line.split("NONSPECIFIC_CURRENT ")[1].rstrip("\n").split(" ")[0] - if var_name[0] == "i": - nonspecific_currents.append(var_name) + # here, we do not check if first letter is i, because + # NONSPECIFIC_CURRENT should indicate a current, + # and some special current do no start with i, e.g. 'lk' + nonspecific_currents.append(var_name) return ion_currs, nonspecific_currents, ionic_concentrations From aaa672116127242287de70ea190265e49ae53562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaquier=20Aur=C3=A9lien=20Tristan?= Date: Fri, 21 Jun 2024 09:46:46 +0200 Subject: [PATCH 2/6] Let currentscape plot SearchThresholdCUrrent in edge case Change-Id: I724132c47f063b536a732f2a8866f88a3e1edc3c --- bluepyemodel/evaluation/evaluator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bluepyemodel/evaluation/evaluator.py b/bluepyemodel/evaluation/evaluator.py index ca4708a6..4a2ec2b7 100644 --- a/bluepyemodel/evaluation/evaluator.py +++ b/bluepyemodel/evaluation/evaluator.py @@ -1020,7 +1020,7 @@ def add_recordings_to_evaluator(cell_evaluator, vars, use_fixed_dt_recordings=Fa """Add a recording for each new variable for each protocol in cell evaluator.""" # add recording for each protocol x new variable combination for prot in cell_evaluator.fitness_protocols["main_protocol"].protocols.values(): - if prot.name not in PRE_PROTOCOLS: + if prot.name == "SearchThresholdCurrent" or prot.name not in PRE_PROTOCOLS: base_rec = prot.recordings[0] for var in vars: location = base_rec.location From 4611406d89d4ee9d20214240acba94bcfc15ae3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaquier=20Aur=C3=A9lien=20Tristan?= Date: Mon, 24 Jun 2024 14:50:55 +0200 Subject: [PATCH 3/6] Do not discards currents not starting with 'i' Change-Id: I64a6695e273f228e8cee28f12af967e60e026fb5 --- bluepyemodel/emodel_pipeline/plotting.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bluepyemodel/emodel_pipeline/plotting.py b/bluepyemodel/emodel_pipeline/plotting.py index 67c5c930..4cadcc25 100644 --- a/bluepyemodel/emodel_pipeline/plotting.py +++ b/bluepyemodel/emodel_pipeline/plotting.py @@ -1495,12 +1495,13 @@ def get_ordered_currentscape_keys(keys): if curr_name == "v": ordered_keys[prot_name][loc_name]["voltage_key"] = name - elif curr_name[0] == "i": - ordered_keys[prot_name][loc_name]["current_keys"].append(name) - ordered_keys[prot_name][loc_name]["current_names"].append(curr_name) elif curr_name[-1] == "i": ordered_keys[prot_name][loc_name]["ion_conc_keys"].append(name) ordered_keys[prot_name][loc_name]["ion_conc_names"].append(curr_name) + # assumes we don't have any extra-cellular concentrations (that ends with 'o') + else: + ordered_keys[prot_name][loc_name]["current_keys"].append(name) + ordered_keys[prot_name][loc_name]["current_names"].append(curr_name) return ordered_keys From 47d99e1c9072723b942ebde362543a7c492983d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaquier=20Aur=C3=A9lien=20Tristan?= Date: Mon, 24 Jun 2024 14:59:41 +0200 Subject: [PATCH 4/6] Use cross_bucket=False in available_mechanisms fetching Change-Id: I91765433d901453d6544dc66af8112f3d4b72ebf --- bluepyemodel/access_point/forge_access_point.py | 9 ++++++--- bluepyemodel/access_point/nexus.py | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bluepyemodel/access_point/forge_access_point.py b/bluepyemodel/access_point/forge_access_point.py index 68a65c90..6fad525b 100644 --- a/bluepyemodel/access_point/forge_access_point.py +++ b/bluepyemodel/access_point/forge_access_point.py @@ -411,24 +411,27 @@ def retrieve(self, id_): return None - def fetch(self, filters): + def fetch(self, filters, cross_bucket=None): """Fetch resources based on filters. Args: filters (dict): keys and values used for the "WHERE". Should include "type" or "id". + cross_bucket (bool): whether to also fetch from other projects or not. Returns: resources (list): list of resources """ - if "type" not in filters and "id" not in filters: raise AccessPointException("Search filters should contain either 'type' or 'id'.") + + if cross_bucket is None: + cross_bucket = self.cross_bucket logger.debug("Searching: %s", filters) resources = self.forge.search( filters, - cross_bucket=self.cross_bucket, + cross_bucket=cross_bucket, limit=self.limit, debug=self.debug, search_endpoint=self.search_endpoint, diff --git a/bluepyemodel/access_point/nexus.py b/bluepyemodel/access_point/nexus.py index d775eb21..010b116f 100755 --- a/bluepyemodel/access_point/nexus.py +++ b/bluepyemodel/access_point/nexus.py @@ -1067,7 +1067,10 @@ def get_available_mechanisms(self, filters=None): filter = {"type": "SubCellularModelScript"} if filters: filter.update(filters) - resources = self.access_point.fetch(filter) + # do not look in other projects for these resources, + # because resources have 'full' metadata only in a few projects. + resources = self.access_point.fetch(filter, cross_bucket=False) + if resources is None: logger.warning("No SubCellularModelScript mechanisms available") From 50380a908bc78032631ed00a12e2aedff11172e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaquier=20Aur=C3=A9lien=20Tristan?= Date: Mon, 24 Jun 2024 15:03:26 +0200 Subject: [PATCH 5/6] update the way we are getting current data from metadata to latest standards Change-Id: I1cd73f3b77297b5815015dfbe1b6598c45529e20 --- bluepyemodel/access_point/nexus.py | 45 +++++++++++++----------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/bluepyemodel/access_point/nexus.py b/bluepyemodel/access_point/nexus.py index 010b116f..790314bc 100755 --- a/bluepyemodel/access_point/nexus.py +++ b/bluepyemodel/access_point/nexus.py @@ -1089,6 +1089,9 @@ def get_available_mechanisms(self, filters=None): stochastic = r.stochastic if hasattr(r, "stochastic") else None parameters = {} + ion_currents = [] + non_specific_currents = [] + ionic_concentrations = [] if hasattr(r, "exposesParameter"): exposes_parameters = r.exposesParameter if not isinstance(exposes_parameters, list): @@ -1097,33 +1100,25 @@ def get_available_mechanisms(self, filters=None): if ep.type == "ConductanceDensity": lower_limit = ep.lowerLimit if hasattr(ep, "lowerLimit") else None upper_limit = ep.upperLimit if hasattr(ep, "upperLimit") else None - if hasattr(r, "mod"): - parameters[f"{ep.name}_{r.mod.suffix}"] = [ - lower_limit, - upper_limit, - ] + # resource name is the mech SUFFIX + parameters[f"{ep.name}_{r.name}"] = [lower_limit, upper_limit] + elif ep.type == "CurrentDensity": + if not hasattr(ep, "ionName"): + logger.warning( + f"Will not add {ep.name} current, " + f"because 'ionName' field was not found in {r.name}." + ) + elif ep.ionName == "non-specific": + non_specific_currents.append(ep.name) else: - parameters[f"{ep.name}_{r.nmodlParameters.suffix}"] = [ - lower_limit, - upper_limit, - ] + ion_currents.append(ep.name) + ionic_concentrations.append(f"{ep.ionName}i") + elif ep.type == "IonConcentration": + ionic_concentrations.append(ep.name) + + # remove duplicates + ionic_concentrations = list(set(ionic_concentrations)) - ion_currents = [] - ionic_concentrations = [] - # technically, also adds non-specific currents to ion_currents list, - # because they are not distinguished in nexus for now, but - # the code should work nevertheless - ions = [] - if hasattr(r, "mod") and hasattr(r.mod, "ion"): - ions = r.mod.ion if isinstance(r.mod.ion, list) else [r.mod.ion] - elif hasattr(r, "ion"): - ions = r.ion if isinstance(r.ion, list) else [r.ion] - - for ion in ions: - if hasattr(ion, "label"): - ion_name = ion.label.lower() - ion_currents.append(f"i{ion_name}") - ionic_concentrations.append(f"{ion_name}i") mech = MechanismConfiguration( r.name, From 8a0c42fac341122670a18f3d23847e5a30066659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaquier=20Aur=C3=A9lien=20Tristan?= Date: Mon, 24 Jun 2024 15:12:02 +0200 Subject: [PATCH 6/6] lint check Change-Id: Ib2e97450eb5ea5415d025f2deaf75e50c7e18a8e --- bluepyemodel/access_point/forge_access_point.py | 2 +- bluepyemodel/access_point/nexus.py | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bluepyemodel/access_point/forge_access_point.py b/bluepyemodel/access_point/forge_access_point.py index 6fad525b..7f4854ed 100644 --- a/bluepyemodel/access_point/forge_access_point.py +++ b/bluepyemodel/access_point/forge_access_point.py @@ -423,7 +423,7 @@ def fetch(self, filters, cross_bucket=None): """ if "type" not in filters and "id" not in filters: raise AccessPointException("Search filters should contain either 'type' or 'id'.") - + if cross_bucket is None: cross_bucket = self.cross_bucket diff --git a/bluepyemodel/access_point/nexus.py b/bluepyemodel/access_point/nexus.py index 790314bc..06629794 100755 --- a/bluepyemodel/access_point/nexus.py +++ b/bluepyemodel/access_point/nexus.py @@ -1070,8 +1070,6 @@ def get_available_mechanisms(self, filters=None): # do not look in other projects for these resources, # because resources have 'full' metadata only in a few projects. resources = self.access_point.fetch(filter, cross_bucket=False) - - if resources is None: logger.warning("No SubCellularModelScript mechanisms available") return None @@ -1105,8 +1103,10 @@ def get_available_mechanisms(self, filters=None): elif ep.type == "CurrentDensity": if not hasattr(ep, "ionName"): logger.warning( - f"Will not add {ep.name} current, " - f"because 'ionName' field was not found in {r.name}." + "Will not add %s current, " + "because 'ionName' field was not found in %s.", + ep.name, + r.name, ) elif ep.ionName == "non-specific": non_specific_currents.append(ep.name) @@ -1119,7 +1119,6 @@ def get_available_mechanisms(self, filters=None): # remove duplicates ionic_concentrations = list(set(ionic_concentrations)) - mech = MechanismConfiguration( r.name, location=None,