diff --git a/ci/run-apitest.sh b/ci/run-apitest.sh
index 48666b1..4e689bb 100755
--- a/ci/run-apitest.sh
+++ b/ci/run-apitest.sh
@@ -6,9 +6,14 @@
#
# Run api tests on GitHub actions
-python examples/apitest.py
-python examples/apitest2.py
-python examples/loadtest.py
+cd examples
+python apitest.py
+python apitest2.py
+python apitest3.py
+python loadtest.py
+python apitest_maxmin.py
+cd ..
+
# Update NeuroML2 path for CI
if [ "$CI" = "true" ]; then
diff --git a/examples/apitest_maxmin.py b/examples/apitest_maxmin.py
new file mode 100644
index 0000000..ad1ebb4
--- /dev/null
+++ b/examples/apitest_maxmin.py
@@ -0,0 +1,35 @@
+#! /usr/bin/python
+
+import lems.api as lems
+
+model = lems.Model()
+
+#model.add(lems.Include("maxmin.xml"))
+
+model.add(lems.Dimension("voltage", m=1, l=3, t=-3, i=-1))
+model.add(lems.Dimension("time", t=1))
+model.add(lems.Dimension("capacitance", m=-1, l=-2, t=4, i=2))
+
+model.add(lems.Unit("milliVolt", "mV", "voltage", -3))
+model.add(lems.Unit("milliSecond", "ms", "time", -3))
+model.add(lems.Unit("microFarad", "uF", "capacitance", -12))
+
+iaf1 = lems.ComponentType("iaf1")
+model.add(iaf1)
+
+iaf1.add(lems.Parameter("threshold", "voltage", minval=-44, maxval=55))
+iaf1.add(lems.Parameter("reset", "voltage"))
+
+
+fn = "maxmin.xml"
+model.export_to_file(fn)
+
+print("----------------------------------------------")
+print(open(fn, "r").read())
+print("----------------------------------------------")
+
+print("Written generated LEMS to %s" % fn)
+
+from lems.base.util import validate_lems
+
+validate_lems(fn)
diff --git a/examples/maxmin.xml b/examples/maxmin.xml
new file mode 100644
index 0000000..a4f428d
--- /dev/null
+++ b/examples/maxmin.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lems/model/component.py b/lems/model/component.py
index ea4b5e0..1fbf735 100644
--- a/lems/model/component.py
+++ b/lems/model/component.py
@@ -21,7 +21,7 @@ class Parameter(LEMSBase):
Stores a parameter declaration.
"""
- def __init__(self, name, dimension, description=""):
+ def __init__(self, name, dimension, minval=None, maxval=None, description=""):
"""
Constructor.
@@ -63,6 +63,14 @@ def __init__(self, name, dimension, description=""):
:type: str """
+ self.minval = minval
+ """ Minimum value of this parameter.
+ :type: str """
+
+ self.maxval = maxval
+ """ Maximum value of this parameter.
+ :type: str """
+
def toxml(self):
"""
Exports this object into a LEMS XML object
@@ -332,7 +340,7 @@ class Exposure(LEMSBase):
Stores a exposure specification.
"""
- def __init__(self, name, dimension, description=""):
+ def __init__(self, name, dimension, minval=None, maxval=None, description=""):
"""
Constructor.
@@ -344,6 +352,14 @@ def __init__(self, name, dimension, description=""):
:type: str """
+ self.minval = minval
+ """ Minimum value of this parameter.
+ :type: str """
+
+ self.maxval = maxval
+ """ Maximum value of this parameter.
+ :type: str """
+
self.dimension = dimension
""" Physical dimension of the exposure.
diff --git a/lems/model/dynamics.py b/lems/model/dynamics.py
index 60b9cc2..8a613fe 100644
--- a/lems/model/dynamics.py
+++ b/lems/model/dynamics.py
@@ -16,7 +16,7 @@ class StateVariable(LEMSBase):
Store the specification of a state variable.
"""
- def __init__(self, name, dimension, exposure=None):
+ def __init__(self, name, dimension, minval=None, maxval=None, exposure=None):
"""
Constructor.
@@ -28,6 +28,14 @@ def __init__(self, name, dimension, exposure=None):
:type: str """
+ self.minval = minval
+ """ Minimum value of this parameter.
+ :type: str """
+
+ self.maxval = maxval
+ """ Maximum value of this parameter.
+ :type: str """
+
self.dimension = dimension
""" Dimension of the state variable.
@@ -185,9 +193,9 @@ def toxml(self):
"""
Exports this object into a LEMS XML object
"""
-
+ cond = ' condition="{0}"'.format(self.condition) if self.condition is not None else ''
return (
- '"
)
diff --git a/lems/parser/LEMS.py b/lems/parser/LEMS.py
index 2cdb725..022c73a 100644
--- a/lems/parser/LEMS.py
+++ b/lems/parser/LEMS.py
@@ -998,6 +998,16 @@ def parse_exposure(self, node):
except:
self.raise_error(" must specify a name")
+ if "minval" in node.lattrib:
+ minval = node.lattrib["minval"]
+ else:
+ minval = 0.0
+
+ if "maxval" in node.lattrib:
+ maxval = node.lattrib["maxval"]
+ else:
+ maxval = 0.0
+
try:
dimension = node.lattrib["dimension"]
except:
@@ -1005,7 +1015,7 @@ def parse_exposure(self, node):
description = node.lattrib.get("description", "")
- self.current_component_type.add_exposure(Exposure(name, dimension, description))
+ self.current_component_type.add_exposure(Exposure(name, dimension, minval, maxval, description))
def parse_fixed(self, node):
"""
@@ -1298,13 +1308,23 @@ def parse_parameter(self, node):
except:
self.raise_error(" must specify a name")
+ if "minval" in node.lattrib:
+ minval = node.lattrib["minval"]
+ else:
+ minval = 0.0
+
+ if "maxval" in node.lattrib:
+ maxval = node.lattrib["maxval"]
+ else:
+ maxval = 0.0
+
try:
dimension = node.lattrib["dimension"]
except:
self.raise_error("Parameter '{0}' has no dimension", name)
description = node.lattrib.get("description", "")
- parameter = Parameter(name, dimension, description)
+ parameter = Parameter(name, dimension, minval, maxval, description)
self.current_component_type.add_parameter(parameter)
@@ -1650,6 +1670,16 @@ def parse_state_variable(self, node):
else:
self.raise_error(" must specify a name")
+ if "minval" in node.lattrib:
+ minval = node.lattrib["minval"]
+ else:
+ minval = 0.0
+
+ if "maxval" in node.lattrib:
+ maxval = node.lattrib["maxval"]
+ else:
+ maxval = 0.0
+
if "dimension" in node.lattrib:
dimension = node.lattrib["dimension"]
else:
@@ -1660,7 +1690,7 @@ def parse_state_variable(self, node):
else:
exposure = None
- self.current_regime.add_state_variable(StateVariable(name, dimension, exposure))
+ self.current_regime.add_state_variable(StateVariable(name, dimension, minval, maxval, exposure))
def parse_structure(self, node):
"""