Skip to content

Commit

Permalink
Merge pull request #262 from NeuroML/feat/sim-meta
Browse files Browse the repository at this point in the history
Expose `meta` in LEMSSimulation
  • Loading branch information
pgleeson authored Nov 15, 2023
2 parents a08ac71 + bbb2e2b commit 3dd5ccd
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 22 deletions.
23 changes: 19 additions & 4 deletions pyneuroml/lems/LEMSSimulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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_<some id string>.xml` is the suggested format. Leave empty
to use `LEMS_<sim_id>.xml` :type file_name: str
to use `LEMS_<sim_id>.xml`
:type file_name: str
:returns: name of file
:rtype: str
"""
Expand Down
38 changes: 20 additions & 18 deletions pyneuroml/lems/LEMS_TEMPLATE.xml
Original file line number Diff line number Diff line change
@@ -1,49 +1,51 @@
<Lems>

#if ($comment)##
<!-- ${comment} -->
#end##

#end##
<!-- Specify which component to run -->
<Target component="${sim_id}"${report}/>

<!-- Include core NeuroML2 ComponentType definitions -->
<Include file="Cells.xml"/>
<Include file="Networks.xml"/>
<Include file="Simulation.xml"/>

#foreach ($include_file in $include_files)##
<Include file="${include_file}"/>
#end##
#end##

#set( $start = -0.1 * $duration )
#set( $end = 1.1 * $duration )
<Simulation id="${sim_id}" length="${duration}ms" step="${dt}ms" target="${target}" seed="${seed}"> <!-- Note seed: ensures same random numbers used every run -->

#if ($meta)##
<Meta for="${meta.for}" method="${meta.method}" abs_tolerance="${meta.abs_tolerance}" rel_tolerance="${meta.rel_tolerance}"/>
#end##
#foreach ($display in $displays)##
<Display id="${display.id}" title="${display.title}" timeScale="${display.time_scale}" xmin="$start" xmax="$end" ymin="${display.ymin}" ymax="${display.ymax}">
#foreach ($line in $display.lines)##
<Line id="${line.id}" quantity="${line.quantity}" scale="${line.scale}" color="${line.color}" timeScale="${line.time_scale}"/>
#end##
#end##
</Display>
#end##

#end##
#foreach ($output_file in $output_files)##
<OutputFile id="${output_file.id}" fileName="${output_file.file_name}">
#foreach ($column in $output_file.columns)##
<OutputColumn id="${column.id}" quantity="${column.quantity}"/>
#end##
<OutputColumn id="${column.id}" quantity="${column.quantity}"/>
#end##
</OutputFile>
#end##

#end##
#foreach ($event_output_file in $event_output_files)##
<EventOutputFile id="${event_output_file.id}" fileName="${event_output_file.file_name}" format="${event_output_file.format}">
#foreach ($selection in $event_output_file.selections)##
<EventSelection id="${selection.id}" select="${selection.select}" eventPort="${selection.event_port}"/>
#end##
<EventSelection id="${selection.id}" select="${selection.select}" eventPort="${selection.event_port}"/>
#end##
</EventOutputFile>
#end##

#end##
</Simulation>

</Lems>
73 changes: 73 additions & 0 deletions tests/lems/test_lemssimulation.py
Original file line number Diff line number Diff line change
@@ -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 <sanjay DOT ankur AT gmail DOT com>
"""

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 = '<Meta for="neuron" method="cvode" abs_tolerance="0.0001" rel_tolerance="0.0004"/>'

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 = '<Meta for="neuron" method="cvode" abs_tolerance="0.0001" rel_tolerance="0.0004"/>'

with open(lems_simulation_file, "r") as f:
self.assertIn(expected_string, f.read())

pl.Path(lems_simulation_file).unlink()

0 comments on commit 3dd5ccd

Please sign in to comment.