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## diff --git a/tests/lems/test_lemssimulation.py b/tests/lems/test_lemssimulation.py new file mode 100644 index 000000000..f479f0e93 --- /dev/null +++ b/tests/lems/test_lemssimulation.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +""" +Test the LEMSSimulation class + +File: tests/lems/test_lemssimulation.py + +Copyright 2023 NeuroML contributors +Author: Ankur Sinha +""" + +import logging +import pathlib as pl +import unittest + +import pytest +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() + + @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()