myokit 1.35.4__py3-none-any.whl → 1.36.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 (59) hide show
  1. myokit/__init__.py +5 -3
  2. myokit/__main__.py +9 -159
  3. myokit/_config.py +2 -2
  4. myokit/_expressions.py +6 -6
  5. myokit/_model_api.py +11 -7
  6. myokit/_myokit_version.py +1 -1
  7. myokit/_protocol.py +4 -0
  8. myokit/_sim/__init__.py +1 -0
  9. myokit/_sim/cvodessim.c +321 -177
  10. myokit/_sim/cvodessim.py +107 -43
  11. myokit/_sim/mcl.h +54 -0
  12. myokit/formats/__init__.py +63 -12
  13. myokit/formats/ansic/__init__.py +2 -1
  14. myokit/formats/ansic/_ewriter.py +159 -40
  15. myokit/formats/cpp/_ewriter.py +12 -1
  16. myokit/formats/cuda/_ewriter.py +15 -51
  17. myokit/formats/easyml/_ewriter.py +26 -54
  18. myokit/formats/heka/_patchmaster.py +15 -3
  19. myokit/formats/latex/_ewriter.py +103 -88
  20. myokit/formats/latex/_exporter.py +1 -1
  21. myokit/formats/mathml/_ewriter.py +2 -2
  22. myokit/formats/matlab/_ewriter.py +50 -28
  23. myokit/formats/opencl/_ewriter.py +61 -78
  24. myokit/formats/python/_ewriter.py +81 -50
  25. myokit/formats/stan/_ewriter.py +29 -37
  26. myokit/gui/source.py +1 -1
  27. myokit/lib/hh.py +3 -0
  28. myokit/lib/markov.py +6 -0
  29. myokit/tests/__init__.py +70 -0
  30. myokit/tests/data/decker.model +59 -59
  31. myokit/tests/test_formats.py +115 -7
  32. myokit/tests/test_formats_ansic.py +344 -0
  33. myokit/tests/test_formats_axon.py +17 -0
  34. myokit/tests/test_formats_cpp.py +97 -0
  35. myokit/tests/test_formats_cuda.py +226 -0
  36. myokit/tests/test_formats_easyml.py +169 -152
  37. myokit/tests/{test_formats_exporters.py → test_formats_exporters_run.py} +1 -69
  38. myokit/tests/test_formats_html.py +1 -3
  39. myokit/tests/test_formats_latex.py +211 -0
  40. myokit/tests/test_formats_mathml_content.py +13 -0
  41. myokit/tests/test_formats_mathml_presentation.py +54 -42
  42. myokit/tests/test_formats_matlab.py +218 -0
  43. myokit/tests/test_formats_opencl.py +206 -380
  44. myokit/tests/test_formats_python.py +557 -0
  45. myokit/tests/test_formats_stan.py +175 -0
  46. myokit/tests/test_formats_sympy.py +9 -2
  47. myokit/tests/test_lib_hh.py +36 -0
  48. myokit/tests/test_lib_plots.py +0 -16
  49. myokit/tests/test_model.py +21 -1
  50. myokit/tests/test_simulation_cvodes.py +137 -56
  51. myokit/tools.py +3 -2
  52. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/LICENSE.txt +1 -1
  53. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/METADATA +19 -8
  54. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/RECORD +57 -52
  55. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/WHEEL +1 -1
  56. myokit/tests/test_formats_expression_writers.py +0 -1281
  57. myokit/tests/test_formats_importers.py +0 -53
  58. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/entry_points.txt +0 -0
  59. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/top_level.txt +0 -0
myokit/__init__.py CHANGED
@@ -79,7 +79,7 @@ Copyright (c) 2017-2020 University of Oxford. All rights reserved.
79
79
  (University of Oxford means the Chancellor, Masters and Scholars of the
80
80
  University of Oxford, having an administrative office at Wellington Square,
81
81
  Oxford OX1 2JD, UK).
82
- Copyright (c) 2020-2023 University of Nottingham. All rights reserved.
82
+ Copyright (c) 2020-2024 University of Nottingham. All rights reserved.
83
83
 
84
84
  Redistribution and use in source and binary forms, with or without
85
85
  modification, are permitted provided that the following conditions are met:
@@ -118,7 +118,7 @@ LICENSE_HTML = """
118
118
  <br />(University of Oxford means the Chancellor, Masters and Scholars of
119
119
  the University of Oxford, having an administrative office at Wellington
120
120
  Square, Oxford OX1 2JD, UK).
121
- <br />Copyright (c) 2020-2023 University of Nottingham. All rights
121
+ <br />Copyright (c) 2020-2024 University of Nottingham. All rights
122
122
  reserved.</br></p>
123
123
  <p>
124
124
  Redistribution and use in source and binary forms, with or without
@@ -220,8 +220,10 @@ DEBUG_WG = False
220
220
  DEBUG_SC = False
221
221
  # Show C debug Messages when running compiled code:
222
222
  DEBUG_SM = False
223
- # Show C Profiling information when running compiled code:
223
+ # Show C profiling information when running compiled code:
224
224
  DEBUG_SP = False
225
+ # Show C detailed simulator stats when running simulations
226
+ DEBUG_SS = False
225
227
 
226
228
  #
227
229
  # Compatibility settings: Some users report problems with output capturing.
myokit/__main__.py CHANGED
@@ -924,10 +924,8 @@ def add_reset_parser(subparsers):
924
924
  # Run
925
925
  #
926
926
 
927
- def run(source, debug_sg, debug_wg, debug_sc, debug_sm, debug_sp):
928
- """
929
- Runs an mmt file script.
930
- """
927
+ def run(source, debug_sg, debug_wg, debug_sc, debug_sm, debug_sp, debug_ss):
928
+ """ Runs an mmt file script. """
931
929
  import sys
932
930
  import myokit
933
931
 
@@ -942,6 +940,8 @@ def run(source, debug_sg, debug_wg, debug_sc, debug_sm, debug_sp):
942
940
  myokit.DEBUG_SM = myokit.DEBUG_SM or debug_sm
943
941
  # Show profiling information when running compiled code
944
942
  myokit.DEBUG_SP = myokit.DEBUG_SP or debug_sp
943
+ # Show CVODES stats
944
+ myokit.DEBUG_SS = myokit.DEBUG_SS or debug_ss
945
945
 
946
946
  # Read mmt file
947
947
  try:
@@ -1011,31 +1011,31 @@ def add_run_parser(subparsers):
1011
1011
  '--debug-sg',
1012
1012
  action='store_true',
1013
1013
  help='Show the generated code instead of executing it.',
1014
- #metavar='debug_sg',
1015
1014
  )
1016
1015
  parser.add_argument(
1017
1016
  '--debug-wg',
1018
1017
  action='store_true',
1019
1018
  help='Write the generated code to file(s) instead of executing it.',
1020
- #metavar='debug_wg',
1021
1019
  )
1022
1020
  parser.add_argument(
1023
1021
  '--debug-sc',
1024
1022
  action='store_true',
1025
1023
  help='Show compiler output.',
1026
- #metavar='debug_sc',
1027
1024
  )
1028
1025
  parser.add_argument(
1029
1026
  '--debug-sm',
1030
1027
  action='store_true',
1031
1028
  help='Show debug messages when executing compiled code.',
1032
- #metavar='debug_sm',
1033
1029
  )
1034
1030
  parser.add_argument(
1035
1031
  '--debug-sp',
1036
1032
  action='store_true',
1037
1033
  help='Show profiling information when executing compiled code.',
1038
- #metavar='debug_sp',
1034
+ )
1035
+ parser.add_argument(
1036
+ '--debug-ss',
1037
+ action='store_true',
1038
+ help='Show CVODES stats when running simulations.',
1039
1039
  )
1040
1040
  parser.set_defaults(func=run)
1041
1041
 
@@ -1239,11 +1239,6 @@ def add_test_parser(subparsers):
1239
1239
  help='Test documentation cover, building, and doc tests.')
1240
1240
  doc_parser.set_defaults(testfunc=test_documentation)
1241
1241
 
1242
- # Example notebooks
1243
- example_parser = subparsers.add_parser(
1244
- 'examples', help='Test example notebooks.')
1245
- example_parser.set_defaults(testfunc=test_examples)
1246
-
1247
1242
  # Style tests
1248
1243
  style_parser = subparsers.add_parser('style', help='Run code style tests.')
1249
1244
  style_parser.set_defaults(testfunc=test_style)
@@ -1643,151 +1638,6 @@ def test_doc_coverage_index(modules, classes, functions):
1643
1638
  return n == 0
1644
1639
 
1645
1640
 
1646
- def test_examples(args):
1647
- """
1648
- Tests the example notebooks.
1649
- """
1650
- books = test_examples_list('examples')
1651
- print(books)
1652
-
1653
- print('Found ' + str(len(books)) + ' notebook(s).')
1654
- test_examples_index('examples', books)
1655
- test_examples_all('examples', books)
1656
-
1657
-
1658
- def test_examples_index(root, books):
1659
- """ Check that every notebook is included in the index. """
1660
- import os
1661
- import sys
1662
-
1663
- print('Checking index...')
1664
-
1665
- # Index file is in ./examples/README.md
1666
- index_file = os.path.join(root, 'README.md')
1667
- with open(index_file, 'r') as f:
1668
- index_contents = f.read()
1669
-
1670
- # Find which are not indexed
1671
- not_indexed = [book for book in books if book not in index_contents]
1672
-
1673
- # Report any failures
1674
- if len(not_indexed) > 0:
1675
- print('FAIL: Unindexed notebooks')
1676
- for book in sorted(not_indexed):
1677
- print(' ' + str(book))
1678
- sys.exit(1)
1679
- else:
1680
- print('ok: All (' + str(len(books)) + ') notebooks are indexed.')
1681
-
1682
-
1683
- def test_examples_list(root, recursive=True):
1684
- """ Returns a list of all notebooks in a directory. """
1685
- import os
1686
-
1687
- def scan(root, recursive, notebooks):
1688
- for filename in os.listdir(root):
1689
- path = os.path.join(root, filename)
1690
-
1691
- # Add notebook
1692
- if os.path.splitext(path)[1] == '.ipynb':
1693
- notebooks.append(path)
1694
-
1695
- # Recurse into subdirectories
1696
- elif recursive and os.path.isdir(path):
1697
- # Ignore hidden directories
1698
- if filename[:1] == '.':
1699
- continue
1700
- scan(path, recursive, notebooks)
1701
- return notebooks
1702
-
1703
- notebooks = []
1704
- scan(root, recursive, notebooks)
1705
- notebooks = [os.path.relpath(book, root) for book in notebooks]
1706
-
1707
- return notebooks
1708
-
1709
-
1710
- def test_examples_single(root, path):
1711
- """ Tests a notebook in a subprocess, exists if it doesn't finish. """
1712
- import myokit
1713
- import nbconvert
1714
- import os
1715
- import subprocess
1716
- import sys
1717
-
1718
- b = myokit.tools.Benchmarker()
1719
- print('Running ' + path + ' ... ', end='')
1720
- sys.stdout.flush()
1721
-
1722
- # Load notebook, convert to python
1723
- e = nbconvert.exporters.PythonExporter()
1724
- code, _ = e.from_filename(os.path.join(root, path))
1725
-
1726
- # Remove coding statement, if present
1727
- code = '\n'.join([x for x in code.splitlines() if x[:9] != '# coding'])
1728
-
1729
- # Tell matplotlib not to produce any figures
1730
- env = os.environ.copy()
1731
- env['MPLBACKEND'] = 'Template'
1732
-
1733
- # Run in subprocess
1734
- cmd = [sys.executable, '-c', code]
1735
- curdir = os.getcwd()
1736
- try:
1737
- os.chdir(root)
1738
- p = subprocess.Popen(
1739
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env
1740
- )
1741
- stdout, stderr = p.communicate(timeout=3600)
1742
- if p.returncode != 0:
1743
- # Show failing code, output and errors before returning
1744
- print('ERROR')
1745
- print('-- script ' + '-' * (79 - 10))
1746
- for i, line in enumerate(code.splitlines()):
1747
- j = str(1 + i)
1748
- print(j + ' ' * (5 - len(j)) + line)
1749
- print('-- stdout ' + '-' * (79 - 10))
1750
- print(stdout)
1751
- print('-- stderr ' + '-' * (79 - 10))
1752
- print(stderr)
1753
- print('-' * 79)
1754
- return False
1755
- except KeyboardInterrupt:
1756
- p.terminate()
1757
- print('ABORTED')
1758
- sys.exit(1)
1759
- finally:
1760
- os.chdir(curdir)
1761
-
1762
- # Successfully run
1763
- print('ok (' + b.format(b.time()) + ')')
1764
- return True
1765
-
1766
-
1767
- def test_examples_all(root, books):
1768
- """ Runs all notebooks, and exits if one fails. """
1769
- import sys
1770
-
1771
- # Ignore books with deliberate errors, but check they still exist
1772
- ignore_list = [
1773
- ]
1774
- books = set(books) - set(ignore_list)
1775
-
1776
- # Scan and run
1777
- print('Testing notebooks')
1778
- failed = []
1779
- for book in books:
1780
- if not test_examples_single(root, book):
1781
- failed.append(book)
1782
- if failed:
1783
- print('FAIL: Errors encountered in notebooks')
1784
- for book in failed:
1785
- print(' ' + str(book))
1786
- sys.exit(1)
1787
- else:
1788
- print('ok: Successfully ran all (' + str(len(books)) + ') notebooks.')
1789
-
1790
-
1791
1641
  def test_examples_web(args):
1792
1642
  """
1793
1643
  Runs all web examples, exits if one of them fails.
myokit/_config.py CHANGED
@@ -139,7 +139,7 @@ def _create(path):
139
139
  config.set('opencl', 'lib', ';'.join([
140
140
  c64 + 'Intel\\OpenCL SDK\\6.3\\lib\\x64',
141
141
  c64 + 'AMD APP SDK\\2.9\\bin\\x64',
142
- c64 + 'NVIDIA GPU Computing Toolkit\CUDA\\v11.8\\lib\\x64',
142
+ c64 + 'NVIDIA GPU Computing Toolkit\\CUDA\\v11.8\\lib\\x64',
143
143
  ]))
144
144
  else:
145
145
  # Linux and mac
@@ -199,7 +199,7 @@ def _load():
199
199
  lines = f.readlines()
200
200
 
201
201
  import re
202
- inline_comment = re.compile('[\w]+[\s]*=[\s]*.+?\s+(;)')
202
+ inline_comment = re.compile(r'[\w]+[\s]*=[\s]*.+?\s+(;)')
203
203
  for i, line in enumerate(lines):
204
204
  m = inline_comment.match(line)
205
205
  if m is not None:
myokit/_expressions.py CHANGED
@@ -665,8 +665,8 @@ class Expression:
665
665
 
666
666
  # Create function text
667
667
  args = [w.ex(x) for x in self._references]
668
- c = 'def ex_pyfunc_generated(' + ','.join(args) + '):\n return ' \
669
- + w.ex(self)
668
+ c = ('def ex_pyfunc_generated(' + ','.join(sorted(args))
669
+ + '):\n return ' + w.ex(self))
670
670
 
671
671
  # Create function
672
672
  local = {}
@@ -682,8 +682,8 @@ class Expression:
682
682
  """
683
683
  Returns a string representing this expression in Python syntax.
684
684
 
685
- By default, built-in functions such as 'exp' are converted to the
686
- Python version 'math.exp'. To use the numpy versions, set
685
+ By default, built-in functions such as ``exp`` are converted to the
686
+ Python version ``math.exp``. To use the numpy versions, set
687
687
  ``numpy=True``.
688
688
  """
689
689
  # Get expression writer
@@ -810,7 +810,6 @@ class Expression:
810
810
  class Number(Expression):
811
811
  """
812
812
  Represents a number with an optional unit for use in Myokit expressions.
813
- All numbers used in Myokit expressions are floating point.
814
813
 
815
814
  >>> import myokit
816
815
  >>> x = myokit.Number(10)
@@ -821,11 +820,12 @@ class Number(Expression):
821
820
  >>> print(x)
822
821
  5 [V]
823
822
 
823
+ All numbers used in Myokit expressions are floating point.
824
+
824
825
  Arguments:
825
826
 
826
827
  ``value``
827
828
  A numerical value (something that can be converted to a ``float``).
828
- Number objects are immutable so no clone constructor is provided.
829
829
  ``unit``
830
830
  A unit to associate with this number. If no unit is specified the
831
831
  number's unit will be left undefined.
myokit/_model_api.py CHANGED
@@ -10,6 +10,8 @@ import re
10
10
 
11
11
  from collections import OrderedDict
12
12
 
13
+ import numpy
14
+
13
15
  import myokit
14
16
 
15
17
 
@@ -1406,11 +1408,13 @@ class Model(ObjectWithMetaData, VarProvider):
1406
1408
  value = float('nan')
1407
1409
  values[eq.lhs] = value
1408
1410
  else:
1409
- for group in order.values():
1410
- for eq in group:
1411
- if eq.lhs in values:
1412
- continue
1413
- values[eq.lhs] = eq.rhs.eval(values, precision=precision)
1411
+ with numpy.errstate(all='raise'):
1412
+ for group in order.values():
1413
+ for eq in group:
1414
+ if eq.lhs in values:
1415
+ continue
1416
+ values[eq.lhs] = eq.rhs.eval(
1417
+ values, precision=precision)
1414
1418
 
1415
1419
  # Return calculated state
1416
1420
  return [values[state.lhs()] for state in self._state_vars]
@@ -1571,7 +1575,7 @@ class Model(ObjectWithMetaData, VarProvider):
1571
1575
  ``derivatives=None``
1572
1576
  An optional list or other sequence of evaluated derivatives. If not
1573
1577
  given, the values will be calculed from ``state`` using
1574
- :meth:`eval_derivatives()`.
1578
+ :meth:`evaluate_derivatives()`.
1575
1579
  ``precision=myokit.DOUBLE_PRECISION``
1576
1580
  An optional precision argument to use when evaluating the state
1577
1581
  derivatives, and to pass into :meth:`myokit.float.str` when
@@ -2196,7 +2200,7 @@ class Model(ObjectWithMetaData, VarProvider):
2196
2200
  """
2197
2201
  # Deprecated since 2023-02-22
2198
2202
  import warnings
2199
- warnings.warn('The method `load_state` is deprecated.')
2203
+ warnings.warn('The method `Model.load_state` is deprecated.')
2200
2204
  self.set_initial_values(myokit.load_state(filename, self))
2201
2205
 
2202
2206
  def map_component_dependencies(
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, 35, 4
17
+ __version_tuple__ = 1, 36, 1
18
18
 
19
19
  # String version of the version number
20
20
  __version__ = '.'.join([str(x) for x in __version_tuple__])
myokit/_protocol.py CHANGED
@@ -858,6 +858,10 @@ class TimeSeriesProtocol:
858
858
  Protocols can be compared with ``==``, which will check if the sequence of
859
859
  time value pairs is the same, and the interpolation method is the same.
860
860
  Protocols can be serialized with ``pickle``.
861
+
862
+ **Note**: Time series protocols cannot be used to represent signals
863
+ containing discontinuities, as these will be smoothed out by the
864
+ interpolation.
861
865
  """
862
866
 
863
867
  def __init__(self, times, values, method=None):
myokit/_sim/__init__.py CHANGED
@@ -150,6 +150,7 @@ class CModule:
150
150
  if platform.system() == 'Linux':
151
151
  carg.extend([
152
152
  '-Wextra',
153
+ #'-Wpedantic',
153
154
  '-Wstrict-prototypes',
154
155
  '-Wold-style-definition',
155
156
  #'-Wmissing-prototypes',