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.
Files changed (47) hide show
  1. myokit/__init__.py +11 -14
  2. myokit/__main__.py +0 -3
  3. myokit/_config.py +1 -3
  4. myokit/_datablock.py +914 -12
  5. myokit/_model_api.py +1 -3
  6. myokit/_myokit_version.py +1 -1
  7. myokit/_protocol.py +14 -28
  8. myokit/_sim/cable.c +1 -1
  9. myokit/_sim/cable.py +3 -2
  10. myokit/_sim/cmodel.h +1 -0
  11. myokit/_sim/cvodessim.c +79 -42
  12. myokit/_sim/cvodessim.py +20 -8
  13. myokit/_sim/fiber_tissue.c +1 -1
  14. myokit/_sim/fiber_tissue.py +3 -2
  15. myokit/_sim/openclsim.c +1 -1
  16. myokit/_sim/openclsim.py +8 -11
  17. myokit/_sim/pacing.h +121 -106
  18. myokit/_unit.py +1 -1
  19. myokit/formats/__init__.py +178 -0
  20. myokit/formats/axon/_abf.py +911 -841
  21. myokit/formats/axon/_atf.py +62 -59
  22. myokit/formats/axon/_importer.py +2 -2
  23. myokit/formats/heka/__init__.py +38 -0
  24. myokit/formats/heka/_importer.py +39 -0
  25. myokit/formats/heka/_patchmaster.py +2512 -0
  26. myokit/formats/wcp/_wcp.py +318 -133
  27. myokit/gui/datablock_viewer.py +144 -77
  28. myokit/gui/datalog_viewer.py +212 -231
  29. myokit/tests/ansic_event_based_pacing.py +3 -3
  30. myokit/tests/{ansic_fixed_form_pacing.py → ansic_time_series_pacing.py} +6 -6
  31. myokit/tests/data/formats/abf-v2.abf +0 -0
  32. myokit/tests/test_datablock.py +84 -0
  33. myokit/tests/test_datalog.py +2 -1
  34. myokit/tests/test_formats_axon.py +589 -136
  35. myokit/tests/test_formats_wcp.py +191 -22
  36. myokit/tests/test_pacing_system_c.py +51 -23
  37. myokit/tests/test_pacing_system_py.py +18 -0
  38. myokit/tests/test_simulation_1d.py +62 -22
  39. myokit/tests/test_simulation_cvodes.py +52 -3
  40. myokit/tests/test_simulation_fiber_tissue.py +35 -4
  41. myokit/tests/test_simulation_opencl.py +28 -4
  42. {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/LICENSE.txt +1 -1
  43. {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/METADATA +1 -1
  44. {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/RECORD +47 -44
  45. {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/WHEEL +0 -0
  46. {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/entry_points.txt +0 -0
  47. {myokit-1.35.0.dist-info → myokit-1.35.2.dist-info}/top_level.txt +0 -0
@@ -13,7 +13,179 @@ import numpy as np
13
13
  import myokit
14
14
  import myokit.formats.axon as axon
15
15
 
16
- from myokit.tests import TemporaryDirectory, DIR_FORMATS
16
+ from myokit.tests import TemporaryDirectory, DIR_FORMATS, WarningCollector
17
+
18
+
19
+ V1_INFO = '''
20
+ Axon Binary File: abf-v1.abf
21
+ ABF Format version 1.65
22
+ Recorded on: 2014-11-14 12:52:29.389999
23
+ Acquisition mode: 5: Episodic stimulation mode
24
+ Protocol set for 1 trials, spaced 0.0s apart.
25
+ with 1 runs per trial, spaced 0.0s apart.
26
+ and 9 sweeps per run, spaced 0.5s apart.
27
+ Sampling rate: 10000.0 Hz
28
+ A/D Channel 0: "IN 0"
29
+ Unit: [pA]
30
+ D/A Channel 0: "OUT 0"
31
+ Unit: [mV]
32
+ '''.strip()
33
+
34
+ V1_PROTO_INFO = '''
35
+ Axon Protocol File: abf-protocol.pro
36
+ ABF Format version 1.65
37
+ Recorded on: 2005-06-17 14:33:02.160000
38
+ Acquisition mode: 5: Episodic stimulation mode
39
+ Protocol set for 1 trials, spaced 0.0s apart.
40
+ with 1 runs per trial, spaced 0.0s apart.
41
+ and 30 sweeps per run, spaced 5.0s apart.
42
+ Sampling rate: 20000.0 Hz
43
+ D/A Channel 0: "Cmd 0"
44
+ Unit: [mV]
45
+ '''.strip()
46
+
47
+ V1_PROTOCOL = '''
48
+ [[protocol]]
49
+ # Level Start Length Period Multiplier
50
+ -100.0 0.0 100.0 0.0 0
51
+ 0.0 100.0 400.0 0.0 0
52
+ -80.0 500.0 100.0 0.0 0
53
+ 0.0 600.0 400.0 0.0 0
54
+ -60.0 1000.0 100.0 0.0 0
55
+ 0.0 1100.0 400.0 0.0 0
56
+ -40.0 1500.0 100.0 0.0 0
57
+ 0.0 1600.0 400.0 0.0 0
58
+ -20.0 2000.0 100.0 0.0 0
59
+ 0.0 2100.0 400.0 0.0 0
60
+ 0.0 2500.0 100.0 0.0 0
61
+ 0.0 2600.0 400.0 0.0 0
62
+ 20.0 3000.0 100.0 0.0 0
63
+ 0.0 3100.0 400.0 0.0 0
64
+ 40.0 3500.0 100.0 0.0 0
65
+ 0.0 3600.0 400.0 0.0 0
66
+ 60.0 4000.0 100.0 0.0 0
67
+ 0.0 4100.0 400.0 0.0 0
68
+ '''.strip()
69
+
70
+ V1_PROTOCOL_VS = '''
71
+ [[protocol]]
72
+ # Level Start Length Period Multiplier
73
+ -0.1 0.0 0.1 0.0 0
74
+ 0.0 0.1 0.4 0.0 0
75
+ -0.08 0.5 0.1 0.0 0
76
+ 0.0 0.6 0.4 0.0 0
77
+ -0.06 1.0 0.1 0.0 0
78
+ 0.0 1.1 0.4 0.0 0
79
+ -0.04 1.5 0.1 0.0 0
80
+ 0.0 1.6 0.4 0.0 0
81
+ -0.02 2.0 0.1 0.0 0
82
+ 0.0 2.1 0.4 0.0 0
83
+ 0.0 2.5 0.1 0.0 0
84
+ 0.0 2.6 0.4 0.0 0
85
+ 0.02 3.0 0.1 0.0 0
86
+ 0.0 3.1 0.4 0.0 0
87
+ 0.04 3.5 0.1 0.0 0
88
+ 0.0 3.6 0.4 0.0 0
89
+ 0.06 4.0 0.1 0.0 0
90
+ 0.0 4.1 0.4 0.0 0
91
+ '''.strip()
92
+
93
+ V2_INFO = '''
94
+ Axon Binary File: abf-v2.abf
95
+ ABF Format version 2.0.0.0
96
+ Recorded on: 2016-01-07 10:51:55.345000
97
+ Acquisition mode: 5: Episodic stimulation mode
98
+ Protocol set for 1 trials, spaced 0.0s apart.
99
+ with 1 runs per trial, spaced 0.0s apart.
100
+ and 37 sweeps per run, spaced 5.0s apart.
101
+ Sampling rate: 20000.0 Hz
102
+ A/D Channel 0: "IN 0"
103
+ Unit: [pA]
104
+ Low-pass filter: 10000.0 Hz
105
+ Cm (telegraphed): 11.083984375 pF
106
+ D/A Channel 0: "Cmd 0"
107
+ Unit: [mV]
108
+
109
+ '''.strip()
110
+
111
+ V2_PROTOCOL = '''
112
+ [[protocol]]
113
+ # Level Start Length Period Multiplier
114
+ -100.0 0.0 25.0 0.0 0
115
+ -120.0 25.0 4975.0 0.0 0
116
+ -95.0 5000.0 25.0 0.0 0
117
+ -120.0 5025.0 4975.0 0.0 0
118
+ -90.0 10000.0 25.0 0.0 0
119
+ -120.0 10025.0 4975.0 0.0 0
120
+ -85.0 15000.0 25.0 0.0 0
121
+ -120.0 15025.0 4975.0 0.0 0
122
+ -80.0 20000.0 25.0 0.0 0
123
+ -120.0 20025.0 4975.0 0.0 0
124
+ -75.0 25000.0 25.0 0.0 0
125
+ -120.0 25025.0 4975.0 0.0 0
126
+ -70.0 30000.0 25.0 0.0 0
127
+ -120.0 30025.0 4975.0 0.0 0
128
+ -65.0 35000.0 25.0 0.0 0
129
+ -120.0 35025.0 4975.0 0.0 0
130
+ -60.0 40000.0 25.0 0.0 0
131
+ -120.0 40025.0 4975.0 0.0 0
132
+ -55.0 45000.0 25.0 0.0 0
133
+ -120.0 45025.0 4975.0 0.0 0
134
+ -50.0 50000.0 25.0 0.0 0
135
+ -120.0 50025.0 4975.0 0.0 0
136
+ -45.0 55000.0 25.0 0.0 0
137
+ -120.0 55025.0 4975.0 0.0 0
138
+ -40.0 60000.0 25.0 0.0 0
139
+ -120.0 60025.0 4975.0 0.0 0
140
+ -35.0 65000.0 25.0 0.0 0
141
+ -120.0 65025.0 4975.0 0.0 0
142
+ -30.0 70000.0 25.0 0.0 0
143
+ -120.0 70025.0 4975.0 0.0 0
144
+ -25.0 75000.0 25.0 0.0 0
145
+ -120.0 75025.0 4975.0 0.0 0
146
+ -20.0 80000.0 25.0 0.0 0
147
+ -120.0 80025.0 4975.0 0.0 0
148
+ -15.0 85000.0 25.0 0.0 0
149
+ -120.0 85025.0 4975.0 0.0 0
150
+ -10.0 90000.0 25.0 0.0 0
151
+ -120.0 90025.0 4975.0 0.0 0
152
+ -5.0 95000.0 25.0 0.0 0
153
+ -120.0 95025.0 4975.0 0.0 0
154
+ 0.0 100000.0 25.0 0.0 0
155
+ -120.0 100025.0 4975.0 0.0 0
156
+ 5.0 105000.0 25.0 0.0 0
157
+ -120.0 105025.0 4975.0 0.0 0
158
+ 10.0 110000.0 25.0 0.0 0
159
+ -120.0 110025.0 4975.0 0.0 0
160
+ 15.0 115000.0 25.0 0.0 0
161
+ -120.0 115025.0 4975.0 0.0 0
162
+ 20.0 120000.0 25.0 0.0 0
163
+ -120.0 120025.0 4975.0 0.0 0
164
+ 25.0 125000.0 25.0 0.0 0
165
+ -120.0 125025.0 4975.0 0.0 0
166
+ 30.0 130000.0 25.0 0.0 0
167
+ -120.0 130025.0 4975.0 0.0 0
168
+ 35.0 135000.0 25.0 0.0 0
169
+ -120.0 135025.0 4975.0 0.0 0
170
+ 40.0 140000.0 25.0 0.0 0
171
+ -120.0 140025.0 4975.0 0.0 0
172
+ 45.0 145000.0 25.0 0.0 0
173
+ -120.0 145025.0 4975.0 0.0 0
174
+ 50.0 150000.0 25.0 0.0 0
175
+ -120.0 150025.0 4975.0 0.0 0
176
+ 55.0 155000.0 25.0 0.0 0
177
+ -120.0 155025.0 4975.0 0.0 0
178
+ 60.0 160000.0 25.0 0.0 0
179
+ -120.0 160025.0 4975.0 0.0 0
180
+ 65.0 165000.0 25.0 0.0 0
181
+ -120.0 165025.0 4975.0 0.0 0
182
+ 70.0 170000.0 25.0 0.0 0
183
+ -120.0 170025.0 4975.0 0.0 0
184
+ 75.0 175000.0 25.0 0.0 0
185
+ -120.0 175025.0 4975.0 0.0 0
186
+ 80.0 180000.0 25.0 0.0 0
187
+ -120.0 180025.0 4975.0 0.0 0
188
+ '''.strip()
17
189
 
18
190
 
19
191
  class AbfTest(unittest.TestCase):
@@ -27,122 +199,203 @@ class AbfTest(unittest.TestCase):
27
199
  # Load file
28
200
  path = os.path.join(DIR_FORMATS, 'abf-v1.abf')
29
201
  abf = axon.AbfFile(path)
30
- self.assertEqual(abf.filename(), path)
202
+ self.assertEqual(abf.path(), path)
203
+ self.assertEqual(abf.filename(), 'abf-v1.abf')
204
+ self.assertIsInstance(abf, myokit.formats.SweepSource)
31
205
 
32
- # Check version info
33
- self.assertIn('version 1.65', abf.info())
34
- self.assertEqual(
35
- abf.info(),
36
- 'Axon Binary File: abf-v1.abf\n'
37
- 'ABF Format version 1.65\n'
38
- 'Recorded on: 2014-11-14 12:52:29.389999\n'
39
- 'Acquisition mode: 5: Episodic stimulation mode\n'
40
- 'Protocol set for 1 trials, spaced 0.0s apart.\n'
41
- ' with 1 runs per trial, spaced 0.0s apart.\n'
42
- ' and 9 sweeps per run, spaced 0.5s apart.\n'
43
- 'Sampling rate: 10000.0 Hz\n'
44
- 'Channel 0: "IN 0 "\n'
45
- ' Unit: pA'
46
- )
47
- # Test getting full header runs without crashing
48
- abf.info(True)
206
+ # Check getting info
207
+ self.assertIn('version 1.65', abf.meta_str())
208
+ self.maxDiff = None
209
+ self.assertEqual(abf.meta_str(), V1_INFO)
49
210
 
50
- # Test len returns number of sweeps
51
- self.assertEqual(len(abf), 9)
211
+ # Test getting full header runs without crashing
212
+ abf.meta_str(True)
52
213
 
53
- # Test data access
54
- self.assertEqual(abf.data_channels(), 1) # 1 data channel
55
- x = abf.extract_channel(0)
56
- self.assertEqual(len(x), 1 + len(abf)) # sweeps + time
57
- self.assertEqual(len(x[0]), len(x[1]))
58
- self.assertEqual(len(x[0]), len(x[2]))
59
- self.assertEqual(len(x[0]), len(x[3]))
60
- self.assertEqual(len(x[0]), len(x[4]))
61
- self.assertEqual(len(x[0]), len(x[5]))
62
- self.assertEqual(len(x[0]), len(x[6]))
63
- self.assertEqual(len(x[0]), len(x[7]))
64
- self.assertEqual(len(x[0]), len(x[8]))
65
- self.assertEqual(len(x[0]), len(x[9]))
66
- y = abf.extract_channel_as_myokit_log(0)
67
- self.assertEqual(len(y), 1 + len(abf)) # sweeps + time
68
- z = abf.myokit_log()
69
- self.assertEqual(len(z), 6) # time + channel + 4 protocol channels
70
- sweep = abf[0]
71
- self.assertEqual(len(sweep), 1) # 1 channel in sweep
72
- channel = sweep[0]
73
- self.assertIsInstance(channel.number(), int)
74
- self.assertIn('Channel', str(channel))
75
- self.assertEqual(len(abf) * len(channel.times()), len(z.time()))
76
- self.assertEqual(len(abf) * len(channel.values()), len(z.time()))
77
-
78
- # Test reading of sweeps as one long array
79
- x, y = abf.extract_channel(0, join=True)
80
- z = abf.extract_channel(0)
81
- self.assertEqual(len(x), len(y))
82
- self.assertEqual(len(x), len(abf) * len(z[0]))
83
- self.assertTrue(np.all(x[1:] > x[:-1]))
214
+ # Get version
215
+ self.assertEqual(abf.version(), '1.65')
84
216
 
85
- # Test protocol extraction
86
- self.assertEqual(abf.protocol_channels(), 4) # 4 protocol channels
87
- p = abf.myokit_protocol()
88
- self.assertEqual(len(p), 18) # 18 steps in this protocol
89
- self.assertEqual(abf.protocol_holding_level(0), 0)
90
- p = abf.myokit_protocol(0)
217
+ # Sweep count
218
+ self.assertEqual(len(abf), 9)
219
+ self.assertEqual(abf.sweep_count(), 9)
220
+ self.assertEqual(len([s for s in abf]), 9)
221
+
222
+ # Test access to A/D and D/A channels via sequence interface
223
+ self.assertIsInstance(abf[0], axon.Sweep)
224
+ self.assertIsInstance(abf[8], axon.Sweep)
225
+ self.assertFalse(abf[0] is abf[1])
226
+ self.assertEqual(len(abf[0]), 2)
227
+ self.assertEqual(len(abf[8]), 2)
228
+ self.assertIsInstance(abf[0][0], axon.Channel)
229
+ self.assertIsInstance(abf[0][1], axon.Channel)
230
+
231
+ # Test abf.Channel methods
232
+ channel = abf[0][0]
233
+ self.assertEqual(channel.index(), 0)
234
+ self.assertEqual(channel.name(), 'IN 0')
235
+ self.assertIsInstance(channel.unit(), myokit.Unit)
236
+ self.assertEqual(channel.unit(), myokit.units.pA)
237
+ self.assertEqual(str(channel),
238
+ 'Channel(0 "IN 0"); 5000 points sampled at 10000.0Hz,'
239
+ ' starts at t=0.0.')
240
+ self.assertEqual(len(channel.times()), len(channel.values()))
241
+ self.assertFalse(np.all(channel.times() == channel.values()))
242
+
243
+ # Test SweepSource info
244
+ self.assertTrue(abf.equal_length_sweeps())
245
+ self.assertEqual(abf.time_unit(), myokit.units.s)
246
+
247
+ # Test A/D channel access via SweepSource interface
248
+ self.assertEqual(abf.channel_count(), 1)
249
+ self.assertEqual(abf.channel_names(), ['IN 0'])
250
+ self.assertEqual(abf.channel_names(0), 'IN 0')
251
+ self.assertEqual(abf.channel_units(), [myokit.units.pA])
252
+ self.assertEqual(abf.channel_units(0), myokit.units.pA)
253
+
254
+ times, values = abf.channel(0)
255
+ self.assertEqual(9, len(times), len(values))
256
+ self.assertEqual(len(times[0]), len(values[0]))
257
+ self.assertEqual(len(times[0]), len(times[1]), len(values[1]))
258
+ self.assertEqual(len(times[0]), len(times[2]), len(values[2]))
259
+ self.assertEqual(len(times[0]), len(times[3]), len(values[3]))
260
+ self.assertEqual(len(times[0]), len(times[4]), len(values[4]))
261
+ self.assertEqual(len(times[0]), len(times[5]), len(values[5]))
262
+ self.assertEqual(len(times[0]), len(times[6]), len(values[6]))
263
+ self.assertEqual(len(times[0]), len(times[7]), len(values[7]))
264
+ self.assertEqual(len(times[0]), len(times[8]), len(values[8]))
265
+
266
+ tj, vj = abf.channel(0, join_sweeps=True)
267
+ self.assertTrue(np.all(tj == np.concatenate(times)))
268
+ self.assertTrue(np.all(vj == np.concatenate(values)))
269
+
270
+ # Channel doesn't exist
271
+ self.assertRaises(IndexError, abf.channel, -1)
272
+ self.assertRaises(IndexError, abf.channel, 1)
273
+ self.assertRaises(KeyError, abf.channel, 'OUT 0')
274
+
275
+ # Test D/A output access via SweepSource interface
276
+ self.assertEqual(abf.da_count(), 1)
277
+ self.assertEqual(abf.da_names(), ['OUT 0'])
278
+ self.assertEqual(abf.da_names(0), 'OUT 0')
279
+ self.assertEqual(abf.da_units(), [myokit.units.mV])
280
+ self.assertEqual(abf.da_units(0), myokit.units.mV)
281
+
282
+ da_times, da_values = abf.da(0)
283
+ self.assertEqual(9, len(da_times), len(da_values))
284
+ self.assertEqual(len(da_times[0]), len(da_values[0]))
285
+ self.assertEqual(len(da_times[0]), len(da_times[1]), len(da_values[1]))
286
+ self.assertEqual(len(da_times[0]), len(da_times[8]), len(da_values[8]))
287
+ self.assertEqual(len(da_times[0]), len(times[0]))
288
+ self.assertTrue(np.all(times[0] == da_times[0]))
289
+ self.assertFalse(np.all(values[0] == da_values[0]))
290
+ self.assertTrue(np.all(da_values[3] == abf.da('OUT 0')[1][3]))
291
+ self.assertRaises(IndexError, abf.da, -1)
292
+ self.assertRaises(IndexError, abf.da, 1)
293
+ self.assertRaises(KeyError, abf.da, 'hiya')
294
+
295
+ tj, vj = abf.da(0, join_sweeps=True)
296
+ self.assertTrue(np.all(tj == np.concatenate(da_times)))
297
+ self.assertTrue(np.all(vj == np.concatenate(da_values)))
298
+
299
+ # Conversion to data log without joining
300
+ x = abf.log()
301
+ k = list(x.keys())
302
+ self.assertEqual(len(x), 1 + 2 * 9)
303
+ self.assertIn('time', x)
304
+ self.assertIn('0.0.channel', k)
305
+ self.assertIn('1.0.channel', k)
306
+ self.assertIn('2.0.channel', k)
307
+ self.assertIn('3.0.channel', k)
308
+ self.assertIn('4.0.channel', k)
309
+ self.assertIn('5.0.channel', k)
310
+ self.assertIn('6.0.channel', k)
311
+ self.assertIn('7.0.channel', k)
312
+ self.assertIn('8.0.channel', k)
313
+ self.assertIn('0.0.da', k)
314
+ self.assertIn('1.0.da', k)
315
+ self.assertIn('2.0.da', k)
316
+ self.assertIn('3.0.da', k)
317
+ self.assertIn('4.0.da', k)
318
+ self.assertIn('5.0.da', k)
319
+ self.assertIn('6.0.da', k)
320
+ self.assertIn('7.0.da', k)
321
+ self.assertIn('8.0.da', k)
322
+ self.assertEqual(len(x['time']), len(x['5.0.channel']))
323
+ self.assertEqual(len(x['7.0.da']), len(x['5.0.channel']))
324
+
325
+ x = abf.log(include_da=False)
326
+ k = list(x.keys())
327
+ self.assertEqual(len(x), 1 + 1 * 9)
328
+ self.assertIn('time', x)
329
+ self.assertIn('0.0.channel', k)
330
+ self.assertIn('1.0.channel', k)
331
+ self.assertIn('2.0.channel', k)
332
+ self.assertIn('3.0.channel', k)
333
+ self.assertIn('4.0.channel', k)
334
+ self.assertIn('5.0.channel', k)
335
+ self.assertIn('6.0.channel', k)
336
+ self.assertIn('7.0.channel', k)
337
+ self.assertIn('8.0.channel', k)
338
+ self.assertEqual(len(x['time']), len(x['5.0.channel']))
339
+
340
+ x = abf.log(use_names=True)
341
+ k = list(x.keys())
342
+ self.assertEqual(len(x), 1 + 2 * 9)
343
+ self.assertIn('time', k)
344
+ self.assertIn('0.IN 0', k)
345
+ self.assertIn('1.IN 0', k)
346
+ self.assertIn('2.IN 0', k)
347
+ self.assertIn('3.IN 0', k)
348
+ self.assertIn('4.IN 0', k)
349
+ self.assertIn('5.IN 0', k)
350
+ self.assertIn('6.IN 0', k)
351
+ self.assertIn('7.IN 0', k)
352
+ self.assertIn('8.IN 0', k)
353
+ self.assertIn('0.OUT 0', k)
354
+ self.assertIn('1.OUT 0', k)
355
+ self.assertIn('2.OUT 0', k)
356
+ self.assertIn('3.OUT 0', k)
357
+ self.assertIn('4.OUT 0', k)
358
+ self.assertIn('5.OUT 0', k)
359
+ self.assertIn('6.OUT 0', k)
360
+ self.assertIn('7.OUT 0', k)
361
+ self.assertIn('8.OUT 0', k)
362
+
363
+ # Conversion to data log with joining
364
+ y = abf.log(join_sweeps=True)
365
+ self.assertEqual(len(y), 3)
366
+ self.assertIn('time', y.keys())
367
+ self.assertIn('0.channel', y.keys())
368
+ self.assertIn('0.da', y.keys())
369
+ self.assertEqual(len(y['time']), 9 * len(x['time']))
370
+ self.assertEqual(len(y['time']), len(y['0.channel']))
371
+ self.assertEqual(len(y['time']), len(y['0.da']))
372
+
373
+ y = abf.log(join_sweeps=True, use_names=True)
374
+ self.assertEqual(len(y), 3)
375
+ self.assertIn('time', y.keys())
376
+ self.assertIn('IN 0', y.keys())
377
+ self.assertIn('OUT 0', y.keys())
378
+ self.assertEqual(len(y['time']), 9 * len(x['time']))
379
+ self.assertEqual(len(y['time']), len(y['IN 0']))
380
+ self.assertEqual(len(y['time']), len(y['OUT 0']))
381
+
382
+ y = abf.log(join_sweeps=True, use_names=True, include_da=False)
383
+ self.assertEqual(len(y), 2)
384
+ self.assertIn('time', y.keys())
385
+ self.assertIn('IN 0', y.keys())
386
+ self.assertEqual(len(y['time']), 9 * len(x['time']))
387
+ self.assertEqual(len(y['time']), len(y['IN 0']))
388
+
389
+ # Test conversion to Myokit protocol
390
+ p = abf.da_protocol(0)
91
391
  self.assertEqual(len(p), 18)
392
+ self.assertEqual(p.code(), V1_PROTOCOL)
92
393
 
93
- def test_read_v2(self):
94
- # Test reading a version 2 file.
95
-
96
- # Load file
97
- path = os.path.join(DIR_FORMATS, 'abf-v2.abf')
98
- abf = axon.AbfFile(path)
99
-
100
- # Check version info
101
- self.assertIn('version 2.0', abf.info())
102
- self.assertEqual(
103
- abf.info(),
104
- 'Axon Binary File: abf-v2.abf\n'
105
- 'ABF Format version 2.0\n'
106
- 'Recorded on: 2014-10-01 14:03:55.980999\n'
107
- 'Acquisition mode: 5: Episodic stimulation mode\n'
108
- 'Protocol set for 1 trials, spaced 0.0s apart.\n'
109
- ' with 1 runs per trial, spaced 0.0s apart.\n'
110
- ' and 1 sweeps per run, spaced 5.0s apart.\n'
111
- 'Sampling rate: 10000.0 Hz\n'
112
- 'Channel 0: "IN 0"\n'
113
- ' Unit: pA\n'
114
- ' Low-pass filter: 10000.0 Hz\n'
115
- ' Cm (telegraphed): 6.34765625 pF')
116
- # Test getting full header runs without crashing
117
- abf.info(True)
118
-
119
- # Test len returns number of sweeps
120
- self.assertEqual(len(abf), 1)
121
-
122
- # Test data access
123
- self.assertEqual(abf.data_channels(), 1) # 1 data channel
124
- x = abf.extract_channel(0)
125
- self.assertEqual(len(x), 1 + len(abf)) # sweeps + time
126
- self.assertEqual(len(x[0]), len(x[1]))
127
- y = abf.extract_channel_as_myokit_log(0)
128
- self.assertEqual(len(y), 1 + len(abf)) # sweeps + time
129
- z = abf.myokit_log()
130
- self.assertEqual(len(z), 6) # time + channel + 4 protocol channels
131
- sweep = abf[0]
132
- self.assertEqual(len(sweep), 1) # 1 channel in sweep
133
- channel = sweep[0]
134
- self.assertEqual(len(abf) * len(channel.times()), len(z.time()))
135
- self.assertEqual(len(abf) * len(channel.values()), len(z.time()))
394
+ p = abf.da_protocol(0, vu=myokit.units.V, tu='s')
395
+ self.assertEqual(len(p), 18)
396
+ self.assertEqual(p.code(), V1_PROTOCOL_VS)
136
397
 
137
- # Test protocol extraction
138
- self.assertEqual(abf.protocol_channels(), 4) # 4 protocol channels
139
- p = abf.myokit_protocol()
140
- self.assertEqual(len(p), 2) # 2 steps in this protocol
141
- self.assertEqual(abf.protocol_holding_level(0), -120)
142
- p = abf.myokit_protocol(0)
143
- self.assertEqual(len(p), 2)
144
-
145
- def test_read_protocol_v1(self):
398
+ def test_read_protocol_file_v1(self):
146
399
  # Test reading a v1 protocol file.
147
400
 
148
401
  # Load file
@@ -150,37 +403,222 @@ class AbfTest(unittest.TestCase):
150
403
  abf = axon.AbfFile(path)
151
404
 
152
405
  # Check version info
153
- self.assertIn('version 1.65', abf.info())
154
- self.assertEqual(
155
- abf.info(),
156
- 'Axon Protocol File: abf-protocol.pro\n'
157
- 'ABF Format version 1.65\n'
158
- 'Recorded on: 2005-06-17 14:33:02.160000\n'
159
- 'Acquisition mode: 5: Episodic stimulation mode\n'
160
- 'Protocol set for 1 trials, spaced 0.0s apart.\n'
161
- ' with 1 runs per trial, spaced 0.0s apart.\n'
162
- ' and 30 sweeps per run, spaced 5.0s apart.\n'
163
- 'Sampling rate: 20000.0 Hz'
164
- )
165
- # Test getting full header runs without crashing
166
- abf.info(True)
406
+ self.assertIn('version 1.65', abf.meta_str())
407
+ self.assertEqual(abf.meta_str(), V1_PROTO_INFO)
408
+ abf.meta_str(True) # Test getting full header runs without crashing
409
+ self.assertEqual(abf.channel_count(), 0)
410
+ self.assertEqual(abf.channel_names(), [])
411
+ self.assertEqual(abf.channel_units(), [])
412
+ self.assertEqual(abf.da_count(), 1)
413
+ self.assertEqual(abf.da_names(), ['Cmd 0'])
414
+ self.assertEqual(abf.da_names(0), 'Cmd 0')
415
+ self.assertEqual(abf.da_units(), [myokit.units.mV])
416
+ self.assertEqual(abf.da_units(0), myokit.units.mV)
417
+ #self.assertEqual(len(abf.log(join_sweeps=True)), 2)
167
418
 
168
419
  # Load, force as protocol
169
420
  path = os.path.join(DIR_FORMATS, 'abf-protocol.pro')
170
421
  abf = axon.AbfFile(path, is_protocol_file=True)
422
+ self.assertEqual(abf.channel_count(), 0)
423
+ self.assertEqual(abf.channel_count(), 0)
424
+ self.assertEqual(abf.da_count(), 1)
171
425
 
172
426
  # Check version info
173
- self.assertIn('version 1.65', abf.info())
174
- self.assertIn('Axon Protocol File', abf.info())
427
+ self.assertIn('version 1.65', abf.meta_str())
428
+ self.assertIn('Axon Protocol File', abf.meta_str())
175
429
 
176
430
  # Test protocol extraction
177
- p = abf.myokit_protocol()
431
+ p = abf.da_protocol()
178
432
  self.assertEqual(len(p), 60)
179
433
 
180
- # Test step extraction
181
- p = abf.protocol_steps()
182
- self.assertEqual(len(p), 1)
183
- self.assertEqual(len(p[0]), 30)
434
+ def test_read_v2(self):
435
+ # Test reading a version 2 file.
436
+
437
+ # Load file
438
+ path = os.path.join(DIR_FORMATS, 'abf-v2.abf')
439
+ abf = axon.AbfFile(path)
440
+ self.assertEqual(abf.path(), path)
441
+ self.assertEqual(abf.filename(), 'abf-v2.abf')
442
+
443
+ # Check getting info
444
+ self.assertIn('version 2.0', abf.meta_str())
445
+ self.maxDiff = None
446
+ self.assertEqual(abf.meta_str(), V2_INFO)
447
+
448
+ # Test getting full header runs without crashing
449
+ abf.meta_str(True)
450
+
451
+ # Get version
452
+ self.assertEqual(abf.version(), '2.0.0.0')
453
+
454
+ # Sweep count
455
+ self.assertEqual(len(abf), 37)
456
+ self.assertEqual(abf.sweep_count(), 37)
457
+
458
+ # Test access to A/D channels via native API
459
+ self.assertIsInstance(abf[0], axon.Sweep)
460
+ self.assertIsInstance(abf[1], axon.Sweep)
461
+ self.assertIsInstance(abf[36], axon.Sweep)
462
+ self.assertFalse(abf[0] is abf[1])
463
+ self.assertEqual(len(abf[0]), 2)
464
+ self.assertEqual(len(abf[36]), 2)
465
+ self.assertIsInstance(abf[0][0], axon.Channel)
466
+ self.assertIsInstance(abf[0][1], axon.Channel)
467
+ self.assertFalse(abf[0][0] is abf[0][1])
468
+
469
+ # Test abf.Channel methods
470
+ channel = abf[0][0]
471
+ self.assertEqual(channel.index(), 0)
472
+ self.assertEqual(channel.name(), 'IN 0')
473
+ self.assertIsInstance(channel.unit(), myokit.Unit)
474
+ self.assertEqual(channel.unit(), myokit.units.pA)
475
+ self.assertEqual(str(channel),
476
+ 'Channel(0 "IN 0"); 516 points sampled at 20000.0Hz,'
477
+ ' starts at t=0.0.')
478
+ self.assertEqual(len(channel.times()), len(channel.values()))
479
+ self.assertFalse(np.all(channel.times() == channel.values()))
480
+
481
+ # Test SweepSource info
482
+ self.assertTrue(abf.equal_length_sweeps())
483
+ self.assertEqual(abf.time_unit(), myokit.units.s)
484
+
485
+ # Test A/D channel access via SweepSource interface
486
+ self.assertEqual(abf.channel_count(), 1)
487
+ self.assertEqual(abf.channel_names(), ['IN 0'])
488
+ self.assertEqual(abf.channel_names(0), 'IN 0')
489
+ self.assertEqual(abf.channel_units(), [myokit.units.pA])
490
+ self.assertEqual(abf.channel_units(0), myokit.units.pA)
491
+
492
+ times, values = abf.channel(0)
493
+ self.assertEqual(37, len(times), len(values))
494
+ self.assertEqual(len(times[0]), len(values[0]))
495
+ self.assertEqual(len(times[0]), len(times[1]), len(values[1]))
496
+ self.assertEqual(len(times[0]), len(times[2]), len(values[2]))
497
+ self.assertEqual(len(times[0]), len(times[17]), len(values[13]))
498
+ self.assertEqual(len(times[0]), len(times[36]), len(values[36]))
499
+
500
+ tj, vj = abf.channel(0, join_sweeps=True)
501
+ self.assertTrue(np.all(tj == np.concatenate(times)))
502
+ self.assertTrue(np.all(vj == np.concatenate(values)))
503
+
504
+ # Channel doesn't exist
505
+ self.assertRaises(IndexError, abf.channel, -1)
506
+ self.assertRaises(IndexError, abf.channel, 1)
507
+ self.assertRaises(KeyError, abf.channel, 'OUT 0')
508
+
509
+ # Test D/A output access via SweepSource interface
510
+ self.assertEqual(abf.da_count(), 1)
511
+ self.assertEqual(abf.da_names(), ['Cmd 0'])
512
+ self.assertEqual(abf.da_names(0), 'Cmd 0')
513
+ self.assertEqual(abf.da_units(), [myokit.units.mV])
514
+ self.assertEqual(abf.da_units(0), myokit.units.mV)
515
+
516
+ da_times, da_values = abf.da(0)
517
+ self.assertEqual(37, len(da_times), len(da_values))
518
+ self.assertEqual(len(da_times[0]), len(da_values[0]))
519
+ self.assertEqual(len(da_times[0]), len(da_times[1]), len(da_values[1]))
520
+ self.assertEqual(len(da_times[0]), len(da_times[4]), len(da_values[9]))
521
+ self.assertEqual(len(da_times[0]), len(times[0]))
522
+ self.assertTrue(np.all(times[0] == da_times[0]))
523
+ self.assertFalse(np.all(values[0] == da_values[0]))
524
+
525
+ tj, vj = abf.da(0, join_sweeps=True)
526
+ self.assertTrue(np.all(tj == np.concatenate(da_times)))
527
+ self.assertTrue(np.all(vj == np.concatenate(da_values)))
528
+
529
+ # Conversion to data log without joining
530
+ x = abf.log()
531
+ k = list(x.keys())
532
+ self.assertEqual(len(x), 1 + 2 * 37)
533
+ self.assertIn('time', x)
534
+ self.assertIn('0.0.channel', k)
535
+ self.assertIn('1.0.channel', k)
536
+ self.assertIn('2.0.channel', k)
537
+ self.assertIn('3.0.channel', k)
538
+ self.assertIn('36.0.channel', k)
539
+ self.assertIn('0.0.da', k)
540
+ self.assertIn('5.0.da', k)
541
+ self.assertIn('16.0.da', k)
542
+ self.assertIn('36.0.da', k)
543
+ self.assertEqual(len(x['time']), len(x['5.0.channel']))
544
+ self.assertEqual(len(x['7.0.da']), len(x['5.0.channel']))
545
+
546
+ x = abf.log(include_da=False)
547
+ k = list(x.keys())
548
+ self.assertEqual(len(x), 1 + 1 * 37)
549
+ self.assertIn('time', x)
550
+ self.assertIn('0.0.channel', k)
551
+ self.assertIn('1.0.channel', k)
552
+ self.assertIn('2.0.channel', k)
553
+ self.assertIn('3.0.channel', k)
554
+ self.assertIn('36.0.channel', k)
555
+ self.assertNotIn('0.0.da', k)
556
+ self.assertNotIn('7.0.da', k)
557
+ self.assertNotIn('36.0.da', k)
558
+ self.assertEqual(len(x['time']), len(x['6.0.channel']))
559
+
560
+ x = abf.log(use_names=True)
561
+ k = list(x.keys())
562
+ self.assertEqual(len(x), 1 + 2 * 37)
563
+ self.assertIn('time', x)
564
+ self.assertIn('0.IN 0', k)
565
+ self.assertIn('1.IN 0', k)
566
+ self.assertIn('2.IN 0', k)
567
+ self.assertIn('36.IN 0', k)
568
+ self.assertIn('0.Cmd 0', k)
569
+ self.assertIn('5.Cmd 0', k)
570
+ self.assertIn('16.Cmd 0', k)
571
+ self.assertIn('36.Cmd 0', k)
572
+ self.assertEqual(len(x['time']), len(x['5.IN 0']))
573
+ self.assertEqual(len(x['7.Cmd 0']), len(x['5.IN 0']))
574
+
575
+ # Conversion to data log with joining
576
+ y = abf.log(join_sweeps=True)
577
+ self.assertEqual(len(y), 3)
578
+ self.assertIn('time', y.keys())
579
+ self.assertIn('0.channel', y.keys())
580
+ self.assertIn('0.da', y.keys())
581
+ self.assertEqual(len(y['time']), 37 * len(x['time']))
582
+ self.assertEqual(len(y['time']), len(y['0.channel']))
583
+ self.assertEqual(len(y['time']), len(y['0.da']))
584
+
585
+ y = abf.log(join_sweeps=True, use_names=True)
586
+ self.assertEqual(len(y), 3)
587
+ self.assertIn('time', y.keys())
588
+ self.assertIn('IN 0', y.keys())
589
+ self.assertIn('Cmd 0', y.keys())
590
+ self.assertEqual(len(y['time']), 37 * len(x['time']))
591
+ self.assertEqual(len(y['time']), len(y['IN 0']))
592
+ self.assertEqual(len(y['time']), len(y['Cmd 0']))
593
+
594
+ y = abf.log(join_sweeps=True, use_names=True, include_da=False)
595
+ self.assertEqual(len(y), 2)
596
+ self.assertIn('time', y.keys())
597
+ self.assertIn('IN 0', y.keys())
598
+ self.assertEqual(len(y['time']), 37 * len(x['time']))
599
+ self.assertEqual(len(y['time']), len(y['IN 0']))
600
+
601
+ # Test conversion to Myokit protocol
602
+ p = abf.da_protocol(0)
603
+ self.assertEqual(len(p), 37 * 2)
604
+ self.assertEqual(p.code(), V2_PROTOCOL)
605
+
606
+ # Test conversion with initial holding as in the real experiment
607
+ p = abf.da_protocol(0, include_initial_holding=True)
608
+ e = p.events()
609
+ self.assertEqual(e[0].level(), -120) # Pre step
610
+ self.assertEqual(e[0].start(), 0)
611
+ self.assertEqual(e[0].duration(), 0.4)
612
+ self.assertEqual(e[1].level(), -100) # Real step
613
+ self.assertEqual(e[1].start(), 0.4)
614
+ self.assertEqual(e[1].duration(), 25)
615
+ self.assertEqual(e[2].level(), -120) # Shortened post-step
616
+ self.assertEqual(e[2].start(), 25.4)
617
+ self.assertEqual(e[2].duration(), 4974.6)
618
+ self.assertEqual(e[3].level(), -120) # Next pre step
619
+ self.assertEqual(e[3].start(), 5000)
620
+ self.assertEqual(e[3].duration(), 0.4)
621
+ self.assertEqual(len(e), 37 * 3)
184
622
 
185
623
  def test_matplotlib_figure(self):
186
624
  # Test figure drawing method (doesn't inspect output).
@@ -189,7 +627,8 @@ class AbfTest(unittest.TestCase):
189
627
  matplotlib.use('template')
190
628
  path = os.path.join(DIR_FORMATS, 'abf-v1.abf')
191
629
  abf = axon.AbfFile(path)
192
- abf.matplotlib_figure()
630
+ f = abf.matplotlib_figure()
631
+ self.assertIsInstance(f, matplotlib.figure.Figure)
193
632
 
194
633
 
195
634
  class AtfTest(unittest.TestCase):
@@ -219,6 +658,15 @@ class AtfTest(unittest.TestCase):
219
658
  for k, v in log.items():
220
659
  self.assertTrue(np.all(v == log2[k]))
221
660
 
661
+ # Deprecated method
662
+ with WarningCollector() as w:
663
+ log3 = axon.AtfFile(path).myokit_log()
664
+ self.assertIn('deprecated', w.text())
665
+ self.assertEqual(len(log), len(log3))
666
+ self.assertEqual(set(log.keys()), set(log3.keys()))
667
+ for k, v in log.items():
668
+ self.assertTrue(np.all(v == log3[k]))
669
+
222
670
  # Write selected fields
223
671
  axon.save_atf(log, path, fields=['time', 'sint'])
224
672
  log2 = axon.load_atf(path)
@@ -272,7 +720,7 @@ class AtfTest(unittest.TestCase):
272
720
  f.write('1\t10\t20\n')
273
721
  f.write('2\t30\t40\n')
274
722
  self.assertRaisesRegex(
275
- Exception, 'double quotation', axon.load_atf, path)
723
+ Exception, 'double quotes', axon.load_atf, path)
276
724
 
277
725
  # Bad column headers
278
726
  with open(path, 'w') as f:
@@ -363,8 +811,9 @@ class AtfTest(unittest.TestCase):
363
811
  # Read atf file
364
812
  atf = myokit.formats.axon.AtfFile(path)
365
813
 
366
- # Test filename()
367
- self.assertEqual(atf.filename(), path)
814
+ # Test filename() and path()
815
+ self.assertEqual(atf.path(), path)
816
+ self.assertEqual(atf.filename(), 'test.atf')
368
817
 
369
818
  # Test iter and getitem
370
819
  self.assertEqual(len(list(iter(atf))), 3)
@@ -394,7 +843,11 @@ class AtfTest(unittest.TestCase):
394
843
  self.assertEqual(len(atf), 3)
395
844
 
396
845
  # Test info
397
- self.assertIn('myokit', atf.info())
846
+ meta = atf.meta_str()
847
+ self.assertIn('myokit', meta)
848
+ with WarningCollector() as w:
849
+ self.assertEqual(meta, atf.info())
850
+ self.assertIn('deprecated', w.text())
398
851
 
399
852
  # Test version
400
853
  self.assertEqual(atf.version(), '1.0')