myokit 1.35.0__py3-none-any.whl → 1.35.2__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 +11 -14
- myokit/__main__.py +0 -3
- myokit/_config.py +1 -3
- myokit/_datablock.py +914 -12
- myokit/_model_api.py +1 -3
- myokit/_myokit_version.py +1 -1
- myokit/_protocol.py +14 -28
- myokit/_sim/cable.c +1 -1
- myokit/_sim/cable.py +3 -2
- myokit/_sim/cmodel.h +1 -0
- myokit/_sim/cvodessim.c +79 -42
- myokit/_sim/cvodessim.py +20 -8
- myokit/_sim/fiber_tissue.c +1 -1
- myokit/_sim/fiber_tissue.py +3 -2
- myokit/_sim/openclsim.c +1 -1
- myokit/_sim/openclsim.py +8 -11
- myokit/_sim/pacing.h +121 -106
- myokit/_unit.py +1 -1
- myokit/formats/__init__.py +178 -0
- myokit/formats/axon/_abf.py +911 -841
- myokit/formats/axon/_atf.py +62 -59
- myokit/formats/axon/_importer.py +2 -2
- myokit/formats/heka/__init__.py +38 -0
- myokit/formats/heka/_importer.py +39 -0
- myokit/formats/heka/_patchmaster.py +2512 -0
- myokit/formats/wcp/_wcp.py +318 -133
- myokit/gui/datablock_viewer.py +144 -77
- myokit/gui/datalog_viewer.py +212 -231
- myokit/tests/ansic_event_based_pacing.py +3 -3
- myokit/tests/{ansic_fixed_form_pacing.py → ansic_time_series_pacing.py} +6 -6
- myokit/tests/data/formats/abf-v2.abf +0 -0
- myokit/tests/test_datablock.py +84 -0
- myokit/tests/test_datalog.py +2 -1
- myokit/tests/test_formats_axon.py +589 -136
- myokit/tests/test_formats_wcp.py +191 -22
- myokit/tests/test_pacing_system_c.py +51 -23
- myokit/tests/test_pacing_system_py.py +18 -0
- myokit/tests/test_simulation_1d.py +62 -22
- myokit/tests/test_simulation_cvodes.py +52 -3
- myokit/tests/test_simulation_fiber_tissue.py +35 -4
- myokit/tests/test_simulation_opencl.py +28 -4
- {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/LICENSE.txt +1 -1
- {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/METADATA +1 -1
- {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/RECORD +47 -44
- {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/WHEEL +0 -0
- {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/entry_points.txt +0 -0
- {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/top_level.txt +0 -0
myokit/tests/test_formats_wcp.py
CHANGED
|
@@ -10,9 +10,77 @@ import unittest
|
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
|
|
13
|
+
import myokit
|
|
13
14
|
import myokit.formats.wcp as wcp
|
|
14
15
|
|
|
15
|
-
from myokit.tests import DIR_FORMATS
|
|
16
|
+
from myokit.tests import DIR_FORMATS, WarningCollector
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
INFO = '''
|
|
20
|
+
WinWCP file: wcp-file.wcp
|
|
21
|
+
WinWCP Format version 9
|
|
22
|
+
Recorded on: 21/11/2014 14:18:28
|
|
23
|
+
Number of records: 11
|
|
24
|
+
Channels per record: 2
|
|
25
|
+
Samples per channel: 256
|
|
26
|
+
Sampling interval: 0.001 s
|
|
27
|
+
A/D channel: Im
|
|
28
|
+
Unit: pA
|
|
29
|
+
A/D channel: Vm
|
|
30
|
+
Unit: mV
|
|
31
|
+
Records: Type, Status, Sampling Interval, Start, Marker
|
|
32
|
+
Record 0: TEST, ACCEPTED, 0.0, ""
|
|
33
|
+
Record 1: TEST, ACCEPTED, 0.5, ""
|
|
34
|
+
Record 2: TEST, ACCEPTED, 1.0, ""
|
|
35
|
+
Record 3: TEST, ACCEPTED, 1.5, ""
|
|
36
|
+
Record 4: TEST, ACCEPTED, 2.0615234375, ""
|
|
37
|
+
Record 5: TEST, ACCEPTED, 3.0615234375, ""
|
|
38
|
+
Record 6: TEST, ACCEPTED, 3.5615234375, ""
|
|
39
|
+
Record 7: TEST, ACCEPTED, 4.0615234375, ""
|
|
40
|
+
Record 8: TEST, ACCEPTED, 4.5615234375, ""
|
|
41
|
+
Record 9: TEST, ACCEPTED, 5.125, ""
|
|
42
|
+
Record 10: TEST, ACCEPTED, 5.625, ""
|
|
43
|
+
'''.strip()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
INFO_LONG = INFO + '''
|
|
47
|
+
----------------------------------- header -----------------------------------
|
|
48
|
+
ver: 9
|
|
49
|
+
ctime: 21/11/2014 12:43:08
|
|
50
|
+
rtime: 21/11/2014 14:18:28
|
|
51
|
+
nbh: 1024
|
|
52
|
+
adcmax: 32677
|
|
53
|
+
nc: 2
|
|
54
|
+
nba: 2
|
|
55
|
+
nbd: 2
|
|
56
|
+
ad: 10.0
|
|
57
|
+
nr: 11
|
|
58
|
+
dt: 0.001
|
|
59
|
+
nz: 20
|
|
60
|
+
id: ''' + '''
|
|
61
|
+
--------------------------------- raw header ---------------------------------
|
|
62
|
+
rtimesecs: 9062.11
|
|
63
|
+
yo0: 0
|
|
64
|
+
yu0: pA
|
|
65
|
+
yn0: Im
|
|
66
|
+
yg0: 0.0005
|
|
67
|
+
yz0: 0
|
|
68
|
+
yr0: 0
|
|
69
|
+
yo1: 1
|
|
70
|
+
yu1: mV
|
|
71
|
+
yn1: Vm
|
|
72
|
+
yg1: 0.01
|
|
73
|
+
yz1: 0
|
|
74
|
+
yr1: 0
|
|
75
|
+
txperc: 0
|
|
76
|
+
pkpavg: 1
|
|
77
|
+
nsvchan: 0
|
|
78
|
+
nsvalign: 0
|
|
79
|
+
nsvtypr: 0
|
|
80
|
+
nsvs2p: F
|
|
81
|
+
nsvcur0: 0
|
|
82
|
+
nsvcur1: 0
|
|
83
|
+
'''.rstrip()
|
|
16
84
|
|
|
17
85
|
|
|
18
86
|
class WcpTest(unittest.TestCase):
|
|
@@ -23,43 +91,144 @@ class WcpTest(unittest.TestCase):
|
|
|
23
91
|
def test_data_file(self):
|
|
24
92
|
# Test basic wcp file reading.
|
|
25
93
|
|
|
26
|
-
# Load
|
|
94
|
+
# Load test file
|
|
27
95
|
fname = 'wcp-file.wcp'
|
|
28
96
|
path = os.path.join(DIR_FORMATS, fname)
|
|
29
97
|
w = wcp.WcpFile(path)
|
|
98
|
+
self.assertEqual(w.version(), '9')
|
|
30
99
|
|
|
31
|
-
self.assertEqual(w.channels(), 2)
|
|
32
|
-
self.assertEqual(w.channel_names(), ['Im', 'Vm'])
|
|
33
100
|
self.assertEqual(w.filename(), fname)
|
|
34
101
|
self.assertEqual(w.path(), path)
|
|
35
|
-
self.assertEqual(w.
|
|
36
|
-
|
|
102
|
+
self.assertEqual(w.record_count(), 11)
|
|
103
|
+
self.assertEqual(w.sample_count(), 256)
|
|
37
104
|
self.assertEqual(len(w.times()), 256)
|
|
38
105
|
self.assertEqual(len(w.values(0, 0)), 256)
|
|
39
106
|
|
|
40
|
-
|
|
41
|
-
|
|
107
|
+
# Test meta data
|
|
108
|
+
self.maxDiff = None
|
|
109
|
+
self.assertEqual(w.meta_str(), INFO)
|
|
110
|
+
self.assertEqual(w.meta_str(True), INFO_LONG)
|
|
111
|
+
with WarningCollector() as c:
|
|
112
|
+
self.assertEqual(w.info(), INFO)
|
|
113
|
+
self.assertIn('deprecated', c.text())
|
|
42
114
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
for
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
self.assertEqual(
|
|
50
|
-
self.assertEqual(
|
|
51
|
-
self.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
115
|
+
# Test Sequence interface
|
|
116
|
+
self.assertEqual(len(w), w.record_count())
|
|
117
|
+
self.assertEqual(np.array(w[0]).shape, (2, 256))
|
|
118
|
+
self.assertEqual(len([r for r in w]), w.record_count())
|
|
119
|
+
|
|
120
|
+
# Test SweepSource interface
|
|
121
|
+
self.assertEqual(w.channel_count(), 2)
|
|
122
|
+
self.assertEqual(w.channel_names(), ['Im', 'Vm'])
|
|
123
|
+
self.assertEqual(w.channel_units(), [myokit.units.pA, myokit.units.mV])
|
|
124
|
+
self.assertEqual(w.channel_names(0), 'Im')
|
|
125
|
+
self.assertEqual(w.channel_names(1), 'Vm')
|
|
126
|
+
self.assertEqual(w.channel_units(0), myokit.units.pA)
|
|
127
|
+
self.assertEqual(w.channel_units(1), myokit.units.mV)
|
|
128
|
+
self.assertEqual(w.sweep_count(), w.record_count())
|
|
129
|
+
self.assertTrue(w.equal_length_sweeps())
|
|
130
|
+
self.assertEqual(w.time_unit(), myokit.units.s)
|
|
131
|
+
|
|
132
|
+
# Test SweepSource.channel()
|
|
133
|
+
# Without joining
|
|
134
|
+
t0, v0 = w.channel(0)
|
|
135
|
+
t1, v1 = w.channel(1)
|
|
136
|
+
self.assertEqual(len(t0), len(t1), w.sweep_count())
|
|
137
|
+
self.assertEqual(len(v0), len(v1), w.sweep_count())
|
|
138
|
+
self.assertEqual(len(t0[0]), w.sample_count())
|
|
139
|
+
self.assertEqual(len(t1[1]), w.sample_count())
|
|
140
|
+
self.assertEqual(len(v0[2]), w.sample_count())
|
|
141
|
+
self.assertEqual(len(v1[3]), w.sample_count())
|
|
142
|
+
self.assertTrue(np.all(v0[0] == w.channel('Im')[1][0]))
|
|
143
|
+
self.assertTrue(np.all(v0[0] != w.channel('Vm')[1][0]))
|
|
144
|
+
self.assertTrue(np.all(v1[1] == w.channel('Vm')[1][1]))
|
|
145
|
+
|
|
146
|
+
# With joining
|
|
147
|
+
x = w.channel(0, join_sweeps=True)
|
|
148
|
+
y = w.channel(1, join_sweeps=True)
|
|
149
|
+
self.assertEqual(len(x), len(y), 2)
|
|
150
|
+
self.assertEqual(len(x[0]), w.sample_count() * w.sweep_count())
|
|
151
|
+
self.assertEqual(len(x[0]), len(x[1]))
|
|
152
|
+
self.assertEqual(len(x[0]), len(y[0]), len(y[1]))
|
|
153
|
+
self.assertTrue(np.all(x[1] == w.channel('Im', True)[1]))
|
|
154
|
+
self.assertTrue(np.all(x[1] != w.channel('Vm', True)[1]))
|
|
155
|
+
self.assertTrue(np.all(y[1] == w.channel('Vm', True)[1]))
|
|
156
|
+
|
|
157
|
+
# Channel doesn't exist
|
|
158
|
+
self.assertRaises(IndexError, w.channel, -1)
|
|
159
|
+
self.assertRaises(IndexError, w.channel, 2)
|
|
160
|
+
self.assertRaises(KeyError, w.channel, 'Tom')
|
|
55
161
|
|
|
162
|
+
# Conversion to log
|
|
163
|
+
# Without joining
|
|
164
|
+
d = w.log()
|
|
165
|
+
k = ['time']
|
|
166
|
+
for r in range(w.record_count()):
|
|
167
|
+
for c in range(w.channel_count()):
|
|
168
|
+
k.append(f'{r}.{c}.channel')
|
|
169
|
+
self.assertEqual(set(k), set(d.keys()))
|
|
170
|
+
self.assertTrue(np.all(d['time'] == w.channel(0)[0][0]))
|
|
171
|
+
self.assertTrue(np.all(d['1.0.channel'] == w.channel(0)[1][1]))
|
|
172
|
+
|
|
173
|
+
# Without joining, use names
|
|
174
|
+
d = w.log(use_names=True)
|
|
175
|
+
k = ['time']
|
|
176
|
+
for c in w.channel_names():
|
|
177
|
+
for r in range(w.record_count()):
|
|
178
|
+
k.append(f'{r}.{c}')
|
|
179
|
+
self.assertEqual(set(k), set(d.keys()))
|
|
180
|
+
self.assertTrue(np.all(d['time'] == w.channel(0)[0][0]))
|
|
181
|
+
self.assertTrue(np.all(d['1.Im'] == w.channel(0)[1][1]))
|
|
182
|
+
|
|
183
|
+
# With joining
|
|
184
|
+
d = w.log(join_sweeps=True)
|
|
185
|
+
self.assertEqual(list(d.keys()), ['time', '0.channel', '1.channel'])
|
|
186
|
+
self.assertTrue(np.all(d['time'] == w.channel(0, True)[0]))
|
|
187
|
+
self.assertTrue(np.all(d['0.channel'] == w.channel(0, True)[1]))
|
|
188
|
+
|
|
189
|
+
# With joining, use names
|
|
190
|
+
d = w.log(join_sweeps=True, use_names=True)
|
|
191
|
+
self.assertEqual(list(d.keys()), ['time', 'Im', 'Vm'])
|
|
192
|
+
self.assertTrue(np.all(d['time'] == w.channel(0, True)[0]))
|
|
193
|
+
self.assertTrue(np.all(d['Vm'] == w.channel(1, True)[1]))
|
|
194
|
+
|
|
195
|
+
# Deprecated methods
|
|
196
|
+
with WarningCollector() as c:
|
|
197
|
+
self.assertEqual(w.records(), w.record_count())
|
|
198
|
+
self.assertIn('deprecated', c.text())
|
|
199
|
+
with WarningCollector() as c:
|
|
200
|
+
self.assertEqual(w.channels(), w.channel_count())
|
|
201
|
+
self.assertIn('deprecated', c.text())
|
|
202
|
+
with WarningCollector() as c:
|
|
203
|
+
e = w.myokit_log()
|
|
204
|
+
self.assertIn('deprecated', c.text())
|
|
205
|
+
|
|
206
|
+
# Unsupported da methods
|
|
207
|
+
self.assertEqual(w.da_count(), 0)
|
|
208
|
+
self.assertRaises(NotImplementedError, w.da, 0)
|
|
209
|
+
self.assertRaises(NotImplementedError, w.da_names)
|
|
210
|
+
self.assertRaises(NotImplementedError, w.da_units)
|
|
211
|
+
self.assertRaises(NotImplementedError, w.da_protocol)
|
|
212
|
+
|
|
213
|
+
def test_figure_method(self):
|
|
214
|
+
# Tests matplotlib_figure
|
|
56
215
|
# Select matplotlib backend that doesn't require a screen
|
|
57
216
|
import matplotlib
|
|
58
217
|
matplotlib.use('template')
|
|
218
|
+
w = wcp.WcpFile(os.path.join(DIR_FORMATS, 'wcp-file.wcp'))
|
|
219
|
+
f = w.matplotlib_figure()
|
|
220
|
+
self.assertIsInstance(f, matplotlib.figure.Figure)
|
|
59
221
|
|
|
60
|
-
|
|
222
|
+
def test_figure_method_deprecated(self):
|
|
223
|
+
# Tests matplotlib_figure
|
|
224
|
+
# Select matplotlib backend that doesn't require a screen
|
|
225
|
+
import matplotlib
|
|
226
|
+
matplotlib.use('template')
|
|
61
227
|
w = wcp.WcpFile(os.path.join(DIR_FORMATS, 'wcp-file.wcp'))
|
|
62
|
-
|
|
228
|
+
with WarningCollector() as c:
|
|
229
|
+
f = w.plot()
|
|
230
|
+
self.assertIn('deprecated', c.text())
|
|
231
|
+
self.assertIsNone(f, matplotlib.figure.Figure)
|
|
63
232
|
|
|
64
233
|
|
|
65
234
|
if __name__ == '__main__':
|
|
@@ -11,7 +11,7 @@ import numpy as np
|
|
|
11
11
|
import myokit
|
|
12
12
|
|
|
13
13
|
from myokit.tests.ansic_event_based_pacing import AnsicEventBasedPacing
|
|
14
|
-
from myokit.tests.
|
|
14
|
+
from myokit.tests.ansic_time_series_pacing import AnsicTimeSeriesPacing
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class EventBasedPacingAnsicTest(unittest.TestCase):
|
|
@@ -96,12 +96,30 @@ class EventBasedPacingAnsicTest(unittest.TestCase):
|
|
|
96
96
|
s = myokit.Simulation(m, p)
|
|
97
97
|
self.assertRaises(myokit.SimultaneousProtocolEventError, s.run, 40)
|
|
98
98
|
|
|
99
|
+
def test_negative_time(self):
|
|
100
|
+
# Test starting from a negative time
|
|
99
101
|
|
|
100
|
-
|
|
102
|
+
p = myokit.pacing.blocktrain(level=1, duration=1, period=2)
|
|
103
|
+
s = AnsicEventBasedPacing(p, initial_time=-100)
|
|
104
|
+
self.assertEqual(s.time(), -100)
|
|
105
|
+
self.assertEqual(s.next_time(), 0)
|
|
106
|
+
self.assertEqual(s.pace(), 0)
|
|
107
|
+
|
|
108
|
+
p = myokit.pacing.blocktrain(level=1, duration=1, period=2, offset=1)
|
|
109
|
+
s = AnsicEventBasedPacing(p, initial_time=-100)
|
|
110
|
+
self.assertEqual(s.time(), -100)
|
|
111
|
+
self.assertEqual(s.next_time(), 1)
|
|
112
|
+
self.assertEqual(s.pace(), 0)
|
|
113
|
+
s.advance(s.next_time())
|
|
114
|
+
self.assertEqual(s.time(), 1)
|
|
115
|
+
self.assertEqual(s.pace(), 1)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class TimeSeriesPacingAnsicTest(unittest.TestCase):
|
|
101
119
|
"""
|
|
102
|
-
Test the Ansi-C
|
|
120
|
+
Test the Ansi-C time-series pacing system (aka point-list, aka data-clamp).
|
|
103
121
|
"""
|
|
104
|
-
def
|
|
122
|
+
def test_time_series_pacing_ansic(self):
|
|
105
123
|
# Tests if the basics work
|
|
106
124
|
|
|
107
125
|
if False:
|
|
@@ -136,27 +154,37 @@ class FixedFormPacingAnsicTest(unittest.TestCase):
|
|
|
136
154
|
sys.exit(1)
|
|
137
155
|
|
|
138
156
|
# Test with small lists
|
|
139
|
-
values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
|
|
140
157
|
times = [0, 0, 1, 1, 1, 2, 2, 2, 3, 4, 5, 7]
|
|
141
158
|
values = list(range(len(times)))
|
|
142
|
-
pacing =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
pacing = AnsicTimeSeriesPacing(
|
|
160
|
+
myokit.TimeSeriesProtocol(times, values))
|
|
161
|
+
|
|
162
|
+
self.assertEqual(pacing.pace(-1), 0)
|
|
163
|
+
self.assertEqual(pacing.pace(0), 1)
|
|
164
|
+
self.assertEqual(pacing.pace(1), 2)
|
|
165
|
+
self.assertEqual(pacing.pace(2), 5)
|
|
166
|
+
self.assertEqual(pacing.pace(3), 8)
|
|
167
|
+
self.assertEqual(pacing.pace(4), 9)
|
|
168
|
+
self.assertEqual(pacing.pace(5), 10)
|
|
169
|
+
self.assertEqual(pacing.pace(7), 11)
|
|
170
|
+
self.assertEqual(pacing.pace(8), 11)
|
|
171
|
+
self.assertEqual(pacing.pace(1.5), 4.5)
|
|
172
|
+
self.assertEqual(pacing.pace(1.75), 4.75)
|
|
173
|
+
self.assertEqual(pacing.pace(6), 10.5)
|
|
174
|
+
self.assertEqual(pacing.pace(5.5), 10.25)
|
|
175
|
+
|
|
176
|
+
# Test not starting at 0
|
|
177
|
+
times = [1, 2]
|
|
178
|
+
values = [10, 20]
|
|
179
|
+
pacing = AnsicTimeSeriesPacing(
|
|
180
|
+
myokit.TimeSeriesProtocol(times, values))
|
|
181
|
+
|
|
182
|
+
self.assertEqual(pacing.pace(-1), 10)
|
|
183
|
+
self.assertEqual(pacing.pace(0), 10)
|
|
184
|
+
self.assertEqual(pacing.pace(1), 10)
|
|
185
|
+
self.assertEqual(pacing.pace(2), 20)
|
|
186
|
+
self.assertEqual(pacing.pace(3), 20)
|
|
187
|
+
self.assertEqual(pacing.pace(1.5), 15)
|
|
160
188
|
|
|
161
189
|
|
|
162
190
|
if __name__ == '__main__':
|
|
@@ -89,6 +89,24 @@ class EventBasedPacingPythonTest(unittest.TestCase):
|
|
|
89
89
|
m = str(e.exception)
|
|
90
90
|
self.assertEqual(float(m[2 + m.index('t='):-1]), 3000)
|
|
91
91
|
|
|
92
|
+
def test_negative_time(self):
|
|
93
|
+
# Test starting from a negative time
|
|
94
|
+
|
|
95
|
+
p = myokit.pacing.blocktrain(level=1, duration=1, period=2)
|
|
96
|
+
s = myokit.PacingSystem(p, initial_time=-100)
|
|
97
|
+
self.assertEqual(s.time(), -100)
|
|
98
|
+
self.assertEqual(s.next_time(), 0)
|
|
99
|
+
self.assertEqual(s.pace(), 0)
|
|
100
|
+
|
|
101
|
+
p = myokit.pacing.blocktrain(level=1, duration=1, period=2, offset=1)
|
|
102
|
+
s = myokit.PacingSystem(p, initial_time=-100)
|
|
103
|
+
self.assertEqual(s.time(), -100)
|
|
104
|
+
self.assertEqual(s.next_time(), 1)
|
|
105
|
+
self.assertEqual(s.pace(), 0)
|
|
106
|
+
s.advance(s.next_time())
|
|
107
|
+
self.assertEqual(s.time(), 1)
|
|
108
|
+
self.assertEqual(s.pace(), 1)
|
|
109
|
+
|
|
92
110
|
|
|
93
111
|
if __name__ == '__main__':
|
|
94
112
|
unittest.main()
|
|
@@ -53,10 +53,6 @@ class Simulation1dTest(unittest.TestCase):
|
|
|
53
53
|
s.pre(1)
|
|
54
54
|
self.assertNotEqual(s.default_state(0), x0)
|
|
55
55
|
|
|
56
|
-
# Test running without a protocol
|
|
57
|
-
s.set_protocol(None)
|
|
58
|
-
s.run(1)
|
|
59
|
-
|
|
60
56
|
# Simulation time can't be negative
|
|
61
57
|
self.assertRaises(ValueError, s.run, -1)
|
|
62
58
|
|
|
@@ -121,26 +117,49 @@ class Simulation1dTest(unittest.TestCase):
|
|
|
121
117
|
self.assertEqual(x, m.initial_values(True) * 2)
|
|
122
118
|
self.assertEqual(x, s.default_state())
|
|
123
119
|
|
|
124
|
-
def
|
|
125
|
-
# Test
|
|
126
|
-
m, p, _ = myokit.load(os.path.join(DIR_DATA, 'lr-1991.mmt'))
|
|
120
|
+
def test_negative_time(self):
|
|
121
|
+
# Test starting at a negative time
|
|
127
122
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
self.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
self.
|
|
138
|
-
|
|
123
|
+
m = myokit.load_model(os.path.join(DIR_DATA, 'lr-1991.mmt'))
|
|
124
|
+
p = myokit.pacing.blocktrain(duration=1, level=1, period=2)
|
|
125
|
+
n = 4
|
|
126
|
+
s = myokit.Simulation1d(m, p, ncells=n)
|
|
127
|
+
|
|
128
|
+
s.set_time(-10)
|
|
129
|
+
self.assertEqual(s.time(), -10)
|
|
130
|
+
d = s.run(5, log=['engine.pace']).npview()
|
|
131
|
+
self.assertEqual(s.time(), -5)
|
|
132
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
133
|
+
d = s.run(6, log=['engine.time', 'engine.pace']).npview()
|
|
134
|
+
#print(d['engine.time'])
|
|
135
|
+
#print(d['engine.pace'])
|
|
136
|
+
self.assertEqual(s.time(), 1)
|
|
137
|
+
self.assertTrue(np.all(d['engine.pace'][:-1] == 0))
|
|
138
|
+
self.assertEqual(d['engine.pace'][-1], 1)
|
|
139
|
+
|
|
140
|
+
def test_no_protocol(self):
|
|
141
|
+
# Test running without a protocol
|
|
142
|
+
m = myokit.load_model(os.path.join(DIR_DATA, 'lr-1991.mmt'))
|
|
143
|
+
x = 0.123
|
|
144
|
+
m.get('engine.pace').set_rhs(x)
|
|
145
|
+
n = 4
|
|
139
146
|
|
|
140
|
-
#
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
# Create without a protocol
|
|
148
|
+
s = myokit.Simulation1d(m, ncells=n)
|
|
149
|
+
d = s.run(10, log=['engine.pace']).npview()
|
|
150
|
+
self.assertIn('engine.pace', d.keys())
|
|
151
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
152
|
+
|
|
153
|
+
# Set, then unset
|
|
154
|
+
y = 0.101
|
|
155
|
+
p = myokit.pacing.blocktrain(level=y, duration=100, period=100)
|
|
156
|
+
s.set_protocol(p)
|
|
157
|
+
d = s.run(5, log=['engine.pace']).npview()
|
|
158
|
+
self.assertTrue(np.all(d['engine.pace'] == y))
|
|
159
|
+
self.assertGreater(len(d['engine.pace']), 1)
|
|
160
|
+
s.set_protocol(None)
|
|
161
|
+
d = s.run(5, log=['engine.pace']).npview()
|
|
162
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
144
163
|
|
|
145
164
|
def test_set_state(self):
|
|
146
165
|
# Test :meth:`Simulation1d.set_state()`.
|
|
@@ -218,6 +237,27 @@ class Simulation1dTest(unittest.TestCase):
|
|
|
218
237
|
self.assertRaises(ValueError, s.default_state, -1)
|
|
219
238
|
self.assertRaises(ValueError, s.default_state, n)
|
|
220
239
|
|
|
240
|
+
def test_with_progress_reporter(self):
|
|
241
|
+
# Test running with a progress reporter.
|
|
242
|
+
m, p, _ = myokit.load(os.path.join(DIR_DATA, 'lr-1991.mmt'))
|
|
243
|
+
|
|
244
|
+
# Test using a progress reporter
|
|
245
|
+
s = myokit.Simulation1d(m, p, ncells=5)
|
|
246
|
+
s.set_step_size(0.05)
|
|
247
|
+
with myokit.tools.capture() as c:
|
|
248
|
+
s.run(110, progress=myokit.ProgressPrinter())
|
|
249
|
+
c = c.text().splitlines()
|
|
250
|
+
self.assertTrue(len(c) > 0)
|
|
251
|
+
|
|
252
|
+
# Not a progress reporter
|
|
253
|
+
self.assertRaisesRegex(
|
|
254
|
+
ValueError, 'ProgressReporter', s.run, 5, progress=12)
|
|
255
|
+
|
|
256
|
+
# Cancel from reporter
|
|
257
|
+
self.assertRaises(
|
|
258
|
+
myokit.SimulationCancelledError, s.run, 1,
|
|
259
|
+
progress=CancellingReporter(0))
|
|
260
|
+
|
|
221
261
|
def test_against_cvode(self):
|
|
222
262
|
# Compare the Simulation1d output with CVODE output
|
|
223
263
|
|
|
@@ -227,16 +227,65 @@ class SimulationTest(unittest.TestCase):
|
|
|
227
227
|
# sine value, while the solver will be interpolating y
|
|
228
228
|
np.testing.assert_array_almost_equal(d[b], b_e, decimal=3)
|
|
229
229
|
|
|
230
|
+
def test_negative_time(self):
|
|
231
|
+
# Test starting at a negative time
|
|
232
|
+
|
|
233
|
+
self.sim.reset()
|
|
234
|
+
self.sim.set_protocol(
|
|
235
|
+
myokit.pacing.blocktrain(duration=1, level=1, period=2))
|
|
236
|
+
self.sim.set_time(-10)
|
|
237
|
+
self.assertEqual(self.sim.time(), -10)
|
|
238
|
+
d = self.sim.run(5, log=['engine.pace']).npview()
|
|
239
|
+
self.assertEqual(self.sim.time(), -5)
|
|
240
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
241
|
+
d = self.sim.run(5, log=['engine.pace']).npview()
|
|
242
|
+
self.assertEqual(self.sim.time(), 0)
|
|
243
|
+
self.assertTrue(np.all(d['engine.pace'][:-1] == 0))
|
|
244
|
+
self.assertEqual(d['engine.pace'][-1], 1)
|
|
245
|
+
self.sim.set_protocol(self.protocol)
|
|
246
|
+
|
|
230
247
|
def test_no_protocol(self):
|
|
231
248
|
# Test running without a protocol.
|
|
232
249
|
|
|
250
|
+
# Check if pace was set to zero (see technical notes).
|
|
233
251
|
self.sim.reset()
|
|
234
252
|
self.sim.pre(50)
|
|
235
253
|
self.sim.set_protocol(None)
|
|
236
|
-
d = self.sim.run(50).npview()
|
|
254
|
+
d = self.sim.run(50, log=['engine.pace']).npview()
|
|
255
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
237
256
|
|
|
238
|
-
#
|
|
239
|
-
self.
|
|
257
|
+
# Defined at the start? Then still counts as bound
|
|
258
|
+
self.assertRaisesRegex(
|
|
259
|
+
ValueError, 'not a literal',
|
|
260
|
+
self.sim.set_constant, 'engine.pace', 1)
|
|
261
|
+
|
|
262
|
+
# Check that pace is reset to zero when protocol is removed
|
|
263
|
+
x = 0.01 # Note: Must be low to stop sim crashing :D
|
|
264
|
+
self.sim.set_protocol(
|
|
265
|
+
myokit.pacing.blocktrain(duration=1000, level=x, period=1000))
|
|
266
|
+
d = self.sim.run(5, log=['engine.pace']).npview()
|
|
267
|
+
self.assertTrue(np.all(d['engine.pace'] == x))
|
|
268
|
+
self.sim.set_protocol(None)
|
|
269
|
+
d = self.sim.run(5, log=['engine.pace']).npview()
|
|
270
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
271
|
+
self.sim.set_protocol(self.protocol)
|
|
272
|
+
|
|
273
|
+
# No protocol set from the start? Then "pace" is set anyway for
|
|
274
|
+
# backwards compatibility
|
|
275
|
+
m = self.model.clone()
|
|
276
|
+
m.get('engine.pace').set_rhs(x)
|
|
277
|
+
s = myokit.Simulation(m)
|
|
278
|
+
d = s.run(50).npview()
|
|
279
|
+
self.assertIn('engine.pace', d.keys())
|
|
280
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
281
|
+
|
|
282
|
+
# But if user explicitly says no labels, then pace isn't treated in a
|
|
283
|
+
# special way.
|
|
284
|
+
s = myokit.Simulation(m, {})
|
|
285
|
+
self.assertRaises(ValueError, s.set_protocol, self.protocol)
|
|
286
|
+
d = s.run(50).npview()
|
|
287
|
+
self.assertNotIn('engine.pace', d.keys())
|
|
288
|
+
#self.assertTrue(np.all(d['engine.pace'] == x)) constant is not logged
|
|
240
289
|
|
|
241
290
|
def test_wrong_label_set_pacing(self):
|
|
242
291
|
# Test set_pacing with incorrect label
|
|
@@ -383,6 +383,27 @@ class FiberTissueSimulationTest(unittest.TestCase):
|
|
|
383
383
|
ValueError, 'diffusion current must have the same unit',
|
|
384
384
|
FT, mf, m2)
|
|
385
385
|
|
|
386
|
+
def test_negative_time(self):
|
|
387
|
+
# Test starting at a negative time
|
|
388
|
+
|
|
389
|
+
p = myokit.pacing.blocktrain(duration=1, level=1, period=2)
|
|
390
|
+
self.s0.reset()
|
|
391
|
+
self.s0.set_protocol(p)
|
|
392
|
+
self.s0.set_time(-10)
|
|
393
|
+
self.assertEqual(self.s0.time(), -10)
|
|
394
|
+
df, dt = self.s0.run(5, logf=['engine.pace'], logt=myokit.LOG_NONE)
|
|
395
|
+
df = df.npview()
|
|
396
|
+
self.assertEqual(self.s0.time(), -5)
|
|
397
|
+
self.assertTrue(np.all(df['engine.pace'] == 0))
|
|
398
|
+
df, dt = self.s0.run(
|
|
399
|
+
6, logf=['engine.time', 'engine.pace'], logt=myokit.LOG_NONE)
|
|
400
|
+
df = df.npview()
|
|
401
|
+
#print(d['engine.time'])
|
|
402
|
+
#print(d['engine.pace'])
|
|
403
|
+
self.assertEqual(self.s0.time(), 1)
|
|
404
|
+
self.assertTrue(np.all(df['engine.pace'][:-1] == 0))
|
|
405
|
+
self.assertEqual(df['engine.pace'][-1], 1)
|
|
406
|
+
|
|
386
407
|
def test_pre_reset(self):
|
|
387
408
|
# Tests getting/setting of states and time, and use of pre() and run()
|
|
388
409
|
try:
|
|
@@ -468,15 +489,25 @@ class FiberTissueSimulationTest(unittest.TestCase):
|
|
|
468
489
|
self.assertGreater(df['membrane.V', 0, 0][-1], 0)
|
|
469
490
|
self.s0.reset()
|
|
470
491
|
|
|
471
|
-
#
|
|
492
|
+
# Run with constant proto
|
|
493
|
+
x = 0.0123
|
|
494
|
+
self.s0.set_protocol(
|
|
495
|
+
myokit.pacing.blocktrain(level=x, duration=1000, period=1000))
|
|
496
|
+
self.s0.reset()
|
|
497
|
+
df, dt = self.s0.run(3, logf=['engine.pace'])
|
|
498
|
+
df = df.npview()
|
|
499
|
+
self.assertTrue(np.all(df['engine.pace'] == x))
|
|
500
|
+
|
|
501
|
+
# Unset: Must now be zero
|
|
472
502
|
self.s0.set_protocol(None)
|
|
473
|
-
df, dt = self.s0.run(
|
|
474
|
-
5, logf=['membrane.V'], logt=myokit.LOG_NONE, log_interval=1)
|
|
475
|
-
self.assertLess(df['membrane.V', 0, 0][-1], 0)
|
|
476
503
|
self.s0.reset()
|
|
504
|
+
df, dt = self.s0.run(3, logf=['engine.pace'])
|
|
505
|
+
df = df.npview()
|
|
506
|
+
self.assertTrue(np.all(df['engine.pace'] == 0))
|
|
477
507
|
|
|
478
508
|
# Reset protocol, check Vm goes high
|
|
479
509
|
self.s0.set_protocol(self.p)
|
|
510
|
+
self.s0.reset()
|
|
480
511
|
df, dt = self.s0.run(
|
|
481
512
|
5, logf=['membrane.V'], logt=myokit.LOG_NONE, log_interval=1)
|
|
482
513
|
self.assertGreater(df['membrane.V', 0, 0][-1], 0)
|
|
@@ -682,6 +682,24 @@ class SimulationOpenCLTest(unittest.TestCase):
|
|
|
682
682
|
self.assertEqual(x, m.initial_values(True) * 2)
|
|
683
683
|
self.assertEqual(x, s.default_state())
|
|
684
684
|
|
|
685
|
+
def test_negative_time(self):
|
|
686
|
+
# Test starting at a negative time
|
|
687
|
+
|
|
688
|
+
p = myokit.pacing.blocktrain(duration=1, level=1, period=2)
|
|
689
|
+
self.s0.reset()
|
|
690
|
+
self.s0.set_protocol(p)
|
|
691
|
+
self.s0.set_time(-10)
|
|
692
|
+
self.assertEqual(self.s0.time(), -10)
|
|
693
|
+
d = self.s0.run(5, log=['engine.pace']).npview()
|
|
694
|
+
self.assertEqual(self.s0.time(), -5)
|
|
695
|
+
self.assertTrue(np.all(d['engine.pace'] == 0))
|
|
696
|
+
d = self.s0.run(6, log=['engine.time', 'engine.pace']).npview()
|
|
697
|
+
#print(d['engine.time'])
|
|
698
|
+
#print(d['engine.pace'])
|
|
699
|
+
self.assertEqual(self.s0.time(), 1)
|
|
700
|
+
self.assertTrue(np.all(d['engine.pace'][:-1] == 0))
|
|
701
|
+
self.assertEqual(d['engine.pace'][-1], 1)
|
|
702
|
+
|
|
685
703
|
def test_neighbors_0d(self):
|
|
686
704
|
# Test listing neighbors in a 0d simulation
|
|
687
705
|
|
|
@@ -813,11 +831,19 @@ class SimulationOpenCLTest(unittest.TestCase):
|
|
|
813
831
|
self.assertEqual(np.max(d0['engine.pace']), 1)
|
|
814
832
|
|
|
815
833
|
try:
|
|
816
|
-
#
|
|
834
|
+
# Make pace high
|
|
835
|
+
x = 0.0123
|
|
836
|
+
self.s0.set_protocol(
|
|
837
|
+
myokit.pacing.blocktrain(level=x, duration=1000, period=1000))
|
|
838
|
+
self.s0.reset()
|
|
839
|
+
d0 = self.s0.run(3, log=['engine.pace']).npview()
|
|
840
|
+
self.assertTrue(np.all(d0['engine.pace'] == x))
|
|
841
|
+
|
|
842
|
+
# Unset protocol: pace must now be 0
|
|
817
843
|
self.s0.reset()
|
|
818
844
|
self.s0.set_protocol(None)
|
|
819
845
|
d0 = self.s0.run(3, log=['engine.pace']).npview()
|
|
820
|
-
self.
|
|
846
|
+
self.assertTrue(np.all(d0['engine.pace'] == 0))
|
|
821
847
|
|
|
822
848
|
# Add new protocol
|
|
823
849
|
p = myokit.pacing.blocktrain(period=1000, duration=2, offset=3)
|
|
@@ -874,8 +900,6 @@ class SimulationOpenCLTest(unittest.TestCase):
|
|
|
874
900
|
self.assertEqual(self.s0.time(), 10)
|
|
875
901
|
self.s0.run(1)
|
|
876
902
|
self.assertEqual(self.s0.time(), 11)
|
|
877
|
-
self.assertRaisesRegex(
|
|
878
|
-
ValueError, 'negative', self.s0.set_time, -1)
|
|
879
903
|
|
|
880
904
|
# Test running for a negative amount of time
|
|
881
905
|
self.assertRaisesRegex(
|
|
@@ -3,7 +3,7 @@ BSD 3-Clause License
|
|
|
3
3
|
Copyright (c) 2011-2017 Maastricht University. All rights reserved.
|
|
4
4
|
Copyright (c) 2017-2020 University of Oxford. All rights reserved.
|
|
5
5
|
(University of Oxford means the Chancellor, Masters and Scholars of the University of Oxford, having an administrative office at Wellington Square, Oxford OX1 2JD, UK).
|
|
6
|
-
Copyright (c) 2020-
|
|
6
|
+
Copyright (c) 2020-2023 University of Nottingham. All rights reserved.
|
|
7
7
|
|
|
8
8
|
Redistribution and use in source and binary forms, with or without
|
|
9
9
|
modification, are permitted provided that the following conditions are met:
|