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.
- myokit/__init__.py +5 -3
- myokit/__main__.py +9 -159
- myokit/_config.py +2 -2
- myokit/_expressions.py +6 -6
- myokit/_model_api.py +11 -7
- myokit/_myokit_version.py +1 -1
- myokit/_protocol.py +4 -0
- myokit/_sim/__init__.py +1 -0
- myokit/_sim/cvodessim.c +321 -177
- myokit/_sim/cvodessim.py +107 -43
- myokit/_sim/mcl.h +54 -0
- myokit/formats/__init__.py +63 -12
- myokit/formats/ansic/__init__.py +2 -1
- myokit/formats/ansic/_ewriter.py +159 -40
- myokit/formats/cpp/_ewriter.py +12 -1
- myokit/formats/cuda/_ewriter.py +15 -51
- myokit/formats/easyml/_ewriter.py +26 -54
- myokit/formats/heka/_patchmaster.py +15 -3
- myokit/formats/latex/_ewriter.py +103 -88
- myokit/formats/latex/_exporter.py +1 -1
- myokit/formats/mathml/_ewriter.py +2 -2
- myokit/formats/matlab/_ewriter.py +50 -28
- myokit/formats/opencl/_ewriter.py +61 -78
- myokit/formats/python/_ewriter.py +81 -50
- myokit/formats/stan/_ewriter.py +29 -37
- myokit/gui/source.py +1 -1
- myokit/lib/hh.py +3 -0
- myokit/lib/markov.py +6 -0
- myokit/tests/__init__.py +70 -0
- myokit/tests/data/decker.model +59 -59
- myokit/tests/test_formats.py +115 -7
- myokit/tests/test_formats_ansic.py +344 -0
- myokit/tests/test_formats_axon.py +17 -0
- myokit/tests/test_formats_cpp.py +97 -0
- myokit/tests/test_formats_cuda.py +226 -0
- myokit/tests/test_formats_easyml.py +169 -152
- myokit/tests/{test_formats_exporters.py → test_formats_exporters_run.py} +1 -69
- myokit/tests/test_formats_html.py +1 -3
- myokit/tests/test_formats_latex.py +211 -0
- myokit/tests/test_formats_mathml_content.py +13 -0
- myokit/tests/test_formats_mathml_presentation.py +54 -42
- myokit/tests/test_formats_matlab.py +218 -0
- myokit/tests/test_formats_opencl.py +206 -380
- myokit/tests/test_formats_python.py +557 -0
- myokit/tests/test_formats_stan.py +175 -0
- myokit/tests/test_formats_sympy.py +9 -2
- myokit/tests/test_lib_hh.py +36 -0
- myokit/tests/test_lib_plots.py +0 -16
- myokit/tests/test_model.py +21 -1
- myokit/tests/test_simulation_cvodes.py +137 -56
- myokit/tools.py +3 -2
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/LICENSE.txt +1 -1
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/METADATA +19 -8
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/RECORD +57 -52
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/WHEEL +1 -1
- myokit/tests/test_formats_expression_writers.py +0 -1281
- myokit/tests/test_formats_importers.py +0 -53
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/entry_points.txt +0 -0
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/top_level.txt +0 -0
myokit/_sim/cvodessim.c
CHANGED
|
@@ -25,20 +25,26 @@ import myokit
|
|
|
25
25
|
#include <Python.h>
|
|
26
26
|
#include <stdio.h>
|
|
27
27
|
|
|
28
|
-
#include <cvodes/cvodes.h>
|
|
29
|
-
#include <nvector/nvector_serial.h>
|
|
30
|
-
#include <sundials/sundials_types.h>
|
|
31
28
|
#include <sundials/sundials_config.h>
|
|
32
29
|
#ifndef SUNDIALS_VERSION_MAJOR
|
|
33
30
|
#define SUNDIALS_VERSION_MAJOR 2
|
|
34
31
|
#endif
|
|
32
|
+
#include <sundials/sundials_types.h>
|
|
33
|
+
#if SUNDIALS_VERSION_MAJOR >= 7
|
|
34
|
+
#define realtype sunrealtype
|
|
35
|
+
#define RCONST SUN_RCONST
|
|
36
|
+
#endif
|
|
37
|
+
#include <nvector/nvector_serial.h>
|
|
38
|
+
#include <cvodes/cvodes.h>
|
|
35
39
|
#if SUNDIALS_VERSION_MAJOR >= 3
|
|
36
40
|
#include <sunmatrix/sunmatrix_dense.h>
|
|
37
41
|
#include <sunlinsol/sunlinsol_dense.h>
|
|
38
|
-
#include <cvodes/cvodes_direct.h>
|
|
39
42
|
#else
|
|
40
43
|
#include <cvodes/cvodes_dense.h>
|
|
41
44
|
#endif
|
|
45
|
+
#if SUNDIALS_VERSION_MAJOR < 6
|
|
46
|
+
#include <cvodes/cvodes_direct.h>
|
|
47
|
+
#endif
|
|
42
48
|
|
|
43
49
|
<?
|
|
44
50
|
if myokit.DEBUG_SM:
|
|
@@ -54,6 +60,13 @@ if myokit.DEBUG_SP:
|
|
|
54
60
|
print('#ifndef MYOKIT_DEBUG_PROFILING')
|
|
55
61
|
print('#define MYOKIT_DEBUG_PROFILING')
|
|
56
62
|
print('#endif')
|
|
63
|
+
|
|
64
|
+
if myokit.DEBUG_SS:
|
|
65
|
+
print('// Show simulator stats')
|
|
66
|
+
print('#ifndef MYOKIT_DEBUG_STATS')
|
|
67
|
+
print('#define MYOKIT_DEBUG_STATS')
|
|
68
|
+
print('#endif')
|
|
69
|
+
|
|
57
70
|
?>
|
|
58
71
|
|
|
59
72
|
#include "pacing.h"
|
|
@@ -68,107 +81,180 @@ typedef struct {
|
|
|
68
81
|
realtype *p;
|
|
69
82
|
} *UserData;
|
|
70
83
|
|
|
84
|
+
/*
|
|
85
|
+
* Check flags set by a generic sundials function, set python error.
|
|
86
|
+
* sundials_flag: The value to check
|
|
87
|
+
* funcname: The name of the function that returned the flag
|
|
88
|
+
*/
|
|
89
|
+
int
|
|
90
|
+
check_sundials_flag(int flag, const char *funcname)
|
|
91
|
+
{
|
|
92
|
+
/* Check if flag < 0 */
|
|
93
|
+
if (flag < 0) {
|
|
94
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag = %d", funcname, flag);
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/*
|
|
101
|
+
* Check flags set by any cvode-related function except cvode(), set python error.
|
|
102
|
+
* sundials_flag: The value to check
|
|
103
|
+
* funcname: The name of the function that returned the flag
|
|
104
|
+
*/
|
|
105
|
+
int
|
|
106
|
+
check_cvode_related_flag(int flag, const char *funcname)
|
|
107
|
+
{
|
|
108
|
+
/* Check if flag < 0 */
|
|
109
|
+
if (flag < 0) {
|
|
110
|
+
switch (flag) {
|
|
111
|
+
case CV_MEM_NULL:
|
|
112
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_MEM_NULL: The cvode memory block was not initialized.", funcname);
|
|
113
|
+
break;
|
|
114
|
+
case CV_MEM_FAIL:
|
|
115
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_MEM_FAIL: A memory allocation failed.", funcname);
|
|
116
|
+
break;
|
|
117
|
+
case CV_NO_MALLOC:
|
|
118
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_NO_MALLOC: A memory allocation function returned NULL.", funcname);
|
|
119
|
+
break;
|
|
120
|
+
case CV_ILL_INPUT:
|
|
121
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_ILL_INPUT: Invalid input arguments.", funcname);
|
|
122
|
+
break;
|
|
123
|
+
case CV_NO_SENS:
|
|
124
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_NO_SENS: Forward sensitivity analysis was not initialized.", funcname);
|
|
125
|
+
break;
|
|
126
|
+
case CV_BAD_K:
|
|
127
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_BAD_K: Argument k is not in range.", funcname);
|
|
128
|
+
break;
|
|
129
|
+
case CV_BAD_T:
|
|
130
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_BAD_T: Argument t is not in range.", funcname);
|
|
131
|
+
break;
|
|
132
|
+
case CV_BAD_DKY:
|
|
133
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with flag CV_BAD_DKY: The argument DKY was NULL.", funcname);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
PyErr_Format(PyExc_Exception, "Function %s failed with unhandled flag = %d", funcname, flag);
|
|
137
|
+
}
|
|
138
|
+
return 1;
|
|
139
|
+
}
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
71
143
|
/*
|
|
72
144
|
* Check sundials flags, set python error.
|
|
73
|
-
*
|
|
145
|
+
* flag: The value to check
|
|
146
|
+
* funcname: The name of the function that returned the flag
|
|
147
|
+
*/
|
|
148
|
+
int
|
|
149
|
+
check_cvode_flag(int flag)
|
|
150
|
+
{
|
|
151
|
+
/* Check if flag < 0 */
|
|
152
|
+
if (flag < 0) {
|
|
153
|
+
switch (flag) {
|
|
154
|
+
case CV_TOO_MUCH_WORK:
|
|
155
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag CV_TOO_MUCH_WORK: The solver took mxstep internal steps but could not reach tout.");
|
|
156
|
+
break;
|
|
157
|
+
case CV_TOO_MUCH_ACC:
|
|
158
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag CV_TOO_MUCH_ACC: The solver could not satisfy the accuracy demanded by the user for some internal step.");
|
|
159
|
+
break;
|
|
160
|
+
case CV_ERR_FAILURE:
|
|
161
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag CV_ERR_FAILURE: Error test failures occurred too many times during one internal time step or minimum step size was reached.");
|
|
162
|
+
break;
|
|
163
|
+
case CV_CONV_FAILURE:
|
|
164
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag CV_CONV_FAILURE: Convergence test failures occurred too many times during one internal time step or minimum step size was reached.");
|
|
165
|
+
break;
|
|
166
|
+
case CV_LINIT_FAIL:
|
|
167
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag CV_LINIT_FAIL: The linear solver's initialization function failed.");
|
|
168
|
+
break;
|
|
169
|
+
case -6:
|
|
170
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -6 CV_LSETUP_FAIL: The linear solver's setup function failed in an unrecoverable manner.");
|
|
171
|
+
break;
|
|
172
|
+
case -7:
|
|
173
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -7 CV_LSOLVE_FAIL: The linear solver's solve function failed in an unrecoverable manner.");
|
|
174
|
+
break;
|
|
175
|
+
case -8:
|
|
176
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -8 CV_RHSFUNC_FAIL: The right-hand side function failed in an unrecoverable manner.");
|
|
177
|
+
break;
|
|
178
|
+
case -9:
|
|
179
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -9 CV_FIRST_RHSFUNC_ERR: The right-hand side function failed at the first call.");
|
|
180
|
+
break;
|
|
181
|
+
case -10:
|
|
182
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -10 CV_REPTD_RHSFUNC_ERR: The right-hand side function had repeated recoverable errors.");
|
|
183
|
+
break;
|
|
184
|
+
case -11:
|
|
185
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -11 CV_UNREC_RHSFUNC_ERR: The right-hand side function had a recoverable error, but no recovery is possible.");
|
|
186
|
+
break;
|
|
187
|
+
case -12:
|
|
188
|
+
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -12 CV_RTFUNC_FAIL: The root finding function failed in an unrecoverable manner.");
|
|
189
|
+
break;
|
|
190
|
+
case -20:
|
|
191
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -20 CV_MEM_FAIL: A memory allocation failed.");
|
|
192
|
+
break;
|
|
193
|
+
case -21:
|
|
194
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -21 CV_MEM_NULL: The cvode mem argument was NULL.");
|
|
195
|
+
break;
|
|
196
|
+
case -22:
|
|
197
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -22 CV_ILL_INPUT: One of the function inputs is illegal.");
|
|
198
|
+
break;
|
|
199
|
+
case -23:
|
|
200
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -23 CV_NO_MALLOC: The cvode memory block was not allocated by a call to CVodeMalloc.");
|
|
201
|
+
break;
|
|
202
|
+
case -24:
|
|
203
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -24 CV_BAD_K: The derivative order k is larger than the order used.");
|
|
204
|
+
break;
|
|
205
|
+
case -25:
|
|
206
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -25 CV_BAD_T: The time t is outside the last step taken.");
|
|
207
|
+
break;
|
|
208
|
+
case -26:
|
|
209
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -26 CV_BAD_DKY: The output derivative vector is NULL.");
|
|
210
|
+
break;
|
|
211
|
+
case -27:
|
|
212
|
+
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -27 CV_TOO_CLOSE: The output and initial times are too close to each other.");
|
|
213
|
+
break;
|
|
214
|
+
default:
|
|
215
|
+
PyErr_Format(PyExc_Exception, "Function CVode() failed with unhandled flag = %d", flag);
|
|
216
|
+
}
|
|
217
|
+
return 1;
|
|
218
|
+
}
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
#if SUNDIALS_VERSION_MAJOR >= 7
|
|
223
|
+
/*
|
|
224
|
+
* Check sundials error code (Sundials 7 and above)
|
|
225
|
+
* sunerr : The SunErroCode to check
|
|
74
226
|
* funcname : The name of the function that returned the flag
|
|
75
|
-
* opt : Mode selector
|
|
76
|
-
* 0 : Error if the flag is null
|
|
77
|
-
* 1 : Error if the flag is < 0
|
|
78
|
-
* 2 : Errir
|
|
79
227
|
*/
|
|
80
228
|
int
|
|
81
|
-
|
|
229
|
+
check_sundials_error(SUNErrCode code, const char *funcname)
|
|
82
230
|
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
231
|
+
const char* msg;
|
|
232
|
+
if (code) {
|
|
233
|
+
msg = SUNGetErrMsg(code);
|
|
234
|
+
PyErr_Format(PyExc_Exception, "%s() failed with message = %s", funcname, msg);
|
|
86
235
|
return 1;
|
|
87
|
-
} else if (opt == 1) {
|
|
88
|
-
/* Check if flag < 0 */
|
|
89
|
-
int flag = *((int*)flagvalue);
|
|
90
|
-
if (flag < 0) {
|
|
91
|
-
if (strcmp(funcname, "CVode") == 0) {
|
|
92
|
-
switch (flag) {
|
|
93
|
-
case -1:
|
|
94
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -1 CV_TOO_MUCH_WORK: The solver took mxstep internal steps but could not reach tout.");
|
|
95
|
-
break;
|
|
96
|
-
case -2:
|
|
97
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -2 CV_TOO_MUCH_ACC: The solver could not satisfy the accuracy demanded by the user for some internal step.");
|
|
98
|
-
break;
|
|
99
|
-
case -3:
|
|
100
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -3 CV_ERR_FAILURE: Error test failures occurred too many times during one internal time step or minimum step size was reached.");
|
|
101
|
-
break;
|
|
102
|
-
case -4:
|
|
103
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -4 CV_CONV_FAILURE: Convergence test failures occurred too many times during one internal time step or minimum step size was reached.");
|
|
104
|
-
break;
|
|
105
|
-
case -5:
|
|
106
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -5 CV_LINIT_FAIL: The linear solver's initialization function failed.");
|
|
107
|
-
break;
|
|
108
|
-
case -6:
|
|
109
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -6 CV_LSETUP_FAIL: The linear solver's setup function failed in an unrecoverable manner.");
|
|
110
|
-
break;
|
|
111
|
-
case -7:
|
|
112
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -7 CV_LSOLVE_FAIL: The linear solver's solve function failed in an unrecoverable manner.");
|
|
113
|
-
break;
|
|
114
|
-
case -8:
|
|
115
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -8 CV_RHSFUNC_FAIL: The right-hand side function failed in an unrecoverable manner.");
|
|
116
|
-
break;
|
|
117
|
-
case -9:
|
|
118
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -9 CV_FIRST_RHSFUNC_ERR: The right-hand side function failed at the first call.");
|
|
119
|
-
break;
|
|
120
|
-
case -10:
|
|
121
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -10 CV_REPTD_RHSFUNC_ERR: The right-hand side function had repeated recoverable errors.");
|
|
122
|
-
break;
|
|
123
|
-
case -11:
|
|
124
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -11 CV_UNREC_RHSFUNC_ERR: The right-hand side function had a recoverable error, but no recovery is possible.");
|
|
125
|
-
break;
|
|
126
|
-
case -12:
|
|
127
|
-
PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -12 CV_RTFUNC_FAIL: The root finding function failed in an unrecoverable manner.");
|
|
128
|
-
break;
|
|
129
|
-
case -20:
|
|
130
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -20 CV_MEM_FAIL: A memory allocation failed.");
|
|
131
|
-
break;
|
|
132
|
-
case -21:
|
|
133
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -21 CV_MEM_NULL: The cvode mem argument was NULL.");
|
|
134
|
-
break;
|
|
135
|
-
case -22:
|
|
136
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -22 CV_ILL_INPUT: One of the function inputs is illegal.");
|
|
137
|
-
break;
|
|
138
|
-
case -23:
|
|
139
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -23 CV_NO_MALLOC: The cvode memory block was not allocated by a call to CVodeMalloc.");
|
|
140
|
-
break;
|
|
141
|
-
case -24:
|
|
142
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -24 CV_BAD_K: The derivative order k is larger than the order used.");
|
|
143
|
-
break;
|
|
144
|
-
case -25:
|
|
145
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -25 CV_BAD_T: The time t is outside the last step taken.");
|
|
146
|
-
break;
|
|
147
|
-
case -26:
|
|
148
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -26 CV_BAD_DKY: The output derivative vector is NULL.");
|
|
149
|
-
break;
|
|
150
|
-
case -27:
|
|
151
|
-
PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -27 CV_TOO_CLOSE: The output and initial times are too close to each other.");
|
|
152
|
-
break;
|
|
153
|
-
default:
|
|
154
|
-
PyErr_Format(PyExc_Exception, "Function CVode() failed with unknown flag = %d", flag);
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
PyErr_Format(PyExc_Exception, "%s() failed with flag = %d", funcname, flag);
|
|
158
|
-
}
|
|
159
|
-
return 1;
|
|
160
|
-
}
|
|
161
236
|
}
|
|
162
237
|
return 0;
|
|
163
238
|
}
|
|
239
|
+
#endif
|
|
164
240
|
|
|
165
241
|
/*
|
|
166
242
|
* Error and warning message handler for CVODES.
|
|
167
|
-
* Error messages are already set via check_cvode_flag, so this method
|
|
243
|
+
* Error messages are already set via check_cvode_flag & co, so this method
|
|
168
244
|
* suppresses error messages.
|
|
169
245
|
* Warnings are passed to Python's warning system, where they can be
|
|
170
246
|
* caught or suppressed using the warnings module.
|
|
171
247
|
*/
|
|
248
|
+
#if SUNDIALS_VERSION_MAJOR >= 7
|
|
249
|
+
void
|
|
250
|
+
ErrorHandler(int line, const char* function, const char* file, const char* msg,
|
|
251
|
+
SUNErrCode error_code, void* err_user_data, SUNContext context)
|
|
252
|
+
{
|
|
253
|
+
if (error_code) {
|
|
254
|
+
PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "CVODES: %s", msg);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
#else
|
|
172
258
|
void
|
|
173
259
|
ErrorHandler(int error_code, const char *module, const char *function,
|
|
174
260
|
char *msg, void *eh_data)
|
|
@@ -177,6 +263,7 @@ ErrorHandler(int error_code, const char *module, const char *function,
|
|
|
177
263
|
PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "CVODES: %s", msg);
|
|
178
264
|
}
|
|
179
265
|
}
|
|
266
|
+
#endif
|
|
180
267
|
|
|
181
268
|
/*
|
|
182
269
|
* Initialisation status.
|
|
@@ -196,7 +283,7 @@ union PSys *pacing_systems; /* Array of pacing systems (event based or time se
|
|
|
196
283
|
enum PSysType *pacing_types; /* Array of pacing system types */
|
|
197
284
|
PyObject *protocols; /* The protocols used to generate the pacing systems */
|
|
198
285
|
double* pacing; /* Pacing values, same size as pacing_systems and pacing_types */
|
|
199
|
-
int n_pace; /* The number of pacing systems */
|
|
286
|
+
int n_pace; /* The number of pacing systems: Must be set with every call from Python that uses it */
|
|
200
287
|
|
|
201
288
|
/*
|
|
202
289
|
* CVODE Memory
|
|
@@ -562,6 +649,10 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
562
649
|
Model_Flag flag_model;
|
|
563
650
|
ESys_Flag flag_epacing;
|
|
564
651
|
TSys_Flag flag_fpacing;
|
|
652
|
+
/* Error handling in >=7 */
|
|
653
|
+
#if SUNDIALS_VERSION_MAJOR >= 7
|
|
654
|
+
SUNErrCode sunerr;
|
|
655
|
+
#endif
|
|
565
656
|
|
|
566
657
|
/* Pacing systems */
|
|
567
658
|
ESys epacing;
|
|
@@ -740,11 +831,12 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
740
831
|
/*
|
|
741
832
|
* Create sundials context
|
|
742
833
|
*/
|
|
743
|
-
#if SUNDIALS_VERSION_MAJOR >=
|
|
834
|
+
#if SUNDIALS_VERSION_MAJOR >= 7
|
|
835
|
+
sunerr = SUNContext_Create(SUN_COMM_NULL, &sundials_context);
|
|
836
|
+
if (check_sundials_error(sunerr, "SUNContext_Create")) return sim_clean();
|
|
837
|
+
#elif SUNDIALS_VERSION_MAJOR >= 6
|
|
744
838
|
flag_cvode = SUNContext_Create(NULL, &sundials_context);
|
|
745
|
-
if (
|
|
746
|
-
return sim_cleanx(PyExc_Exception, "Failed to create Sundials context.");
|
|
747
|
-
}
|
|
839
|
+
if (check_sundials_flag(flag_cvode, "SUNContext_Create")) return sim_clean();
|
|
748
840
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
749
841
|
benchmarker_print("CP Created sundials context.");
|
|
750
842
|
#endif
|
|
@@ -760,9 +852,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
760
852
|
#else
|
|
761
853
|
y = N_VNew_Serial(model->n_states);
|
|
762
854
|
#endif
|
|
763
|
-
if (
|
|
764
|
-
return sim_cleanx(PyExc_Exception, "Failed to create state vector.");
|
|
765
|
-
}
|
|
855
|
+
if (y == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for state vector.");
|
|
766
856
|
|
|
767
857
|
/* Create state vector copy for error handling */
|
|
768
858
|
#if SUNDIALS_VERSION_MAJOR >= 6
|
|
@@ -770,16 +860,12 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
770
860
|
#else
|
|
771
861
|
ylast = N_VNew_Serial(model->n_states);
|
|
772
862
|
#endif
|
|
773
|
-
if (
|
|
774
|
-
return sim_cleanx(PyExc_Exception, "Failed to create last-state vector.");
|
|
775
|
-
}
|
|
863
|
+
if (ylast == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for last-state vector.");
|
|
776
864
|
|
|
777
865
|
/* Create sensitivity vector array */
|
|
778
866
|
if (model->has_sensitivities) {
|
|
779
867
|
sy = N_VCloneVectorArray(model->ns_independents, y);
|
|
780
|
-
if (
|
|
781
|
-
return sim_cleanx(PyExc_Exception, "Failed to allocate space to store sensitivities.");
|
|
782
|
-
}
|
|
868
|
+
if (sy == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for sensitivity vector array.");
|
|
783
869
|
}
|
|
784
870
|
|
|
785
871
|
/*
|
|
@@ -802,14 +888,10 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
802
888
|
#else
|
|
803
889
|
z = N_VNew_Serial(model->n_states);
|
|
804
890
|
#endif
|
|
805
|
-
if (
|
|
806
|
-
return sim_cleanx(PyExc_Exception, "Failed to create state vector for logging.");
|
|
807
|
-
}
|
|
891
|
+
if (z == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for state vector for logging.");
|
|
808
892
|
if (model->has_sensitivities) {
|
|
809
893
|
sz = N_VCloneVectorArray(model->ns_independents, y);
|
|
810
|
-
if (
|
|
811
|
-
return sim_cleanx(PyExc_Exception, "Failed to create state sensitivity vector array for logging.");
|
|
812
|
-
}
|
|
894
|
+
if (sz == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for sensitivity vector array for logging.");
|
|
813
895
|
}
|
|
814
896
|
}
|
|
815
897
|
|
|
@@ -957,9 +1039,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
957
1039
|
/* Create parameter scaling vector, for error control */
|
|
958
1040
|
/* TODO: Get this from the Python code ? */
|
|
959
1041
|
pbar = (realtype*)malloc((size_t)model->ns_independents * sizeof(realtype));
|
|
960
|
-
if (pbar == NULL)
|
|
961
|
-
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store parameter scales.");
|
|
962
|
-
}
|
|
1042
|
+
if (pbar == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for parameter scale array.");
|
|
963
1043
|
for (i=0; i<model->ns_independents; i++) {
|
|
964
1044
|
pbar[i] = (udata->p[i] == 0.0 ? 1.0 : fabs(udata->p[i]));
|
|
965
1045
|
}
|
|
@@ -983,17 +1063,11 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
983
1063
|
n_pace = (int)PyList_Size(protocols);
|
|
984
1064
|
}
|
|
985
1065
|
pacing_systems = (union PSys*)malloc((size_t)n_pace * sizeof(union PSys));
|
|
986
|
-
if (pacing_systems == NULL)
|
|
987
|
-
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing systems.");
|
|
988
|
-
}
|
|
1066
|
+
if (pacing_systems == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for pacing systems.");
|
|
989
1067
|
pacing_types = (enum PSysType *)malloc((size_t)n_pace * sizeof(enum PSysType));
|
|
990
|
-
if (pacing_types == NULL)
|
|
991
|
-
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing types.");
|
|
992
|
-
}
|
|
1068
|
+
if (pacing_types == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for pacing types.");
|
|
993
1069
|
pacing = (realtype*)malloc((size_t)n_pace * sizeof(realtype));
|
|
994
|
-
if (pacing == NULL)
|
|
995
|
-
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing values.");
|
|
996
|
-
}
|
|
1070
|
+
if (pacing == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for pacing values.");
|
|
997
1071
|
Model_SetupPacing(model, n_pace);
|
|
998
1072
|
|
|
999
1073
|
/*
|
|
@@ -1074,68 +1148,73 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1074
1148
|
#else
|
|
1075
1149
|
cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON);
|
|
1076
1150
|
#endif
|
|
1077
|
-
if (
|
|
1151
|
+
if (cvode_mem == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate CVODE memory.");
|
|
1078
1152
|
|
|
1079
1153
|
/* Set error and warning-message handler */
|
|
1154
|
+
#if SUNDIALS_VERSION_MAJOR >= 7
|
|
1155
|
+
sunerr = SUNContext_PushErrHandler(sundials_context, ErrorHandler, NULL);
|
|
1156
|
+
if (check_sundials_error(sunerr, "SUNContext_PushErrHandler")) return sim_clean();
|
|
1157
|
+
#else
|
|
1080
1158
|
flag_cvode = CVodeSetErrHandlerFn(cvode_mem, ErrorHandler, NULL);
|
|
1081
|
-
if (
|
|
1159
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSetErrHandlerFn")) return sim_clean();
|
|
1160
|
+
#endif
|
|
1082
1161
|
|
|
1083
1162
|
/* Initialize solver memory, specify the rhs */
|
|
1084
1163
|
flag_cvode = CVodeInit(cvode_mem, rhs, t, y);
|
|
1085
|
-
if (
|
|
1164
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeInit")) return sim_clean();
|
|
1086
1165
|
|
|
1087
1166
|
/* Set absolute and relative tolerances */
|
|
1088
1167
|
flag_cvode = CVodeSStolerances(cvode_mem, RCONST(rel_tol), RCONST(abs_tol));
|
|
1089
|
-
if (
|
|
1168
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSStolerances")) return sim_clean();
|
|
1090
1169
|
|
|
1091
1170
|
/* Set a maximum step size (or 0.0 for none) */
|
|
1092
1171
|
flag_cvode = CVodeSetMaxStep(cvode_mem, dt_max < 0 ? 0.0 : dt_max);
|
|
1093
|
-
if (
|
|
1172
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSetmaxStep")) return sim_clean();
|
|
1094
1173
|
|
|
1095
1174
|
/* Set a minimum step size (or 0.0 for none) */
|
|
1096
1175
|
flag_cvode = CVodeSetMinStep(cvode_mem, dt_min < 0 ? 0.0 : dt_min);
|
|
1097
|
-
if (
|
|
1176
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSetminStep")) return sim_clean();
|
|
1098
1177
|
|
|
1099
1178
|
#if SUNDIALS_VERSION_MAJOR >= 6
|
|
1100
1179
|
/* Create dense matrix for use in linear solves */
|
|
1101
1180
|
sundense_matrix = SUNDenseMatrix(model->n_states, model->n_states, sundials_context);
|
|
1102
|
-
if (
|
|
1181
|
+
if (sundense_matrix == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense matrix.");
|
|
1103
1182
|
|
|
1104
1183
|
/* Create dense linear solver object with matrix */
|
|
1105
1184
|
sundense_solver = SUNLinSol_Dense(y, sundense_matrix, sundials_context);
|
|
1106
|
-
if (
|
|
1185
|
+
if (sundense_solver == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense solver.");
|
|
1107
1186
|
|
|
1108
1187
|
/* Attach the matrix and solver to cvode */
|
|
1109
1188
|
flag_cvode = CVodeSetLinearSolver(cvode_mem, sundense_solver, sundense_matrix);
|
|
1110
|
-
if (
|
|
1189
|
+
if (check_sundials_flag(flag_cvode, "CVodeSetLinearSolver")) return sim_clean();
|
|
1111
1190
|
#elif SUNDIALS_VERSION_MAJOR >= 4
|
|
1112
1191
|
/* Create dense matrix for use in linear solves */
|
|
1113
1192
|
sundense_matrix = SUNDenseMatrix(model->n_states, model->n_states);
|
|
1114
|
-
if (
|
|
1193
|
+
if (sundense_matrix == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense matrix.");
|
|
1115
1194
|
|
|
1116
1195
|
/* Create dense linear solver object with matrix */
|
|
1117
1196
|
sundense_solver = SUNLinSol_Dense(y, sundense_matrix);
|
|
1118
|
-
if (
|
|
1197
|
+
if (sundense_solver == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense solver.");
|
|
1119
1198
|
|
|
1120
1199
|
/* Attach the matrix and solver to cvode */
|
|
1121
1200
|
flag_cvode = CVodeSetLinearSolver(cvode_mem, sundense_solver, sundense_matrix);
|
|
1122
|
-
if (
|
|
1201
|
+
if (check_sundials_flag(flag_cvode, "CVodeSetLinearSolver")) return sim_clean();
|
|
1123
1202
|
#elif SUNDIALS_VERSION_MAJOR >= 3
|
|
1124
1203
|
/* Create dense matrix for use in linear solves */
|
|
1125
1204
|
sundense_matrix = SUNDenseMatrix(model->n_states, model->n_states);
|
|
1126
|
-
if (
|
|
1205
|
+
if (sundense_matrix == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense matrix.");
|
|
1127
1206
|
|
|
1128
1207
|
/* Create dense linear solver object with matrix */
|
|
1129
1208
|
sundense_solver = SUNDenseLinearSolver(y, sundense_matrix);
|
|
1130
|
-
if (
|
|
1209
|
+
if (sundense_solver == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense solver.");
|
|
1131
1210
|
|
|
1132
1211
|
/* Attach the matrix and solver to cvode */
|
|
1133
1212
|
flag_cvode = CVDlsSetLinearSolver(cvode_mem, sundense_solver, sundense_matrix);
|
|
1134
|
-
if (
|
|
1213
|
+
if (check_sundials_flag(flag_cvode, "CVDlsSetLinearSolver")) return sim_clean();
|
|
1135
1214
|
#else
|
|
1136
1215
|
/* Create dense matrix for use in linear solves */
|
|
1137
1216
|
flag_cvode = CVDense(cvode_mem, model->n_states);
|
|
1138
|
-
if (
|
|
1217
|
+
if (check_sundials_flag(flag_cvode, "CVDense")) return sim_clean();
|
|
1139
1218
|
#endif
|
|
1140
1219
|
|
|
1141
1220
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
@@ -1148,19 +1227,19 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1148
1227
|
RHS of the sensitivity ODE */
|
|
1149
1228
|
/*flag_cvode = CVodeSensInit(cvode_mem, model->ns_independents, CV_SIMULTANEOUS, rhs1, sy);*/
|
|
1150
1229
|
flag_cvode = CVodeSensInit(cvode_mem, model->ns_independents, CV_SIMULTANEOUS, NULL, sy);
|
|
1151
|
-
if (
|
|
1230
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSensInit")) return sim_clean();
|
|
1152
1231
|
|
|
1153
1232
|
/* Attach user data */
|
|
1154
1233
|
flag_cvode = CVodeSetUserData(cvode_mem, udata);
|
|
1155
|
-
if (
|
|
1234
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSetUserData")) return sim_clean();
|
|
1156
1235
|
|
|
1157
1236
|
/* Set parameter scales used in tolerances */
|
|
1158
1237
|
flag_cvode = CVodeSetSensParams(cvode_mem, udata->p, pbar, NULL);
|
|
1159
|
-
if (
|
|
1238
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSetSensParams")) return sim_clean();
|
|
1160
1239
|
|
|
1161
1240
|
/* Set sensitivity tolerances calculating method (using pbar) */
|
|
1162
1241
|
flag_cvode = CVodeSensEEtolerances(cvode_mem);
|
|
1163
|
-
if (
|
|
1242
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSensEEtolerances")) return sim_clean();
|
|
1164
1243
|
|
|
1165
1244
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1166
1245
|
benchmarker_print("CP CVODES sensitivity methods initialized.");
|
|
@@ -1177,7 +1256,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1177
1256
|
if (model->is_ode && PyList_Check(rf_list)) {
|
|
1178
1257
|
/* Initialize root function with 1 component */
|
|
1179
1258
|
flag_cvode = CVodeRootInit(cvode_mem, 1, rf_function);
|
|
1180
|
-
if (
|
|
1259
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeRootInit")) return sim_clean();
|
|
1181
1260
|
|
|
1182
1261
|
/* Direction of root crossings, one entry per root function, but we only use 1. */
|
|
1183
1262
|
rf_direction = (int*)malloc(sizeof(int));
|
|
@@ -1302,6 +1381,22 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1302
1381
|
benchmarker_print("CP Logging times and strategy initialized.");
|
|
1303
1382
|
#endif
|
|
1304
1383
|
|
|
1384
|
+
#ifdef MYOKIT_DEBUG_STATS
|
|
1385
|
+
if (model->is_ode) {
|
|
1386
|
+
printf(" 1. number of steps taken by cvodes.\n");
|
|
1387
|
+
printf(" 2. number of calls to the user's f function.\n");
|
|
1388
|
+
printf(" 3. number of calls made to the linear solver setup function.\n");
|
|
1389
|
+
printf(" 4. number of error test failures.\n");
|
|
1390
|
+
printf(" 5. method order used on the last internal step.\n");
|
|
1391
|
+
printf(" 6. method order to be used on the next internal step.\n");
|
|
1392
|
+
printf(" 7. actual value of initial step size.\n");
|
|
1393
|
+
printf(" 8. step size taken on the last internal step.\n");
|
|
1394
|
+
printf(" 9. step size to be attempted on the next internal step.\n");
|
|
1395
|
+
printf("10. current internal time reached.\n");
|
|
1396
|
+
printf("1\t2\t3\t4\t5\t6\t\t7\t\t8\t\t9\t\t10\n");
|
|
1397
|
+
}
|
|
1398
|
+
#endif
|
|
1399
|
+
|
|
1305
1400
|
/*
|
|
1306
1401
|
* Done!
|
|
1307
1402
|
*/
|
|
@@ -1340,6 +1435,13 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1340
1435
|
PyObject *val;
|
|
1341
1436
|
PyObject* ret;
|
|
1342
1437
|
|
|
1438
|
+
#ifdef MYOKIT_DEBUG_STATS
|
|
1439
|
+
/* CVODE stats */
|
|
1440
|
+
long int cv_nsteps, cv_nfevals, cv_nlinsetups, cv_netfails;
|
|
1441
|
+
int cv_qlast, cv_qcur;
|
|
1442
|
+
realtype cv_hinused, cv_hlast, cv_hcur, cv_tcur;
|
|
1443
|
+
#endif
|
|
1444
|
+
|
|
1343
1445
|
/*
|
|
1344
1446
|
* Set start time for logging of realtime.
|
|
1345
1447
|
* This is handled here instead of in sim_init so it only includes time
|
|
@@ -1367,12 +1469,30 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1367
1469
|
|
|
1368
1470
|
/* Take a single ODE step */
|
|
1369
1471
|
#ifdef MYOKIT_DEBUG_MESSAGES
|
|
1370
|
-
printf("\nCM Taking CVODE step from time %g to %g
|
|
1472
|
+
printf("\nCM Taking CVODE step from time %g to %g", t, tnext);
|
|
1371
1473
|
#endif
|
|
1372
1474
|
flag_cvode = CVode(cvode_mem, tnext, y, &t, CV_ONE_STEP);
|
|
1475
|
+
#ifdef MYOKIT_DEBUG_MESSAGES
|
|
1476
|
+
printf(" : flag %d\n", flag_cvode);
|
|
1477
|
+
#endif
|
|
1478
|
+
|
|
1479
|
+
/* Show cvodes stats */
|
|
1480
|
+
#ifdef MYOKIT_DEBUG_STATS
|
|
1481
|
+
CVodeGetIntegratorStats(cvode_mem, &cv_nsteps, &cv_nfevals,
|
|
1482
|
+
&cv_nlinsetups, &cv_netfails, &cv_qlast, &cv_qcur,
|
|
1483
|
+
&cv_hinused, &cv_hlast, &cv_hcur, &cv_tcur);
|
|
1484
|
+
printf("%ld,\t%ld,\t%ld,\t%ld,\t%d,\t%d,\t%g,\t%g,\t%g,\t%g\n",
|
|
1485
|
+
cv_nsteps, cv_nfevals, cv_nlinsetups, cv_netfails,
|
|
1486
|
+
cv_qlast, cv_qcur,
|
|
1487
|
+
cv_hinused, cv_hlast, cv_hcur, cv_tcur);
|
|
1488
|
+
#endif
|
|
1373
1489
|
|
|
1374
1490
|
/* Check for errors */
|
|
1375
|
-
if (check_cvode_flag(
|
|
1491
|
+
if (check_cvode_flag(flag_cvode)) {
|
|
1492
|
+
#ifdef MYOKIT_DEBUG_MESSAGES
|
|
1493
|
+
printf("\nCM CVODE flag %d. Setting error output and returning.\n", flag_cvode);
|
|
1494
|
+
#endif
|
|
1495
|
+
|
|
1376
1496
|
/* Something went wrong... Set outputs and return */
|
|
1377
1497
|
for (i=0; i<model->n_states; i++) {
|
|
1378
1498
|
PyList_SetItem(state_py, i, PyFloat_FromDouble(NV_Ith_S(ylast, i)));
|
|
@@ -1384,6 +1504,8 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1384
1504
|
for (i=0; i<n_pace; i++) {
|
|
1385
1505
|
PyList_SetItem(bound_py, 3 + i, PyFloat_FromDouble(pacing[i]));
|
|
1386
1506
|
}
|
|
1507
|
+
|
|
1508
|
+
/* Error state set by check_cvode_flag, so use ordinary return. */
|
|
1387
1509
|
return sim_clean();
|
|
1388
1510
|
}
|
|
1389
1511
|
|
|
@@ -1400,7 +1522,18 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1400
1522
|
/* Check if progress is being made */
|
|
1401
1523
|
if (t == tlast) {
|
|
1402
1524
|
if (++zero_step_count >= max_zero_step_count) {
|
|
1403
|
-
|
|
1525
|
+
/* Something went wrong: set outputs and return */
|
|
1526
|
+
for (i=0; i<model->n_states; i++) {
|
|
1527
|
+
PyList_SetItem(state_py, i, PyFloat_FromDouble(NV_Ith_S(ylast, i)));
|
|
1528
|
+
/* PyList_SetItem steals a reference: no need to decref the double! */
|
|
1529
|
+
}
|
|
1530
|
+
PyList_SetItem(bound_py, 0, PyFloat_FromDouble(tlast));
|
|
1531
|
+
PyList_SetItem(bound_py, 1, PyFloat_FromDouble(realtime));
|
|
1532
|
+
PyList_SetItem(bound_py, 2, PyFloat_FromDouble((double)evaluations));
|
|
1533
|
+
for (i=0; i<n_pace; i++) {
|
|
1534
|
+
PyList_SetItem(bound_py, 3 + i, PyFloat_FromDouble(pacing[i]));
|
|
1535
|
+
}
|
|
1536
|
+
return sim_cleanx(PyExc_ArithmeticError, "Maximum number of zero-length steps taken.");
|
|
1404
1537
|
}
|
|
1405
1538
|
} else {
|
|
1406
1539
|
/* Only count consecutive zero steps */
|
|
@@ -1426,10 +1559,10 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1426
1559
|
|
|
1427
1560
|
/* Go back to time=tnext */
|
|
1428
1561
|
flag_cvode = CVodeGetDky(cvode_mem, tnext, 0, y);
|
|
1429
|
-
if (
|
|
1562
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeGetDky")) return sim_clean();
|
|
1430
1563
|
if (model->has_sensitivities) {
|
|
1431
1564
|
flag_cvode = CVodeGetSensDky(cvode_mem, tnext, 0, sy);
|
|
1432
|
-
if (
|
|
1565
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeGetSensDky")) return sim_clean();
|
|
1433
1566
|
}
|
|
1434
1567
|
t = tnext;
|
|
1435
1568
|
/* Require reinit (after logging) */
|
|
@@ -1440,7 +1573,7 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1440
1573
|
/* Get current sensitivity vector */
|
|
1441
1574
|
if (model->has_sensitivities) {
|
|
1442
1575
|
flag_cvode = CVodeGetSens(cvode_mem, &t, sy);
|
|
1443
|
-
if (
|
|
1576
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeGetSens")) return sim_clean();
|
|
1444
1577
|
}
|
|
1445
1578
|
|
|
1446
1579
|
/* Root found */
|
|
@@ -1448,7 +1581,7 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1448
1581
|
|
|
1449
1582
|
/* Get directions of root crossings (1 per root function) */
|
|
1450
1583
|
flag_root = CVodeGetRootInfo(cvode_mem, rf_direction);
|
|
1451
|
-
if (
|
|
1584
|
+
if (check_cvode_related_flag(flag_root, "CVodeGetRootInfo")) return sim_clean();
|
|
1452
1585
|
/* We only have one root function, so we know that rf_direction[0] is non-zero at this point. */
|
|
1453
1586
|
|
|
1454
1587
|
/* Store tuple (time, direction) for the found root */
|
|
@@ -1488,10 +1621,10 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1488
1621
|
/* Get interpolated y(tlog) */
|
|
1489
1622
|
if (model->is_ode) {
|
|
1490
1623
|
flag_cvode = CVodeGetDky(cvode_mem, tlog, 0, z);
|
|
1491
|
-
if (
|
|
1624
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeGetDky")) return sim_clean();
|
|
1492
1625
|
if (model->has_sensitivities) {
|
|
1493
1626
|
flag_cvode = CVodeGetSensDky(cvode_mem, tlog, 0, sz);
|
|
1494
|
-
if (
|
|
1627
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeGetSensDky")) return sim_clean();
|
|
1495
1628
|
}
|
|
1496
1629
|
}
|
|
1497
1630
|
/* If cvode-free mode, the states can't change so we don't
|
|
@@ -1617,10 +1750,10 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1617
1750
|
*/
|
|
1618
1751
|
if (model->is_ode && flag_reinit) {
|
|
1619
1752
|
flag_cvode = CVodeReInit(cvode_mem, t, y);
|
|
1620
|
-
if (
|
|
1753
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeReInit")) return sim_clean();
|
|
1621
1754
|
if (model->has_sensitivities) {
|
|
1622
1755
|
flag_cvode = CVodeSensReInit(cvode_mem, CV_SIMULTANEOUS, sy);
|
|
1623
|
-
if (
|
|
1756
|
+
if (check_cvode_related_flag(flag_cvode, "CVodeSensReInit")) return sim_clean();
|
|
1624
1757
|
}
|
|
1625
1758
|
flag_reinit = 0;
|
|
1626
1759
|
}
|
|
@@ -1697,36 +1830,40 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1697
1830
|
* Evaluates the state derivatives at the given state
|
|
1698
1831
|
*/
|
|
1699
1832
|
PyObject*
|
|
1700
|
-
|
|
1833
|
+
sim_evaluate_derivatives(PyObject *self, PyObject *args)
|
|
1701
1834
|
{
|
|
1702
1835
|
/* Declare variables here for C89 compatibility */
|
|
1703
1836
|
int i;
|
|
1704
1837
|
int success;
|
|
1705
1838
|
double time_in;
|
|
1839
|
+
double realtime_in;
|
|
1840
|
+
double evaluations_in;
|
|
1706
1841
|
PyObject *pace_in;
|
|
1707
|
-
double *
|
|
1708
|
-
Model model;
|
|
1709
|
-
Model_Flag flag_model;
|
|
1710
|
-
PyObject *state;
|
|
1711
|
-
PyObject *deriv;
|
|
1842
|
+
double *pacing_values;
|
|
1712
1843
|
PyObject *literals;
|
|
1713
1844
|
PyObject *parameters;
|
|
1845
|
+
PyObject *state;
|
|
1846
|
+
PyObject *deriv;
|
|
1714
1847
|
PyObject *val;
|
|
1848
|
+
Model model;
|
|
1849
|
+
Model_Flag flag_model;
|
|
1715
1850
|
|
|
1716
1851
|
/* Start */
|
|
1717
1852
|
success = 0;
|
|
1718
1853
|
|
|
1719
1854
|
/* Check input arguments */
|
|
1720
1855
|
/* Check input arguments 0123456789ABCDEF*/
|
|
1721
|
-
if (!PyArg_ParseTuple(args, "
|
|
1856
|
+
if (!PyArg_ParseTuple(args, "dOddOOOO",
|
|
1722
1857
|
&time_in, /* 0. Float: time */
|
|
1723
|
-
&pace_in, /* 1. List:
|
|
1724
|
-
&
|
|
1725
|
-
&
|
|
1858
|
+
&pace_in, /* 1. List: pacing values */
|
|
1859
|
+
&realtime_in, /* 2. Float: realtime */
|
|
1860
|
+
&evaluations_in, /* 3. Float: evaluations */
|
|
1726
1861
|
&literals, /* 4. List: literal constant values */
|
|
1727
|
-
¶meters
|
|
1728
|
-
|
|
1729
|
-
|
|
1862
|
+
¶meters, /* 5. List: parameter values */
|
|
1863
|
+
&state, /* 6. List: state */
|
|
1864
|
+
&deriv /* 7. List: store derivatives here */
|
|
1865
|
+
)) {
|
|
1866
|
+
PyErr_SetString(PyExc_Exception, "Incorrect input arguments in sim_evaluate_derivatives.");
|
|
1730
1867
|
/* Nothing allocated yet, no pyobjects _created_, return directly */
|
|
1731
1868
|
return 0;
|
|
1732
1869
|
}
|
|
@@ -1736,14 +1873,6 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1736
1873
|
PyErr_SetString(PyExc_Exception, "Pace argument must be a list.");
|
|
1737
1874
|
return 0;
|
|
1738
1875
|
}
|
|
1739
|
-
if (!PyList_Check(state)) {
|
|
1740
|
-
PyErr_SetString(PyExc_Exception, "State argument must be a list.");
|
|
1741
|
-
return 0;
|
|
1742
|
-
}
|
|
1743
|
-
if (!PyList_Check(deriv)) {
|
|
1744
|
-
PyErr_SetString(PyExc_Exception, "Derivatives argument must be a list.");
|
|
1745
|
-
return 0;
|
|
1746
|
-
}
|
|
1747
1876
|
if (!PyList_Check(literals)) {
|
|
1748
1877
|
PyErr_SetString(PyExc_Exception, "Literals argument must be a list.");
|
|
1749
1878
|
return 0;
|
|
@@ -1752,6 +1881,14 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1752
1881
|
PyErr_SetString(PyExc_Exception, "Parameters argument must be a list.");
|
|
1753
1882
|
return 0;
|
|
1754
1883
|
}
|
|
1884
|
+
if (!PyList_Check(state)) {
|
|
1885
|
+
PyErr_SetString(PyExc_Exception, "State argument must be a list.");
|
|
1886
|
+
return 0;
|
|
1887
|
+
}
|
|
1888
|
+
if (!PyList_Check(deriv)) {
|
|
1889
|
+
PyErr_SetString(PyExc_Exception, "Derivatives argument must be a list.");
|
|
1890
|
+
return 0;
|
|
1891
|
+
}
|
|
1755
1892
|
|
|
1756
1893
|
/* From this point on, no more direct returning: use goto error */
|
|
1757
1894
|
model = NULL;
|
|
@@ -1767,6 +1904,8 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1767
1904
|
goto error;
|
|
1768
1905
|
}
|
|
1769
1906
|
|
|
1907
|
+
/* Set up pacing (but without protocols) */
|
|
1908
|
+
n_pace = (int)PyList_Size(pace_in);
|
|
1770
1909
|
flag_model = Model_SetupPacing(model, n_pace);
|
|
1771
1910
|
if (flag_model != Model_OK) {
|
|
1772
1911
|
Model_SetPyErr(flag_model);
|
|
@@ -1774,18 +1913,23 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1774
1913
|
}
|
|
1775
1914
|
|
|
1776
1915
|
/* Set pacing values */
|
|
1777
|
-
|
|
1916
|
+
pacing_values = (double*)malloc((size_t)n_pace * sizeof(double));
|
|
1778
1917
|
for (i=0; i<n_pace; i++) {
|
|
1779
1918
|
val = PyList_GetItem(pace_in, i); /* Don't decref */
|
|
1780
1919
|
if (!PyFloat_Check(val)) {
|
|
1781
1920
|
PyErr_Format(PyExc_Exception, "Item %d in pace vector is not a float.", i);
|
|
1782
1921
|
goto error;
|
|
1783
1922
|
}
|
|
1784
|
-
|
|
1923
|
+
pacing_values[i] = PyFloat_AsDouble(val);
|
|
1785
1924
|
}
|
|
1786
1925
|
|
|
1787
1926
|
/* Set bound variables */
|
|
1788
|
-
Model_SetBoundVariables(
|
|
1927
|
+
Model_SetBoundVariables(
|
|
1928
|
+
model,
|
|
1929
|
+
(realtype)time_in,
|
|
1930
|
+
(realtype*)pacing_values,
|
|
1931
|
+
(realtype)realtime_in,
|
|
1932
|
+
(realtype)evaluations_in);
|
|
1789
1933
|
|
|
1790
1934
|
/* Set literal values */
|
|
1791
1935
|
for (i=0; i<model->n_literals; i++) {
|
|
@@ -1925,7 +2069,7 @@ PyMethodDef SimMethods[] = {
|
|
|
1925
2069
|
{"sim_init", sim_init, METH_VARARGS, "Initialize the simulation."},
|
|
1926
2070
|
{"sim_step", sim_step, METH_VARARGS, "Perform the next step in the simulation."},
|
|
1927
2071
|
{"sim_clean", py_sim_clean, METH_VARARGS, "Clean up after an aborted simulation."},
|
|
1928
|
-
{"
|
|
2072
|
+
{"evaluate_derivatives", sim_evaluate_derivatives, METH_VARARGS, "Evaluate the state derivatives."},
|
|
1929
2073
|
{"set_tolerance", sim_set_tolerance, METH_VARARGS, "Set the absolute and relative solver tolerance."},
|
|
1930
2074
|
{"set_max_step_size", sim_set_max_step_size, METH_VARARGS, "Set the maximum solver step size (0 for none)."},
|
|
1931
2075
|
{"set_min_step_size", sim_set_min_step_size, METH_VARARGS, "Set the minimum solver step size (0 for none)."},
|