From 0c3db7052076d40865bf91d455497afdeea3be41 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Wed, 18 Oct 2023 16:44:48 +0100 Subject: [PATCH 1/4] feat(lems-simulation): expose Meta simulation attribute --- pyneuroml/lems/LEMSSimulation.py | 23 +++++++++++++++---- pyneuroml/lems/LEMS_TEMPLATE.xml | 38 +++++++++++++++++--------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/pyneuroml/lems/LEMSSimulation.py b/pyneuroml/lems/LEMSSimulation.py index 77d12e43b..82b73e1ae 100644 --- a/pyneuroml/lems/LEMSSimulation.py +++ b/pyneuroml/lems/LEMSSimulation.py @@ -34,11 +34,12 @@ def __init__( sim_id: str, duration: float, dt: float, - target: str = None, + target: typing.Optional[str] = None, comment: str = "\n\n This LEMS file has been automatically generated using PyNeuroML v%s (libNeuroML v%s)\n\n " % (pynml_ver, libnml_ver), lems_file_generate_seed: typing.Any = None, simulation_seed: int = 12345, + meta: typing.Optional[typing.Dict[str, str]] = None, ) -> None: """Init a new LEMSSimulation object. @@ -62,6 +63,18 @@ def __init__( :type lems_file_generate_seed: :param simulation_seed: simulation seed to set to :type simulation_seed: int + :param meta: dictionary to set Meta options. + + Currently, only supported for the Neuron simulator to use the CVODE + solver. A dict needs to be passed: + { + "for": "neuron", + "method": "cvode", + "abs_tolerance" = "0.001", + "rel_tolerance": "0.001" + } + + :type meta: dict """ self.lems_info["sim_id"] = sim_id @@ -75,6 +88,7 @@ def __init__( self.lems_info["displays"] = [] self.lems_info["output_files"] = [] self.lems_info["event_output_files"] = [] + self.lems_info["meta"] = meta if target: self.lems_info["target"] = target @@ -251,7 +265,7 @@ def add_line_to_display( line_id: str, quantity: str, scale: str = "1", - color: str = None, + color: typing.Optional[str] = None, timeScale: str = "1ms", ) -> None: """Add a new line to the display @@ -364,12 +378,13 @@ def to_xml(self) -> str: templ = airspeed.Template(f.read()) return templ.merge(self.lems_info) - def save_to_file(self, file_name: str = None): + def save_to_file(self, file_name: typing.Optional[str] = None): """Save LEMSSimulation to a file. :param file_name: name of file to store to. `LEMS_.xml` is the suggested format. Leave empty - to use `LEMS_.xml` :type file_name: str + to use `LEMS_.xml` + :type file_name: str :returns: name of file :rtype: str """ diff --git a/pyneuroml/lems/LEMS_TEMPLATE.xml b/pyneuroml/lems/LEMS_TEMPLATE.xml index c7b05763c..c18e4054f 100644 --- a/pyneuroml/lems/LEMS_TEMPLATE.xml +++ b/pyneuroml/lems/LEMS_TEMPLATE.xml @@ -1,9 +1,9 @@ - + #if ($comment)## - -#end## + +#end## @@ -11,39 +11,41 @@ - + #foreach ($include_file in $include_files)## -#end## - +#end## + #set( $start = -0.1 * $duration ) #set( $end = 1.1 * $duration ) - +#if ($meta)## + +#end## #foreach ($display in $displays)## #foreach ($line in $display.lines)## -#end## +#end## - -#end## + +#end## #foreach ($output_file in $output_files)## #foreach ($column in $output_file.columns)## - -#end## + +#end## - -#end## + +#end## #foreach ($event_output_file in $event_output_files)## #foreach ($selection in $event_output_file.selections)## - -#end## + +#end## - -#end## + +#end## From f7fddfeb6ae2a0480b71bb35d9e7601d9d3bc991 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Wed, 18 Oct 2023 16:58:25 +0100 Subject: [PATCH 2/4] test(lemssimulation): add test for meta --- tests/lems/test_lemssimulation.py | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/lems/test_lemssimulation.py diff --git a/tests/lems/test_lemssimulation.py b/tests/lems/test_lemssimulation.py new file mode 100644 index 000000000..b16ee8f5e --- /dev/null +++ b/tests/lems/test_lemssimulation.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +""" +Test the LEMSSimulation class + +File: tests/lems/test_lemssimulation.py + +Copyright 2023 NeuroML contributors +Author: Ankur Sinha +""" + +import unittest +import logging +import pathlib as pl + +from pyneuroml.lems import LEMSSimulation + + +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + + +class TestLEMSSimulation(unittest.TestCase): + + """Test the LEMSSimulation class""" + + def test_lemssimulation_meta(self): + """Test the LEMSSimulation class.""" + # Create a simulation instance of the model + simulation_id = "tests-sim" + simulation = LEMSSimulation( + sim_id=simulation_id, + duration=1000, + dt=0.1, + simulation_seed=123, + meta={ + "for": "neuron", + "method": "cvode", + "abs_tolerance": "0.0001", + "rel_tolerance": "0.0004", + }, + ) + simulation.assign_simulation_target("some_network") + # Save the simulation to a file + lems_simulation_file = simulation.save_to_file() + + expected_string = '' + + with open(lems_simulation_file, "r") as f: + self.assertIn(expected_string, f.read()) + + pl.Path(lems_simulation_file).unlink() From df82e71fd7ab35ad837b914406e38b881eb09836 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Wed, 18 Oct 2023 17:00:53 +0100 Subject: [PATCH 3/4] test(LEMSSimulation): add xfail test for meta --- tests/lems/test_lemssimulation.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/lems/test_lemssimulation.py b/tests/lems/test_lemssimulation.py index b16ee8f5e..a6b49d970 100644 --- a/tests/lems/test_lemssimulation.py +++ b/tests/lems/test_lemssimulation.py @@ -11,6 +11,7 @@ import unittest import logging import pathlib as pl +import pytest from pyneuroml.lems import LEMSSimulation @@ -49,3 +50,25 @@ def test_lemssimulation_meta(self): self.assertIn(expected_string, f.read()) pl.Path(lems_simulation_file).unlink() + + @pytest.mark.xfail + def test_lemssimulation_meta_should_fail(self): + """Test without meta to ensure it's not always added""" + # Create a simulation instance of the model + simulation_id = "tests-sim-failure" + simulation = LEMSSimulation( + sim_id=simulation_id, + duration=1000, + dt=0.1, + simulation_seed=123, + ) + simulation.assign_simulation_target("some_network") + # Save the simulation to a file + lems_simulation_file = simulation.save_to_file() + + expected_string = '' + + with open(lems_simulation_file, "r") as f: + self.assertIn(expected_string, f.read()) + + pl.Path(lems_simulation_file).unlink() From 73d6c90eedf3112fa51566d8a966b5a62209be36 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Wed, 18 Oct 2023 17:01:26 +0100 Subject: [PATCH 4/4] chore: format with isort --- tests/lems/test_lemssimulation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/lems/test_lemssimulation.py b/tests/lems/test_lemssimulation.py index a6b49d970..f479f0e93 100644 --- a/tests/lems/test_lemssimulation.py +++ b/tests/lems/test_lemssimulation.py @@ -8,14 +8,13 @@ Author: Ankur Sinha """ -import unittest import logging import pathlib as pl -import pytest +import unittest +import pytest from pyneuroml.lems import LEMSSimulation - logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG)