myokit 1.38.0__py3-none-any.whl → 1.39.1__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 (44) hide show
  1. myokit/__init__.py +5 -0
  2. myokit/_config.py +18 -19
  3. myokit/_datablock.py +6 -5
  4. myokit/_expressions.py +6 -1
  5. myokit/_model_api.py +44 -18
  6. myokit/_myokit_version.py +1 -1
  7. myokit/_parsing.py +8 -2
  8. myokit/_sim/cvodessim.py +26 -0
  9. myokit/formats/__init__.py +37 -0
  10. myokit/formats/ansic/_ewriter.py +1 -1
  11. myokit/formats/axon/_abf.py +43 -9
  12. myokit/formats/cellml/v1/__init__.py +5 -5
  13. myokit/formats/cellml/v1/_api.py +220 -122
  14. myokit/formats/cellml/v1/_parser.py +91 -87
  15. myokit/formats/cellml/v1/_writer.py +13 -6
  16. myokit/formats/cellml/v2/__init__.py +5 -8
  17. myokit/formats/cellml/v2/_api.py +182 -106
  18. myokit/formats/cellml/v2/_parser.py +68 -64
  19. myokit/formats/cellml/v2/_writer.py +7 -3
  20. myokit/formats/heka/_patchmaster.py +71 -14
  21. myokit/formats/mathml/_parser.py +106 -67
  22. myokit/gui/source.py +18 -12
  23. myokit/lib/hh.py +21 -37
  24. myokit/tests/test_cellml_v1_api.py +227 -33
  25. myokit/tests/test_cellml_v1_parser.py +48 -17
  26. myokit/tests/test_cellml_v1_writer.py +14 -4
  27. myokit/tests/test_cellml_v2_api.py +132 -114
  28. myokit/tests/test_cellml_v2_parser.py +31 -1
  29. myokit/tests/test_cellml_v2_writer.py +8 -1
  30. myokit/tests/test_datalog.py +17 -0
  31. myokit/tests/test_expressions.py +61 -0
  32. myokit/tests/test_formats.py +99 -0
  33. myokit/tests/test_formats_mathml_content.py +97 -37
  34. myokit/tests/test_formats_python.py +1 -1
  35. myokit/tests/test_model_building.py +2 -0
  36. myokit/tests/test_parsing.py +32 -0
  37. myokit/tests/test_simulation_cvodes.py +10 -4
  38. myokit/tests/test_variable.py +10 -7
  39. {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/METADATA +22 -7
  40. {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/RECORD +44 -44
  41. {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/WHEEL +1 -1
  42. {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/entry_points.txt +0 -0
  43. {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info/licenses}/LICENSE.txt +0 -0
  44. {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/top_level.txt +0 -0
@@ -851,6 +851,65 @@ class TestCellML2ModelConversion(unittest.TestCase):
851
851
  mm = cm.myokit_model()
852
852
  self.assertEqual(mm.get('c.y').eval(), 6.2)
853
853
 
854
+ def test_m2c_initial_values(self):
855
+ # Test conversion of initial values
856
+
857
+ m = myokit.parse_model('''
858
+ [[model]]
859
+ x.a = 1e3
860
+ x.b = -1 # parsed as PrefixMinus(Number(1))
861
+ x.c = --+-+-5 # extreme case of same
862
+ x.d = 1 + sqrt(4)
863
+ x.e = x.p
864
+ x.f = x.p + 3
865
+ x.g = y.q
866
+
867
+ [x]
868
+ t = 0 bind time
869
+ dot(a) = 0
870
+ dot(b) = 1
871
+ dot(c) = 2
872
+ dot(d) = 3
873
+ dot(e) = 4
874
+ dot(f) = 5
875
+ dot(g) = 6
876
+ p = 12
877
+ g_init = 0
878
+
879
+ [y]
880
+ q = 13
881
+ ''')
882
+ self.assertIsInstance(m.get('x.b').initial_value(), myokit.PrefixMinus)
883
+
884
+ with WarningCollector() as w:
885
+ cm = cellml.Model.from_myokit_model(m)
886
+ self.assertFalse(w.has_warnings())
887
+ a, b, c, d, e, f, g, p = [cm['x'][i] for i in 'abcdefgp']
888
+ di = cm['x']['d_init']
889
+ fi = cm['x']['f_init']
890
+ gi = cm['x']['g_init_1']
891
+ self.assertEqual(a.initial_value(), myokit.Number(1e3))
892
+ self.assertEqual(b.initial_value(), myokit.Number(-1))
893
+ self.assertEqual(c.initial_value(), myokit.Number(5))
894
+ self.assertEqual(d.initial_value(), myokit.Name(di))
895
+ self.assertEqual(e.initial_value(), myokit.Name(p))
896
+ self.assertEqual(f.initial_value(), myokit.Name(fi))
897
+ self.assertEqual(g.initial_value(), myokit.Name(gi))
898
+ self.assertEqual(
899
+ fi.rhs(), myokit.Plus(myokit.Name(p), myokit.Number(3)))
900
+ # Note: ei has rhs x.q, not y.q, because connections!
901
+ self.assertEqual(gi.rhs(), myokit.Name(cm['x']['q']))
902
+ self.assertEqual(cm['x']['q'].interface(), 'public')
903
+ self.assertEqual(a.rhs(), myokit.Number(0))
904
+ self.assertEqual(b.rhs(), myokit.Number(1))
905
+ self.assertEqual(c.rhs(), myokit.Number(2))
906
+ self.assertEqual(d.rhs(), myokit.Number(3))
907
+ self.assertEqual(e.rhs(), myokit.Number(4))
908
+ self.assertEqual(f.rhs(), myokit.Number(5))
909
+ self.assertEqual(g.rhs(), myokit.Number(6))
910
+ cm.validate()
911
+ del di, fi, gi
912
+
854
913
  def test_m2c_oxmeta(self):
855
914
  # Test that oxmeta data is passed on when creating a CellML model.
856
915
 
@@ -929,7 +988,13 @@ class TestCellML2ModelConversion(unittest.TestCase):
929
988
  m.add_connection(x, xb)
930
989
  m.add_connection(xc, xb)
931
990
  z2 = c.add_variable('z2', 'metre')
932
- z2.set_initial_value(4)
991
+ z3 = c.add_variable('z3', 'metre')
992
+ m.add_units(
993
+ 'meter_per_second', myokit.units.meter / myokit.units.second)
994
+ z2.set_equation(myokit.Equation(
995
+ myokit.Derivative(myokit.Name(z2)), myokit.Number(1.23, 'm/s')))
996
+ z2.set_initial_value('z3')
997
+ z3.set_initial_value(13)
933
998
  t = a.add_variable('t', 'second')
934
999
  t.meta['yes'] = 'no'
935
1000
  m.set_variable_of_integration(t)
@@ -952,7 +1017,7 @@ class TestCellML2ModelConversion(unittest.TestCase):
952
1017
  self.assertEqual(mm.name(), 'm')
953
1018
 
954
1019
  # Check meta data is added
955
- self.assertIn('author', mm.meta)
1020
+ self.assertIn('mmt_authors', mm.meta)
956
1021
 
957
1022
  # Check meta data is passed on
958
1023
  self.assertIn('documentation', mm.meta)
@@ -963,20 +1028,16 @@ class TestCellML2ModelConversion(unittest.TestCase):
963
1028
  self.assertEqual(mm.get('a.t').meta['yes'], 'no')
964
1029
 
965
1030
  # Check components are present
966
- ma = mm['a']
967
- mb = mm['b']
968
- mc = mm['c']
1031
+ ma, mb, mc = mm['a'], mm['b'], mm['c']
969
1032
  self.assertEqual(len(mm), 3)
970
1033
 
971
1034
  # Check variables are present
972
- mt = ma['t']
973
- mx = ma['x']
1035
+ mt, mx = ma['t'], ma['x']
974
1036
  self.assertEqual(len(ma), 2)
975
1037
  my = mb['y']
976
1038
  self.assertEqual(len(mb), 1)
977
- mz = mc['z']
978
- mz2 = mc['z2']
979
- self.assertEqual(len(mc), 2)
1039
+ mz, mz2, mz3 = mc['z'], mc['z2'], mc['z3']
1040
+ self.assertEqual(len(mc), 3)
980
1041
 
981
1042
  # Check units are set
982
1043
  self.assertEqual(mt.unit(), myokit.units.second)
@@ -994,7 +1055,9 @@ class TestCellML2ModelConversion(unittest.TestCase):
994
1055
  self.assertEqual(
995
1056
  mz.rhs(),
996
1057
  myokit.Plus(myokit.Number(3, myokit.units.volt), myokit.Name(mx)))
997
- self.assertEqual(mz2.rhs(), myokit.Number(4, myokit.units.meter))
1058
+ self.assertEqual(mz3.rhs(), myokit.Number(13, myokit.units.meter))
1059
+ self.assertEqual(mz2.rhs(), myokit.Number(1.23, 'm/s'))
1060
+ self.assertEqual(mz2.initial_value(), myokit.Name(mz3))
998
1061
 
999
1062
  # Check state
1000
1063
  self.assertTrue(mx.is_state())
@@ -1314,27 +1377,74 @@ class TestCellML2Variable(unittest.TestCase):
1314
1377
  m.add_units('millivolt', myokit.units.mV)
1315
1378
  c = m.add_component('c1')
1316
1379
  x = c.add_variable('bart', 'volt', 'public')
1380
+ y = c.add_variable('bort', 'volt')
1381
+ y.set_initial_value(1)
1382
+ z = c.add_variable('burt', 'ampere')
1383
+ z.set_initial_value(0)
1384
+ d = m.add_component('c2')
1385
+ p = d.add_variable('birt', 'volt', 'public')
1317
1386
 
1318
1387
  # Not set yet
1319
1388
  self.assertIsNone(x.initial_value())
1320
1389
 
1321
- # Set with float
1390
+ # Set with number type
1322
1391
  x.set_initial_value(3)
1323
1392
  self.assertTrue(x.has_initial_value())
1324
- self.assertEqual(x.initial_value(), myokit.Number(3, myokit.units.V))
1393
+ self.assertEqual(
1394
+ x.initial_value(), myokit.Number(3, myokit.units.volt))
1395
+
1396
+ # If using Number, the units must be correct
1397
+ self.assertRaisesRegex(
1398
+ cellml.CellMLError, 'must have the same units',
1399
+ x.set_initial_value, myokit.Number(2, myokit.units.dimensionless))
1400
+ x.set_initial_value(myokit.Number(1, myokit.units.volt))
1401
+ self.assertEqual(
1402
+ x.initial_value(), myokit.Number(1, myokit.units.volt))
1325
1403
 
1326
- # Unit is ignored
1327
- x.set_initial_value(myokit.Number(2, myokit.units.dimensionless))
1328
- self.assertEqual(x.initial_value(), myokit.Number(2, myokit.units.V))
1404
+ # Prefix operators are fine
1405
+ x.set_initial_value(myokit.PrefixMinus(myokit.PrefixPlus(
1406
+ myokit.Number(1.23, myokit.units.volt))))
1407
+ self.assertEqual(
1408
+ x.initial_value(), myokit.Number(-1.23, myokit.units.volt))
1329
1409
 
1330
1410
  # Unset
1331
1411
  x.set_initial_value(None)
1332
1412
  self.assertIsNone(x.initial_value())
1333
1413
 
1334
- # Set with other than a number
1414
+ # Local names are allowed
1415
+ x.set_initial_value(myokit.Name(y))
1416
+ self.assertEqual(x.initial_value(), myokit.Name(y))
1335
1417
  self.assertRaisesRegex(
1336
- cellml.CellMLError, 'must be a real number',
1337
- x.set_initial_value, 'twelve')
1418
+ cellml.CellMLError, 'Non-local variable',
1419
+ x.set_initial_value, myokit.Name(p))
1420
+ self.assertRaisesRegex(
1421
+ cellml.CellMLError, 'Unknown local variable',
1422
+ x.set_initial_value, 'brrr')
1423
+
1424
+ # Strings are allowed
1425
+ x.set_initial_value('-1')
1426
+ self.assertEqual(
1427
+ x.initial_value(), myokit.Number(-1, myokit.units.volt))
1428
+ x.set_initial_value('3.21e4')
1429
+ self.assertEqual(
1430
+ x.initial_value(), myokit.Number(3.21e4, myokit.units.volt))
1431
+ x.set_initial_value('bort')
1432
+ self.assertEqual(x.initial_value(), myokit.Name(y))
1433
+ self.assertRaisesRegex(
1434
+ cellml.CellMLError, 'If given, a variable initial_value',
1435
+ x.set_initial_value, '@hello')
1436
+
1437
+ # Set with expression other than a number or name
1438
+ self.assertRaisesRegex(
1439
+ cellml.CellMLError, 'must be a real number or a local variable',
1440
+ x.set_initial_value, myokit.Plus(
1441
+ myokit.Number(1, myokit.units.volt),
1442
+ myokit.Number(2, myokit.units.volt)))
1443
+
1444
+ # Set with unhandled type
1445
+ self.assertRaisesRegex(
1446
+ cellml.CellMLError, 'must be a real number or a local variable',
1447
+ x.set_initial_value, self)
1338
1448
 
1339
1449
  def test_initial_value_setting_connection(self):
1340
1450
  # Tests setting of initial values on connected variables.
@@ -1394,8 +1504,8 @@ class TestCellML2Variable(unittest.TestCase):
1394
1504
  self.assertIs(z.initial_value_variable(), z)
1395
1505
 
1396
1506
  # Check double initial values can't be set
1397
- z.set_initial_value(v2)
1398
- z.set_initial_value(myokit.Number(200))
1507
+ z.set_initial_value(v3)
1508
+ z.set_initial_value(myokit.Number(200, myokit.units.V))
1399
1509
  z.set_initial_value(-123)
1400
1510
  self.assertRaisesRegex(
1401
1511
  cellml.CellMLError, 'Unable to change initial value',
@@ -1474,7 +1584,7 @@ class TestCellML2Variable(unittest.TestCase):
1474
1584
  # Only initial value set
1475
1585
  x.set_equation(None)
1476
1586
  self.assertEqual(x.rhs(), y.rhs())
1477
- self.assertEqual(y.rhs(), myokit.Number(4, myokit.units.V))
1587
+ self.assertEqual(y.rhs(), myokit.Number(4, myokit.units.volt))
1478
1588
 
1479
1589
  # Neither set
1480
1590
  y.set_initial_value(None)
@@ -1885,98 +1995,6 @@ class TestCellML2Methods(unittest.TestCase):
1885
1995
  self.assertFalse(cellml.is_identifier('123'))
1886
1996
  self.assertFalse(cellml.is_identifier('1e3'))
1887
1997
 
1888
- def test_is_integer_string(self):
1889
- # Tests is_integer_string().
1890
-
1891
- self.assertTrue(cellml.is_integer_string('0'))
1892
- self.assertTrue(cellml.is_integer_string('+0'))
1893
- self.assertTrue(cellml.is_integer_string('-0'))
1894
- self.assertTrue(cellml.is_integer_string('3'))
1895
- self.assertTrue(cellml.is_integer_string('+3'))
1896
- self.assertTrue(cellml.is_integer_string('-3'))
1897
- self.assertTrue(cellml.is_integer_string('34269386698604537836794387'))
1898
-
1899
- self.assertFalse(cellml.is_integer_string(''))
1900
- self.assertFalse(cellml.is_integer_string('.'))
1901
- self.assertFalse(cellml.is_integer_string('1.2'))
1902
- self.assertFalse(cellml.is_integer_string('-1.2'))
1903
- self.assertFalse(cellml.is_integer_string('1.0'))
1904
- self.assertFalse(cellml.is_integer_string('1.'))
1905
- self.assertFalse(cellml.is_integer_string('.0'))
1906
- self.assertFalse(cellml.is_integer_string('1e3'))
1907
- self.assertFalse(cellml.is_integer_string('++1'))
1908
- self.assertFalse(cellml.is_integer_string('+-3'))
1909
- self.assertFalse(cellml.is_integer_string('--1'))
1910
- self.assertFalse(cellml.is_integer_string('+'))
1911
- self.assertFalse(cellml.is_integer_string('-'))
1912
- self.assertFalse(cellml.is_integer_string('a'))
1913
- self.assertFalse(cellml.is_integer_string('12C'))
1914
-
1915
- def test_is_basic_real_number_string(self):
1916
- # Tests is_basic_real_number_string().
1917
-
1918
- self.assertTrue(cellml.is_basic_real_number_string('0'))
1919
- self.assertTrue(cellml.is_basic_real_number_string('+0'))
1920
- self.assertTrue(cellml.is_basic_real_number_string('-0'))
1921
- self.assertTrue(cellml.is_basic_real_number_string('3'))
1922
- self.assertTrue(cellml.is_basic_real_number_string('+3'))
1923
- self.assertTrue(cellml.is_basic_real_number_string('-3'))
1924
- self.assertTrue(cellml.is_basic_real_number_string(
1925
- '3426938669860453783679436474536745674567887'))
1926
- self.assertTrue(cellml.is_basic_real_number_string(
1927
- '-.342693866982438645847568457875604537836794387'))
1928
- self.assertTrue(cellml.is_basic_real_number_string('1.2'))
1929
- self.assertTrue(cellml.is_basic_real_number_string('-1.2'))
1930
- self.assertTrue(cellml.is_basic_real_number_string('1.0'))
1931
- self.assertTrue(cellml.is_basic_real_number_string('1.'))
1932
- self.assertTrue(cellml.is_basic_real_number_string('.1'))
1933
-
1934
- self.assertFalse(cellml.is_basic_real_number_string(''))
1935
- self.assertFalse(cellml.is_basic_real_number_string('.'))
1936
- self.assertFalse(cellml.is_basic_real_number_string('1e3'))
1937
- self.assertFalse(cellml.is_basic_real_number_string('++1'))
1938
- self.assertFalse(cellml.is_basic_real_number_string('+-3'))
1939
- self.assertFalse(cellml.is_basic_real_number_string('--1'))
1940
- self.assertFalse(cellml.is_basic_real_number_string('+'))
1941
- self.assertFalse(cellml.is_basic_real_number_string('-'))
1942
- self.assertFalse(cellml.is_basic_real_number_string('a'))
1943
- self.assertFalse(cellml.is_basic_real_number_string('12C'))
1944
-
1945
- def test_is_real_number_string(self):
1946
- # Tests is_real_number_string().
1947
-
1948
- self.assertTrue(cellml.is_real_number_string('0'))
1949
- self.assertTrue(cellml.is_real_number_string('+0'))
1950
- self.assertTrue(cellml.is_real_number_string('-0'))
1951
- self.assertTrue(cellml.is_real_number_string('3'))
1952
- self.assertTrue(cellml.is_real_number_string('+3'))
1953
- self.assertTrue(cellml.is_real_number_string('-3'))
1954
- self.assertTrue(cellml.is_real_number_string(
1955
- '3426938669860453783679436474536745674567887'))
1956
- self.assertTrue(cellml.is_real_number_string(
1957
- '-.342693866982438645847568457875604537836794387'))
1958
- self.assertTrue(cellml.is_real_number_string('1.2'))
1959
- self.assertTrue(cellml.is_real_number_string('-1.2'))
1960
- self.assertTrue(cellml.is_real_number_string('+1.0'))
1961
- self.assertTrue(cellml.is_real_number_string('+1.'))
1962
- self.assertTrue(cellml.is_real_number_string('.1'))
1963
- self.assertTrue(cellml.is_real_number_string('1e3'))
1964
- self.assertTrue(cellml.is_real_number_string('.1e-3'))
1965
- self.assertTrue(cellml.is_real_number_string('-1.E0'))
1966
- self.assertTrue(cellml.is_real_number_string('1E33464636'))
1967
- self.assertTrue(cellml.is_real_number_string(
1968
- '1.23000000000000028e+02'))
1969
-
1970
- self.assertFalse(cellml.is_real_number_string(''))
1971
- self.assertFalse(cellml.is_real_number_string('.'))
1972
- self.assertFalse(cellml.is_real_number_string('++1'))
1973
- self.assertFalse(cellml.is_real_number_string('+-3'))
1974
- self.assertFalse(cellml.is_real_number_string('--1'))
1975
- self.assertFalse(cellml.is_real_number_string('+'))
1976
- self.assertFalse(cellml.is_real_number_string('-'))
1977
- self.assertFalse(cellml.is_real_number_string('a'))
1978
- self.assertFalse(cellml.is_real_number_string('12C'))
1979
-
1980
1998
 
1981
1999
  if __name__ == '__main__':
1982
2000
  import warnings
@@ -711,9 +711,39 @@ class TestCellMLParser(unittest.TestCase):
711
711
 
712
712
  # CellML errors are converted to parsing errors
713
713
  x = '<variable name="1" units="volt"/>'
714
- x = '<component name="a">' + x + '</component>'
714
+ x = f'<component name="a">{x}</component>'
715
715
  self.assertBad(x, 'valid CellML identifier')
716
716
 
717
+ # Initial values can be numbers or variables
718
+ m = self.parse(
719
+ '<component name="c">'
720
+ ' <variable name="x" units="volt" initial_value="1" />'
721
+ ' <variable name="y" units="volt" initial_value="x" />'
722
+ '</component>'
723
+ )
724
+ x, y = m['c']['x'], m['c']['y']
725
+ self.assertEqual(
726
+ x.initial_value(), myokit.Number(1, myokit.units.volt))
727
+ self.assertEqual(y.initial_value(), myokit.Name(x))
728
+
729
+ # And initial values need delayed handling: Can refer to variable that
730
+ # has not been parsed yet!
731
+ m = self.parse(
732
+ '<component name="c">'
733
+ ' <variable name="y" units="volt" initial_value="x" />'
734
+ ' <variable name="x" units="volt" initial_value="1" />'
735
+ '</component>'
736
+ )
737
+ x, y = m['c']['x'], m['c']['y']
738
+ self.assertEqual(
739
+ x.initial_value(), myokit.Number(1, myokit.units.volt))
740
+ self.assertEqual(y.initial_value(), myokit.Name(x))
741
+
742
+ # Bad initial values are passed back from the API
743
+ x = '<variable name="b" units="volt" initial_value="1 + 2" />'
744
+ x = f'<component name="a">{x}</component>'
745
+ self.assertBad(x, 'must be a real number or the name of')
746
+
717
747
 
718
748
  if __name__ == '__main__':
719
749
  import warnings
@@ -112,7 +112,7 @@ class TestCellMLWriter(unittest.TestCase):
112
112
  self.assertIs(c.parent(), e)
113
113
  self.assertIs(b.parent(), c)
114
114
 
115
- def test_initial_value_representation(self):
115
+ def test_initial_values(self):
116
116
  # Test the way initial values are represented in generated CellML code
117
117
 
118
118
  def find(xml):
@@ -142,6 +142,13 @@ class TestCellMLWriter(unittest.TestCase):
142
142
  x = find(cellml.write_string(m))
143
143
  self.assertEqual(x, '1.23424352342422994')
144
144
 
145
+ # Variable
146
+ q = c.add_variable('q', 'mole')
147
+ q.set_initial_value(1)
148
+ p.set_initial_value('q')
149
+ x = find(cellml.write_string(m))
150
+ self.assertEqual(x, 'q')
151
+
145
152
  def test_maths(self):
146
153
  # Test maths is written
147
154
 
@@ -100,6 +100,23 @@ class DataLogTest(unittest.TestCase):
100
100
  self.assertAlmostEqual(1, apds1['duration'][0] / apds2['duration'][0])
101
101
  self.assertAlmostEqual(1, apds1['duration'][1] / apds2['duration'][1])
102
102
 
103
+ def test_append_after_access(self):
104
+ # Test appending to a log after it's been used by matplotlib,
105
+ # caused problems in older matplotlibs on Python3, but fixed since
106
+ # Matplotlib 3.6.3 or earlier.
107
+ import matplotlib
108
+ matplotlib.use('template')
109
+ import matplotlib.pyplot as plt
110
+
111
+ # Create log, write to it
112
+ m, p, _ = myokit.load(os.path.join(DIR_DATA, 'lr-1991.mmt'))
113
+ s = myokit.Simulation(m, p)
114
+ d = s.run(1)
115
+ plt.figure()
116
+ plt.plot(d.time(), d['membrane.V'])
117
+ d = s.run(1, log=d)
118
+ plt.close()
119
+
103
120
  def test_clone(self):
104
121
  # Test cloning via constructor and clone() method
105
122
 
@@ -5,6 +5,7 @@
5
5
  # This file is part of Myokit.
6
6
  # See http://myokit.org for copyright, sharing, and licensing details.
7
7
  #
8
+ import math
8
9
  import pickle
9
10
  import unittest
10
11
 
@@ -708,6 +709,66 @@ class NumberTest(unittest.TestCase):
708
709
  self.assertTrue(x.is_number())
709
710
  self.assertTrue(x.is_number(0))
710
711
 
712
+ def test_nan_inf(self):
713
+ # Test nan and inf are represented correctly in code
714
+
715
+ # Create from float
716
+ x = myokit.Number(float('inf'))
717
+ self.assertTrue(math.isinf(x.eval()))
718
+ self.assertGreater(x.eval(), 0)
719
+ self.assertEqual(x.code(), 'infinity')
720
+
721
+ # Conversion via Python parsing
722
+ x = myokit.Number('inf')
723
+ self.assertTrue(math.isinf(x.eval()))
724
+ self.assertGreater(x.eval(), 0)
725
+ self.assertEqual(x.code(), 'infinity')
726
+
727
+ # Conversion via Python parsing, but with Myokit syntax
728
+ x = myokit.Number('infinity')
729
+ self.assertTrue(math.isinf(x.eval()))
730
+ self.assertGreater(x.eval(), 0)
731
+ self.assertEqual(x.code(), 'infinity')
732
+
733
+ # Create from float
734
+ x = myokit.Number(float('-inf'))
735
+ self.assertTrue(math.isinf(x.eval()))
736
+ self.assertLess(x.eval(), 0)
737
+ self.assertEqual(x.code(), '-infinity')
738
+
739
+ # Conversion via Python parsing
740
+ x = myokit.Number('-inf')
741
+ self.assertTrue(math.isinf(x.eval()))
742
+ self.assertLess(x.eval(), 0)
743
+ self.assertEqual(x.code(), '-infinity')
744
+
745
+ # Conversion via Python parsing, but with Myokit syntax
746
+ x = myokit.Number('-infinity')
747
+ self.assertTrue(math.isinf(x.eval()))
748
+ self.assertLess(x.eval(), 0)
749
+ self.assertEqual(x.code(), '-infinity')
750
+
751
+ # Create from float
752
+ x = myokit.Number(float('nan'))
753
+ self.assertTrue(math.isnan(x.eval()))
754
+ self.assertEqual(x.code(), 'nan')
755
+
756
+ # Conversion via Python parsing
757
+ x = myokit.Number('nan')
758
+ self.assertTrue(math.isnan(x.eval()))
759
+ self.assertEqual(x.code(), 'nan')
760
+
761
+ # Conversion via Myokit parsing
762
+ x = myokit.parse_expression('infinity')
763
+ self.assertIsInstance(x, myokit.Number)
764
+ self.assertTrue(math.isinf(x.eval()))
765
+ self.assertGreater(x.eval(), 0)
766
+ self.assertEqual(x.code(), 'infinity')
767
+ x = myokit.parse_expression('nan')
768
+ self.assertIsInstance(x, myokit.Number)
769
+ self.assertTrue(math.isnan(x.eval()))
770
+ self.assertEqual(x.code(), 'nan')
771
+
711
772
  def test_tree_str(self):
712
773
  # Test Number.tree_str()
713
774
 
@@ -235,5 +235,104 @@ class EWriterTest(unittest.TestCase):
235
235
  'dada')
236
236
 
237
237
 
238
+ class FormatsStringTest(unittest.TestCase):
239
+ """ Test shared string checking functionality """
240
+
241
+ def test_is_integer_string(self):
242
+ # Tests is_integer_string().
243
+
244
+ from myokit.formats import is_integer_string as t
245
+ self.assertTrue(t('0'))
246
+ self.assertTrue(t('+0'))
247
+ self.assertTrue(t('-0'))
248
+ self.assertTrue(t('3'))
249
+ self.assertTrue(t('+3'))
250
+ self.assertTrue(t('-3'))
251
+ self.assertTrue(t('34269386698604537836794387'))
252
+
253
+ self.assertFalse(t(''))
254
+ self.assertFalse(t('.'))
255
+ self.assertFalse(t('1.2'))
256
+ self.assertFalse(t('-1.2'))
257
+ self.assertFalse(t('1.0'))
258
+ self.assertFalse(t('1.'))
259
+ self.assertFalse(t('.0'))
260
+ self.assertFalse(t('1e3'))
261
+ self.assertFalse(t('++1'))
262
+ self.assertFalse(t('+-3'))
263
+ self.assertFalse(t('--1'))
264
+ self.assertFalse(t('+'))
265
+ self.assertFalse(t('-'))
266
+ self.assertFalse(t('a'))
267
+ self.assertFalse(t('12C'))
268
+
269
+ self.assertFalse(t(' -3'))
270
+ self.assertFalse(t('-3 '))
271
+ self.assertFalse(t('\t\f123 '))
272
+ self.assertTrue(t(' -3', True))
273
+ self.assertTrue(t('-3 ', True))
274
+ self.assertTrue(t('\t\f123', True))
275
+
276
+ # Newline at end: potential pitfall for $
277
+ self.assertFalse(t('546184\n'))
278
+ self.assertTrue(t('546184\n', True))
279
+
280
+ self.assertFalse(t('', True))
281
+ self.assertFalse(t('.', True))
282
+ self.assertFalse(t('-1.2', True))
283
+ self.assertFalse(t('++1', True))
284
+
285
+ def test_is_real_number_string(self):
286
+ # Tests is_real_number_string().
287
+
288
+ from myokit.formats import is_real_number_string as t
289
+ self.assertTrue(t('0'))
290
+ self.assertTrue(t('+0'))
291
+ self.assertTrue(t('-0'))
292
+ self.assertTrue(t('3'))
293
+ self.assertTrue(t('+3'))
294
+ self.assertTrue(t('-3'))
295
+ self.assertTrue(t(
296
+ '3426938669860453783679436474536745674567887'))
297
+ self.assertTrue(t(
298
+ '-.342693866982438645847568457875604537836794387'))
299
+ self.assertTrue(t('1.2'))
300
+ self.assertTrue(t('-1.2'))
301
+ self.assertTrue(t('+1.0'))
302
+ self.assertTrue(t('+1.'))
303
+ self.assertTrue(t('.1'))
304
+ self.assertTrue(t('1e3'))
305
+ self.assertTrue(t('.1e-3'))
306
+ self.assertTrue(t('-1.E0'))
307
+ self.assertTrue(t('1E33464636'))
308
+ self.assertTrue(t('1.23000000000000028e+02'))
309
+
310
+ self.assertFalse(t(''))
311
+ self.assertFalse(t('.'))
312
+ self.assertFalse(t('++1'))
313
+ self.assertFalse(t('+-3'))
314
+ self.assertFalse(t('--1'))
315
+ self.assertFalse(t('+'))
316
+ self.assertFalse(t('-'))
317
+ self.assertFalse(t('a'))
318
+ self.assertFalse(t('12C'))
319
+
320
+ self.assertFalse(t(' 1'))
321
+ self.assertFalse(t('1 '))
322
+ self.assertFalse(t('\t\f1'))
323
+ self.assertTrue(t(' 1', True))
324
+ self.assertTrue(t('1 ', True))
325
+ self.assertTrue(t('\t\f1', True))
326
+
327
+ # Newline at end: potential pitfall for $
328
+ self.assertFalse(t('+3\n'))
329
+ self.assertTrue(t('+3\n', True))
330
+
331
+ self.assertFalse(t('', True))
332
+ self.assertFalse(t('.', True))
333
+ self.assertFalse(t('++1', True))
334
+ self.assertFalse(t('+', True))
335
+
336
+
238
337
  if __name__ == '__main__':
239
338
  unittest.main()