myokit 1.33.9__py3-none-any.whl → 1.35.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. myokit/__init__.py +9 -36
  2. myokit/__main__.py +76 -142
  3. myokit/_aux.py +62 -16
  4. myokit/_bin/example.mmt +1 -2
  5. myokit/_bin/install-win/menu.json +7 -7
  6. myokit/_config.py +22 -31
  7. myokit/_datablock.py +30 -74
  8. myokit/_datalog.py +49 -72
  9. myokit/_err.py +25 -24
  10. myokit/_expressions.py +50 -68
  11. myokit/_io.py +15 -27
  12. myokit/_model_api.py +453 -249
  13. myokit/_myokit_version.py +1 -5
  14. myokit/_parsing.py +38 -44
  15. myokit/_progress.py +5 -8
  16. myokit/_protocol.py +99 -9
  17. myokit/_sim/__init__.py +7 -24
  18. myokit/_sim/cable.c +6 -8
  19. myokit/_sim/cable.py +6 -8
  20. myokit/_sim/cmodel.h +125 -70
  21. myokit/_sim/cmodel.py +12 -14
  22. myokit/_sim/compiler.py +1 -4
  23. myokit/_sim/cvodessim.c +196 -118
  24. myokit/_sim/cvodessim.py +130 -103
  25. myokit/_sim/differential.hpp +4 -4
  26. myokit/_sim/fiber_tissue.c +4 -8
  27. myokit/_sim/fiber_tissue.py +11 -13
  28. myokit/_sim/jacobian.cpp +2 -2
  29. myokit/_sim/jacobian.py +11 -8
  30. myokit/_sim/mcl.h +53 -55
  31. myokit/_sim/opencl.py +21 -27
  32. myokit/_sim/openclsim.c +3 -7
  33. myokit/_sim/openclsim.cl +3 -3
  34. myokit/_sim/openclsim.py +49 -40
  35. myokit/_sim/pacing.h +36 -16
  36. myokit/_sim/rhs.c +6 -13
  37. myokit/_sim/rhs.py +5 -14
  38. myokit/_sim/sundials.py +1 -4
  39. myokit/_system.py +10 -16
  40. myokit/_unit.py +4 -13
  41. myokit/float.py +0 -3
  42. myokit/formats/__init__.py +8 -10
  43. myokit/formats/ansic/__init__.py +0 -3
  44. myokit/formats/ansic/_ewriter.py +2 -4
  45. myokit/formats/ansic/_exporter.py +1 -4
  46. myokit/formats/ansic/template/cable.c +4 -4
  47. myokit/formats/ansic/template/euler.c +5 -5
  48. myokit/formats/ansic/template/sim.c +6 -6
  49. myokit/formats/axon/__init__.py +1 -3
  50. myokit/formats/axon/_abf.py +12 -17
  51. myokit/formats/axon/_atf.py +5 -6
  52. myokit/formats/axon/_importer.py +0 -3
  53. myokit/formats/cellml/__init__.py +0 -3
  54. myokit/formats/cellml/_ewriter.py +3 -6
  55. myokit/formats/cellml/_exporter.py +3 -6
  56. myokit/formats/cellml/_importer.py +1 -4
  57. myokit/formats/cellml/v1/__init__.py +0 -4
  58. myokit/formats/cellml/v1/_api.py +8 -11
  59. myokit/formats/cellml/v1/_parser.py +2 -5
  60. myokit/formats/cellml/v1/_writer.py +2 -11
  61. myokit/formats/cellml/v2/__init__.py +0 -3
  62. myokit/formats/cellml/v2/_api.py +8 -17
  63. myokit/formats/cellml/v2/_parser.py +2 -5
  64. myokit/formats/cellml/v2/_writer.py +1 -4
  65. myokit/formats/channelml/__init__.py +0 -3
  66. myokit/formats/channelml/_importer.py +11 -21
  67. myokit/formats/cpp/__init__.py +1 -3
  68. myokit/formats/cpp/_ewriter.py +0 -3
  69. myokit/formats/cuda/__init__.py +0 -3
  70. myokit/formats/cuda/_ewriter.py +2 -4
  71. myokit/formats/cuda/_exporter.py +0 -3
  72. myokit/formats/cuda/template/kernel.cu +8 -5
  73. myokit/formats/easyml/__init__.py +0 -3
  74. myokit/formats/easyml/_ewriter.py +9 -11
  75. myokit/formats/easyml/_exporter.py +2 -5
  76. myokit/formats/html/__init__.py +0 -3
  77. myokit/formats/html/_exporter.py +0 -3
  78. myokit/formats/html/_flatten.py +5 -21
  79. myokit/formats/latex/__init__.py +0 -3
  80. myokit/formats/latex/_ewriter.py +1 -4
  81. myokit/formats/latex/_exporter.py +4 -6
  82. myokit/formats/mathml/__init__.py +0 -3
  83. myokit/formats/mathml/_ewriter.py +2 -11
  84. myokit/formats/mathml/_parser.py +4 -6
  85. myokit/formats/matlab/__init__.py +0 -3
  86. myokit/formats/matlab/_ewriter.py +1 -4
  87. myokit/formats/matlab/_exporter.py +2 -5
  88. myokit/formats/matlab/template/main.m +3 -2
  89. myokit/formats/opencl/__init__.py +0 -3
  90. myokit/formats/opencl/_ewriter.py +2 -4
  91. myokit/formats/opencl/_exporter.py +2 -5
  92. myokit/formats/opencl/template/cable.c +10 -10
  93. myokit/formats/opencl/template/kernel.cl +1 -1
  94. myokit/formats/opencl/template/minilog.py +1 -1
  95. myokit/formats/python/__init__.py +0 -3
  96. myokit/formats/python/_ewriter.py +2 -5
  97. myokit/formats/python/_exporter.py +0 -3
  98. myokit/formats/python/template/sim.py +14 -14
  99. myokit/formats/sbml/__init__.py +0 -3
  100. myokit/formats/sbml/_api.py +50 -44
  101. myokit/formats/sbml/_importer.py +1 -4
  102. myokit/formats/sbml/_parser.py +2 -5
  103. myokit/formats/stan/__init__.py +0 -3
  104. myokit/formats/stan/_ewriter.py +2 -4
  105. myokit/formats/stan/_exporter.py +2 -5
  106. myokit/formats/stan/template/cell.stan +3 -3
  107. myokit/formats/sympy/__init__.py +0 -3
  108. myokit/formats/sympy/_ereader.py +1 -4
  109. myokit/formats/sympy/_ewriter.py +2 -5
  110. myokit/formats/wcp/__init__.py +0 -3
  111. myokit/formats/wcp/_wcp.py +2 -8
  112. myokit/formats/xml/__init__.py +0 -3
  113. myokit/formats/xml/_exporter.py +0 -3
  114. myokit/formats/xml/_split.py +0 -3
  115. myokit/gui/__init__.py +80 -246
  116. myokit/gui/datablock_viewer.py +103 -86
  117. myokit/gui/datalog_viewer.py +214 -66
  118. myokit/gui/explorer.py +15 -21
  119. myokit/gui/ide.py +171 -144
  120. myokit/gui/progress.py +9 -9
  121. myokit/gui/source.py +406 -375
  122. myokit/gui/vargrapher.py +2 -12
  123. myokit/lib/deps.py +12 -13
  124. myokit/lib/guess.py +3 -4
  125. myokit/lib/hh.py +20 -18
  126. myokit/lib/markov.py +21 -20
  127. myokit/lib/multi.py +1 -3
  128. myokit/lib/plots.py +20 -9
  129. myokit/pacing.py +0 -3
  130. myokit/pype.py +7 -18
  131. myokit/tests/__init__.py +3 -6
  132. myokit/tests/ansic_event_based_pacing.py +1 -4
  133. myokit/tests/ansic_fixed_form_pacing.py +3 -6
  134. myokit/tests/data/beeler-1977-model-compare-b.mmt +2 -2
  135. myokit/tests/data/clancy-1999-fitting.mmt +1 -0
  136. myokit/tests/test_aux.py +13 -28
  137. myokit/tests/test_cellml_v1_api.py +4 -19
  138. myokit/tests/test_cellml_v1_parser.py +0 -15
  139. myokit/tests/test_cellml_v1_writer.py +0 -9
  140. myokit/tests/test_cellml_v2_api.py +4 -19
  141. myokit/tests/test_cellml_v2_parser.py +0 -15
  142. myokit/tests/test_cellml_v2_writer.py +0 -9
  143. myokit/tests/test_cmodel.py +16 -22
  144. myokit/tests/test_compiler_detection.py +1 -11
  145. myokit/tests/test_component.py +108 -56
  146. myokit/tests/test_config.py +34 -67
  147. myokit/tests/test_datablock.py +1 -9
  148. myokit/tests/test_datalog.py +19 -24
  149. myokit/tests/test_dependency_checking.py +8 -23
  150. myokit/tests/test_expressions.py +0 -9
  151. myokit/tests/test_float.py +1 -5
  152. myokit/tests/test_formats.py +0 -9
  153. myokit/tests/test_formats_axon.py +1 -9
  154. myokit/tests/test_formats_cellml.py +0 -15
  155. myokit/tests/test_formats_channelml.py +0 -15
  156. myokit/tests/test_formats_easyml.py +0 -14
  157. myokit/tests/test_formats_exporters.py +1 -16
  158. myokit/tests/test_formats_expression_writers.py +1 -17
  159. myokit/tests/test_formats_html.py +0 -3
  160. myokit/tests/test_formats_importers.py +1 -16
  161. myokit/tests/test_formats_mathml_content.py +0 -9
  162. myokit/tests/test_formats_mathml_presentation.py +0 -9
  163. myokit/tests/test_formats_opencl.py +0 -10
  164. myokit/tests/test_formats_sbml.py +0 -15
  165. myokit/tests/test_formats_sympy.py +0 -9
  166. myokit/tests/test_formats_wcp.py +1 -3
  167. myokit/tests/test_io.py +27 -27
  168. myokit/tests/test_jacobian_calculator.py +6 -14
  169. myokit/tests/test_jacobian_tracer.py +0 -9
  170. myokit/tests/test_lib_deps.py +0 -9
  171. myokit/tests/test_lib_guess.py +0 -9
  172. myokit/tests/test_lib_hh.py +18 -12
  173. myokit/tests/test_lib_markov.py +21 -13
  174. myokit/tests/test_lib_multi.py +0 -9
  175. myokit/tests/test_lib_plots.py +13 -8
  176. myokit/tests/test_meta.py +0 -3
  177. myokit/tests/test_model.py +390 -96
  178. myokit/tests/test_model_building.py +44 -96
  179. myokit/tests/test_opencl_info.py +5 -14
  180. myokit/tests/test_pacing_factory.py +0 -3
  181. myokit/tests/test_pacing_system_c.py +1 -23
  182. myokit/tests/test_pacing_system_py.py +0 -9
  183. myokit/tests/test_parsing.py +139 -56
  184. myokit/tests/test_progress_reporters.py +0 -3
  185. myokit/tests/test_protocol.py +0 -9
  186. myokit/tests/test_protocol_floating_point.py +1 -10
  187. myokit/tests/test_protocol_time_series.py +82 -0
  188. myokit/tests/test_pype.py +0 -9
  189. myokit/tests/test_quantity.py +0 -9
  190. myokit/tests/test_rhs_benchmarker.py +1 -9
  191. myokit/tests/test_sbml_api.py +27 -42
  192. myokit/tests/test_sbml_parser.py +4 -19
  193. myokit/tests/test_simulation_1d.py +45 -25
  194. myokit/tests/test_simulation_cvodes.py +321 -55
  195. myokit/tests/test_simulation_cvodes_from_disk.py +0 -3
  196. myokit/tests/test_simulation_fiber_tissue.py +39 -12
  197. myokit/tests/test_simulation_log_interval.py +1 -431
  198. myokit/tests/test_simulation_opencl.py +69 -48
  199. myokit/tests/test_simulation_opencl_log_interval.py +1 -3
  200. myokit/tests/test_simulation_opencl_vs_cvode.py +1 -10
  201. myokit/tests/test_simulation_opencl_vs_sim1d.py +1 -10
  202. myokit/tests/test_system_info.py +1 -11
  203. myokit/tests/test_tools.py +0 -9
  204. myokit/tests/test_unit.py +1 -10
  205. myokit/tests/test_user_functions.py +0 -10
  206. myokit/tests/test_variable.py +231 -27
  207. myokit/tools.py +5 -21
  208. myokit/units.py +5 -3
  209. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/METADATA +12 -15
  210. myokit-1.35.0.dist-info/RECORD +391 -0
  211. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/WHEEL +1 -1
  212. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/entry_points.txt +0 -1
  213. myokit/_exec_new.py +0 -15
  214. myokit/_exec_old.py +0 -15
  215. myokit/_sim/cvodesim.c +0 -1551
  216. myokit/_sim/cvodesim.py +0 -674
  217. myokit/_sim/icsim.cpp +0 -563
  218. myokit/_sim/icsim.py +0 -363
  219. myokit/_sim/psim.cpp +0 -656
  220. myokit/_sim/psim.py +0 -493
  221. myokit/lib/common.py +0 -1094
  222. myokit/tests/test_lib_common.py +0 -130
  223. myokit/tests/test_simulation_cvode.py +0 -612
  224. myokit/tests/test_simulation_ic.py +0 -108
  225. myokit/tests/test_simulation_p.py +0 -223
  226. myokit-1.33.9.dist-info/RECORD +0 -403
  227. /myokit/formats/opencl/template/{test → test.sh} +0 -0
  228. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/LICENSE.txt +0 -0
  229. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/top_level.txt +0 -0
myokit/_sim/psim.cpp DELETED
@@ -1,656 +0,0 @@
1
- <?
2
- # psim.cpp
3
- #
4
- # Runs a simulation with differential objects, to obtain the state and the
5
- # partial derivatives of the state with respect to a list of parameters.
6
- #
7
- # Required variables
8
- # -----------------------------------------------------------------------------
9
- # module_name A module name
10
- # model A myokit model
11
- # variables A list of variables y whose derivatives dy/dp to track
12
- # parameters A list of parameters p (all literal constants)
13
- # -----------------------------------------------------------------------------
14
- #
15
- # This file is part of Myokit.
16
- # See http://myokit.org for copyright, sharing, and licensing details.
17
- #
18
- import myokit
19
- import myokit.formats.cpp as cpp
20
-
21
- # Get model
22
- model.reserve_unique_names(*cpp.keywords)
23
- model.create_unique_names()
24
-
25
- # Get mapping of bound variables
26
- bound = model.prepare_bindings({
27
- 'time' : 'engine_time',
28
- 'pace' : 'engine_pace',
29
- })
30
-
31
- # Get equations
32
- equations = model.solvable_order()
33
-
34
- # Get expression writer
35
- w = cpp.CppExpressionWriter()
36
-
37
- # Set if-then-else function
38
- w.set_condition_function('ifte')
39
-
40
- # Define var/lhs function
41
- def v(var):
42
- # Explicitly asked for derivative?
43
- if isinstance(var, myokit.Derivative):
44
- return 'D_' + var.var().uname()
45
- # Convert LhsExpressions to Variables
46
- if isinstance(var, myokit.Name):
47
- var = var.var()
48
- # Handle bound variables, states, constants and others
49
- return 'V_' + var.uname()
50
- w.set_lhs_function(v)
51
-
52
- # Tab
53
- tab = ' '
54
-
55
- ?>
56
- #define PY_SSIZE_T_CLEAN
57
- #include <Python.h>
58
- #include "pacing.h"
59
-
60
- /* C89 Doesn't have isnan */
61
- #ifndef isnan
62
- #define isnan(arg) (arg != arg)
63
- #endif
64
-
65
- /* Number of states, variables, parameters */
66
- #define NS <?= model.count_states() ?>
67
- #define NV <?= len(variables) ?>
68
- #define NP <?= len(parameters) ?>
69
- #define NSP <?= model.count_states() * len(parameters) ?>
70
- #define NVP <?= len(variables) * len(parameters) ?>
71
-
72
- /* Define numerical type */
73
- typedef double Real;
74
-
75
- /* Number of derivatives in each differential vector (required for differential.hpp) */
76
- #define N_DIFFS <?= len(parameters) ?>
77
-
78
- /* Load differential object */
79
- #include "differential.hpp"
80
-
81
- /* Define differential type. */
82
- typedef FirstDifferential Diff;
83
-
84
- <?
85
- print('/* Aliases of state variable values */')
86
- for var in model.states():
87
- print('#define ' + v(var) + ' state[' + str(var.indice()) + ']')
88
- print('')
89
-
90
- print('/* Aliases of state variable derivatives */')
91
- for var in model.states():
92
- print('#define ' + v(var.lhs()) + ' state_ddt[' + str(var.indice()) + ']')
93
- print('')
94
-
95
- print('/* Aliases of parameters */')
96
- for k, var in enumerate(parameters):
97
- print('#define ' + v(var.lhs()) + ' param[' + str(k) + ']')
98
- print('')
99
-
100
- print('/* Constants & calculated constants (may depend on parameters!) */')
101
- for group in equations.values():
102
- for eq in group.equations(const=True):
103
- if eq.lhs.var() not in parameters:
104
- if isinstance(eq.rhs, myokit.Number):
105
- print('static Real ' + v(eq.lhs) + ' = ' + w.ex(eq.rhs) + ';')
106
- else:
107
- print('static Diff ' + v(eq.lhs) + ';')
108
- print('')
109
-
110
- print('/* Declare remaining variables */')
111
- for var in model.variables(state=False, const=False, deep=True):
112
- print('static Diff ' + v(var) + ';')
113
- print('')
114
-
115
- ?>
116
-
117
- /* Inputs */
118
- double engine_time;
119
- double engine_pace;
120
-
121
- /* Simple exception raising with return e("message") */
122
- PyObject* e(const char* msg)
123
- {
124
- PyErr_SetString(PyExc_Exception, msg);
125
- return 0;
126
- }
127
-
128
- /* Calculated constants */
129
- static void
130
- calculate_constants(Diff* state, Diff* state_ddt, Diff* param)
131
- {
132
- <?
133
- for group in equations.values():
134
- for eq in group.equations(const=True):
135
- if eq.lhs.var() not in parameters:
136
- if not isinstance(eq.rhs, myokit.Number):
137
- print(tab + w.eq(eq) + ';')
138
- ?>
139
- }
140
-
141
- /* Right-hand-side function of the model ODE */
142
- static int
143
- rhs(Diff* state, Diff* state_ddt, Diff* param)
144
- {
145
- <?
146
- for label, eqs in equations.items():
147
- if eqs.has_equations(const=False):
148
- print(tab + '/* ' + label + ' */')
149
- for eq in eqs.equations(const=False):
150
- var = eq.lhs.var()
151
- if var in bound:
152
- print(tab + v(var) + ' = ' + bound[var] + ';')
153
- else:
154
- print(tab + w.eq(eq) + ';')
155
- print(tab)
156
- ?>
157
- return 0;
158
- }
159
-
160
- /* Adds a variable to the logging lists. Returns 1 if successful. */
161
- static int
162
- log_add(PyObject* log_dict, PyObject** logs, Diff** vars, int i, const char* name, const Diff* var)
163
- {
164
- int added = 0;
165
- PyObject* key = PyUnicode_FromString(name);
166
- if (PyDict_Contains(log_dict, key)) {
167
- logs[i] = PyDict_GetItem(log_dict, key);
168
- vars[i] = (Diff*)var;
169
- added = 1;
170
- }
171
- Py_DECREF(key);
172
- return added;
173
- }
174
-
175
- /* Input arguments */
176
- double tmin; /* The initial simulation time */
177
- double tmax; /* The final simulation time */
178
- double default_dt; /* The default step size */
179
- PyObject* param_in; /* The parameter values */
180
- PyObject* state_in; /* The initial state */
181
- PyObject* state_ddp_in; /* The initial state-parameter-derivatives (as a list) */
182
- PyObject* state_out; /* The final state */
183
- PyObject* state_ddp_out; /* The final state-parameter-derivatives (as a list) */
184
- PyObject* protocol; /* The pacing protocol (if any) */
185
- PyObject* log_dict; /* The simulation log to log to */
186
- PyObject* log_varab_ddp; /* A list to store lists of variable-parameter-derivatives in */
187
- double log_interval; /* The logging interval */
188
-
189
- /* State vector & state vector time derivatives */
190
- Diff* state;
191
- Diff* state_ddt;
192
-
193
- /* Parameters */
194
- Diff* param;
195
-
196
- /* Step size
197
- Typically, dt = default_dt. However, if that dt would take the simulation
198
- beyond the next pacing event or the end of the simulation, it will be
199
- shortened to arrive there exactly. */
200
- double dt;
201
- double dt_min; /* Minimum step size */
202
-
203
- /* Simulation state */
204
- int running;
205
-
206
- /* Logging */
207
- PyObject** logs = NULL; /* An array of lists to log into */
208
- Diff** vars = NULL; /* An array of pointers to variables to log */
209
- Py_ssize_t n_vars; /* Number of logging variables */
210
- unsigned long ilog; /* Index of next logging point */
211
- double tlog; /* Time of next logging point */
212
-
213
- /* Pacing */
214
- ESys pacing = NULL; /* Pacing system */
215
- double tpace; /* Time of next event */
216
-
217
- /* Temporary python objects */
218
- PyObject* flt = NULL; /* PyFloat, various uses */
219
- PyObject* ret = NULL; /* PyFloat, used as return value */
220
- PyObject* list_update_str = NULL; /* PyUnicode, used to call "append" method */
221
- PyObject* list = NULL; /* A new list, created to hold derivatives */
222
-
223
- /* Python callable methods */
224
- extern "C" {
225
-
226
- /*
227
- * Cleans up after a simulation
228
- */
229
- static PyObject*
230
- sim_clean()
231
- {
232
- if (running != 0) {
233
- /* Done with str="append", decref it */
234
- Py_XDECREF(list_update_str); list_update_str = NULL;
235
-
236
- /* Free allocated memory */
237
- free(state); state = NULL;
238
- free(state_ddt); state_ddt = NULL;
239
- free(param); param = NULL;
240
- free(vars); vars = NULL;
241
- free(logs); logs = NULL;
242
-
243
- /* Free pacing system space */
244
- ESys_Destroy(pacing); pacing = NULL;
245
-
246
- /* No longer running */
247
- running = 0;
248
- }
249
-
250
- /* Return 0, allowing the construct
251
- PyErr_SetString(PyExc_Exception, "Oh noes!");
252
- return sim_clean()
253
- to terminate a python function. */
254
- return 0;
255
- }
256
- static PyObject*
257
- py_sim_clean(PyObject *self, PyObject *args)
258
- {
259
- sim_clean();
260
-
261
- Py_RETURN_NONE;
262
- }
263
-
264
- /*
265
- * Initializes a simulation
266
- */
267
- static PyObject*
268
- sim_init(PyObject* self, PyObject* args)
269
- {
270
- int i, j;
271
-
272
- /* Check if already running */
273
- if (running != 0) {
274
- PyErr_SetString(PyExc_Exception, "Simulation already initialized.");
275
- return 0;
276
- }
277
-
278
- /* Check input arguments */
279
- if (!PyArg_ParseTuple(args, "dddOOOOOOOOd",
280
- &tmin,
281
- &tmax,
282
- &default_dt,
283
- &param_in,
284
- &state_in,
285
- &state_ddp_in,
286
- &state_out,
287
- &state_ddp_out,
288
- &protocol,
289
- &log_dict,
290
- &log_varab_ddp,
291
- &log_interval
292
- )) {
293
- PyErr_SetString(PyExc_Exception, "Incorrect input arguments.");
294
- /* Nothing allocated yet, no pyobjects _created_, return directly */
295
- return 0;
296
- }
297
-
298
- /* Check tmin, tmax */
299
- if (tmax < tmin) return e("Error: tmax < tmin!");
300
-
301
- /* Check default step size */
302
- if (default_dt <= 0) return e("Error: step size must be > 0");
303
- dt_min = default_dt * 1e-2;
304
-
305
- /* Check initial state vector state_in */
306
- if (!PyList_Check(state_in)) { return e("Not a list: state_in."); }
307
- if (PyList_Size(state_in) != NS) { return e("Incorrect length: state_in."); }
308
- for(i=0; i<NS; i++) {
309
- if (!PyFloat_Check(PyList_GetItem(state_in, i))) {
310
- return e("Must contain floats: arg_state.");
311
- }
312
- }
313
-
314
- /* Check initial state derivatives vector state_ddp_in */
315
- if (!PyList_Check(state_ddp_in)) { return e("Not a list: state_ddp_in."); }
316
- if (PyList_Size(state_ddp_in) != NSP) { return e("Incorrect length: state_ddp_in."); }
317
- for(i=0; i<NSP; i++) {
318
- if (!PyFloat_Check(PyList_GetItem(state_ddp_in, i))) {
319
- return e("Must contain floats: state_ddp_in.");
320
- }
321
- }
322
-
323
- /* Check parameter values vector param_in */
324
- if (!PyList_Check(param_in)) { return e("Not a list: param_in."); }
325
- if (PyList_Size(param_in) != NP) { return e("Incorrect length: param_in."); }
326
- for(i=0; i<NP; i++) {
327
- if (!PyFloat_Check(PyList_GetItem(param_in, i))) {
328
- return e("Must contain floats: param_in.");
329
- }
330
- }
331
-
332
- /* Check final state vector state_out */
333
- if (!PyList_Check(state_out)) { return e("Not a list: state_out."); }
334
- if (PyList_Size(state_out) != NS) { return e("Incorrect length: state_out."); }
335
-
336
- /* Check final derivatives vector state_ddp_out */
337
- if (!PyList_Check(state_ddp_out)) { return e("Not a list: state_ddp_out."); }
338
- if (PyList_Size(state_ddp_out) != NSP) { return e("Incorrect length: state_ddp_out."); }
339
-
340
- /* Check if the log is a dict */
341
- if (!PyDict_Check(log_dict)) { return e("Not a dict: log_dict."); }
342
-
343
- /* Check list for logging derivatives in */
344
- if (!PyList_Check(log_varab_ddp)) { return e("Not a list: log_varab_ddp."); }
345
- if (PyList_Size(log_varab_ddp) != 0) { return e("Not empty: log_varab_ddp."); }
346
-
347
- /**********************************************************************
348
- *
349
- * From this point on, memory will be allocated. Any further errors
350
- * should call sim_clean() before returning
351
- *
352
- */
353
-
354
- /* From this point on, we're running! */
355
- running = 1;
356
-
357
- /* Initialize state vector */
358
- state = (Diff*)malloc(sizeof(Diff) * NS);
359
- for(i=0; i<NS; i++) {
360
- state[i] = Diff(PyFloat_AsDouble(PyList_GetItem(state_in, i)));
361
- for(j=0; j<NP; j++) {
362
- state[i][j] = PyFloat_AsDouble(PyList_GetItem(state_ddp_in, i*NP+j));
363
- }
364
- }
365
-
366
- /* Initialize state-time-derivatives vector */
367
- state_ddt = (Diff*)malloc(sizeof(Diff) * NS);
368
-
369
- /* Initialize parameter vector */
370
- param = (Diff*)malloc(sizeof(Diff) * NP);
371
- for(i=0; i<NP; i++) {
372
- param[i] = Diff(PyFloat_AsDouble(PyList_GetItem(param_in, i)), i);
373
- param[i][i] = 1.0;
374
- }
375
-
376
- /* Set up pacing */
377
- ESys_Flag flag_pacing;
378
- pacing = ESys_Create(&flag_pacing);
379
- if (flag_pacing != ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
380
- flag_pacing = ESys_Populate(pacing, protocol);
381
- if (flag_pacing != ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
382
- flag_pacing = ESys_AdvanceTime(pacing, tmin);
383
- if (flag_pacing != ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
384
-
385
- /* Initialize inputs */
386
- engine_time = tmin;
387
- engine_pace = ESys_GetLevel(pacing, NULL);
388
-
389
- /* Calculate constants */
390
- calculate_constants(state, state_ddt, param);
391
-
392
- /* Evaluate derivatives at this point. This will be used for logging
393
- and to take the first step. */
394
- rhs(state, state_ddt, param);
395
-
396
- /*
397
- Running & logging:
398
- - We start at time t, with a known state y and inputs i
399
- - At this point, we make a call to rhs()
400
- - Now we have y(t), all intermediary variables at t, and ydot(t)
401
- - If needed, log everything for time-point t
402
- - Now we can update to time t+dt
403
- So, before the simulation starts y is known and rhs() is called to
404
- evaluate the rest. If no previous logged data is present, this first
405
- data point is logged.
406
- At each simulation step:
407
- - y is updated to time t + t_step
408
- - rhs(y) is called to evaluate everything else
409
- - t is updated to t + tstep
410
- - If needed, everything is logged for this new t
411
- */
412
-
413
- /* Next event & logging times */
414
- tpace = ESys_GetNextTime(pacing, NULL);
415
- tlog = tmin;
416
-
417
- /* Set up logging */
418
- n_vars = PyDict_Size(log_dict);
419
- logs = (PyObject**)malloc(sizeof(PyObject*)*n_vars);
420
- vars = (Diff**)malloc(sizeof(Diff*)*n_vars);
421
- i = 0;
422
- <?
423
- for var in model.variables(deep=True, const=False):
424
- print(tab*2 + 'i += log_add(log_dict, logs, vars, i, "' + var.qname() + '", &' + v(var) + ');')
425
- ?>
426
- if (i != n_vars) {
427
- PyErr_SetString(PyExc_Exception, "Unknown variables found in logging dictionary.");
428
- return sim_clean();
429
- }
430
-
431
- /* Always store initial position */
432
- list_update_str = PyUnicode_FromString("append");
433
-
434
- /* Log variables */
435
- for(i=0; i<n_vars; i++) {
436
- flt = PyFloat_FromDouble(vars[i]->value()); /* Append doesn't steal */
437
- ret = PyObject_CallMethodObjArgs(logs[i], list_update_str, flt, NULL);
438
- Py_DECREF(flt); flt = NULL;
439
- Py_XDECREF(ret);
440
- if (ret == NULL) {
441
- PyErr_SetString(PyExc_Exception, "Call to append() failed on logging list.");
442
- return sim_clean();
443
- }
444
- }
445
- ret = NULL;
446
-
447
- /* Log variable-parameter-derivatives */
448
- list = PyList_New(NVP);
449
- if (list == NULL) return sim_clean();
450
- <?
451
- NP = len(parameters)
452
- for i, var in enumerate(variables):
453
- for j, par in enumerate(parameters):
454
- print(tab*2 + 'PyList_SetItem(list, ' + str(i*NP+j) + ', PyFloat_FromDouble(' + v(var) + '[' + str(j) + ']));')
455
- ?>
456
- if (PyList_Append(log_varab_ddp, list) != 0) {
457
- Py_DECREF(list);
458
- list = NULL;
459
- return sim_clean();
460
- }
461
- Py_DECREF(list);
462
- list = NULL;
463
-
464
- /* Set periodic log point 1 log_interval ahead */
465
- ilog = 1;
466
- tlog = tmin + log_interval;
467
-
468
- /* Done! */
469
- Py_RETURN_NONE;
470
- }
471
-
472
- /*
473
- * Takes the next steps in a simulation run
474
- */
475
- static PyObject*
476
- sim_step(PyObject *self, PyObject *args)
477
- {
478
- ESys_Flag flag_pacing;
479
- int i, j;
480
- int steps_taken = 0; /* Steps taken during this call */
481
- double d;
482
-
483
- while(1) {
484
-
485
- /* Calculate next step size */
486
- dt = default_dt;
487
- d = tpace - engine_time; if (d > dt_min && d < dt) dt = d;
488
- d = tmax - engine_time; if (d > dt_min && d < dt) dt = d;
489
- d = tlog - engine_time; if (d > dt_min && d < dt) dt = d;
490
-
491
- /* Advance to next time step */
492
- for(i=0; i<NS; i++) {
493
- state[i] += state_ddt[i] * dt;
494
- }
495
- engine_time += dt;
496
- flag_pacing = ESys_AdvanceTime(pacing, engine_time);
497
- if (flag_pacing!=ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
498
- tpace = ESys_GetNextTime(pacing, NULL);
499
- engine_pace = ESys_GetLevel(pacing, NULL);
500
- rhs(state, state_ddt, param);
501
-
502
- /* Check for NaN, these will eventually propagate to all variables,
503
- so we only have to check a single one. */
504
- if (isnan(state[0].value())) {
505
- PyErr_SetString(PyExc_Exception, "NaN occurred in state vector during simulation. Perhaps there is an error in the model code or the step size should be reduced.");
506
- return sim_clean();
507
- }
508
-
509
- /* Check if we're finished
510
- Do this *before* logging (half-open interval rule) */
511
- if (engine_time >= tmax) break;
512
-
513
- /* Logging */
514
- if (engine_time >= tlog) {
515
-
516
- /* Log variables */
517
- for(i=0; i<n_vars; i++) {
518
- flt = PyFloat_FromDouble(vars[i]->value());
519
- ret = PyObject_CallMethodObjArgs(logs[i], list_update_str, flt, NULL);
520
- Py_DECREF(flt); flt = NULL;
521
- Py_XDECREF(ret);
522
- if (ret == NULL) {
523
- PyErr_SetString(PyExc_Exception, "Call to append() failed on logging list.");
524
- return sim_clean();
525
- }
526
- }
527
- ret = NULL;
528
-
529
- /* Log variable-parameter-derivatives */
530
- list = PyList_New(NVP);
531
- if (list == NULL) return sim_clean();
532
- <?
533
- NP = len(parameters)
534
- for i, var in enumerate(variables):
535
- for j, par in enumerate(parameters):
536
- print(tab*4 + 'PyList_SetItem(list, ' + str(i*NP+j) + ', PyFloat_FromDouble(' + v(var) + '[' + str(j) + ']));')
537
- ?>
538
- if (PyList_Append(log_varab_ddp, list) != 0) {
539
- Py_DECREF(list);
540
- list = NULL;
541
- return sim_clean();
542
- }
543
- Py_DECREF(list);
544
- list = NULL;
545
-
546
- /* Calculate next logging point */
547
- ilog++;
548
- tlog = tmin + (double)ilog * log_interval;
549
- }
550
-
551
- /* Perform any Python signal handling */
552
- if (PyErr_CheckSignals() != 0) {
553
- /* Exception (e.g. timeout or keyboard interrupt) occurred?
554
- Then cancel everything! */
555
- return sim_clean();
556
- }
557
-
558
- /* Report back to python after every x steps */
559
- steps_taken++;
560
- if (steps_taken >= 100) {
561
- return PyFloat_FromDouble(engine_time);
562
- }
563
- }
564
-
565
- /* Set final state & state-parameter-derivatives */
566
- for(i=0; i<NS; i++) {
567
- PyList_SetItem(state_out, i, PyFloat_FromDouble(state[i].value()));
568
- /* PyList_SetItem steals a reference: no need to decref the Float! */
569
- for(j=0; j<NP; j++) {
570
- PyList_SetItem(state_ddp_out, i*NP+j, PyFloat_FromDouble(state[i][j]));
571
- }
572
- }
573
-
574
- /* Clean up and return */
575
- sim_clean();
576
- return PyFloat_FromDouble(engine_time);
577
- }
578
-
579
- /*
580
- * Alters the value of a (literal) constant
581
- */
582
- static PyObject*
583
- sim_set_constant(PyObject *self, PyObject *args)
584
- {
585
- /* Check input arguments */
586
- char* name;
587
- double value;
588
- if (!PyArg_ParseTuple(args, "sd", &name, &value)) {
589
- PyErr_SetString(PyExc_Exception, "Expected input arguments: name (str), value (Float).");
590
- /* Nothing allocated yet, no pyobjects _created_, return directly */
591
- return 0;
592
- }
593
-
594
- <?
595
- for var in model.variables(const=True, deep=True):
596
- if var.is_literal() and var not in parameters:
597
- print(tab + 'if(strcmp("' + var.qname() + '", name) == 0) {')
598
- print(tab + tab + v(var) + ' = value;')
599
- print(tab + tab + 'Py_RETURN_NONE;')
600
- print(tab + '}')
601
- ?>
602
- char errstr[200];
603
- sprintf(errstr, "Constant not found: <%s>", name);
604
- PyErr_SetString(PyExc_Exception, errstr);
605
- return 0;
606
- }
607
-
608
- /* Methods in this module */
609
- static PyMethodDef SimMethods[] = {
610
- {"set_constant", sim_set_constant, METH_VARARGS, "Change a (literal) constant."},
611
- {"sim_clean", py_sim_clean, METH_VARARGS, "Clean up after an aborted simulation."},
612
- {"sim_init", sim_init, METH_VARARGS, "Initialize the simulation."},
613
- {"sim_step", sim_step, METH_VARARGS, "Perform the next step in the simulation."},
614
- {NULL},
615
- };
616
-
617
- /*
618
- * Module definition
619
- */
620
- #if PY_MAJOR_VERSION >= 3
621
-
622
- static struct PyModuleDef moduledef = {
623
- PyModuleDef_HEAD_INIT,
624
- "<?= module_name ?>", /* m_name */
625
- "Generated PSimulation module", /* m_doc */
626
- -1, /* m_size */
627
- SimMethods, /* m_methods */
628
- NULL, /* m_reload */
629
- NULL, /* m_traverse */
630
- NULL, /* m_clear */
631
- NULL, /* m_free */
632
- };
633
-
634
- PyMODINIT_FUNC PyInit_<?=module_name?>(void) {
635
- return PyModule_Create(&moduledef);
636
- }
637
-
638
- #else
639
-
640
- PyMODINIT_FUNC
641
- init<?=module_name?>(void) {
642
- (void) Py_InitModule("<?= module_name ?>", SimMethods);
643
- }
644
-
645
- #endif
646
- }
647
-
648
- /*
649
- * Remove aliases of states, bound variables
650
- */
651
- <?
652
- for var in model.states():
653
- print('#undef ' + v(var.lhs()))
654
- for var in model.states():
655
- print('#undef ' + v(var))
656
- ?>