From cad8fe5cd08a23327d88b0422aa794402698a09f Mon Sep 17 00:00:00 2001
From: pgleeson
Date: Fri, 19 Apr 2024 14:05:22 +0100
Subject: [PATCH 1/5] Quick & dirty implementation of running xpp files in
xppaut & plotting results
---
pyneuroml/xppaut/__init__.py | 66 ++++++++++++++++++++++++++++++++++--
1 file changed, 63 insertions(+), 3 deletions(-)
diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py
index 6c9f4822..c03ad7c7 100644
--- a/pyneuroml/xppaut/__init__.py
+++ b/pyneuroml/xppaut/__init__.py
@@ -6,6 +6,7 @@
import typing
import argparse
import logging
+import os
XPP_TIME = 'xpp_time'
LEMS_TIME = 't'
@@ -592,6 +593,55 @@ def main(args=None):
cli(a=args)
+def run_xpp_file(filename, plot):
+ import subprocess as sp
+ cmds = ['%s/xppaut'%os.environ["XPP_HOME"],filename, '-silent']
+ cwd = os.getcwd()
+ try:
+ ret_string = sp.check_output(
+ cmds, cwd=cwd, shell=False, stderr=sp.STDOUT
+ )
+ logger.info(
+ "Commands: %s completed successfully" % (cmds)
+ )
+ if isinstance(ret_string, bytes):
+ ret_string = ret_string.decode("utf-8") # For Python 3...
+
+ except sp.CalledProcessError as err:
+ logger.error(
+ "CalledProcessError running commands: %s in %s (return code: %s), output:\n%s"
+ % (cmds, cwd, err.returncode, err.output),
+ )
+ raise err
+ except Exception as err:
+ logger.info(
+ "Error running commands: %s in (%s)!" % (cmds, cwd)
+ )
+ logger.info("Error: %s" % (err))
+ raise err
+
+ if plot:
+ from pyneuroml.pynml import reload_standard_dat_file
+ result_file = 'output.dat'
+ data, indeces = reload_standard_dat_file(result_file)
+ logger.info('Loading %s with %s'%(data, indeces))
+ ts = []
+ xs = []
+ labels = []
+ for i in indeces:
+ ts.append(data['t'])
+ xs.append(data[i])
+ labels.append(i)
+
+ from pyneuroml.plot.Plot import generate_plot
+ ax = generate_plot(ts, xs,
+ "Data from %s after running %s"%(result_file, filename), # Title
+ labels=labels,
+ xaxis="Time (?)", # x axis legend
+ yaxis="??", # y axis legend
+ show_plot_already=True, # Show or wait for plt.show()?
+ legend_position = "bottom center",
+ ) # Save figure
def cli(a: typing.Optional[typing.Any] = None, **kwargs: str):
"""Main cli caller method"""
@@ -608,19 +658,29 @@ def cli(a: typing.Optional[typing.Any] = None, **kwargs: str):
lems_model_id = file_path.replace('.ode','').split('/')[-1]
lems_model_file = file_path.replace('.ode','.model.xml')
+ if a.run and not a.lems and not a.xpp and not a.brian2:
+
+ logger.info("Running %s with XPP (plotting: %s)..." % (a.ode_filename, a.plot))
+
+ run_xpp_file(a.ode_filename, a.plot)
+
+
if a.lems:
lems_filename = to_lems(parsed_data, lems_model_id, lems_model_file)
logger.info("Generated LEMS file: %s" % lems_filename)
if a.run:
logger.info("Running %s with jNeuroML (plotting: %s)..." % (lems_filename, a.plot))
+
from pyneuroml.runners import run_lems_with_jneuroml
run_lems_with_jneuroml(lems_filename, nogui=True, plot=a.plot, verbose=True, load_saved_data=True)
if a.xpp:
- to_xpp(parsed_data, file_path.replace('.ode','_2.ode'))
- if a.run or a.plot:
- raise NotImplementedError("Running XPP not yet implemented!")
+ new_xppfile = file_path.replace('.ode','_2.ode')
+ to_xpp(parsed_data, new_xppfile)
+
+ if a.run:
+ run_xpp_file(new_xppfile, a.plot)
if a.brian2:
to_brian2(parsed_data, file_path.replace('.ode','_brian2.py'))
From 95f5e14585ab118e687169c4cef3aff2c67bb8d2 Mon Sep 17 00:00:00 2001
From: pgleeson
Date: Fri, 19 Apr 2024 15:49:49 +0100
Subject: [PATCH 2/5] Improved xpp handling
---
.gitignore | 2 ++
pyneuroml/xppaut/__init__.py | 17 ++++++++++++-----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/.gitignore b/.gitignore
index 9b703336..0fd85fa8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -173,3 +173,5 @@ arm64
/pyneuroml/xppaut/report.txt
/examples/test_data/xppaut/fhn_2.ode
/examples/test_data/xppaut/fhn_brain.py
+/examples/test_data/xppaut/nca_2.ode
+/examples/test_data/xppaut/wc_2.ode
diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py
index c03ad7c7..101123e1 100644
--- a/pyneuroml/xppaut/__init__.py
+++ b/pyneuroml/xppaut/__init__.py
@@ -80,6 +80,7 @@ def parse_script(file_path):
elif line.startswith(('number', 'p', 'par', 'param')):
params = line.replace('number ', '').replace('par ', '').replace('p ', '').replace('param ', '') # Skip the first word ('number', 'p', 'param' or 'par')
for pp1 in params.split(','):
+ pp1 = pp1.replace(' = ','=').replace('= ','=').replace(' =','=') # better solution required...
for pp2 in pp1.split(' '):
if len(pp2)>0:
key, value = pp2.split('=')
@@ -190,7 +191,7 @@ def to_xpp(data, new_xpp_filename):
xpp_ode+='\n# Parameters\n'
for k,v in data["parameters"].items():
if not k in INBUILT.keys():
- xpp_ode += f'{k} = {v}\n'
+ xpp_ode += f'par {k} = {v}\n'
xpp_ode+='\n# Functions\n'
for k,v in data["functions"].items():
@@ -621,17 +622,24 @@ def run_xpp_file(filename, plot):
raise err
if plot:
+
+ parsed_data = parse_script(filename)
+
from pyneuroml.pynml import reload_standard_dat_file
result_file = 'output.dat'
data, indeces = reload_standard_dat_file(result_file)
- logger.info('Loading %s with %s'%(data, indeces))
+ logger.info('Loading data: %s'%(data.keys()))
ts = []
xs = []
labels = []
+ tds = list(parsed_data['time_derivatives'].keys())
+ cdvs = ['%s??'%c for c in parsed_data['conditional_derived_variables'].keys()]
+ outputs = tds+cdvs
+ logger.info('Loading data: %s, assuming these represent %s (%i values)'%(data.keys(),outputs, len(outputs)))
for i in indeces:
ts.append(data['t'])
xs.append(data[i])
- labels.append(i)
+ labels.append(outputs[i] if i < len(outputs) else '???')
from pyneuroml.plot.Plot import generate_plot
ax = generate_plot(ts, xs,
@@ -640,8 +648,7 @@ def run_xpp_file(filename, plot):
xaxis="Time (?)", # x axis legend
yaxis="??", # y axis legend
show_plot_already=True, # Show or wait for plt.show()?
- legend_position = "bottom center",
- ) # Save figure
+ )
def cli(a: typing.Optional[typing.Any] = None, **kwargs: str):
"""Main cli caller method"""
From 537dd0092cda0a912fdab45c64882af6a431f77d Mon Sep 17 00:00:00 2001
From: pgleeson
Date: Mon, 29 Apr 2024 17:49:18 +0100
Subject: [PATCH 3/5] Indeces -> indices
---
pyneuroml/pynml.py | 8 ++++----
pyneuroml/xppaut/__init__.py | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/pyneuroml/pynml.py b/pyneuroml/pynml.py
index af2fc3ee..560f52a0 100644
--- a/pyneuroml/pynml.py
+++ b/pyneuroml/pynml.py
@@ -897,7 +897,7 @@ def reload_standard_dat_file(file_name: str) -> typing.Tuple[dict, list]:
"""
with open(file_name) as dat_file:
data = {} # type: dict
- indeces = [] # type: list
+ indices = [] # type: list
for line in dat_file:
words = line.split()
@@ -905,13 +905,13 @@ def reload_standard_dat_file(file_name: str) -> typing.Tuple[dict, list]:
data["t"] = []
for i in range(len(words) - 1):
data[i] = []
- indeces.append(i)
+ indices.append(i)
data["t"].append(float(words[0]))
for i in range(len(words) - 1):
data[i].append(float(words[i + 1]))
- logger.info("Loaded data from %s; columns: %s" % (file_name, indeces))
- return data, indeces
+ logger.info("Loaded data from %s; columns: %s" % (file_name, indices))
+ return data, indices
def evaluate_component(comp_type, req_variables={}, parameter_values={}):
diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py
index 101123e1..db347e2a 100644
--- a/pyneuroml/xppaut/__init__.py
+++ b/pyneuroml/xppaut/__init__.py
@@ -594,7 +594,7 @@ def main(args=None):
cli(a=args)
-def run_xpp_file(filename, plot):
+def run_xpp_file(filename, plot, show_plot_already=True):
import subprocess as sp
cmds = ['%s/xppaut'%os.environ["XPP_HOME"],filename, '-silent']
cwd = os.getcwd()
@@ -627,7 +627,7 @@ def run_xpp_file(filename, plot):
from pyneuroml.pynml import reload_standard_dat_file
result_file = 'output.dat'
- data, indeces = reload_standard_dat_file(result_file)
+ data, indices = reload_standard_dat_file(result_file)
logger.info('Loading data: %s'%(data.keys()))
ts = []
xs = []
@@ -636,7 +636,7 @@ def run_xpp_file(filename, plot):
cdvs = ['%s??'%c for c in parsed_data['conditional_derived_variables'].keys()]
outputs = tds+cdvs
logger.info('Loading data: %s, assuming these represent %s (%i values)'%(data.keys(),outputs, len(outputs)))
- for i in indeces:
+ for i in indices:
ts.append(data['t'])
xs.append(data[i])
labels.append(outputs[i] if i < len(outputs) else '???')
@@ -647,7 +647,7 @@ def run_xpp_file(filename, plot):
labels=labels,
xaxis="Time (?)", # x axis legend
yaxis="??", # y axis legend
- show_plot_already=True, # Show or wait for plt.show()?
+ show_plot_already=show_plot_already, # Show or wait for plt.show()?
)
def cli(a: typing.Optional[typing.Any] = None, **kwargs: str):
From 49f9de43b96534f45f2ba4db1f3728263a3a3edd Mon Sep 17 00:00:00 2001
From: pgleeson
Date: Tue, 30 Apr 2024 18:34:50 +0100
Subject: [PATCH 4/5] Updates to xpp running/plotting
---
pyneuroml/utils/__init__.py | 5 ++++
pyneuroml/xppaut/__init__.py | 46 +++++++++++++++++++++++++-----------
2 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/pyneuroml/utils/__init__.py b/pyneuroml/utils/__init__.py
index 85dbb784..3ced389b 100644
--- a/pyneuroml/utils/__init__.py
+++ b/pyneuroml/utils/__init__.py
@@ -327,6 +327,11 @@ def get_state_color(s: str) -> str:
if s.startswith("u"):
col = "#880088"
+ if '/' in s: # e.g. for sub gates
+ from pyneuroml.utils.plot import get_next_hex_color
+ col = get_next_hex_color()
+
+
return col
diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py
index db347e2a..e0b58f0e 100644
--- a/pyneuroml/xppaut/__init__.py
+++ b/pyneuroml/xppaut/__init__.py
@@ -594,7 +594,7 @@ def main(args=None):
cli(a=args)
-def run_xpp_file(filename, plot, show_plot_already=True):
+def run_xpp_file(filename, plot, show_plot_already=True, plot_separately={}):
import subprocess as sp
cmds = ['%s/xppaut'%os.environ["XPP_HOME"],filename, '-silent']
cwd = os.getcwd()
@@ -629,26 +629,44 @@ def run_xpp_file(filename, plot, show_plot_already=True):
result_file = 'output.dat'
data, indices = reload_standard_dat_file(result_file)
logger.info('Loading data: %s'%(data.keys()))
- ts = []
- xs = []
- labels = []
+ default_figure = "Data loaded from: %s after running %s"%(result_file, filename) # Title
+ ts = {default_figure:[]}
+ xs = {default_figure:[]}
+ labels = {default_figure:[]}
+ for new_fig in plot_separately:
+ ts[new_fig] = []
+ xs[new_fig] = []
+ labels[new_fig] = []
+
tds = list(parsed_data['time_derivatives'].keys())
cdvs = ['%s??'%c for c in parsed_data['conditional_derived_variables'].keys()]
outputs = tds+cdvs
logger.info('Loading data: %s, assuming these represent %s (%i values)'%(data.keys(),outputs, len(outputs)))
for i in indices:
- ts.append(data['t'])
- xs.append(data[i])
- labels.append(outputs[i] if i < len(outputs) else '???')
+ label = outputs[i] if i < len(outputs) else '???'
+
+ fig = default_figure
+ for new_fig in plot_separately:
+ if label in plot_separately[new_fig]:
+ fig = new_fig
+ ts[fig].append(data['t'])
+ xs[fig].append(data[i])
+ labels[fig].append(label)
from pyneuroml.plot.Plot import generate_plot
- ax = generate_plot(ts, xs,
- "Data from %s after running %s"%(result_file, filename), # Title
- labels=labels,
- xaxis="Time (?)", # x axis legend
- yaxis="??", # y axis legend
- show_plot_already=show_plot_already, # Show or wait for plt.show()?
- )
+ axes = {}
+ for fig_title in ts:
+
+ ax = generate_plot(ts[fig_title], xs[fig_title],
+ title = fig_title,
+ labels=labels[fig_title],
+ xaxis="Time (?)", # x axis legend
+ yaxis="??", # y axis legend
+ show_plot_already=show_plot_already, # Show or wait for plt.show()?
+ )
+ axes[fig_title] = ax
+ return axes
+
def cli(a: typing.Optional[typing.Any] = None, **kwargs: str):
"""Main cli caller method"""
From e309515a302bcb768db4e6b8a18f9332bfc065aa Mon Sep 17 00:00:00 2001
From: pgleeson
Date: Tue, 30 Apr 2024 18:35:53 +0100
Subject: [PATCH 5/5] Updates to pynml-channelanalysis to allow plotting
subgates
---
pyneuroml/analysis/LEMS_Test_TEMPLATE.xml | 4 ++--
pyneuroml/analysis/NML2ChannelAnalysis.py | 10 +++++++++-
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml b/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml
index b131a1c7..5609ec96 100644
--- a/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml
+++ b/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml
@@ -139,10 +139,10 @@
#end##
#foreach ($g in $gates)##
-
+
-
+
#end##
diff --git a/pyneuroml/analysis/NML2ChannelAnalysis.py b/pyneuroml/analysis/NML2ChannelAnalysis.py
index 7bb3c03c..66cd6f1f 100644
--- a/pyneuroml/analysis/NML2ChannelAnalysis.py
+++ b/pyneuroml/analysis/NML2ChannelAnalysis.py
@@ -469,9 +469,17 @@ def get_channel_gates(
"gate_hh_rates",
"gate_hh_tau_infs",
"gate_hh_instantaneouses",
+ "gate_fractionals",
]:
if hasattr(channel, gates):
- channel_gates += [g.id for g in getattr(channel, gates)]
+ if gates == "gate_fractionals":
+ for g in getattr(channel, gates):
+ for sg in g.sub_gates:
+ channel_gates.append(str('%s/%s'%(g.id, sg.id)))
+ else:
+ for g in getattr(channel, gates):
+ channel_gates.append(g.id)
+ #print('- Found gates: %s'%channel_gates)
return channel_gates