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