myokit 1.37.3__py3-none-any.whl → 1.37.5__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/_datablock.py +4 -6
- myokit/_myokit_version.py +1 -1
- myokit/_parsing.py +5 -1
- myokit/_sim/cable.c +1 -1
- myokit/_sim/fiber_tissue.c +1 -1
- myokit/_unit.py +1 -1
- myokit/formats/axon/_abf.py +72 -46
- myokit/formats/heka/_patchmaster.py +56 -15
- myokit/formats/sbml/_api.py +11 -8
- myokit/gui/datalog_viewer.py +61 -8
- myokit/tests/test_formats_axon.py +4 -0
- myokit/tests/test_sbml_export.py +21 -0
- {myokit-1.37.3.dist-info → myokit-1.37.5.dist-info}/METADATA +13 -13
- {myokit-1.37.3.dist-info → myokit-1.37.5.dist-info}/RECORD +18 -18
- {myokit-1.37.3.dist-info → myokit-1.37.5.dist-info}/WHEEL +1 -1
- {myokit-1.37.3.dist-info → myokit-1.37.5.dist-info}/LICENSE.txt +0 -0
- {myokit-1.37.3.dist-info → myokit-1.37.5.dist-info}/entry_points.txt +0 -0
- {myokit-1.37.3.dist-info → myokit-1.37.5.dist-info}/top_level.txt +0 -0
myokit/_datablock.py
CHANGED
|
@@ -2169,8 +2169,7 @@ class ColorMapViridis(ColorMap):
|
|
|
2169
2169
|
https://github.com/BIDS/colormap/blob/master/colormaps.py
|
|
2170
2170
|
and were distributed under a CC0 license.
|
|
2171
2171
|
|
|
2172
|
-
Viridis was designed by
|
|
2173
|
-
Walt.
|
|
2172
|
+
Viridis was designed by Nathaniel J. Smith and Stefan van der Walt.
|
|
2174
2173
|
"""
|
|
2175
2174
|
_VALUES = np.array((
|
|
2176
2175
|
(68, 1, 84),
|
|
@@ -2456,14 +2455,13 @@ class ColorMapViridis(ColorMap):
|
|
|
2456
2455
|
|
|
2457
2456
|
class ColorMapInferno(ColorMap):
|
|
2458
2457
|
"""
|
|
2459
|
-
A colormap using "
|
|
2458
|
+
A colormap using "Inferno".
|
|
2460
2459
|
|
|
2461
|
-
The values used by this color map are
|
|
2460
|
+
The values used by this color map are adapted from
|
|
2462
2461
|
https://github.com/BIDS/colormap/blob/master/colormaps.py
|
|
2463
2462
|
and were distributed under a CC0 license.
|
|
2464
2463
|
|
|
2465
|
-
|
|
2466
|
-
Walt.
|
|
2464
|
+
Inferno was designed by Nathaniel J. Smith and Stefan van der Walt.
|
|
2467
2465
|
"""
|
|
2468
2466
|
_VALUES = np.array((
|
|
2469
2467
|
(0, 0, 4),
|
myokit/_myokit_version.py
CHANGED
|
@@ -14,7 +14,7 @@ __release__ = True
|
|
|
14
14
|
# incompatibility
|
|
15
15
|
# - Changes to revision indicate bugfixes, tiny new features
|
|
16
16
|
# - There is no significance to odd/even numbers
|
|
17
|
-
__version_tuple__ = 1, 37,
|
|
17
|
+
__version_tuple__ = 1, 37, 5
|
|
18
18
|
|
|
19
19
|
# String version of the version number
|
|
20
20
|
__version__ = '.'.join([str(x) for x in __version_tuple__])
|
myokit/_parsing.py
CHANGED
|
@@ -949,6 +949,10 @@ def parse_protocol_from_stream(stream):
|
|
|
949
949
|
'Expecting [[protocol]]')
|
|
950
950
|
expect(next(stream), EOL)
|
|
951
951
|
|
|
952
|
+
# Handling "next" accuracy: after summing, times set using "next" will be
|
|
953
|
+
# rounded to 9 digits precision.
|
|
954
|
+
round_next = lambda x: round(x, 9)
|
|
955
|
+
|
|
952
956
|
# Create protocol
|
|
953
957
|
protocol = myokit.Protocol()
|
|
954
958
|
|
|
@@ -971,7 +975,7 @@ def parse_protocol_from_stream(stream):
|
|
|
971
975
|
'Unable to determine end of previous event, "next" cannot'
|
|
972
976
|
' be used here.')
|
|
973
977
|
else:
|
|
974
|
-
t = t_next
|
|
978
|
+
t = round_next(t_next)
|
|
975
979
|
else:
|
|
976
980
|
t = parse_number(stream)
|
|
977
981
|
if t_last is None:
|
myokit/_sim/cable.c
CHANGED
myokit/_sim/fiber_tissue.c
CHANGED
myokit/_unit.py
CHANGED
|
@@ -186,7 +186,7 @@ class Unit:
|
|
|
186
186
|
``unit2``.
|
|
187
187
|
|
|
188
188
|
Exponents are stored internally as floating point numbers, and the
|
|
189
|
-
check for closeness
|
|
189
|
+
check for closeness is made with a relative tolerance of ``reltol`` and
|
|
190
190
|
absolute tolerance of ``abstol``, using::
|
|
191
191
|
|
|
192
192
|
abs(a - b) < max(reltol * max(abs(a), abs(b)), abstol)
|
myokit/formats/axon/_abf.py
CHANGED
|
@@ -254,7 +254,6 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
254
254
|
# Read the protocol information
|
|
255
255
|
self._n_adc = None
|
|
256
256
|
self._n_dac = None
|
|
257
|
-
|
|
258
257
|
self._rate = None
|
|
259
258
|
self._mode = None
|
|
260
259
|
|
|
@@ -264,6 +263,7 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
264
263
|
self._run_start_to_start = None
|
|
265
264
|
self._sweeps_per_run = None
|
|
266
265
|
self._sweep_start_to_start = None
|
|
266
|
+
self._equal_length_sweeps = None
|
|
267
267
|
self._samples_per_channel = None
|
|
268
268
|
|
|
269
269
|
# To be able to treat v1 and v2 slightly more easily, we define 3
|
|
@@ -281,7 +281,6 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
281
281
|
# will have A/D but no (or no supported) D/A. Conversely protocol files
|
|
282
282
|
# will have D/A only. So all in one sweep is easiest.
|
|
283
283
|
self._sweeps = None
|
|
284
|
-
|
|
285
284
|
self._read_3_protocol_information()
|
|
286
285
|
|
|
287
286
|
# Read and calculate conversion factors for integer data in ADC
|
|
@@ -553,7 +552,10 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
553
552
|
# 1.x versions only seem to have 1 DAC channel, but this is not
|
|
554
553
|
# supported here.
|
|
555
554
|
self._n_adc = int(h['nADCNumChannels'])
|
|
556
|
-
|
|
555
|
+
if h['sDACChannelName'] is None: # pragma: no cover
|
|
556
|
+
self._n_dac = 2
|
|
557
|
+
else:
|
|
558
|
+
self._n_dac = min(len(h['sDACChannelName']), 2)
|
|
557
559
|
self._rate = 1e6 / (h['fADCSampleInterval'] * self._n_adc)
|
|
558
560
|
self._mode = h['nOperationMode']
|
|
559
561
|
else:
|
|
@@ -577,11 +579,7 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
577
579
|
'Unsupported acquisition method'
|
|
578
580
|
f' {acquisition_modes[self._mode]}; unable to read D/A'
|
|
579
581
|
' channels.')
|
|
580
|
-
|
|
581
|
-
# Remaining code is all about reading D/A info for episodic
|
|
582
|
-
# stimulation, so return
|
|
583
582
|
self._n_dac = 0
|
|
584
|
-
return
|
|
585
583
|
|
|
586
584
|
# Gather protocol information
|
|
587
585
|
if self._version < 2:
|
|
@@ -668,9 +666,16 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
668
666
|
self._sweep_start_to_start = self._samples_per_channel / self._rate
|
|
669
667
|
|
|
670
668
|
# Create empty sweeps
|
|
671
|
-
|
|
672
|
-
|
|
669
|
+
if self._mode == ACMODE_GAP_FREE: # pragma: no cover
|
|
670
|
+
# In gap-free mode, treat the data as a single sweep
|
|
671
|
+
n = 1
|
|
672
|
+
elif self._is_protocol_file:
|
|
673
|
+
# In protocol file, there is no number of recorded sweeps, so use
|
|
674
|
+
# intended number of sweeps instead
|
|
673
675
|
n = self._sweeps_per_run
|
|
676
|
+
else:
|
|
677
|
+
# Use number of recorded sweeps
|
|
678
|
+
n = h['lActualSweeps']
|
|
674
679
|
self._sweeps = [Sweep() for i in range(n)]
|
|
675
680
|
|
|
676
681
|
# User lists are not supported for D/A reconstruction
|
|
@@ -811,7 +816,8 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
811
816
|
# Get binary integer format
|
|
812
817
|
dt = np.dtype('i2') if h['nDataFormat'] == 0 else np.dtype('f4')
|
|
813
818
|
|
|
814
|
-
# Get number of channels, create a numpy memory map
|
|
819
|
+
# Get number of channels, create a numpy memory map of all data
|
|
820
|
+
# The map has size n and starts at offset o
|
|
815
821
|
if self._version < 2:
|
|
816
822
|
# Old files, get info from fields stored directly in header
|
|
817
823
|
o = h['lDataSectionPtr'] * BLOCKSIZE \
|
|
@@ -823,37 +829,57 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
823
829
|
n = h['sections']['Data']['length']
|
|
824
830
|
data = np.memmap(self._filepath, dt, 'r', shape=(n,), offset=o)
|
|
825
831
|
|
|
826
|
-
# Load
|
|
832
|
+
# Load information about sweep sizes from "SynchArray".
|
|
833
|
+
# The number of sweep information structs will be n, and information
|
|
834
|
+
# starts at an offset o
|
|
827
835
|
if self._version < 2:
|
|
828
836
|
n = h['lSynchArraySize']
|
|
829
837
|
o = h['lSynchArrayPtr'] * BLOCKSIZE
|
|
830
838
|
else:
|
|
831
839
|
n = h['sections']['SynchArray']['length']
|
|
832
840
|
o = h['sections']['SynchArray']['index'] * BLOCKSIZE
|
|
833
|
-
if n > 0:
|
|
834
|
-
dt = [(str('offset'), str('i4')), (str('len'), str('i4'))]
|
|
835
|
-
sweep_data = np.memmap(
|
|
836
|
-
self._filepath, dt, 'r', shape=(n,), offset=o)
|
|
837
|
-
else: # pragma: no cover
|
|
838
|
-
# Cover pragma: Don't have appropriate test file
|
|
839
|
-
sweep_data = np.empty((1), dt)
|
|
840
|
-
sweep_data[0]['len'] = data.size
|
|
841
|
-
sweep_data[0]['offset'] = 0
|
|
842
841
|
|
|
843
|
-
#
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
842
|
+
# Get sweep start times (real times, not array offsets) and sizes
|
|
843
|
+
# (as number of points in an array)
|
|
844
|
+
if self._mode != ACMODE_GAP_FREE:
|
|
845
|
+
# This will be read in as an array of numpy.Void objects, which are
|
|
846
|
+
# similar to structs. In ``dt`` we name the entries offset and len.
|
|
847
|
+
sweep_starts_sizes = np.memmap(
|
|
848
|
+
self._filepath, [('offset', 'i4'), ('len', 'i4')], 'r',
|
|
849
|
+
shape=(n,), offset=o)
|
|
850
|
+
else: # pragma: no cover
|
|
851
|
+
# In gap-free model, all data is a single sweep
|
|
852
|
+
sweep_starts_sizes = [(0, len(data))]
|
|
853
|
+
|
|
854
|
+
# Sanity check
|
|
855
|
+
if len(sweep_starts_sizes) != len(self._sweeps): # pragma: no cover
|
|
856
|
+
raise RuntimeError(
|
|
857
|
+
'Unexpected situation: number of sweeps is'
|
|
858
|
+
f' {len(self._sweeps)} but found list of'
|
|
859
|
+
f' {len(sweep_starts_sizes)} sweep sizes.')
|
|
860
|
+
|
|
861
|
+
# Check if sweep sizes are all the same
|
|
862
|
+
self._equal_length_sweeps = True
|
|
863
|
+
if len(sweep_starts_sizes) > 0:
|
|
864
|
+
size = sweep_starts_sizes[0][1]
|
|
865
|
+
for o, s in sweep_starts_sizes[1:]:
|
|
866
|
+
if s != size: # pragma: no cover
|
|
867
|
+
self._equal_length_sweeps = False
|
|
868
|
+
break
|
|
869
|
+
del size
|
|
870
|
+
|
|
871
|
+
# Episodic stimulation? Then increment start time using sweep interval
|
|
872
|
+
# First time is time listed in first sweep
|
|
873
|
+
if self._mode == ACMODE_EPISODIC_STIMULATION:
|
|
874
|
+
tstart = sweep_starts_sizes[0][0] / rate
|
|
850
875
|
|
|
851
876
|
# Get data
|
|
852
877
|
pos = 0
|
|
853
|
-
for i_sweep,
|
|
878
|
+
for i_sweep, (start, size) in enumerate(sweep_starts_sizes):
|
|
854
879
|
|
|
855
|
-
#
|
|
856
|
-
|
|
880
|
+
# Not episodic: Then use listed start time
|
|
881
|
+
if self._mode != ACMODE_EPISODIC_STIMULATION: # pragma: no cover
|
|
882
|
+
tstart = start / rate
|
|
857
883
|
|
|
858
884
|
# Calculate the correct size for variable-length event mode
|
|
859
885
|
if self._mode == ACMODE_VARIABLE_LENGTH_EVENTS: # pragma: no cover
|
|
@@ -874,25 +900,20 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
874
900
|
# If needed, reformat the integers
|
|
875
901
|
if h['nDataFormat'] == 0:
|
|
876
902
|
# Data given as integers? Convert to floating point
|
|
877
|
-
|
|
878
903
|
for i in range(self._n_adc):
|
|
879
904
|
part[:, i] *= self._adc_factors[i]
|
|
880
905
|
part[:, i] += self._adc_offsets[i]
|
|
881
906
|
|
|
882
|
-
#
|
|
883
|
-
if self._mode != ACMODE_EPISODIC_STIMULATION: # pragma: no cover
|
|
884
|
-
# All modes except episodic stimulation
|
|
885
|
-
start = data['offset'] / rate
|
|
886
|
-
|
|
887
|
-
# Create and populate sweep
|
|
907
|
+
# Create and populate sweep object
|
|
888
908
|
sweep = self._sweeps[i_sweep]
|
|
889
909
|
for i in range(self._n_adc):
|
|
890
910
|
c = Channel(self)
|
|
891
911
|
c._data = part[:, i] # Actually store the data
|
|
892
912
|
c._rate = rate
|
|
893
|
-
c._start =
|
|
913
|
+
c._start = tstart
|
|
894
914
|
c._is_reconstruction = False
|
|
895
915
|
|
|
916
|
+
# Add meta data
|
|
896
917
|
if self._version < 2:
|
|
897
918
|
j = h['nADCSamplingSeq'][i]
|
|
898
919
|
|
|
@@ -947,9 +968,9 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
947
968
|
|
|
948
969
|
sweep._channels.append(c)
|
|
949
970
|
|
|
971
|
+
# In episodic mode, increase time according to sweep interval
|
|
950
972
|
if self._mode == ACMODE_EPISODIC_STIMULATION:
|
|
951
|
-
|
|
952
|
-
start += self._sweep_start_to_start
|
|
973
|
+
tstart += self._sweep_start_to_start
|
|
953
974
|
|
|
954
975
|
def _read_6_da_reconstructions(self):
|
|
955
976
|
"""
|
|
@@ -1034,6 +1055,12 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
1034
1055
|
|
|
1035
1056
|
return int_id
|
|
1036
1057
|
|
|
1058
|
+
def acquisition_mode_str(self):
|
|
1059
|
+
"""
|
|
1060
|
+
Returns the acquisition mode, as a string.
|
|
1061
|
+
"""
|
|
1062
|
+
return acquisition_modes[self._mode]
|
|
1063
|
+
|
|
1037
1064
|
def channel(self, channel_id, join_sweeps=False):
|
|
1038
1065
|
# Docstring in SweepSource
|
|
1039
1066
|
channel_id = self._channel_id(channel_id)
|
|
@@ -1193,8 +1220,7 @@ class AbfFile(myokit.formats.SweepSource):
|
|
|
1193
1220
|
return self._da_units[index]
|
|
1194
1221
|
|
|
1195
1222
|
def equal_length_sweeps(self):
|
|
1196
|
-
|
|
1197
|
-
return True
|
|
1223
|
+
return self._equal_length_sweeps
|
|
1198
1224
|
|
|
1199
1225
|
def filename(self):
|
|
1200
1226
|
""" Returns this ABF file's filename. """
|
|
@@ -1530,13 +1556,13 @@ HEADER_FIELDS = {
|
|
|
1530
1556
|
# Note that a lot of the groups in the version 1 header start with obsolete
|
|
1531
1557
|
# fields, followed later by their newer equivalents.
|
|
1532
1558
|
1: [
|
|
1533
|
-
('fFileSignature', 0, '4s'),
|
|
1559
|
+
('fFileSignature', 0, '4s'), # Coarse file version indication
|
|
1534
1560
|
# Group 1, File info and sizes
|
|
1535
|
-
('fFileVersionNumber', 4, 'f'),
|
|
1536
|
-
('nOperationMode', 8, 'h'),
|
|
1561
|
+
('fFileVersionNumber', 4, 'f'), # Version number as float
|
|
1562
|
+
('nOperationMode', 8, 'h'), # Acquisition mode
|
|
1537
1563
|
('lActualAcqLength', 10, 'i'),
|
|
1538
1564
|
('nNumPointsIgnored', 14, 'h'),
|
|
1539
|
-
('lActualSweeps', 16, 'i'),
|
|
1565
|
+
('lActualSweeps', 16, 'i'), # AKA lActualEpisodes
|
|
1540
1566
|
('lFileStartDate', 20, 'i'),
|
|
1541
1567
|
('lFileStartTime', 24, 'i'),
|
|
1542
1568
|
('lStopWatchTime', 28, 'i'),
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
#
|
|
4
4
|
# Specifically, it targets the 2x90.2 format.
|
|
5
5
|
#
|
|
6
|
-
# It has not been extensively tested.
|
|
7
|
-
#
|
|
8
6
|
# Notes:
|
|
9
7
|
# - HEKA publishes a lot of information about its file format on its FTP
|
|
10
8
|
# server: server.hekahome.de
|
|
@@ -25,6 +23,9 @@
|
|
|
25
23
|
# numbers of steps are given; the manual mentions two types of log
|
|
26
24
|
# interpretation but there is no obvious field to select one; a "toggle"
|
|
27
25
|
# mode is mentioned in the manual but again is not easy to find in the file.
|
|
26
|
+
# - Series resistance prediction percentage is not stored separately in the
|
|
27
|
+
# Patchmaster file. In addition, the value stored seems to be either
|
|
28
|
+
# percentage compensation or prediction, without much consistency.
|
|
28
29
|
#
|
|
29
30
|
# This file is part of Myokit.
|
|
30
31
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
@@ -78,7 +79,8 @@ class PatchMasterFile:
|
|
|
78
79
|
represent a single cell, and each "series" will be a protocol (called a
|
|
79
80
|
"stimulus") run on that cell. Groups are named by the user. Series are
|
|
80
81
|
named after the "stimulus" they run. Sweeps are usually unnamed (although
|
|
81
|
-
they do have a ``label`` property), and channels are named by the
|
|
82
|
+
they do have a ``label`` property), and traces (channels) are named by the
|
|
83
|
+
user.
|
|
82
84
|
|
|
83
85
|
To access groups, index them by integer, or use the :meth:`group` method to
|
|
84
86
|
find the first group with a given label::
|
|
@@ -236,6 +238,9 @@ class PatchMasterFile:
|
|
|
236
238
|
def __iter__(self):
|
|
237
239
|
return iter(self._pulsed_tree)
|
|
238
240
|
|
|
241
|
+
def __len__(self):
|
|
242
|
+
return len(self._pulsed_tree)
|
|
243
|
+
|
|
239
244
|
def amplifier_tree(self):
|
|
240
245
|
"""
|
|
241
246
|
Returns this file's amplifier tree (an :class:`AmplifierFile` object),
|
|
@@ -291,8 +296,6 @@ class EndianAwareReader:
|
|
|
291
296
|
|
|
292
297
|
def read(self, form):
|
|
293
298
|
""" Read and unpack using the struct format ``form``. """
|
|
294
|
-
#if offset is not None:
|
|
295
|
-
# f.seek(offset)
|
|
296
299
|
return struct.unpack(
|
|
297
300
|
self._e + form, self._f.read(struct.calcsize(form)))
|
|
298
301
|
|
|
@@ -626,7 +629,7 @@ class Series(TreeNode, myokit.formats.SweepSource):
|
|
|
626
629
|
1. In the individual :class:`Trace` objects. This is somewhat
|
|
627
630
|
counter-intuitive as some of these properties (e.g.
|
|
628
631
|
:meth:Trace.r_pipette()`) were set before a series was
|
|
629
|
-
acquired and do
|
|
632
|
+
acquired and do not change between channels or sweeps.
|
|
630
633
|
2. In the series' :class:`AmplifierState`, which can be accessed via
|
|
631
634
|
the :meth:`amplifier_state()` method.
|
|
632
635
|
|
|
@@ -984,6 +987,8 @@ class Series(TreeNode, myokit.formats.SweepSource):
|
|
|
984
987
|
log.meta[f'{pre}current_gain_mV_per_pA'] = a.current_gain()
|
|
985
988
|
log.meta[f'{pre}filter1'] = a.filter1_str()
|
|
986
989
|
log.meta[f'{pre}filter2'] = a.filter2_str()
|
|
990
|
+
log.meta[f'{pre}filter1_kHz'] = a.filter1().frequency()
|
|
991
|
+
log.meta[f'{pre}filter2_kHz'] = a.filter2()[2]
|
|
987
992
|
log.meta[f'{pre}stimulus_filter'] = a.stimulus_filter_str()
|
|
988
993
|
log.meta[f'{pre}ljp_correction_mV'] = a.ljp()
|
|
989
994
|
log.meta[f'{pre}voltage_offset_mV'] = a.v_off()
|
|
@@ -991,6 +996,10 @@ class Series(TreeNode, myokit.formats.SweepSource):
|
|
|
991
996
|
if a.c_fast_enabled():
|
|
992
997
|
log.meta[f'{pre}c_fast_compensation_enabled'] = 'true'
|
|
993
998
|
log.meta[f'{pre}c_fast_pF'] = a.c_fast()
|
|
999
|
+
cf = a.c_fast_detailed()
|
|
1000
|
+
log.meta[f'{pre}c_fast_amp1_pF'] = cf[0]
|
|
1001
|
+
log.meta[f'{pre}c_fast_amp2_pF'] = cf[1]
|
|
1002
|
+
log.meta[f'{pre}c_fast_tau2_us'] = cf[2]
|
|
994
1003
|
else:
|
|
995
1004
|
log.meta[f'{pre}c_fast_compensation_enabled'] = 'false'
|
|
996
1005
|
log.meta[f'{pre}c_slow_pF'] = a.c_slow()
|
|
@@ -1080,6 +1089,9 @@ class Series(TreeNode, myokit.formats.SweepSource):
|
|
|
1080
1089
|
# C fast
|
|
1081
1090
|
if a.c_fast_enabled():
|
|
1082
1091
|
out.append(f' C fast compensation: {a.c_fast()} pF,')
|
|
1092
|
+
cf = a.c_fast_detailed()
|
|
1093
|
+
out.append(f' C fast (amp1, amp2, tau2): {cf[0]} pF, {cf[1]}'
|
|
1094
|
+
f' pF, {cf[2]} us')
|
|
1083
1095
|
else:
|
|
1084
1096
|
out.append(' C fast compensation: not enabled')
|
|
1085
1097
|
# C slow
|
|
@@ -1197,7 +1209,6 @@ class Sweep(TreeNode):
|
|
|
1197
1209
|
# Seconds since first sweep, based on self._time, set by parent series
|
|
1198
1210
|
self._time_since_first = None
|
|
1199
1211
|
|
|
1200
|
-
#self._data_offset = None
|
|
1201
1212
|
self._stimulus_id = None
|
|
1202
1213
|
|
|
1203
1214
|
def _read_properties(self, handle, reader):
|
|
@@ -1205,7 +1216,6 @@ class Sweep(TreeNode):
|
|
|
1205
1216
|
i = handle.tell()
|
|
1206
1217
|
handle.seek(i + 4) # SwLabel = 4; (* String32Type *)
|
|
1207
1218
|
self._label = reader.str(32)
|
|
1208
|
-
#self._data_offset = reader.read1('i')
|
|
1209
1219
|
handle.seek(i + 40) # SwStimCount = 40; (* INT32 *)
|
|
1210
1220
|
self._stimulus_id = reader.read1('i') - 1
|
|
1211
1221
|
handle.seek(i + 48) # SwTime = 48; (* LONGREAL *)
|
|
@@ -1352,6 +1362,7 @@ class Trace(TreeNode):
|
|
|
1352
1362
|
handle.seek(i + 40) # TrData
|
|
1353
1363
|
self._data_pos = reader.read1('i')
|
|
1354
1364
|
self._n = reader.read1('i')
|
|
1365
|
+
handle.seek(i + 70) # TrDataFormat
|
|
1355
1366
|
dtype = int(reader.read1('b'))
|
|
1356
1367
|
self._data_type = _data_types[dtype]
|
|
1357
1368
|
self._data_size = _data_sizes[dtype]
|
|
@@ -1635,6 +1646,20 @@ class Trace(TreeNode):
|
|
|
1635
1646
|
class AmplifierState:
|
|
1636
1647
|
"""
|
|
1637
1648
|
Describes the state of an amplifier used by PatchMaster.
|
|
1649
|
+
|
|
1650
|
+
This "state" contains lots of valuable meta data about the fast and slow
|
|
1651
|
+
capacitance correction, the series resistance compensation (and/or
|
|
1652
|
+
prediction, but see below!), the filtering, the gain, and voltage offset
|
|
1653
|
+
corrections (zeroing and online LJP).
|
|
1654
|
+
|
|
1655
|
+
A notable issue is information omission is information about the series
|
|
1656
|
+
compensation _prediction_ feature. By default, the level of prediction is
|
|
1657
|
+
the same as the level of correction. A checkbox in the software (which the
|
|
1658
|
+
manual erroneously described as an on/off switch) can be used to set both
|
|
1659
|
+
values independently. If this is done, it becomes unclear what the value in
|
|
1660
|
+
the file represents, as only one value is stored. For this reason, if
|
|
1661
|
+
prediction is set seperately from correction, both values must be noted
|
|
1662
|
+
down by the experimenter and the value from the file should be ignored.
|
|
1638
1663
|
"""
|
|
1639
1664
|
def __init__(self, handle, reader):
|
|
1640
1665
|
|
|
@@ -1697,10 +1722,13 @@ class AmplifierState:
|
|
|
1697
1722
|
# 2 is the combined bandwidth of Filter 1 and Filter 2.
|
|
1698
1723
|
handle.seek(i + 239) # sF2Response = 239; (* BYTE *)
|
|
1699
1724
|
self._filter2_type = Filter2Type(reader.read1('b'))
|
|
1700
|
-
|
|
1701
|
-
|
|
1725
|
+
if self._filter2_type is Filter2Type.BYPASS:
|
|
1726
|
+
self._filter2_freq_solo = 0
|
|
1727
|
+
else:
|
|
1728
|
+
handle.seek(i + 24) # sF2Frequency = 24; (* LONGREAL *)
|
|
1729
|
+
self._filter2_freq_solo = reader.read1('d') * 1e-3
|
|
1702
1730
|
handle.seek(i + 16) # sF2Bandwidth = 16; (* LONGREAL *)
|
|
1703
|
-
self._filter2_freq_both = reader.read1('d')
|
|
1731
|
+
self._filter2_freq_both = reader.read1('d') * 1e-3
|
|
1704
1732
|
|
|
1705
1733
|
# Suspect this indicates external filter 2
|
|
1706
1734
|
#handle.seek(i + 287) # sF2Source = 287; (* BYTE *)
|
|
@@ -1818,11 +1846,13 @@ class AmplifierState:
|
|
|
1818
1846
|
"""
|
|
1819
1847
|
Returns a tuple ``(type, f_both, f_solo)`` describing the Filter 2
|
|
1820
1848
|
settings, where ``type`` is a :class:`Filter2Type`, where ``f_both`` is
|
|
1821
|
-
the frequency in
|
|
1822
|
-
the frequency of Filter 2 alone.
|
|
1849
|
+
the frequency in kHz of both filters combined, and when ``f_solo`` is
|
|
1850
|
+
the frequency in kHz of Filter 2 alone.
|
|
1823
1851
|
|
|
1824
1852
|
The frequency shown in PatchMaster is that of both filters combined.
|
|
1825
1853
|
If the "bypass" filter is selected, the frequency settings are unused.
|
|
1854
|
+
In this case, ``f_both`` will be the frequency of filter 1 and
|
|
1855
|
+
``f_solo`` will be returned as 0.
|
|
1826
1856
|
|
|
1827
1857
|
For more information on Filter 1 and 2, see :class:`Filter1Setting`.
|
|
1828
1858
|
"""
|
|
@@ -1840,8 +1870,8 @@ class AmplifierState:
|
|
|
1840
1870
|
"""
|
|
1841
1871
|
if self._filter2_type is Filter2Type.BYPASS:
|
|
1842
1872
|
return str(self._filter2_type)
|
|
1843
|
-
fb = round(self._filter2_freq_both
|
|
1844
|
-
fs = round(self._filter2_freq_solo
|
|
1873
|
+
fb = round(self._filter2_freq_both, 2)
|
|
1874
|
+
fs = round(self._filter2_freq_solo, 2)
|
|
1845
1875
|
fb = int(fb) if fb == int(fb) else fb
|
|
1846
1876
|
return f'{self._filter2_type} {fb} kHz combined, {fs} kHz f2-only'
|
|
1847
1877
|
|
|
@@ -1949,6 +1979,17 @@ class Filter1Setting(enum.Enum):
|
|
|
1949
1979
|
else:
|
|
1950
1980
|
return 'HQ 30 kHz'
|
|
1951
1981
|
|
|
1982
|
+
def frequency(self):
|
|
1983
|
+
""" Returns the cut-off frequency for this filter setting, in kHz. """
|
|
1984
|
+
if self is Filter1Setting.BESSEL_100K:
|
|
1985
|
+
return 100
|
|
1986
|
+
elif self is Filter1Setting.BESSEL_30K:
|
|
1987
|
+
return 30
|
|
1988
|
+
elif self is Filter1Setting.BESSEL_10K:
|
|
1989
|
+
return 10
|
|
1990
|
+
else:
|
|
1991
|
+
return 30
|
|
1992
|
+
|
|
1952
1993
|
|
|
1953
1994
|
class Filter2Type(enum.Enum):
|
|
1954
1995
|
"""
|
myokit/formats/sbml/_api.py
CHANGED
|
@@ -313,15 +313,18 @@ class Model:
|
|
|
313
313
|
variable.uname(),
|
|
314
314
|
variable.is_constant(),
|
|
315
315
|
)
|
|
316
|
-
if variable.is_state() or variable.is_literal():
|
|
317
|
-
v.set_value(variable.rhs(), variable.is_state())
|
|
318
|
-
else:
|
|
319
|
-
# if variable is constant but not literal,
|
|
320
|
-
# set via initial value
|
|
321
|
-
v.set_initial_value(variable.rhs())
|
|
322
316
|
|
|
323
|
-
if variable.
|
|
324
|
-
|
|
317
|
+
if variable.is_constant():
|
|
318
|
+
if variable.is_literal():
|
|
319
|
+
v.set_value(variable.rhs())
|
|
320
|
+
else:
|
|
321
|
+
v.set_initial_value(variable.rhs())
|
|
322
|
+
else:
|
|
323
|
+
if variable.is_state():
|
|
324
|
+
v.set_initial_value(variable.initial_value())
|
|
325
|
+
v.set_value(variable.rhs(), True)
|
|
326
|
+
else:
|
|
327
|
+
v.set_value(variable.rhs())
|
|
325
328
|
|
|
326
329
|
unit = variable_unit(variable, time_unit)
|
|
327
330
|
if unit is not None:
|
myokit/gui/datalog_viewer.py
CHANGED
|
@@ -63,8 +63,8 @@ SETTINGS_FILE = os.path.join(myokit.DIR_USER, 'DataLogViewer.ini')
|
|
|
63
63
|
# About
|
|
64
64
|
ABOUT = '<h1>' + TITLE + '</h1>' + """
|
|
65
65
|
<p>
|
|
66
|
-
The DataLog viewer is a PROTOTYPE utility to examine time series data
|
|
67
|
-
|
|
66
|
+
The DataLog viewer is a PROTOTYPE utility to examine time series data in
|
|
67
|
+
formats supported by Myokit.
|
|
68
68
|
</p>
|
|
69
69
|
<p>
|
|
70
70
|
System info:
|
|
@@ -162,6 +162,8 @@ class DataLogViewer(myokit.gui.MyokitApplication):
|
|
|
162
162
|
self._tool_next_file.setEnabled(True)
|
|
163
163
|
self._tool_prev_file.setEnabled(True)
|
|
164
164
|
self._tabs.setCurrentIndex(0)
|
|
165
|
+
self._tool_close.setEnabled(True)
|
|
166
|
+
self._tool_close_all.setEnabled(True)
|
|
165
167
|
|
|
166
168
|
def action_about(self):
|
|
167
169
|
"""
|
|
@@ -178,15 +180,48 @@ class DataLogViewer(myokit.gui.MyokitApplication):
|
|
|
178
180
|
self._tabs.removeTab(index)
|
|
179
181
|
|
|
180
182
|
# Update buttons
|
|
181
|
-
|
|
183
|
+
n = self._tabs.count()
|
|
184
|
+
if n < 2:
|
|
182
185
|
self._tool_next_file.setEnabled(False)
|
|
183
186
|
self._tool_prev_file.setEnabled(False)
|
|
187
|
+
if n < 1:
|
|
188
|
+
self._tool_close.setEnabled(False)
|
|
189
|
+
self._tool_close_all.setEnabled(False)
|
|
184
190
|
|
|
185
191
|
# Delete tab
|
|
186
192
|
if tab is not None:
|
|
187
193
|
tab.deleteLater()
|
|
188
|
-
gc.collect()
|
|
189
194
|
del tab
|
|
195
|
+
gc.collect()
|
|
196
|
+
|
|
197
|
+
def action_close_current(self):
|
|
198
|
+
""" Close the current tab. """
|
|
199
|
+
idx = self._tabs.currentIndex()
|
|
200
|
+
if idx >= 0:
|
|
201
|
+
self.action_close(idx)
|
|
202
|
+
|
|
203
|
+
def action_close_all(self):
|
|
204
|
+
""" Called to close all tabs. """
|
|
205
|
+
n = self._tabs.count()
|
|
206
|
+
if n < 1:
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
# Get all tabs, to delete later
|
|
210
|
+
tabs = [self._tabs.widget(i) for i in range(n)]
|
|
211
|
+
# Remove all tabs, without deleting
|
|
212
|
+
self._tabs.clear()
|
|
213
|
+
|
|
214
|
+
# Update buttons
|
|
215
|
+
self._tool_close.setEnabled(False)
|
|
216
|
+
self._tool_close_all.setEnabled(False)
|
|
217
|
+
self._tool_next_file.setEnabled(False)
|
|
218
|
+
self._tool_prev_file.setEnabled(False)
|
|
219
|
+
|
|
220
|
+
# Delete tabs
|
|
221
|
+
for tab in tabs:
|
|
222
|
+
tab.deleteLater()
|
|
223
|
+
del tab, tabs
|
|
224
|
+
gc.collect()
|
|
190
225
|
|
|
191
226
|
def action_first_var(self):
|
|
192
227
|
""" Select the first variable in the current file. """
|
|
@@ -225,6 +260,10 @@ class DataLogViewer(myokit.gui.MyokitApplication):
|
|
|
225
260
|
if tab_count_new > tab_count:
|
|
226
261
|
self._tabs.setCurrentIndex(tab_count)
|
|
227
262
|
|
|
263
|
+
# Enable tab closing buttons
|
|
264
|
+
self._tool_close.setEnabled(True)
|
|
265
|
+
self._tool_close_all.setEnabled(True)
|
|
266
|
+
|
|
228
267
|
# Enable next/previous file menu items
|
|
229
268
|
if tab_count_new > 1:
|
|
230
269
|
self._tool_next_file.setEnabled(True)
|
|
@@ -285,6 +324,21 @@ class DataLogViewer(myokit.gui.MyokitApplication):
|
|
|
285
324
|
self._tool_open.setIcon(QtGui.QIcon.fromTheme('document-open'))
|
|
286
325
|
self._tool_open.triggered.connect(self.action_open)
|
|
287
326
|
self._menu_file.addAction(self._tool_open)
|
|
327
|
+
# File > Close
|
|
328
|
+
self._tool_close = QtGui.QAction('&Close tab', self)
|
|
329
|
+
self._tool_close.setShortcut('Ctrl+W')
|
|
330
|
+
self._tool_close.setStatusTip('Close the current tab')
|
|
331
|
+
self._tool_close.setIcon(QtGui.QIcon.fromTheme('document-close'))
|
|
332
|
+
self._tool_close.triggered.connect(self.action_close_current)
|
|
333
|
+
self._tool_close.setEnabled(False)
|
|
334
|
+
self._menu_file.addAction(self._tool_close)
|
|
335
|
+
# File > Close all
|
|
336
|
+
self._tool_close_all = QtGui.QAction('Close &all tabs', self)
|
|
337
|
+
self._tool_close_all.setStatusTip('Close all tabs')
|
|
338
|
+
self._tool_close_all.setIcon(QtGui.QIcon.fromTheme('document-close'))
|
|
339
|
+
self._tool_close_all.triggered.connect(self.action_close_all)
|
|
340
|
+
self._tool_close_all.setEnabled(False)
|
|
341
|
+
self._menu_file.addAction(self._tool_close_all)
|
|
288
342
|
# File > ----
|
|
289
343
|
self._menu_file.addSeparator()
|
|
290
344
|
# File > Quit
|
|
@@ -401,9 +455,7 @@ class DataLogViewer(myokit.gui.MyokitApplication):
|
|
|
401
455
|
self._path = path
|
|
402
456
|
|
|
403
457
|
def load_file(self, filename):
|
|
404
|
-
"""
|
|
405
|
-
Loads a data file.
|
|
406
|
-
"""
|
|
458
|
+
""" Loads a data file. """
|
|
407
459
|
root, ext = os.path.splitext(os.path.basename(filename))
|
|
408
460
|
try:
|
|
409
461
|
action = self._load_actions[ext.lower()]
|
|
@@ -700,7 +752,8 @@ class SweepSourceTab(GraphTabWidget):
|
|
|
700
752
|
widget.setLayout(vbox)
|
|
701
753
|
|
|
702
754
|
# Add tab
|
|
703
|
-
|
|
755
|
+
adda = 'D/A' if da else 'A/D'
|
|
756
|
+
self.addTab(widget, f'{adda}: {name}')
|
|
704
757
|
|
|
705
758
|
'''
|
|
706
759
|
def debug_tab(self, channel_index, da=True):
|
|
@@ -208,6 +208,8 @@ class AbfTest(unittest.TestCase):
|
|
|
208
208
|
self.assertIn('version 1.65', abf.meta_str())
|
|
209
209
|
self.maxDiff = None
|
|
210
210
|
self.assertEqual(abf.meta_str(), V1_INFO)
|
|
211
|
+
self.assertEqual(abf.acquisition_mode_str(),
|
|
212
|
+
'Episodic stimulation mode')
|
|
211
213
|
|
|
212
214
|
# Test getting full header runs without crashing
|
|
213
215
|
abf.meta_str(True)
|
|
@@ -445,6 +447,8 @@ class AbfTest(unittest.TestCase):
|
|
|
445
447
|
self.assertIn('version 2.0', abf.meta_str())
|
|
446
448
|
self.maxDiff = None
|
|
447
449
|
self.assertEqual(abf.meta_str(), V2_INFO)
|
|
450
|
+
self.assertEqual(abf.acquisition_mode_str(),
|
|
451
|
+
'Episodic stimulation mode')
|
|
448
452
|
|
|
449
453
|
# Test getting full header runs without crashing
|
|
450
454
|
abf.meta_str(True)
|
myokit/tests/test_sbml_export.py
CHANGED
|
@@ -170,6 +170,7 @@ class TestSBMLExport(unittest.TestCase):
|
|
|
170
170
|
self.assertIn("<listOfUnitDefinitions>", sbml_str)
|
|
171
171
|
self.assertIn('<unitDefinition id="m_per_s_times_1e3">', sbml_str)
|
|
172
172
|
|
|
173
|
+
def test_list_of_parameters_const_depend(self):
|
|
173
174
|
# Test setting a constant parameter that depends on another parameter
|
|
174
175
|
model = Model()
|
|
175
176
|
p = model.add_parameter("my_parameter")
|
|
@@ -193,6 +194,7 @@ class TestSBMLExport(unittest.TestCase):
|
|
|
193
194
|
self.assertIn('<initialAssignment symbol="my_parameter2">', sbml_str)
|
|
194
195
|
self.assertIn("<times/>\n <ci>my_parameter</ci>\n <cn>2.0</cn>", sbml_str) # noqa: E501
|
|
195
196
|
|
|
197
|
+
def test_list_of_parameters_var(self):
|
|
196
198
|
model = Model()
|
|
197
199
|
p = model.add_parameter("my_parameter", is_constant=False)
|
|
198
200
|
p.set_initial_value(myokit.Number(1))
|
|
@@ -325,3 +327,22 @@ class TestSBMLExport(unittest.TestCase):
|
|
|
325
327
|
sbml_str
|
|
326
328
|
)
|
|
327
329
|
|
|
330
|
+
def test_variable_dependent_variables(self):
|
|
331
|
+
m = myokit.Model()
|
|
332
|
+
c = m.add_component('comp')
|
|
333
|
+
t = c.add_variable('time', rhs=myokit.Number(0))
|
|
334
|
+
t.set_unit(myokit.units.second)
|
|
335
|
+
t.set_binding('time')
|
|
336
|
+
v = c.add_variable('var', initial_value=3)
|
|
337
|
+
v.set_rhs(myokit.Number(1))
|
|
338
|
+
v2 = c.add_variable('var2')
|
|
339
|
+
v2.set_rhs(myokit.Name(v))
|
|
340
|
+
|
|
341
|
+
s = sbml.Model.from_myokit_model(m)
|
|
342
|
+
self.assertEqual(s.parameter('var2').is_rate(), False)
|
|
343
|
+
self.assertEqual(s.parameter('var').is_rate(), True)
|
|
344
|
+
|
|
345
|
+
sbml_str = write_string(s).decode("utf8")
|
|
346
|
+
self.assertIn('<initialAssignment symbol="var">', sbml_str)
|
|
347
|
+
self.assertNotIn('<initialAssignment symbol="var2">', sbml_str)
|
|
348
|
+
self.assertIn('<assignmentRule variable="var2">', sbml_str)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: myokit
|
|
3
|
-
Version: 1.37.
|
|
3
|
+
Version: 1.37.5
|
|
4
4
|
Summary: A modeling and simulation tool for cardiac cellular electrophysiology
|
|
5
5
|
Home-page: http://myokit.org
|
|
6
6
|
Author: Michael Clerx
|
|
@@ -25,25 +25,25 @@ Description-Content-Type: text/markdown
|
|
|
25
25
|
License-File: LICENSE.txt
|
|
26
26
|
Requires-Dist: configparser
|
|
27
27
|
Requires-Dist: lxml
|
|
28
|
-
Requires-Dist: matplotlib
|
|
28
|
+
Requires-Dist: matplotlib>=2.2
|
|
29
29
|
Requires-Dist: numpy
|
|
30
30
|
Requires-Dist: setuptools
|
|
31
31
|
Provides-Extra: dev
|
|
32
|
-
Requires-Dist: coverage
|
|
33
|
-
Requires-Dist: flake8
|
|
32
|
+
Requires-Dist: coverage; extra == "dev"
|
|
33
|
+
Requires-Dist: flake8>=3; extra == "dev"
|
|
34
34
|
Provides-Extra: docs
|
|
35
|
-
Requires-Dist: sphinx
|
|
35
|
+
Requires-Dist: sphinx>=1.7.4; extra == "docs"
|
|
36
36
|
Provides-Extra: gui
|
|
37
|
-
Requires-Dist: pyqt6
|
|
38
|
-
Requires-Dist: sip
|
|
37
|
+
Requires-Dist: pyqt6; extra == "gui"
|
|
38
|
+
Requires-Dist: sip; extra == "gui"
|
|
39
39
|
Provides-Extra: optional
|
|
40
|
-
Requires-Dist: scipy
|
|
41
|
-
Requires-Dist: sympy
|
|
40
|
+
Requires-Dist: scipy; extra == "optional"
|
|
41
|
+
Requires-Dist: sympy; extra == "optional"
|
|
42
42
|
Provides-Extra: pyqt
|
|
43
|
-
Requires-Dist: pyqt6
|
|
44
|
-
Requires-Dist: sip
|
|
43
|
+
Requires-Dist: pyqt6; extra == "pyqt"
|
|
44
|
+
Requires-Dist: sip; extra == "pyqt"
|
|
45
45
|
Provides-Extra: pyside
|
|
46
|
-
Requires-Dist: pyside6
|
|
46
|
+
Requires-Dist: pyside6; extra == "pyside"
|
|
47
47
|
|
|
48
48
|
[](https://github.com/myokit/myokit/actions/workflows/unit-tests-ubuntu.yml)
|
|
49
49
|
[](https://github.com/myokit/myokit/actions/workflows/unit-tests-macos.yml)
|
|
@@ -123,7 +123,7 @@ A high-level plan for Myokit's future is provided in the [roadmap](./ROADMAP.md)
|
|
|
123
123
|
### Meet the team!
|
|
124
124
|
|
|
125
125
|
Myokit's development is driven by a [team](https://github.com/orgs/myokit/people) at the Universities of Nottingham, Oxford, and Macao, led by Michael Clerx (Nottingham).
|
|
126
|
-
It is guided by an external advisory
|
|
126
|
+
It is guided by an external advisory group composed of Jordi Heijman (Maastricht University), Trine Krogh-Madsen (Weill Cornell Medicine), and David Gavaghan (Oxford).
|
|
127
127
|
|
|
128
128
|
|
|
129
129
|
## Citing Myokit
|
|
@@ -2,18 +2,18 @@ myokit/__init__.py,sha256=6Df0drToZtBEqsRWTDtedcU_OMMn8d0oNxRtJaFAkww,13644
|
|
|
2
2
|
myokit/__main__.py,sha256=VXyt8m2GG62pz32H-qATT4tw988p-LlIKih0mkVYlJk,53688
|
|
3
3
|
myokit/_aux.py,sha256=x8VgBbdKF9yY7bBwi2mbuITyIzN3K7fj-ylCZrJQCJs,23948
|
|
4
4
|
myokit/_config.py,sha256=WoUMTcHOO9oerqtad7AnQgXAND41YO-WfqlSSyCuHgU,11989
|
|
5
|
-
myokit/_datablock.py,sha256=
|
|
5
|
+
myokit/_datablock.py,sha256=kz9oqggFhQ2ovyqTOEeOSgm8GdosPpHgDBKxNXFVPgE,88683
|
|
6
6
|
myokit/_datalog.py,sha256=eWMpgyLa5Nx98RQZO3fK2PZKp2vLsBCddq6nB-9aVK4,77749
|
|
7
7
|
myokit/_err.py,sha256=n8Ggy2VKnyx_h_ySuNe77tIFXzh1yO7sWBvc7YPC2cM,11974
|
|
8
8
|
myokit/_expressions.py,sha256=VpxJAax0OHAWj0AnIH5xkGVWLrmVxBP9tykaccV86BU,109246
|
|
9
9
|
myokit/_io.py,sha256=2ll5Yb-sbP4tvc3pPmzhNuv_PaRMPJlNRWb1TzXfELg,8948
|
|
10
10
|
myokit/_model_api.py,sha256=LRHT-RcqyB2UTNrvg7iMXN0D_lpParrks5YKcVZPJJY,194650
|
|
11
|
-
myokit/_myokit_version.py,sha256
|
|
12
|
-
myokit/_parsing.py,sha256=
|
|
11
|
+
myokit/_myokit_version.py,sha256=-XbOLRR_wIl6x4Vx_YsS-NvGU4aExjqMDkoe_gdCDoQ,726
|
|
12
|
+
myokit/_parsing.py,sha256=o7O39o50QWCKIPbadhxluv7lDdJbTfnYbV3kzfWOG78,74232
|
|
13
13
|
myokit/_progress.py,sha256=Mi2QU6Vqj4qudhXc76amXM31iID2Mo8Gljw5OH2COZ4,4410
|
|
14
14
|
myokit/_protocol.py,sha256=_N16LGHppIv4yCSPjy0q2f-Oed0yG1wMk0ipTtXnMck,30756
|
|
15
15
|
myokit/_system.py,sha256=IX3Q7_7f9X9aYsxSL2CXJc9bTcFJsJbfq_e2w-OkhOI,4602
|
|
16
|
-
myokit/_unit.py,sha256=
|
|
16
|
+
myokit/_unit.py,sha256=scKgDxN8bBab1jlYYMt3MkkJLC_DUUl5BbocjWYsop8,30102
|
|
17
17
|
myokit/float.py,sha256=7-BqdABN5Vm4HIgRMHSgcZ4O4Vd085-5hMB6z8zJZtg,3066
|
|
18
18
|
myokit/pacing.py,sha256=_My0GwIPJh4DuUiK_kYDNBcacUaOKsffjbK5LvgK6z8,4552
|
|
19
19
|
myokit/pype.py,sha256=JTKuoiwxGui6iqBXK4gxNlCdtH_IGY0FiZLtmaJ580c,8230
|
|
@@ -79,7 +79,7 @@ myokit/_bin/sundials-win-vs/lib/sundials_cvodes.lib,sha256=FEmPq4BcmyOZReaM68pMD
|
|
|
79
79
|
myokit/_bin/sundials-win-vs/lib/sundials_nvecserial.dll,sha256=QwCosLqDBV0YIYvxfTGm0h5rM6iDNNXt5apu3hMZDiY,160768
|
|
80
80
|
myokit/_bin/sundials-win-vs/lib/sundials_nvecserial.lib,sha256=UmH8HCEFT_A8hsIw9Mj-ZgXeqNJJNadHnvQj9RJsfQg,59576
|
|
81
81
|
myokit/_sim/__init__.py,sha256=CuO1se4k-kpyh0muzBjdTrVfm31ZjXRLAZYhBg8P0I4,13488
|
|
82
|
-
myokit/_sim/cable.c,sha256=
|
|
82
|
+
myokit/_sim/cable.c,sha256=mOWdKhx0tNwPVNItJd3-IzG8W_-fizaREqlrEZrrzK8,19186
|
|
83
83
|
myokit/_sim/cable.py,sha256=GF1LJhoR9iSjVi16n7PhKYvSn1bDJVzSws1i8nJwM4c,18908
|
|
84
84
|
myokit/_sim/cmodel.h,sha256=PlXRNDWV5JDsl28G-k3UlzwFCF5_crkAeWpRgPO8a0s,38795
|
|
85
85
|
myokit/_sim/cmodel.py,sha256=9amSihccWepI1SGI98b5tvvSq2cmAMLX-ecgHoXnc0Y,15775
|
|
@@ -88,7 +88,7 @@ myokit/_sim/compiler.py,sha256=80Qwk7_LOjbu0jt9_aeMLQMEvYj3H4xIoE525zUUEK8,2664
|
|
|
88
88
|
myokit/_sim/cvodessim.c,sha256=iWXHVSNTN2VqGGu24N8QFRWwpUUxDo17fTIP0Fv0Ikg,78062
|
|
89
89
|
myokit/_sim/cvodessim.py,sha256=T2vwuSJFtHWTdzJv7xhFRC9l2OJY-7r4L6VVEpnIZI8,46158
|
|
90
90
|
myokit/_sim/differential.hpp,sha256=LiaFNQks_4RkWeNEnUc48XjbdYyGSsxfWo35leygM68,15446
|
|
91
|
-
myokit/_sim/fiber_tissue.c,sha256=
|
|
91
|
+
myokit/_sim/fiber_tissue.c,sha256=P9AJZlq9C3DNFxpzvseBbqozxMg6oMiolitWr-cQtv4,47474
|
|
92
92
|
myokit/_sim/fiber_tissue.py,sha256=A3zyGPGHNjFdGgbIzCiKYN8o4L2nq7W_ZjO996jF9Kc,50780
|
|
93
93
|
myokit/_sim/jacobian.cpp,sha256=mvuxHnxiyg4GW-ik1qOgOGbaj-sb-DbtidsRDXfRIjc,8012
|
|
94
94
|
myokit/_sim/jacobian.py,sha256=-PWjGRqr8VygrqnITtju8aWDkPvt9srATcrenOShR1s,12927
|
|
@@ -111,7 +111,7 @@ myokit/formats/ansic/template/cable.c,sha256=e7V4CVeoIN0N8MSVenPmtst31HkiZb5Jfx1
|
|
|
111
111
|
myokit/formats/ansic/template/euler.c,sha256=_ENsjDV-J0P7JEIeZBRO3L_kjyWZWiORyH5uFJXmB0Q,6044
|
|
112
112
|
myokit/formats/ansic/template/sim.c,sha256=wf8aFpzyoEopZIG6vITfSkFdPPGkRX53hL8Lujjo5qs,14244
|
|
113
113
|
myokit/formats/axon/__init__.py,sha256=qgo7UvLOYP_IZDYijkJhdGtwLc40Q80UpksivXaVojg,538
|
|
114
|
-
myokit/formats/axon/_abf.py,sha256=
|
|
114
|
+
myokit/formats/axon/_abf.py,sha256=7SZPVeS43W8i-p6gGFX45_Zh3eIkYcQr5ceP24mBSUY,77759
|
|
115
115
|
myokit/formats/axon/_atf.py,sha256=B0DQ_SiYv_izygBFCe8QXewsmxjPpq-7M2rqXcSFND4,10543
|
|
116
116
|
myokit/formats/axon/_importer.py,sha256=WaPkQ7CCFOIQnEkOiXXd1ICHPiXPicv9YFyJB5yLt2k,826
|
|
117
117
|
myokit/formats/cellml/__init__.py,sha256=Iz5kYXkjx0_mypcR0h5mV0sfVkVwaUWzUH8z4Goetq8,1466
|
|
@@ -142,7 +142,7 @@ myokit/formats/easyml/_ewriter.py,sha256=5T1GoiMtotlKMY3ZaYKcoWUeUZtWIbh3Xii8x0v
|
|
|
142
142
|
myokit/formats/easyml/_exporter.py,sha256=lGUJBO3ZAJfVcbTBQUEkGqUqdmtMXDzfGGtVda54Bx0,15771
|
|
143
143
|
myokit/formats/heka/__init__.py,sha256=JsHFKPdtzlYDgtCwA4ENODMAhOen9ygl-RwtrPXz-wU,927
|
|
144
144
|
myokit/formats/heka/_importer.py,sha256=4HaxswB8Uvngahsh34eEXaQnE9SYakpugFo3jc6VNrA,1154
|
|
145
|
-
myokit/formats/heka/_patchmaster.py,sha256=
|
|
145
|
+
myokit/formats/heka/_patchmaster.py,sha256=QxNSxT2pFpjqRfzHXFerUexDVhQTJJ-7dX0YwAEFVxk,118662
|
|
146
146
|
myokit/formats/html/__init__.py,sha256=pFJtVdw_SIaZZO0dfYUH9XyqPO46CuxSTL4iwvcC-4U,457
|
|
147
147
|
myokit/formats/html/_exporter.py,sha256=kWTB_6peG1MoxWPnGjm35Axkmw1tONSX1dCwWt0_arE,2343
|
|
148
148
|
myokit/formats/html/_flatten.py,sha256=kosDcmr6KKrZbaIsXewGNiIAlpVq4N9POdPrKygcvQs,6606
|
|
@@ -173,7 +173,7 @@ myokit/formats/python/_ewriter.py,sha256=bdW3YrZLO7a_A_aqfnPQHAnyjU7EQBCG490oUF3
|
|
|
173
173
|
myokit/formats/python/_exporter.py,sha256=_qgRV1mFDZxhjhWG5rUsCkhaoGh-mxiZPwYA_6RHNRA,969
|
|
174
174
|
myokit/formats/python/template/sim.py,sha256=HHQMZUFKC0711AFgaA8mgYc75O576PMIsujjm00MZcM,10311
|
|
175
175
|
myokit/formats/sbml/__init__.py,sha256=6JeedBTc4Ct-bc7Tdu_P_adKalmW3AQUj91dM3Pzwnw,944
|
|
176
|
-
myokit/formats/sbml/_api.py,sha256=
|
|
176
|
+
myokit/formats/sbml/_api.py,sha256=s4jPk6_TyLP4Y7I5UcpTnRpoArcDoqXpH0iVr3dEGII,64828
|
|
177
177
|
myokit/formats/sbml/_exporter.py,sha256=_cjogI63t0j_Pt6LrKvYy70_oTvvMXCHtc8j-7WZzhg,1430
|
|
178
178
|
myokit/formats/sbml/_importer.py,sha256=CiejktBXOsVmq6FuP4ayBztUJ6d4peSqjxGltTBvn38,987
|
|
179
179
|
myokit/formats/sbml/_parser.py,sha256=ZEchxxsd7IdS-PDnIDppULiUmCUlvPDYBM98cXkLTzs,29181
|
|
@@ -193,7 +193,7 @@ myokit/formats/xml/_exporter.py,sha256=PxoqHcc9abRF5TXWTOpZ96krrNdcRBLNWEiOvExr8
|
|
|
193
193
|
myokit/formats/xml/_split.py,sha256=9q_ff11kqfFt9XNvJZHnNb_UcOymMxrpJrLLwJypKt4,393
|
|
194
194
|
myokit/gui/__init__.py,sha256=CXXlxDpavx2xHOD30Q-EhVkCsR1vI1_8DPMe7PvZUoE,6426
|
|
195
195
|
myokit/gui/datablock_viewer.py,sha256=DGVUl5qMJsPWdS7jA0Aw9d_lfU1x0HnoO1SDkb62LDo,49529
|
|
196
|
-
myokit/gui/datalog_viewer.py,sha256=
|
|
196
|
+
myokit/gui/datalog_viewer.py,sha256=GYv-s5dmxeFAX48b0HekUxvWDeCvRDXqNGEZdyyGM7Q,35558
|
|
197
197
|
myokit/gui/explorer.py,sha256=WCAU9g7lPKxddIgp9Sr4nTfQ2wTzN9faVvIxg1D1PVA,8676
|
|
198
198
|
myokit/gui/ide.py,sha256=T-Acv6bPt0TVADxhGeBjiASzISwjjpUabZ_Z-p3VKZ4,108238
|
|
199
199
|
myokit/gui/progress.py,sha256=kzm7QsnoNySi9f2oosUcvIOGq9eGi0Pt4QfMl4EViPA,2157
|
|
@@ -227,7 +227,7 @@ myokit/tests/test_expressions.py,sha256=o7dQV95Gx4diX2vdJbVQ-bEN5ROa14SUAb4EFSGK
|
|
|
227
227
|
myokit/tests/test_float.py,sha256=s4GpsSHDSmmstPTpXCFCLE-44lvZqM71OtVTooZBDSA,4882
|
|
228
228
|
myokit/tests/test_formats.py,sha256=UfxN8d2SkEip9SLZ4aBIE95WnY1LaGvnxd2xh8RWIA4,8085
|
|
229
229
|
myokit/tests/test_formats_ansic.py,sha256=3qnqOU-xvIPp-NSBno_IRVVgwBC8p59LprxYMFusD3E,12712
|
|
230
|
-
myokit/tests/test_formats_axon.py,sha256=
|
|
230
|
+
myokit/tests/test_formats_axon.py,sha256=vbc0_G4b7etzazyz0uFMSX9SveIExR8WXY41MdNGJ3k,33395
|
|
231
231
|
myokit/tests/test_formats_cellml.py,sha256=WeNecMsTWubIBq6C0QMU4-cR-ZpNk69dJ7aHldb22zE,19078
|
|
232
232
|
myokit/tests/test_formats_channelml.py,sha256=BS90euUpWN1DgkShTYK7fdwuP8qIt3CzUAXoiY5YZYc,6703
|
|
233
233
|
myokit/tests/test_formats_cpp.py,sha256=giVwKzbHmjqx6VZHQBI1OV4oZrBnaKmquBmWlt9igx0,3537
|
|
@@ -271,7 +271,7 @@ myokit/tests/test_pype.py,sha256=vf3mympasLZwgTUQTSoe8e98Hp31cXo71APjlZEANKE,240
|
|
|
271
271
|
myokit/tests/test_quantity.py,sha256=etmbqlqBNt2OZFku_P-s5n8RlA-gxVyRAWjOPq9xD7s,7373
|
|
272
272
|
myokit/tests/test_rhs_benchmarker.py,sha256=Gb3LaAiu8SW__BBM3l0TbMzxML1PpEqm3g8TCteyCZg,3452
|
|
273
273
|
myokit/tests/test_sbml_api.py,sha256=9SIwsAT5lyGYnVZvPjW-EOd6mdIbrGMFpB5e981vAxM,74820
|
|
274
|
-
myokit/tests/test_sbml_export.py,sha256=
|
|
274
|
+
myokit/tests/test_sbml_export.py,sha256=35KypObiBajpTaONhkv3HaT0JxN1r_i9p2bNBwB1N_I,14271
|
|
275
275
|
myokit/tests/test_sbml_parser.py,sha256=ipiFs8VHcXq1-yC_9XUuonMQPLhlrYdkqvQ05BdtYiw,54542
|
|
276
276
|
myokit/tests/test_simulation_1d.py,sha256=YIjqVoyOgxrvAabpSOfLfUAOBR6dIKJoqac92VjL4ww,19281
|
|
277
277
|
myokit/tests/test_simulation_cvodes.py,sha256=wqjp8D8ksINWmC1tyYeSpAaAzGqrpXVOYvqip1FObSI,48408
|
|
@@ -401,9 +401,9 @@ myokit/tests/data/multi/beeler-no-name.mmt,sha256=tBeWcTVag1gAQAvxWlUqH6GQhF1D4D
|
|
|
401
401
|
myokit/tests/data/multi/lr-1991.mmt,sha256=9jzHRAy1nLiBOPioiEpXmsRvIqwEezRY_ve2eHMDbTQ,6013
|
|
402
402
|
myokit/tests/data/multi/not-a-model.csv,sha256=7ek3pQXr2fpjNjFTs-B-T_kEehx8IQ-evdcg24dtMEs,109
|
|
403
403
|
myokit/tests/data/multi/subdir/beeler-no-name.mmt,sha256=tBeWcTVag1gAQAvxWlUqH6GQhF1D4DMnlmuePQn1vBY,3008
|
|
404
|
-
myokit-1.37.
|
|
405
|
-
myokit-1.37.
|
|
406
|
-
myokit-1.37.
|
|
407
|
-
myokit-1.37.
|
|
408
|
-
myokit-1.37.
|
|
409
|
-
myokit-1.37.
|
|
404
|
+
myokit-1.37.5.dist-info/LICENSE.txt,sha256=0WNshB_he7HnJ4ROvVAaX95yz9760DE9ps8PbyvrGvw,1833
|
|
405
|
+
myokit-1.37.5.dist-info/METADATA,sha256=dZnApEbm1uvpK324S7j7bY4ZrPOJQ4KjPxD-Ovfl03s,6260
|
|
406
|
+
myokit-1.37.5.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91
|
|
407
|
+
myokit-1.37.5.dist-info/entry_points.txt,sha256=yP9wy3w0YAAYUD5PYGliYKhnKvEp5l6p4S_XvXsqreM,48
|
|
408
|
+
myokit-1.37.5.dist-info/top_level.txt,sha256=vopnhGEticqud7tKy6L6dvi_n_AMXoiYBEiboRTnsWY,7
|
|
409
|
+
myokit-1.37.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|