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.
- myokit/__init__.py +5 -0
- myokit/_config.py +18 -19
- myokit/_datablock.py +6 -5
- myokit/_expressions.py +6 -1
- myokit/_model_api.py +44 -18
- myokit/_myokit_version.py +1 -1
- myokit/_parsing.py +8 -2
- myokit/_sim/cvodessim.py +26 -0
- myokit/formats/__init__.py +37 -0
- myokit/formats/ansic/_ewriter.py +1 -1
- myokit/formats/axon/_abf.py +43 -9
- myokit/formats/cellml/v1/__init__.py +5 -5
- myokit/formats/cellml/v1/_api.py +220 -122
- myokit/formats/cellml/v1/_parser.py +91 -87
- myokit/formats/cellml/v1/_writer.py +13 -6
- myokit/formats/cellml/v2/__init__.py +5 -8
- myokit/formats/cellml/v2/_api.py +182 -106
- myokit/formats/cellml/v2/_parser.py +68 -64
- myokit/formats/cellml/v2/_writer.py +7 -3
- myokit/formats/heka/_patchmaster.py +71 -14
- myokit/formats/mathml/_parser.py +106 -67
- myokit/gui/source.py +18 -12
- myokit/lib/hh.py +21 -37
- myokit/tests/test_cellml_v1_api.py +227 -33
- myokit/tests/test_cellml_v1_parser.py +48 -17
- myokit/tests/test_cellml_v1_writer.py +14 -4
- myokit/tests/test_cellml_v2_api.py +132 -114
- myokit/tests/test_cellml_v2_parser.py +31 -1
- myokit/tests/test_cellml_v2_writer.py +8 -1
- myokit/tests/test_datalog.py +17 -0
- myokit/tests/test_expressions.py +61 -0
- myokit/tests/test_formats.py +99 -0
- myokit/tests/test_formats_mathml_content.py +97 -37
- myokit/tests/test_formats_python.py +1 -1
- myokit/tests/test_model_building.py +2 -0
- myokit/tests/test_parsing.py +32 -0
- myokit/tests/test_simulation_cvodes.py +10 -4
- myokit/tests/test_variable.py +10 -7
- {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/METADATA +22 -7
- {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/RECORD +44 -44
- {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/WHEEL +1 -1
- {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info}/entry_points.txt +0 -0
- {myokit-1.38.0.dist-info → myokit-1.39.1.dist-info/licenses}/LICENSE.txt +0 -0
- {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
|
-
|
|
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('
|
|
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
|
-
|
|
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(
|
|
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
|
|
1390
|
+
# Set with number type
|
|
1322
1391
|
x.set_initial_value(3)
|
|
1323
1392
|
self.assertTrue(x.has_initial_value())
|
|
1324
|
-
self.assertEqual(
|
|
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
|
-
#
|
|
1327
|
-
x.set_initial_value(myokit.
|
|
1328
|
-
|
|
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
|
-
#
|
|
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, '
|
|
1337
|
-
x.set_initial_value,
|
|
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(
|
|
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.
|
|
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">
|
|
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
|
|
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
|
|
myokit/tests/test_datalog.py
CHANGED
|
@@ -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
|
|
myokit/tests/test_expressions.py
CHANGED
|
@@ -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
|
|
myokit/tests/test_formats.py
CHANGED
|
@@ -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()
|