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
|
@@ -1,612 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
#
|
|
3
|
-
# Tests the CVODE simulation class.
|
|
4
|
-
#
|
|
5
|
-
# This file is part of Myokit.
|
|
6
|
-
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
|
-
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
|
-
import os
|
|
12
|
-
import pickle
|
|
13
|
-
import platform
|
|
14
|
-
import re
|
|
15
|
-
import sys
|
|
16
|
-
import unittest
|
|
17
|
-
|
|
18
|
-
import numpy as np
|
|
19
|
-
|
|
20
|
-
import myokit
|
|
21
|
-
|
|
22
|
-
from myokit.tests import DIR_DATA, CancellingReporter, WarningCollector
|
|
23
|
-
|
|
24
|
-
# Unit testing in Python 2 and 3
|
|
25
|
-
try:
|
|
26
|
-
unittest.TestCase.assertRaisesRegex
|
|
27
|
-
except AttributeError:
|
|
28
|
-
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@unittest.skipIf(platform.system() != 'Linux', 'Legacy CVODE tests')
|
|
32
|
-
class LegacySimulationTest(unittest.TestCase):
|
|
33
|
-
"""
|
|
34
|
-
Tests the Legacy CVODE simulation class.
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
@classmethod
|
|
38
|
-
def setUpClass(cls):
|
|
39
|
-
# Test simulation creation.
|
|
40
|
-
|
|
41
|
-
m, p, x = myokit.load(os.path.join(DIR_DATA, 'lr-1991.mmt'))
|
|
42
|
-
cls.model = m
|
|
43
|
-
cls.protocol = p
|
|
44
|
-
cls.sim = myokit.LegacySimulation(cls.model, cls.protocol)
|
|
45
|
-
|
|
46
|
-
def test_pre(self):
|
|
47
|
-
# Test pre-pacing.
|
|
48
|
-
|
|
49
|
-
self.sim.reset()
|
|
50
|
-
self.sim.pre(200)
|
|
51
|
-
|
|
52
|
-
def test_simple(self):
|
|
53
|
-
# Test simple run.
|
|
54
|
-
|
|
55
|
-
self.sim.reset()
|
|
56
|
-
self.assertEqual(self.sim.time(), 0)
|
|
57
|
-
self.sim.pre(5)
|
|
58
|
-
self.assertEqual(self.sim.time(), 0)
|
|
59
|
-
d = self.sim.run(5)
|
|
60
|
-
self.assertEqual(self.sim.time(), 5)
|
|
61
|
-
self.sim.set_time(0)
|
|
62
|
-
self.assertEqual(self.sim.time(), 0)
|
|
63
|
-
self.assertEqual(type(d), myokit.DataLog)
|
|
64
|
-
self.assertIn('engine.time', d)
|
|
65
|
-
n = len(d['engine.time'])
|
|
66
|
-
for k, v in d.items():
|
|
67
|
-
self.assertEqual(n, len(v))
|
|
68
|
-
|
|
69
|
-
# Can't do negative times
|
|
70
|
-
self.assertRaisesRegex(ValueError, 'negative', self.sim.run, -1)
|
|
71
|
-
|
|
72
|
-
# Negative log interval is set to zero
|
|
73
|
-
self.sim.reset()
|
|
74
|
-
d1 = self.sim.run(5)
|
|
75
|
-
self.sim.reset()
|
|
76
|
-
d2 = self.sim.run(5, log_interval=-5)
|
|
77
|
-
self.assertEqual(d1.time(), d2.time())
|
|
78
|
-
|
|
79
|
-
def test_no_protocol(self):
|
|
80
|
-
# Test running without a protocol.
|
|
81
|
-
|
|
82
|
-
self.sim.reset()
|
|
83
|
-
self.sim.pre(50)
|
|
84
|
-
self.sim.set_protocol(None)
|
|
85
|
-
d = self.sim.run(50).npview()
|
|
86
|
-
|
|
87
|
-
# Check if pace was set to zero (see prop 651 / technical docs).
|
|
88
|
-
self.assertTrue(np.all(d['engine.pace'] == 0.0))
|
|
89
|
-
|
|
90
|
-
def test_fixed_form_protocol(self):
|
|
91
|
-
# Test running with a fixed form protocol.
|
|
92
|
-
|
|
93
|
-
n = 10
|
|
94
|
-
time = list(range(n))
|
|
95
|
-
pace = [0] * n
|
|
96
|
-
pace[2:4] = [0.5, 0.5]
|
|
97
|
-
|
|
98
|
-
self.sim.set_fixed_form_protocol(time, pace)
|
|
99
|
-
self.sim.reset()
|
|
100
|
-
d = self.sim.run(n, log_interval=1)
|
|
101
|
-
self.assertEqual(list(d.time()), time)
|
|
102
|
-
self.assertEqual(list(d['engine.pace']), pace)
|
|
103
|
-
|
|
104
|
-
# Unset
|
|
105
|
-
self.sim.set_fixed_form_protocol(None)
|
|
106
|
-
self.sim.reset()
|
|
107
|
-
d = self.sim.run(n, log_interval=1)
|
|
108
|
-
self.assertEqual(list(d['engine.pace']), [0] * n)
|
|
109
|
-
|
|
110
|
-
# Reset
|
|
111
|
-
self.sim.set_fixed_form_protocol(time, pace)
|
|
112
|
-
self.sim.reset()
|
|
113
|
-
d = self.sim.run(n, log_interval=1)
|
|
114
|
-
self.assertEqual(list(d.time()), time)
|
|
115
|
-
self.assertEqual(list(d['engine.pace']), pace)
|
|
116
|
-
|
|
117
|
-
# Unset, replace with original protocol
|
|
118
|
-
self.sim.set_protocol(self.protocol)
|
|
119
|
-
self.sim.reset()
|
|
120
|
-
d = self.sim.run(n, log_interval=1)
|
|
121
|
-
self.assertNotEqual(list(d['engine.pace']), pace)
|
|
122
|
-
self.assertNotEqual(list(d['engine.pace']), [0] * n)
|
|
123
|
-
|
|
124
|
-
# Invalid protocols
|
|
125
|
-
self.assertRaisesRegex(
|
|
126
|
-
ValueError, 'no times', self.sim.set_fixed_form_protocol,
|
|
127
|
-
values=pace)
|
|
128
|
-
self.assertRaisesRegex(
|
|
129
|
-
ValueError, 'no values', self.sim.set_fixed_form_protocol,
|
|
130
|
-
times=time)
|
|
131
|
-
self.assertRaisesRegex(
|
|
132
|
-
ValueError, 'same size', self.sim.set_fixed_form_protocol,
|
|
133
|
-
time, pace[:-1])
|
|
134
|
-
|
|
135
|
-
def test_in_parts(self):
|
|
136
|
-
# Test running the simulation in parts.
|
|
137
|
-
|
|
138
|
-
self.sim.reset()
|
|
139
|
-
# New logs should start with first state, finish with final
|
|
140
|
-
d = self.sim.run(150)
|
|
141
|
-
self.assertEqual(d['engine.time'][0], 0.0)
|
|
142
|
-
self.assertEqual(d['engine.time'][-1], 150.0)
|
|
143
|
-
# Next part should continue at 150, leave where last left off
|
|
144
|
-
e = self.sim.run(50)
|
|
145
|
-
self.assertEqual(d['engine.time'][-1], e['engine.time'][0])
|
|
146
|
-
self.assertEqual(d['membrane.V'][-1], e['membrane.V'][0])
|
|
147
|
-
# Re-used logs shouldn't re-log their first state
|
|
148
|
-
n = len(e['engine.time'])
|
|
149
|
-
e = self.sim.run(50, log=e)
|
|
150
|
-
self.assertNotEqual(e['engine.time'][n - 1], e['engine.time'][n])
|
|
151
|
-
self.assertGreater(e['engine.time'][n], e['engine.time'][n - 1])
|
|
152
|
-
|
|
153
|
-
def test_pacing_values_at_event_transitions(self):
|
|
154
|
-
# Tests the value of the pacing signal at event transitions
|
|
155
|
-
|
|
156
|
-
# Create a simple model
|
|
157
|
-
m = myokit.Model()
|
|
158
|
-
c = m.add_component('c')
|
|
159
|
-
t = c.add_variable('t')
|
|
160
|
-
t.set_rhs(0)
|
|
161
|
-
t.set_binding('time')
|
|
162
|
-
v = c.add_variable('v')
|
|
163
|
-
v.set_rhs('0')
|
|
164
|
-
v.set_binding('pace')
|
|
165
|
-
x = c.add_variable('x')
|
|
166
|
-
x.set_rhs(0.1)
|
|
167
|
-
x.promote(0)
|
|
168
|
-
|
|
169
|
-
# Create step protocol
|
|
170
|
-
p = myokit.Protocol()
|
|
171
|
-
p.schedule(0, 0, 2)
|
|
172
|
-
p.schedule(1, 2, 2)
|
|
173
|
-
p.schedule(2, 4, 4)
|
|
174
|
-
p.schedule(3, 8, 2)
|
|
175
|
-
|
|
176
|
-
# Simulate with dynamic logging
|
|
177
|
-
s = myokit.LegacySimulation(m, p)
|
|
178
|
-
d = s.run(p.characteristic_time())
|
|
179
|
-
time = list(d.time())
|
|
180
|
-
value = list(d['c.v'])
|
|
181
|
-
|
|
182
|
-
if False:
|
|
183
|
-
for i, t in enumerate(d.time()):
|
|
184
|
-
t = str(np.round(t, 5))
|
|
185
|
-
print(t + ' ' * (10 - len(t)) + str(d['c.v'][i]))
|
|
186
|
-
|
|
187
|
-
# Values should be
|
|
188
|
-
# t 0 1 2 3 4 5 6 7 8 9 10
|
|
189
|
-
# p 0 0 1 1 2 2 2 2 3 3 0
|
|
190
|
-
self.assertEqual(value[time.index(0.0)], 0)
|
|
191
|
-
self.assertEqual(value[time.index(0.0) + 1], 0)
|
|
192
|
-
self.assertEqual(value[time.index(2.0) - 1], 0)
|
|
193
|
-
self.assertEqual(value[time.index(2.0)], 1)
|
|
194
|
-
self.assertEqual(value[time.index(2.0) + 1], 1)
|
|
195
|
-
self.assertEqual(value[time.index(4.0) - 1], 1)
|
|
196
|
-
self.assertEqual(value[time.index(4.0)], 2)
|
|
197
|
-
self.assertEqual(value[time.index(4.0) + 1], 2)
|
|
198
|
-
self.assertEqual(value[time.index(8.0) - 1], 2)
|
|
199
|
-
self.assertEqual(value[time.index(8.0)], 3)
|
|
200
|
-
self.assertEqual(value[time.index(8.0) + 1], 3)
|
|
201
|
-
self.assertEqual(value[time.index(10.0) - 1], 3)
|
|
202
|
-
self.assertEqual(value[time.index(10.0)], 0)
|
|
203
|
-
|
|
204
|
-
# Simulate with fixed logging
|
|
205
|
-
s.reset()
|
|
206
|
-
d = s.run(p.characteristic_time() + 1, log_times=d.time())
|
|
207
|
-
time2 = list(d.time())
|
|
208
|
-
value2 = list(d['c.v'])
|
|
209
|
-
self.assertEqual(time, time2)
|
|
210
|
-
self.assertEqual(value, value2)
|
|
211
|
-
|
|
212
|
-
def test_progress_reporter(self):
|
|
213
|
-
# Test running with a progress reporter.
|
|
214
|
-
|
|
215
|
-
# Test if it works
|
|
216
|
-
sim = myokit.LegacySimulation(self.model, self.protocol)
|
|
217
|
-
with myokit.tools.capture() as c:
|
|
218
|
-
sim.run(110, progress=myokit.ProgressPrinter())
|
|
219
|
-
c = c.text().splitlines()
|
|
220
|
-
self.assertEqual(len(c), 2)
|
|
221
|
-
p = re.compile(re.escape('[0.0 minutes] 1.9 % done, estimated ') +
|
|
222
|
-
'[0-9]+' + re.escape(' seconds remaining'))
|
|
223
|
-
self.assertIsNotNone(p.match(c[0]))
|
|
224
|
-
p = re.compile(re.escape('[0.0 minutes] 100.0 % done, estimated ') +
|
|
225
|
-
'[0-9]+' + re.escape(' seconds remaining'))
|
|
226
|
-
self.assertIsNotNone(p.match(c[1]))
|
|
227
|
-
|
|
228
|
-
# Not a progress reporter
|
|
229
|
-
self.assertRaisesRegex(
|
|
230
|
-
ValueError, 'ProgressReporter', self.sim.run, 5, progress=12)
|
|
231
|
-
|
|
232
|
-
# Cancel from reporter
|
|
233
|
-
self.assertRaises(
|
|
234
|
-
myokit.SimulationCancelledError, self.sim.run, 1,
|
|
235
|
-
progress=CancellingReporter(0))
|
|
236
|
-
|
|
237
|
-
def test_apd_tracking(self):
|
|
238
|
-
# Test the APD calculation method.
|
|
239
|
-
|
|
240
|
-
# More testing is done in test_datalog.py!
|
|
241
|
-
|
|
242
|
-
# Apd var is not a state
|
|
243
|
-
v = self.model.get('ina.INa')
|
|
244
|
-
self.assertRaisesRegex(
|
|
245
|
-
ValueError, 'must be a state', myokit.LegacySimulation, self.model,
|
|
246
|
-
self.protocol, apd_var=v)
|
|
247
|
-
|
|
248
|
-
# Set a valid apd variable
|
|
249
|
-
v = self.model.get('ik.x')
|
|
250
|
-
sim = myokit.LegacySimulation(
|
|
251
|
-
self.model, self.protocol, apd_var=v)
|
|
252
|
-
sim.run(1, apd_threshold=12)
|
|
253
|
-
|
|
254
|
-
# No apd var given, but threshold provided
|
|
255
|
-
self.assertRaisesRegex(
|
|
256
|
-
ValueError, 'without apd_var', self.sim.run, 1, apd_threshold=12)
|
|
257
|
-
|
|
258
|
-
def test_last_state(self):
|
|
259
|
-
# Returns the last state before an error, or None.
|
|
260
|
-
|
|
261
|
-
m = self.model.clone()
|
|
262
|
-
istim = m.get('membrane.i_stim')
|
|
263
|
-
istim.set_rhs('engine.pace / stim_amplitude')
|
|
264
|
-
s = myokit.LegacySimulation(m, self.protocol)
|
|
265
|
-
self.assertIsNone(s.last_state())
|
|
266
|
-
s.run(1)
|
|
267
|
-
self.assertIsNone(s.last_state())
|
|
268
|
-
s.set_constant('membrane.i_stim.stim_amplitude', 0)
|
|
269
|
-
s.reset()
|
|
270
|
-
self.assertRaisesRegex(myokit.SimulationError, "at t = 0", s.run, 5)
|
|
271
|
-
self.assertEqual(len(s.last_state()), len(s.state()))
|
|
272
|
-
self.assertEqual(s.last_state(), s.state())
|
|
273
|
-
|
|
274
|
-
def test_last_evaluations_and_steps(self):
|
|
275
|
-
# Test :meth:`LegacySimulation.last_number_of_evaluations()` and
|
|
276
|
-
# :meth:`LegacySimulation.last_number_of_steps()`
|
|
277
|
-
|
|
278
|
-
s = myokit.LegacySimulation(self.model, self.protocol)
|
|
279
|
-
self.assertEqual(s.last_number_of_evaluations(), 0)
|
|
280
|
-
self.assertEqual(s.last_number_of_steps(), 0)
|
|
281
|
-
s.run(1)
|
|
282
|
-
self.assertTrue(s.last_number_of_evaluations() > 0)
|
|
283
|
-
self.assertTrue(s.last_number_of_steps() > 0)
|
|
284
|
-
self.assertNotEqual(
|
|
285
|
-
s.last_number_of_evaluations(), s.last_number_of_steps())
|
|
286
|
-
|
|
287
|
-
def test_eval_derivatives(self):
|
|
288
|
-
# Test :meth:`LegacySimulation.eval_derivatives()`.
|
|
289
|
-
|
|
290
|
-
self.sim.reset()
|
|
291
|
-
s1 = self.sim.state()
|
|
292
|
-
d1 = self.sim.eval_derivatives()
|
|
293
|
-
self.sim.run(1)
|
|
294
|
-
d2 = self.sim.eval_derivatives()
|
|
295
|
-
self.assertNotEqual(d1, d2)
|
|
296
|
-
self.assertEqual(d1, self.sim.eval_derivatives(s1))
|
|
297
|
-
self.sim.set_state(s1)
|
|
298
|
-
self.assertEqual(d1, self.sim.eval_derivatives())
|
|
299
|
-
|
|
300
|
-
def test_set_tolerance(self):
|
|
301
|
-
# Test :meth:`LegacySimulation.set_tolerance()`.
|
|
302
|
-
|
|
303
|
-
self.assertRaisesRegex(
|
|
304
|
-
ValueError, 'Absolute', self.sim.set_tolerance, abs_tol=0)
|
|
305
|
-
self.assertRaisesRegex(
|
|
306
|
-
ValueError, 'Relative', self.sim.set_tolerance, rel_tol=0)
|
|
307
|
-
self.sim.set_tolerance(1e-6, 1e-4)
|
|
308
|
-
|
|
309
|
-
def test_set_step_size(self):
|
|
310
|
-
# Test :meth:`LegacySimulation.set_min_step_size()` and
|
|
311
|
-
# :meth:`LegacySimulation.set_max_step_size()`.
|
|
312
|
-
|
|
313
|
-
# Minimum: set, unset, allow negative value to unset
|
|
314
|
-
self.sim.set_min_step_size(0.1)
|
|
315
|
-
self.sim.set_min_step_size(None)
|
|
316
|
-
self.sim.set_min_step_size(-1)
|
|
317
|
-
|
|
318
|
-
# Same for max
|
|
319
|
-
self.sim.set_max_step_size(0.1)
|
|
320
|
-
self.sim.set_max_step_size(None)
|
|
321
|
-
self.sim.set_max_step_size(-1)
|
|
322
|
-
|
|
323
|
-
def test_set_state(self):
|
|
324
|
-
# Test :meth:`LegacySimulation.set_state()` and
|
|
325
|
-
# :meth:`LegacySimulation.set_default_state()`.
|
|
326
|
-
|
|
327
|
-
# Get state and default state, both different from current
|
|
328
|
-
state = self.sim.state()
|
|
329
|
-
state[0] += 1
|
|
330
|
-
default_state = self.sim.default_state()
|
|
331
|
-
default_state[1] += 1
|
|
332
|
-
if state == default_state:
|
|
333
|
-
default_state[0] += 2
|
|
334
|
-
|
|
335
|
-
self.assertNotEqual(self.sim.state(), state)
|
|
336
|
-
self.assertNotEqual(self.sim.default_state(), default_state)
|
|
337
|
-
|
|
338
|
-
self.sim.set_state(state)
|
|
339
|
-
self.sim.set_default_state(default_state)
|
|
340
|
-
|
|
341
|
-
self.assertEqual(self.sim.state(), state)
|
|
342
|
-
self.assertEqual(self.sim.default_state(), default_state)
|
|
343
|
-
|
|
344
|
-
def test_set_constant(self):
|
|
345
|
-
# Test :meth:`LegacySimulation.set_constant()`.
|
|
346
|
-
|
|
347
|
-
# Literal
|
|
348
|
-
v = self.model.get('cell.Na_i')
|
|
349
|
-
self.sim.set_constant(v, 11)
|
|
350
|
-
self.assertRaises(KeyError, self.sim.set_constant, 'cell.Bert', 11)
|
|
351
|
-
|
|
352
|
-
# Calculated constant
|
|
353
|
-
self.assertRaisesRegex(
|
|
354
|
-
ValueError, 'not a literal', self.sim.set_constant, 'ina.ENa', 11)
|
|
355
|
-
|
|
356
|
-
def test_short_runs(self):
|
|
357
|
-
# Test for simulations run a very short time
|
|
358
|
-
|
|
359
|
-
# Run for 1 unit (OK)
|
|
360
|
-
self.sim.reset()
|
|
361
|
-
self.sim.run(1)
|
|
362
|
-
|
|
363
|
-
# Test running for 0 units doesn't affect state
|
|
364
|
-
x0 = self.sim.state()
|
|
365
|
-
self.sim.run(0)
|
|
366
|
-
self.assertEqual(x0, self.sim.state())
|
|
367
|
-
self.sim.run(0)
|
|
368
|
-
self.assertEqual(x0, self.sim.state())
|
|
369
|
-
|
|
370
|
-
# Test running between indistinguishable times doesn't affect state
|
|
371
|
-
t = self.sim.time()
|
|
372
|
-
d = 0.5 * sys.float_info.epsilon
|
|
373
|
-
self.assertEqual(t, t + d)
|
|
374
|
-
self.sim.run(d)
|
|
375
|
-
|
|
376
|
-
# Test running between only just distinguishable times is fine
|
|
377
|
-
self.sim.reset()
|
|
378
|
-
self.sim.run(1)
|
|
379
|
-
t = self.sim.time()
|
|
380
|
-
d = 3 * sys.float_info.epsilon
|
|
381
|
-
self.assertNotEqual(t, t + d)
|
|
382
|
-
self.sim.run(d)
|
|
383
|
-
|
|
384
|
-
# Test running between barely distinguishable times raises CVODE error.
|
|
385
|
-
t = self.sim.time()
|
|
386
|
-
d = 2 * sys.float_info.epsilon
|
|
387
|
-
self.assertNotEqual(t, t + d)
|
|
388
|
-
self.assertRaisesRegex(
|
|
389
|
-
myokit.SimulationError, 'CV_TOO_CLOSE', self.sim.run, d)
|
|
390
|
-
|
|
391
|
-
# Empty log times
|
|
392
|
-
self.sim.reset()
|
|
393
|
-
self.sim.run(1, log_times=[])
|
|
394
|
-
|
|
395
|
-
# Non-monotonic times
|
|
396
|
-
self.sim.reset()
|
|
397
|
-
with self.assertRaisesRegex(ValueError, 'Values in log_times'):
|
|
398
|
-
self.sim.run(1, log_times=[1, 2, 1])
|
|
399
|
-
|
|
400
|
-
# Simultaneous use of log_times and log_interval
|
|
401
|
-
self.sim.reset()
|
|
402
|
-
with self.assertRaisesRegex(ValueError, 'The arguments log_times'):
|
|
403
|
-
self.sim.run(1, log_times=[1, 2], log_interval=2)
|
|
404
|
-
|
|
405
|
-
def test_simulation_error_1(self):
|
|
406
|
-
# Test for simulation error detection: massive stimulus.
|
|
407
|
-
|
|
408
|
-
# Silly protocol
|
|
409
|
-
p = myokit.Protocol()
|
|
410
|
-
p.schedule(level=1000, start=1, duration=1)
|
|
411
|
-
self.sim.reset()
|
|
412
|
-
self.sim.set_protocol(p)
|
|
413
|
-
self.assertRaisesRegex(
|
|
414
|
-
myokit.SimulationError, 'numerical error', self.sim.run, 10)
|
|
415
|
-
self.sim.set_protocol(self.protocol)
|
|
416
|
-
|
|
417
|
-
@unittest.skipIf(platform.system() != 'Linux', 'CVODE error tests')
|
|
418
|
-
def test_simulation_error_2(self):
|
|
419
|
-
# Test for simulation error detection: failure occurred too often.
|
|
420
|
-
|
|
421
|
-
# Cvode error (test failure occurred too many times)
|
|
422
|
-
m = self.model.clone()
|
|
423
|
-
v = m.get('membrane.V')
|
|
424
|
-
v.set_rhs(myokit.Multiply(v.rhs(), myokit.Number(1e18)))
|
|
425
|
-
s = myokit.LegacySimulation(m, self.protocol)
|
|
426
|
-
with WarningCollector():
|
|
427
|
-
self.assertRaisesRegex(
|
|
428
|
-
myokit.SimulationError, 'numerical error', s.run, 5000)
|
|
429
|
-
|
|
430
|
-
def test_cvode_simulation_with_zero_states(self):
|
|
431
|
-
# Tests running cvode simulations on models with no ODEs
|
|
432
|
-
|
|
433
|
-
# Create a model without states
|
|
434
|
-
m1 = myokit.Model()
|
|
435
|
-
c = m1.add_component('c')
|
|
436
|
-
t = c.add_variable('t')
|
|
437
|
-
t.set_rhs(0)
|
|
438
|
-
t.set_binding('time')
|
|
439
|
-
v = c.add_variable('v')
|
|
440
|
-
v.set_rhs('0')
|
|
441
|
-
v.set_binding('pace')
|
|
442
|
-
w = c.add_variable('w')
|
|
443
|
-
w.set_rhs('2 * v')
|
|
444
|
-
|
|
445
|
-
# Create a model with a state
|
|
446
|
-
m2 = m1.clone()
|
|
447
|
-
z = m2.get('c').add_variable('z')
|
|
448
|
-
z.set_rhs(0.1)
|
|
449
|
-
z.promote(0)
|
|
450
|
-
|
|
451
|
-
# Test without protocol and dynamic logging
|
|
452
|
-
s1 = myokit.LegacySimulation(m1)
|
|
453
|
-
d1 = s1.run(5)
|
|
454
|
-
self.assertEqual(len(d1.time()), 2)
|
|
455
|
-
self.assertEqual(list(d1.time()), [0, 5])
|
|
456
|
-
self.assertEqual(list(d1['c.w']), [0, 0])
|
|
457
|
-
s2 = myokit.LegacySimulation(m2)
|
|
458
|
-
d2 = s2.run(6, log_times=d1.time())
|
|
459
|
-
self.assertEqual(d1.time(), d2.time())
|
|
460
|
-
self.assertEqual(d1['c.w'], d2['c.w'])
|
|
461
|
-
|
|
462
|
-
# Test with a protocol and dynamic logging
|
|
463
|
-
p = myokit.Protocol()
|
|
464
|
-
p.schedule(0, 0, 2)
|
|
465
|
-
p.schedule(1, 2, 2)
|
|
466
|
-
p.schedule(2, 4, 4)
|
|
467
|
-
p.schedule(3, 8, 2)
|
|
468
|
-
s1.reset()
|
|
469
|
-
s1.set_protocol(p)
|
|
470
|
-
d1 = s1.run(p.characteristic_time())
|
|
471
|
-
self.assertEqual(len(d1.time()), 5)
|
|
472
|
-
self.assertEqual(list(d1.time()), [0, 2, 4, 8, 10])
|
|
473
|
-
self.assertEqual(list(d1['c.w']), [0, 2, 4, 6, 0])
|
|
474
|
-
s2.reset()
|
|
475
|
-
s2.set_protocol(p)
|
|
476
|
-
d2 = s2.run(p.characteristic_time() + 1, log_times=d1.time())
|
|
477
|
-
self.assertEqual(d1.time(), d2.time())
|
|
478
|
-
self.assertEqual(d1['c.w'], d2['c.w'])
|
|
479
|
-
|
|
480
|
-
# Test with fixed logging times
|
|
481
|
-
s1.reset()
|
|
482
|
-
d1 = s1.run(p.characteristic_time() + 1, log_times=d1['c.t'])
|
|
483
|
-
self.assertEqual(list(d1.time()), [0, 2, 4, 8, 10])
|
|
484
|
-
self.assertEqual(list(d1['c.w']), [0, 2, 4, 6, 0])
|
|
485
|
-
s2.reset()
|
|
486
|
-
d2 = s2.run(p.characteristic_time() + 1, log_times=d1.time())
|
|
487
|
-
self.assertEqual(d1.time(), d2.time())
|
|
488
|
-
self.assertEqual(d1['c.w'], d2['c.w'])
|
|
489
|
-
|
|
490
|
-
# Test appending to log
|
|
491
|
-
s1.reset()
|
|
492
|
-
d1 = s1.run(5)
|
|
493
|
-
d1 = s1.run(5, log=d1)
|
|
494
|
-
self.assertEqual(list(d1.time()), [0, 2, 4, 5, 8, 10])
|
|
495
|
-
self.assertEqual(list(d1['c.w']), [0, 2, 4, 4, 6, 0])
|
|
496
|
-
|
|
497
|
-
# Test with a log interval
|
|
498
|
-
s1.reset()
|
|
499
|
-
d1 = s1.run(11, log_interval=1)
|
|
500
|
-
self.assertEqual(list(d1.time()), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
|
501
|
-
self.assertEqual(list(d1['c.w']), [0, 0, 2, 2, 4, 4, 4, 4, 6, 6, 0])
|
|
502
|
-
|
|
503
|
-
def test_pickling(self):
|
|
504
|
-
# Test pickling a simulation
|
|
505
|
-
|
|
506
|
-
# Test with myokit.Protocol
|
|
507
|
-
m, p, _ = myokit.load('example')
|
|
508
|
-
s1 = myokit.LegacySimulation(m, p)
|
|
509
|
-
s1.pre(123)
|
|
510
|
-
s_bytes = pickle.dumps(s1)
|
|
511
|
-
s2 = pickle.loads(s_bytes)
|
|
512
|
-
self.assertEqual(s1.time(), s2.time())
|
|
513
|
-
self.assertEqual(s1.state(), s2.state())
|
|
514
|
-
self.assertEqual(s1.default_state(), s2.default_state())
|
|
515
|
-
s1.run(123, log=myokit.LOG_NONE)
|
|
516
|
-
s2.run(123, log=myokit.LOG_NONE)
|
|
517
|
-
self.assertEqual(s1.time(), s2.time())
|
|
518
|
-
self.assertEqual(s1.state(), s2.state())
|
|
519
|
-
|
|
520
|
-
# Test simulation properties
|
|
521
|
-
s1.set_tolerance(1e-8, 1e-8)
|
|
522
|
-
s1.set_min_step_size(1e-2)
|
|
523
|
-
s1.set_max_step_size(0.1)
|
|
524
|
-
s2 = pickle.loads(pickle.dumps(s1))
|
|
525
|
-
s1.run(23, log=myokit.LOG_NONE)
|
|
526
|
-
s2.run(23, log=myokit.LOG_NONE)
|
|
527
|
-
self.assertEqual(s1.time(), s2.time())
|
|
528
|
-
self.assertEqual(s1.state(), s2.state())
|
|
529
|
-
|
|
530
|
-
# Test changed constants
|
|
531
|
-
s1.set_constant('membrane.C', 1.1)
|
|
532
|
-
s2 = pickle.loads(pickle.dumps(s1))
|
|
533
|
-
s1.run(17, log=myokit.LOG_NONE)
|
|
534
|
-
s2.run(17, log=myokit.LOG_NONE)
|
|
535
|
-
self.assertEqual(s1.time(), s2.time())
|
|
536
|
-
self.assertEqual(s1.state(), s2.state())
|
|
537
|
-
|
|
538
|
-
def test_sim_stats(self):
|
|
539
|
-
# Test extraction of simulation statistics
|
|
540
|
-
m, p, _ = myokit.load('example')
|
|
541
|
-
rt = m['engine'].add_variable('realtime')
|
|
542
|
-
rt.set_rhs(0)
|
|
543
|
-
rt.set_binding('realtime')
|
|
544
|
-
ev = m['engine'].add_variable('evaluations')
|
|
545
|
-
ev.set_rhs(0)
|
|
546
|
-
ev.set_binding('evaluations')
|
|
547
|
-
s = myokit.LegacySimulation(m, p)
|
|
548
|
-
d = s.run(100, log=myokit.LOG_BOUND).npview()
|
|
549
|
-
|
|
550
|
-
self.assertIn('engine.realtime', d)
|
|
551
|
-
self.assertIn('engine.evaluations', d)
|
|
552
|
-
rt, ev = d['engine.realtime'], d['engine.evaluations']
|
|
553
|
-
self.assertEqual(len(d.time()), len(rt))
|
|
554
|
-
self.assertEqual(len(d.time()), len(ev))
|
|
555
|
-
self.assertTrue(np.all(rt >= 0))
|
|
556
|
-
self.assertTrue(np.all(ev >= 0))
|
|
557
|
-
self.assertTrue(np.all(rt[1:] >= rt[:-1]))
|
|
558
|
-
self.assertTrue(np.all(ev[1:] >= ev[:-1]))
|
|
559
|
-
|
|
560
|
-
def test_apd(self):
|
|
561
|
-
# Test the apd rootfinding routine
|
|
562
|
-
|
|
563
|
-
s = myokit.LegacySimulation(
|
|
564
|
-
self.model, self.protocol, apd_var='membrane.V')
|
|
565
|
-
s.set_tolerance(1e-8, 1e-8)
|
|
566
|
-
d, apds = s.run(1800, log=myokit.LOG_NONE, apd_threshold=-70)
|
|
567
|
-
|
|
568
|
-
# Check with threshold equal to V
|
|
569
|
-
self.assertEqual(len(apds['start']), 2)
|
|
570
|
-
self.assertEqual(len(apds['duration']), 2)
|
|
571
|
-
self.assertAlmostEqual(apds['start'][0], 1.19, places=1)
|
|
572
|
-
self.assertAlmostEqual(apds['start'][1], 1001.19, places=1)
|
|
573
|
-
self.assertAlmostEqual(apds['duration'][0], 383.88262, places=0)
|
|
574
|
-
self.assertAlmostEqual(apds['duration'][1], 378.31448, places=0)
|
|
575
|
-
|
|
576
|
-
def test_derivatives(self):
|
|
577
|
-
# Tests logging of derivatives by comparing with a finite difference
|
|
578
|
-
# approximation
|
|
579
|
-
|
|
580
|
-
# Run past the upstroke, where finite diff approx is worst
|
|
581
|
-
self.sim.reset()
|
|
582
|
-
self.sim.run(52)
|
|
583
|
-
|
|
584
|
-
# Now run logged part
|
|
585
|
-
d = self.sim.run(600).npview()
|
|
586
|
-
if False:
|
|
587
|
-
import matplotlib.pyplot as plt
|
|
588
|
-
plt.figure()
|
|
589
|
-
ax = plt.subplot(3, 1, 1)
|
|
590
|
-
ax.plot(d.time(), d['membrane.V'])
|
|
591
|
-
ax = plt.subplot(3, 1, 2)
|
|
592
|
-
ax.plot(d.time(), d['dot(membrane.V)'])
|
|
593
|
-
|
|
594
|
-
# Get central difference approximation
|
|
595
|
-
t = d.time()
|
|
596
|
-
v = d['membrane.V']
|
|
597
|
-
dv = (v[2:] - v[:-2]) / (t[2:] - t[:-2])
|
|
598
|
-
e = d['dot(membrane.V)'][1:-1] - dv
|
|
599
|
-
if False:
|
|
600
|
-
t = t[1:-1]
|
|
601
|
-
ax.plot(t, dv, '--')
|
|
602
|
-
ax = plt.subplot(3, 1, 3)
|
|
603
|
-
ax.plot(t, e)
|
|
604
|
-
print(np.max(np.abs(e)))
|
|
605
|
-
|
|
606
|
-
# Compare
|
|
607
|
-
self.assertLess(np.max(np.abs(e)), 0.1)
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
if __name__ == '__main__':
|
|
611
|
-
unittest.main()
|
|
612
|
-
|