myokit 1.36.0__py3-none-any.whl → 1.37.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. myokit/__init__.py +6 -19
  2. myokit/_datablock.py +45 -55
  3. myokit/_datalog.py +2 -2
  4. myokit/_err.py +26 -3
  5. myokit/_expressions.py +241 -127
  6. myokit/_model_api.py +19 -13
  7. myokit/_myokit_version.py +1 -1
  8. myokit/_sim/cvodessim.c +221 -149
  9. myokit/_sim/jacobian.py +3 -3
  10. myokit/_sim/mcl.h +54 -0
  11. myokit/_sim/openclsim.py +5 -5
  12. myokit/_sim/rhs.py +1 -1
  13. myokit/formats/__init__.py +4 -9
  14. myokit/formats/ansic/_ewriter.py +4 -20
  15. myokit/formats/heka/_patchmaster.py +16 -10
  16. myokit/formats/opencl/_ewriter.py +3 -42
  17. myokit/formats/opencl/template/minilog.py +1 -1
  18. myokit/formats/sympy/_ereader.py +2 -1
  19. myokit/formats/wcp/_wcp.py +3 -3
  20. myokit/gui/datalog_viewer.py +12 -7
  21. myokit/lib/hh.py +3 -0
  22. myokit/lib/markov.py +2 -2
  23. myokit/lib/plots.py +4 -4
  24. myokit/tests/data/formats/wcp-file-empty.wcp +0 -0
  25. myokit/tests/test_datablock.py +10 -10
  26. myokit/tests/test_datalog.py +4 -1
  27. myokit/tests/test_expressions.py +532 -251
  28. myokit/tests/test_formats_ansic.py +6 -18
  29. myokit/tests/test_formats_cpp.py +0 -5
  30. myokit/tests/test_formats_cuda.py +7 -15
  31. myokit/tests/test_formats_easyml.py +4 -9
  32. myokit/tests/test_formats_latex.py +10 -11
  33. myokit/tests/test_formats_matlab.py +0 -8
  34. myokit/tests/test_formats_opencl.py +0 -29
  35. myokit/tests/test_formats_python.py +2 -19
  36. myokit/tests/test_formats_stan.py +0 -13
  37. myokit/tests/test_formats_sympy.py +3 -3
  38. myokit/tests/test_formats_wcp.py +15 -0
  39. myokit/tests/test_lib_hh.py +36 -0
  40. myokit/tests/test_model.py +20 -20
  41. myokit/tests/test_parsing.py +19 -0
  42. {myokit-1.36.0.dist-info → myokit-1.37.0.dist-info}/METADATA +1 -1
  43. {myokit-1.36.0.dist-info → myokit-1.37.0.dist-info}/RECORD +47 -46
  44. {myokit-1.36.0.dist-info → myokit-1.37.0.dist-info}/LICENSE.txt +0 -0
  45. {myokit-1.36.0.dist-info → myokit-1.37.0.dist-info}/WHEEL +0 -0
  46. {myokit-1.36.0.dist-info → myokit-1.37.0.dist-info}/entry_points.txt +0 -0
  47. {myokit-1.36.0.dist-info → myokit-1.37.0.dist-info}/top_level.txt +0 -0
@@ -176,11 +176,13 @@ class AnsiCExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
176
176
 
177
177
  def test_conditions(self):
178
178
  a, b, c, d = self.abcd
179
+ p = myokit.Equal(a, b)
180
+ q = myokit.NotEqual(c, d)
179
181
 
180
- self.eq(And(a, b), '(a && b)')
181
- self.eq(Or(d, c), '(d || c)')
182
- self.eq(Not(And(a, b)), '(!(a && b))')
183
- self.eq(Not(c), '(!(c))')
182
+ self.eq(And(p, q), '((a == b) && (c != d))')
183
+ self.eq(Or(q, p), '((c != d) || (a == b))')
184
+ self.eq(Not(And(p, q)), '(!((a == b) && (c != d)))')
185
+ self.eq(Not(p), '(!(a == b))')
184
186
 
185
187
  self.eq(Equal(a, b), '(a == b)')
186
188
  self.eq(NotEqual(a, b), '(a != b)')
@@ -191,12 +193,6 @@ class AnsiCExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
191
193
 
192
194
  self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
193
195
  self.eq(Or(More(d, c), Less(b, a)), '((d > c) || (b < a))')
194
- self.eq(Not(Or(Number(1), Number(2))), '(!(1.0 || 2.0))')
195
- self.eq(Not(Less(Number(1), Number(2))), '(!(1.0 < 2.0))')
196
- self.eq(Not(Plus(Number(1), Number(2))), '(!(1.0 + 2.0))')
197
-
198
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
199
- '((0.0 == 0.0) == 0.0)')
200
196
 
201
197
  def test_conditionals(self):
202
198
 
@@ -206,11 +202,6 @@ class AnsiCExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
206
202
  self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
207
203
  '((a == b) ? c : ((a == d) ? 3.0 : 4.0))')
208
204
 
209
- # Extra parentheses if condition is not a condition
210
- self.eq(If(a, d, c), '((a) ? d : c)')
211
- self.eq(Piecewise(a, b, c, d, Number(4)),
212
- '((a) ? b : ((c) ? d : 4.0))')
213
-
214
205
  # Using if-then-else function
215
206
  w = self._target()
216
207
  w.set_lhs_function(lambda v: v.var().name())
@@ -329,9 +320,6 @@ class AnsiCExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
329
320
  c.add(If(Not(true), a, b), 20)
330
321
  c.add(If(Not(false), a, b), 10)
331
322
 
332
- c.add(If(Equal(Equal(Number(0), Number(0)), Number(0)), a, b), 20)
333
- c.add(If(Equal(Equal(Number(0), Number(0)), Number(1)), a, b), 10)
334
-
335
323
  c.add(Piecewise(true, Number(10), false, Number(20), Number(30)), 10)
336
324
  c.add(Piecewise(true, Number(10), true, Number(20), Number(30)), 10)
337
325
  c.add(Piecewise(false, Number(10), true, Number(20), Number(30)), 20)
@@ -72,11 +72,6 @@ class CppExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
72
72
  myokit.Number(4)),
73
73
  '((a == b) ? c : ((a == d) ? 3.0 : 4.0))')
74
74
 
75
- # Extra parentheses if condition is not a condition
76
- self.eq(myokit.If(a, d, c), '((a) ? d : c)')
77
- self.eq(myokit.Piecewise(a, b, c, d, myokit.Number(4)),
78
- '((a) ? b : ((c) ? d : 4.0))')
79
-
80
75
  # Using if-then-else function
81
76
  w = self._target()
82
77
  w.set_lhs_function(lambda v: v.var().name())
@@ -186,10 +186,12 @@ class CudaExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
186
186
  # Inherited from c-based
187
187
 
188
188
  a, b, c, d = self.abcd
189
- self.eq(And(a, b), '(a && b)')
190
- self.eq(Or(d, c), '(d || c)')
191
- self.eq(Not(And(a, b)), '(!(a && b))')
192
- self.eq(Not(c), '(!(c))')
189
+ p = Equal(a, b)
190
+ q = NotEqual(c, d)
191
+ self.eq(And(p, q), '((a == b) && (c != d))')
192
+ self.eq(Or(q, p), '((c != d) || (a == b))')
193
+ self.eq(Not(And(p, p)), '(!((a == b) && (a == b)))')
194
+ self.eq(Not(q), '(!(c != d))')
193
195
 
194
196
  self.eq(Equal(a, b), '(a == b)')
195
197
  self.eq(NotEqual(a, b), '(a != b)')
@@ -198,14 +200,9 @@ class CudaExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
198
200
  self.eq(MoreEqual(c, a), '(c >= a)')
199
201
  self.eq(LessEqual(b, d), '(b <= d)')
200
202
 
201
- self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
202
203
  self.eq(Or(More(d, c), Less(b, a)), '((d > c) || (b < a))')
203
- self.eq(Not(Or(Number(1), Number(2))), '(!(1.0f || 2.0f))')
204
+ self.eq(Not(Equal(Number(1), Number(2))), '(!(1.0f == 2.0f))')
204
205
  self.eq(Not(Less(Number(1), Number(2))), '(!(1.0f < 2.0f))')
205
- self.eq(Not(Plus(Number(1), Number(2))), '(!(1.0f + 2.0f))')
206
-
207
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
208
- '((0.0f == 0.0f) == 0.0f)')
209
206
 
210
207
  def test_conditionals(self):
211
208
  # Inherited from c-based
@@ -216,11 +213,6 @@ class CudaExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
216
213
  self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
217
214
  '((a == b) ? c : ((a == d) ? 3.0f : 4.0f))')
218
215
 
219
- # If condition is not a condition
220
- self.eq(If(a, d, c), '((a) ? d : c)')
221
- self.eq(Piecewise(a, b, c, d, Number(4)),
222
- '((a) ? b : ((c) ? d : 4.0f))')
223
-
224
216
 
225
217
  if __name__ == '__main__':
226
218
  unittest.main()
@@ -400,16 +400,14 @@ class EasyMLExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
400
400
  def test_conditions(self):
401
401
  # Inherited from CBasedExpressionWriter
402
402
  a, b, c, d = self.abcd
403
- self.eq(Not(And(a, b)), '(!(a && b))')
404
- self.eq(Not(c), '(!(c))')
403
+ self.eq(Not(NotEqual(a, b)), '(!(a != b))')
405
404
  self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
406
405
  self.eq(Or(More(d, c), MoreEqual(b, a)), '((d > c) || (b >= a))')
407
406
  self.eq(Or(Less(d, c), LessEqual(b, a)), '((d < c) || (b <= a))')
408
- self.eq(Not(Or(Number(1), Number(2))), '(!(1.0 || 2.0))')
407
+ self.eq(
408
+ Not(Or(Equal(Number(1), Number(2)), Equal(Number(3), Number(4)))),
409
+ '(!((1.0 == 2.0) || (3.0 == 4.0)))')
409
410
  self.eq(Not(Less(Number(1), Number(2))), '(!(1.0 < 2.0))')
410
- self.eq(Not(Plus(Number(1), Number(2))), '(!(1.0 + 2.0))')
411
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
412
- '((0.0 == 0.0) == 0.0)')
413
411
 
414
412
  def test_conditionals(self):
415
413
  # Inherited from CBasedExpressionWriter
@@ -418,9 +416,6 @@ class EasyMLExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
418
416
  self.eq(Piecewise(NotEqual(d, c), b, a), '((d != c) ? b : a)')
419
417
  self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
420
418
  '((a == b) ? c : ((a == d) ? 3.0 : 4.0))')
421
- self.eq(If(a, d, c), '((a) ? d : c)')
422
- self.eq(Piecewise(a, b, c, d, Number(4)),
423
- '((a) ? b : ((c) ? d : 4.0))')
424
419
 
425
420
 
426
421
  if __name__ == '__main__':
@@ -179,10 +179,6 @@ class LatexExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
179
179
  def test_conditions(self):
180
180
  a, b, c, d = self.abcd
181
181
 
182
- self.eq(And(a, b), r'\left(\text{a}\and\text{b}\right)')
183
- self.eq(Or(d, c), r'\left(\text{d}\or\text{c}\right)')
184
- self.eq(Not(c), r'\left(\not\text{c}\right)')
185
-
186
182
  self.eq(Equal(a, b), r'\left(\text{a}=\text{b}\right)')
187
183
  self.eq(NotEqual(a, b), r'\left(\text{a}\neq\text{b}\right)')
188
184
  self.eq(More(b, a), r'\left(\text{b}>\text{a}\right)')
@@ -193,18 +189,21 @@ class LatexExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
193
189
  self.eq(And(Equal(a, b), NotEqual(c, d)),
194
190
  r'\left(\left(\text{a}=\text{b}\right)\and'
195
191
  r'\left(\text{c}\neq\text{d}\right)\right)')
192
+ self.eq(Or(Equal(a, b), NotEqual(c, d)),
193
+ r'\left(\left(\text{a}=\text{b}\right)\or'
194
+ r'\left(\text{c}\neq\text{d}\right)\right)')
196
195
  self.eq(Not(Equal(d, d)),
197
196
  r'\left(\not\left(\text{d}=\text{d}\right)\right)')
198
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
199
- r'\left(\left(0.0=0.0\right)=0.0\right)')
200
197
 
201
198
  def test_conditionals(self):
202
-
203
199
  a, b, c, d = self.abcd
204
- self.eq(myokit.If(a, b, c),
205
- r'\text{if}\left(\text{a},\text{b},\text{c}\right)')
206
- self.eq(myokit.Piecewise(a, b, c, d, Number(1)), r'\text{piecewise}'
207
- r'\left(\text{a},\text{b},\text{c},\text{d},1.0\right)')
200
+ p = myokit.Equal(a, b)
201
+ q = myokit.NotEqual(c, d)
202
+ self.eq(myokit.If(p, c, d), r'\text{if}\left(\left(\text{a}=\text{b}'
203
+ r'\right),\text{c},\text{d}\right)')
204
+ self.eq(myokit.Piecewise(p, b, q, d, Number(1)), r'\text{piecewise}'
205
+ r'\left(\left(\text{a}=\text{b}\right),\text{b},\left(\text{c}'
206
+ r'\neq\text{d}\right),\text{d},1.0\right)')
208
207
 
209
208
 
210
209
  if __name__ == '__main__':
@@ -177,10 +177,6 @@ class MatlabExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
177
177
  def test_conditions(self):
178
178
  a, b, c, d = self.abcd
179
179
 
180
- self.eq(And(a, b), '(a && b)')
181
- self.eq(Or(d, c), '(d || c)')
182
- self.eq(Not(c), '(!c)')
183
-
184
180
  self.eq(Equal(a, b), '(a == b)')
185
181
  self.eq(NotEqual(a, b), '(a != b)')
186
182
  self.eq(More(b, a), '(b > a)')
@@ -191,10 +187,6 @@ class MatlabExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
191
187
  self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
192
188
  self.eq(Or(More(d, c), Less(b, a)), '((d > c) || (b < a))')
193
189
  self.eq(Not(Equal(d, d)), '(!(d == d))')
194
- self.eq(Not(Or(Number(1), Number(2))), '(!(1.0 || 2.0))')
195
-
196
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
197
- '((0.0 == 0.0) == 0.0)')
198
190
 
199
191
  def test_conditionals(self):
200
192
  a, b, c, d = self.abcd
@@ -170,16 +170,8 @@ class OpenCLExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
170
170
  self.assertEqual(w.ex(Abs(self.a)), 'fabs(comp.a)')
171
171
 
172
172
  def test_conditions(self):
173
- # Can be greatly simplified after
174
- # https://github.com/myokit/myokit/issues/1056
175
-
176
173
  a, b, c, d = self.abcd
177
174
 
178
- self.eq(And(a, b), '((a != 0.0f) && (b != 0.0f))')
179
- self.eq(Or(d, c), '((d != 0.0f) || (c != 0.0f))')
180
- self.eq(Not(And(a, b)), '(!((a != 0.0f) && (b != 0.0f)))')
181
- self.eq(Not(c), '(!(c != 0.0f))')
182
-
183
175
  self.eq(Equal(a, b), '(a == b)')
184
176
  self.eq(NotEqual(a, b), '(a != b)')
185
177
  self.eq(More(b, a), '(b > a)')
@@ -189,23 +181,7 @@ class OpenCLExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
189
181
 
190
182
  self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
191
183
  self.eq(Or(More(d, c), Less(b, a)), '((d > c) || (b < a))')
192
- self.eq(Not(Or(Number(1), Number(2))),
193
- '(!((1.0f != 0.0f) || (2.0f != 0.0f)))')
194
184
  self.eq(Not(Less(Number(1), Number(2))), '(!(1.0f < 2.0f))')
195
- self.eq(Not(Plus(Number(1), Number(2))), '(!(1.0f + 2.0f != 0.0f))')
196
-
197
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
198
- '((0.0f == 0.0f) == (0.0f != 0.0f))')
199
-
200
- def test_boolean_comparisons(self):
201
- # Can be removed after https://github.com/myokit/myokit/issues/1056
202
-
203
- a, b = self.ab
204
- c1, c2 = More(Number(5), Number(3)), Less(Number(2), Number(1))
205
- self.eq(Equal(c1, c2), '((5.0f > 3.0f) == (2.0f < 1.0f))')
206
- self.eq(NotEqual(c1, a), '((5.0f > 3.0f) != (a != 0.0f))')
207
- self.eq(More(b, c2), '((b != 0.0f) > (2.0f < 1.0f))')
208
- self.eq(LessEqual(a, b), '(a <= b)')
209
185
 
210
186
  def test_conditionals(self):
211
187
  # Inherited from c-based
@@ -216,11 +192,6 @@ class OpenCLExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
216
192
  self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
217
193
  '((a == b) ? c : ((a == d) ? 3.0f : 4.0f))')
218
194
 
219
- # If condition is not a condition
220
- self.eq(If(a, d, c), '((a != 0.0f) ? d : c)')
221
- self.eq(Piecewise(a, b, c, d, Number(4)),
222
- '((a != 0.0f) ? b : ((c != 0.0f) ? d : 4.0f))')
223
-
224
195
 
225
196
  if __name__ == '__main__':
226
197
  unittest.main()
@@ -232,10 +232,6 @@ class PythonExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
232
232
  def test_conditions(self):
233
233
  a, b, c, d = self.abcd
234
234
 
235
- self.eq(And(a, b), '(a and b)')
236
- self.eq(Or(d, c), '(d or c)')
237
- self.eq(Not(c), '(not c)')
238
-
239
235
  self.eq(Equal(a, b), '(a == b)')
240
236
  self.eq(NotEqual(a, b), '(a != b)')
241
237
  self.eq(More(b, a), '(b > a)')
@@ -246,7 +242,6 @@ class PythonExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
246
242
  self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) and (c != d))')
247
243
  self.eq(Or(More(d, c), Less(b, a)), '((d > c) or (b < a))')
248
244
  self.eq(Not(Equal(d, d)), '(not (d == d))')
249
- self.eq(Not(Or(Number(1), Number(2))), '(not (1.0 or 2.0))')
250
245
 
251
246
  true = Equal(Number(3), Number(3))
252
247
  self.py(true, True)
@@ -267,11 +262,6 @@ class PythonExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
267
262
  self.py(Not(true), False)
268
263
  self.py(Not(false), True)
269
264
 
270
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
271
- '((0.0 == 0.0) == 0.0)')
272
- self.py(Equal(Equal(Number(0), Number(0)), Number(0)), False)
273
- self.py(Equal(Equal(Number(0), Number(0)), Number(1)), True)
274
-
275
265
  def test_conditionals(self):
276
266
 
277
267
  a, b, c, d = self.abcd
@@ -501,10 +491,6 @@ class NumPyExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
501
491
  def test_conditions(self):
502
492
  a, b, c, d = self.abcd
503
493
 
504
- self.eq(And(a, b), 'numpy.logical_and(a, b)')
505
- self.eq(Or(d, c), 'numpy.logical_or(d, c)')
506
- self.eq(Not(c), 'numpy.logical_not(c)')
507
-
508
494
  self.eq(Equal(a, b), '(a == b)')
509
495
  self.eq(NotEqual(a, b), '(a != b)')
510
496
  self.eq(More(b, a), '(b > a)')
@@ -517,8 +503,6 @@ class NumPyExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
517
503
  self.eq(Or(More(d, c), Less(b, a)),
518
504
  'numpy.logical_or((d > c), (b < a))')
519
505
  self.eq(Not(Equal(d, d)), 'numpy.logical_not((d == d))')
520
- self.eq(Not(Or(Number(1), Number(2))),
521
- 'numpy.logical_not(numpy.logical_or(1.0, 2.0))')
522
506
 
523
507
  true = Equal(Number(3), Number(3))
524
508
  self.py(true, True)
@@ -532,9 +516,8 @@ class NumPyExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
532
516
  self.py(LessEqual(Number(3), Number(3)), True)
533
517
  self.py(And(true, false), False)
534
518
  self.py(And(true, true), True)
535
- self.py(Or(a, b), [True, True, True, False],
536
- [True, True, False, False], [True, False, True, False])
537
- self.py(Not(a), [True, False], [False, True])
519
+ self.py(Or(true, false), True)
520
+ self.py(Not(true), False)
538
521
 
539
522
  def test_conditionals(self):
540
523
  a, b, c, d = self.abcd
@@ -139,10 +139,6 @@ class StanExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
139
139
  def test_conditions(self):
140
140
  a, b, c, d = self.abcd
141
141
 
142
- self.eq(And(a, b), '(a && b)')
143
- self.eq(Or(d, c), '(d || c)')
144
- self.eq(Not(c), '(!c)')
145
-
146
142
  self.eq(Equal(a, b), '(a == b)')
147
143
  self.eq(NotEqual(a, b), '(a != b)')
148
144
  self.eq(More(b, a), '(b > a)')
@@ -153,10 +149,6 @@ class StanExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
153
149
  self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
154
150
  self.eq(Or(More(d, c), Less(b, a)), '((d > c) || (b < a))')
155
151
  self.eq(Not(Equal(d, d)), '(!(d == d))')
156
- self.eq(Not(Or(Number(1), Number(2))), '(!(1.0 || 2.0))')
157
-
158
- self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
159
- '((0.0 == 0.0) == 0.0)')
160
152
 
161
153
  def test_conditionals(self):
162
154
  a, b, c, d = self.abcd
@@ -165,11 +157,6 @@ class StanExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
165
157
  self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
166
158
  '((a == b) ? c : ((a == d) ? 3.0 : 4.0))')
167
159
 
168
- # Extra parentheses if condition is not a condition
169
- self.eq(If(a, d, c), '(a ? d : c)')
170
- self.eq(Piecewise(a, b, c, d, Number(4)),
171
- '(a ? b : (c ? d : 4.0))')
172
-
173
160
 
174
161
  if __name__ == '__main__':
175
162
  unittest.main()
@@ -237,10 +237,10 @@ class SymPyReadWriteTest(unittest.TestCase):
237
237
  self.assertEqual(r.ex(cx), x)
238
238
 
239
239
  # Not
240
- x = myokit.Not(a)
241
- cx = sp.Not(ca)
240
+ x = myokit.Not(x)
241
+ cx = sp.Not(cx)
242
242
  self.assertEqual(w.ex(x), cx)
243
- self.assertEqual(r.ex(cx), x)
243
+ self.assertEqual(r.ex(cx), myokit.More(a, b)) # Can't test!
244
244
 
245
245
  # And
246
246
  cond1 = myokit.More(a, b)
@@ -210,6 +210,21 @@ class WcpTest(unittest.TestCase):
210
210
  self.assertRaises(NotImplementedError, w.da_units)
211
211
  self.assertRaises(NotImplementedError, w.da_protocol)
212
212
 
213
+ def test_empty_file(self):
214
+ # Tests reading a file with no data
215
+
216
+ path = os.path.join(DIR_FORMATS, 'wcp-file-empty.wcp')
217
+ w = wcp.WcpFile(path)
218
+ self.assertEqual(w.version(), '9')
219
+
220
+ # No records, but it still has a channel
221
+ self.assertEqual(w.record_count(), 0)
222
+ self.assertEqual(w.channel_count(), 1)
223
+ self.assertRaisesRegex(KeyError, 'empty file', w.channel, 0)
224
+
225
+ d = w.log()
226
+ self.assertEqual(len(d), 0)
227
+
213
228
  def test_figure_method(self):
214
229
  # Tests matplotlib_figure
215
230
  # Select matplotlib backend that doesn't require a screen
@@ -15,6 +15,8 @@ import myokit.lib.hh as hh
15
15
 
16
16
  from myokit.tests import DIR_DATA
17
17
 
18
+ from myokit.tests import WarningCollector
19
+
18
20
 
19
21
  MODEL = """
20
22
  [[model]]
@@ -914,6 +916,40 @@ class AnalyticalSimulationTest(unittest.TestCase):
914
916
  e = np.abs(d1['binding.I'] - d2['binding.I'])
915
917
  self.assertLess(np.max(e), 2e-4)
916
918
 
919
+ def test_tau_overflow(self):
920
+ # Overflows leading to tau=0 should still report current
921
+ # https://github.com/myokit/myokit/issues/1059
922
+
923
+ # Load model and convert to inf-tau form
924
+ fname = os.path.join(DIR_DATA, 'lr-1991-fitting.mmt')
925
+ model = hh.convert_hh_states_to_inf_tau_form(myokit.load_model(fname))
926
+
927
+ # Get initial state and set steady state
928
+ initial_state = model.get('ina.m').initial_value(as_float=True)
929
+ steady_state = 0.75
930
+ model.get('ina.m.inf').set_rhs(steady_state)
931
+
932
+ # Create an analytical simulation
933
+ model = hh.HHModel(model, states=['ina.m', 'ina.h', 'ina.j'],
934
+ parameters=['ina.p5'], current='ina.INa')
935
+ p = myokit.pacing.steptrain_linear(20, 40, 10, -80, 10, 10)
936
+ s = hh.AnalyticalSimulation(model, protocol=p)
937
+
938
+ # Setting p5=0.001 will trigger an overflow in ina.m.beta
939
+ s.set_parameters([0.001])
940
+ with WarningCollector() as wc:
941
+ # Log times chosen so that s._function varies length of _t
942
+ log = s.run(41, log_times=np.array([0, 1, 2, 10, 11, 12, 20, 40]))
943
+ self.assertIn('overflow', wc.text())
944
+
945
+ # Should be no NaNs in log
946
+ self.assertFalse(np.any(np.isnan(log['ina.INa'])))
947
+ self.assertFalse(np.any(np.isnan(log['ina.m'])))
948
+
949
+ # Should immediately jump from initial state to steady state
950
+ self.assertTrue(log['ina.m'][0] == initial_state)
951
+ self.assertTrue(np.all(log['ina.m'][1:] == steady_state))
952
+
917
953
 
918
954
  if __name__ == '__main__':
919
955
  unittest.main()
@@ -636,18 +636,18 @@ class ModelTest(unittest.TestCase):
636
636
  self.assertEqual(len(x), len(y))
637
637
 
638
638
  # Test with state argument
639
- state1 = [1, 2, 3, 4, 5, 6, 7, 8]
639
+ state1 = [-40, 2, 3, 4, 5, 6, 7, 8]
640
640
  state1[2] = 536.46745856785678567845745637
641
641
  x = m.format_state_derivatives(state1).splitlines()
642
642
  y = [
643
- 'membrane.V = 1 dot = 1.90853168050245158e+07', # noqa
644
- 'ina.m = 2 dot = -1.56738349674489310e+01', # noqa
645
- 'ina.h = 5.36467458567856738e+02 dot = -3.05729251015767022e+03', # noqa
646
- 'ina.j = 4 dot = -1.15731427949362953e+00', # noqa
647
- 'ica.d = 5 dot = -1.85001944916516836e-01', # noqa
648
- 'ica.f = 6 dot = -2.15435819790876573e-02', # noqa
649
- 'ik.x = 7 dot = -1.25154369264425316e-02', # noqa
650
- 'ica.Ca_i = 8 dot = -5.63431267451130036e-01', # noqa ^ ^^ ^ --------- ^
643
+ 'membrane.V = -40 dot = 3.03469590344436094e+07', # noqa
644
+ 'ina.m = 2 dot = -1.05478017767301395e+01', # noqa
645
+ 'ina.h = 5.36467458567856738e+02 dot = -2.46776607600654586e+02', # noqa
646
+ 'ina.j = 4 dot = -3.72528160028099076e-01', # noqa
647
+ 'ica.d = 5 dot = -1.69660729614147049e-01', # noqa
648
+ 'ica.f = 6 dot = -6.23551094458582103e-02', # noqa
649
+ 'ik.x = 7 dot = -1.18521143826784449e-02', # noqa
650
+ 'ica.Ca_i = 8 dot = -5.52361267451130011e-01', # noqa
651
651
  ]
652
652
  for a, b in zip(x, y):
653
653
  self.assertTrue(almost_equal(a, b))
@@ -664,7 +664,7 @@ class ModelTest(unittest.TestCase):
664
664
  out = m.format_state_derivatives(
665
665
  state1, precision=myokit.SINGLE_PRECISION).splitlines()
666
666
  self.assertEqual(len(out), 8)
667
- self.assertEqual(out[0][:15], 'membrane.V = 1 ')
667
+ self.assertEqual(out[0][:16], 'membrane.V = -40')
668
668
  self.assertEqual(out[1][:15], 'ina.m = 2 ')
669
669
  self.assertEqual(out[2][:29], 'ina.h = 5.364674586e+02')
670
670
  self.assertEqual(out[3][:15], 'ina.j = 4 ')
@@ -673,18 +673,18 @@ class ModelTest(unittest.TestCase):
673
673
  self.assertEqual(out[6][:15], 'ik.x = 7 ')
674
674
  self.assertEqual(out[7][:15], 'ica.Ca_i = 8 ')
675
675
  out = [x[x.index('dot') + 6:] for x in out]
676
- self.assertEqual(out[0][:8], ' 1.90853')
677
- self.assertEqual(out[1][:8], '-1.56738')
678
- self.assertEqual(out[2][:8], '-3.05729')
679
- self.assertEqual(out[3][:8], '-1.15731')
680
- self.assertEqual(out[4][:8], '-1.85001')
681
- self.assertEqual(out[5][:8], '-2.15435')
682
- self.assertEqual(out[6][:8], '-1.25154')
683
- self.assertEqual(out[7][:8], '-5.63431')
676
+ self.assertEqual(out[0][:8], ' 3.03469')
677
+ self.assertEqual(out[1][:8], '-1.05478')
678
+ self.assertEqual(out[2][:8], '-2.46776')
679
+ self.assertEqual(out[3][:8], '-3.72528')
680
+ self.assertEqual(out[4][:8], '-1.69660')
681
+ self.assertEqual(out[5][:8], '-6.23551')
682
+ self.assertEqual(out[6][:8], '-1.18521')
683
+ self.assertEqual(out[7][:8], '-5.52361')
684
684
  self.assertEqual(out[0][12:], 'e+07')
685
685
  self.assertEqual(out[1][12:], 'e+01')
686
- self.assertEqual(out[2][12:], 'e+03')
687
- self.assertEqual(out[3][12:], 'e+00')
686
+ self.assertEqual(out[2][12:], 'e+02')
687
+ self.assertEqual(out[3][12:], 'e-01')
688
688
  self.assertEqual(out[4][12:], 'e-01')
689
689
  self.assertEqual(out[5][12:], 'e-02')
690
690
  self.assertEqual(out[6][12:], 'e-02')
@@ -697,6 +697,25 @@ class PhasedParseTest(unittest.TestCase):
697
697
  self.assertRaisesRegex(
698
698
  myokit.ParseError, 'Duplicate variable unit', p, code)
699
699
 
700
+ # Invalid use of condition
701
+ code = (
702
+ '[[model]]',
703
+ '[x]',
704
+ 't = 0 bind time',
705
+ 'x = 3 == 2',
706
+ )
707
+ self.assertRaisesRegex(
708
+ myokit.ParseError, 'not be a condition', p, code)
709
+ code = (
710
+ '[[model]]',
711
+ 'x.y = 1 < 2',
712
+ '[x]',
713
+ 't = 0 bind time',
714
+ 'dot(y) = 1',
715
+ )
716
+ self.assertRaisesRegex(
717
+ myokit.ParseError, 'not be a condition', p, code)
718
+
700
719
  def test_parse_unit(self):
701
720
  # Test :meth:`parse_unit` and :meth:`parse_unit_string`.
702
721
  from myokit._parsing import parse_unit_string as p
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: myokit
3
- Version: 1.36.0
3
+ Version: 1.37.0
4
4
  Summary: A modeling and simulation tool for cardiac cellular electrophysiology
5
5
  Home-page: http://myokit.org
6
6
  Author: Michael Clerx