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/_myokit_version.py
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
# This file is part of Myokit.
|
|
5
5
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
6
6
|
#
|
|
7
|
-
import sys
|
|
8
7
|
|
|
9
8
|
# True if this is a release, False for a development version
|
|
10
9
|
__release__ = True
|
|
@@ -15,7 +14,7 @@ __release__ = True
|
|
|
15
14
|
# incompatibility
|
|
16
15
|
# - Changes to revision indicate bugfixes, tiny new features
|
|
17
16
|
# - There is no significance to odd/even numbers
|
|
18
|
-
__version_tuple__ = 1,
|
|
17
|
+
__version_tuple__ = 1, 35, 0
|
|
19
18
|
|
|
20
19
|
# String version of the version number
|
|
21
20
|
__version__ = '.'.join([str(x) for x in __version_tuple__])
|
|
@@ -23,6 +22,3 @@ if not __release__: # pragma: no cover
|
|
|
23
22
|
__version_tuple__ += ('dev', )
|
|
24
23
|
__version__ += '.dev'
|
|
25
24
|
|
|
26
|
-
# Don't expose x on Python2
|
|
27
|
-
if sys.hexversion < 0x03000000: # pragma: no python 3 cover
|
|
28
|
-
del x
|
myokit/_parsing.py
CHANGED
|
@@ -4,22 +4,14 @@
|
|
|
4
4
|
# This file is part of Myokit.
|
|
5
5
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
6
6
|
#
|
|
7
|
-
from __future__ import absolute_import, division
|
|
8
|
-
from __future__ import print_function, unicode_literals
|
|
9
|
-
|
|
10
7
|
import os
|
|
11
8
|
import re
|
|
12
|
-
|
|
9
|
+
|
|
13
10
|
from collections import OrderedDict
|
|
14
11
|
|
|
15
12
|
import myokit
|
|
16
|
-
from myokit import ParseError, ProtocolParseError
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
try:
|
|
20
|
-
basestring
|
|
21
|
-
except NameError: # pragma: no cover
|
|
22
|
-
basestring = str
|
|
14
|
+
from myokit import ParseError, ProtocolParseError
|
|
23
15
|
|
|
24
16
|
|
|
25
17
|
def parse(source):
|
|
@@ -34,7 +26,7 @@ def parse(source):
|
|
|
34
26
|
"""
|
|
35
27
|
# Get raw stream
|
|
36
28
|
raw = source
|
|
37
|
-
if isinstance(raw,
|
|
29
|
+
if isinstance(raw, str):
|
|
38
30
|
raw = raw.splitlines()
|
|
39
31
|
raw = iter(raw)
|
|
40
32
|
|
|
@@ -78,7 +70,7 @@ def parse_model(source):
|
|
|
78
70
|
"""
|
|
79
71
|
# Get raw stream
|
|
80
72
|
raw = source
|
|
81
|
-
if isinstance(raw,
|
|
73
|
+
if isinstance(raw, str):
|
|
82
74
|
raw = raw.splitlines()
|
|
83
75
|
raw = iter(raw)
|
|
84
76
|
|
|
@@ -100,7 +92,7 @@ def parse_protocol(source):
|
|
|
100
92
|
"""
|
|
101
93
|
# Get raw stream
|
|
102
94
|
raw = source
|
|
103
|
-
if isinstance(raw,
|
|
95
|
+
if isinstance(raw, str):
|
|
104
96
|
raw = raw.splitlines()
|
|
105
97
|
raw = iter(raw)
|
|
106
98
|
|
|
@@ -122,7 +114,7 @@ def parse_script(source):
|
|
|
122
114
|
"""
|
|
123
115
|
# Get raw stream
|
|
124
116
|
raw = source
|
|
125
|
-
if isinstance(raw,
|
|
117
|
+
if isinstance(raw, str):
|
|
126
118
|
raw = raw.splitlines()
|
|
127
119
|
raw = iter(raw)
|
|
128
120
|
|
|
@@ -162,7 +154,7 @@ def parse_state(state):
|
|
|
162
154
|
"""
|
|
163
155
|
# Get raw stream
|
|
164
156
|
raw = state
|
|
165
|
-
if isinstance(raw,
|
|
157
|
+
if isinstance(raw, str):
|
|
166
158
|
raw = raw.splitlines()
|
|
167
159
|
raw = iter(raw)
|
|
168
160
|
|
|
@@ -205,7 +197,7 @@ def split(source):
|
|
|
205
197
|
"""
|
|
206
198
|
# Get raw stream
|
|
207
199
|
raw = source
|
|
208
|
-
if isinstance(raw,
|
|
200
|
+
if isinstance(raw, str):
|
|
209
201
|
raw = raw.splitlines()
|
|
210
202
|
raw = iter(raw)
|
|
211
203
|
segments = ['', '', '']
|
|
@@ -317,7 +309,7 @@ def unexpected_token(token, expected):
|
|
|
317
309
|
# Parse expected token(s) or string
|
|
318
310
|
if type(expected) == int:
|
|
319
311
|
expected = [expected]
|
|
320
|
-
if not isinstance(expected,
|
|
312
|
+
if not isinstance(expected, str):
|
|
321
313
|
if len(expected) > 2:
|
|
322
314
|
expected = 'one of [' \
|
|
323
315
|
+ ', '.join([token_str[i] for i in expected]) + ']'
|
|
@@ -348,10 +340,11 @@ def reg_token(info, token, obj):
|
|
|
348
340
|
d[token[3]] = (token, obj)
|
|
349
341
|
|
|
350
342
|
|
|
351
|
-
class ParseInfo
|
|
343
|
+
class ParseInfo:
|
|
352
344
|
def __init__(self):
|
|
353
345
|
self.model = None
|
|
354
346
|
self.initial_values = OrderedDict()
|
|
347
|
+
self.initial_value_tokens = {}
|
|
355
348
|
self.alias_map = {}
|
|
356
349
|
self.user_functions = {}
|
|
357
350
|
|
|
@@ -420,10 +413,10 @@ def parse_model_from_stream(stream, syntax_only=False):
|
|
|
420
413
|
'Duplicate initial value', t0[2], t0[3],
|
|
421
414
|
'A value for <' + name + '> was already specified.')
|
|
422
415
|
expect(next(stream), EQUAL)
|
|
423
|
-
expr =
|
|
416
|
+
expr = parse_proto_expression(stream)
|
|
424
417
|
expect(next(stream), EOL)
|
|
425
418
|
info.initial_values[name] = expr
|
|
426
|
-
|
|
419
|
+
info.initial_value_tokens[name] = t0
|
|
427
420
|
|
|
428
421
|
token = stream.peek()
|
|
429
422
|
|
|
@@ -439,15 +432,6 @@ def parse_model_from_stream(stream, syntax_only=False):
|
|
|
439
432
|
if syntax_only:
|
|
440
433
|
return True
|
|
441
434
|
|
|
442
|
-
# All initial variables must have been used
|
|
443
|
-
for qname, e in info.initial_values.items():
|
|
444
|
-
raise ParseError(
|
|
445
|
-
'Unused initial value', 0, 0,
|
|
446
|
-
'An unused initial value was found for "' + str(qname) + '".')
|
|
447
|
-
|
|
448
|
-
# Re-order the model state
|
|
449
|
-
model.reorder_state(state_order)
|
|
450
|
-
|
|
451
435
|
# Order encountered tokens
|
|
452
436
|
m = model._tokens
|
|
453
437
|
model._tokens = {}
|
|
@@ -468,6 +452,23 @@ def parse_model_from_stream(stream, syntax_only=False):
|
|
|
468
452
|
var.set_rhs(convert_proto_expression(var._proto_rhs, var, info))
|
|
469
453
|
del var._proto_rhs
|
|
470
454
|
|
|
455
|
+
# Resolve variable references in initial values
|
|
456
|
+
for i, var in enumerate(model.states()):
|
|
457
|
+
e = info.initial_values[var.qname()]
|
|
458
|
+
expr = convert_proto_expression(e, model, info)
|
|
459
|
+
var.set_initial_value(expr)
|
|
460
|
+
del info.initial_values[var.qname()]
|
|
461
|
+
|
|
462
|
+
# All initial variables must have been used
|
|
463
|
+
for qname, e in info.initial_values.items():
|
|
464
|
+
t = info.initial_value_tokens[qname]
|
|
465
|
+
raise ParseError(
|
|
466
|
+
'Unused initial value', t[2], t[3],
|
|
467
|
+
'An unused initial value was found for "' + qname + '".')
|
|
468
|
+
|
|
469
|
+
# Re-order the model state
|
|
470
|
+
model.reorder_state(state_order)
|
|
471
|
+
|
|
471
472
|
# Check the semantics of the model
|
|
472
473
|
try:
|
|
473
474
|
model.validate()
|
|
@@ -675,14 +676,7 @@ def parse_variable(stream, info, parent):
|
|
|
675
676
|
raise ParseError(
|
|
676
677
|
'Missing initial value', line, char,
|
|
677
678
|
'No initial value was found for "' + var.qname() + '"')
|
|
678
|
-
|
|
679
|
-
try:
|
|
680
|
-
var.promote(state_value)
|
|
681
|
-
except myokit.NonLiteralValueError as e:
|
|
682
|
-
t = state_value._token
|
|
683
|
-
raise ParseError(
|
|
684
|
-
'Illegal state value', t[2], t[3], str(e), cause=e)
|
|
685
|
-
del info.initial_values[var.qname()]
|
|
679
|
+
var.promote()
|
|
686
680
|
|
|
687
681
|
# Parse definition, quick unit, bind, label and description syntax
|
|
688
682
|
# These token must occur in a fixed order!
|
|
@@ -1069,7 +1063,7 @@ def strip_expression_units(model_text, skip_literals=True):
|
|
|
1069
1063
|
This method will raise a :class:`myokit.ParseError` if the given code
|
|
1070
1064
|
cannot be parsed to a valid model.
|
|
1071
1065
|
"""
|
|
1072
|
-
if isinstance(model_text,
|
|
1066
|
+
if isinstance(model_text, str):
|
|
1073
1067
|
lines = model_text.splitlines()
|
|
1074
1068
|
else:
|
|
1075
1069
|
lines = model_text
|
|
@@ -1265,7 +1259,7 @@ _COMPEQ = '=!><'
|
|
|
1265
1259
|
_COMPEQ_MAP = [EQEQUAL, NOTEQUAL, MOREEQUAL, LESSEQUAL]
|
|
1266
1260
|
|
|
1267
1261
|
|
|
1268
|
-
class Tokenizer
|
|
1262
|
+
class Tokenizer:
|
|
1269
1263
|
"""
|
|
1270
1264
|
Takes a stream of lines as input and provides a stream interface returning
|
|
1271
1265
|
tokens.
|
|
@@ -1310,7 +1304,7 @@ class Tokenizer(object):
|
|
|
1310
1304
|
self._catcheri = 0
|
|
1311
1305
|
|
|
1312
1306
|
# String given instead of stream of lines? Convert
|
|
1313
|
-
if isinstance(stream_of_lines,
|
|
1307
|
+
if isinstance(stream_of_lines, str):
|
|
1314
1308
|
stream_of_lines = iter(stream_of_lines.splitlines())
|
|
1315
1309
|
|
|
1316
1310
|
# Create tokenizer
|
|
@@ -1963,7 +1957,7 @@ def format_parse_error(ex, source=None):
|
|
|
1963
1957
|
line = None
|
|
1964
1958
|
|
|
1965
1959
|
if ex.line > 0 and source is not None:
|
|
1966
|
-
if isinstance(source,
|
|
1960
|
+
if isinstance(source, str) and os.path.isfile(source):
|
|
1967
1961
|
# Re-open file, find line
|
|
1968
1962
|
with open(source, 'r') as f:
|
|
1969
1963
|
for i in range(0, ex.line):
|
|
@@ -2013,7 +2007,7 @@ def format_parse_error(ex, source=None):
|
|
|
2013
2007
|
return '\n'.join(out)
|
|
2014
2008
|
|
|
2015
2009
|
|
|
2016
|
-
class NudParser
|
|
2010
|
+
class NudParser:
|
|
2017
2011
|
"""
|
|
2018
2012
|
Expression parser for nud operators.
|
|
2019
2013
|
|
|
@@ -2082,7 +2076,7 @@ class FunctionParser(NudParser):
|
|
|
2082
2076
|
Parser for function calls.
|
|
2083
2077
|
"""
|
|
2084
2078
|
def __init__(self):
|
|
2085
|
-
super(
|
|
2079
|
+
super().__init__()
|
|
2086
2080
|
self._rbp = myokit.Function._rbp
|
|
2087
2081
|
|
|
2088
2082
|
def parse(self, stream, info):
|
|
@@ -2123,7 +2117,7 @@ class FunctionParser(NudParser):
|
|
|
2123
2117
|
return (func, ops, (name,))
|
|
2124
2118
|
|
|
2125
2119
|
|
|
2126
|
-
class LedParser
|
|
2120
|
+
class LedParser:
|
|
2127
2121
|
"""
|
|
2128
2122
|
Expression parser for led operators.
|
|
2129
2123
|
|
myokit/_progress.py
CHANGED
|
@@ -4,15 +4,12 @@
|
|
|
4
4
|
# This file is part of Myokit.
|
|
5
5
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
6
6
|
#
|
|
7
|
-
from __future__ import absolute_import, division
|
|
8
|
-
from __future__ import print_function, unicode_literals
|
|
9
|
-
|
|
10
7
|
import timeit
|
|
11
8
|
|
|
12
9
|
import myokit
|
|
13
10
|
|
|
14
11
|
|
|
15
|
-
class ProgressReporter
|
|
12
|
+
class ProgressReporter:
|
|
16
13
|
"""
|
|
17
14
|
Interface for progress updates in Simulations. Also allows some job types
|
|
18
15
|
to be cancelled by the user.
|
|
@@ -21,7 +18,7 @@ class ProgressReporter(object):
|
|
|
21
18
|
pass in an object implementing this interface. The simulation will use this
|
|
22
19
|
object to report on its progress.
|
|
23
20
|
|
|
24
|
-
Note that progress reporters should be re-usable, but the
|
|
21
|
+
Note that progress reporters should be re-usable, but the behavior when
|
|
25
22
|
making calls to a reporter from two different processes (either through
|
|
26
23
|
multi-threading/multi-processing or jobs nested within jobs) is undefined.
|
|
27
24
|
|
|
@@ -62,7 +59,7 @@ class ProgressReporter(object):
|
|
|
62
59
|
"""
|
|
63
60
|
pass
|
|
64
61
|
|
|
65
|
-
class _Job
|
|
62
|
+
class _Job:
|
|
66
63
|
def __init__(self, parent, msg):
|
|
67
64
|
self._parent = parent
|
|
68
65
|
self._msg = msg
|
|
@@ -97,7 +94,7 @@ class ProgressPrinter(ProgressReporter):
|
|
|
97
94
|
status every ten percent.
|
|
98
95
|
"""
|
|
99
96
|
def __init__(self, digits=1):
|
|
100
|
-
super(
|
|
97
|
+
super().__init__()
|
|
101
98
|
self._b = myokit.tools.Benchmarker()
|
|
102
99
|
self._f = None
|
|
103
100
|
self._d = int(digits)
|
|
@@ -138,7 +135,7 @@ class Timeout(ProgressReporter):
|
|
|
138
135
|
Progress reporter that cancels a simulation after ``timeout`` seconds.
|
|
139
136
|
"""
|
|
140
137
|
def __init__(self, timeout):
|
|
141
|
-
super(
|
|
138
|
+
super().__init__()
|
|
142
139
|
self._timeout = float(timeout)
|
|
143
140
|
|
|
144
141
|
def enter(self, msg=None):
|
myokit/_protocol.py
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Defines the python classes that represent
|
|
2
|
+
# Defines the python classes that represent pacing protocols.
|
|
3
3
|
#
|
|
4
4
|
# This file is part of Myokit.
|
|
5
5
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
6
6
|
#
|
|
7
|
-
from __future__ import absolute_import, division
|
|
8
|
-
from __future__ import print_function, unicode_literals
|
|
9
|
-
|
|
10
7
|
import myokit
|
|
11
8
|
|
|
12
9
|
import numpy as np
|
|
13
10
|
|
|
11
|
+
from bisect import bisect_right
|
|
12
|
+
|
|
14
13
|
|
|
15
|
-
class Protocol
|
|
14
|
+
class Protocol:
|
|
16
15
|
"""
|
|
17
16
|
Represents a pacing protocol as a sequence of :class:`events
|
|
18
17
|
<ProtocolEvent>`.
|
|
@@ -43,11 +42,11 @@ class Protocol(object):
|
|
|
43
42
|
is not.
|
|
44
43
|
|
|
45
44
|
Protocols can be compared with ``==``, which will check if the :meth:`code`
|
|
46
|
-
for both protocols is the same. Protocols can be
|
|
45
|
+
for both protocols is the same. Protocols can be serialized with
|
|
47
46
|
``pickle``.
|
|
48
47
|
"""
|
|
49
48
|
def __init__(self):
|
|
50
|
-
super(
|
|
49
|
+
super().__init__()
|
|
51
50
|
self._head = None
|
|
52
51
|
|
|
53
52
|
def add(self, e):
|
|
@@ -534,7 +533,7 @@ class Protocol(object):
|
|
|
534
533
|
return [p.advance(t) for t in times]
|
|
535
534
|
|
|
536
535
|
|
|
537
|
-
class ProtocolEvent
|
|
536
|
+
class ProtocolEvent:
|
|
538
537
|
"""
|
|
539
538
|
Describes an event occurring as part of a protocol.
|
|
540
539
|
"""
|
|
@@ -717,7 +716,7 @@ class ProtocolEvent(object):
|
|
|
717
716
|
return self.in_words()
|
|
718
717
|
|
|
719
718
|
|
|
720
|
-
class PacingSystem
|
|
719
|
+
class PacingSystem:
|
|
721
720
|
"""
|
|
722
721
|
This class uses a :class:`myokit.Protocol` to update the value of a
|
|
723
722
|
pacing variable over time.
|
|
@@ -850,3 +849,94 @@ class NotAnUnbrokenSequenceError(myokit.MyokitError):
|
|
|
850
849
|
""" Error raised exclusively by is_unbroken_sequence_exception(). """
|
|
851
850
|
pass
|
|
852
851
|
|
|
852
|
+
|
|
853
|
+
class TimeSeriesProtocol:
|
|
854
|
+
"""
|
|
855
|
+
Represents a pacing protocol as a sequence of time value pairs and an
|
|
856
|
+
interpolation method (currently only linear interpolation is supported).
|
|
857
|
+
|
|
858
|
+
A 1D time-series should be given as input. During the simulation, the value
|
|
859
|
+
of the pacing variable will be determined by interpolating between the two
|
|
860
|
+
nearest points in the series. If the simulation time is outside the bounds
|
|
861
|
+
of the time-series, the first or last value in the series will be used.
|
|
862
|
+
|
|
863
|
+
Protocols can be compared with ``==``, which will check if the sequence of
|
|
864
|
+
time value pairs is the same, and the interpolation method is the same.
|
|
865
|
+
Protocols can be serialized with ``pickle``.
|
|
866
|
+
|
|
867
|
+
"""
|
|
868
|
+
|
|
869
|
+
def __init__(self, times, values, method=None):
|
|
870
|
+
super().__init__()
|
|
871
|
+
|
|
872
|
+
if len(times) != len(values):
|
|
873
|
+
raise ValueError('Times and values array must have same size.')
|
|
874
|
+
times_tpl, values_tpl = zip(*[
|
|
875
|
+
(float(t), float(v)) for t, v in sorted(zip(times, values))
|
|
876
|
+
])
|
|
877
|
+
self._times = list(times_tpl)
|
|
878
|
+
self._values = list(values_tpl)
|
|
879
|
+
|
|
880
|
+
if method is None:
|
|
881
|
+
self._method = 'linear'
|
|
882
|
+
else:
|
|
883
|
+
self._method = str(method).lower()
|
|
884
|
+
if self._method not in ('linear', ):
|
|
885
|
+
raise ValueError(
|
|
886
|
+
'Unknown interpolation method: ' + self._method)
|
|
887
|
+
|
|
888
|
+
def __eq__(self, other):
|
|
889
|
+
if self is other:
|
|
890
|
+
return True
|
|
891
|
+
if not isinstance(other, TimeSeriesProtocol):
|
|
892
|
+
return False
|
|
893
|
+
return (
|
|
894
|
+
self._method == other._method
|
|
895
|
+
and self._values == other._values
|
|
896
|
+
and self._times == other._times
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
def __getstate__(self):
|
|
900
|
+
return {
|
|
901
|
+
'times': self._times,
|
|
902
|
+
'values': self._values,
|
|
903
|
+
'method': self._method,
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
def __setstate__(self, values):
|
|
907
|
+
self._times = values['times']
|
|
908
|
+
self._values = values['values']
|
|
909
|
+
self._method = values['method']
|
|
910
|
+
|
|
911
|
+
def clone(self):
|
|
912
|
+
"""
|
|
913
|
+
Returns a clone of this protocol.
|
|
914
|
+
"""
|
|
915
|
+
return TimeSeriesProtocol(self._times, self._values, self._method)
|
|
916
|
+
|
|
917
|
+
def pace(self, t):
|
|
918
|
+
"""
|
|
919
|
+
Returns the value of the pacing variable at time ``t``.
|
|
920
|
+
"""
|
|
921
|
+
if t < self._times[0]:
|
|
922
|
+
return self._values[0]
|
|
923
|
+
if t > self._times[-1]:
|
|
924
|
+
return self._values[-1]
|
|
925
|
+
i = bisect_right(self._times, t) - 1
|
|
926
|
+
if i == len(self._times) - 1:
|
|
927
|
+
return self._values[i]
|
|
928
|
+
return self._values[i] + (t - self._times[i]) * (
|
|
929
|
+
self._values[i + 1] - self._values[i]
|
|
930
|
+
) / (self._times[i + 1] - self._times[i])
|
|
931
|
+
|
|
932
|
+
def times(self):
|
|
933
|
+
"""
|
|
934
|
+
Returns a list of the times in this protocol.
|
|
935
|
+
"""
|
|
936
|
+
return self._times
|
|
937
|
+
|
|
938
|
+
def values(self):
|
|
939
|
+
"""
|
|
940
|
+
Returns a list of the values in this protocol.
|
|
941
|
+
"""
|
|
942
|
+
return self._values
|
myokit/_sim/__init__.py
CHANGED
|
@@ -5,10 +5,6 @@
|
|
|
5
5
|
# This file is part of Myokit.
|
|
6
6
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
7
|
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
|
-
# Library imports
|
|
12
8
|
import os
|
|
13
9
|
import platform
|
|
14
10
|
import sys
|
|
@@ -36,36 +32,23 @@ if platform.system() == 'Windows': # pragma: no linux cover
|
|
|
36
32
|
).stdin
|
|
37
33
|
os.popen = _ospop
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
# Setuptools imports
|
|
41
35
|
from setuptools import setup, Extension # noqa
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
# Myokit imports
|
|
45
37
|
import myokit # noqa
|
|
46
38
|
import myokit.pype # noqa
|
|
47
39
|
|
|
48
40
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
import importlib.machinery
|
|
41
|
+
def load_module(name, path):
|
|
42
|
+
""" Dynamically find and load a module (Python 3.5+). """
|
|
52
43
|
import importlib
|
|
44
|
+
import importlib.machinery
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return module
|
|
58
|
-
|
|
59
|
-
else: # pragma: no python 3 cover
|
|
60
|
-
import imp
|
|
61
|
-
|
|
62
|
-
def load_module(name, path):
|
|
63
|
-
(f, pathname, description) = imp.find_module(name, [path])
|
|
64
|
-
f.close()
|
|
65
|
-
return imp.load_dynamic(name, pathname)
|
|
46
|
+
spec = importlib.machinery.PathFinder.find_spec(name, [path])
|
|
47
|
+
module = importlib.util.module_from_spec(spec)
|
|
48
|
+
return module
|
|
66
49
|
|
|
67
50
|
|
|
68
|
-
class CModule
|
|
51
|
+
class CModule:
|
|
69
52
|
"""
|
|
70
53
|
Abstract base class for classes that dynamically create and compile a
|
|
71
54
|
back-end C-module.
|
myokit/_sim/cable.c
CHANGED
|
@@ -26,11 +26,11 @@ model.create_unique_names()
|
|
|
26
26
|
w = ansic.AnsiCExpressionWriter()
|
|
27
27
|
|
|
28
28
|
# Process bindings, remove unsupported bindings.
|
|
29
|
-
bound_variables =
|
|
29
|
+
bound_variables = myokit._prepare_bindings(model, {
|
|
30
30
|
'time' : 'engine_time',
|
|
31
31
|
'pace' : 'engine_pace',
|
|
32
32
|
'diffusion_current' : 'diffusion_current',
|
|
33
|
-
|
|
33
|
+
})
|
|
34
34
|
|
|
35
35
|
# Define var/lhs function
|
|
36
36
|
def v(var, pre='cell->'):
|
|
@@ -279,7 +279,7 @@ py_sim_clean()
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
/*
|
|
282
|
-
*
|
|
282
|
+
* Initialize a run
|
|
283
283
|
*/
|
|
284
284
|
static PyObject*
|
|
285
285
|
sim_init(PyObject *self, PyObject *args)
|
|
@@ -367,9 +367,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
367
367
|
for(i_state=0; i_state<ncells * N_STATE; i_state++) {
|
|
368
368
|
flt = PyList_GetItem(state_in, i_state); /* Borrowed reference */
|
|
369
369
|
if (!PyFloat_Check(flt)) {
|
|
370
|
-
|
|
371
|
-
sprintf(errstr, "Item %d in state vector is not a float.", i_state);
|
|
372
|
-
PyErr_SetString(PyExc_Exception, errstr);
|
|
370
|
+
PyErr_Format(PyExc_Exception, "Item %d in state vector is not a float.", i_state);
|
|
373
371
|
return sim_clean();
|
|
374
372
|
}
|
|
375
373
|
}
|
|
@@ -441,7 +439,7 @@ for label, eqs in equations.items():
|
|
|
441
439
|
/* Initial values */
|
|
442
440
|
<?
|
|
443
441
|
for var in model.states():
|
|
444
|
-
print(tab*2 + v(var) + ' = PyFloat_AsDouble(PyList_GetItem(state_in, icell * N_STATE + ' + str(var.
|
|
442
|
+
print(tab*2 + v(var) + ' = PyFloat_AsDouble(PyList_GetItem(state_in, icell * N_STATE + ' + str(var.index()) + '));')
|
|
445
443
|
?>
|
|
446
444
|
/* Zeros for pacing and diffusion current */
|
|
447
445
|
<?
|
|
@@ -581,7 +579,7 @@ for var in model.states():
|
|
|
581
579
|
for(icell=0; icell<ncells; icell++) {
|
|
582
580
|
<?
|
|
583
581
|
for var in model.states():
|
|
584
|
-
print(tab*2 + 'PyList_SetItem(state_out, icell * N_STATE + ' + str(var.
|
|
582
|
+
print(tab*2 + 'PyList_SetItem(state_out, icell * N_STATE + ' + str(var.index()) + ', PyFloat_FromDouble(' + v(var) + '));')
|
|
585
583
|
?>
|
|
586
584
|
cell++;
|
|
587
585
|
}
|
myokit/_sim/cable.py
CHANGED
|
@@ -4,13 +4,11 @@
|
|
|
4
4
|
# This file is part of Myokit.
|
|
5
5
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
6
6
|
#
|
|
7
|
-
from __future__ import absolute_import, division
|
|
8
|
-
from __future__ import print_function, unicode_literals
|
|
9
|
-
|
|
10
7
|
import os
|
|
11
|
-
import myokit
|
|
12
8
|
import platform
|
|
13
9
|
|
|
10
|
+
import myokit
|
|
11
|
+
|
|
14
12
|
# Location of source file
|
|
15
13
|
SOURCE_FILE = 'cable.c'
|
|
16
14
|
|
|
@@ -39,7 +37,7 @@ class Simulation1d(myokit.CModule):
|
|
|
39
37
|
``pace``
|
|
40
38
|
The pacing level, this is set if a protocol was passed in.
|
|
41
39
|
``diffusion_current``
|
|
42
|
-
The current flowing from the cell to its
|
|
40
|
+
The current flowing from the cell to its neighbors. This will be
|
|
43
41
|
positive when the cell is acting as a source, negative when it is
|
|
44
42
|
acting as a sink.
|
|
45
43
|
|
|
@@ -77,7 +75,7 @@ class Simulation1d(myokit.CModule):
|
|
|
77
75
|
|
|
78
76
|
i = sum[g * (V - V_j)]
|
|
79
77
|
|
|
80
|
-
Where the sum is taken over all
|
|
78
|
+
Where the sum is taken over all neighboring cells j (see [1]).
|
|
81
79
|
|
|
82
80
|
The resulting ODE system is solved using a forward Euler (FE) method with
|
|
83
81
|
fixed step sizes. Smaller step sizes lead to more accurate results, and it
|
|
@@ -101,7 +99,7 @@ class Simulation1d(myokit.CModule):
|
|
|
101
99
|
_index = 0 # Unique id for generated module
|
|
102
100
|
|
|
103
101
|
def __init__(self, model, protocol=None, ncells=50, rl=False):
|
|
104
|
-
super(
|
|
102
|
+
super().__init__()
|
|
105
103
|
|
|
106
104
|
# Require a valid model
|
|
107
105
|
model.validate()
|
|
@@ -176,7 +174,7 @@ class Simulation1d(myokit.CModule):
|
|
|
176
174
|
' next')
|
|
177
175
|
|
|
178
176
|
# Set state and default state
|
|
179
|
-
self._state = self._model.
|
|
177
|
+
self._state = self._model.initial_values(True) * ncells
|
|
180
178
|
self._default_state = list(self._state)
|
|
181
179
|
|
|
182
180
|
# Unique simulation id
|