myokit 1.36.0__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/_myokit_version.py CHANGED
@@ -14,7 +14,7 @@ __release__ = True
14
14
  # incompatibility
15
15
  # - Changes to revision indicate bugfixes, tiny new features
16
16
  # - There is no significance to odd/even numbers
17
- __version_tuple__ = 1, 36, 0
17
+ __version_tuple__ = 1, 36, 1
18
18
 
19
19
  # String version of the version number
20
20
  __version__ = '.'.join([str(x) for x in __version_tuple__])
myokit/_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:
@@ -75,107 +81,180 @@ typedef struct {
75
81
  realtype *p;
76
82
  } *UserData;
77
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
+
78
143
  /*
79
144
  * Check sundials flags, set python error.
80
- * flagvalue : The value to check
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
81
226
  * funcname : The name of the function that returned the flag
82
- * opt : Mode selector
83
- * 0 : Error if the flag is null
84
- * 1 : Error if the flag is < 0
85
- * 2 : Errir
86
227
  */
87
228
  int
88
- check_cvode_flag(void *flagvalue, char *funcname, int opt)
229
+ check_sundials_error(SUNErrCode code, const char *funcname)
89
230
  {
90
- if (opt == 0 && flagvalue == NULL) {
91
- /* Check if sundials function returned null pointer */
92
- PyErr_Format(PyExc_Exception, "%s() failed - returned NULL pointer", funcname);
231
+ const char* msg;
232
+ if (code) {
233
+ msg = SUNGetErrMsg(code);
234
+ PyErr_Format(PyExc_Exception, "%s() failed with message = %s", funcname, msg);
93
235
  return 1;
94
- } else if (opt == 1) {
95
- /* Check if flag < 0 */
96
- int flag = *((int*)flagvalue);
97
- if (flag < 0) {
98
- if (strcmp(funcname, "CVode") == 0) {
99
- switch (flag) {
100
- case -1:
101
- 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.");
102
- break;
103
- case -2:
104
- 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.");
105
- break;
106
- case -3:
107
- 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.");
108
- break;
109
- case -4:
110
- 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.");
111
- break;
112
- case -5:
113
- PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -5 CV_LINIT_FAIL: The linear solver's initialization function failed.");
114
- break;
115
- case -6:
116
- PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -6 CV_LSETUP_FAIL: The linear solver's setup function failed in an unrecoverable manner.");
117
- break;
118
- case -7:
119
- PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -7 CV_LSOLVE_FAIL: The linear solver's solve function failed in an unrecoverable manner.");
120
- break;
121
- case -8:
122
- PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -8 CV_RHSFUNC_FAIL: The right-hand side function failed in an unrecoverable manner.");
123
- break;
124
- case -9:
125
- PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -9 CV_FIRST_RHSFUNC_ERR: The right-hand side function failed at the first call.");
126
- break;
127
- case -10:
128
- PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -10 CV_REPTD_RHSFUNC_ERR: The right-hand side function had repeated recoverable errors.");
129
- break;
130
- case -11:
131
- 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.");
132
- break;
133
- case -12:
134
- PyErr_SetString(PyExc_ArithmeticError, "Function CVode() failed with flag -12 CV_RTFUNC_FAIL: The root finding function failed in an unrecoverable manner.");
135
- break;
136
- case -20:
137
- PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -20 CV_MEM_FAIL: A memory allocation failed.");
138
- break;
139
- case -21:
140
- PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -21 CV_MEM_NULL: The cvode mem argument was NULL.");
141
- break;
142
- case -22:
143
- PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -22 CV_ILL_INPUT: One of the function inputs is illegal.");
144
- break;
145
- case -23:
146
- 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.");
147
- break;
148
- case -24:
149
- PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -24 CV_BAD_K: The derivative order k is larger than the order used.");
150
- break;
151
- case -25:
152
- PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -25 CV_BAD_T: The time t is outside the last step taken.");
153
- break;
154
- case -26:
155
- PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -26 CV_BAD_DKY: The output derivative vector is NULL.");
156
- break;
157
- case -27:
158
- PyErr_SetString(PyExc_Exception, "Function CVode() failed with flag -27 CV_TOO_CLOSE: The output and initial times are too close to each other.");
159
- break;
160
- default:
161
- PyErr_Format(PyExc_Exception, "Function CVode() failed with unknown flag = %d", flag);
162
- }
163
- } else {
164
- PyErr_Format(PyExc_Exception, "%s() failed with flag = %d", funcname, flag);
165
- }
166
- return 1;
167
- }
168
236
  }
169
237
  return 0;
170
238
  }
239
+ #endif
171
240
 
172
241
  /*
173
242
  * Error and warning message handler for CVODES.
174
- * 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
175
244
  * suppresses error messages.
176
245
  * Warnings are passed to Python's warning system, where they can be
177
246
  * caught or suppressed using the warnings module.
178
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
179
258
  void
180
259
  ErrorHandler(int error_code, const char *module, const char *function,
181
260
  char *msg, void *eh_data)
@@ -184,6 +263,7 @@ ErrorHandler(int error_code, const char *module, const char *function,
184
263
  PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "CVODES: %s", msg);
185
264
  }
186
265
  }
266
+ #endif
187
267
 
188
268
  /*
189
269
  * Initialisation status.
@@ -569,6 +649,10 @@ sim_init(PyObject *self, PyObject *args)
569
649
  Model_Flag flag_model;
570
650
  ESys_Flag flag_epacing;
571
651
  TSys_Flag flag_fpacing;
652
+ /* Error handling in >=7 */
653
+ #if SUNDIALS_VERSION_MAJOR >= 7
654
+ SUNErrCode sunerr;
655
+ #endif
572
656
 
573
657
  /* Pacing systems */
574
658
  ESys epacing;
@@ -747,11 +831,12 @@ sim_init(PyObject *self, PyObject *args)
747
831
  /*
748
832
  * Create sundials context
749
833
  */
750
- #if SUNDIALS_VERSION_MAJOR >= 6
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
751
838
  flag_cvode = SUNContext_Create(NULL, &sundials_context);
752
- if (check_cvode_flag(&flag_cvode, "SUNContext_Create", 1)) {
753
- return sim_cleanx(PyExc_Exception, "Failed to create Sundials context.");
754
- }
839
+ if (check_sundials_flag(flag_cvode, "SUNContext_Create")) return sim_clean();
755
840
  #ifdef MYOKIT_DEBUG_PROFILING
756
841
  benchmarker_print("CP Created sundials context.");
757
842
  #endif
@@ -767,9 +852,7 @@ sim_init(PyObject *self, PyObject *args)
767
852
  #else
768
853
  y = N_VNew_Serial(model->n_states);
769
854
  #endif
770
- if (check_cvode_flag((void*)y, "N_VNew_Serial", 0)) {
771
- return sim_cleanx(PyExc_Exception, "Failed to create state vector.");
772
- }
855
+ if (y == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for state vector.");
773
856
 
774
857
  /* Create state vector copy for error handling */
775
858
  #if SUNDIALS_VERSION_MAJOR >= 6
@@ -777,16 +860,12 @@ sim_init(PyObject *self, PyObject *args)
777
860
  #else
778
861
  ylast = N_VNew_Serial(model->n_states);
779
862
  #endif
780
- if (check_cvode_flag((void*)ylast, "N_VNew_Serial", 0)) {
781
- return sim_cleanx(PyExc_Exception, "Failed to create last-state vector.");
782
- }
863
+ if (ylast == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for last-state vector.");
783
864
 
784
865
  /* Create sensitivity vector array */
785
866
  if (model->has_sensitivities) {
786
867
  sy = N_VCloneVectorArray(model->ns_independents, y);
787
- if (check_cvode_flag((void*)sy, "N_VCloneVectorArray", 0)) {
788
- return sim_cleanx(PyExc_Exception, "Failed to allocate space to store sensitivities.");
789
- }
868
+ if (sy == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for sensitivity vector array.");
790
869
  }
791
870
 
792
871
  /*
@@ -809,14 +888,10 @@ sim_init(PyObject *self, PyObject *args)
809
888
  #else
810
889
  z = N_VNew_Serial(model->n_states);
811
890
  #endif
812
- if (check_cvode_flag((void*)z, "N_VNew_Serial", 0)) {
813
- return sim_cleanx(PyExc_Exception, "Failed to create state vector for logging.");
814
- }
891
+ if (z == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for state vector for logging.");
815
892
  if (model->has_sensitivities) {
816
893
  sz = N_VCloneVectorArray(model->ns_independents, y);
817
- if (check_cvode_flag((void*)sz, "N_VCloneVectorArray", 0)) {
818
- return sim_cleanx(PyExc_Exception, "Failed to create state sensitivity vector array for logging.");
819
- }
894
+ if (sz == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for sensitivity vector array for logging.");
820
895
  }
821
896
  }
822
897
 
@@ -964,9 +1039,7 @@ sim_init(PyObject *self, PyObject *args)
964
1039
  /* Create parameter scaling vector, for error control */
965
1040
  /* TODO: Get this from the Python code ? */
966
1041
  pbar = (realtype*)malloc((size_t)model->ns_independents * sizeof(realtype));
967
- if (pbar == NULL) {
968
- return sim_cleanx(PyExc_Exception, "Unable to allocate space to store parameter scales.");
969
- }
1042
+ if (pbar == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for parameter scale array.");
970
1043
  for (i=0; i<model->ns_independents; i++) {
971
1044
  pbar[i] = (udata->p[i] == 0.0 ? 1.0 : fabs(udata->p[i]));
972
1045
  }
@@ -990,17 +1063,11 @@ sim_init(PyObject *self, PyObject *args)
990
1063
  n_pace = (int)PyList_Size(protocols);
991
1064
  }
992
1065
  pacing_systems = (union PSys*)malloc((size_t)n_pace * sizeof(union PSys));
993
- if (pacing_systems == NULL) {
994
- return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing systems.");
995
- }
1066
+ if (pacing_systems == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for pacing systems.");
996
1067
  pacing_types = (enum PSysType *)malloc((size_t)n_pace * sizeof(enum PSysType));
997
- if (pacing_types == NULL) {
998
- return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing types.");
999
- }
1068
+ if (pacing_types == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for pacing types.");
1000
1069
  pacing = (realtype*)malloc((size_t)n_pace * sizeof(realtype));
1001
- if (pacing == NULL) {
1002
- return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing values.");
1003
- }
1070
+ if (pacing == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for pacing values.");
1004
1071
  Model_SetupPacing(model, n_pace);
1005
1072
 
1006
1073
  /*
@@ -1081,68 +1148,73 @@ sim_init(PyObject *self, PyObject *args)
1081
1148
  #else
1082
1149
  cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON);
1083
1150
  #endif
1084
- if (check_cvode_flag((void*)cvode_mem, "CVodeCreate", 0)) return sim_clean();
1151
+ if (cvode_mem == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate CVODE memory.");
1085
1152
 
1086
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
1087
1158
  flag_cvode = CVodeSetErrHandlerFn(cvode_mem, ErrorHandler, NULL);
1088
- if (check_cvode_flag(&flag_cvode, "CVodeInit", 1)) return sim_clean();
1159
+ if (check_cvode_related_flag(flag_cvode, "CVodeSetErrHandlerFn")) return sim_clean();
1160
+ #endif
1089
1161
 
1090
1162
  /* Initialize solver memory, specify the rhs */
1091
1163
  flag_cvode = CVodeInit(cvode_mem, rhs, t, y);
1092
- if (check_cvode_flag(&flag_cvode, "CVodeInit", 1)) return sim_clean();
1164
+ if (check_cvode_related_flag(flag_cvode, "CVodeInit")) return sim_clean();
1093
1165
 
1094
1166
  /* Set absolute and relative tolerances */
1095
1167
  flag_cvode = CVodeSStolerances(cvode_mem, RCONST(rel_tol), RCONST(abs_tol));
1096
- if (check_cvode_flag(&flag_cvode, "CVodeSStolerances", 1)) return sim_clean();
1168
+ if (check_cvode_related_flag(flag_cvode, "CVodeSStolerances")) return sim_clean();
1097
1169
 
1098
1170
  /* Set a maximum step size (or 0.0 for none) */
1099
1171
  flag_cvode = CVodeSetMaxStep(cvode_mem, dt_max < 0 ? 0.0 : dt_max);
1100
- if (check_cvode_flag(&flag_cvode, "CVodeSetmaxStep", 1)) return sim_clean();
1172
+ if (check_cvode_related_flag(flag_cvode, "CVodeSetmaxStep")) return sim_clean();
1101
1173
 
1102
1174
  /* Set a minimum step size (or 0.0 for none) */
1103
1175
  flag_cvode = CVodeSetMinStep(cvode_mem, dt_min < 0 ? 0.0 : dt_min);
1104
- if (check_cvode_flag(&flag_cvode, "CVodeSetminStep", 1)) return sim_clean();
1176
+ if (check_cvode_related_flag(flag_cvode, "CVodeSetminStep")) return sim_clean();
1105
1177
 
1106
1178
  #if SUNDIALS_VERSION_MAJOR >= 6
1107
1179
  /* Create dense matrix for use in linear solves */
1108
1180
  sundense_matrix = SUNDenseMatrix(model->n_states, model->n_states, sundials_context);
1109
- if (check_cvode_flag((void *)sundense_matrix, "SUNDenseMatrix", 0)) return sim_clean();
1181
+ if (sundense_matrix == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense matrix.");
1110
1182
 
1111
1183
  /* Create dense linear solver object with matrix */
1112
1184
  sundense_solver = SUNLinSol_Dense(y, sundense_matrix, sundials_context);
1113
- if (check_cvode_flag((void *)sundense_solver, "SUNLinSol_Dense", 0)) return sim_clean();
1185
+ if (sundense_solver == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense solver.");
1114
1186
 
1115
1187
  /* Attach the matrix and solver to cvode */
1116
1188
  flag_cvode = CVodeSetLinearSolver(cvode_mem, sundense_solver, sundense_matrix);
1117
- if (check_cvode_flag(&flag_cvode, "CVodeSetLinearSolver", 1)) return sim_clean();
1189
+ if (check_sundials_flag(flag_cvode, "CVodeSetLinearSolver")) return sim_clean();
1118
1190
  #elif SUNDIALS_VERSION_MAJOR >= 4
1119
1191
  /* Create dense matrix for use in linear solves */
1120
1192
  sundense_matrix = SUNDenseMatrix(model->n_states, model->n_states);
1121
- if (check_cvode_flag((void *)sundense_matrix, "SUNDenseMatrix", 0)) return sim_clean();
1193
+ if (sundense_matrix == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense matrix.");
1122
1194
 
1123
1195
  /* Create dense linear solver object with matrix */
1124
1196
  sundense_solver = SUNLinSol_Dense(y, sundense_matrix);
1125
- if (check_cvode_flag((void *)sundense_solver, "SUNLinSol_Dense", 0)) return sim_clean();
1197
+ if (sundense_solver == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense solver.");
1126
1198
 
1127
1199
  /* Attach the matrix and solver to cvode */
1128
1200
  flag_cvode = CVodeSetLinearSolver(cvode_mem, sundense_solver, sundense_matrix);
1129
- if (check_cvode_flag(&flag_cvode, "CVodeSetLinearSolver", 1)) return sim_clean();
1201
+ if (check_sundials_flag(flag_cvode, "CVodeSetLinearSolver")) return sim_clean();
1130
1202
  #elif SUNDIALS_VERSION_MAJOR >= 3
1131
1203
  /* Create dense matrix for use in linear solves */
1132
1204
  sundense_matrix = SUNDenseMatrix(model->n_states, model->n_states);
1133
- if (check_cvode_flag((void *)sundense_matrix, "SUNDenseMatrix", 0)) return sim_clean();
1205
+ if (sundense_matrix == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense matrix.");
1134
1206
 
1135
1207
  /* Create dense linear solver object with matrix */
1136
1208
  sundense_solver = SUNDenseLinearSolver(y, sundense_matrix);
1137
- if (check_cvode_flag((void *)sundense_solver, "SUNDenseLinearSolver", 0)) return sim_clean();
1209
+ if (sundense_solver == NULL) return sim_cleanx(PyExc_Exception, "Unable to allocate space for dense solver.");
1138
1210
 
1139
1211
  /* Attach the matrix and solver to cvode */
1140
1212
  flag_cvode = CVDlsSetLinearSolver(cvode_mem, sundense_solver, sundense_matrix);
1141
- if (check_cvode_flag(&flag_cvode, "CVDlsSetLinearSolver", 1)) return sim_clean();
1213
+ if (check_sundials_flag(flag_cvode, "CVDlsSetLinearSolver")) return sim_clean();
1142
1214
  #else
1143
1215
  /* Create dense matrix for use in linear solves */
1144
1216
  flag_cvode = CVDense(cvode_mem, model->n_states);
1145
- if (check_cvode_flag(&flag_cvode, "CVDense", 1)) return sim_clean();
1217
+ if (check_sundials_flag(flag_cvode, "CVDense")) return sim_clean();
1146
1218
  #endif
1147
1219
 
1148
1220
  #ifdef MYOKIT_DEBUG_PROFILING
@@ -1155,19 +1227,19 @@ sim_init(PyObject *self, PyObject *args)
1155
1227
  RHS of the sensitivity ODE */
1156
1228
  /*flag_cvode = CVodeSensInit(cvode_mem, model->ns_independents, CV_SIMULTANEOUS, rhs1, sy);*/
1157
1229
  flag_cvode = CVodeSensInit(cvode_mem, model->ns_independents, CV_SIMULTANEOUS, NULL, sy);
1158
- if (check_cvode_flag(&flag_cvode, "CVodeSensInit", 1)) return sim_clean();
1230
+ if (check_cvode_related_flag(flag_cvode, "CVodeSensInit")) return sim_clean();
1159
1231
 
1160
1232
  /* Attach user data */
1161
1233
  flag_cvode = CVodeSetUserData(cvode_mem, udata);
1162
- if (check_cvode_flag(&flag_cvode, "CVodeSetUserData", 1)) return sim_clean();
1234
+ if (check_cvode_related_flag(flag_cvode, "CVodeSetUserData")) return sim_clean();
1163
1235
 
1164
1236
  /* Set parameter scales used in tolerances */
1165
1237
  flag_cvode = CVodeSetSensParams(cvode_mem, udata->p, pbar, NULL);
1166
- if (check_cvode_flag(&flag_cvode, "CVodeSetSensParams", 1)) return sim_clean();
1238
+ if (check_cvode_related_flag(flag_cvode, "CVodeSetSensParams")) return sim_clean();
1167
1239
 
1168
1240
  /* Set sensitivity tolerances calculating method (using pbar) */
1169
1241
  flag_cvode = CVodeSensEEtolerances(cvode_mem);
1170
- if (check_cvode_flag(&flag_cvode, "CVodeSensEEtolerances", 1)) return sim_clean();
1242
+ if (check_cvode_related_flag(flag_cvode, "CVodeSensEEtolerances")) return sim_clean();
1171
1243
 
1172
1244
  #ifdef MYOKIT_DEBUG_PROFILING
1173
1245
  benchmarker_print("CP CVODES sensitivity methods initialized.");
@@ -1184,7 +1256,7 @@ sim_init(PyObject *self, PyObject *args)
1184
1256
  if (model->is_ode && PyList_Check(rf_list)) {
1185
1257
  /* Initialize root function with 1 component */
1186
1258
  flag_cvode = CVodeRootInit(cvode_mem, 1, rf_function);
1187
- if (check_cvode_flag(&flag_cvode, "CVodeRootInit", 1)) return sim_clean();
1259
+ if (check_cvode_related_flag(flag_cvode, "CVodeRootInit")) return sim_clean();
1188
1260
 
1189
1261
  /* Direction of root crossings, one entry per root function, but we only use 1. */
1190
1262
  rf_direction = (int*)malloc(sizeof(int));
@@ -1416,7 +1488,7 @@ sim_step(PyObject *self, PyObject *args)
1416
1488
  #endif
1417
1489
 
1418
1490
  /* Check for errors */
1419
- if (check_cvode_flag(&flag_cvode, "CVode", 1)) {
1491
+ if (check_cvode_flag(flag_cvode)) {
1420
1492
  #ifdef MYOKIT_DEBUG_MESSAGES
1421
1493
  printf("\nCM CVODE flag %d. Setting error output and returning.\n", flag_cvode);
1422
1494
  #endif
@@ -1487,10 +1559,10 @@ sim_step(PyObject *self, PyObject *args)
1487
1559
 
1488
1560
  /* Go back to time=tnext */
1489
1561
  flag_cvode = CVodeGetDky(cvode_mem, tnext, 0, y);
1490
- if (check_cvode_flag(&flag_cvode, "CVodeGetDky", 1)) return sim_clean();
1562
+ if (check_cvode_related_flag(flag_cvode, "CVodeGetDky")) return sim_clean();
1491
1563
  if (model->has_sensitivities) {
1492
1564
  flag_cvode = CVodeGetSensDky(cvode_mem, tnext, 0, sy);
1493
- if (check_cvode_flag(&flag_cvode, "CVodeGetSensDky", 1)) return sim_clean();
1565
+ if (check_cvode_related_flag(flag_cvode, "CVodeGetSensDky")) return sim_clean();
1494
1566
  }
1495
1567
  t = tnext;
1496
1568
  /* Require reinit (after logging) */
@@ -1501,7 +1573,7 @@ sim_step(PyObject *self, PyObject *args)
1501
1573
  /* Get current sensitivity vector */
1502
1574
  if (model->has_sensitivities) {
1503
1575
  flag_cvode = CVodeGetSens(cvode_mem, &t, sy);
1504
- if (check_cvode_flag(&flag_cvode, "CVodeGetSens", 1)) return sim_clean();
1576
+ if (check_cvode_related_flag(flag_cvode, "CVodeGetSens")) return sim_clean();
1505
1577
  }
1506
1578
 
1507
1579
  /* Root found */
@@ -1509,7 +1581,7 @@ sim_step(PyObject *self, PyObject *args)
1509
1581
 
1510
1582
  /* Get directions of root crossings (1 per root function) */
1511
1583
  flag_root = CVodeGetRootInfo(cvode_mem, rf_direction);
1512
- if (check_cvode_flag(&flag_root, "CVodeGetRootInfo", 1)) return sim_clean();
1584
+ if (check_cvode_related_flag(flag_root, "CVodeGetRootInfo")) return sim_clean();
1513
1585
  /* We only have one root function, so we know that rf_direction[0] is non-zero at this point. */
1514
1586
 
1515
1587
  /* Store tuple (time, direction) for the found root */
@@ -1549,10 +1621,10 @@ sim_step(PyObject *self, PyObject *args)
1549
1621
  /* Get interpolated y(tlog) */
1550
1622
  if (model->is_ode) {
1551
1623
  flag_cvode = CVodeGetDky(cvode_mem, tlog, 0, z);
1552
- if (check_cvode_flag(&flag_cvode, "CVodeGetDky", 1)) return sim_clean();
1624
+ if (check_cvode_related_flag(flag_cvode, "CVodeGetDky")) return sim_clean();
1553
1625
  if (model->has_sensitivities) {
1554
1626
  flag_cvode = CVodeGetSensDky(cvode_mem, tlog, 0, sz);
1555
- if (check_cvode_flag(&flag_cvode, "CVodeGetSensDky", 1)) return sim_clean();
1627
+ if (check_cvode_related_flag(flag_cvode, "CVodeGetSensDky")) return sim_clean();
1556
1628
  }
1557
1629
  }
1558
1630
  /* If cvode-free mode, the states can't change so we don't
@@ -1678,10 +1750,10 @@ sim_step(PyObject *self, PyObject *args)
1678
1750
  */
1679
1751
  if (model->is_ode && flag_reinit) {
1680
1752
  flag_cvode = CVodeReInit(cvode_mem, t, y);
1681
- if (check_cvode_flag(&flag_cvode, "CVodeReInit", 1)) return sim_clean();
1753
+ if (check_cvode_related_flag(flag_cvode, "CVodeReInit")) return sim_clean();
1682
1754
  if (model->has_sensitivities) {
1683
1755
  flag_cvode = CVodeSensReInit(cvode_mem, CV_SIMULTANEOUS, sy);
1684
- if (check_cvode_flag(&flag_cvode, "CVodeSensReInit", 1)) return sim_clean();
1756
+ if (check_cvode_related_flag(flag_cvode, "CVodeSensReInit")) return sim_clean();
1685
1757
  }
1686
1758
  flag_reinit = 0;
1687
1759
  }
myokit/_sim/mcl.h CHANGED
@@ -651,6 +651,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
651
651
  }
652
652
 
653
653
  // Name
654
+ #ifdef MYOKIT_DEBUG_MESSAGES
655
+ printf(" Querying name\n");
656
+ #endif
654
657
  flag = clGetDeviceInfo(device_id, CL_DEVICE_NAME, bufsize, buffer, NULL);
655
658
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
656
659
  val = PyUnicode_FromString(buffer);
@@ -658,6 +661,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
658
661
  Py_CLEAR(val);
659
662
 
660
663
  // Vendor
664
+ #ifdef MYOKIT_DEBUG_MESSAGES
665
+ printf(" Querying vendor\n");
666
+ #endif
661
667
  flag = clGetDeviceInfo(device_id, CL_DEVICE_VENDOR, bufsize, buffer, NULL);
662
668
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
663
669
  val = PyUnicode_FromString(buffer);
@@ -665,6 +671,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
665
671
  Py_CLEAR(val);
666
672
 
667
673
  // Device version
674
+ #ifdef MYOKIT_DEBUG_MESSAGES
675
+ printf(" Querying device version\n");
676
+ #endif
668
677
  flag = clGetDeviceInfo(device_id, CL_DEVICE_VERSION, bufsize, buffer, NULL);
669
678
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
670
679
  val = PyUnicode_FromString(buffer);
@@ -672,6 +681,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
672
681
  Py_CLEAR(val);
673
682
 
674
683
  // Driver version
684
+ #ifdef MYOKIT_DEBUG_MESSAGES
685
+ printf(" Querying driver version\n");
686
+ #endif
675
687
  flag = clGetDeviceInfo(device_id, CL_DRIVER_VERSION, bufsize, buffer, NULL);
676
688
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
677
689
  val = PyUnicode_FromString(buffer);
@@ -679,6 +691,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
679
691
  Py_CLEAR(val);
680
692
 
681
693
  // Clock speed (MHz)
694
+ #ifdef MYOKIT_DEBUG_MESSAGES
695
+ printf(" Querying clock speed\n");
696
+ #endif
682
697
  flag = clGetDeviceInfo(device_id, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(buf_uint), &buf_uint, NULL);
683
698
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
684
699
  val = PyLong_FromUnsignedLong(buf_uint);
@@ -686,6 +701,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
686
701
  Py_CLEAR(val);
687
702
 
688
703
  // Global memory (bytes)
704
+ #ifdef MYOKIT_DEBUG_MESSAGES
705
+ printf(" Querying global memory size\n");
706
+ #endif
689
707
  flag = clGetDeviceInfo(device_id, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(buf_ulong), &buf_ulong, NULL);
690
708
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
691
709
  val = PyLong_FromUnsignedLongLong(buf_ulong);
@@ -693,6 +711,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
693
711
  Py_CLEAR(val);
694
712
 
695
713
  // Local memory (bytes)
714
+ #ifdef MYOKIT_DEBUG_MESSAGES
715
+ printf(" Querying local memory size\n");
716
+ #endif
696
717
  flag = clGetDeviceInfo(device_id, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(buf_ulong), &buf_ulong, NULL);
697
718
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
698
719
  val = PyLong_FromUnsignedLongLong(buf_ulong);
@@ -700,6 +721,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
700
721
  Py_CLEAR(val);
701
722
 
702
723
  // Const memory (bytes)
724
+ #ifdef MYOKIT_DEBUG_MESSAGES
725
+ printf(" Querying max buffer size\n");
726
+ #endif
703
727
  flag = clGetDeviceInfo(device_id, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(buf_ulong), &buf_ulong, NULL);
704
728
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
705
729
  val = PyLong_FromUnsignedLongLong(buf_ulong);
@@ -707,6 +731,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
707
731
  Py_CLEAR(val);
708
732
 
709
733
  // Computing units
734
+ #ifdef MYOKIT_DEBUG_MESSAGES
735
+ printf(" Querying max computing units\n");
736
+ #endif
710
737
  flag = clGetDeviceInfo(device_id, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(buf_uint), &buf_uint, NULL);
711
738
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
712
739
  val = PyLong_FromUnsignedLong(buf_uint);
@@ -714,6 +741,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
714
741
  Py_CLEAR(val);
715
742
 
716
743
  // Max workgroup size
744
+ #ifdef MYOKIT_DEBUG_MESSAGES
745
+ printf(" Querying max work group size\n");
746
+ #endif
717
747
  flag = clGetDeviceInfo(device_id, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(buf_size_t), &buf_size_t, NULL);
718
748
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
719
749
  val = PyLong_FromSize_t(buf_size_t);
@@ -721,6 +751,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
721
751
  Py_CLEAR(val);
722
752
 
723
753
  // Max workitem sizes
754
+ #ifdef MYOKIT_DEBUG_MESSAGES
755
+ printf(" Querying max work item sizes\n");
756
+ #endif
724
757
  flag = clGetDeviceInfo(device_id, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(buf_uint), &buf_uint, NULL);
725
758
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
726
759
  val = PyLong_FromUnsignedLong(buf_uint);
@@ -739,6 +772,9 @@ PyObject* mcl_info_device_dict(cl_device_id device_id, size_t bufsize, char* buf
739
772
  Py_CLEAR(items_sizes_tuple);
740
773
 
741
774
  // Maximum size of a kernel parameter
775
+ #ifdef MYOKIT_DEBUG_MESSAGES
776
+ printf(" Querying maximum kernel parameter size\n");
777
+ #endif
742
778
  flag = clGetDeviceInfo(device_id, CL_DEVICE_MAX_PARAMETER_SIZE, sizeof(buf_size_t), &buf_size_t, NULL);
743
779
  if(mcl_flag(flag)) { Py_DECREF(device); return NULL; }
744
780
  val = PyLong_FromSize_t(buf_size_t);
@@ -834,29 +870,47 @@ mcl_info(void)
834
870
 
835
871
  // Check all platforms
836
872
  for (i=0; i<n_platforms; i++) {
873
+ #ifdef MYOKIT_DEBUG_MESSAGES
874
+ printf("Checking platform %u\n", (unsigned int)i);
875
+ #endif
837
876
 
838
877
  // Create platform dict
839
878
  platform = mcl_info_platform_dict(platform_ids[i], sizeof(buffer), buffer);
840
879
  if (platform == NULL) { Py_DECREF(platforms); return NULL; }
880
+ #ifdef MYOKIT_DEBUG_MESSAGES
881
+ printf(" Obtained platform info dict.\n");
882
+ #endif
841
883
 
842
884
  // Count devices
843
885
  flag = clGetDeviceIDs(platform_ids[i], CL_DEVICE_TYPE_ALL, MCL_MAX_DEVICES, device_ids, &n_devices);
844
886
  if (flag == CL_DEVICE_NOT_FOUND) {
845
887
  n_devices = 0;
888
+ } else if (flag == CL_INVALID_VALUE) {
889
+ // This seems to happen on Mac OS 14.4.1
890
+ n_devices = 0;
846
891
  } else if (mcl_flag(flag)) {
847
892
  Py_DECREF(platforms);
848
893
  return NULL;
849
894
  }
895
+ #ifdef MYOKIT_DEBUG_MESSAGES
896
+ printf(" Found %u devices.\n", (unsigned int)n_devices);
897
+ #endif
850
898
 
851
899
  // Create devices tuple, must decref on exception
852
900
  devices = PyTuple_New((size_t)n_devices);
853
901
 
854
902
  // Add devices
855
903
  for (j=0; j<n_devices; j++) {
904
+ #ifdef MYOKIT_DEBUG_MESSAGES
905
+ printf(" Checking device %u\n", (unsigned int)j);
906
+ #endif
856
907
 
857
908
  // Create device dict, must decref on exception
858
909
  device = mcl_info_device_dict(device_ids[j], sizeof(buffer), buffer);
859
910
  if (device == NULL) { Py_DECREF(platforms); Py_DECREF(devices); return NULL; }
911
+ #ifdef MYOKIT_DEBUG_MESSAGES
912
+ printf(" Obtained device info dict.\n");
913
+ #endif
860
914
 
861
915
  // Add device to devices tuple (steals reference)
862
916
  PyTuple_SetItem(devices, j, device);
myokit/lib/hh.py CHANGED
@@ -298,6 +298,9 @@ class HHModel:
298
298
  '_y[' + k + '] = ' + state.uname() + ' = '
299
299
  + inf + ' + (_y0[' + k + '] - ' + inf
300
300
  + ') * numpy.exp(-_t / ' + tau + ')')
301
+ f.append(
302
+ '_y[' + k + '][_t == 0] = ' + state.uname() + '[_t == 0] = '
303
+ + '_y0[' + k + ']')
301
304
 
302
305
  # Add current calculation
303
306
  if self._current is not None:
@@ -15,6 +15,8 @@ import myokit.lib.hh as hh
15
15
 
16
16
  from myokit.tests import DIR_DATA
17
17
 
18
+ from myokit.tests import WarningCollector
19
+
18
20
 
19
21
  MODEL = """
20
22
  [[model]]
@@ -914,6 +916,40 @@ class AnalyticalSimulationTest(unittest.TestCase):
914
916
  e = np.abs(d1['binding.I'] - d2['binding.I'])
915
917
  self.assertLess(np.max(e), 2e-4)
916
918
 
919
+ def test_tau_overflow(self):
920
+ # Overflows leading to tau=0 should still report current
921
+ # https://github.com/myokit/myokit/issues/1059
922
+
923
+ # Load model and convert to inf-tau form
924
+ fname = os.path.join(DIR_DATA, 'lr-1991-fitting.mmt')
925
+ model = hh.convert_hh_states_to_inf_tau_form(myokit.load_model(fname))
926
+
927
+ # Get initial state and set steady state
928
+ initial_state = model.get('ina.m').initial_value(as_float=True)
929
+ steady_state = 0.75
930
+ model.get('ina.m.inf').set_rhs(steady_state)
931
+
932
+ # Create an analytical simulation
933
+ model = hh.HHModel(model, states=['ina.m', 'ina.h', 'ina.j'],
934
+ parameters=['ina.p5'], current='ina.INa')
935
+ p = myokit.pacing.steptrain_linear(20, 40, 10, -80, 10, 10)
936
+ s = hh.AnalyticalSimulation(model, protocol=p)
937
+
938
+ # Setting p5=0.001 will trigger an overflow in ina.m.beta
939
+ s.set_parameters([0.001])
940
+ with WarningCollector() as wc:
941
+ # Log times chosen so that s._function varies length of _t
942
+ log = s.run(41, log_times=np.array([0, 1, 2, 10, 11, 12, 20, 40]))
943
+ self.assertIn('overflow', wc.text())
944
+
945
+ # Should be no NaNs in log
946
+ self.assertFalse(np.any(np.isnan(log['ina.INa'])))
947
+ self.assertFalse(np.any(np.isnan(log['ina.m'])))
948
+
949
+ # Should immediately jump from initial state to steady state
950
+ self.assertTrue(log['ina.m'][0] == initial_state)
951
+ self.assertTrue(np.all(log['ina.m'][1:] == steady_state))
952
+
917
953
 
918
954
  if __name__ == '__main__':
919
955
  unittest.main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: myokit
3
- Version: 1.36.0
3
+ Version: 1.36.1
4
4
  Summary: A modeling and simulation tool for cardiac cellular electrophysiology
5
5
  Home-page: http://myokit.org
6
6
  Author: Michael Clerx
@@ -8,7 +8,7 @@ myokit/_err.py,sha256=PZJFrb3KGqW8XiT466UDtSTsW83M2J02T96Vm2CaCto,11060
8
8
  myokit/_expressions.py,sha256=7We9a830pV7bvQziZcjwab-96p0LXg4AfawZhvvdR8U,103902
9
9
  myokit/_io.py,sha256=2ll5Yb-sbP4tvc3pPmzhNuv_PaRMPJlNRWb1TzXfELg,8948
10
10
  myokit/_model_api.py,sha256=I93WLjstvikqpkqQ5KC4PjNVlSz3nrxms_aKDgSEZ2c,194214
11
- myokit/_myokit_version.py,sha256=ps-8_nYwMU87PvevIU7ZzXjDQ-nrIwylXhDzIpiv3VM,726
11
+ myokit/_myokit_version.py,sha256=Tj0x0hW2n9taFBS4CUqW6b_QI-kKolONZiG692DKLek,726
12
12
  myokit/_parsing.py,sha256=GTVUwJvqjkQ3rc6BiwMFnzanLivbSUzW796gHCTJrNg,74065
13
13
  myokit/_progress.py,sha256=Mi2QU6Vqj4qudhXc76amXM31iID2Mo8Gljw5OH2COZ4,4410
14
14
  myokit/_protocol.py,sha256=_N16LGHppIv4yCSPjy0q2f-Oed0yG1wMk0ipTtXnMck,30756
@@ -85,14 +85,14 @@ myokit/_sim/cmodel.h,sha256=PlXRNDWV5JDsl28G-k3UlzwFCF5_crkAeWpRgPO8a0s,38795
85
85
  myokit/_sim/cmodel.py,sha256=9amSihccWepI1SGI98b5tvvSq2cmAMLX-ecgHoXnc0Y,15775
86
86
  myokit/_sim/compiler.c,sha256=yahdqeQhEU4Uduy3xP2NS21k8h2rQXEQTWYpsE6NEFk,4047
87
87
  myokit/_sim/compiler.py,sha256=80Qwk7_LOjbu0jt9_aeMLQMEvYj3H4xIoE525zUUEK8,2664
88
- myokit/_sim/cvodessim.c,sha256=CU7kQcKCIAhuPfb-R83i5Vy8PNCS8PGmwa3mgSu_WdQ,75604
88
+ myokit/_sim/cvodessim.c,sha256=iWXHVSNTN2VqGGu24N8QFRWwpUUxDo17fTIP0Fv0Ikg,78062
89
89
  myokit/_sim/cvodessim.py,sha256=EtFixQFg84qQy134TWOAgFd__cUrWs1LdXiJ_YJ-e_Y,46122
90
90
  myokit/_sim/differential.hpp,sha256=LiaFNQks_4RkWeNEnUc48XjbdYyGSsxfWo35leygM68,15446
91
91
  myokit/_sim/fiber_tissue.c,sha256=mKtNy3Qs2Tg917hgCryaftwJGHqFn7WZAOuJWG3VVpY,47444
92
92
  myokit/_sim/fiber_tissue.py,sha256=A3zyGPGHNjFdGgbIzCiKYN8o4L2nq7W_ZjO996jF9Kc,50780
93
93
  myokit/_sim/jacobian.cpp,sha256=mvuxHnxiyg4GW-ik1qOgOGbaj-sb-DbtidsRDXfRIjc,8012
94
94
  myokit/_sim/jacobian.py,sha256=5Gmli0knQUozhYyarOrMBFnvytKnrufOh3HrGiycUMM,12957
95
- myokit/_sim/mcl.h,sha256=psbSuBr38bEBhS3CqNfgBjnQflqGny5uDZfL1bpb558,32352
95
+ myokit/_sim/mcl.h,sha256=B8k6eur1VsvnYO2bV94Zm2-B66sCZMgPmzCUQnfelqA,34114
96
96
  myokit/_sim/opencl.c,sha256=jQ3eJNldvX-sOnbIrexUSnOmIfEFSL9ceHNYkW18y80,5037
97
97
  myokit/_sim/opencl.py,sha256=cHJ4CeqAmDLEik0WSuZ46UJYKmpaq2i0wuEZu_ZC7ng,16446
98
98
  myokit/_sim/openclsim.c,sha256=St0P93K0mcYt2oabR7-XRsVFRsrL6kGW-b_kA-P6TsE,46541
@@ -197,7 +197,7 @@ myokit/gui/vargrapher.py,sha256=GALPOZjQ0ShOBu_qd_RwVRRQla0t2ctgQ25Jb8NmuJ8,6072
197
197
  myokit/lib/__init__.py,sha256=GWvBrLDJHdbobXjt9WMFAd1td2Ml7dnvtzsDmYfuVFM,216
198
198
  myokit/lib/deps.py,sha256=gB-W7LFZK6gAzf00mXvu6ws44Yua06Gd9HsKMe0lpXM,23859
199
199
  myokit/lib/guess.py,sha256=BW_wOeStFKpjdZWRZpaO5PLEj8KGSdy_1kc3FM36zfk,28056
200
- myokit/lib/hh.py,sha256=TR9ENse4bG5uvh-7r5_LyEo7m5IJBcoTP3KEXp1EYIs,46678
200
+ myokit/lib/hh.py,sha256=8wMRnjrjZ8gNeErKz0KYQSqUeljJPPC2G339jPjNFXw,46813
201
201
  myokit/lib/markov.py,sha256=VNXvrRdnATILxvuXm-VPw7S_L1Jtd9rRJPtOHKYtxZQ,67940
202
202
  myokit/lib/multi.py,sha256=WDYvoAaVsMqnshk1NoVnH1zyVeVZ0GtsdHplZlkG86A,4408
203
203
  myokit/lib/plots.py,sha256=tRyM4DhcZzlPLBs-VxdsZ7MJXvqLlDWmC12WhL7pP44,13875
@@ -245,7 +245,7 @@ myokit/tests/test_jacobian_calculator.py,sha256=_nBJdNI0L6tspWX7RgZcM-WW9CJ8oxZp
245
245
  myokit/tests/test_jacobian_tracer.py,sha256=SoT6pOXKtzsDHPY2krHVCTtu7BDBtYobhFqejj77q4M,1767
246
246
  myokit/tests/test_lib_deps.py,sha256=0Hgw_ncakKuKOe8awVezmTdxIIoVMZz4JjTEFsIOakc,7476
247
247
  myokit/tests/test_lib_guess.py,sha256=IqbElIMWQN_FxiGj4tohZq9JZLpSAFzn4d9lo0-WKOE,42333
248
- myokit/tests/test_lib_hh.py,sha256=rbNtnT_JXGIEbM-nN82IfntHAz7W2XbRW9CCMo7fOB8,31014
248
+ myokit/tests/test_lib_hh.py,sha256=f6QUvPpsJlRQ5gnULlQQUO9yh4sRSYr7rsqQCURNi3o,32591
249
249
  myokit/tests/test_lib_markov.py,sha256=Rg_jqgSiKtlpaE6pLiCcmYlCTqyVkPkQ5SIGfyPRv2I,39983
250
250
  myokit/tests/test_lib_multi.py,sha256=XL2qxtgNeO2aRaaM1VEzYBo1H3FTBY7-cftqsKwoNHo,5145
251
251
  myokit/tests/test_lib_plots.py,sha256=_t1QucHdCoy6fALOZDY9DL0cMRJYB0nflk68LFSwU7U,5754
@@ -391,9 +391,9 @@ myokit/tests/data/multi/beeler-no-name.mmt,sha256=tBeWcTVag1gAQAvxWlUqH6GQhF1D4D
391
391
  myokit/tests/data/multi/lr-1991.mmt,sha256=9jzHRAy1nLiBOPioiEpXmsRvIqwEezRY_ve2eHMDbTQ,6013
392
392
  myokit/tests/data/multi/not-a-model.csv,sha256=7ek3pQXr2fpjNjFTs-B-T_kEehx8IQ-evdcg24dtMEs,109
393
393
  myokit/tests/data/multi/subdir/beeler-no-name.mmt,sha256=tBeWcTVag1gAQAvxWlUqH6GQhF1D4DMnlmuePQn1vBY,3008
394
- myokit-1.36.0.dist-info/LICENSE.txt,sha256=19_GtuJ-mvPSB1zH9rF_uKVK-bs5bEXFc7PISIRF1KI,1833
395
- myokit-1.36.0.dist-info/METADATA,sha256=biNDDX8Nml4PH94SP_ocYhcwVn4cN6gFj6iWMCknl5Y,6279
396
- myokit-1.36.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
397
- myokit-1.36.0.dist-info/entry_points.txt,sha256=yP9wy3w0YAAYUD5PYGliYKhnKvEp5l6p4S_XvXsqreM,48
398
- myokit-1.36.0.dist-info/top_level.txt,sha256=vopnhGEticqud7tKy6L6dvi_n_AMXoiYBEiboRTnsWY,7
399
- myokit-1.36.0.dist-info/RECORD,,
394
+ myokit-1.36.1.dist-info/LICENSE.txt,sha256=19_GtuJ-mvPSB1zH9rF_uKVK-bs5bEXFc7PISIRF1KI,1833
395
+ myokit-1.36.1.dist-info/METADATA,sha256=bCxAeMCjxz2LrlwPK6TPNKOUBXlZhfr_Jtqfn_GMBOA,6279
396
+ myokit-1.36.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
397
+ myokit-1.36.1.dist-info/entry_points.txt,sha256=yP9wy3w0YAAYUD5PYGliYKhnKvEp5l6p4S_XvXsqreM,48
398
+ myokit-1.36.1.dist-info/top_level.txt,sha256=vopnhGEticqud7tKy6L6dvi_n_AMXoiYBEiboRTnsWY,7
399
+ myokit-1.36.1.dist-info/RECORD,,