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
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Tests the expression writer for CUDA.
4
+ #
5
+ # This file is part of Myokit.
6
+ # See http://myokit.org for copyright, sharing, and licensing details.
7
+ #
8
+ import unittest
9
+
10
+ import myokit
11
+ import myokit.formats.cuda
12
+
13
+ from myokit import (
14
+ Number, PrefixPlus, PrefixMinus, Plus, Minus,
15
+ Multiply, Divide, Quotient, Remainder, Power, Sqrt,
16
+ Exp, Log, Log10, Sin, Cos, Tan, ASin, ACos, ATan, Floor, Ceil, Abs,
17
+ Not, And, Or, Equal, NotEqual, More, Less, MoreEqual, LessEqual,
18
+ If, Piecewise,
19
+ )
20
+
21
+ import myokit.tests
22
+
23
+
24
+ class CudaExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
25
+ """
26
+ Test conversion to Ansi C, as used by the Simulation.
27
+ Numerical tests are provided by composing and evaluating a single RHS.
28
+ """
29
+ _name = 'cuda'
30
+ _target = myokit.formats.cuda.CudaExpressionWriter
31
+
32
+ def test_number(self):
33
+ self.eq(Number(1), '1.0f')
34
+ self.eq(Number(-2), '-2.0f')
35
+ self.eq(Number(13, 'mV'), '13.0f')
36
+
37
+ def test_number_double(self):
38
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
39
+ self.assertEqual(w.ex(Number(1)), '1.0')
40
+ self.assertEqual(w.ex(Number(-2)), '-2.0')
41
+ self.assertEqual(w.ex(Number(13, 'mV')), '13.0')
42
+
43
+ def test_name(self):
44
+ self.eq(self.a, 'a')
45
+ w = self._target()
46
+ w.set_lhs_function(lambda v: v.var().qname().upper())
47
+ self.assertEqual(w.ex(self.a), 'COMP.A')
48
+
49
+ def test_derivative(self):
50
+ self.eq(myokit.Derivative(self.a), 'dot(a)')
51
+
52
+ def test_partial_derivative(self):
53
+ self.assertRaisesRegex(
54
+ NotImplementedError, 'Partial',
55
+ self.w.ex, myokit.PartialDerivative(self.a, self.b))
56
+
57
+ def test_initial_value(self):
58
+ self.assertRaisesRegex(
59
+ NotImplementedError, 'Initial',
60
+ self.w.ex, myokit.InitialValue(self.a))
61
+
62
+ def test_prefix_plus_minus(self):
63
+ # Inherited from c-based
64
+
65
+ p = Number(11, 'kV')
66
+ self.eq(PrefixPlus(p), '+11.0f')
67
+ self.eq(PrefixPlus(PrefixPlus(p)), '+(+11.0f)')
68
+ self.eq(PrefixPlus(PrefixPlus(PrefixPlus(p))), '+(+(+11.0f))')
69
+ self.eq(PrefixPlus(Number('+1')), '+1.0f')
70
+ self.eq(PrefixMinus(p), '-11.0f')
71
+ self.eq(PrefixMinus(PrefixMinus(p)), '-(-11.0f)')
72
+ self.eq(PrefixMinus(Number(-1)), '-(-1.0f)')
73
+ self.eq(PrefixMinus(PrefixMinus(Number(-2))), '-(-(-2.0f))')
74
+
75
+ # Test with operators of precedence SUM, PRODUCT
76
+ a, b, c = self.abc
77
+ self.eq(PrefixPlus(Plus(a, b)), '+(a + b)')
78
+ self.eq(Divide(PrefixPlus(Plus(a, b)), c), '+(a + b) / c')
79
+ self.eq(PrefixPlus(Divide(b, a)), '+(b / a)')
80
+ self.eq(PrefixMinus(Minus(a, b)), '-(a - b)')
81
+ self.eq(Multiply(PrefixMinus(Plus(b, a)), c), '-(b + a) * c')
82
+ self.eq(PrefixMinus(Divide(b, a)), '-(b / a)')
83
+
84
+ def test_prefix_plus_minus_double(self):
85
+ # Inherited from c-based
86
+
87
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
88
+ p = Number(3, 'mA')
89
+ self.assertEqual(w.ex(PrefixPlus(p)), '+3.0')
90
+ self.assertEqual(w.ex(PrefixPlus(PrefixPlus(p))), '+(+3.0)')
91
+ self.assertEqual(
92
+ w.ex(PrefixPlus(PrefixPlus(PrefixPlus(p)))), '+(+(+3.0))')
93
+ self.assertEqual(w.ex(PrefixPlus(Number('+1'))), '+1.0')
94
+ self.assertEqual(w.ex(PrefixMinus(p)), '-3.0')
95
+ self.assertEqual(w.ex(PrefixMinus(PrefixMinus(p))), '-(-3.0)')
96
+ self.assertEqual(w.ex(PrefixMinus(Number(-1))), '-(-1.0)')
97
+ self.assertEqual(
98
+ w.ex(PrefixMinus(PrefixMinus(Number(-2)))), '-(-(-2.0))')
99
+
100
+ def test_arithmetic(self):
101
+ # Inherited from c-based
102
+
103
+ a, b, c = self.abc
104
+ self.eq(Minus(Plus(a, b), c), 'a + b - c')
105
+ self.eq(Minus(a, Plus(b, c)), 'a - (b + c)')
106
+ self.eq(Multiply(Minus(a, b), c), '(a - b) * c')
107
+ self.eq(Multiply(a, Plus(b, c)), 'a * (b + c)')
108
+ self.eq(Minus(Multiply(a, b), c), 'a * b - c')
109
+ self.eq(Divide(a, Minus(b, c)), 'a / (b - c)')
110
+ self.eq(Plus(Divide(a, b), c), 'a / b + c')
111
+ self.eq(Divide(Divide(a, b), c), 'a / b / c')
112
+
113
+ def test_quotient_remainder(self):
114
+ # Inherited from c-based
115
+
116
+ a, b, c = self.abc
117
+ self.eq(Quotient(a, Divide(b, c)), 'floorf(a / (b / c))')
118
+ self.eq(Remainder(Plus(a, c), b), '(a + c - b * floorf((a + c) / b))')
119
+ self.eq(Divide(c, Remainder(b, a)), 'c / ((b - a * floorf(b / a)))')
120
+
121
+ def test_quotient_remainder_double(self):
122
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
123
+ a, b, c = self.abc
124
+ self.assertEqual(w.ex(Quotient(a, b)), 'floor(comp.a / comp.b)')
125
+
126
+ def test_power(self):
127
+ a, b, c = self.abc
128
+ self.eq(Power(a, b), 'powf(a, b)')
129
+ self.eq(Power(Power(a, b), c), 'powf(powf(a, b), c)')
130
+ self.eq(Power(a, Power(b, c)), 'powf(a, powf(b, c))')
131
+
132
+ self.eq(Power(Plus(a, b), c), 'powf(a + b, c)')
133
+ self.eq(Power(a, Minus(b, c)), 'powf(a, b - c)')
134
+ self.eq(Power(Multiply(a, b), c), 'powf(a * b, c)')
135
+ self.eq(Power(a, Divide(b, c)), 'powf(a, b / c)')
136
+
137
+ def test_power_double(self):
138
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
139
+ a, b, c = self.abc
140
+ self.assertEqual(w.ex(Power(a, b)), 'pow(comp.a, comp.b)')
141
+ self.assertEqual(w.ex(Power(Plus(a, b), c)),
142
+ 'pow(comp.a + comp.b, comp.c)')
143
+
144
+ def test_log(self):
145
+ a, b = self.ab
146
+ self.eq(Log(a), 'logf(a)')
147
+ self.eq(Log10(a), 'log10f(a)')
148
+ self.eq(Log(a, b), '(logf(a) / logf(b))')
149
+
150
+ def test_log_double(self):
151
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
152
+ a, b = self.ab
153
+ self.assertEqual(w.ex(Log(a)), 'log(comp.a)')
154
+ self.assertEqual(w.ex(Log10(b)), 'log10(comp.b)')
155
+ self.assertEqual(w.ex(Log(b, a)), '(log(comp.b) / log(comp.a))')
156
+
157
+ def test_functions(self):
158
+ a = self.a
159
+ self.eq(Sqrt(self.a), 'sqrtf(a)')
160
+ self.eq(Exp(self.a), 'expf(a)')
161
+ self.eq(Sin(self.a), 'sinf(a)')
162
+ self.eq(Cos(self.a), 'cosf(a)')
163
+ self.eq(Tan(self.a), 'tanf(a)')
164
+ self.eq(ASin(self.a), 'asinf(a)')
165
+ self.eq(ACos(self.a), 'acosf(a)')
166
+ self.eq(ATan(self.a), 'atanf(a)')
167
+ self.eq(Floor(self.a), 'floorf(a)')
168
+ self.eq(Ceil(self.a), 'ceilf(a)')
169
+ self.eq(Abs(self.a), 'fabsf(a)')
170
+
171
+ def test_functions_double(self):
172
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
173
+ self.assertEqual(w.ex(Sqrt(self.a)), 'sqrt(comp.a)')
174
+ self.assertEqual(w.ex(Exp(self.a)), 'exp(comp.a)')
175
+ self.assertEqual(w.ex(Sin(self.a)), 'sin(comp.a)')
176
+ self.assertEqual(w.ex(Cos(self.a)), 'cos(comp.a)')
177
+ self.assertEqual(w.ex(Tan(self.a)), 'tan(comp.a)')
178
+ self.assertEqual(w.ex(ASin(self.a)), 'asin(comp.a)')
179
+ self.assertEqual(w.ex(ACos(self.a)), 'acos(comp.a)')
180
+ self.assertEqual(w.ex(ATan(self.a)), 'atan(comp.a)')
181
+ self.assertEqual(w.ex(Floor(self.a)), 'floor(comp.a)')
182
+ self.assertEqual(w.ex(Ceil(self.a)), 'ceil(comp.a)')
183
+ self.assertEqual(w.ex(Abs(self.a)), 'fabs(comp.a)')
184
+
185
+ def test_conditions(self):
186
+ # Inherited from c-based
187
+
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))')
193
+
194
+ self.eq(Equal(a, b), '(a == b)')
195
+ self.eq(NotEqual(a, b), '(a != b)')
196
+ self.eq(More(b, a), '(b > a)')
197
+ self.eq(Less(d, c), '(d < c)')
198
+ self.eq(MoreEqual(c, a), '(c >= a)')
199
+ self.eq(LessEqual(b, d), '(b <= d)')
200
+
201
+ self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
202
+ 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(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
+
210
+ def test_conditionals(self):
211
+ # Inherited from c-based
212
+
213
+ a, b, c, d = self.abcd
214
+ self.eq(If(Equal(a, b), d, c), '((a == b) ? d : c)')
215
+ self.eq(Piecewise(NotEqual(d, c), b, a), '((d != c) ? b : a)')
216
+ self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
217
+ '((a == b) ? c : ((a == d) ? 3.0f : 4.0f))')
218
+
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
+
225
+ if __name__ == '__main__':
226
+ unittest.main()
@@ -11,6 +11,15 @@ import unittest
11
11
  import myokit
12
12
  import myokit.formats
13
13
  import myokit.formats.easyml
14
+ import myokit.tests
15
+
16
+ from myokit import (
17
+ Number, PrefixPlus, PrefixMinus, Plus, Minus,
18
+ Multiply, Divide, Quotient, Remainder, Power, Sqrt,
19
+ Exp, Log, Log10, Sin, Cos, Tan, ASin, ACos, ATan, Floor, Ceil, Abs,
20
+ Not, And, Or, Equal, NotEqual, More, Less, MoreEqual, LessEqual,
21
+ If, Piecewise,
22
+ )
14
23
 
15
24
  from myokit.tests import TemporaryDirectory, WarningCollector, DIR_DATA
16
25
 
@@ -247,164 +256,172 @@ class EasyMLExporterTest(unittest.TestCase):
247
256
  self.assertTrue(e.supports_model())
248
257
 
249
258
 
250
- class EasyMLExpressionWriterTest(unittest.TestCase):
251
- """ Tests EasyML expression writer functionality. """
252
-
253
- def test_all(self):
254
- w = myokit.formats.ewriter('easyml')
255
-
256
- model = myokit.Model()
257
- component = model.add_component('c')
258
- avar = component.add_variable('a')
259
-
260
- # Name
261
- a = myokit.Name(avar)
262
- self.assertEqual(w.ex(a), 'c.a')
263
- # Number with unit
264
- b = myokit.Number('12', 'pF')
265
- self.assertEqual(w.ex(b), '12.0')
266
- # Integer
267
- c = myokit.Number(1)
268
- self.assertEqual(w.ex(c), '1.0')
269
- # Integer
270
-
271
- # Prefix plus
272
- x = myokit.PrefixPlus(b)
273
- self.assertEqual(w.ex(x), '12.0')
274
- # Prefix minus
275
- x = myokit.PrefixMinus(b)
276
- self.assertEqual(w.ex(x), '(-12.0)')
277
-
278
- # Plus
279
- x = myokit.Plus(a, b)
280
- self.assertEqual(w.ex(x), 'c.a + 12.0')
281
- # Minus
282
- x = myokit.Minus(a, b)
283
- self.assertEqual(w.ex(x), 'c.a - 12.0')
284
- # Multiply
285
- x = myokit.Multiply(a, b)
286
- self.assertEqual(w.ex(x), 'c.a * 12.0')
287
- # Divide
288
- x = myokit.Divide(a, b)
289
- self.assertEqual(w.ex(x), 'c.a / 12.0')
290
-
291
- # 1 - exp() and exp() - 1
292
- x = myokit.Minus(myokit.Exp(myokit.Number(2)), myokit.Number(1))
293
- self.assertEqual(w.ex(x), 'expm1(2.0)')
294
- x = myokit.Minus(myokit.Number(1), myokit.Exp(myokit.Number(3)))
295
- self.assertEqual(w.ex(x), '-expm1(3.0)')
296
-
297
- # Quotient
298
- x = myokit.Quotient(a, b)
259
+ class EasyMLExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
260
+ """ Test conversion to EasyML syntax. """
261
+ _name = 'easyml'
262
+ _target = myokit.formats.easyml.EasyMLExpressionWriter
263
+
264
+ def test_number(self):
265
+ self.eq(Number(1), '1.0')
266
+ self.eq(Number(-2), '-2.0')
267
+ self.eq(Number(13, 'mV'), '13.0')
268
+
269
+ def test_name(self):
270
+ # Inherited from CBasedExpressionWriter
271
+ self.eq(self.a, 'a')
272
+ w = self._target()
273
+ w.set_lhs_function(lambda v: v.var().qname().upper())
274
+ self.assertEqual(w.ex(self.a), 'COMP.A')
275
+
276
+ def test_derivative(self):
277
+ # Inherited from CBasedExpressionWriter
278
+ self.eq(myokit.Derivative(self.a), 'dot(a)')
279
+
280
+ def test_partial_derivative(self):
281
+ e = myokit.PartialDerivative(self.a, self.b)
282
+ self.assertRaisesRegex(NotImplementedError, 'Partial', self.w.ex, e)
283
+
284
+ def test_initial_value(self):
285
+ e = myokit.InitialValue(self.a)
286
+ self.assertRaisesRegex(NotImplementedError, 'Initial', self.w.ex, e)
287
+
288
+ def test_prefix_plus_minus(self):
289
+ # Inherited from CBasedExpressionWriter
290
+ p = Number(11, 'kV')
291
+ a, b, c = self.abc
292
+ self.eq(PrefixPlus(p), '+11.0')
293
+ self.eq(PrefixPlus(PrefixPlus(PrefixPlus(p))), '+(+(+11.0))')
294
+ self.eq(Divide(PrefixPlus(Plus(a, b)), c), '+(a + b) / c')
295
+ self.eq(PrefixMinus(p), '-11.0')
296
+ self.eq(PrefixMinus(PrefixMinus(p)), '-(-11.0)')
297
+ self.eq(PrefixMinus(Number(-1)), '-(-1.0)')
298
+ self.eq(PrefixMinus(Minus(a, b)), '-(a - b)')
299
+ self.eq(Multiply(PrefixMinus(Plus(b, a)), c), '-(b + a) * c')
300
+ self.eq(PrefixMinus(Divide(b, a)), '-(b / a)')
301
+
302
+ def test_plus_minus(self):
303
+ a, b, c = self.abc
304
+ self.eq(Plus(a, b), 'a + b')
305
+ self.eq(Plus(Plus(a, b), c), 'a + b + c')
306
+ self.eq(Plus(a, Plus(b, c)), 'a + (b + c)')
307
+
308
+ self.eq(Minus(a, b), 'a - b')
309
+ self.eq(Minus(Minus(a, b), c), 'a - b - c')
310
+ self.eq(Minus(a, Minus(b, c)), 'a - (b - c)')
311
+
312
+ self.eq(Minus(a, b), 'a - b')
313
+ self.eq(Plus(Minus(a, b), c), 'a - b + c')
314
+ self.eq(Minus(a, Plus(b, c)), 'a - (b + c)')
315
+ self.eq(Minus(Plus(a, b), c), 'a + b - c')
316
+ self.eq(Minus(a, Plus(b, c)), 'a - (b + c)')
317
+
318
+ # Substitution of expm for 1 - exp() and exp() - 1
319
+ self.eq(Minus(Exp(Number(2)), Number(1)), 'expm1(2.0)')
320
+ self.eq(Minus(Number(1), Exp(Number(3))), '-expm1(3.0)')
321
+
322
+ def test_multiply_divide(self):
323
+ # Inherited from CBasedExpressionWriter
324
+ a, b, c = self.abc
325
+ self.eq(Multiply(a, b), 'a * b')
326
+ self.eq(Multiply(Multiply(a, b), c), 'a * b * c')
327
+ self.eq(Multiply(a, Multiply(b, c)), 'a * (b * c)')
328
+ self.eq(Divide(a, b), 'a / b')
329
+ self.eq(Divide(Divide(a, b), c), 'a / b / c')
330
+ self.eq(Divide(a, Divide(b, c)), 'a / (b / c)')
331
+
332
+ def test_quotient(self):
333
+ # Inherited from CBasedExpressionWriter
334
+ a, b, c = self.abc
335
+ with WarningCollector():
336
+ self.eq(Quotient(a, b), 'floor(a / b)')
337
+ self.eq(Quotient(Plus(a, c), b), 'floor((a + c) / b)')
338
+ self.eq(Quotient(Divide(a, c), b), 'floor(a / c / b)')
339
+ self.eq(Quotient(a, Divide(b, c)), 'floor(a / (b / c))')
340
+ self.eq(Multiply(Quotient(a, b), c), 'floor(a / b) * c')
341
+ self.eq(Multiply(c, Quotient(a, b)), 'c * (floor(a / b))')
342
+
343
+ def test_remainder(self):
344
+ # Inherited from CBasedExpressionWriter
345
+ a, b, c = self.abc
346
+ with WarningCollector():
347
+ self.eq(Remainder(a, b), '(a - b * floor(a / b))')
348
+ self.eq(Remainder(Plus(a, c), b),
349
+ '(a + c - b * floor((a + c) / b))')
350
+ self.eq(Multiply(Remainder(a, b), c), '(a - b * floor(a / b)) * c')
351
+ self.eq(Divide(c, Remainder(b, a)), 'c / ((b - a * floor(b / a)))')
352
+
353
+ def test_power(self):
354
+ # Inherited from CBasedExpressionWriter
355
+ a, b, c = self.abc
356
+ self.eq(Power(a, b), 'pow(a, b)')
357
+ self.eq(Power(Power(a, b), c), 'pow(pow(a, b), c)')
358
+ self.eq(Power(a, Power(b, c)), 'pow(a, pow(b, c))')
359
+
360
+ def test_log(self):
361
+ # Inherited from CBasedExpressionWriter
362
+ a, b = self.ab
363
+ self.eq(Log(a), 'log(a)')
364
+ self.eq(Log10(a), 'log10(a)')
365
+ self.eq(Log(a, b), '(log(a) / log(b))')
366
+
367
+ def test_functions(self):
368
+ a, b = self.ab
369
+
370
+ self.eq(Sqrt(a), 'sqrt(a)')
371
+ self.eq(Exp(a), 'exp(a)')
372
+ self.eq(Cos(a), 'cos(a)')
373
+ self.eq(ACos(a), 'acos(a)')
374
+ self.eq(Abs(a), 'fabs(a)')
375
+
299
376
  with WarningCollector() as c:
300
- self.assertEqual(w.ex(x), 'floor(c.a / 12.0)')
301
- # Remainder
302
- x = myokit.Remainder(a, b)
377
+ self.eq(Sin(a), 'sin(a)')
378
+ self.assertIn('Unsupported', c.text())
379
+
303
380
  with WarningCollector() as c:
304
- self.assertEqual(w.ex(x), 'c.a - 12.0 * (floor(c.a / 12.0))')
305
-
306
- # Power
307
- x = myokit.Power(a, b)
308
- self.assertEqual(w.ex(x), 'pow(c.a, 12.0)')
309
- # Sqrt
310
- x = myokit.Sqrt(b)
311
- self.assertEqual(w.ex(x), 'sqrt(12.0)')
312
- # Exp
313
- x = myokit.Exp(a)
314
- self.assertEqual(w.ex(x), 'exp(c.a)')
315
- # Log(a)
316
- x = myokit.Log(b)
317
- self.assertEqual(w.ex(x), 'log(12.0)')
318
- # Log(a, b)
319
- x = myokit.Log(a, b)
320
- self.assertEqual(w.ex(x), '(log(c.a) / log(12.0))')
321
- # Log10
322
- x = myokit.Log10(b)
323
- self.assertEqual(w.ex(x), 'log10(12.0)')
324
-
325
- # Sin
381
+ self.eq(Tan(a), 'tan(a)')
382
+ self.assertIn('Unsupported', c.text())
383
+
326
384
  with WarningCollector() as c:
327
- x = myokit.Sin(b)
328
- self.assertEqual(w.ex(x), 'sin(12.0)')
329
- # Cos
330
- x = myokit.Cos(b)
331
- self.assertEqual(w.ex(x), 'cos(12.0)')
332
- # Tan
333
- x = myokit.Tan(b)
334
- self.assertEqual(w.ex(x), 'tan(12.0)')
335
- # ASin
336
- x = myokit.ASin(b)
337
- self.assertEqual(w.ex(x), 'asin(12.0)')
338
- # ACos
339
- x = myokit.ACos(b)
340
- self.assertEqual(w.ex(x), 'acos(12.0)')
341
- # ATan
342
- x = myokit.ATan(b)
343
- self.assertEqual(w.ex(x), 'atan(12.0)')
385
+ self.eq(ASin(a), 'asin(a)')
386
+ self.assertIn('Unsupported', c.text())
344
387
 
345
388
  with WarningCollector() as c:
346
- # Floor
347
- x = myokit.Floor(b)
348
- self.assertEqual(w.ex(x), 'floor(12.0)')
349
- # Ceil
350
- x = myokit.Ceil(b)
351
- self.assertEqual(w.ex(x), 'ceil(12.0)')
352
- # Abs
353
- x = myokit.Abs(b)
354
- self.assertEqual(w.ex(x), 'fabs(12.0)')
355
-
356
- # Equal
357
- x = myokit.Equal(a, b)
358
- self.assertEqual(w.ex(x), '(c.a == 12.0)')
359
- # NotEqual
360
- x = myokit.NotEqual(a, b)
361
- self.assertEqual(w.ex(x), '(c.a != 12.0)')
362
- # More
363
- x = myokit.More(a, b)
364
- self.assertEqual(w.ex(x), '(c.a > 12.0)')
365
- # Less
366
- x = myokit.Less(a, b)
367
- self.assertEqual(w.ex(x), '(c.a < 12.0)')
368
- # MoreEqual
369
- x = myokit.MoreEqual(a, b)
370
- self.assertEqual(w.ex(x), '(c.a >= 12.0)')
371
- # LessEqual
372
- x = myokit.LessEqual(a, b)
373
- self.assertEqual(w.ex(x), '(c.a <= 12.0)')
374
-
375
- # Not
376
- cond1 = myokit.parse_expression('5 > 3')
377
- cond2 = myokit.parse_expression('2 < 1')
378
- x = myokit.Not(cond1)
379
- self.assertEqual(w.ex(x), '!((5.0 > 3.0))')
380
- # And
381
- x = myokit.And(cond1, cond2)
382
- self.assertEqual(w.ex(x), '((5.0 > 3.0) and (2.0 < 1.0))')
383
- # Or
384
- x = myokit.Or(cond1, cond2)
385
- self.assertEqual(w.ex(x), '((5.0 > 3.0) or (2.0 < 1.0))')
386
-
387
- # If
388
- x = myokit.If(cond1, a, b)
389
- self.assertEqual(w.ex(x), '((5.0 > 3.0) ? c.a : 12.0)')
390
- # Piecewise
391
- c = myokit.Number(1)
392
- x = myokit.Piecewise(cond1, a, cond2, b, c)
393
- self.assertEqual(
394
- w.ex(x),
395
- '((5.0 > 3.0) ? c.a : ((2.0 < 1.0) ? 12.0 : 1.0))')
396
-
397
- # Test without a Myokit expression
398
- self.assertRaisesRegex(
399
- ValueError, 'Unknown expression type', w.ex, 7)
400
-
401
- def test_easyml_ewriter_fetching(self):
402
-
403
- # Test fetching using ewriter method
404
- w = myokit.formats.ewriter('easyml')
405
- self.assertIsInstance(w, myokit.formats.easyml.EasyMLExpressionWriter)
389
+ self.eq(ATan(a), 'atan(a)')
390
+ self.assertIn('Unsupported', c.text())
391
+
392
+ with WarningCollector() as c:
393
+ self.eq(Floor(a), 'floor(a)')
394
+ self.assertIn('Unsupported', c.text())
395
+
396
+ with WarningCollector() as c:
397
+ self.eq(Ceil(a), 'ceil(a)')
398
+ self.assertIn('Unsupported', c.text())
399
+
400
+ def test_conditions(self):
401
+ # Inherited from CBasedExpressionWriter
402
+ a, b, c, d = self.abcd
403
+ self.eq(Not(And(a, b)), '(!(a && b))')
404
+ self.eq(Not(c), '(!(c))')
405
+ self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
406
+ self.eq(Or(More(d, c), MoreEqual(b, a)), '((d > c) || (b >= a))')
407
+ 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))')
409
+ 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
+
414
+ def test_conditionals(self):
415
+ # Inherited from CBasedExpressionWriter
416
+ a, b, c, d = self.abcd
417
+ self.eq(If(Equal(a, b), d, c), '((a == b) ? d : c)')
418
+ self.eq(Piecewise(NotEqual(d, c), b, a), '((d != c) ? b : a)')
419
+ self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
420
+ '((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))')
406
424
 
407
425
 
408
426
  if __name__ == '__main__':
409
427
  unittest.main()
410
-
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  #
3
- # Tests the exporters from the format module.
3
+ # Tests that exporters run: doesn't check output
4
4
  #
5
5
  # This file is part of Myokit.
6
6
  # See http://myokit.org for copyright, sharing, and licensing details.
@@ -95,74 +95,6 @@ class ExportTest(unittest.TestCase):
95
95
  raise Exception(
96
96
  'No types of export supported by: ' + exporter)
97
97
 
98
- def test_runnable_exporter_shared(self):
99
- # Test shared functionality of the TemplatedRunnableExporters.
100
-
101
- e = myokit.formats.exporter('ansic')
102
-
103
- # Load model, protocol
104
- m, p, x = myokit.load('example')
105
-
106
- # Create empty output directory as subdirectory of DIR_OUT
107
- with TemporaryDirectory() as d:
108
- path = d.path()
109
-
110
- # Simple export
111
- dpath = os.path.join(path, 'runnable1')
112
- ret = e.runnable(dpath, m)
113
- self.assertIsNone(ret)
114
- self.assertTrue(os.path.isdir(dpath))
115
- self.assertTrue(len(os.listdir(dpath)) > 0)
116
-
117
- # Write to complex path
118
- dpath = os.path.join(path, 'runnable2', 'nest', 'test')
119
- ret = e.runnable(dpath, m, p)
120
- self.assertIsNone(ret)
121
- self.assertTrue(os.path.isdir(dpath))
122
- self.assertTrue(len(os.listdir(dpath)) > 0)
123
-
124
- # Overwrite existing path
125
- ret = e.runnable(dpath, m, p)
126
- self.assertIsNone(ret)
127
- self.assertTrue(os.path.isdir(dpath))
128
- self.assertTrue(len(os.listdir(dpath)) > 0)
129
-
130
- # Path pointing to file
131
- dpath = os.path.join(path, 'file')
132
- with open(dpath, 'w') as f:
133
- f.write('contents\n')
134
- self.assertRaisesRegex(
135
- myokit.ExportError, 'file exists', e.runnable, dpath, m, p)
136
-
137
- # Directory exists where we're trying to write a file
138
- dpath = os.path.join(path, 'runnable3')
139
- fname = os.path.join(dpath, 'sim.c')
140
- os.makedirs(fname)
141
- self.assertRaisesRegex(
142
- myokit.ExportError, 'Directory exists',
143
- e.runnable, dpath, m, p)
144
-
145
- # Directory embedded in the output file path
146
- def embedded():
147
- return {'sim.c': 'nested/sim.c'}
148
-
149
- # 1. Normal operation
150
- e._dict = embedded
151
- dpath = os.path.join(path, 'runnable4')
152
- ret = e.runnable(dpath, m, p)
153
- self.assertIsNone(ret)
154
- self.assertTrue(os.path.isdir(dpath))
155
- self.assertTrue(len(os.listdir(dpath)) > 0)
156
-
157
- # 2. Try to create directory where file exists
158
- def embedded():
159
- return {'sim.c': 'nested/sim.c/som.c'}
160
-
161
- e._dict = embedded
162
- dpath = os.path.join(path, 'runnable4')
163
- self.assertRaisesRegex(
164
- myokit.ExportError, 'file or link', e.runnable, dpath, m, p)
165
-
166
98
  def test_completeness(self):
167
99
  # Test that all exporters have a test (so meta!).
168
100
 
@@ -112,9 +112,7 @@ line break.
112
112
 
113
113
 
114
114
  class AsciifierTest(unittest.TestCase):
115
- """
116
- Tests the method to convert html to ascii.
117
- """
115
+ """ Tests converting HTML to ASCII. """
118
116
  def test_asciify(self):
119
117
 
120
118
  # Compare line by line