myokit 1.33.9__py3-none-any.whl → 1.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- myokit/__init__.py +9 -36
- myokit/__main__.py +76 -142
- myokit/_aux.py +62 -16
- myokit/_bin/example.mmt +1 -2
- myokit/_bin/install-win/menu.json +7 -7
- myokit/_config.py +22 -31
- myokit/_datablock.py +30 -74
- myokit/_datalog.py +49 -72
- myokit/_err.py +25 -24
- myokit/_expressions.py +50 -68
- myokit/_io.py +15 -27
- myokit/_model_api.py +453 -249
- myokit/_myokit_version.py +1 -5
- myokit/_parsing.py +38 -44
- myokit/_progress.py +5 -8
- myokit/_protocol.py +99 -9
- myokit/_sim/__init__.py +7 -24
- myokit/_sim/cable.c +6 -8
- myokit/_sim/cable.py +6 -8
- myokit/_sim/cmodel.h +125 -70
- myokit/_sim/cmodel.py +12 -14
- myokit/_sim/compiler.py +1 -4
- myokit/_sim/cvodessim.c +196 -118
- myokit/_sim/cvodessim.py +130 -103
- myokit/_sim/differential.hpp +4 -4
- myokit/_sim/fiber_tissue.c +4 -8
- myokit/_sim/fiber_tissue.py +11 -13
- myokit/_sim/jacobian.cpp +2 -2
- myokit/_sim/jacobian.py +11 -8
- myokit/_sim/mcl.h +53 -55
- myokit/_sim/opencl.py +21 -27
- myokit/_sim/openclsim.c +3 -7
- myokit/_sim/openclsim.cl +3 -3
- myokit/_sim/openclsim.py +49 -40
- myokit/_sim/pacing.h +36 -16
- myokit/_sim/rhs.c +6 -13
- myokit/_sim/rhs.py +5 -14
- myokit/_sim/sundials.py +1 -4
- myokit/_system.py +10 -16
- myokit/_unit.py +4 -13
- myokit/float.py +0 -3
- myokit/formats/__init__.py +8 -10
- myokit/formats/ansic/__init__.py +0 -3
- myokit/formats/ansic/_ewriter.py +2 -4
- myokit/formats/ansic/_exporter.py +1 -4
- myokit/formats/ansic/template/cable.c +4 -4
- myokit/formats/ansic/template/euler.c +5 -5
- myokit/formats/ansic/template/sim.c +6 -6
- myokit/formats/axon/__init__.py +1 -3
- myokit/formats/axon/_abf.py +12 -17
- myokit/formats/axon/_atf.py +5 -6
- myokit/formats/axon/_importer.py +0 -3
- myokit/formats/cellml/__init__.py +0 -3
- myokit/formats/cellml/_ewriter.py +3 -6
- myokit/formats/cellml/_exporter.py +3 -6
- myokit/formats/cellml/_importer.py +1 -4
- myokit/formats/cellml/v1/__init__.py +0 -4
- myokit/formats/cellml/v1/_api.py +8 -11
- myokit/formats/cellml/v1/_parser.py +2 -5
- myokit/formats/cellml/v1/_writer.py +2 -11
- myokit/formats/cellml/v2/__init__.py +0 -3
- myokit/formats/cellml/v2/_api.py +8 -17
- myokit/formats/cellml/v2/_parser.py +2 -5
- myokit/formats/cellml/v2/_writer.py +1 -4
- myokit/formats/channelml/__init__.py +0 -3
- myokit/formats/channelml/_importer.py +11 -21
- myokit/formats/cpp/__init__.py +1 -3
- myokit/formats/cpp/_ewriter.py +0 -3
- myokit/formats/cuda/__init__.py +0 -3
- myokit/formats/cuda/_ewriter.py +2 -4
- myokit/formats/cuda/_exporter.py +0 -3
- myokit/formats/cuda/template/kernel.cu +8 -5
- myokit/formats/easyml/__init__.py +0 -3
- myokit/formats/easyml/_ewriter.py +9 -11
- myokit/formats/easyml/_exporter.py +2 -5
- myokit/formats/html/__init__.py +0 -3
- myokit/formats/html/_exporter.py +0 -3
- myokit/formats/html/_flatten.py +5 -21
- myokit/formats/latex/__init__.py +0 -3
- myokit/formats/latex/_ewriter.py +1 -4
- myokit/formats/latex/_exporter.py +4 -6
- myokit/formats/mathml/__init__.py +0 -3
- myokit/formats/mathml/_ewriter.py +2 -11
- myokit/formats/mathml/_parser.py +4 -6
- myokit/formats/matlab/__init__.py +0 -3
- myokit/formats/matlab/_ewriter.py +1 -4
- myokit/formats/matlab/_exporter.py +2 -5
- myokit/formats/matlab/template/main.m +3 -2
- myokit/formats/opencl/__init__.py +0 -3
- myokit/formats/opencl/_ewriter.py +2 -4
- myokit/formats/opencl/_exporter.py +2 -5
- myokit/formats/opencl/template/cable.c +10 -10
- myokit/formats/opencl/template/kernel.cl +1 -1
- myokit/formats/opencl/template/minilog.py +1 -1
- myokit/formats/python/__init__.py +0 -3
- myokit/formats/python/_ewriter.py +2 -5
- myokit/formats/python/_exporter.py +0 -3
- myokit/formats/python/template/sim.py +14 -14
- myokit/formats/sbml/__init__.py +0 -3
- myokit/formats/sbml/_api.py +50 -44
- myokit/formats/sbml/_importer.py +1 -4
- myokit/formats/sbml/_parser.py +2 -5
- myokit/formats/stan/__init__.py +0 -3
- myokit/formats/stan/_ewriter.py +2 -4
- myokit/formats/stan/_exporter.py +2 -5
- myokit/formats/stan/template/cell.stan +3 -3
- myokit/formats/sympy/__init__.py +0 -3
- myokit/formats/sympy/_ereader.py +1 -4
- myokit/formats/sympy/_ewriter.py +2 -5
- myokit/formats/wcp/__init__.py +0 -3
- myokit/formats/wcp/_wcp.py +2 -8
- myokit/formats/xml/__init__.py +0 -3
- myokit/formats/xml/_exporter.py +0 -3
- myokit/formats/xml/_split.py +0 -3
- myokit/gui/__init__.py +80 -246
- myokit/gui/datablock_viewer.py +103 -86
- myokit/gui/datalog_viewer.py +214 -66
- myokit/gui/explorer.py +15 -21
- myokit/gui/ide.py +171 -144
- myokit/gui/progress.py +9 -9
- myokit/gui/source.py +406 -375
- myokit/gui/vargrapher.py +2 -12
- myokit/lib/deps.py +12 -13
- myokit/lib/guess.py +3 -4
- myokit/lib/hh.py +20 -18
- myokit/lib/markov.py +21 -20
- myokit/lib/multi.py +1 -3
- myokit/lib/plots.py +20 -9
- myokit/pacing.py +0 -3
- myokit/pype.py +7 -18
- myokit/tests/__init__.py +3 -6
- myokit/tests/ansic_event_based_pacing.py +1 -4
- myokit/tests/ansic_fixed_form_pacing.py +3 -6
- myokit/tests/data/beeler-1977-model-compare-b.mmt +2 -2
- myokit/tests/data/clancy-1999-fitting.mmt +1 -0
- myokit/tests/test_aux.py +13 -28
- myokit/tests/test_cellml_v1_api.py +4 -19
- myokit/tests/test_cellml_v1_parser.py +0 -15
- myokit/tests/test_cellml_v1_writer.py +0 -9
- myokit/tests/test_cellml_v2_api.py +4 -19
- myokit/tests/test_cellml_v2_parser.py +0 -15
- myokit/tests/test_cellml_v2_writer.py +0 -9
- myokit/tests/test_cmodel.py +16 -22
- myokit/tests/test_compiler_detection.py +1 -11
- myokit/tests/test_component.py +108 -56
- myokit/tests/test_config.py +34 -67
- myokit/tests/test_datablock.py +1 -9
- myokit/tests/test_datalog.py +19 -24
- myokit/tests/test_dependency_checking.py +8 -23
- myokit/tests/test_expressions.py +0 -9
- myokit/tests/test_float.py +1 -5
- myokit/tests/test_formats.py +0 -9
- myokit/tests/test_formats_axon.py +1 -9
- myokit/tests/test_formats_cellml.py +0 -15
- myokit/tests/test_formats_channelml.py +0 -15
- myokit/tests/test_formats_easyml.py +0 -14
- myokit/tests/test_formats_exporters.py +1 -16
- myokit/tests/test_formats_expression_writers.py +1 -17
- myokit/tests/test_formats_html.py +0 -3
- myokit/tests/test_formats_importers.py +1 -16
- myokit/tests/test_formats_mathml_content.py +0 -9
- myokit/tests/test_formats_mathml_presentation.py +0 -9
- myokit/tests/test_formats_opencl.py +0 -10
- myokit/tests/test_formats_sbml.py +0 -15
- myokit/tests/test_formats_sympy.py +0 -9
- myokit/tests/test_formats_wcp.py +1 -3
- myokit/tests/test_io.py +27 -27
- myokit/tests/test_jacobian_calculator.py +6 -14
- myokit/tests/test_jacobian_tracer.py +0 -9
- myokit/tests/test_lib_deps.py +0 -9
- myokit/tests/test_lib_guess.py +0 -9
- myokit/tests/test_lib_hh.py +18 -12
- myokit/tests/test_lib_markov.py +21 -13
- myokit/tests/test_lib_multi.py +0 -9
- myokit/tests/test_lib_plots.py +13 -8
- myokit/tests/test_meta.py +0 -3
- myokit/tests/test_model.py +390 -96
- myokit/tests/test_model_building.py +44 -96
- myokit/tests/test_opencl_info.py +5 -14
- myokit/tests/test_pacing_factory.py +0 -3
- myokit/tests/test_pacing_system_c.py +1 -23
- myokit/tests/test_pacing_system_py.py +0 -9
- myokit/tests/test_parsing.py +139 -56
- myokit/tests/test_progress_reporters.py +0 -3
- myokit/tests/test_protocol.py +0 -9
- myokit/tests/test_protocol_floating_point.py +1 -10
- myokit/tests/test_protocol_time_series.py +82 -0
- myokit/tests/test_pype.py +0 -9
- myokit/tests/test_quantity.py +0 -9
- myokit/tests/test_rhs_benchmarker.py +1 -9
- myokit/tests/test_sbml_api.py +27 -42
- myokit/tests/test_sbml_parser.py +4 -19
- myokit/tests/test_simulation_1d.py +45 -25
- myokit/tests/test_simulation_cvodes.py +321 -55
- myokit/tests/test_simulation_cvodes_from_disk.py +0 -3
- myokit/tests/test_simulation_fiber_tissue.py +39 -12
- myokit/tests/test_simulation_log_interval.py +1 -431
- myokit/tests/test_simulation_opencl.py +69 -48
- myokit/tests/test_simulation_opencl_log_interval.py +1 -3
- myokit/tests/test_simulation_opencl_vs_cvode.py +1 -10
- myokit/tests/test_simulation_opencl_vs_sim1d.py +1 -10
- myokit/tests/test_system_info.py +1 -11
- myokit/tests/test_tools.py +0 -9
- myokit/tests/test_unit.py +1 -10
- myokit/tests/test_user_functions.py +0 -10
- myokit/tests/test_variable.py +231 -27
- myokit/tools.py +5 -21
- myokit/units.py +5 -3
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/METADATA +12 -15
- myokit-1.35.0.dist-info/RECORD +391 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/WHEEL +1 -1
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/entry_points.txt +0 -1
- myokit/_exec_new.py +0 -15
- myokit/_exec_old.py +0 -15
- myokit/_sim/cvodesim.c +0 -1551
- myokit/_sim/cvodesim.py +0 -674
- myokit/_sim/icsim.cpp +0 -563
- myokit/_sim/icsim.py +0 -363
- myokit/_sim/psim.cpp +0 -656
- myokit/_sim/psim.py +0 -493
- myokit/lib/common.py +0 -1094
- myokit/tests/test_lib_common.py +0 -130
- myokit/tests/test_simulation_cvode.py +0 -612
- myokit/tests/test_simulation_ic.py +0 -108
- myokit/tests/test_simulation_p.py +0 -223
- myokit-1.33.9.dist-info/RECORD +0 -403
- /myokit/formats/opencl/template/{test → test.sh} +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/LICENSE.txt +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/top_level.txt +0 -0
myokit/_sim/cvodessim.c
CHANGED
|
@@ -173,11 +173,8 @@ void
|
|
|
173
173
|
ErrorHandler(int error_code, const char *module, const char *function,
|
|
174
174
|
char *msg, void *eh_data)
|
|
175
175
|
{
|
|
176
|
-
char errstr[1024];
|
|
177
176
|
if (error_code > 0) {
|
|
178
|
-
|
|
179
|
-
PyErr_WarnEx(PyExc_RuntimeWarning, errstr, 1);
|
|
180
|
-
/* Python 3.2+: PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "CVODES: %s", msg); */
|
|
177
|
+
PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "CVODES: %s", msg);
|
|
181
178
|
}
|
|
182
179
|
}
|
|
183
180
|
|
|
@@ -185,7 +182,7 @@ ErrorHandler(int error_code, const char *module, const char *function,
|
|
|
185
182
|
* Initialisation status.
|
|
186
183
|
* Proper sequence is init(), repeated step() calls till finished, then clean.
|
|
187
184
|
*/
|
|
188
|
-
int
|
|
185
|
+
int initialized = 0; /* Has the simulation been initialized */
|
|
189
186
|
|
|
190
187
|
/*
|
|
191
188
|
* Model
|
|
@@ -195,11 +192,19 @@ Model model; /* A model object */
|
|
|
195
192
|
/*
|
|
196
193
|
* Pacing
|
|
197
194
|
*/
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
FSys
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
union PSys {
|
|
196
|
+
ESys event;
|
|
197
|
+
FSys fixed;
|
|
198
|
+
};
|
|
199
|
+
enum PSysType {
|
|
200
|
+
EVENT,
|
|
201
|
+
FIXED
|
|
202
|
+
};
|
|
203
|
+
union PSys *pacing_systems; /* Array of pacing system (event or fixed) */
|
|
204
|
+
enum PSysType *pacing_types; /* Array of pacing system types */
|
|
205
|
+
PyObject *protocols; /* The protocols used to generate the pacing systems */
|
|
206
|
+
double* pacing; /* Pacing values, same size as pacing_systems and pacing_types */
|
|
207
|
+
int n_pace; /* The number of pacing systems */
|
|
203
208
|
|
|
204
209
|
/*
|
|
205
210
|
* CVODE Memory
|
|
@@ -289,7 +294,7 @@ PyObject* log_times; /* The point list (or None if disabled) */
|
|
|
289
294
|
/*
|
|
290
295
|
* Root finding
|
|
291
296
|
*/
|
|
292
|
-
int
|
|
297
|
+
int rf_index; /* Index of state variable to use in root finding (ignored if not enabled) */
|
|
293
298
|
double rf_threshold; /* Threshold to use for root finding (ignored if not enabled) */
|
|
294
299
|
PyObject* rf_list; /* List to store found roots in (or None if not enabled) */
|
|
295
300
|
int* rf_direction; /* Direction of root crossings: 1 for up, -1 for down, 0 for no crossing. */
|
|
@@ -306,7 +311,7 @@ double realtime_start; /* time when sim run started */
|
|
|
306
311
|
* Returns the current time as given by the benchmarker.
|
|
307
312
|
*/
|
|
308
313
|
double
|
|
309
|
-
benchmarker_realtime()
|
|
314
|
+
benchmarker_realtime(void)
|
|
310
315
|
{
|
|
311
316
|
double val;
|
|
312
317
|
PyObject* ret = PyObject_CallMethodObjArgs(benchmarker, benchmarker_time_str, NULL);
|
|
@@ -350,12 +355,14 @@ rhs(realtype t, N_Vector y, N_Vector ydot, void *user_data)
|
|
|
350
355
|
UserData fdata;
|
|
351
356
|
int i;
|
|
352
357
|
|
|
353
|
-
/* Fixed-form pacing? Then look-up correct value of pacing variable
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
358
|
+
/* Fixed-form pacing? Then look-up correct value of pacing variable */
|
|
359
|
+
for (int i = 0; i < n_pace; i++) {
|
|
360
|
+
if (pacing_types[i] == FIXED) {
|
|
361
|
+
pacing[i] = FSys_GetLevel(pacing_systems[i].fixed, t, &flag_fpacing);
|
|
362
|
+
if (flag_fpacing != FSys_OK) { /* This should never happen */
|
|
363
|
+
FSys_SetPyErr(flag_fpacing);
|
|
364
|
+
return -1; /* Negative value signals irrecoverable error to CVODE */
|
|
365
|
+
}
|
|
359
366
|
}
|
|
360
367
|
}
|
|
361
368
|
|
|
@@ -363,7 +370,7 @@ rhs(realtype t, N_Vector y, N_Vector ydot, void *user_data)
|
|
|
363
370
|
|
|
364
371
|
/* Set time, pace, evaluations and realtime */
|
|
365
372
|
evaluations++;
|
|
366
|
-
Model_SetBoundVariables(model, t,
|
|
373
|
+
Model_SetBoundVariables(model, (realtype)t, (realtype*)pacing, (realtype)realtime, (realtype)evaluations);
|
|
367
374
|
|
|
368
375
|
/* Set sensitivity parameters */
|
|
369
376
|
if (model->has_sensitivities) {
|
|
@@ -416,7 +423,7 @@ shs(N_Vector* sy)
|
|
|
416
423
|
int
|
|
417
424
|
rf_function(realtype t, N_Vector y, realtype *gout, void *user_data)
|
|
418
425
|
{
|
|
419
|
-
gout[0] = NV_Ith_S(y,
|
|
426
|
+
gout[0] = NV_Ith_S(y, rf_index) - rf_threshold;
|
|
420
427
|
return 0;
|
|
421
428
|
}
|
|
422
429
|
|
|
@@ -424,9 +431,9 @@ rf_function(realtype t, N_Vector y, realtype *gout, void *user_data)
|
|
|
424
431
|
* Cleans up after a simulation
|
|
425
432
|
*/
|
|
426
433
|
PyObject*
|
|
427
|
-
sim_clean()
|
|
434
|
+
sim_clean(void)
|
|
428
435
|
{
|
|
429
|
-
if (
|
|
436
|
+
if (initialized) {
|
|
430
437
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
431
438
|
benchmarker_print("CP Entered sim_clean.");
|
|
432
439
|
#elif defined MYOKIT_DEBUG_MESSAGES
|
|
@@ -463,8 +470,16 @@ sim_clean()
|
|
|
463
470
|
}
|
|
464
471
|
|
|
465
472
|
/* Pacing systems */
|
|
466
|
-
|
|
467
|
-
|
|
473
|
+
for (int i = 0; i < n_pace; i++) {
|
|
474
|
+
if (pacing_types[i] == FIXED) {
|
|
475
|
+
FSys_Destroy(pacing_systems[i].fixed);
|
|
476
|
+
} else if (pacing_types[i] == EVENT) {
|
|
477
|
+
ESys_Destroy(pacing_systems[i].event);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
free(pacing_systems); pacing_systems = NULL;
|
|
481
|
+
free(pacing_types); pacing_types = NULL;
|
|
482
|
+
free(pacing); pacing = NULL;
|
|
468
483
|
|
|
469
484
|
/* CModel */
|
|
470
485
|
Model_Destroy(model); model = NULL;
|
|
@@ -477,7 +492,7 @@ sim_clean()
|
|
|
477
492
|
Py_XDECREF(benchmarker_time_str); benchmarker_time_str = NULL;
|
|
478
493
|
|
|
479
494
|
/* Deinitialisation complete */
|
|
480
|
-
|
|
495
|
+
initialized = 0;
|
|
481
496
|
}
|
|
482
497
|
|
|
483
498
|
/* Return 0, allowing the construct
|
|
@@ -515,7 +530,7 @@ py_sim_clean(PyObject *self, PyObject *args)
|
|
|
515
530
|
}
|
|
516
531
|
|
|
517
532
|
/*
|
|
518
|
-
*
|
|
533
|
+
* Initialize a run.
|
|
519
534
|
* Called by the Python code's run(), followed by several calls to sim_step().
|
|
520
535
|
*/
|
|
521
536
|
PyObject*
|
|
@@ -531,20 +546,27 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
531
546
|
ESys_Flag flag_epacing;
|
|
532
547
|
FSys_Flag flag_fpacing;
|
|
533
548
|
|
|
549
|
+
/* Pacing systems */
|
|
550
|
+
ESys epacing;
|
|
551
|
+
FSys fpacing;
|
|
552
|
+
|
|
534
553
|
/* General purpose ints for iterating */
|
|
535
554
|
int i, j;
|
|
536
555
|
|
|
537
556
|
/* Log the first point? Only happens if not continuing from a log */
|
|
538
557
|
int log_first_point;
|
|
539
558
|
|
|
559
|
+
/* Proposed next logging or pacing point */
|
|
560
|
+
double t_proposed;
|
|
561
|
+
|
|
540
562
|
/* Python objects, and a python list index variable */
|
|
541
563
|
Py_ssize_t pos;
|
|
542
564
|
PyObject *val;
|
|
543
565
|
PyObject *ret;
|
|
544
566
|
|
|
545
|
-
/* Check if already
|
|
546
|
-
if (
|
|
547
|
-
PyErr_SetString(PyExc_Exception, "Simulation already
|
|
567
|
+
/* Check if already initialized */
|
|
568
|
+
if (initialized) {
|
|
569
|
+
PyErr_SetString(PyExc_Exception, "Simulation already initialized.");
|
|
548
570
|
return 0;
|
|
549
571
|
}
|
|
550
572
|
|
|
@@ -557,8 +579,9 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
557
579
|
/* Set all global pointers to null */
|
|
558
580
|
/* Model and pacing */
|
|
559
581
|
model = NULL;
|
|
560
|
-
|
|
561
|
-
|
|
582
|
+
pacing_types = NULL;
|
|
583
|
+
pacing_systems = NULL;
|
|
584
|
+
pacing = NULL;
|
|
562
585
|
/* User data and parameter scaling */
|
|
563
586
|
udata = NULL;
|
|
564
587
|
pbar = NULL;
|
|
@@ -586,8 +609,8 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
586
609
|
sundials_context = NULL;
|
|
587
610
|
#endif
|
|
588
611
|
|
|
589
|
-
/* Check input arguments
|
|
590
|
-
if (!PyArg_ParseTuple(args, "
|
|
612
|
+
/* Check input arguments 01234567890123456 */
|
|
613
|
+
if (!PyArg_ParseTuple(args, "ddOOOOOOOdOOidOOi",
|
|
591
614
|
&tmin, /* 0. Float: initial time */
|
|
592
615
|
&tmax, /* 1. Float: final time */
|
|
593
616
|
&state_py, /* 2. List: initial and final state */
|
|
@@ -595,24 +618,23 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
595
618
|
&bound_py, /* 4. List: store final bound variables here */
|
|
596
619
|
&literals, /* 5. List: literal constant values */
|
|
597
620
|
¶meters, /* 6. List: parameter values */
|
|
598
|
-
&
|
|
599
|
-
&
|
|
600
|
-
&
|
|
601
|
-
&
|
|
602
|
-
&
|
|
603
|
-
&
|
|
604
|
-
&
|
|
605
|
-
&
|
|
606
|
-
&
|
|
607
|
-
&
|
|
608
|
-
&log_realtime /* 17. Int: 1 if logging real time */
|
|
621
|
+
&protocols, /* 7. Event-based or fixed protocols */
|
|
622
|
+
&log_dict, /* 8. DataLog */
|
|
623
|
+
&log_interval, /* 9. Float: log interval, or 0 */
|
|
624
|
+
&log_times, /* 10. List of logging times, or None */
|
|
625
|
+
&sens_list, /* 11. List to store sensitivities in */
|
|
626
|
+
&rf_index, /* 12. Int: root-finding state variable */
|
|
627
|
+
&rf_threshold, /* 13. Float: root-finding threshold */
|
|
628
|
+
&rf_list, /* 14. List to store roots in or None */
|
|
629
|
+
&benchmarker, /* 15. myokit.tools.Benchmarker object */
|
|
630
|
+
&log_realtime /* 16. Int: 1 if logging real time */
|
|
609
631
|
)) {
|
|
610
632
|
PyErr_SetString(PyExc_Exception, "Incorrect input arguments.");
|
|
611
633
|
return 0;
|
|
612
634
|
}
|
|
613
635
|
|
|
614
|
-
/* Now officialy
|
|
615
|
-
|
|
636
|
+
/* Now officialy initialized */
|
|
637
|
+
initialized = 1;
|
|
616
638
|
|
|
617
639
|
/*************************************************************************
|
|
618
640
|
From this point on, no more direct returning! Use sim_clean()
|
|
@@ -899,7 +921,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
899
921
|
if (udata == 0) {
|
|
900
922
|
return sim_cleanx(PyExc_Exception, "Unable to create user data object to store parameter values.");
|
|
901
923
|
}
|
|
902
|
-
udata->p = (realtype*)malloc(
|
|
924
|
+
udata->p = (realtype*)malloc((size_t)model->ns_independents * sizeof(realtype));
|
|
903
925
|
if (udata->p == 0) {
|
|
904
926
|
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store parameter values.");
|
|
905
927
|
}
|
|
@@ -915,7 +937,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
915
937
|
|
|
916
938
|
/* Create parameter scaling vector, for error control */
|
|
917
939
|
/* TODO: Get this from the Python code ? */
|
|
918
|
-
pbar = (realtype*)malloc(
|
|
940
|
+
pbar = (realtype*)malloc((size_t)model->ns_independents * sizeof(realtype));
|
|
919
941
|
if (pbar == NULL) {
|
|
920
942
|
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store parameter scales.");
|
|
921
943
|
}
|
|
@@ -929,48 +951,74 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
929
951
|
}
|
|
930
952
|
|
|
931
953
|
/*
|
|
932
|
-
* Set up pacing
|
|
954
|
+
* Set up pacing systems
|
|
933
955
|
*/
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
956
|
+
n_pace = 0;
|
|
957
|
+
if (protocols != Py_None) {
|
|
958
|
+
if (!PyList_Check(protocols)) {
|
|
959
|
+
return sim_cleanx(PyExc_TypeError, "'protocols' must be a list.");
|
|
960
|
+
}
|
|
961
|
+
n_pace = (int)PyList_Size(protocols);
|
|
962
|
+
}
|
|
963
|
+
pacing_systems = (union PSys*)malloc((size_t)n_pace * sizeof(union PSys));
|
|
964
|
+
if (pacing_systems == NULL) {
|
|
965
|
+
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing systems.");
|
|
966
|
+
}
|
|
967
|
+
pacing_types = (enum PSysType *)malloc((size_t)n_pace * sizeof(enum PSysType));
|
|
968
|
+
if (pacing_types == NULL) {
|
|
969
|
+
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing types.");
|
|
970
|
+
}
|
|
971
|
+
pacing = (realtype*)malloc((size_t)n_pace * sizeof(realtype));
|
|
972
|
+
if (pacing == NULL) {
|
|
973
|
+
return sim_cleanx(PyExc_Exception, "Unable to allocate space to store pacing values.");
|
|
952
974
|
}
|
|
975
|
+
Model_SetupPacing(model, n_pace);
|
|
953
976
|
|
|
954
|
-
/*
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
return sim_cleanx(PyExc_TypeError, "Fixed-form pacing protocol should be tuple or None.");
|
|
959
|
-
}
|
|
960
|
-
if (PyTuple_Size(fprotocol) != 2) {
|
|
961
|
-
return sim_cleanx(PyExc_ValueError, "Fixed-form pacing protocol tuple should have size 2.");
|
|
962
|
-
}
|
|
963
|
-
/* Create fixed-form pacing object and populate */
|
|
964
|
-
fpacing = FSys_Create(&flag_fpacing);
|
|
965
|
-
if (flag_fpacing != FSys_OK) { FSys_SetPyErr(flag_fpacing); return sim_clean(); }
|
|
966
|
-
flag_fpacing = FSys_Populate(fpacing,
|
|
967
|
-
PyTuple_GetItem(fprotocol, 0), /* Borrowed, no decref */
|
|
968
|
-
PyTuple_GetItem(fprotocol, 1));
|
|
969
|
-
if (flag_fpacing != FSys_OK) { FSys_SetPyErr(flag_fpacing); return sim_clean(); }
|
|
977
|
+
/*
|
|
978
|
+
* Unless set by pacing, tnext is set to tmax
|
|
979
|
+
*/
|
|
980
|
+
tnext = tmax;
|
|
970
981
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
982
|
+
/*
|
|
983
|
+
* Set up event-based and/or fixed pacing.
|
|
984
|
+
*/
|
|
985
|
+
if (protocols != Py_None) {
|
|
986
|
+
for (int i = 0; i < PyList_Size(protocols); i++) {
|
|
987
|
+
PyObject *protocol = PyList_GetItem(protocols, i);
|
|
988
|
+
const char* protocol_type_name = Py_TYPE(protocol)->tp_name;
|
|
989
|
+
if (strcmp(protocol_type_name, "Protocol") == 0) {
|
|
990
|
+
pacing_systems[i].event = ESys_Create(&flag_epacing);
|
|
991
|
+
pacing_types[i] = EVENT;
|
|
992
|
+
epacing = pacing_systems[i].event;
|
|
993
|
+
if (flag_epacing != ESys_OK) { ESys_SetPyErr(flag_epacing); return sim_clean(); }
|
|
994
|
+
flag_epacing = ESys_Populate(epacing, protocol);
|
|
995
|
+
if (flag_epacing != ESys_OK) { ESys_SetPyErr(flag_epacing); return sim_clean(); }
|
|
996
|
+
flag_epacing = ESys_AdvanceTime(epacing, tmin);
|
|
997
|
+
if (flag_epacing != ESys_OK) { ESys_SetPyErr(flag_epacing); return sim_clean(); }
|
|
998
|
+
t_proposed = ESys_GetNextTime(epacing, &flag_epacing);
|
|
999
|
+
pacing[i] = ESys_GetLevel(epacing, &flag_epacing);
|
|
1000
|
+
tnext = fmin(t_proposed, tnext);
|
|
1001
|
+
|
|
1002
|
+
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1003
|
+
benchmarker_print("CP Created event-based pacing system.");
|
|
1004
|
+
#endif
|
|
1005
|
+
} else if (strcmp(protocol_type_name, "TimeSeriesProtocol") == 0) {
|
|
1006
|
+
pacing_systems[i].fixed = FSys_Create(&flag_fpacing);
|
|
1007
|
+
pacing_types[i] = FIXED;
|
|
1008
|
+
fpacing = pacing_systems[i].fixed;
|
|
1009
|
+
if (flag_fpacing != FSys_OK) { FSys_SetPyErr(flag_fpacing); return sim_clean(); }
|
|
1010
|
+
flag_fpacing = FSys_Populate(fpacing, protocol);
|
|
1011
|
+
if (flag_fpacing != FSys_OK) { FSys_SetPyErr(flag_fpacing); return sim_clean(); }
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1015
|
+
benchmarker_print("CP Created fixed-form pacing system.");
|
|
1016
|
+
#endif
|
|
1017
|
+
} else {
|
|
1018
|
+
printf("protocol_type_name: %s", protocol_type_name);
|
|
1019
|
+
return sim_cleanx(PyExc_TypeError, "Item %d in 'protocols' is not a myokit.Protocol or myokit.TimeSeriesProtocol object.", i);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
974
1022
|
}
|
|
975
1023
|
|
|
976
1024
|
/*
|
|
@@ -992,7 +1040,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
992
1040
|
flag_cvode = CVodeSetErrHandlerFn(cvode_mem, ErrorHandler, NULL);
|
|
993
1041
|
if (check_cvode_flag(&flag_cvode, "CVodeInit", 1)) return sim_clean();
|
|
994
1042
|
|
|
995
|
-
/*
|
|
1043
|
+
/* Initialize solver memory, specify the rhs */
|
|
996
1044
|
flag_cvode = CVodeInit(cvode_mem, rhs, t, y);
|
|
997
1045
|
if (check_cvode_flag(&flag_cvode, "CVodeInit", 1)) return sim_clean();
|
|
998
1046
|
|
|
@@ -1051,7 +1099,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1051
1099
|
#endif
|
|
1052
1100
|
|
|
1053
1101
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1054
|
-
benchmarker_print("CP CVODES solver
|
|
1102
|
+
benchmarker_print("CP CVODES solver initialized.");
|
|
1055
1103
|
#endif
|
|
1056
1104
|
|
|
1057
1105
|
/* Activate forward sensitivity computations */
|
|
@@ -1075,7 +1123,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1075
1123
|
if (check_cvode_flag(&flag_cvode, "CVodeSensEEtolerances", 1)) return sim_clean();
|
|
1076
1124
|
|
|
1077
1125
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1078
|
-
benchmarker_print("CP CVODES sensitivity methods
|
|
1126
|
+
benchmarker_print("CP CVODES sensitivity methods initialized.");
|
|
1079
1127
|
#endif
|
|
1080
1128
|
}
|
|
1081
1129
|
}
|
|
@@ -1092,10 +1140,10 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1092
1140
|
if (check_cvode_flag(&flag_cvode, "CVodeRootInit", 1)) return sim_clean();
|
|
1093
1141
|
|
|
1094
1142
|
/* Direction of root crossings, one entry per root function, but we only use 1. */
|
|
1095
|
-
rf_direction = (int*)malloc(sizeof(int)
|
|
1143
|
+
rf_direction = (int*)malloc(sizeof(int));
|
|
1096
1144
|
|
|
1097
1145
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1098
|
-
benchmarker_print("CP CVODES root-finding
|
|
1146
|
+
benchmarker_print("CP CVODES root-finding initialized.");
|
|
1099
1147
|
#endif
|
|
1100
1148
|
}
|
|
1101
1149
|
|
|
@@ -1111,10 +1159,10 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1111
1159
|
}
|
|
1112
1160
|
|
|
1113
1161
|
/* Set up logging */
|
|
1114
|
-
flag_model =
|
|
1162
|
+
flag_model = Model_InitializeLogging(model, log_dict);
|
|
1115
1163
|
if (flag_model != Model_OK) { Model_SetPyErr(flag_model); return sim_clean(); }
|
|
1116
1164
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1117
|
-
benchmarker_print("CP Logging
|
|
1165
|
+
benchmarker_print("CP Logging initialized.");
|
|
1118
1166
|
#endif
|
|
1119
1167
|
|
|
1120
1168
|
/* Check logging list for sensitivities */
|
|
@@ -1211,7 +1259,7 @@ sim_init(PyObject *self, PyObject *args)
|
|
|
1211
1259
|
}
|
|
1212
1260
|
|
|
1213
1261
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1214
|
-
benchmarker_print("CP Logging times and strategy
|
|
1262
|
+
benchmarker_print("CP Logging times and strategy initialized.");
|
|
1215
1263
|
#endif
|
|
1216
1264
|
|
|
1217
1265
|
/*
|
|
@@ -1242,8 +1290,8 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1242
1290
|
/* Number of integration steps taken in this call */
|
|
1243
1291
|
int steps_taken = 0;
|
|
1244
1292
|
|
|
1245
|
-
/* Proposed next logging point */
|
|
1246
|
-
double
|
|
1293
|
+
/* Proposed next logging or pacing point */
|
|
1294
|
+
double t_proposed;
|
|
1247
1295
|
|
|
1248
1296
|
/* Multi-purpose Python objects */
|
|
1249
1297
|
PyObject *val;
|
|
@@ -1288,9 +1336,11 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1288
1336
|
/* PyList_SetItem steals a reference: no need to decref the double! */
|
|
1289
1337
|
}
|
|
1290
1338
|
PyList_SetItem(bound_py, 0, PyFloat_FromDouble(tlast));
|
|
1291
|
-
PyList_SetItem(bound_py, 1, PyFloat_FromDouble(
|
|
1292
|
-
PyList_SetItem(bound_py, 2, PyFloat_FromDouble(
|
|
1293
|
-
|
|
1339
|
+
PyList_SetItem(bound_py, 1, PyFloat_FromDouble(realtime));
|
|
1340
|
+
PyList_SetItem(bound_py, 2, PyFloat_FromDouble((double)evaluations));
|
|
1341
|
+
for (int i = 0; i < n_pace; i++) {
|
|
1342
|
+
PyList_SetItem(bound_py, 3 + i, PyFloat_FromDouble(pacing[i]));
|
|
1343
|
+
}
|
|
1294
1344
|
return sim_clean();
|
|
1295
1345
|
}
|
|
1296
1346
|
|
|
@@ -1435,7 +1485,7 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1435
1485
|
if (ilog < PySequence_Size(log_times)) {
|
|
1436
1486
|
val = PySequence_GetItem(log_times, ilog); /* New reference */
|
|
1437
1487
|
if (PyFloat_Check(val)) {
|
|
1438
|
-
|
|
1488
|
+
t_proposed = PyFloat_AsDouble(val);
|
|
1439
1489
|
Py_DECREF(val);
|
|
1440
1490
|
} else if (PyNumber_Check(val)) {
|
|
1441
1491
|
ret = PyNumber_Float(val); /* New reference */
|
|
@@ -1443,17 +1493,17 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1443
1493
|
if (ret == NULL) {
|
|
1444
1494
|
return sim_cleanx(PyExc_ValueError, "Unable to cast entry in 'log_times' to float.");
|
|
1445
1495
|
} else {
|
|
1446
|
-
|
|
1496
|
+
t_proposed = PyFloat_AsDouble(ret);
|
|
1447
1497
|
Py_DECREF(ret);
|
|
1448
1498
|
}
|
|
1449
1499
|
} else {
|
|
1450
1500
|
Py_DECREF(val);
|
|
1451
1501
|
return sim_cleanx(PyExc_ValueError, "Entries in 'log_times' must be floats.");
|
|
1452
1502
|
}
|
|
1453
|
-
if (
|
|
1503
|
+
if (t_proposed < tlog) {
|
|
1454
1504
|
return sim_cleanx(PyExc_ValueError, "Values in log_times must be non-decreasing.");
|
|
1455
1505
|
}
|
|
1456
|
-
tlog =
|
|
1506
|
+
tlog = t_proposed;
|
|
1457
1507
|
ilog++;
|
|
1458
1508
|
val = NULL;
|
|
1459
1509
|
} else {
|
|
@@ -1469,14 +1519,18 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1469
1519
|
* At this point we have logged everything _before_ time t, so it
|
|
1470
1520
|
* is safe to update the pacing mechanism to time t.
|
|
1471
1521
|
*/
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
if (
|
|
1475
|
-
|
|
1522
|
+
tnext = tmax;
|
|
1523
|
+
for (int i = 0; i < n_pace; i++) {
|
|
1524
|
+
if (pacing_types[i] == EVENT) {
|
|
1525
|
+
ESys epacing = pacing_systems[i].event;
|
|
1526
|
+
flag_epacing = ESys_AdvanceTime(epacing, t);
|
|
1527
|
+
if (flag_epacing != ESys_OK) {
|
|
1528
|
+
ESys_SetPyErr(flag_epacing); return sim_clean();
|
|
1529
|
+
}
|
|
1530
|
+
t_proposed = ESys_GetNextTime(epacing, NULL);
|
|
1531
|
+
tnext = fmin(tnext, t_proposed);
|
|
1532
|
+
pacing[i] = ESys_GetLevel(epacing, NULL);
|
|
1476
1533
|
}
|
|
1477
|
-
tnext = ESys_GetNextTime(epacing, NULL);
|
|
1478
|
-
tnext = (tnext < tmax) ? tnext : tmax;
|
|
1479
|
-
pace = ESys_GetLevel(epacing, NULL);
|
|
1480
1534
|
}
|
|
1481
1535
|
|
|
1482
1536
|
/* Dynamic logging: Log every visited point */
|
|
@@ -1500,7 +1554,7 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1500
1554
|
} else if (model->logging_bound) {
|
|
1501
1555
|
/* Logging bounds but not derivs or inters: No need to run
|
|
1502
1556
|
full rhs, just update bound variables */
|
|
1503
|
-
Model_SetBoundVariables(model, t,
|
|
1557
|
+
Model_SetBoundVariables(model, (realtype)t, (realtype*)pacing, (realtype)realtime, (realtype)evaluations);
|
|
1504
1558
|
}
|
|
1505
1559
|
|
|
1506
1560
|
/* Write to log */
|
|
@@ -1584,9 +1638,11 @@ sim_step(PyObject *self, PyObject *args)
|
|
|
1584
1638
|
|
|
1585
1639
|
/* Set bound variable values */
|
|
1586
1640
|
PyList_SetItem(bound_py, 0, PyFloat_FromDouble(t));
|
|
1587
|
-
PyList_SetItem(bound_py, 1, PyFloat_FromDouble(
|
|
1588
|
-
PyList_SetItem(bound_py, 2, PyFloat_FromDouble(
|
|
1589
|
-
|
|
1641
|
+
PyList_SetItem(bound_py, 1, PyFloat_FromDouble(realtime));
|
|
1642
|
+
PyList_SetItem(bound_py, 2, PyFloat_FromDouble((double)evaluations));
|
|
1643
|
+
for (int i = 0; i < n_pace; i++) {
|
|
1644
|
+
PyList_SetItem(bound_py, 3 + i, PyFloat_FromDouble(pacing[i]));
|
|
1645
|
+
}
|
|
1590
1646
|
|
|
1591
1647
|
#ifdef MYOKIT_DEBUG_PROFILING
|
|
1592
1648
|
benchmarker_print("CP Set final state and bound variable values.");
|
|
@@ -1606,7 +1662,8 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1606
1662
|
int i;
|
|
1607
1663
|
int success;
|
|
1608
1664
|
double time_in;
|
|
1609
|
-
|
|
1665
|
+
PyObject *pace_in;
|
|
1666
|
+
double *pacing_in;
|
|
1610
1667
|
Model model;
|
|
1611
1668
|
Model_Flag flag_model;
|
|
1612
1669
|
PyObject *state;
|
|
@@ -1620,9 +1677,9 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1620
1677
|
|
|
1621
1678
|
/* Check input arguments */
|
|
1622
1679
|
/* Check input arguments 0123456789ABCDEF*/
|
|
1623
|
-
if (!PyArg_ParseTuple(args, "
|
|
1680
|
+
if (!PyArg_ParseTuple(args, "dOOOOO",
|
|
1624
1681
|
&time_in, /* 0. Float: time */
|
|
1625
|
-
&pace_in, /* 1.
|
|
1682
|
+
&pace_in, /* 1. List: pace */
|
|
1626
1683
|
&state, /* 2. List: state */
|
|
1627
1684
|
&deriv, /* 3. List: store derivatives here */
|
|
1628
1685
|
&literals, /* 4. List: literal constant values */
|
|
@@ -1634,6 +1691,10 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1634
1691
|
}
|
|
1635
1692
|
|
|
1636
1693
|
/* Check lists are sequences */
|
|
1694
|
+
if (!PyList_Check(pace_in)) {
|
|
1695
|
+
PyErr_SetString(PyExc_Exception, "Pace argument must be a list.");
|
|
1696
|
+
return 0;
|
|
1697
|
+
}
|
|
1637
1698
|
if (!PyList_Check(state)) {
|
|
1638
1699
|
PyErr_SetString(PyExc_Exception, "State argument must be a list.");
|
|
1639
1700
|
return 0;
|
|
@@ -1665,8 +1726,25 @@ sim_eval_derivatives(PyObject *self, PyObject *args)
|
|
|
1665
1726
|
goto error;
|
|
1666
1727
|
}
|
|
1667
1728
|
|
|
1729
|
+
flag_model = Model_SetupPacing(model, n_pace);
|
|
1730
|
+
if (flag_model != Model_OK) {
|
|
1731
|
+
Model_SetPyErr(flag_model);
|
|
1732
|
+
goto error;
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
/* Set pacing values */
|
|
1736
|
+
pacing_in = (double*)malloc((size_t)n_pace * sizeof(double));
|
|
1737
|
+
for (int i = 0; i < n_pace; i++) {
|
|
1738
|
+
val = PyList_GetItem(pace_in, i); /* Don't decref */
|
|
1739
|
+
if (!PyFloat_Check(val)) {
|
|
1740
|
+
PyErr_Format(PyExc_Exception, "Item %d in pace vector is not a float.", i);
|
|
1741
|
+
goto error;
|
|
1742
|
+
}
|
|
1743
|
+
pacing_in[i] = PyFloat_AsDouble(val);
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1668
1746
|
/* Set bound variables */
|
|
1669
|
-
Model_SetBoundVariables(model, time_in,
|
|
1747
|
+
Model_SetBoundVariables(model, (realtype)time_in, (realtype*)pacing_in, 0, 0);
|
|
1670
1748
|
|
|
1671
1749
|
/* Set literal values */
|
|
1672
1750
|
for (i=0; i<model->n_literals; i++) {
|