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/icsim.cpp DELETED
@@ -1,563 +0,0 @@
1
- <?
2
- # icsim.cpp
3
- #
4
- # Runs a simulation with differential objects, to obtain the state and the
5
- # partial derivatives of the state with respect to the initial conditions.
6
- #
7
- # Required variables
8
- # -----------------------------------------------------------------------------
9
- # module_name A module name
10
- # model A myokit model
11
- # -----------------------------------------------------------------------------
12
- #
13
- # This file is part of Myokit.
14
- # See http://myokit.org for copyright, sharing, and licensing details.
15
- #
16
- import myokit
17
- import myokit.formats.cpp as cpp
18
-
19
- # Get model
20
- model.reserve_unique_names(*cpp.keywords)
21
- model.create_unique_names()
22
-
23
- # Get mapping of bound variables
24
- bound = model.prepare_bindings({
25
- 'time' : 'engine_time',
26
- 'pace' : 'engine_pace',
27
- })
28
-
29
- # Get equations
30
- equations = model.solvable_order()
31
-
32
- # Get expression writer
33
- w = cpp.CppExpressionWriter()
34
-
35
- # Set if-then-else function
36
- w.set_condition_function('ifte')
37
-
38
- # Define var/lhs function
39
- def v(var):
40
- # Explicitly asked for derivative?
41
- if isinstance(var, myokit.Derivative):
42
- return 'D_' + var.var().uname()
43
- # Convert LhsExpressions to Variables
44
- if isinstance(var, myokit.Name):
45
- var = var.var()
46
- # Handle bound variables, states, constants and others
47
- return 'V_' + var.uname()
48
- w.set_lhs_function(v)
49
-
50
- # Tab
51
- tab = ' '
52
-
53
- ?>
54
- #define PY_SSIZE_T_CLEAN
55
- #include <Python.h>
56
- #include "pacing.h"
57
-
58
- // Number of states
59
- #define N_STATE <?= model.count_states() ?>
60
- #define N_MATRIX <?= model.count_states() ** 2 ?>
61
-
62
- // Define numerical type
63
- typedef double Real;
64
-
65
- // Number of derivatives in each derivative vector
66
- #define N_DIFFS <?= model.count_states() ?>
67
-
68
- // Load differential object
69
- #include "differential.hpp"
70
-
71
- // Define differential type.
72
- typedef FirstDifferential Diff;
73
-
74
- <?
75
- print('// Aliases of state variable derivatives')
76
- for var in model.states():
77
- print('#define ' + v(var.lhs()) + ' deriv[' + str(var.indice()) + ']')
78
- print('')
79
-
80
- print('// Aliases of state variable values')
81
- for var in model.states():
82
- print('#define ' + v(var) + ' state[' + str(var.indice()) + ']')
83
- print('')
84
-
85
- print('// Aliases of constants and calculated constants')
86
- for group in equations.values():
87
- for eq in group.equations(const=True):
88
- if isinstance(eq.rhs, myokit.Number):
89
- print('#define ' + v(eq.lhs) + ' ' + w.ex(eq.rhs))
90
- else:
91
- print('#define ' + v(eq.lhs) + ' (' + w.ex(eq.rhs) + ')')
92
- print('')
93
-
94
- print('// Declare remaining variables')
95
- for var in model.variables(state=False, const=False, deep=True):
96
- print('static Diff ' + v(var) + ';')
97
- print('')
98
-
99
- ?>
100
-
101
- // Inputs
102
- double engine_time;
103
- double engine_pace;
104
-
105
- // Simple exceptions
106
- PyObject* e(const char* msg)
107
- {
108
- PyErr_SetString(PyExc_Exception, msg);
109
- return 0;
110
- }
111
-
112
- // Right-hand-side function of the model ODE
113
- static int
114
- rhs(Diff* state, Diff* deriv)
115
- {
116
- <?
117
- for label, eqs in equations.items():
118
- if eqs.has_equations(const=False):
119
- print(tab + '// ' + label)
120
- for eq in eqs.equations(const=False):
121
- var = eq.lhs.var()
122
- if var in bound:
123
- print(tab + v(var) + ' = ' + bound[var] + ';')
124
- else:
125
- print(tab + w.eq(eq) + ';')
126
- print(tab)
127
- ?>
128
- return 0;
129
- }
130
-
131
- // Adds a variable to the logging lists. Returns 1 if successful.
132
- static int
133
- log_add(PyObject* log_dict, PyObject** logs, Diff** vars, int i, const char* name, const Diff* var)
134
- {
135
- int added = 0;
136
- PyObject* key = PyUnicode_FromString(name);
137
- if (PyDict_Contains(log_dict, key)) {
138
- logs[i] = PyDict_GetItem(log_dict, key);
139
- vars[i] = (Diff*)var;
140
- added = 1;
141
- }
142
- Py_DECREF(key);
143
- return added;
144
- }
145
-
146
- // Input arguments
147
- double tmin; // The initial simulation time
148
- double tmax; // The final simulation time
149
- double default_dt; // The default step size
150
- PyObject* state_in; // The initial state
151
- PyObject* deriv_in; // The initial partial derivatives (as a list)
152
- PyObject* state_out; // The final state
153
- PyObject* deriv_out; // The final partial derivatives (as a list)
154
- PyObject* protocol; // The pacing protocol (if any)
155
- PyObject* log_dict; // The simulation log to log to
156
- PyObject* log_deriv; // A list to store lists of partial derivatives in
157
- double log_interval; // The logging interval
158
-
159
- // State vector & derivatives
160
- Diff* state;
161
- Diff* deriv;
162
-
163
- // Step size
164
- // Typically, dt = default_dt. However, if that dt would take the simulation
165
- // beyond the next pacing event or the end of the simulation, it will be
166
- // shortened to arrive there exactly.
167
- double dt;
168
- double dt_min; // Minimum step size
169
-
170
- // Simulation state
171
- int running;
172
-
173
- // Logging
174
- PyObject** logs = NULL; // An array of lists to log into
175
- Diff** vars = NULL; // An array of pointers to variables to log
176
- Py_ssize_t n_vars; // Number of logging variables
177
- unsigned long ilog; // Index of next logging point
178
- double tlog; // Time of next logging point
179
-
180
- // Pacing
181
- ESys pacing = NULL; // Pacing system
182
- double tpace; // Time of next event
183
-
184
- // Temporary python objects
185
- PyObject* flt = NULL; // PyFloat, various uses
186
- PyObject* ret = NULL; // PyFloat, used as return value
187
- PyObject* list_update_str = NULL; // PyUnicode, used to call "append" method
188
- PyObject* list = NULL; // A new list, created to hold derivatives
189
-
190
- // Python callable methods
191
- extern "C" {
192
-
193
- /*
194
- * Cleans up after a simulation
195
- */
196
- static PyObject*
197
- sim_clean()
198
- {
199
- if (running != 0) {
200
- // Done with str="append", decref it
201
- Py_XDECREF(list_update_str); list_update_str = NULL;
202
-
203
- // Free allocated memory
204
- free(state); state = NULL;
205
- free(deriv); deriv = NULL;
206
- free(vars); vars = NULL;
207
- free(logs); logs = NULL;
208
-
209
- // Free pacing system space
210
- ESys_Destroy(pacing); pacing = NULL;
211
-
212
- // No longer running
213
- running = 0;
214
- }
215
-
216
- // Return 0, allowing the construct
217
- // PyErr_SetString(PyExc_Exception, "Oh noes!");
218
- // return sim_clean()
219
- // to terminate a python function.
220
- return 0;
221
- }
222
- static PyObject*
223
- py_sim_clean(PyObject *self, PyObject *args)
224
- {
225
- sim_clean();
226
-
227
- Py_RETURN_NONE;
228
- }
229
-
230
- /*
231
- * Initializes a simulation
232
- */
233
- static PyObject*
234
- sim_init(PyObject* self, PyObject* args)
235
- {
236
- int i, j;
237
-
238
- // Check if already running
239
- if (running != 0) {
240
- PyErr_SetString(PyExc_Exception, "Simulation already initialized.");
241
- return 0;
242
- }
243
-
244
- // Check input arguments
245
- if (!PyArg_ParseTuple(args, "dddOOOOOOOd",
246
- &tmin,
247
- &tmax,
248
- &default_dt,
249
- &state_in,
250
- &deriv_in,
251
- &state_out,
252
- &deriv_out,
253
- &protocol,
254
- &log_dict,
255
- &log_deriv,
256
- &log_interval
257
- )) {
258
- PyErr_SetString(PyExc_Exception, "Incorrect input arguments.");
259
- // Nothing allocated yet, no pyobjects _created_, return directly
260
- return 0;
261
- }
262
-
263
- // Check tmin, tmax
264
- if (tmax < tmin) return e("Error: tmax < tmin!");
265
-
266
- // Check default step size
267
- if (default_dt <= 0) return e("Error: step size must be > 0");
268
- dt_min = default_dt * 1e-2;
269
-
270
- // Check initial state vector state_in
271
- if (!PyList_Check(state_in)) { return e("Not a list: state_in."); }
272
- if (PyList_Size(state_in) != N_STATE) { return e("Incorrect length: state_in."); }
273
- for(i=0; i<N_STATE; i++) {
274
- if (!PyFloat_Check(PyList_GetItem(state_in, i))) {
275
- return e("Must contain floats: state_in.");
276
- }
277
- }
278
-
279
- // Check initial derivatives vector deriv_in
280
- if (!PyList_Check(deriv_in)) { return e("Not a list: deriv_in."); }
281
- if (PyList_Size(deriv_in) != N_MATRIX) { return e("Incorrect length: deriv_in."); }
282
- for(i=0; i<N_MATRIX; i++) {
283
- if (!PyFloat_Check(PyList_GetItem(deriv_in, i))) {
284
- return e("Must contain floats: deriv_in.");
285
- }
286
- }
287
-
288
- // Check final state vector state_out
289
- if (!PyList_Check(state_out)) { return e("Not a list: state_out."); }
290
- if (PyList_Size(state_out) != N_STATE) { return e("Incorrect length: state_out."); }
291
-
292
- // Check final derivatives vector deriv_out
293
- if (!PyList_Check(deriv_out)) { return e("Not a list: deriv_out."); }
294
- if (PyList_Size(deriv_out) != N_MATRIX) { return e("Incorrect length: deriv_out."); }
295
-
296
- // Check if the log is a dict
297
- if (!PyDict_Check(log_dict)) { return e("Not a dict: log_dict."); }
298
-
299
- // Check list for logging derivatives in
300
- if (!PyList_Check(log_deriv)) { return e("Not a list: log_deriv."); }
301
- if (PyList_Size(log_deriv) != 0) { return e("Not empty: log_deriv."); }
302
-
303
- ///////////////////////////////////////////////////////////////////////
304
- //
305
- // From this point on, memory will be allocated. Any further errors
306
- // should call sim_clean() before returning
307
- //
308
-
309
- // From this point on, we're running!
310
- running = 1;
311
-
312
- // Initialize state vector
313
- state = (Diff*)malloc(sizeof(Diff) * N_STATE);
314
- for(i=0; i<N_STATE; i++) {
315
- state[i] = Diff(PyFloat_AsDouble(PyList_GetItem(state_in, i)));
316
- for(j=0; j<N_STATE; j++) {
317
- state[i][j] = PyFloat_AsDouble(PyList_GetItem(deriv_in, i*N_STATE+j));
318
- }
319
- }
320
-
321
- // Initialize derivatives vector
322
- deriv = (Diff*)malloc(sizeof(Diff) * N_STATE);
323
-
324
- // Set up pacing
325
- ESys_Flag flag_pacing;
326
- pacing = ESys_Create(&flag_pacing);
327
- if (flag_pacing != ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
328
- flag_pacing = ESys_Populate(pacing, protocol);
329
- if (flag_pacing != ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
330
- flag_pacing = ESys_AdvanceTime(pacing, tmin);
331
- if (flag_pacing != ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
332
-
333
- // Initialize inputs
334
- engine_time = tmin;
335
- engine_pace = ESys_GetLevel(pacing, NULL);
336
-
337
- // Evaluate derivatives at this point. This will be used for logging
338
- // and to take the first step.
339
- rhs(state, deriv);
340
-
341
- //
342
- // Running & logging:
343
- // - We start at time t, with a known state y and inputs i
344
- // - At this point, we make a call to rhs()
345
- // - Now we have y(t), all intermediary variables at t, and ydot(t)
346
- // - If needed, log everything for time-point t
347
- // - Now we can update to time t+dt
348
- // So, before the simulation starts y is known and rhs() is called to
349
- // evaluate the rest. If no previous logged data is present, this first
350
- // data point is logged.
351
- // At each simulation step:
352
- // - y is updated to time t + t_step
353
- // - rhs(y) is called to evaluate everything else
354
- // - t is updated to t + tstep
355
- // - If needed, everything is logged for this new t
356
- //
357
-
358
- // Next event & logging times
359
- tpace = ESys_GetNextTime(pacing, NULL);
360
- tlog = tmin;
361
-
362
- // Set up logging
363
- n_vars = PyDict_Size(log_dict);
364
- logs = (PyObject**)malloc(sizeof(PyObject*)*n_vars);
365
- vars = (Diff**)malloc(sizeof(Diff*)*n_vars);
366
- i = 0;
367
- <?
368
- for var in model.variables(deep=True, const=False):
369
- print(tab*2 + 'i += log_add(log_dict, logs, vars, i, "' + var.qname() + '", &' + v(var) + ');')
370
- ?>
371
- if (i != n_vars) {
372
- PyErr_SetString(PyExc_Exception, "Unknown variables found in logging dictionary.");
373
- return sim_clean();
374
- }
375
-
376
- /* Always store initial position in logs */
377
- list_update_str = PyUnicode_FromString("append");
378
-
379
- /* Log variables */
380
- for(i=0; i<n_vars; i++) {
381
- flt = PyFloat_FromDouble(vars[i]->value()); // Append doesn't steal
382
- ret = PyObject_CallMethodObjArgs(logs[i], list_update_str, flt, NULL);
383
- Py_DECREF(flt); flt = NULL;
384
- Py_XDECREF(ret);
385
- if (ret == NULL) {
386
- PyErr_SetString(PyExc_Exception, "Call to append() failed on logging list.");
387
- return sim_clean();
388
- }
389
- }
390
- ret = NULL;
391
-
392
- /* Log partial derivatives */
393
- list = PyList_New(N_MATRIX);
394
- if (list == NULL) return sim_clean();
395
- for(i=0; i<N_STATE; i++) {
396
- for(j=0; j<N_STATE; j++) {
397
- PyList_SetItem(list, i*N_STATE+j, PyFloat_FromDouble(state[i][j]));
398
- }
399
- }
400
- if (PyList_Append(log_deriv, list) != 0) {
401
- Py_DECREF(list);
402
- list = NULL;
403
- return sim_clean();
404
- }
405
- Py_DECREF(list);
406
- list = NULL;
407
-
408
- // Set periodic log point 1 log_interval ahead
409
- ilog = 1;
410
- tlog = tmin + log_interval;
411
-
412
- // Done!
413
- Py_RETURN_NONE;
414
- }
415
-
416
- /*
417
- * Takes the next steps in a simulation run
418
- */
419
- static PyObject*
420
- sim_step(PyObject *self, PyObject *args)
421
- {
422
- ESys_Flag flag_pacing;
423
- int i, j;
424
- int steps_taken = 0; /* Steps taken during this call */
425
- double d;
426
-
427
- while(1) {
428
-
429
- /* Calculate next step size */
430
- dt = default_dt;
431
- d = tpace - engine_time; if (d > dt_min && d < dt) dt = d;
432
- d = tmax - engine_time; if (d > dt_min && d < dt) dt = d;
433
- d = tlog - engine_time; if (d > dt_min && d < dt) dt = d;
434
-
435
- /* Advance to next time step */
436
- for(i=0; i<N_STATE; i++) state[i] += deriv[i] * dt;
437
- engine_time += dt;
438
- flag_pacing = ESys_AdvanceTime(pacing, engine_time);
439
- if (flag_pacing!=ESys_OK) { ESys_SetPyErr(flag_pacing); return sim_clean(); }
440
- tpace = ESys_GetNextTime(pacing, NULL);
441
- engine_pace = ESys_GetLevel(pacing, NULL);
442
- rhs(state, deriv);
443
-
444
- /* Check if we're finished
445
- Do this *before* logging (half-open interval rule) */
446
- if (engine_time >= tmax) break;
447
-
448
- /* Logging */
449
- if (engine_time >= tlog) {
450
-
451
- /* Log variables */
452
- for(i=0; i<n_vars; i++) {
453
- flt = PyFloat_FromDouble(vars[i]->value());
454
- ret = PyObject_CallMethodObjArgs(logs[i], list_update_str, flt, NULL);
455
- Py_DECREF(flt); flt = NULL;
456
- Py_XDECREF(ret);
457
- if (ret == NULL) {
458
- PyErr_SetString(PyExc_Exception, "Call to append() failed on logging list.");
459
- return sim_clean();
460
- }
461
- }
462
- ret = NULL;
463
-
464
- /* Log partial derivatives */
465
- list = PyList_New(N_MATRIX);
466
- if (list == NULL) return sim_clean();
467
- for(i=0; i<N_STATE; i++) {
468
- for(j=0; j<N_STATE; j++) {
469
- PyList_SetItem(list, i*N_STATE+j, PyFloat_FromDouble(state[i][j]));
470
- }
471
- }
472
- if (PyList_Append(log_deriv, list) != 0) {
473
- Py_DECREF(list); list = NULL;
474
- return sim_clean();
475
- }
476
- Py_DECREF(list); list = NULL;
477
-
478
- /* Calculate next logging point */
479
- ilog++;
480
- tlog = tmin + (double)ilog * log_interval;
481
- }
482
-
483
- /* Perform any Python signal handling */
484
- if (PyErr_CheckSignals() != 0) {
485
- /* Exception (e.g. timeout or keyboard interrupt) occurred?
486
- Then cancel everything! */
487
- return sim_clean();
488
- }
489
-
490
- /* Report back to python after every x steps */
491
- steps_taken++;
492
- if (steps_taken >= 20) {
493
- return PyFloat_FromDouble(engine_time);
494
- }
495
- }
496
-
497
- /* Set final state & partial derivatives */
498
- for(i=0; i<N_STATE; i++) {
499
- PyList_SetItem(state_out, i, PyFloat_FromDouble(state[i].value()));
500
- /* PyList_SetItem steals a reference: no need to decref the Float! */
501
- for(j=0; j<N_STATE; j++) {
502
- PyList_SetItem(deriv_out, i*N_STATE+j, PyFloat_FromDouble(state[i][j]));
503
- }
504
- }
505
-
506
- /* Clean up and return */
507
- sim_clean();
508
- return PyFloat_FromDouble(engine_time);
509
- }
510
-
511
- /*
512
- * Methods in this module
513
- */
514
- static PyMethodDef SimMethods[] = {
515
- {"sim_init", sim_init, METH_VARARGS, "Initialize the simulation."},
516
- {"sim_step", sim_step, METH_VARARGS, "Perform the next step in the simulation."},
517
- {"sim_clean", py_sim_clean, METH_VARARGS, "Clean up after an aborted simulation."},
518
- {NULL},
519
- };
520
-
521
- /*
522
- * Module definition
523
- */
524
- #if PY_MAJOR_VERSION >= 3
525
-
526
- static struct PyModuleDef moduledef = {
527
- PyModuleDef_HEAD_INIT,
528
- "<?= module_name ?>", /* m_name */
529
- "Generated ICSIM module", /* m_doc */
530
- -1, /* m_size */
531
- SimMethods, /* m_methods */
532
- NULL, /* m_reload */
533
- NULL, /* m_traverse */
534
- NULL, /* m_clear */
535
- NULL, /* m_free */
536
- };
537
-
538
- PyMODINIT_FUNC PyInit_<?=module_name?>(void) {
539
- return PyModule_Create(&moduledef);
540
- }
541
-
542
- #else
543
-
544
- PyMODINIT_FUNC
545
- init<?=module_name?>(void) {
546
- (void) Py_InitModule("<?= module_name ?>", SimMethods);
547
- }
548
-
549
- #endif
550
- }
551
-
552
- /*
553
- * Remove aliases of states, bound variables, constants
554
- */
555
- <?
556
- for var in model.states():
557
- print('#undef ' + v(var.lhs()))
558
- for var in model.states():
559
- print('#undef ' + v(var))
560
- for group in equations.values():
561
- for eq in group.equations(const=True):
562
- print('#undef ' + v(eq.lhs))
563
- ?>