Skip to content

Commit

Permalink
Merge pull request #254 from NeuroML/experimental
Browse files Browse the repository at this point in the history
To v1.1.0; Update to jnml v0.12.3 jar
  • Loading branch information
pgleeson authored Sep 19, 2023
2 parents 13ae421 + c90cd3a commit 5d66555
Show file tree
Hide file tree
Showing 17 changed files with 512 additions and 86 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,11 @@ arm64
/examples/plot.py
/tests/utils/test_rotation.net.nml
/tests/utils/test_rotation.net.png
/tests/analysis/test_analysis_if.png
/tests/analysis/test_analysis_iv.png
/tests/analysis/test_analysis_traces.png
/tests/analysis/test_cell_analysis.cell.nml
/tests/plot/test_schematic_plot_2d_test_cell_nml_xy.png
/tests/plot/test_schematic_plot_2d_test_cell_nml_xz.png
/tests/plot/test_schematic_plot_2d_test_cell_nml_yz.png
/tests/analysis/*png
18 changes: 7 additions & 11 deletions examples/LeakConductance.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ NEURON {
RANGE i__LeakConductance : a copy of the variable for current which makes it easier to access from outside the mod file
RANGE gmax : Will be changed when ion channel mechanism placed on cell!
RANGE conductance : parameter

RANGE g : exposure

RANGE fopen : exposure
RANGE conductanceScale : derived variable
RANGE fopen0 : derived variable
Expand All @@ -36,11 +34,13 @@ UNITS {
(mV) = (millivolt)
(mS) = (millisiemens)
(uS) = (microsiemens)
(nF) = (nanofarad)
(molar) = (1/liter)
(kHz) = (kilohertz)
(mM) = (millimolar)
(um) = (micrometer)
(umol) = (micromole)
(pC) = (picocoulomb)
(S) = (siemens)

}
Expand All @@ -49,7 +49,7 @@ PARAMETER {

gmax = 0 (S/cm2) : Will be changed when ion channel mechanism placed on cell!

conductance = 1.0E-5 (uS)
conductance = 1.0E-5 (uS) : was: 1.0E-11 (conductance)
}

ASSIGNED {
Expand All @@ -62,14 +62,10 @@ ASSIGNED {
i (mA/cm2)
i__LeakConductance (mA/cm2)


conductanceScale : derived variable

fopen0 : derived variable

fopen : derived variable

g (uS) : derived variable
conductanceScale : derived variable
fopen0 : derived variable
fopen : derived variable
g (uS) : derived variable

}

Expand Down
2 changes: 1 addition & 1 deletion pyneuroml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
__version__ = importlib_metadata.version("pyNeuroML")


JNEUROML_VERSION = "0.12.2"
JNEUROML_VERSION = "0.12.3"

# Define a logger for the package
logging.basicConfig(
Expand Down
11 changes: 7 additions & 4 deletions pyneuroml/analysis/ChannelDensityPlot.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ def plot_channel_densities(
show_plots_already: bool = True,
morph_plot_type: str = "constant",
morph_min_width: float = 2.0,
target_directory=None
):
"""Plot channel densities on a Cell on morphology plots.
Expand Down Expand Up @@ -603,6 +604,8 @@ def plot_channel_densities(
:type colormap_name: str
:returns: None
"""
tgt_dir = target_directory+'/' if target_directory else './'

if channel_density_ids is not None and ion_channels is not None:
raise ValueError(
"Only one of channel_density_ids or ions channels may be provided"
Expand Down Expand Up @@ -685,7 +688,7 @@ def plot_channel_densities(
min_width=morph_min_width,
overlay_data=data,
overlay_data_label="(S/m2)",
save_to_file=f"{cell.id}_{cd.id}.cd.png",
save_to_file=f"{tgt_dir}{cell.id}_{cd.id}.cd.png",
datamin=ymin,
plane2d=plane2d,
nogui=not show_plots_already,
Expand All @@ -710,7 +713,7 @@ def plot_channel_densities(
title_above_plot=True,
xaxis="Distance from soma (um)",
yaxis="g density (S/m2)",
save_figure_to=f"{cell.id}_{cd.id}_cd_vs_dist.png",
save_figure_to=f"{tgt_dir}{cell.id}_{cd.id}_cd_vs_dist.png",
show_plot_already=show_plots_already,
linestyles=[" "],
linewidths=["0"],
Expand Down Expand Up @@ -786,7 +789,7 @@ def plot_channel_densities(
min_width=morph_min_width,
overlay_data=data,
overlay_data_label="(S/m2)",
save_to_file=f"{cell.id}_{ion_channel}.ion.png",
save_to_file=f"{tgt_dir}{cell.id}_{ion_channel}.ion.png",
datamin=ymin,
plane2d=plane2d,
nogui=not show_plots_already,
Expand All @@ -811,7 +814,7 @@ def plot_channel_densities(
title_above_plot=True,
xaxis="Distance from soma (um)",
yaxis="g density (S/m2)",
save_figure_to=f"{cell.id}_{ion_channel}_ion_vs_dist.png",
save_figure_to=f"{tgt_dir}{cell.id}_{ion_channel}_ion_vs_dist.png",
show_plot_already=show_plots_already,
linestyles=[" "],
linewidths=["0"],
Expand Down
13 changes: 7 additions & 6 deletions pyneuroml/archive/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
"""


import os
import typing
import argparse
import logging
import os
import pathlib
import argparse
import shutil
import typing
from zipfile import ZipFile

from lems.model.model import Model
from neuroml.loaders import read_neuroml2_file
from pyneuroml.pynml import extract_lems_definition_files
from pyneuroml.utils.cli import build_namespace
from lems.model.model import Model

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
Expand Down Expand Up @@ -107,7 +108,7 @@ def get_model_file_list(
rootfile: str,
filelist: typing.List[str],
rootdir: str = ".",
lems_def_dir: str = None,
lems_def_dir: typing.Optional[str] = None,
) -> typing.Optional[str]:
"""Get the list of files to archive.
Expand Down Expand Up @@ -188,8 +189,8 @@ def get_model_file_list(


def create_combine_archive(
zipfile_name: str,
rootfile: str,
zipfile_name: typing.Optional[str] = None,
zipfile_extension=".neux",
filelist: typing.List[str] = [],
):
Expand Down
Binary file not shown.
227 changes: 227 additions & 0 deletions pyneuroml/nsgr/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
#!/usr/bin/env python3
"""
Module for working with NSG. See https://github.com/OpenSourceBrain/pynsgr
File: pyneuroml/nsgr/__init__.py
Copyright 2023 NeuroML contributors
"""


import logging
import os
import pathlib
import shutil
import time
import typing
from zipfile import ZipFile

from pyneuroml.archive import get_model_file_list
from pyneuroml.pynml import run_lems_with
from pyneuroml.utils import get_files_generated_after, get_pyneuroml_tempdir
from pynsgr.commands.nsgr_submit import nsgr_submit

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


def run_on_nsg(
engine: str,
lems_file_name: str,
nsg_sim_config: typing.Dict[typing.Any, typing.Any] = {},
run_dir: typing.Optional[str] = None,
dry_run: bool = False,
*engine_args: typing.Any,
**engine_kwargs: typing.Any,
):
"""Run NeuroML/LEMS simulation on NSG.
Since the versions of tools on NSG may differ from what you have installed
locally, this method first generates the simulation engine specific files
(runner script for NEURON and mod files, for example) for the provided
engine in a new folder, zips them up, writes the config files, and then
submits the job to NSG using pynsgr.
The data generated by the job (if the command is not interrupted) is also
downloaded to the newly created directory.
Please ensure that you have set up an account and have your NSG
configuration file populated as noted in pynsgr.
- https://nsgr.sdsc.edu:8443/restusers/documentation
- https://nsgr.sdsc.edu:8443/restusers/docs/tools
Default for the nsg_sim_config is below, keys provided by the user in
nsg_sim_config overwrite these:
.. code:: python
nsg_sim_config_dict = {
"number_cores_": "1",
"number_nodes_": "1",
"tasks_per_node_": "1",
"runtime_": "0.5",
'toolId': "PY_EXPANSE",
'nrnivmodl_o_': "1"
}
.. versionadded:: 1.0.10
:param engine: name of engine: suffixes of the run_lems_with.. functions
:type engine: str
:param lems_file_name: name of LEMS simulation file
:type lems_file_name: str
:param nsg_sim_config: dict containing params and values that will be
printed to testParam.properties
:type nsg_sim_config: dict
:param run_dir: directory in which model files are copied, backend specific
files are generated, and from which the archive is sent to NSG. Results
from the NSG run will also be downloaded to this directory.
By default, this is the directory that the command is run from (".")
It is good practice to separate directories where simulations are run
from the source of the model/simulations.
:type run_dir: str
:param *engine_args: positional args to be passed to the engine runner
function
:param **engine_kwargs: keyword args to be be passed to the engine runner
function
:param dry_run: do everything but do not submit
:type dry_run: bool
"""
supported_engines = ["jneuroml_neuron", "jneuroml_netpyne"]
if engine not in supported_engines:
print(f"Engine {engine} is not currently supported on NSG")
print(f"Supported engines are: {supported_engines}")
return

logger.debug(f"NSGR: engine is {engine}")

zipfile_name = lems_file_name.replace(".xml", "") + "_NSG.zip"
# default dictionary
nsg_sim_config_dict = {
"number_cores_": "1",
"number_nodes_": "1",
"tasks_per_node_": "1",
"runtime_": "0.5",
"toolId": "PY_EXPANSE",
"nrnivmodl_o_": "1",
}

# update dict based on user values
for key, val in nsg_sim_config.items():
nsg_sim_config_dict[key] = val

if run_dir is None:
run_dir = "."

tdir = get_pyneuroml_tempdir(rootdir=run_dir, prefix="pyneuroml")
os.mkdir(tdir)

logger.debug("Getting list of model files")
model_file_list = [] # type: list
lems_def_dir = None
lems_def_dir = get_model_file_list(
lems_file_name, model_file_list, ".", lems_def_dir
)

for model_file in model_file_list:
logger.debug(f"Copying: {model_file} -> {tdir + '/' + model_file}")
# if model file has directory structures in it, recreate the dirs in
# the temporary directory
if len(model_file.split("/")) > 1:
# throw error if files in parent directories are referred to
if "../" in model_file:
raise ValueError(
"""
Cannot handle parent directories because we
cannot create these directories correctly in
the temporary location. Please re-organize
your code such that all included files are in
sub-directories of this main directory.
"""
)

model_file_path = pathlib.Path(tdir + "/" + model_file)
parent = model_file_path.parent
parent.mkdir(parents=True, exist_ok=True)
shutil.copy(model_file, tdir + "/" + model_file)

if lems_def_dir is not None:
logger.info(f"Removing LEMS definitions directory {lems_def_dir}")
shutil.rmtree(lems_def_dir)

os.chdir(tdir)
logger.info(f"Generating simulator specific files in {tdir}")
start_time = time.time() - 1.0

if engine == "jneuroml_neuron":
run_lems_with(
engine,
lems_file_name=lems_file_name,
compile_mods=False,
only_generate_scripts=True,
*engine_args,
**engine_kwargs,
)
elif engine == "jneuroml_netpyne":
run_lems_with(
engine,
lems_file_name=lems_file_name,
only_generate_scripts=True,
*engine_args,
**engine_kwargs,
)

generated_files = get_files_generated_after(
start_time, ignore_suffixes=["xml", "nml"]
)
logger.debug(f"Generated files are: {generated_files}")

logger.info("Generating zip file")
runner_file = ""
# NSG requires that the top level directory exist
nsg_dir = pathlib.Path(zipfile_name.replace(".zip", ""))
logger.debug(f"Creating directory and moving generated files to it: {nsg_dir}")

# remove it if it exists
if nsg_dir.is_dir():
shutil.rmtree(str(nsg_dir))
nsg_dir.mkdir()

with ZipFile(zipfile_name, "w") as archive:
for f in generated_files:
if engine == "jneuroml_neuron":
if f.endswith("_nrn.py"):
runner_file = f
elif engine == "jneuroml_netpyne":
if f.endswith("_netpyne.py"):
runner_file = f
fpath = pathlib.Path(f)
moved_path = fpath.rename(nsg_dir / fpath)
archive.write(str(moved_path))

logger.debug("Printing testParam.properties")
nsg_sim_config_dict["filename_"] = runner_file
logger.debug(f"NSG sim config is: {nsg_sim_config_dict}")

with open("testParam.properties", "w") as file:
for key, val in nsg_sim_config_dict.items():
print(f"{key}={val}", file=file)

logger.debug("Printing testInput.properties")
with open("testInput.properties", "w") as file:
print(f"infile_=@./{zipfile_name}", file=file)

print(f"{zipfile_name} generated")
# uses argv, where the first argument is the script itself, so we must pass
# something as the 0th index of the list
if not dry_run:
if nsgr_submit(["", ".", "validate"]) == 0:
print("Attempting to submit to NSGR")
return nsgr_submit(["", ".", "run"])
else:
print("Dry run mode enabled. Not submitting to NSG.")

return True
Loading

0 comments on commit 5d66555

Please sign in to comment.