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
|
@@ -5,9 +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
8
|
import os
|
|
12
9
|
import pickle
|
|
13
10
|
import platform
|
|
@@ -26,12 +23,6 @@ from myokit.tests import (
|
|
|
26
23
|
WarningCollector,
|
|
27
24
|
)
|
|
28
25
|
|
|
29
|
-
# Unit testing in Python 2 and 3
|
|
30
|
-
try:
|
|
31
|
-
unittest.TestCase.assertRaisesRegex
|
|
32
|
-
except AttributeError:
|
|
33
|
-
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
|
34
|
-
|
|
35
26
|
|
|
36
27
|
class SimulationTest(unittest.TestCase):
|
|
37
28
|
"""
|
|
@@ -80,6 +71,162 @@ class SimulationTest(unittest.TestCase):
|
|
|
80
71
|
d2 = self.sim.run(5, log_interval=-5)
|
|
81
72
|
self.assertEqual(d1.time(), d2.time())
|
|
82
73
|
|
|
74
|
+
def test_multiple_protocols(self):
|
|
75
|
+
# Test using multiple protocols
|
|
76
|
+
|
|
77
|
+
# Set up a model
|
|
78
|
+
model = myokit.Model()
|
|
79
|
+
c = model.add_component('c')
|
|
80
|
+
t = c.add_variable('t')
|
|
81
|
+
t.set_binding('time')
|
|
82
|
+
t.set_rhs(0)
|
|
83
|
+
|
|
84
|
+
a = c.add_variable('a')
|
|
85
|
+
a.set_binding('a')
|
|
86
|
+
a.set_rhs(0)
|
|
87
|
+
b = c.add_variable('b')
|
|
88
|
+
b.set_binding('b')
|
|
89
|
+
b.set_rhs(0)
|
|
90
|
+
y = c.add_variable('y')
|
|
91
|
+
y.promote(1)
|
|
92
|
+
y.set_rhs('-a * y - b * y')
|
|
93
|
+
|
|
94
|
+
# Create two overlapping protocols
|
|
95
|
+
pa = myokit.Protocol()
|
|
96
|
+
pa.schedule(level=1, start=0.2, duration=0.5)
|
|
97
|
+
|
|
98
|
+
pb = myokit.Protocol()
|
|
99
|
+
pb.schedule(level=2, start=0.5, duration=0.6)
|
|
100
|
+
|
|
101
|
+
# Run a simulation with both
|
|
102
|
+
s = myokit.Simulation(model, {'a': pa, 'b': pb})
|
|
103
|
+
s.set_tolerance(1e-8)
|
|
104
|
+
d = s.run(2).npview()
|
|
105
|
+
times = d[t]
|
|
106
|
+
|
|
107
|
+
# Check that the changing points are in the log
|
|
108
|
+
self.assertIn(0, times)
|
|
109
|
+
self.assertIn(0.2, times)
|
|
110
|
+
self.assertIn(0.5, times)
|
|
111
|
+
self.assertIn(0.7, times)
|
|
112
|
+
self.assertIn(1.1, times)
|
|
113
|
+
self.assertIn(2, times)
|
|
114
|
+
|
|
115
|
+
# Check that a, b, and y have the expected values
|
|
116
|
+
a_up = (times >= 0.2) & (times < 0.7)
|
|
117
|
+
np.testing.assert_array_equal(d[a], np.where(a_up, 1, 0))
|
|
118
|
+
|
|
119
|
+
b_up = (times >= 0.5) & (times < 1.1)
|
|
120
|
+
np.testing.assert_array_equal(d[b], np.where(b_up, 2, 0))
|
|
121
|
+
|
|
122
|
+
# Check that dy/dt has the expected values
|
|
123
|
+
# dy/dt =
|
|
124
|
+
# 0 from 0 to 0.2
|
|
125
|
+
# -y from 0.2 to 0.5
|
|
126
|
+
# -3y from 0.5 to 0.7
|
|
127
|
+
# -2y from 0.7 to 1.1
|
|
128
|
+
# 0 after 1.1
|
|
129
|
+
#
|
|
130
|
+
dy_expect = 0 * times
|
|
131
|
+
dy_expect[a_up] -= 1 * d[y][a_up]
|
|
132
|
+
dy_expect[b_up] -= 2 * d[y][b_up]
|
|
133
|
+
np.testing.assert_array_equal(d['dot(c.y)'], dy_expect)
|
|
134
|
+
|
|
135
|
+
# Check that y has the expected values
|
|
136
|
+
# The solution for dy/dt = -a*y is y(t) = c * exp(-at), so
|
|
137
|
+
# y =
|
|
138
|
+
# 1
|
|
139
|
+
# exp(-(t - 0.5))
|
|
140
|
+
# exp(-0.3) * exp(-3 * (t - 0.5))
|
|
141
|
+
# exp(-0.9) * exp(-2 * (t - 0.7))
|
|
142
|
+
# exp(-1.7)
|
|
143
|
+
#
|
|
144
|
+
y_expect = np.ones(times.shape)
|
|
145
|
+
i = (times >= 0.2) & (times < 0.5)
|
|
146
|
+
y_expect[i] = np.exp(-(times[i] - 0.2))
|
|
147
|
+
i = (times >= 0.5) & (times < 0.7)
|
|
148
|
+
y_expect[i] = np.exp(-0.3) * np.exp(-3 * (times[i] - 0.5))
|
|
149
|
+
i = (times >= 0.7) & (times < 1.1)
|
|
150
|
+
y_expect[i] = np.exp(-0.9) * np.exp(-2 * (times[i] - 0.7))
|
|
151
|
+
y_expect[times >= 1.1] = np.exp(-1.7)
|
|
152
|
+
np.testing.assert_array_almost_equal(d[y], y_expect, decimal=3)
|
|
153
|
+
|
|
154
|
+
# Test unsetting
|
|
155
|
+
s.set_protocol(None, label='a')
|
|
156
|
+
s.reset()
|
|
157
|
+
d = s.run(2).npview()
|
|
158
|
+
np.testing.assert_array_equal(d[a], np.zeros(d[a].shape))
|
|
159
|
+
times = d[t]
|
|
160
|
+
b_up = (times >= 0.5) & (times < 1.1)
|
|
161
|
+
np.testing.assert_array_equal(d[b], np.where(b_up, 2, 0))
|
|
162
|
+
y_expect = np.ones(times.shape)
|
|
163
|
+
i = (times >= 0.5) & (times < 1.1)
|
|
164
|
+
y_expect[i] = np.exp(-2 * (times[i] - 0.5))
|
|
165
|
+
y_expect[times >= 1.1] = np.exp(-1.2)
|
|
166
|
+
np.testing.assert_array_almost_equal(d[y], y_expect, decimal=3)
|
|
167
|
+
|
|
168
|
+
# Test unsetting
|
|
169
|
+
s.set_protocol(None, label='b')
|
|
170
|
+
s.reset()
|
|
171
|
+
d = s.run(2).npview()
|
|
172
|
+
np.testing.assert_array_equal(d[a], np.zeros(d[a].shape))
|
|
173
|
+
np.testing.assert_array_equal(d[a], np.zeros(d[a].shape))
|
|
174
|
+
np.testing.assert_array_equal(d[y], np.ones(d[a].shape))
|
|
175
|
+
|
|
176
|
+
def test_mixed_protocols(self):
|
|
177
|
+
# Test using a step and a time series protocol at the same time
|
|
178
|
+
|
|
179
|
+
# Set up a model
|
|
180
|
+
model = myokit.Model()
|
|
181
|
+
c = model.add_component('c')
|
|
182
|
+
t = c.add_variable('t')
|
|
183
|
+
t.set_binding('time')
|
|
184
|
+
t.set_rhs(0)
|
|
185
|
+
a = c.add_variable('a')
|
|
186
|
+
a.set_binding('a')
|
|
187
|
+
a.set_rhs(0)
|
|
188
|
+
b = c.add_variable('b')
|
|
189
|
+
b.set_binding('b')
|
|
190
|
+
b.set_rhs(0)
|
|
191
|
+
y = c.add_variable('y') # Just to log more points
|
|
192
|
+
y.promote(1)
|
|
193
|
+
y.set_rhs('a + b')
|
|
194
|
+
|
|
195
|
+
# Set up protocols
|
|
196
|
+
pa = myokit.pacing.blocktrain(level=2, offset=1, duration=2, period=5)
|
|
197
|
+
x = np.linspace(0, 10, 100)
|
|
198
|
+
y = 0.1 + 0.2 * np.sin(x)
|
|
199
|
+
pb = myokit.TimeSeriesProtocol(x, y)
|
|
200
|
+
|
|
201
|
+
# Run a simulation with both
|
|
202
|
+
s = myokit.Simulation(model, {'a': pa, 'b': pb})
|
|
203
|
+
s.set_tolerance(1e-8)
|
|
204
|
+
d = s.run(12).npview()
|
|
205
|
+
t = d[t]
|
|
206
|
+
|
|
207
|
+
# Start, end, and change points visited exactly
|
|
208
|
+
self.assertIn(0, t)
|
|
209
|
+
self.assertIn(1, t)
|
|
210
|
+
self.assertIn(3, t)
|
|
211
|
+
self.assertIn(6, t)
|
|
212
|
+
self.assertIn(8, t)
|
|
213
|
+
self.assertIn(11, t)
|
|
214
|
+
self.assertIn(12, t)
|
|
215
|
+
|
|
216
|
+
# Test a
|
|
217
|
+
a_e = np.zeros(t.shape)
|
|
218
|
+
a_e[(t >= 1) & (t < 3)] = 2
|
|
219
|
+
a_e[(t >= 6) & (t < 8)] = 2
|
|
220
|
+
a_e[(t >= 11) & (t < 13)] = 2
|
|
221
|
+
np.testing.assert_array_equal(d[a], a_e)
|
|
222
|
+
|
|
223
|
+
# Test b
|
|
224
|
+
b_e = 0.1 + 0.2 * np.sin(t)
|
|
225
|
+
b_e[t > 10] = y[-1]
|
|
226
|
+
# Note: We don't expect a super good match here, as b_e is an exact
|
|
227
|
+
# sine value, while the solver will be interpolating y
|
|
228
|
+
np.testing.assert_array_almost_equal(d[b], b_e, decimal=3)
|
|
229
|
+
|
|
83
230
|
def test_no_protocol(self):
|
|
84
231
|
# Test running without a protocol.
|
|
85
232
|
|
|
@@ -91,50 +238,74 @@ class SimulationTest(unittest.TestCase):
|
|
|
91
238
|
# Check if pace was set to zero (see prop 651 / technical docs).
|
|
92
239
|
self.assertTrue(np.all(d['engine.pace'] == 0.0))
|
|
93
240
|
|
|
94
|
-
def
|
|
95
|
-
# Test
|
|
241
|
+
def test_wrong_label_set_pacing(self):
|
|
242
|
+
# Test set_pacing with incorrect label
|
|
243
|
+
self.sim.reset()
|
|
244
|
+
self.sim.pre(50)
|
|
245
|
+
with self.assertRaisesRegex(ValueError, 'Unknown pacing label'):
|
|
246
|
+
self.sim.set_protocol(None, label='does not exist')
|
|
247
|
+
|
|
248
|
+
def test_time_series_protocol(self):
|
|
249
|
+
# Test running with a time series protocol
|
|
96
250
|
|
|
97
251
|
n = 10
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
252
|
+
times = list(range(n))
|
|
253
|
+
values = [0] * n
|
|
254
|
+
values[2:4] = [0.5, 0.5]
|
|
255
|
+
p = myokit.TimeSeriesProtocol(times, values)
|
|
101
256
|
|
|
102
|
-
self.sim.
|
|
257
|
+
self.sim.set_protocol(p)
|
|
103
258
|
self.sim.reset()
|
|
104
259
|
d = self.sim.run(n, log_interval=1)
|
|
105
|
-
self.assertEqual(list(d.time()),
|
|
106
|
-
self.assertEqual(list(d['engine.pace']),
|
|
260
|
+
self.assertEqual(list(d.time()), times)
|
|
261
|
+
self.assertEqual(list(d['engine.pace']), values)
|
|
107
262
|
|
|
108
263
|
# Unset
|
|
109
|
-
self.sim.
|
|
264
|
+
self.sim.set_protocol(None)
|
|
110
265
|
self.sim.reset()
|
|
111
266
|
d = self.sim.run(n, log_interval=1)
|
|
112
267
|
self.assertEqual(list(d['engine.pace']), [0] * n)
|
|
113
268
|
|
|
114
269
|
# Reset
|
|
115
|
-
self.sim.
|
|
270
|
+
self.sim.set_protocol(p)
|
|
116
271
|
self.sim.reset()
|
|
117
272
|
d = self.sim.run(n, log_interval=1)
|
|
118
|
-
self.assertEqual(list(d.time()),
|
|
119
|
-
self.assertEqual(list(d['engine.pace']),
|
|
273
|
+
self.assertEqual(list(d.time()), times)
|
|
274
|
+
self.assertEqual(list(d['engine.pace']), values)
|
|
120
275
|
|
|
121
276
|
# Unset, replace with original protocol
|
|
122
277
|
self.sim.set_protocol(self.protocol)
|
|
123
278
|
self.sim.reset()
|
|
124
279
|
d = self.sim.run(n, log_interval=1)
|
|
125
|
-
self.assertNotEqual(list(d['engine.pace']),
|
|
280
|
+
self.assertNotEqual(list(d['engine.pace']), values)
|
|
126
281
|
self.assertNotEqual(list(d['engine.pace']), [0] * n)
|
|
127
282
|
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
self.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
self.
|
|
136
|
-
|
|
137
|
-
|
|
283
|
+
# Deprecated version
|
|
284
|
+
with WarningCollector() as w:
|
|
285
|
+
self.sim.set_fixed_form_protocol(times, values)
|
|
286
|
+
self.assertIn('eprecated', w.text())
|
|
287
|
+
self.sim.reset()
|
|
288
|
+
d = self.sim.run(n, log_interval=1)
|
|
289
|
+
self.assertEqual(list(d.time()), times)
|
|
290
|
+
self.assertEqual(list(d['engine.pace']), values)
|
|
291
|
+
with WarningCollector() as w:
|
|
292
|
+
self.assertRaisesRegex(
|
|
293
|
+
ValueError, 'No times',
|
|
294
|
+
self.sim.set_fixed_form_protocol, values=values)
|
|
295
|
+
self.assertRaisesRegex(
|
|
296
|
+
ValueError, 'No values',
|
|
297
|
+
self.sim.set_fixed_form_protocol, times=times)
|
|
298
|
+
self.sim.set_fixed_form_protocol(None)
|
|
299
|
+
self.sim.reset()
|
|
300
|
+
d = self.sim.run(n, log_interval=1)
|
|
301
|
+
self.assertEqual(list(d['engine.pace']), [0] * n)
|
|
302
|
+
|
|
303
|
+
# Reset original protocol
|
|
304
|
+
self.sim.set_protocol(self.protocol)
|
|
305
|
+
self.sim.reset()
|
|
306
|
+
d = self.sim.run(n, log_interval=1)
|
|
307
|
+
self.assertNotEqual(list(d['engine.pace']), values)
|
|
308
|
+
self.assertNotEqual(list(d['engine.pace']), [0] * n)
|
|
138
309
|
|
|
139
310
|
def test_in_parts(self):
|
|
140
311
|
# Test running the simulation in parts.
|
|
@@ -154,6 +325,30 @@ class SimulationTest(unittest.TestCase):
|
|
|
154
325
|
self.assertNotEqual(e['engine.time'][n - 1], e['engine.time'][n])
|
|
155
326
|
self.assertGreater(e['engine.time'][n], e['engine.time'][n - 1])
|
|
156
327
|
|
|
328
|
+
def test_initial_value_expressions(self):
|
|
329
|
+
# Test if initial value expressions are converted to floats
|
|
330
|
+
|
|
331
|
+
m = myokit.parse_model('''
|
|
332
|
+
[[model]]
|
|
333
|
+
c.x = 1 + sqrt(3)
|
|
334
|
+
c.y = 1 / c.p
|
|
335
|
+
c.z = 3
|
|
336
|
+
|
|
337
|
+
[c]
|
|
338
|
+
t = 0 bind time
|
|
339
|
+
dot(x) = 1
|
|
340
|
+
dot(y) = 2
|
|
341
|
+
dot(z) = 3
|
|
342
|
+
p = log(3)
|
|
343
|
+
''')
|
|
344
|
+
s = myokit.Simulation(m)
|
|
345
|
+
x = s.state()
|
|
346
|
+
self.assertIsInstance(x[0], float)
|
|
347
|
+
self.assertIsInstance(x[1], float)
|
|
348
|
+
self.assertIsInstance(x[2], float)
|
|
349
|
+
self.assertEqual(x, m.initial_values(True))
|
|
350
|
+
self.assertEqual(x, s.default_state())
|
|
351
|
+
|
|
157
352
|
def test_pacing_values_at_event_transitions(self):
|
|
158
353
|
# Tests the value of the pacing signal at event transitions
|
|
159
354
|
|
|
@@ -239,9 +434,34 @@ class SimulationTest(unittest.TestCase):
|
|
|
239
434
|
progress=CancellingReporter(0))
|
|
240
435
|
|
|
241
436
|
def test_apd_tracking(self):
|
|
242
|
-
# Test the APD
|
|
437
|
+
# Test the APD / rootfinding method.
|
|
438
|
+
# Tested against offline method in test_datalog.py
|
|
243
439
|
|
|
244
|
-
#
|
|
440
|
+
# Test that it works
|
|
441
|
+
self.sim.reset()
|
|
442
|
+
res = self.sim.run(
|
|
443
|
+
1800, log=['engine.time', 'membrane.V'],
|
|
444
|
+
apd_variable='membrane.V', apd_threshold=-70)
|
|
445
|
+
|
|
446
|
+
self.assertIsInstance(res, tuple)
|
|
447
|
+
self.assertEqual(len(res), 2)
|
|
448
|
+
d, apds = res
|
|
449
|
+
self.assertIsInstance(d, myokit.DataLog)
|
|
450
|
+
self.assertIsInstance(apds, myokit.DataLog)
|
|
451
|
+
self.assertEqual(len(apds), 2)
|
|
452
|
+
self.assertEqual(apds.length(), 2)
|
|
453
|
+
self.assertIn('start', apds)
|
|
454
|
+
self.assertAlmostEqual(apds['start'][0], 1, places=0)
|
|
455
|
+
self.assertAlmostEqual(apds['start'][1], 1001, places=0)
|
|
456
|
+
self.assertIn('start', apds)
|
|
457
|
+
self.assertAlmostEqual(apds['duration'][0], 383.877194, places=1)
|
|
458
|
+
self.assertAlmostEqual(apds['duration'][1], 378.315915, places=1)
|
|
459
|
+
|
|
460
|
+
# Works with variable objects too
|
|
461
|
+
self.sim.reset()
|
|
462
|
+
res = self.sim.run(
|
|
463
|
+
1000, log=['engine.time', 'membrane.V'],
|
|
464
|
+
apd_variable=self.model.get('membrane.V'), apd_threshold=-70)
|
|
245
465
|
|
|
246
466
|
# Apd var is not a state
|
|
247
467
|
self.assertRaisesRegex(
|
|
@@ -335,12 +555,53 @@ class SimulationTest(unittest.TestCase):
|
|
|
335
555
|
self.sim.set_state(s1)
|
|
336
556
|
self.assertEqual(d1, self.sim.eval_derivatives())
|
|
337
557
|
|
|
338
|
-
def
|
|
558
|
+
def test_eval_derivatives_with_pacing(self):
|
|
559
|
+
# Test :meth:`Simulation.eval_derivatives()`.
|
|
560
|
+
|
|
561
|
+
model = myokit.Model()
|
|
562
|
+
c = model.add_component('c')
|
|
563
|
+
|
|
564
|
+
a = c.add_variable('a')
|
|
565
|
+
a.set_binding('a')
|
|
566
|
+
a.set_rhs(0)
|
|
567
|
+
b = c.add_variable('b')
|
|
568
|
+
b.set_binding('b')
|
|
569
|
+
b.set_rhs(0)
|
|
570
|
+
|
|
571
|
+
y = c.add_variable('y')
|
|
572
|
+
t = c.add_variable('t')
|
|
573
|
+
t.set_binding('time')
|
|
574
|
+
t.set_rhs(0)
|
|
575
|
+
y.promote(1)
|
|
576
|
+
y.set_rhs('- a * y - b * y')
|
|
577
|
+
|
|
578
|
+
pa = myokit.Protocol()
|
|
579
|
+
pa.schedule(1, 0, 0.5)
|
|
580
|
+
|
|
581
|
+
pb = myokit.Protocol()
|
|
582
|
+
pb.schedule(2, 1.0, 0.5)
|
|
583
|
+
|
|
584
|
+
sim = myokit.Simulation(model, {'a': pa, 'b': pb})
|
|
585
|
+
sim.run(1)
|
|
586
|
+
d1 = sim.eval_derivatives(pacing={'a': 0.5, 'b': 0.5})
|
|
587
|
+
d2 = sim.eval_derivatives(pacing={'a': 1.5, 'b': 0.5})
|
|
588
|
+
self.assertNotEqual(d1, d2)
|
|
589
|
+
d1 = sim.eval_derivatives(pacing={'b': 0.5})
|
|
590
|
+
d2 = sim.eval_derivatives(pacing={'a': 0.0, 'b': 0.5})
|
|
591
|
+
self.assertEqual(d1, d2)
|
|
592
|
+
d1 = sim.eval_derivatives()
|
|
593
|
+
d2 = sim.eval_derivatives(pacing={'a': 0.0, 'b': 0.0})
|
|
594
|
+
self.assertEqual(d1, d2)
|
|
595
|
+
d1 = sim.eval_derivatives(pacing={'a': 0.0, 'b': 0.5})
|
|
596
|
+
d2 = sim.eval_derivatives(pacing={'aaaaa': 1.0, 'b': 0.5})
|
|
597
|
+
self.assertEqual(d1, d2)
|
|
598
|
+
|
|
599
|
+
def test_sensitivities_initial(self):
|
|
339
600
|
# Test setting initial sensitivity values.
|
|
340
601
|
|
|
341
602
|
m = myokit.parse_model('''
|
|
342
603
|
[[model]]
|
|
343
|
-
e.y =
|
|
604
|
+
e.y = 1 + 1.3
|
|
344
605
|
|
|
345
606
|
[e]
|
|
346
607
|
t = 0 bind time
|
|
@@ -352,6 +613,26 @@ class SimulationTest(unittest.TestCase):
|
|
|
352
613
|
#TODO: Test results
|
|
353
614
|
s = myokit.Simulation(m, sensitivities=(['e.y'], ['e.p', 'init(e.y)']))
|
|
354
615
|
|
|
616
|
+
# Warn if a parameter sensitivity won't be picked up.
|
|
617
|
+
m = myokit.parse_model('''
|
|
618
|
+
[[model]]
|
|
619
|
+
c.x = 1 / c.p
|
|
620
|
+
|
|
621
|
+
[c]
|
|
622
|
+
t = 0 bind time
|
|
623
|
+
p = 1 / q
|
|
624
|
+
q = 5
|
|
625
|
+
r = 3
|
|
626
|
+
dot(x) = 2 + r
|
|
627
|
+
''')
|
|
628
|
+
m.validate()
|
|
629
|
+
s = (['c.x'], ['c.q'])
|
|
630
|
+
self.assertRaisesRegex(
|
|
631
|
+
NotImplementedError, 'respect to parameters used in initial',
|
|
632
|
+
myokit.Simulation, m, sensitivities=s)
|
|
633
|
+
s = (['c.x'], ['c.r'])
|
|
634
|
+
s = myokit.Simulation(m, sensitivities=s)
|
|
635
|
+
|
|
355
636
|
# Test bad initial matrix
|
|
356
637
|
self.assertRaisesRegex(
|
|
357
638
|
ValueError, 'None or a list',
|
|
@@ -539,8 +820,8 @@ class SimulationTest(unittest.TestCase):
|
|
|
539
820
|
''')
|
|
540
821
|
m.validate()
|
|
541
822
|
|
|
542
|
-
x0 = m.get('e.x').
|
|
543
|
-
y0 = m.get('e.y').
|
|
823
|
+
x0 = m.get('e.x').initial_value(True)
|
|
824
|
+
y0 = m.get('e.y').initial_value(True)
|
|
544
825
|
p = m.get('e.p').eval()
|
|
545
826
|
q = m.get('e.q').eval()
|
|
546
827
|
r = m.get('e.r').eval()
|
|
@@ -693,6 +974,7 @@ class SimulationTest(unittest.TestCase):
|
|
|
693
974
|
|
|
694
975
|
# Literal
|
|
695
976
|
self.sim.set_constant('cell.Na_i', 11)
|
|
977
|
+
self.sim.set_constant(self.model.get('cell.Na_i'), 11)
|
|
696
978
|
self.assertRaises(KeyError, self.sim.set_constant, 'cell.Bert', 11)
|
|
697
979
|
|
|
698
980
|
# Parameter (needs sensitivies set)
|
|
@@ -786,6 +1068,7 @@ class SimulationTest(unittest.TestCase):
|
|
|
786
1068
|
z.promote(0)
|
|
787
1069
|
|
|
788
1070
|
# Test without protocol and dynamic logging
|
|
1071
|
+
#myokit.DEBUG_WG = True
|
|
789
1072
|
s1 = myokit.Simulation(m1)
|
|
790
1073
|
d1 = s1.run(5)
|
|
791
1074
|
self.assertEqual(len(d1.time()), 2)
|
|
@@ -886,23 +1169,6 @@ class SimulationTest(unittest.TestCase):
|
|
|
886
1169
|
self.assertTrue(np.all(rt[1:] >= rt[:-1]))
|
|
887
1170
|
self.assertTrue(np.all(ev[1:] >= ev[:-1]))
|
|
888
1171
|
|
|
889
|
-
def test_apd(self):
|
|
890
|
-
# Test the apd rootfinding routine
|
|
891
|
-
|
|
892
|
-
s = myokit.Simulation(self.model, self.protocol)
|
|
893
|
-
s.set_tolerance(1e-8, 1e-8)
|
|
894
|
-
d, apds = s.run(
|
|
895
|
-
1800, log=myokit.LOG_NONE,
|
|
896
|
-
apd_variable='membrane.V', apd_threshold=-70)
|
|
897
|
-
|
|
898
|
-
# Check with threshold equal to V
|
|
899
|
-
self.assertEqual(len(apds['start']), 2)
|
|
900
|
-
self.assertEqual(len(apds['duration']), 2)
|
|
901
|
-
self.assertAlmostEqual(apds['start'][0], 1.19, places=1)
|
|
902
|
-
self.assertAlmostEqual(apds['start'][1], 1001.19, places=1)
|
|
903
|
-
self.assertAlmostEqual(apds['duration'][0], 383.88262, places=1)
|
|
904
|
-
self.assertAlmostEqual(apds['duration'][1], 378.31448, places=1)
|
|
905
|
-
|
|
906
1172
|
def test_derivatives(self):
|
|
907
1173
|
# Tests logging of derivatives by comparing with a finite difference
|
|
908
1174
|
# approximation
|
|
@@ -5,11 +5,9 @@
|
|
|
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
8
|
import os
|
|
12
9
|
import unittest
|
|
10
|
+
|
|
13
11
|
import numpy as np
|
|
14
12
|
|
|
15
13
|
import myokit
|
|
@@ -21,13 +19,6 @@ from myokit.tests import (
|
|
|
21
19
|
WarningCollector,
|
|
22
20
|
)
|
|
23
21
|
|
|
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
22
|
# Show simulation output
|
|
32
23
|
debug = False
|
|
33
24
|
|
|
@@ -535,7 +526,7 @@ class FiberTissueSimulationTest(unittest.TestCase):
|
|
|
535
526
|
m = self.mf.count_states()
|
|
536
527
|
nx, ny = self.nfx, self.nfy
|
|
537
528
|
|
|
538
|
-
sm = self.mf.
|
|
529
|
+
sm = self.mf.initial_values(True)
|
|
539
530
|
for i in range(nx):
|
|
540
531
|
for j in range(ny):
|
|
541
532
|
self.assertEqual(sm, self.s1.fiber_state(i, j))
|
|
@@ -622,6 +613,42 @@ class FiberTissueSimulationTest(unittest.TestCase):
|
|
|
622
613
|
finally:
|
|
623
614
|
self.s1.reset()
|
|
624
615
|
|
|
616
|
+
def test_initial_value_expressions(self):
|
|
617
|
+
# Test if initial value expressions are converted to floats
|
|
618
|
+
m = myokit.parse_model('''
|
|
619
|
+
[[model]]
|
|
620
|
+
c.x = 1 + sqrt(3)
|
|
621
|
+
c.y = 1 / c.p
|
|
622
|
+
c.z = 3
|
|
623
|
+
|
|
624
|
+
[c]
|
|
625
|
+
t = 0 bind time
|
|
626
|
+
dot(x) = 1 label membrane_potential
|
|
627
|
+
in [mV]
|
|
628
|
+
dot(y) = 2
|
|
629
|
+
dot(z) = 3
|
|
630
|
+
p = log(3)
|
|
631
|
+
q = 0 bind diffusion_current
|
|
632
|
+
in [A/F]
|
|
633
|
+
''')
|
|
634
|
+
s = myokit.FiberTissueSimulation(
|
|
635
|
+
m, m, ncells_fiber=(1, 1), ncells_tissue=(3, 1))
|
|
636
|
+
x = s.fiber_state()
|
|
637
|
+
self.assertIsInstance(x[0], float)
|
|
638
|
+
self.assertIsInstance(x[1], float)
|
|
639
|
+
self.assertIsInstance(x[2], float)
|
|
640
|
+
self.assertEqual(x, m.initial_values(True))
|
|
641
|
+
self.assertEqual(x, s.default_fiber_state())
|
|
642
|
+
|
|
643
|
+
x = s.tissue_state()
|
|
644
|
+
self.assertIsInstance(x[0], float)
|
|
645
|
+
self.assertIsInstance(x[1], float)
|
|
646
|
+
self.assertIsInstance(x[2], float)
|
|
647
|
+
self.assertEqual(x[:3], x[3:6])
|
|
648
|
+
self.assertEqual(x[:3], x[6:])
|
|
649
|
+
self.assertEqual(x, m.initial_values(True) * 3)
|
|
650
|
+
self.assertEqual(x, s.default_tissue_state())
|
|
651
|
+
|
|
625
652
|
def test_tissue_state(self):
|
|
626
653
|
# Test the set_tissue_state and set_default_tissue_state methods
|
|
627
654
|
|
|
@@ -629,7 +656,7 @@ class FiberTissueSimulationTest(unittest.TestCase):
|
|
|
629
656
|
m = self.mt.count_states()
|
|
630
657
|
nx, ny = self.ntx, self.nty
|
|
631
658
|
|
|
632
|
-
sm = self.mt.
|
|
659
|
+
sm = self.mt.initial_values(True)
|
|
633
660
|
for i in range(nx):
|
|
634
661
|
for j in range(ny):
|
|
635
662
|
self.assertEqual(sm, self.s1.tissue_state(i, j))
|