myokit 1.33.9__py3-none-any.whl → 1.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- myokit/__init__.py +9 -36
- myokit/__main__.py +76 -142
- myokit/_aux.py +62 -16
- myokit/_bin/example.mmt +1 -2
- myokit/_bin/install-win/menu.json +7 -7
- myokit/_config.py +22 -31
- myokit/_datablock.py +30 -74
- myokit/_datalog.py +49 -72
- myokit/_err.py +25 -24
- myokit/_expressions.py +50 -68
- myokit/_io.py +15 -27
- myokit/_model_api.py +453 -249
- myokit/_myokit_version.py +1 -5
- myokit/_parsing.py +38 -44
- myokit/_progress.py +5 -8
- myokit/_protocol.py +99 -9
- myokit/_sim/__init__.py +7 -24
- myokit/_sim/cable.c +6 -8
- myokit/_sim/cable.py +6 -8
- myokit/_sim/cmodel.h +125 -70
- myokit/_sim/cmodel.py +12 -14
- myokit/_sim/compiler.py +1 -4
- myokit/_sim/cvodessim.c +196 -118
- myokit/_sim/cvodessim.py +130 -103
- myokit/_sim/differential.hpp +4 -4
- myokit/_sim/fiber_tissue.c +4 -8
- myokit/_sim/fiber_tissue.py +11 -13
- myokit/_sim/jacobian.cpp +2 -2
- myokit/_sim/jacobian.py +11 -8
- myokit/_sim/mcl.h +53 -55
- myokit/_sim/opencl.py +21 -27
- myokit/_sim/openclsim.c +3 -7
- myokit/_sim/openclsim.cl +3 -3
- myokit/_sim/openclsim.py +49 -40
- myokit/_sim/pacing.h +36 -16
- myokit/_sim/rhs.c +6 -13
- myokit/_sim/rhs.py +5 -14
- myokit/_sim/sundials.py +1 -4
- myokit/_system.py +10 -16
- myokit/_unit.py +4 -13
- myokit/float.py +0 -3
- myokit/formats/__init__.py +8 -10
- myokit/formats/ansic/__init__.py +0 -3
- myokit/formats/ansic/_ewriter.py +2 -4
- myokit/formats/ansic/_exporter.py +1 -4
- myokit/formats/ansic/template/cable.c +4 -4
- myokit/formats/ansic/template/euler.c +5 -5
- myokit/formats/ansic/template/sim.c +6 -6
- myokit/formats/axon/__init__.py +1 -3
- myokit/formats/axon/_abf.py +12 -17
- myokit/formats/axon/_atf.py +5 -6
- myokit/formats/axon/_importer.py +0 -3
- myokit/formats/cellml/__init__.py +0 -3
- myokit/formats/cellml/_ewriter.py +3 -6
- myokit/formats/cellml/_exporter.py +3 -6
- myokit/formats/cellml/_importer.py +1 -4
- myokit/formats/cellml/v1/__init__.py +0 -4
- myokit/formats/cellml/v1/_api.py +8 -11
- myokit/formats/cellml/v1/_parser.py +2 -5
- myokit/formats/cellml/v1/_writer.py +2 -11
- myokit/formats/cellml/v2/__init__.py +0 -3
- myokit/formats/cellml/v2/_api.py +8 -17
- myokit/formats/cellml/v2/_parser.py +2 -5
- myokit/formats/cellml/v2/_writer.py +1 -4
- myokit/formats/channelml/__init__.py +0 -3
- myokit/formats/channelml/_importer.py +11 -21
- myokit/formats/cpp/__init__.py +1 -3
- myokit/formats/cpp/_ewriter.py +0 -3
- myokit/formats/cuda/__init__.py +0 -3
- myokit/formats/cuda/_ewriter.py +2 -4
- myokit/formats/cuda/_exporter.py +0 -3
- myokit/formats/cuda/template/kernel.cu +8 -5
- myokit/formats/easyml/__init__.py +0 -3
- myokit/formats/easyml/_ewriter.py +9 -11
- myokit/formats/easyml/_exporter.py +2 -5
- myokit/formats/html/__init__.py +0 -3
- myokit/formats/html/_exporter.py +0 -3
- myokit/formats/html/_flatten.py +5 -21
- myokit/formats/latex/__init__.py +0 -3
- myokit/formats/latex/_ewriter.py +1 -4
- myokit/formats/latex/_exporter.py +4 -6
- myokit/formats/mathml/__init__.py +0 -3
- myokit/formats/mathml/_ewriter.py +2 -11
- myokit/formats/mathml/_parser.py +4 -6
- myokit/formats/matlab/__init__.py +0 -3
- myokit/formats/matlab/_ewriter.py +1 -4
- myokit/formats/matlab/_exporter.py +2 -5
- myokit/formats/matlab/template/main.m +3 -2
- myokit/formats/opencl/__init__.py +0 -3
- myokit/formats/opencl/_ewriter.py +2 -4
- myokit/formats/opencl/_exporter.py +2 -5
- myokit/formats/opencl/template/cable.c +10 -10
- myokit/formats/opencl/template/kernel.cl +1 -1
- myokit/formats/opencl/template/minilog.py +1 -1
- myokit/formats/python/__init__.py +0 -3
- myokit/formats/python/_ewriter.py +2 -5
- myokit/formats/python/_exporter.py +0 -3
- myokit/formats/python/template/sim.py +14 -14
- myokit/formats/sbml/__init__.py +0 -3
- myokit/formats/sbml/_api.py +50 -44
- myokit/formats/sbml/_importer.py +1 -4
- myokit/formats/sbml/_parser.py +2 -5
- myokit/formats/stan/__init__.py +0 -3
- myokit/formats/stan/_ewriter.py +2 -4
- myokit/formats/stan/_exporter.py +2 -5
- myokit/formats/stan/template/cell.stan +3 -3
- myokit/formats/sympy/__init__.py +0 -3
- myokit/formats/sympy/_ereader.py +1 -4
- myokit/formats/sympy/_ewriter.py +2 -5
- myokit/formats/wcp/__init__.py +0 -3
- myokit/formats/wcp/_wcp.py +2 -8
- myokit/formats/xml/__init__.py +0 -3
- myokit/formats/xml/_exporter.py +0 -3
- myokit/formats/xml/_split.py +0 -3
- myokit/gui/__init__.py +80 -246
- myokit/gui/datablock_viewer.py +103 -86
- myokit/gui/datalog_viewer.py +214 -66
- myokit/gui/explorer.py +15 -21
- myokit/gui/ide.py +171 -144
- myokit/gui/progress.py +9 -9
- myokit/gui/source.py +406 -375
- myokit/gui/vargrapher.py +2 -12
- myokit/lib/deps.py +12 -13
- myokit/lib/guess.py +3 -4
- myokit/lib/hh.py +20 -18
- myokit/lib/markov.py +21 -20
- myokit/lib/multi.py +1 -3
- myokit/lib/plots.py +20 -9
- myokit/pacing.py +0 -3
- myokit/pype.py +7 -18
- myokit/tests/__init__.py +3 -6
- myokit/tests/ansic_event_based_pacing.py +1 -4
- myokit/tests/ansic_fixed_form_pacing.py +3 -6
- myokit/tests/data/beeler-1977-model-compare-b.mmt +2 -2
- myokit/tests/data/clancy-1999-fitting.mmt +1 -0
- myokit/tests/test_aux.py +13 -28
- myokit/tests/test_cellml_v1_api.py +4 -19
- myokit/tests/test_cellml_v1_parser.py +0 -15
- myokit/tests/test_cellml_v1_writer.py +0 -9
- myokit/tests/test_cellml_v2_api.py +4 -19
- myokit/tests/test_cellml_v2_parser.py +0 -15
- myokit/tests/test_cellml_v2_writer.py +0 -9
- myokit/tests/test_cmodel.py +16 -22
- myokit/tests/test_compiler_detection.py +1 -11
- myokit/tests/test_component.py +108 -56
- myokit/tests/test_config.py +34 -67
- myokit/tests/test_datablock.py +1 -9
- myokit/tests/test_datalog.py +19 -24
- myokit/tests/test_dependency_checking.py +8 -23
- myokit/tests/test_expressions.py +0 -9
- myokit/tests/test_float.py +1 -5
- myokit/tests/test_formats.py +0 -9
- myokit/tests/test_formats_axon.py +1 -9
- myokit/tests/test_formats_cellml.py +0 -15
- myokit/tests/test_formats_channelml.py +0 -15
- myokit/tests/test_formats_easyml.py +0 -14
- myokit/tests/test_formats_exporters.py +1 -16
- myokit/tests/test_formats_expression_writers.py +1 -17
- myokit/tests/test_formats_html.py +0 -3
- myokit/tests/test_formats_importers.py +1 -16
- myokit/tests/test_formats_mathml_content.py +0 -9
- myokit/tests/test_formats_mathml_presentation.py +0 -9
- myokit/tests/test_formats_opencl.py +0 -10
- myokit/tests/test_formats_sbml.py +0 -15
- myokit/tests/test_formats_sympy.py +0 -9
- myokit/tests/test_formats_wcp.py +1 -3
- myokit/tests/test_io.py +27 -27
- myokit/tests/test_jacobian_calculator.py +6 -14
- myokit/tests/test_jacobian_tracer.py +0 -9
- myokit/tests/test_lib_deps.py +0 -9
- myokit/tests/test_lib_guess.py +0 -9
- myokit/tests/test_lib_hh.py +18 -12
- myokit/tests/test_lib_markov.py +21 -13
- myokit/tests/test_lib_multi.py +0 -9
- myokit/tests/test_lib_plots.py +13 -8
- myokit/tests/test_meta.py +0 -3
- myokit/tests/test_model.py +390 -96
- myokit/tests/test_model_building.py +44 -96
- myokit/tests/test_opencl_info.py +5 -14
- myokit/tests/test_pacing_factory.py +0 -3
- myokit/tests/test_pacing_system_c.py +1 -23
- myokit/tests/test_pacing_system_py.py +0 -9
- myokit/tests/test_parsing.py +139 -56
- myokit/tests/test_progress_reporters.py +0 -3
- myokit/tests/test_protocol.py +0 -9
- myokit/tests/test_protocol_floating_point.py +1 -10
- myokit/tests/test_protocol_time_series.py +82 -0
- myokit/tests/test_pype.py +0 -9
- myokit/tests/test_quantity.py +0 -9
- myokit/tests/test_rhs_benchmarker.py +1 -9
- myokit/tests/test_sbml_api.py +27 -42
- myokit/tests/test_sbml_parser.py +4 -19
- myokit/tests/test_simulation_1d.py +45 -25
- myokit/tests/test_simulation_cvodes.py +321 -55
- myokit/tests/test_simulation_cvodes_from_disk.py +0 -3
- myokit/tests/test_simulation_fiber_tissue.py +39 -12
- myokit/tests/test_simulation_log_interval.py +1 -431
- myokit/tests/test_simulation_opencl.py +69 -48
- myokit/tests/test_simulation_opencl_log_interval.py +1 -3
- myokit/tests/test_simulation_opencl_vs_cvode.py +1 -10
- myokit/tests/test_simulation_opencl_vs_sim1d.py +1 -10
- myokit/tests/test_system_info.py +1 -11
- myokit/tests/test_tools.py +0 -9
- myokit/tests/test_unit.py +1 -10
- myokit/tests/test_user_functions.py +0 -10
- myokit/tests/test_variable.py +231 -27
- myokit/tools.py +5 -21
- myokit/units.py +5 -3
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/METADATA +12 -15
- myokit-1.35.0.dist-info/RECORD +391 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/WHEEL +1 -1
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/entry_points.txt +0 -1
- myokit/_exec_new.py +0 -15
- myokit/_exec_old.py +0 -15
- myokit/_sim/cvodesim.c +0 -1551
- myokit/_sim/cvodesim.py +0 -674
- myokit/_sim/icsim.cpp +0 -563
- myokit/_sim/icsim.py +0 -363
- myokit/_sim/psim.cpp +0 -656
- myokit/_sim/psim.py +0 -493
- myokit/lib/common.py +0 -1094
- myokit/tests/test_lib_common.py +0 -130
- myokit/tests/test_simulation_cvode.py +0 -612
- myokit/tests/test_simulation_ic.py +0 -108
- myokit/tests/test_simulation_p.py +0 -223
- myokit-1.33.9.dist-info/RECORD +0 -403
- /myokit/formats/opencl/template/{test → test.sh} +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/LICENSE.txt +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/top_level.txt +0 -0
myokit/_expressions.py
CHANGED
|
@@ -5,26 +5,14 @@
|
|
|
5
5
|
# This file is part of Myokit.
|
|
6
6
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
7
|
#
|
|
8
|
-
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
8
|
+
import io
|
|
11
9
|
import math
|
|
12
10
|
import numpy
|
|
13
11
|
|
|
14
12
|
import myokit
|
|
15
|
-
from myokit import IntegrityError
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
try:
|
|
19
|
-
from cStringIO import StringIO
|
|
20
|
-
except ImportError:
|
|
21
|
-
from io import StringIO
|
|
14
|
+
from myokit import IntegrityError
|
|
22
15
|
|
|
23
|
-
# Strings in Python 2 and 3
|
|
24
|
-
try:
|
|
25
|
-
basestring
|
|
26
|
-
except NameError: # pragma: no python 2 cover
|
|
27
|
-
basestring = str
|
|
28
16
|
|
|
29
17
|
# Expression precedence levels
|
|
30
18
|
FUNCTION_CALL = 70
|
|
@@ -37,7 +25,7 @@ CONDITION_AND = 10
|
|
|
37
25
|
LITERAL = 0
|
|
38
26
|
|
|
39
27
|
|
|
40
|
-
class Expression
|
|
28
|
+
class Expression:
|
|
41
29
|
"""
|
|
42
30
|
Myokit's most generic interface for expressions. All expressions extend
|
|
43
31
|
this class.
|
|
@@ -85,8 +73,8 @@ class Expression(object):
|
|
|
85
73
|
self._cached_unit_tolerant = None
|
|
86
74
|
self._cached_unit_strict = None
|
|
87
75
|
|
|
88
|
-
def __bool__(self):
|
|
89
|
-
|
|
76
|
+
def __bool__(self):
|
|
77
|
+
# Determines the outcome of "if expression".
|
|
90
78
|
return True
|
|
91
79
|
|
|
92
80
|
def bracket(self, op=None):
|
|
@@ -142,7 +130,7 @@ class Expression(object):
|
|
|
142
130
|
"""
|
|
143
131
|
# Note: Because variable and component names can change, the output of
|
|
144
132
|
# code can not be cached (for non-literal expressions).
|
|
145
|
-
b = StringIO()
|
|
133
|
+
b = io.StringIO()
|
|
146
134
|
self._code(b, component)
|
|
147
135
|
return b.getvalue()
|
|
148
136
|
|
|
@@ -540,8 +528,6 @@ class Expression(object):
|
|
|
540
528
|
raise NotImplementedError
|
|
541
529
|
|
|
542
530
|
def __float__(self):
|
|
543
|
-
# Cast to float is required in Python 3: numpy float etc. are ok, but
|
|
544
|
-
# this is deprecated.
|
|
545
531
|
return float(self.eval())
|
|
546
532
|
|
|
547
533
|
def __getitem__(self, key):
|
|
@@ -551,9 +537,7 @@ class Expression(object):
|
|
|
551
537
|
if self._cached_hash is None:
|
|
552
538
|
self._cached_hash = hash(self._polish())
|
|
553
539
|
return self._cached_hash
|
|
554
|
-
# Note
|
|
555
|
-
# In Python3, anything that has an __eq__ stops inheriting this hash
|
|
556
|
-
# method!
|
|
540
|
+
# Note: anything that has an __eq__ stops inheriting this hash method!
|
|
557
541
|
# From: https://docs.python.org/3.1/reference/datamodel.html
|
|
558
542
|
# > If a class that overrides __eq__() needs to retain the
|
|
559
543
|
# implementation of __hash__() from a parent class, the interpreter
|
|
@@ -595,7 +579,7 @@ class Expression(object):
|
|
|
595
579
|
|
|
596
580
|
def is_literal(self):
|
|
597
581
|
"""
|
|
598
|
-
Returns ``True`` if this expression
|
|
582
|
+
Returns ``True`` if this expression does not contain any references.
|
|
599
583
|
"""
|
|
600
584
|
return len(self._references) == 0
|
|
601
585
|
|
|
@@ -608,8 +592,10 @@ class Expression(object):
|
|
|
608
592
|
|
|
609
593
|
def is_number(self, value=None):
|
|
610
594
|
"""
|
|
611
|
-
Returns ``True`` only if this expression is a :class:`myokit.Number
|
|
612
|
-
|
|
595
|
+
Returns ``True`` only if this expression is a :class:`myokit.Number`.
|
|
596
|
+
|
|
597
|
+
If the optional argument ``value`` is set, it will also return
|
|
598
|
+
``False`` if the number does not have the given value.
|
|
613
599
|
"""
|
|
614
600
|
return False
|
|
615
601
|
|
|
@@ -629,10 +615,6 @@ class Expression(object):
|
|
|
629
615
|
def __ne__(self, other):
|
|
630
616
|
return not self.__eq__(other)
|
|
631
617
|
|
|
632
|
-
def __nonzero__(self): # pragma: no python 3 cover
|
|
633
|
-
""" Python 2 method to determine the outcome of "if expression". """
|
|
634
|
-
return True
|
|
635
|
-
|
|
636
618
|
def operator_rep(self):
|
|
637
619
|
"""
|
|
638
620
|
Returns a representation of this expression's type. (For example '+' or
|
|
@@ -651,7 +633,7 @@ class Expression(object):
|
|
|
651
633
|
variable id is immutable in the expression's lifetime.
|
|
652
634
|
"""
|
|
653
635
|
if self._cached_polish is None:
|
|
654
|
-
b = StringIO()
|
|
636
|
+
b = io.StringIO()
|
|
655
637
|
self._polishb(b)
|
|
656
638
|
self._cached_polish = b.getvalue()
|
|
657
639
|
return self._cached_polish
|
|
@@ -668,7 +650,7 @@ class Expression(object):
|
|
|
668
650
|
|
|
669
651
|
def pyfunc(self, use_numpy=True):
|
|
670
652
|
"""
|
|
671
|
-
Converts this expression to
|
|
653
|
+
Converts this expression to Python and returns the new function's
|
|
672
654
|
handle.
|
|
673
655
|
|
|
674
656
|
By default, when converting mathematical functions such as ``log``, the
|
|
@@ -689,19 +671,19 @@ class Expression(object):
|
|
|
689
671
|
# Create function
|
|
690
672
|
local = {}
|
|
691
673
|
if use_numpy:
|
|
692
|
-
|
|
674
|
+
exec(c, {'numpy': numpy}, local)
|
|
693
675
|
else:
|
|
694
|
-
|
|
676
|
+
exec(c, {'math': math}, local)
|
|
695
677
|
|
|
696
678
|
# Return
|
|
697
679
|
return local['ex_pyfunc_generated']
|
|
698
680
|
|
|
699
681
|
def pystr(self, use_numpy=False):
|
|
700
682
|
"""
|
|
701
|
-
Returns a string representing this expression in
|
|
683
|
+
Returns a string representing this expression in Python syntax.
|
|
702
684
|
|
|
703
685
|
By default, built-in functions such as 'exp' are converted to the
|
|
704
|
-
|
|
686
|
+
Python version 'math.exp'. To use the numpy versions, set
|
|
705
687
|
``numpy=True``.
|
|
706
688
|
"""
|
|
707
689
|
# Get expression writer
|
|
@@ -740,7 +722,7 @@ class Expression(object):
|
|
|
740
722
|
Returns a string representing the parse tree corresponding to this
|
|
741
723
|
expression.
|
|
742
724
|
"""
|
|
743
|
-
b = StringIO()
|
|
725
|
+
b = io.StringIO()
|
|
744
726
|
self._tree_str(b, 0)
|
|
745
727
|
return b.getvalue()
|
|
746
728
|
|
|
@@ -853,7 +835,7 @@ class Number(Expression):
|
|
|
853
835
|
_rbp = LITERAL
|
|
854
836
|
|
|
855
837
|
def __init__(self, value, unit=None):
|
|
856
|
-
super(
|
|
838
|
+
super().__init__()
|
|
857
839
|
if isinstance(value, myokit.Quantity):
|
|
858
840
|
# Conversion from Quantity class
|
|
859
841
|
if unit is not None:
|
|
@@ -867,7 +849,7 @@ class Number(Expression):
|
|
|
867
849
|
self._value = float(value) if value else 0.0
|
|
868
850
|
if unit is None or isinstance(unit, myokit.Unit):
|
|
869
851
|
self._unit = unit
|
|
870
|
-
elif isinstance(unit,
|
|
852
|
+
elif isinstance(unit, str):
|
|
871
853
|
self._unit = myokit.parse_unit(unit)
|
|
872
854
|
else:
|
|
873
855
|
raise ValueError(
|
|
@@ -983,7 +965,7 @@ class LhsExpression(Expression):
|
|
|
983
965
|
return self.var().is_constant()
|
|
984
966
|
|
|
985
967
|
def is_literal(self):
|
|
986
|
-
"""See :meth:`Expression.
|
|
968
|
+
"""See :meth:`Expression.is_literal()`."""
|
|
987
969
|
return False
|
|
988
970
|
|
|
989
971
|
def rhs(self):
|
|
@@ -1011,10 +993,10 @@ class Name(LhsExpression):
|
|
|
1011
993
|
*Extends:* :class:`LhsExpression`
|
|
1012
994
|
"""
|
|
1013
995
|
_rbp = LITERAL
|
|
1014
|
-
__hash__ = LhsExpression.__hash__
|
|
996
|
+
__hash__ = LhsExpression.__hash__
|
|
1015
997
|
|
|
1016
998
|
def __init__(self, value):
|
|
1017
|
-
super(
|
|
999
|
+
super().__init__()
|
|
1018
1000
|
self._value = value
|
|
1019
1001
|
self._references = set([self])
|
|
1020
1002
|
self._proper = isinstance(self._value, myokit.Variable)
|
|
@@ -1052,7 +1034,7 @@ class Name(LhsExpression):
|
|
|
1052
1034
|
except KeyError:
|
|
1053
1035
|
pass
|
|
1054
1036
|
b.write(self._value.qname(c))
|
|
1055
|
-
elif isinstance(self._value,
|
|
1037
|
+
elif isinstance(self._value, str):
|
|
1056
1038
|
# Allow strings for debugging
|
|
1057
1039
|
b.write('str:' + str(self._value))
|
|
1058
1040
|
else:
|
|
@@ -1123,7 +1105,7 @@ class Name(LhsExpression):
|
|
|
1123
1105
|
return self._proper and self._value.is_state()
|
|
1124
1106
|
|
|
1125
1107
|
def _polishb(self, b):
|
|
1126
|
-
if isinstance(self._value,
|
|
1108
|
+
if isinstance(self._value, str):
|
|
1127
1109
|
# Allow an exception for strings
|
|
1128
1110
|
b.write('str:')
|
|
1129
1111
|
b.write(self._value)
|
|
@@ -1142,7 +1124,7 @@ class Name(LhsExpression):
|
|
|
1142
1124
|
"""See :meth:`LhsExpression.rhs()`."""
|
|
1143
1125
|
if self._proper:
|
|
1144
1126
|
if self._value.is_state():
|
|
1145
|
-
return
|
|
1127
|
+
return self._value.initial_value()
|
|
1146
1128
|
elif self._value.lhs() == self:
|
|
1147
1129
|
return self._value.rhs()
|
|
1148
1130
|
return None
|
|
@@ -1151,7 +1133,7 @@ class Name(LhsExpression):
|
|
|
1151
1133
|
b.write(' ' * n + str(self._value) + '\n')
|
|
1152
1134
|
|
|
1153
1135
|
def _validate(self, trail):
|
|
1154
|
-
super(
|
|
1136
|
+
super()._validate(trail)
|
|
1155
1137
|
# Check value: String is allowed at construction for debugging, but
|
|
1156
1138
|
# not here!
|
|
1157
1139
|
if not self._proper:
|
|
@@ -1172,10 +1154,10 @@ class Derivative(LhsExpression):
|
|
|
1172
1154
|
"""
|
|
1173
1155
|
_rbp = FUNCTION_CALL
|
|
1174
1156
|
_nargs = [1] # Allows parsing as a function
|
|
1175
|
-
__hash__ = LhsExpression.__hash__
|
|
1157
|
+
__hash__ = LhsExpression.__hash__
|
|
1176
1158
|
|
|
1177
1159
|
def __init__(self, op):
|
|
1178
|
-
super(
|
|
1160
|
+
super().__init__((op,))
|
|
1179
1161
|
if not isinstance(op, Name):
|
|
1180
1162
|
raise IntegrityError(
|
|
1181
1163
|
'The dot() operator can only be used on variables.',
|
|
@@ -1272,7 +1254,7 @@ class Derivative(LhsExpression):
|
|
|
1272
1254
|
return self._op._value
|
|
1273
1255
|
|
|
1274
1256
|
def _validate(self, trail):
|
|
1275
|
-
super(
|
|
1257
|
+
super()._validate(trail)
|
|
1276
1258
|
# Check that value is a variable has already been performed by name
|
|
1277
1259
|
# Check if value is the name of a state variable
|
|
1278
1260
|
if not self._op._value.is_state():
|
|
@@ -1293,7 +1275,7 @@ class PartialDerivative(LhsExpression):
|
|
|
1293
1275
|
"""
|
|
1294
1276
|
_rbp = FUNCTION_CALL
|
|
1295
1277
|
_nargs = [2] # Allows parsing as a function
|
|
1296
|
-
__hash__ = LhsExpression.__hash__
|
|
1278
|
+
__hash__ = LhsExpression.__hash__
|
|
1297
1279
|
|
|
1298
1280
|
def __init__(self, var1, var2):
|
|
1299
1281
|
if not isinstance(var1, (Name, Derivative)):
|
|
@@ -1304,7 +1286,7 @@ class PartialDerivative(LhsExpression):
|
|
|
1304
1286
|
raise IntegrityError(
|
|
1305
1287
|
'The second argument to a partial derivative must be a'
|
|
1306
1288
|
' variable name or an initial value.')
|
|
1307
|
-
super(
|
|
1289
|
+
super().__init__((var1, var2))
|
|
1308
1290
|
|
|
1309
1291
|
self._var1 = var1
|
|
1310
1292
|
self._var2 = var2
|
|
@@ -1390,7 +1372,7 @@ class PartialDerivative(LhsExpression):
|
|
|
1390
1372
|
As with time-derivatives, this returns the variable of which a
|
|
1391
1373
|
derivative is taken (i.e. the dependent variable "y" in "dy/dx").
|
|
1392
1374
|
"""
|
|
1393
|
-
return self._var1.
|
|
1375
|
+
return self._var1.var()
|
|
1394
1376
|
|
|
1395
1377
|
|
|
1396
1378
|
class InitialValue(LhsExpression):
|
|
@@ -1404,13 +1386,13 @@ class InitialValue(LhsExpression):
|
|
|
1404
1386
|
"""
|
|
1405
1387
|
_rbp = FUNCTION_CALL
|
|
1406
1388
|
_nargs = [1] # Allows parsing as a function
|
|
1407
|
-
__hash__ = LhsExpression.__hash__
|
|
1389
|
+
__hash__ = LhsExpression.__hash__
|
|
1408
1390
|
|
|
1409
1391
|
def __init__(self, var):
|
|
1410
|
-
super(
|
|
1392
|
+
super().__init__((var, ))
|
|
1411
1393
|
if not isinstance(var, Name):
|
|
1412
1394
|
raise IntegrityError(
|
|
1413
|
-
'The first argument to an initial
|
|
1395
|
+
'The first argument to an initial value must be a variable'
|
|
1414
1396
|
' name.', self._token)
|
|
1415
1397
|
|
|
1416
1398
|
self._var = var
|
|
@@ -1436,7 +1418,7 @@ class InitialValue(LhsExpression):
|
|
|
1436
1418
|
|
|
1437
1419
|
def _diff(self, lhs, idstates):
|
|
1438
1420
|
raise NotImplementedError(
|
|
1439
|
-
'Partial derivatives of initial
|
|
1421
|
+
'Partial derivatives of initial values are not supported.')
|
|
1440
1422
|
|
|
1441
1423
|
def _eval_unit(self, mode):
|
|
1442
1424
|
return self._var._eval_unit(mode)
|
|
@@ -1453,7 +1435,7 @@ class InitialValue(LhsExpression):
|
|
|
1453
1435
|
See :meth:`LhsExpression.rhs()`.
|
|
1454
1436
|
|
|
1455
1437
|
The RHS returned in this case will be ``None``, as there is no RHS
|
|
1456
|
-
associated with initial
|
|
1438
|
+
associated with initial values in the model.
|
|
1457
1439
|
"""
|
|
1458
1440
|
# Note: This _could_ return a Number(init, var unit) instead...
|
|
1459
1441
|
return None
|
|
@@ -1466,12 +1448,12 @@ class InitialValue(LhsExpression):
|
|
|
1466
1448
|
return self._var._value
|
|
1467
1449
|
|
|
1468
1450
|
def _validate(self, trail):
|
|
1469
|
-
super(
|
|
1451
|
+
super()._validate(trail)
|
|
1470
1452
|
# Check if value is the name of a state variable
|
|
1471
1453
|
var = self._var._value
|
|
1472
1454
|
if not (isinstance(var, myokit.Variable) and var.is_state()):
|
|
1473
1455
|
raise IntegrityError(
|
|
1474
|
-
'Initial
|
|
1456
|
+
'Initial values can only be defined for state variables.',
|
|
1475
1457
|
self._token)
|
|
1476
1458
|
|
|
1477
1459
|
|
|
@@ -1485,7 +1467,7 @@ class PrefixExpression(Expression):
|
|
|
1485
1467
|
_rep = None
|
|
1486
1468
|
|
|
1487
1469
|
def __init__(self, op):
|
|
1488
|
-
super(
|
|
1470
|
+
super().__init__((op,))
|
|
1489
1471
|
self._op = op
|
|
1490
1472
|
|
|
1491
1473
|
def bracket(self, op):
|
|
@@ -1584,7 +1566,7 @@ class InfixExpression(Expression):
|
|
|
1584
1566
|
_spaces_round_operator = True
|
|
1585
1567
|
|
|
1586
1568
|
def __init__(self, left, right):
|
|
1587
|
-
super(
|
|
1569
|
+
super().__init__((left, right))
|
|
1588
1570
|
self._op1 = left
|
|
1589
1571
|
self._op2 = right
|
|
1590
1572
|
|
|
@@ -1878,7 +1860,7 @@ class Quotient(InfixExpression):
|
|
|
1878
1860
|
#
|
|
1879
1861
|
# Alternatively, a // b = floor(a / b).
|
|
1880
1862
|
#
|
|
1881
|
-
# Here we ignore the discontinuities in
|
|
1863
|
+
# Here we ignore the discontinuities in favor of a left or right
|
|
1882
1864
|
# derivative, and simply return zero for all points.
|
|
1883
1865
|
return None
|
|
1884
1866
|
|
|
@@ -2087,7 +2069,7 @@ class Function(Expression):
|
|
|
2087
2069
|
_rbp = FUNCTION_CALL
|
|
2088
2070
|
|
|
2089
2071
|
def __init__(self, *ops):
|
|
2090
|
-
super(
|
|
2072
|
+
super().__init__(ops)
|
|
2091
2073
|
if self._nargs is not None:
|
|
2092
2074
|
if not len(ops) in self._nargs:
|
|
2093
2075
|
raise IntegrityError(
|
|
@@ -2658,7 +2640,7 @@ class If(Function):
|
|
|
2658
2640
|
_fname = 'if'
|
|
2659
2641
|
|
|
2660
2642
|
def __init__(self, i, t, e):
|
|
2661
|
-
super(
|
|
2643
|
+
super().__init__(i, t, e)
|
|
2662
2644
|
self._i = i # if
|
|
2663
2645
|
self._t = t # then
|
|
2664
2646
|
self._e = e # else
|
|
@@ -2764,7 +2746,7 @@ class Piecewise(Function):
|
|
|
2764
2746
|
_fname = 'piecewise'
|
|
2765
2747
|
|
|
2766
2748
|
def __init__(self, *ops):
|
|
2767
|
-
super(
|
|
2749
|
+
super().__init__(*ops)
|
|
2768
2750
|
|
|
2769
2751
|
# Check number of arguments
|
|
2770
2752
|
n = len(self._operands)
|
|
@@ -2852,7 +2834,7 @@ class Piecewise(Function):
|
|
|
2852
2834
|
return iter(self._e)
|
|
2853
2835
|
|
|
2854
2836
|
|
|
2855
|
-
class Condition
|
|
2837
|
+
class Condition:
|
|
2856
2838
|
"""
|
|
2857
2839
|
*Abstract class*
|
|
2858
2840
|
|
|
@@ -2866,7 +2848,7 @@ class Condition(object):
|
|
|
2866
2848
|
'Conditions do not have partial derivatives.')
|
|
2867
2849
|
|
|
2868
2850
|
|
|
2869
|
-
class PrefixCondition(
|
|
2851
|
+
class PrefixCondition(PrefixExpression, Condition):
|
|
2870
2852
|
"""
|
|
2871
2853
|
Interface for prefix conditions.
|
|
2872
2854
|
|
|
@@ -2920,7 +2902,7 @@ class Not(PrefixCondition):
|
|
|
2920
2902
|
self._op._polishb(b)
|
|
2921
2903
|
|
|
2922
2904
|
|
|
2923
|
-
class InfixCondition(
|
|
2905
|
+
class InfixCondition(InfixExpression, Condition):
|
|
2924
2906
|
"""
|
|
2925
2907
|
Base class for infix expressions.
|
|
2926
2908
|
|
myokit/_io.py
CHANGED
|
@@ -6,19 +6,11 @@
|
|
|
6
6
|
# This file is part of Myokit.
|
|
7
7
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
8
8
|
#
|
|
9
|
-
from __future__ import absolute_import, division
|
|
10
|
-
from __future__ import print_function, unicode_literals
|
|
11
|
-
|
|
12
9
|
import array
|
|
10
|
+
import io
|
|
13
11
|
import os
|
|
14
12
|
import sys
|
|
15
13
|
|
|
16
|
-
# StringIO in Python 2 and 3
|
|
17
|
-
try:
|
|
18
|
-
from cStringIO import StringIO
|
|
19
|
-
except ImportError: # pragma: no python 2 cover
|
|
20
|
-
from io import StringIO
|
|
21
|
-
|
|
22
14
|
import myokit
|
|
23
15
|
|
|
24
16
|
|
|
@@ -93,7 +85,7 @@ def load_script(filename):
|
|
|
93
85
|
|
|
94
86
|
def load_state(filename, model=None):
|
|
95
87
|
"""
|
|
96
|
-
Loads
|
|
88
|
+
Loads a model state from a file in one of the formats specified by
|
|
97
89
|
:func:`myokit.parse_state()`.
|
|
98
90
|
|
|
99
91
|
If a :class:`Model` is provided the state will be run through
|
|
@@ -110,7 +102,8 @@ def load_state(filename, model=None):
|
|
|
110
102
|
|
|
111
103
|
def load_state_bin(filename):
|
|
112
104
|
"""
|
|
113
|
-
Loads
|
|
105
|
+
Loads a model state from a file in the binary format used by Myokit.
|
|
106
|
+
|
|
114
107
|
See :meth:`save_state_bin` for details.
|
|
115
108
|
"""
|
|
116
109
|
filename = os.path.expanduser(filename)
|
|
@@ -144,8 +137,6 @@ def load_state_bin(filename):
|
|
|
144
137
|
code = parts[1]
|
|
145
138
|
if code not in ['d', 'f']: # pragma: no cover
|
|
146
139
|
raise Exception('Invalid state file format [40].')
|
|
147
|
-
# Convert code to str for Python 2.7.10 (see #225)
|
|
148
|
-
code = str(code)
|
|
149
140
|
|
|
150
141
|
size = int(parts[2])
|
|
151
142
|
if size < 0: # pragma: no cover
|
|
@@ -153,10 +144,7 @@ def load_state_bin(filename):
|
|
|
153
144
|
|
|
154
145
|
# Create array, read bytes into array
|
|
155
146
|
ar = array.array(code)
|
|
156
|
-
|
|
157
|
-
ar.frombytes(f.read(info))
|
|
158
|
-
except AttributeError: # pragma: no python 3 cover
|
|
159
|
-
ar.fromstring(f.read(info))
|
|
147
|
+
ar.frombytes(f.read(info))
|
|
160
148
|
|
|
161
149
|
# Always store as little endian
|
|
162
150
|
if sys.byteorder == 'big': # pragma: no cover
|
|
@@ -175,11 +163,15 @@ def save(filename=None, model=None, protocol=None, script=None):
|
|
|
175
163
|
|
|
176
164
|
If no filename is given the ``mmt`` code is returned as a string.
|
|
177
165
|
"""
|
|
166
|
+
if model is None and protocol is None and script is None:
|
|
167
|
+
raise ValueError(
|
|
168
|
+
'At least one of [model, protocol, script] must not be None.')
|
|
169
|
+
|
|
178
170
|
if filename:
|
|
179
171
|
filename = os.path.expanduser(filename)
|
|
180
172
|
f = open(filename, 'w')
|
|
181
173
|
else:
|
|
182
|
-
f = StringIO()
|
|
174
|
+
f = io.StringIO()
|
|
183
175
|
out = None
|
|
184
176
|
try:
|
|
185
177
|
if model is not None:
|
|
@@ -244,7 +236,7 @@ def save_script(filename, script):
|
|
|
244
236
|
|
|
245
237
|
def save_state(filename, state, model=None):
|
|
246
238
|
"""
|
|
247
|
-
Stores
|
|
239
|
+
Stores a model state to the path ``filename``.
|
|
248
240
|
|
|
249
241
|
If no ``model`` is specified ``state`` should be given as a list of
|
|
250
242
|
floating point numbers and will be stored by simply placing each number on
|
|
@@ -272,8 +264,8 @@ def save_state(filename, state, model=None):
|
|
|
272
264
|
|
|
273
265
|
def save_state_bin(filename, state, precision=myokit.DOUBLE_PRECISION):
|
|
274
266
|
"""
|
|
275
|
-
Stores
|
|
276
|
-
|
|
267
|
+
Stores a model state (or any given list of floating point numbers) to the
|
|
268
|
+
path ``filename``, using a binary format.
|
|
277
269
|
|
|
278
270
|
The used format is a zip file, containing a single entry: ``state_x_y``,
|
|
279
271
|
where ``x`` is the used data type (``d`` or ``f``) and ``y`` is the number
|
|
@@ -292,8 +284,7 @@ def save_state_bin(filename, state, precision=myokit.DOUBLE_PRECISION):
|
|
|
292
284
|
'This method requires the `zlib` module to be installed.')
|
|
293
285
|
|
|
294
286
|
# Data type
|
|
295
|
-
|
|
296
|
-
code = str('d' if precision == myokit.DOUBLE_PRECISION else 'f')
|
|
287
|
+
code = 'd' if precision == myokit.DOUBLE_PRECISION else 'f'
|
|
297
288
|
|
|
298
289
|
# Create array, ensure it's little-endian
|
|
299
290
|
ar = array.array(code, state)
|
|
@@ -306,10 +297,7 @@ def save_state_bin(filename, state, precision=myokit.DOUBLE_PRECISION):
|
|
|
306
297
|
info.compress_type = zipfile.ZIP_DEFLATED
|
|
307
298
|
|
|
308
299
|
# Write to compressed file
|
|
309
|
-
|
|
310
|
-
ar = ar.tobytes()
|
|
311
|
-
except AttributeError: # pragma: no python 3 cover
|
|
312
|
-
ar = ar.tostring()
|
|
300
|
+
ar = ar.tobytes()
|
|
313
301
|
with zipfile.ZipFile(filename, 'w') as f:
|
|
314
302
|
f.writestr(info, ar)
|
|
315
303
|
|