OpenCL Simulation

Myokit provides a simulation engine for parallelized multi-cellular simulations, implemented using OpenCL. The engine can handle 1d and 2d rectangular tissue or networks of arbitrarily connected cells. Heterogeneity can be introduced by replacing model constants with fields, using the method set_field.

A two-model fiber and tissue simulation can be run using the FiberTissueSimulation.

Information about the available OpenCL devices can be obtained using the OpenCL class, which also allows the preferred device to be selected. Note that this functionality is also accessible through the command-line myo script (see opencl-select).

class myokit.SimulationOpenCL(model, protocol=None, ncells=256, diffusion=True, precision=32)

Can run 1d or 2d simulations based on a model using OpenCL for parallelization.

Takes the following input arguments:

model
The model to simulate with. This model will be cloned when the simulation is created so that no changes to the given model will be made.
protocol
An optional pacing protocol, used to stimulate a number of cells either at the start of a fiber or at the bottom-left of the tissue.
ncells
The number of cells. Use a scalar for 1d simulations or a tuple (nx, ny) for 2d simulations.
diffusion
Can be set to False to disable diffusion currents. This can be useful in combination with set_field() to explore the effects of varying one or more parameters in a single cell model.
precision
Can be set to myokit.SINGLE_PRECISION (default) or myokit.DOUBLE_PRECISION if the used device supports it.

The simulation provides the following inputs variables can bind to:

time
The simulation time
pace
The pacing level, this is set if a protocol was passed in.
diffusion_current (if enabled)
The current flowing from the cell to its neighbours. This will be positive when the cell is acting as a source, negative when it is acting as a sink.

The input time is set globally: Any variable bound to time will appear in the logs as single, global variable (for example engine.time instead of 1.2.engine.time. Variables bound to pace or diffusion_current are logged per cell. (If diffusion currents are disabled, the input diffusion_current will not be used, and any variables bound to it will be logged or not according to their default value).

To set the number of cells that will be paced, the methods set_paced_cells() and set_paced_cell_list() can be used.

A single labeled variable is required for this simulation to work:

membrane_potential
The variable representing the membrane potential.

Simulations maintain an internal state consisting of

  • the current simulation time
  • the current state
  • the default state

When a simulation is created, the simulation time is set to 0 and both the current and the default state are equal to the state of the given model, copied once for each cell. After each call to run() the time variable and current state are updated, so that each successive call to run continues where the previous simulation left off. A reset() method is provided that will set the time back to 0 and revert the current state to the default state. To change the time or state manually, use set_time() and set_state().

A pre-pacing method pre() is provided that doesn’t affect the simulation time but will update the current and the default state. This allows you to pre-pace, run a simulation, reset to the pre-paced state, run another simulation etc.

The diffusion_current is calculated as:

i = sum[g * (V - V_j)]

Where the sum is taken over all neighbouring cells j.

Models used with this simulation need to have independent components: it should be possible to evaluate the model’s equations one component at a time. A model’s suitability can be tested using has_interdependent_components.

calculate_conductance(r, sx, chi, dx)

The bidomain and monodomain models both start from the assumption of ohmic conductance between cells. In this way, Myokit’s diffusion current

I_diff[ij] = sum[g[ij] * (V[i] - V[j])]

(where the sum is over all neighbours j of cell i) is equivalent to the fundamental assumption of the bidomain model. In some cases it may be desirable to work backwards from the bidomain model, via the monodomain model, to the Myokit formulation. This can be done under the following conditions:

  1. The conductivity tensor sigma has only diagonal components (so cells never conduct diagonally).
  2. The zero-flux boundary condution is used: no current flows between the simulated tissue and its surroundings.

Then, using a finite-difference approximation for the second order derivative:

d^2V[i]   V[i-1] - 2*V[i] + V[i+1]
------- = ------------------------
 dx^2              dx^2

we can equate I_diff and the monodomain model to find:

       r    sx * chi
gx = ----- ---------
     1 + r    dx^2

with

r
The intra- to extracellular conductivity ratio
sx
The intracellular conductivity in direction “x”
chi
The surface area of the membrane per unit volume
dx
The size of the spatial discretisation step in direction x
gx
The cell-to-cell conductance in direction x, as used by Myokit

This method uses the above equation to calculate and return a conductance value from the parameters used in monodomain model based simulations.

conductance()

Returns the cell-to-cell conductance used in this simulation. The returned value will be a single float for 1d simulations and a tuple (gx, gy) for 2d simulations. If a list of connections was passed in None is returned

find_nan(log, watch_var=None, safe_range=None)

Searches for the origin of a NaN (or inf) in a simulation log generated by this Simulation.

The log must contain the state of each cell and all bound variables. The NaN can occur at any point in time except the first.

Returns a tuple (time, icell, variable, value, states, bound) where time is the time the first NaN was found and icell is the index of the cell in which it happened. The variable’s name is given as variable and its (illegal) value as value. The current state and, if available, any previous states are given in the list states. Here, states[0] points to the current state, state[1] is the previous state and so on. Similarly the values of the model’s bound variables is given in bound.

To aid in diagnosis, a variable can be selected as watch_var and a safe_range can be specified. With this option, the function will find and report either the first NaN or the first time the watched variable left the safe range, whatever came first. The safe range should be specified as (lower, upper) where both bounds are assumed to be in the safe range. The watched variable must be a state variable.

is2d()

Returns True if and only if this is a 2d simulation.

pre(duration, report_nan=True, progress=None, msg='Pre-pacing SimulationOpenCL')

This method can be used to perform an unlogged simulation, typically to pre-pace to a (semi-)stable orbit.

After running this method

  • The simulation time is not affected
  • The current state and the default state are updated to the final state reached in the simulation.

Calls to reset() after using pre() will revert the simulation to this new default state.

If numerical errors during the simulation lead to NaNs appearing in the result, the find_nan method will be used to pinpoint their location. Next, a call to the model’s rhs will be evaluated in python using checks for numerical errors to pinpoint the offending equation. The results of these operations will be written to stdout. To disable this feature, set report_nan=False.

To obtain feedback on the simulation progress, an object implementing the myokit.ProgressReporter interface can be passed in. passed in as progress. An optional description of the current simulation to use in the ProgressReporter can be passed in as msg.

remove_field(var)

Removes any field set for the given variable.

reset()

Resets the simulations:

  • The time variable is set to 0
  • The current state is set to the default state (either the model’s initial state or the last state reached using pre())
run(duration, log=None, log_interval=1.0, report_nan=True, progress=None, msg='Running SimulationOpenCL')

Runs a simulation and returns the logged results. Running a simulation has the following effects:

  • The internal state is updated to the last state in the simulation.
  • The simulation’s time variable is updated to reflect the time elapsed during the simulation.

The number of time units to simulate can be set with duration.

The variables to log can be indicated using the log argument. There are several options for its value:

  • None (default), to log all states
  • An integer flag or a combination of flags. Options: myokit.LOG_NONE, myokit.LOG_STATE, myokit.LOG_BOUND, myokit.LOG_INTER or myokit.LOG_ALL.
  • A list of qnames or variable objects
  • A myokit.DataLog object or another dictionary of
    qname : list mappings.

For more details on the log argument, see the function myokit.prepare_log().

Variables that vary from cell to cell will be logged with a prefix indicating the cell index. For example, when using:

s = SimulationOpenCL(m, p, ncells=256)
d = s.run(1000, log=['engine.time', 'membrane.V']

where engine.time is bound to time and membrane.V is the membrane potential variable, the resulting log will contain the following variables:

{
    'engine.time'  : [...],
    '0.membrane.V' : [...],
    '1.membrane.V' : [...],
    '2.membrane.V' : [...],
}

Alternatively, you can specify variables exactly:

d = s.run(1000, log=['engine.time', '0.membrane.V']

For 2d simulations, the naming scheme x.y.name is used, for example 0.0.membrane.V.

A log entry will be made every time at least log_interval time units have passed. No guarantee is given about the exact time log entries will be made, but the value of any logged time variable is guaranteed to be accurate.

Intermediary variables can be logged, but with one small drawback: for performance reasons the logged values of states and bound variables will always be one time step dt ahead of the intermediary variables. For example if running the simulation with a step size dt=0.001 the entry for a current IKr stored at t=1 will be IKr(0.999), while the entry for state V will be V(1). If exact intermediary variables are needed it’s best to log only states and bound variables and re-calculate the intermediary variables from these manually.

If numerical errors during the simulation lead to NaNs appearing in the result, the find_nan method will be used to pinpoint their location. Next, a call to the model’s rhs will be evaluated in python using checks for numerical errors to pinpoint the offending equation. The results of these operations will be written to stdout. To disable this feature, set report_nan=False.

To obtain feedback on the simulation progress, an object implementing the myokit.ProgressReporter interface can be passed in. passed in as progress. An optional description of the current simulation to use in the ProgressReporter can be passed in as msg.

set_conductance(gx=10, gy=5)

Sets the cell-to-cell conductance used in this simulation.

For 1d simulations, only gx will be used and the argument gy can be omitted. For 2d simulations both arguments should be set.

The diffusion current is calculated as:

i = gx * ((V - V_xnext) - (V_xlast - V))
  + gy * ((V - V_ynext) - (V_ylast - V))

Where the second term gy * ... is only used for 2d simulations. At the boundaries, where either V_ilast or V_inext is unavailable, the value of V is substituted, causing the term to go to zero.

For a model with currents in [uA/uF] and voltage in [mV], gx` and gy have the unit [mS/uF].

set_connections(connections)

Adds a list of connections between cells, each with their own conductance. This allows the creation of arbitrary geometries.

The connections list should be given as a list of tuples (cell1, cell2, conductance).

Connections are only supported for “1d” simulations (even though the simulated geometry may have any number of dimensions).

Setting a connection list overrules the conductances set with set_conductance().

set_constant(var, value)

Changes a model constant. Only literal constants (constants not dependent on any other variable) can be changed.

The constant var can be given as a Variable or a string containing a variable qname. The value should be given as a float.

Note that any scalar fields set for the same variable will overwrite this value without warning.

set_default_state(state, x=None, y=None)

Changes this simulation’s default state.

This can be used in three different ways:

  1. When called with an argument state of size n_states and x=None the given state will be set as the new state of all cells in the simulation.
  2. Called with an argument state of size n_states and x, y equal to a valid cell index, this method will update only the selected cell’s state.
  3. Finally, when called with a state of size n_states * n_cells the method will treat state as a concatenation of state vectors for each cell.
set_field(var, values)

Can be used to replace a model constant with a scalar field.

The argument var must specify a variable from the simulation’s model. The field itself is given as values, which must have the dimensions (ny, nx). Multiple fields can be added, depending on the memory available on the device. If a field is added for a variable already associated with a field, the old data will be overwritten.

With diffusion currents enabled, this method can let you simulate heterogeneous tissue properties. With diffusion disabled, it can be used to investigate the effects of changing a parameter through the parallel simulation of several cells.

set_paced_cell_list(cells)

Selects the cells to be paced using a list of cell indices. In 1d simulations a cell index is an integer i, in 2d simulations cell indices are specified as tuples (i, j).

For large numbers of cells, this method becomes very inefficient. In these cases it may be better to use a rectangular pacing area set using set_paced_cells().

If diffusion is disabled all cells will be paced.

set_paced_cells(nx=5, ny=5, x=0, y=0)

Sets the number of cells that will receive a stimulus from the pacing protocol. For 1d simulations, the values ny and y will be ignored.

This method can only define rectangular pacing areas. To select an arbitrary set of cells, use set_paced_cell_list().

If diffusion is disabled all cells will be paced.

Arguments:

nx
The number of cells/nodes in the x-direction. If a negative number of cells is set the cells left of the offset (x) are stimulated.
ny
The number of cells/nodes in the y-direction. If a negative number of cells is set the cells left of the offset (x) are stimulated.
x
The offset of the pacing rectangle in the x-direction. If a negative offset is given the offset is calculated from right to left.
y
The offset of the pacing rectangle in the y-direction. If a negative offset is given the offset is calculated from bottom to top.
set_protocol(protocol=None)

Changes the pacing protocol used by this simulation.

set_state(state, x=None, y=None)

Changes the state of this simulation’s model.

This can be used in three different ways:

  1. When called with an argument state of size n_states and x=None the given state will be set as the new state of all cells in the simulation.
  2. Called with an argument state of size n_states and x, y equal to a valid cell index, this method will update only the selected cell’s state.
  3. Finally, when called with a state of size n_states * n_cells the method will treat state as a concatenation of state vectors for each cell.
set_step_size(step_size=0.005)

Sets the step size used in the forward Euler solving routine.

set_time(time=0)

Sets the current simulation time.

shape()

Returns the shape of this Simulation’s grid of cells as a tuple (ny, nx) for 2d simulations, or a single value nx for 1d simulations.

state(x=None, y=None)

Returns the current simulation state as a list of len(state) * ncells floating point values.

If the optional arguments x and y specify a valid cell index a single cell’s state is returned. For example state(4) can be used with a 1d simulation, while state(4,2) is a valid index in the 2d case.

step_size()

Returns the current step size.

time()

Returns the current simulation time.

Fiber-Tissue Simulation

class myokit.FiberTissueSimulation(fiber_model, tissue_model, protocol=None, ncells_fiber=(128, 2), ncells_tissue=(128, 128), nx_paced=5, g_fiber=(9, 6), g_tissue=(9, 6), g_fiber_tissue=9, dt=0.005, double_precision=False)

Runs a simulation of a fiber leading up to a rectangular piece of tissue.

Takes the following input arguments:

fiber_model
The model to simulate the fiber with.
tissue_model
The model to simulate the tissue with. Both models will be cloned when the simulation is created so that no changes to the given models will be made.
protocol
An optional pacing protocol, used to stimulate a number of cells at the start of the fiber.
ncells_fiber
The number of cells in the fiber (a tuple).
ncells_tissue
The number of cells in the tissue (a tuple).
nx_paced
The width (in cells) of the stimulus applied to the fiber. The fiber will be stimulated along its full height.
join
A tuple (x,y) specifying the top-left coordinate on the tissue that the fiber connects to.
g_fiber
The cell to cell conductance in the fiber (a tuple).
g_tissue
The cell to cell conductance in the tissue (a tuple).
g_fiber_tissue
The fiber-cell to tissue-cell conductance at the junction (a scalar).
dt
The time step to use in the forward-Euler integration scheme.
double_precision
Set this to True if your OpenCL device supports double precision. This will greatly reduce the chance of a divide-by-zero or other numerical error introducing NaNs into the simulation.

The simulation provides the following inputs variables can bind to:

time (global)
The simulation time
pace (per-cell)
The pacing level, this is set if a protocol was passed in.
diffusion_current (per-cell)
The current flowing from the cell to its neighbours. This will be positive when the cell is acting as a source, negative when it is acting as a sink.

The variable time is set globally, meaning each cell uses the same value. The variables pace and diffusion_current have different values per cell.

The following labeled variables are required for this simulation to work:

membrane_potential
The variable representing the membrane potential.

The diffusion_current is calculated as:

i = gx * ((V - V_xnext) - (V_xlast - V))
  + gy * ((V - V_ynext) - (V_ylast - V))

At the boundaries, where either V_ilast or V_inext is unavailable, the value of V is substituted, causing the term to go to zero. The values of gx and gy can be set in the simulation’s constructor.

For a typical model with currents in [uA/uF] and voltage in [mV], gx` and gy have the unit [mS/uF].

Simulations maintain an internal state consisting of

  • the current simulation time
  • the current states
  • the default states

When a simulation is created, the simulation time is set to 0 and both the current and the default state are equal to the state of the given models, copied once for each cell. After each call to run() the time variable and current state are updated, so that each successive call to run continues where the previous simulation left off. A reset() method is provided that will set the time back to 0 and revert the current state to the default state. To change the time or state manually, use set_time() and set_fiber_state() and set_tissue_state().

A pre-pacing method pre() is provided that doesn’t affect the simulation time but will update the current and the default state. This allows you to pre-pace, run a simulation, reset to the pre-paced state, run another simulation etc.

The model passed to the simulation is cloned and stored internally, so changes to the original model object will not affect the simulation.

Models used with this simulation need to have independent components: it should be possible to evaluate the model’s equations one component at a time. A model’s suitability can be tested using :meth:` has_interdependent_components <myokit.Model.has_interdependent_components>`.

fiber_state(x=None)

Returns the current simulation state in the fiber as a list of len(state_fiber) * ncells_fiber floating point values.

If the optional arguments x and y specify a valid cell index a single cell’s state is returned.

find_nan(logf, logt)

Searches for the origin of a NaN (or inf) in a set of simulation logs generated by this Simulation.

The logs must contain the state of each cell and all bound variables. The NaN can occur at any point in time except the first.

Returns a tuple (part, time, icell, variable, value, states, bound) where time is the time the first NaN was found and icell is the index of the cell in which it happened. The entry part is a string containing either “fiber” or “tissue”, indicating which part of the simulation triggered the error. The offending variable’s name is given as variable and its (illegal) value as value. The current state and, if available, any previous states are given in the list states. Here, states[0] points to the current state in the simulation part causing the error, state[1] is the previous state and so on. Similarly the values of the error causing model’s bound variables is given in bound.

pre(duration, report_nan=True, progress=None, msg='Pre-pacing FiberTissueSimulation')

This method can be used to perform an unlogged simulation, typically to pre-pace to a (semi-)stable orbit.

After running this method

  • The simulation time is not affected
  • The current state and the default state are updated to the final state reached in the simulation.

simulation to this new default state.

Calls to reset() after using pre() will revert the To obtain feedback on the simulation progress, an object implementing the myokit.ProgressReporter interface can be passed in. passed in as progress. An optional description of the current simulation to use in the ProgressReporter can be passed in as msg.

reset()

Resets the simulation:

  • The time variable is set to 0
  • The current state is set to the default state (either the model’s initial state or the last state reached using pre())
run(duration, logf=None, logt=None, log_interval=1.0, report_nan=True, progress=None, msg='Running FiberTissueSimulation')

Runs a simulation and returns the logged results as a tuple containing two myokit.DataLog objects.. Running a simulation has the following effects:

  • The internal state is updated to the last state in the simulation.
  • The simulation’s time variable is updated to reflect the time elapsed during the simulation.

The number of time units to simulate can be set with duration.

The variables to log can be indicated using the arguments logf and logt. There are several options for their values:

  • None (default), to log all states
  • An integer flag or a combination of flags. Options: myokit.LOG_NONE, myokit.LOG_STATE, myokit.LOG_BOUND, myokit.LOG_INTER, myokit.LOG_ALL.
  • A list of qnames or variable objects
  • A myokit.DataLog. In this case, new data will be appended to the existing log.

For more details on the log arguments, see the function myokit.prepare_log().

Any variables bound to “time” or “pace” will be logged globally, all others will be logged per cell. These variables will be prefixed with a single number indicating the cell index in the fiber, and with two numbers indicating the index in the tissue.

A log entry will be made every time at least log_interval time units have passed. No guarantee is given about the exact time log entries will be made, but the value of any logged time variable is guaranteed to be accurate.

Intermediary variables can be logged, but with one small drawback: for performance reasons the logged values of states and bound variables will always be one time step dt ahead of the intermediary variables. For example if running the simulation with a step size dt=0.001 the entry for a current IKr stored at t=1 will be IKr(0.999), while the entry for state V will be V(1). If exact intermediary variables are needed it’s best to log only states and bound variables and re-calculate the intermediary variables from these manually.

To obtain feedback on the simulation progress, an object implementing the myokit.ProgressReporter interface can be passed in. passed in as progress. An optional description of the current simulation to use in the ProgressReporter can be passed in as msg.

set_default_fiber_state(state, x=None, y=None)

Changes this simulation’s default state for the fiber model.

This can be used in three different ways:

  1. When called with an argument state of size n_states and x=y=None the given state will be set as the new default state of all fiber cells in the simulation.
  2. Called with an argument state of size n_states and x, y equal to a valid cell index, this method will update only the selected fiber cell’s default state.
  3. Finally, when called with a state of size n_states * n_cells the method will treat state as a concatenation of state vectors for each fiber cell.
set_default_tissue_state(state, x=None, y=None)

Changes this simulation’s default state for the tissue model.

This can be used in three different ways:

  1. When called with an argument state of size n_states and x=None the given state will be set as the new default state of tissue cells in the simulation.
  2. Called with an argument state of size n_states and x, y equal to a valid cell index, this method will update only the selected tissue cell’s default state.
  3. Finally, when called with a state of size n_states * n_cells the method will treat state as a concatenation of state vectors for each tissue cell.
set_fiber_state(state, x=None, y=None)

Changes the state of this simulation’s fiber model.

This can be used in three different ways:

  1. When called with an argument state of size n_states and x=y=None the given state will be set as the new state of all fiber cells in the simulation.
  2. Called with an argument state of size n_states and x, y equal to a valid cell index, this method will update only the selected fiber cell’s state.
  3. Finally, when called with a state of size n_states * n_cells the method will treat state as a concatenation of state vectors for each fiber cell.
set_protocol(protocol=None)

Changes the pacing protocol used by this simulation.

set_step_size(step_size=0.005)

Sets the solver step size.

set_time(time=0)

Sets the current simulation time.

set_tissue_state(state, x=None, y=None)

Changes the state of this simulation’s tissue model.

This can be used in three different ways:

  1. When called with an argument state of size n_states and x=y=None the given state will be set as the new state of all tissue cells in the simulation.
  2. Called with an argument state of size n_states and x, y equal to a valid cell index, this method will update only the selected tissue cell’s state.
  3. Finally, when called with a state of size n_states * n_cells the method will treat state as a concatenation of state vectors for each tissue cell.
time()

Returns the current simulation time.

tissue_state(x=None)

Returns the current simulation state in the tissue as a list of len(state_tissue) * ncells_tissue floating point values.

If the optional arguments x and y specify a valid cell index a single cell’s state is returned.

OpenCL utility classes

class myokit.OpenCL

Tests for OpenCL support and can return information about opencl simulations.

static info(formatted=False)

Queries the OpenCL installation for the available platforms and devices and returns a myokit.OpenCLInfo object.

If formatted=True is set, a formatted version of the information is returned instead.

static load_selection()

Loads a platform/device selection from disk and returns a tuple (platform, device). Each entry in the tuple is either a string with the platform/device name, or None if no preference was set.

static save_selection(platform=None, device=None)

” Stores a platform/device selection to disk.

Both platform and device are identified by their names.

static selection_info()

Returns a list of platform/device combinations along with information allowing the user to select one.

The returned output is a list of tuples, where each tuple has the form (platform_name, device_name, specs).

A preferred device can be selected by passing one of the returned platform_name, device_name combinations to OpenCL.set_preferred_device().

static supported()

Returns True if OpenCL support has been detected on this system.

class myokit.OpenCLInfo(mcl_info)

Represents information about the available OpenCL platforms and devices.

Each OpenCLInfo object has a property platforms, containing a list (actually a tuple) of OpenCLPlatformInfo objects.

OpenCLInfo objects can be created by any OpenCL enabled part of Myokit.

format()

Returns a formatted version of the information.

class myokit.OpenCLPlatformInfo(platform)

Represents information about an OpenCL platform.

An OpenCLPlatformInfo object has the following properties:

name (string)
This platform’s name.
vendor (string)
The vendor of this platform.
version (string)
The OpenCL version supported by this platform.
profile (string)
The supported OpenCL profile of this platform.
extensions (string)
The available OpenCL extensions on this platform.
devices (tuple)
A tuple of device information dicts for the devices available on this platform.

OpenCLPlatformInfo objects are created as part of a OpenCLInfo objects, as returned by most OpenCL enabled parts of Myokit.

class myokit.OpenCLDeviceInfo(device)

Represents information about an OpenCL device.

An OpenCLDeviceInfo object has the following properties:

name (string)
This device’s name.
vendor (string)
This device’s vendor.
version (string)
The OpenCL version supported by this device.
driver (string)
The driver version for this device.
clock (int)
This device’s clock speed (in MHz).
globl (int)
The available global memory on this device (in bytes).
local (int)
The available local memory on this device (in bytes).
const (int)
The available constant memory on this device (in bytes).
units (int)
The number of computing units on this device.
param (int)
The maximum total size (in bytes) of arguments passed to the kernel. This limits the number of arguments a kernel can get.
groups (int)
The maximum work group size.
dimensions (int)
The maximum work item dimension.
items (tuple)
A tuple of ints specifying the maximum work item size in each dimension.

OpenCLDeviceInfo objects are created as part of a OpenCLInfo objects, as returned by most OpenCL enabled parts of Myokit.