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): """