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
@@ -11,6 +11,7 @@ import numpy as np
11
11
 
12
12
  from collections import OrderedDict
13
13
 
14
+ import myokit
14
15
 
15
16
  # Format used for any text
16
17
  _ENC = 'ascii'
@@ -30,11 +31,11 @@ class AtfFile:
30
31
  """
31
32
  def __init__(self, filename):
32
33
  # The path to the file and its basename
33
- self._file = os.path.abspath(filename)
34
+ self._path = os.path.abspath(filename)
34
35
  self._filename = os.path.basename(filename)
35
36
 
36
37
  # A version string
37
- self._version = None
38
+ self._version_str = None
38
39
 
39
40
  # A (multi-line) string containing meta-data found in this file
40
41
  self._meta = None
@@ -45,56 +46,39 @@ class AtfFile:
45
46
  # Read data
46
47
  self._read()
47
48
 
48
- def filename(self):
49
- """
50
- Returns this ATF's filename.
51
- """
52
- return self._file
53
-
54
49
  def __getitem__(self, key):
55
50
  return self._data.__getitem__(key)
56
51
 
57
52
  def __iter__(self):
58
- """
59
- Iterates over all data arrays in this ATF file.
60
- """
61
53
  return iter(self._data)
62
54
 
55
+ def __len__(self):
56
+ return len(self._data)
57
+
58
+ def filename(self):
59
+ """ Returns this ATF's filename. """
60
+ return self._filename
61
+
62
+ def info(self):
63
+ """ Returns this ATF's header/meta data. """
64
+ # Deprecated since 2023-07-12
65
+ import warnings
66
+ warnings.warn(
67
+ 'The method `info` is deprecated. Please use `meta_str` instead.')
68
+ return self.meta_str()
69
+
63
70
  def items(self):
64
- """
65
- Iterates over all key-value pairs in this ATF file's data.
66
- """
71
+ """ Returns an iterator over all ``(key, value)`` pairs. """
67
72
  return iter(self._data.items())
68
73
 
69
74
  def keys(self):
70
- """
71
- Iterates over all keys in this ATF file's data.
72
- """
75
+ """ Returns an iterator over all keys in this ATF. """
73
76
  return iter(self._data.keys())
74
77
 
75
- def values(self):
76
- """
77
- Iterates over all values in this ATF file's data.
78
- """
79
- return iter(self._data.values())
80
-
81
- def __len__(self):
82
- """
83
- Returns the number of records in this file.
84
- """
85
- return len(self._data)
86
-
87
- def info(self):
88
- """
89
- Returns the header/meta data found in this file.
90
- """
91
- return self._meta
92
-
93
- def myokit_log(self):
78
+ def log(self):
94
79
  """
95
80
  Returns this file's time series data as a :class:`myokit.DataLog`.
96
81
  """
97
- import myokit
98
82
  log = myokit.DataLog()
99
83
  if len(self._data) > 0:
100
84
  log.set_time_key(next(iter(self._data.keys())))
@@ -102,17 +86,36 @@ class AtfFile:
102
86
  log[k] = v
103
87
  return log
104
88
 
105
- def _read(self):
89
+ def meta_str(self, verbose=True):
106
90
  """
107
- Reads the data in the file.
91
+ Returns this ATF's header data as an unstructured multi-line string.
92
+
93
+ Note that the ``verbose`` argument doesn't do anything, but provides
94
+ compatibility with similar methods in other files.
108
95
  """
109
- with open(self._file, 'rb') as f:
96
+ return self._meta
97
+
98
+ def myokit_log(self):
99
+ """ Deprecated alias of :meth:`log`. """
100
+ # Deprecated since 2023-06-22
101
+ import warnings
102
+ warnings.warn(
103
+ 'The method `myokit_log` is deprecated. Please use `log` instead.')
104
+ return self.log()
105
+
106
+ def path(self):
107
+ """ Returns the path to this ATF file. """
108
+ return self._path
109
+
110
+ def _read(self):
111
+ """ Reads the data in this file. """
112
+ with open(self._path, 'rb') as f:
110
113
  # Check version
111
114
  line = f.readline().decode(_ENC)
112
115
  line_index = 1
113
116
  if line[:3] != 'ATF':
114
117
  raise Exception('Unrecognised file type.')
115
- self._version = line[3:].strip()
118
+ self._version_str = line[3:].strip()
116
119
 
117
120
  # Read number of header lines, number of fields
118
121
  line = f.readline().decode(_ENC)
@@ -131,9 +134,8 @@ class AtfFile:
131
134
  line_index += 1
132
135
  if line[0] != '"' or line[-1] != '"':
133
136
  raise Exception(
134
- 'Invalid header on line ' + str(line_index)
135
- + ': expecting lines wrapped in double quotation'
136
- ' marks "like this".')
137
+ f'Invalid header on line f{line_index}: expecting '
138
+ f' lines wrapped in double quotes ("like this").')
137
139
  line = line[1:-1].strip()
138
140
  raw.append(line)
139
141
  if key_value_pairs:
@@ -170,8 +172,8 @@ class AtfFile:
170
172
  delims = delims[1:-1]
171
173
  if len(delims) + 1 != nf:
172
174
  raise Exception(
173
- 'Unable to parse column headers: Expected ' + str(nf)
174
- + ' headers, found ' + str(len(delims) + 1) + '.')
175
+ f'Unable to parse column headers: Expected {nf} headers,'
176
+ f' found {len(delims) + 1}.')
175
177
  commas = ',' in delims[0]
176
178
  for delim in delims:
177
179
  if commas != (',' in delim):
@@ -193,8 +195,8 @@ class AtfFile:
193
195
  if len(keys) != nf: # pragma: no cover
194
196
  # This should have been picked up above
195
197
  raise Exception(
196
- 'Unable to parse column headers: Expected ' + str(nf)
197
- + ' headers, found ' + str(len(keys)) + '.')
198
+ f'Unable to parse column headers: Expected {nf} headers,'
199
+ f' found {len(keys)}.')
198
200
 
199
201
  # Read data
200
202
  data = []
@@ -209,18 +211,19 @@ class AtfFile:
209
211
  vals = line.split(sep)
210
212
  if len(vals) != nf:
211
213
  raise Exception(
212
- 'Invalid data on line ' + str(line_index)
213
- + ': expecting ' + str(nf) + ' fields, found'
214
- + ' ' + str(len(vals)) + '.')
214
+ f'Invalid data on line f{line_index}: expecting {nf}'
215
+ f' fields, found {len(vals)}.')
215
216
  vals = [float(x) for x in vals]
216
217
  for k, d in enumerate(vals):
217
218
  data[k].append(d)
218
219
 
220
+ def values(self):
221
+ """ Returns an iterator over all values in this ATF. """
222
+ return iter(self._data.values())
223
+
219
224
  def version(self):
220
- """
221
- Returns the file type version of this ATF file (as a string).
222
- """
223
- return self._version
225
+ """ Returns a string representation of this file's version number. """
226
+ return self._version_str
224
227
 
225
228
 
226
229
  def load_atf(filename):
@@ -228,7 +231,7 @@ def load_atf(filename):
228
231
  Reads an ATF file and returns its data as a :class:`myokit.DataLog`.
229
232
  """
230
233
  filename = os.path.expanduser(filename)
231
- return AtfFile(filename).myokit_log()
234
+ return AtfFile(filename).log()
232
235
 
233
236
 
234
237
  def save_atf(log, filename, fields=None):
@@ -306,12 +309,12 @@ def save_atf(log, filename, fields=None):
306
309
  f.write(('ATF 1.0' + eol).encode(_ENC))
307
310
 
308
311
  # Write number of header lines, number of fields
309
- f.write((str(nh) + delim + str(nf) + eol).encode(_ENC))
312
+ f.write(f'{nh}{delim}{nf}{eol}'.encode(_ENC))
310
313
  for k, v in header:
311
- f.write(('"' + str(k) + '=' + str(v) + '"' + eol).encode(_ENC))
314
+ f.write(f'"{k}={v}"{eol}'.encode(_ENC))
312
315
 
313
316
  # Write field names
314
- f.write((delim.join(['"' + k + '"' for k in keys]) + eol).encode(_ENC))
317
+ f.write((delim.join([f'"{k}"' for k in keys]) + eol).encode(_ENC))
315
318
 
316
319
  # Write data
317
320
  for i in range(nd):
@@ -16,7 +16,7 @@ class AbfImporter(myokit.formats.Importer):
16
16
  def supports_protocol(self):
17
17
  return True
18
18
 
19
- def protocol(self, filename, channel=None):
19
+ def protocol(self, filename, channel=0):
20
20
  """
21
21
  Attempts to load the protocol from the file at ``filename``.
22
22
 
@@ -25,4 +25,4 @@ class AbfImporter(myokit.formats.Importer):
25
25
  """
26
26
  from myokit.formats.axon import AbfFile
27
27
  abf = AbfFile(filename)
28
- return abf.myokit_protocol(channel)
28
+ return abf.da_protocol(channel)
@@ -0,0 +1,38 @@
1
+ #
2
+ # Provides support for working with data in formats used by HEKA.
3
+ #
4
+ # This file is part of Myokit.
5
+ # See http://myokit.org for copyright, sharing, and licensing details.
6
+ from ._patchmaster import ( # noqa
7
+ AmplifierMode,
8
+ EndianAwareReader,
9
+ Group,
10
+ NoSupportedDAChannelError,
11
+ PatchMasterFile,
12
+ PulsedFile,
13
+ Segment,
14
+ SegmentClass,
15
+ SegmentIncrement,
16
+ SegmentStorage,
17
+ Series,
18
+ Stimulus,
19
+ StimulusChannel,
20
+ StimulusFile,
21
+ Sweep,
22
+ Trace,
23
+ TreeNode,
24
+ )
25
+ from ._importer import PatchMasterImporter
26
+
27
+
28
+ # Importers
29
+ _importers = {
30
+ 'heka': PatchMasterImporter,
31
+ }
32
+
33
+
34
+ def importers():
35
+ """ Returns a dict of all importers available in this module. """
36
+ return dict(_importers)
37
+ # Exporters
38
+ # Expression writers
@@ -0,0 +1,39 @@
1
+ #
2
+ # Imports step protocols from HEKA PatchMaster files.
3
+ #
4
+ # This file is part of Myokit.
5
+ # See http://myokit.org for copyright, sharing, and licensing details.
6
+ #
7
+ import myokit.formats
8
+
9
+
10
+ class PatchMasterImporter(myokit.formats.Importer):
11
+ """
12
+ This :class:`Importer <myokit.formats.Importer>` can import (step)
13
+ protocols from "series" inside HEKA PatchMaster files.
14
+ """
15
+
16
+ def supports_protocol(self):
17
+ return True
18
+
19
+ def protocol(self, filename, group=None, series=None):
20
+ """
21
+ Attempts to load the protocol from the file at ``filename``.
22
+
23
+ Because PatchMaster files can contain several experiments, a further
24
+ selection can be made with the arguments:
25
+
26
+ ``filename``
27
+ The file to read
28
+ ``group``
29
+ The group to read from (as a string).
30
+ ``series``
31
+ The integer index of the desired series in the specified group.
32
+
33
+ """
34
+ from myokit.formats.heka import PatchMasterFile
35
+ with PatchMasterFile(filename) as f:
36
+ group = f.group(group)
37
+ series = group[series]
38
+ return series.stimulus().protocol()
39
+