# AUTOMATICALLY GENERATED FILE!
# Edit the templates ``*.jinja``, the header files ``*.cl``, or the model
# definitions in ``models/`` instead, then run the ``prepare.py``
# script in the main directory.


"""
Kernels and model definitions
-----------------------------
"""

from typing import Any
from jinja2 import Template

HEADER: str = r"""
#define Size ulong
#define Int int

#ifdef DOUBLE_PRECISION

#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#define Real double
#define REAL(x) x
#define VERY_SMALL_NUMBER 1e-20

#else // single precision

#define Real float
#define REAL(x) x##f
#define VERY_SMALL_NUMBER 1e-10f

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmacro-redefined"
#define M_PI M_PI_F
#define exp(x) native_exp((Real)(x))
#define log(x) native_log((Real)(x))
#define sqrt(x) native_sqrt((Real)(x))
inline Real pow_(Real base, Real exp) { return pow(base, exp); }
#define pow(x, y) pow_((Real)(x), (Real)(y))
#pragma clang diagnostic pop

#endif

Real safe_mult(Real w, Real x) {
  // safe multiplication that checks if w is zero,
  // such that safe_mult(0., nan) returns 0.
  return (w == REAL(0.0)) ? REAL(0.0) : w * x;
}

Real safe_divide(Real a, Real b) {
  // safe division that avoids division by zero,
  // i.e., if the denominator b is too close to zero,
  // it instead divides by a VERY_SMALL_NUMBER.
  if (fabs(b) < VERY_SMALL_NUMBER) {
    b = b < REAL(0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER;
  }
  return a / b;
}

#define GET_NPY_SHAPE(arr, i)                                                  \
  (i <= Int(arr.ndim()) ? Int(arr.shape(Int(arr.ndim()) - i)) : 1)
#define STATES_ADDRESS(s)                                                      \
  ((((s.it * s.Nz + s.iz) * s.Ny + s.iy) * s.Nx + s.ix) * s.Nv + s.iv) * s.Ns
#define STATES_FROM_NPY(type, x)                                               \
  States_from_shape(sizeof(type), GET_NPY_SHAPE(x, 5), GET_NPY_SHAPE(x, 4),    \
                    GET_NPY_SHAPE(x, 3), GET_NPY_SHAPE(x, 2),                  \
                    GET_NPY_SHAPE(x, 1));
#define STATES_DATA_SIZE(s) s.Ns *STATES_SIZE(s)
#define STATES_SHAPE(s) {s.Nt, s.Nz, s.Ny, s.Nx, s.Nv}
#define STATES_SIZE(s) s.Nt *s.Nz *s.Ny *s.Nx *s.Nv
#define STATES_UNPACK(s)                                                       \
  s.Ns, s.Nt, s.Nz, s.Ny, s.Nx, s.Nv, s.it, s.iz, s.iy, s.ix, s.iv

struct States {
  __global void *data;
  Size Ns;                 // byte size of one element
  Size Nt, Nz, Ny, Nx, Nv; // points per dimension
  Size it, iz, iy, ix, iv; // indices per dimension
#ifndef __OPENCL_VERSION__
  cl_mem buffer;
#endif
};

struct StatesIdx {
  Size Ns;                 // byte size of one element
  Size Nt, Nz, Ny, Nx, Nv; // points per dimension
  Size it, iz, iy, ix, iv; // indices per dimension
};

Size offset(Size i, Int o, Size N) {
  if (o == 0) {
    return i;
  }
  return (((i + N) + o) % N + N) % N;
}

struct States States_from_shape(Size Ns, Size Nt, Size Nz, Size Ny, Size Nx,
                                Size Nv) {
  struct States s = {NULL, Ns, Nt, Nz, Ny, Nx, Nv, 0, 0, 0, 0, 0};
  return s;
}

struct States States_offset(struct States s, Int ot, // codespell:ignore ot
                            Int oz, Int oy, Int ox, Int ov) {
  s.it = offset(s.it, ot, s.Nt); // codespell:ignore ot
  s.iz = offset(s.iz, oz, s.Nz);
  s.iy = offset(s.iy, oy, s.Ny);
  s.ix = offset(s.ix, ox, s.Nx);
  s.iv = offset(s.iv, ov, s.Nv);
  return s;
}

struct States States_offset_t(Int o, struct States s) {
  s.it = offset(s.it, o, s.Nt);
  return s;
}
struct States States_offset_z(Int o, struct States s) {
  s.iz = offset(s.iz, o, s.Nz);
  return s;
}
struct States States_offset_y(Int o, struct States s) {
  s.iy = offset(s.iy, o, s.Ny);
  return s;
}
struct States States_offset_x(Int o, struct States s) {
  s.ix = offset(s.ix, o, s.Nx);
  return s;
}
struct States States_offset_v(Int o, struct States s) {
  s.iv = offset(s.iv, o, s.Nv);
  return s;
}

__global void *States_get_pointer(struct States s) {
  return (__global char *)(s.data) + STATES_ADDRESS(s);
}
__global Int *States_get_pointer_int(struct States s) {
  return (__global Int *)States_get_pointer(s);
}
__global Real *States_get_pointer_real(struct States s) {
  return (__global Real *)States_get_pointer(s);
}
Int States_get_int(struct States s) { return *States_get_pointer_int(s); }
Real States_get_real(struct States s) { return *States_get_pointer_real(s); }
Int States_get_bool(struct States s) { return States_get_int(s) != 0; }

#define _t States_offset_t
#define _z States_offset_z
#define _y States_offset_y
#define _x States_offset_x
#define _v States_offset_v
#define _p States_get_pointer
#define _pi States_get_pointer_int
#define _pr States_get_pointer_real
#define _i States_get_int
#define _r States_get_real
#define _b States_get_bool

// AUTOMATICALLY GENERATED FILE!
// Edit the templates ``*.jinja``, the header files ``*.cl``, or the model
// definitions in ``models/`` instead, then run the ``prepare.py``
// script in the main directory.


Real diffuse(struct States w, struct States u) {
  return
    safe_mult(States_get_real(States_offset_v(0, w)),
        States_get_real(States_offset(u, 0, 0, 0, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(1, w)),
        States_get_real(States_offset(u, 0, 0, 0, 1, 0)))
    + safe_mult(States_get_real(States_offset_v(2, w)),
        States_get_real(States_offset(u, 0, 0, 0, -1, 0)))
    + safe_mult(States_get_real(States_offset_v(3, w)),
        States_get_real(States_offset(u, 0, 0, 1, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(4, w)),
        States_get_real(States_offset(u, 0, 0, -1, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(5, w)),
        States_get_real(States_offset(u, 0, 1, 0, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(6, w)),
        States_get_real(States_offset(u, 0, -1, 0, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(7, w)),
        States_get_real(States_offset(u, 0, 1, 1, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(8, w)),
        States_get_real(States_offset(u, 0, -1, 1, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(9, w)),
        States_get_real(States_offset(u, 0, 1, -1, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(10, w)),
        States_get_real(States_offset(u, 0, -1, -1, 0, 0)))
    + safe_mult(States_get_real(States_offset_v(11, w)),
        States_get_real(States_offset(u, 0, 1, 0, 1, 0)))
    + safe_mult(States_get_real(States_offset_v(12, w)),
        States_get_real(States_offset(u, 0, -1, 0, 1, 0)))
    + safe_mult(States_get_real(States_offset_v(13, w)),
        States_get_real(States_offset(u, 0, 1, 0, -1, 0)))
    + safe_mult(States_get_real(States_offset_v(14, w)),
        States_get_real(States_offset(u, 0, -1, 0, -1, 0)))
    + safe_mult(States_get_real(States_offset_v(15, w)),
        States_get_real(States_offset(u, 0, 0, 1, 1, 0)))
    + safe_mult(States_get_real(States_offset_v(16, w)),
        States_get_real(States_offset(u, 0, 0, -1, 1, 0)))
    + safe_mult(States_get_real(States_offset_v(17, w)),
        States_get_real(States_offset(u, 0, 0, 1, -1, 0)))
    + safe_mult(States_get_real(States_offset_v(18, w)),
        States_get_real(States_offset(u, 0, 0, -1, -1, 0)));
}
"""

CORE: str = r"""
__kernel void set_outside(const Real value, __global void *mask_data,
                          struct StatesIdx mask_idx, __global void *states_data,
                          struct StatesIdx states_idx) {

  struct States mask = {mask_data, STATES_UNPACK(mask_idx)};
  struct States states = {states_data, STATES_UNPACK(states_idx)};

  const Size iz = get_global_id(0);
  const Size iy = get_global_id(1);
  const Size ix = get_global_id(2);

  if (ix < states.Nx && iy < states.Ny && iz < states.Nz) {
    if (!States_get_bool(States_offset(mask, 0, iz, iy, ix, 0))) {
      __global Real *u = States_get_pointer_real(States_offset(states, 0, iz, iy, ix, 0));
      for (Size iv = 0; iv < states.Nv; iv++) {
        u[iv] = value;
      }
    }
  }
}

__kernel void add_stimulus(const Real amplitude, __global void *shape_data,
                           struct StatesIdx shape_idx,
                           __global void *states_data,
                           struct StatesIdx states_idx) {

  struct States shape = {shape_data, STATES_UNPACK(shape_idx)};
  struct States states = {states_data, STATES_UNPACK(states_idx)};

  const Size iz = get_global_id(0);
  const Size iy = get_global_id(1);
  const Size ix = get_global_id(2);

  if (ix < states.Nx && iy < states.Ny && iz < states.Nz) {
    const Real current = amplitude * States_get_real(States_offset(shape, 0, iz, iy, ix, 0));
    if (fabs(current) > VERY_SMALL_NUMBER) {
      *States_get_pointer_real(States_offset(states, 0, iz, iy, ix, 0)) += current;
    }
  }
}

// AUTOMATICALLY GENERATED FILE!
// Edit the templates ``*.jinja``, the header files ``*.cl``, or the model
// definitions in ``models/`` instead, then run the ``prepare.py``
// script in the main directory.


__kernel void calculate_weights(
    const Real dz, const Real dy, const Real dx,
    __global void *mask_data, struct StatesIdx mask_idx,
    __global void *diffusivity_data, struct StatesIdx diffusivity_idx,
    __global void *weights_data, struct StatesIdx weights_idx
) {

  struct States mask = {mask_data, STATES_UNPACK(mask_idx)};
  struct States diffusivity = {diffusivity_data, STATES_UNPACK(diffusivity_idx)};
  struct States weights = {weights_data, STATES_UNPACK(weights_idx)};

  const Size iz = get_global_id(0);
  const Size iy = get_global_id(1);
  const Size ix = get_global_id(2);

  
  const Real idxx = REAL(0.5) / (dx * dx);
  const Real idyz = REAL(0.125) / (dy * dz);
  const Real idyy = REAL(0.5) / (dy * dy);
  const Real idxz = REAL(0.125) / (dx * dz);
  const Real idzz = REAL(0.5) / (dz * dz);
  const Real idxy = REAL(0.125) / (dx * dy);

  if (ix < weights.Nx && iy < weights.Ny && iz < weights.Nz) {
    // shortcut notation
    // xzwXy -> ((x=-1, z=-1), weights, (X=+1, y=-1))
    // left group -> variable indices
    // right group -> offsets in x, y, z

    // shortcuts for mask (iv is always 0)
    struct States m_ = States_offset(mask, 0, iz, iy, ix, 0);
    const bool m = States_get_bool(States_offset(m_, 0, 0, 0, 0, 0));
    const bool mz = States_get_bool(States_offset(m_, 0, -1, 0, 0, 0));
    const bool mZ = States_get_bool(States_offset(m_, 0, 1, 0, 0, 0));
    const bool my = States_get_bool(States_offset(m_, 0, 0, -1, 0, 0));
    const bool myz = States_get_bool(States_offset(m_, 0, -1, -1, 0, 0));
    const bool myZ = States_get_bool(States_offset(m_, 0, 1, -1, 0, 0));
    const bool mY = States_get_bool(States_offset(m_, 0, 0, 1, 0, 0));
    const bool mYz = States_get_bool(States_offset(m_, 0, -1, 1, 0, 0));
    const bool mYZ = States_get_bool(States_offset(m_, 0, 1, 1, 0, 0));
    const bool mx = States_get_bool(States_offset(m_, 0, 0, 0, -1, 0));
    const bool mxz = States_get_bool(States_offset(m_, 0, -1, 0, -1, 0));
    const bool mxZ = States_get_bool(States_offset(m_, 0, 1, 0, -1, 0));
    const bool mxy = States_get_bool(States_offset(m_, 0, 0, -1, -1, 0));
    const bool mxY = States_get_bool(States_offset(m_, 0, 0, 1, -1, 0));
    const bool mX = States_get_bool(States_offset(m_, 0, 0, 0, 1, 0));
    const bool mXz = States_get_bool(States_offset(m_, 0, -1, 0, 1, 0));
    const bool mXZ = States_get_bool(States_offset(m_, 0, 1, 0, 1, 0));
    const bool mXy = States_get_bool(States_offset(m_, 0, 0, -1, 1, 0));
    const bool mXY = States_get_bool(States_offset(m_, 0, 0, 1, 1, 0));

    // shortcuts for diffusivity (iv in range(6))
    struct States D = States_offset(diffusivity, 0, iz, iy, ix, 0);
    const Real xxD = States_get_real(States_offset(D, 0, 0, 0, 0, 0));
    const Real xxDx = States_get_real(States_offset(D, 0, 0, 0, -1, 0));
    const Real xxDX = States_get_real(States_offset(D, 0, 0, 0, 1, 0));
    const Real yyD = States_get_real(States_offset(D, 0, 0, 0, 0, 1));
    const Real yyDy = States_get_real(States_offset(D, 0, 0, -1, 0, 1));
    const Real yyDY = States_get_real(States_offset(D, 0, 0, 1, 0, 1));
    const Real zzD = States_get_real(States_offset(D, 0, 0, 0, 0, 2));
    const Real zzDz = States_get_real(States_offset(D, 0, -1, 0, 0, 2));
    const Real zzDZ = States_get_real(States_offset(D, 0, 1, 0, 0, 2));
    const Real yzD = States_get_real(States_offset(D, 0, 0, 0, 0, 3));
    const Real yzDy = States_get_real(States_offset(D, 0, 0, -1, 0, 3));
    const Real yzDY = States_get_real(States_offset(D, 0, 0, 1, 0, 3));
    const Real yzDz = States_get_real(States_offset(D, 0, -1, 0, 0, 3));
    const Real yzDZ = States_get_real(States_offset(D, 0, 1, 0, 0, 3));
    const Real xzD = States_get_real(States_offset(D, 0, 0, 0, 0, 4));
    const Real xzDx = States_get_real(States_offset(D, 0, 0, 0, -1, 4));
    const Real xzDX = States_get_real(States_offset(D, 0, 0, 0, 1, 4));
    const Real xzDz = States_get_real(States_offset(D, 0, -1, 0, 0, 4));
    const Real xzDZ = States_get_real(States_offset(D, 0, 1, 0, 0, 4));
    const Real xyD = States_get_real(States_offset(D, 0, 0, 0, 0, 5));
    const Real xyDx = States_get_real(States_offset(D, 0, 0, 0, -1, 5));
    const Real xyDX = States_get_real(States_offset(D, 0, 0, 0, 1, 5));
    const Real xyDy = States_get_real(States_offset(D, 0, 0, -1, 0, 5));
    const Real xyDY = States_get_real(States_offset(D, 0, 0, 1, 0, 5));

    // shortcuts for weights (iv in range(19))
    struct States w_ = States_offset(weights, 0, iz, iy, ix, 0);
    __global Real* const w = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 0));
    __global Real* const Xw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 1));
    __global Real* const xw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 2));
    __global Real* const Yw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 3));
    __global Real* const yw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 4));
    __global Real* const Zw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 5));
    __global Real* const zw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 6));
    __global Real* const YZw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 7));
    __global Real* const Yzw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 8));
    __global Real* const yZw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 9));
    __global Real* const yzw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 10));
    __global Real* const XZw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 11));
    __global Real* const Xzw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 12));
    __global Real* const xZw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 13));
    __global Real* const xzw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 14));
    __global Real* const XYw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 15));
    __global Real* const Xyw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 16));
    __global Real* const xYw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 17));
    __global Real* const xyw = States_get_pointer_real(States_offset(w_, 0, 0, 0, 0, 18));

    // fill weights with zero
    for (Size iv = 0; iv < weights.Nv; iv++) {
      *_pr(_v(iv, w_)) = REAL(0.0);
    }

    if (m) {
      if (mx) {
        const Real hx = (xxDx + xxD) * idxx;
        *w -= hx; *xw += hx;
        
        const Real hy = (xyDx + xyD) * idxy;
        if (mY)  { *w  += hy; *Yw  -= hy; }
        if (mxY) { *xw += hy; *xYw -= hy; }
        if (my)  { *w  -= hy; *yw  += hy; }
        if (mxy) { *xw -= hy; *xyw += hy; }
        
        const Real hz = (xzDx + xzD) * idxz;
        if (mZ)  { *w  += hz; *Zw  -= hz; }
        if (mxZ) { *xw += hz; *xZw -= hz; }
        if (mz)  { *w  -= hz; *zw  += hz; }
        if (mxz) { *xw -= hz; *xzw += hz; }
      }
      
      if (mX) {
        const Real hx = (xxDX + xxD) * idxx;
        *w -= hx; *Xw += hx;
        
        const Real hy = (xyDX + xyD) * idxy;
        if (my)  { *w  += hy; *yw  -= hy; }
        if (mXy) { *Xw += hy; *Xyw -= hy; }
        if (mY)  { *w  -= hy; *Yw  += hy; }
        if (mXY) { *Xw -= hy; *XYw += hy; }
        
        const Real hz = (xzDX + xzD) * idxz;
        if (mz)  { *w  += hz; *zw  -= hz; }
        if (mXz) { *Xw += hz; *Xzw -= hz; }
        if (mZ)  { *w  -= hz; *Zw  += hz; }
        if (mXZ) { *Xw -= hz; *XZw += hz; }
      }
      
      if (my) {
        const Real hy = (yyDy + yyD) * idyy;
        *w -= hy; *yw += hy;
        
        const Real hz = (yzDy + yzD) * idyz;
        if (mZ)  { *w  += hz; *Zw  -= hz; }
        if (myZ) { *yw += hz; *yZw -= hz; }
        if (mz)  { *w  -= hz; *zw  += hz; }
        if (myz) { *yw -= hz; *yzw += hz; }
        
        const Real hx = (xyDy + xyD) * idxy;
        if (mX)  { *w  += hx; *Xw  -= hx; }
        if (mXy) { *yw += hx; *Xyw -= hx; }
        if (mx)  { *w  -= hx; *xw  += hx; }
        if (mxy) { *yw -= hx; *xyw += hx; }
      }
      
      if (mY) {
        const Real hy = (yyDY + yyD) * idyy;
        *w -= hy; *Yw += hy;
        
        const Real hz = (yzDY + yzD) * idyz;
        if (mz)  { *w  += hz; *zw  -= hz; }
        if (mYz) { *Yw += hz; *Yzw -= hz; }
        if (mZ)  { *w  -= hz; *Zw  += hz; }
        if (mYZ) { *Yw -= hz; *YZw += hz; }
        
        const Real hx = (xyDY + xyD) * idxy;
        if (mx)  { *w  += hx; *xw  -= hx; }
        if (mxY) { *Yw += hx; *xYw -= hx; }
        if (mX)  { *w  -= hx; *Xw  += hx; }
        if (mXY) { *Yw -= hx; *XYw += hx; }
      }
      
      if (mz) {
        const Real hz = (zzDz + zzD) * idzz;
        *w -= hz; *zw += hz;
        
        const Real hx = (xzDz + xzD) * idxz;
        if (mX)  { *w  += hx; *Xw  -= hx; }
        if (mXz) { *zw += hx; *Xzw -= hx; }
        if (mx)  { *w  -= hx; *xw  += hx; }
        if (mxz) { *zw -= hx; *xzw += hx; }
        
        const Real hy = (yzDz + yzD) * idyz;
        if (mY)  { *w  += hy; *Yw  -= hy; }
        if (mYz) { *zw += hy; *Yzw -= hy; }
        if (my)  { *w  -= hy; *yw  += hy; }
        if (myz) { *zw -= hy; *yzw += hy; }
      }
      
      if (mZ) {
        const Real hz = (zzDZ + zzD) * idzz;
        *w -= hz; *Zw += hz;
        
        const Real hx = (xzDZ + xzD) * idxz;
        if (mx)  { *w  += hx; *xw  -= hx; }
        if (mxZ) { *Zw += hx; *xZw -= hx; }
        if (mX)  { *w  -= hx; *Xw  += hx; }
        if (mXZ) { *Zw -= hx; *XZw += hx; }
        
        const Real hy = (yzDZ + yzD) * idyz;
        if (my)  { *w  += hy; *yw  -= hy; }
        if (myZ) { *Zw += hy; *yZw -= hy; }
        if (mY)  { *w  -= hy; *Yw  += hy; }
        if (mYZ) { *Zw -= hy; *YZw += hy; }
      }
      
    }
  }
}
"""

TEMPLATE = Template(r"""
void Model_{{ key }}_step(
        __global Real* const params,
        struct States weights,
        struct States states_old,
        struct States states_new,
        const Real dt
) {
  {% for param in model_def.all_parameters %}
  const Real {{ param }} = params[{{ loop.index0 }}];
  {%- endfor %}
  {% for varname in model_def.variables %}
  const Real {{ varname }} = _r(_v({{ loop.index0 }}, states_old));
  __global Real* const _new_{{ varname }} = _pr(_v({{ loop.index0 }}, states_new));
  {%- if varname in model_def.diffusivity %}
  const Real _diffuse_{{ varname }} = diffusivity_{{ varname }} * diffuse(weights, _v({{ loop.index0 }}, states_old));
  {%- endif %}
  {%- endfor %}

  {{ model_def.code | indent(2) -}}
}

__kernel void Model_{{ key }}_kernel(
        Size model_count,
        __global Size* model_ids,
        __global Size* model_offsets,
        __global Real* model_params,
        __global void* inhom_data,      struct StatesIdx inhom_idx,
        __global void* weights_data,    struct StatesIdx weights_idx,
        __global void* states_old_data, struct StatesIdx states_old_idx,
        __global void* states_new_data, struct StatesIdx states_new_idx,
        const Real dt
) {

  struct States inhom      = {inhom_data,      STATES_UNPACK(inhom_idx)};
  struct States weights    = {weights_data,    STATES_UNPACK(weights_idx)};
  struct States states_old = {states_old_data, STATES_UNPACK(states_old_idx)};
  struct States states_new = {states_new_data, STATES_UNPACK(states_new_idx)};

  const Size iz = get_global_id(0);
  const Size iy = get_global_id(1);
  const Size ix = get_global_id(2);

  if (ix < states_old.Nx && iy < states_old.Ny && iz < states_old.Nz) {
    const Int inhom_zyx = _i(States_offset(inhom, 0, iz, iy, ix, 0));
    if (inhom_zyx > 0) {
      const Size imodel = (inhom_zyx - 1) % model_count;
      const Size model_id = model_ids[imodel];
      if (model_id == {{ model_id }}) {
        __global Real* params = model_params + model_offsets[imodel];
        struct States w = States_offset(weights, 0, iz, iy, ix, 0);
        struct States u = States_offset(states_old, 0, iz, iy, ix, 0);
        struct States u_ = States_offset(states_new, 0, iz, iy, ix, 0);
        Model_{{ key }}_step(params, w, u, u_, dt);
      }
    }
  }
}

""")

PREDEFINED_MODELS: dict[str, dict[str, Any]] = {'aliev1996simple': {'name': 'Aliev & Panfilov 1996', 'description': 'This simple two-variable model was created by modifying the model by FitzHugh\n& Nagumo to describe cardiac excitation waves. It models restitution of\naction potential duration, i.e., its dependence on cycle length. It was\noriginally designed for canine ventricles, but is considered a\nphenomenological model.\n', 'dois': ['https://doi.org/10.1016/0960-0779(95)00089-5'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'phenomenological'], 'variables': {'u': 0.0, 'v': 0.0}, 'diffusivity': {'u': 1.0}, 'parameters': {'eps0': 0.002, 'mu1': 0.2, 'mu2': 0.3, 'a': 0.15, 'k': 8.0}, 'example discretisation': {'dt': 0.023, 'dx': 0.43, 'stimulus': 0.22}, 'units': {'t': 1, 'x': 1, 'u': 1}, 'code': 'const Real eps = eps0 + mu1 * v / (u + mu2);\nconst Real _react_u = -k * u * (u - a) * (u - 1.0) - u * v;\nconst Real _react_v = eps * (-v - k * u * (u - a - 1.0));\n*_new_u = u + dt * (_react_u + _diffuse_u);\n*_new_v = v + dt * _react_v;\n'}, 'bar1993turbulence': {'name': 'Bar & Eiswirth 1993', 'description': 'This simple two-variable model was created by modifying the model by FitzHugh\n& Nagumo to describe cardiac excitation waves. This model shows that spiral breakup,\nleading to turbulence, can occur in a two-dimensional reaction-diffusion system with\ndelayed-inhibitor production.\n', 'dois': ['https://doi.org/10.1103/PhysRevE.48.R1635'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'phenomenological'], 'variables': {'u': 0.0, 'v': 0.0}, 'diffusivity': {'u': 1.0}, 'parameters': {'eps': 0.075, 'a': 0.84, 'b': 0.07}, 'code': 'const Real _react_u = - u * (u - 1.0) * (u - ((v + b)/a) )/eps;\nconst Real f = (u < 1.0/3.0) ? 0.0 : (u > 1.0) ? 1.0 : (1 - 6.75*u*(u - 1)*(u - 1));\nconst Real _react_v = f - v;\n*_new_u = u + dt * (_react_u + _diffuse_u);\n*_new_v = v + dt * _react_v;\n'}, 'barkley1991model': {'name': 'Barkley 1991', 'description': 'This early phenomenological model of excitable media is one of the\nsimplest models describing both excitation and recovery enabling\nspiral waves.\n', 'dois': ['https://doi.org/10.1016/0167-2789(91)90194-E'], 'keywords': ['excitable media', 'phenomenological'], 'variables': {'u': 0.0, 'v': 0.0}, 'diffusivity': {'u': 1.0, 'v': 0.0}, 'parameters': {'a': 0.75, 'b': 0.02, 'eps': 0.02}, 'example discretisation': {'dt': 0.002, 'dx': 0.2, 'stimulus': 1.0}, 'units': {'t': 1, 'x': 1, 'u': 1}, 'code': 'const Real _react_u = u*(1 - u)*(u - (v + b)/a)/eps;\nconst Real _react_v = u - v;\n*_new_u = u + dt * (_react_u + _diffuse_u);\n*_new_v = v + dt * (_react_v + _diffuse_v);\n'}, 'beeler1977reconstruction': {'name': 'Beeler & Reuter 1977', 'description': 'The G.W. Beeler and H. Reuter 1977 model was developed to describe the\nmammalian ventricular action potential. The total ionic flux is divided into\nonly four discrete, individual ionic currents. The main additional feature of\nthe Beeler-Reuter ionic current model is a representation of the intracellular\ncalcium ion concentration.\n', 'dois': ['https://doi.org/10.1113/jphysiol.1977.sp011853'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'phenomenological', 'ventricle'], 'variables': {'V': -84.624, 'm': 0.011, 'h': 0.988, 'j': 0.975, 'd': 0.003, 'f': 0.994, 'x1': 0.0001, 'Cai': 0.0001}, 'diffusivity': {'V': 1.0}, 'parameters': {'g_s': 0.0009, 'E_Na': 50.0, 'g_Na': 0.04, 'g_Nac': 3e-05, 'C': 0.01}, 'example discretisation': {'dt': 0.031, 'dx': 0.49, 'stimulus': 32.7}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}, 'code': '// slow inward current\nconst Real E_s = -82.3 - 13.0287 * log(Cai * 0.001);\nconst Real i_s = g_s * d * f * (V - E_s);\n*_new_Cai = Cai + dt*(-0.01 * i_s + 0.07 * (0.0001 - Cai));\n\n// d gate\nconst Real alpha_d = 0.095 * exp(-(V - 5.0) / 100.0) / (1.0 + exp(-(V - 5.0) / 13.89));\nconst Real beta_d = 0.07 * exp(-(V + 44.0) / 59.0) / (1.0 + exp((V + 44.0) / 20.0));\nconst Real tau_d = 1.0 / (alpha_d + beta_d);\nconst Real d_inf = alpha_d * tau_d;\n*_new_d = d_inf + (d - d_inf) * exp(-dt / tau_d);\n\n// f gate\nconst Real alpha_f = 0.012 * exp(-(V + 28.0) / 125.0) / (1.0 + exp((V + 28.0) / 6.67));\nconst Real beta_f = 0.0065 * exp(-(V + 30.0) / 50.0) / (1.0 + exp(-(V + 30.0) / 5.0));\nconst Real tau_f = 1.0 / (alpha_f + beta_f);\nconst Real f_inf = alpha_f * tau_f;\n*_new_f = f_inf + (f - f_inf) * exp(-dt / tau_f);\n\n// sodium current\nconst Real i_Na = (g_Na * m * m * m * h * j + g_Nac) * (V - E_Na);\n\n// h gate\nconst Real alpha_h = 0.126 * exp(-0.25 * (V + 77.0));\nconst Real beta_h = 1.7 / (exp(-0.082 * (V + 22.5)) + 1.0);\nconst Real tau_h = 1.0 / (alpha_h + beta_h);\nconst Real h_inf = alpha_h * tau_h;\n*_new_h = h_inf + (h - h_inf) * exp(-dt / tau_h);\n\n// j gate\nconst Real alpha_j = 0.055 * exp(-0.25 * (V + 78.0)) / (exp(-0.2 * (V + 78.0)) + 1.0);\nconst Real beta_j = 0.3 / (exp(-0.1 * (V + 32.0)) + 1.0);\nconst Real tau_j = 1.0 / (alpha_j + beta_j);\nconst Real j_inf = alpha_j * tau_j;\n*_new_j = j_inf + (j - j_inf) * exp(-dt / tau_j);\n\n// m gate\nconst Real alpha_m = -safe_divide(V + 47.0, exp(-0.1 * (V + 47.0)) - 1.0);\nconst Real beta_m = 40.0 * exp(-0.056 * (V + 72.0));\nconst Real tau_m = 1.0 / (alpha_m + beta_m);\nconst Real m_inf = alpha_m * tau_m;\n*_new_m = m_inf + (m - m_inf) * exp(-dt / tau_m);\n\n// time dependent outward current\nconst Real i_x1 = x1 * 0.008 * (exp(0.04 * (V + 77.0)) - 1.0) / (exp(0.04 * (V + 35.0)));\n\n// x1 gate\nconst Real alpha_x1 = 0.0005 * exp((V + 50.0) / 12.1) / (1.0 + exp((V + 50.0) / 17.5));\nconst Real beta_x1 = 0.0013 * exp(-(V + 20.0) / 16.67) / (1.0 + exp(-(V + 20.0) / 25.0));\nconst Real tau_x1 = 1.0 / (alpha_x1 + beta_x1);\nconst Real x1_inf = alpha_x1 * tau_x1;\n*_new_x1 = x1_inf + (x1 - x1_inf) * exp(-dt / tau_x1);\n\n// time independent outward current\nconst Real i_K1 = 0.0035 * (4.0 * (exp(0.04 * (V + 85.0)) - 1.0) / (exp(0.08 * (V + 53.0)) + exp(0.04 * (V + 53.0))) + 0.2 * safe_divide(V + 23.0, 1.0 - exp(-0.04 * (V + 23.0))));\n\n// membrane\n*_new_V = V + dt*(_diffuse_V - (i_Na + i_s + i_x1 + i_K1) / C);\n'}, 'bueno2008minimal': {'name': 'Bueno-Orovio et al. 2008', 'description': 'This cardiac electrophysiology model by Bueno-Orovio, Cherry, and Fenton is a\nfour-variable extension of the model by Fenton & Karma 1998. It was designed\nto reproduce action potential shapes and the restitution characteristics of\ntheir duration and of conduction velocity.\n\nThe model comes with parameter sets for the epi- (default) and\nendocardium of the human ventricule, as well as a midwall parameter sets.\nAdditionally, the authors provide parameter sets emulating the models by\nPriebe & Beuckelmann 1998 (PB) and Ten Tusscher et al. 2004 (TNNP).\n', 'dois': ['https://doi.org/10.1016/j.jtbi.2008.03.029', 'https://doi.org/10.1063/1.166311', 'https://doi.org/10.1161/01.RES.82.11.1206', 'https://doi.org/10.1152/ajpheart.00794.2003'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'generic'], 'variables': {'u': 0.0, 'v': 1.0, 'w': 1.0, 's': 0.0}, 'diffusivity': {'u': 0.1171}, 'parameters': {'u0': 0, 'u_u': 1.55, 'theta_v': 0.3, 'theta_w': 0.13, 'theta_vm': 0.006, 'theta_0': 0.006, 'tau_v1m': 60, 'tau_v2m': 1150, 'tau_vp': 1.4506, 'tau_w1m': 60, 'tau_w2m': 15, 'k_wm': 65, 'u_wm': 0.03, 'tau_wp': 200, 'tau_fi': 0.11, 'tau_o1': 400, 'tau_o2': 6, 'tau_so1': 30.0181, 'tau_so2': 0.9957, 'k_so': 2.0458, 'u_so': 0.65, 'tau_s1': 2.7342, 'tau_s2': 16, 'k_s': 2.0994, 'u_s': 0.9087, 'tau_si': 1.8875, 'tau_winf': 0.07, 'w_infstar': 0.94}, 'parameter sets': {'EPI': {'u0': 0, 'u_u': 1.55, 'theta_v': 0.3, 'theta_w': 0.13, 'theta_vm': 0.006, 'theta_0': 0.006, 'tau_v1m': 60, 'tau_v2m': 1150, 'tau_vp': 1.4506, 'tau_w1m': 60, 'tau_w2m': 15, 'k_wm': 65, 'u_wm': 0.03, 'tau_wp': 200, 'tau_fi': 0.11, 'tau_o1': 400, 'tau_o2': 6, 'tau_so1': 30.0181, 'tau_so2': 0.9957, 'k_so': 2.0458, 'u_so': 0.65, 'tau_s1': 2.7342, 'tau_s2': 16, 'k_s': 2.0994, 'u_s': 0.9087, 'tau_si': 1.8875, 'tau_winf': 0.07, 'w_infstar': 0.94}, 'ENDO': {'u0': 0, 'u_u': 1.56, 'theta_v': 0.3, 'theta_w': 0.13, 'theta_vm': 0.2, 'theta_0': 0.006, 'tau_v1m': 75, 'tau_v2m': 10, 'tau_vp': 1.4506, 'tau_w1m': 6, 'tau_w2m': 140, 'k_wm': 200, 'u_wm': 0.016, 'tau_wp': 280, 'tau_fi': 0.1, 'tau_o1': 470, 'tau_o2': 6, 'tau_so1': 40, 'tau_so2': 1.2, 'k_so': 2, 'u_so': 0.65, 'tau_s1': 2.7342, 'tau_s2': 2, 'k_s': 2.0994, 'u_s': 0.9087, 'tau_si': 2.9013, 'tau_winf': 0.0273, 'w_infstar': 0.78}, 'Midwall': {'u0': 0, 'u_u': 1.61, 'theta_v': 0.3, 'theta_w': 0.13, 'theta_vm': 0.1, 'theta_0': 0.005, 'tau_v1m': 80, 'tau_v2m': 1.4506, 'tau_vp': 1.4506, 'tau_w1m': 70, 'tau_w2m': 8, 'k_wm': 200, 'u_wm': 0.016, 'tau_wp': 280, 'tau_fi': 0.078, 'tau_o1': 410, 'tau_o2': 7, 'tau_so1': 91, 'tau_so2': 0.8, 'k_so': 2.1, 'u_so': 0.6, 'tau_s1': 2.7342, 'tau_s2': 4, 'k_s': 2.0994, 'u_s': 0.9087, 'tau_si': 3.3849, 'tau_winf': 0.01, 'w_infstar': 0.5}, 'PB': {'u0': 0, 'u_u': 1.45, 'theta_v': 0.35, 'theta_w': 0.13, 'theta_vm': 0.175, 'theta_0': 0.006, 'tau_v1m': 10, 'tau_v2m': 1150, 'tau_vp': 1.4506, 'tau_w1m': 140, 'tau_w2m': 6.25, 'k_wm': 65, 'u_wm': 0.015, 'tau_wp': 326, 'tau_fi': 0.105, 'tau_o1': 400, 'tau_o2': 6, 'tau_so1': 30.0181, 'tau_so2': 0.9957, 'k_so': 2.0458, 'u_so': 0.65, 'tau_s1': 2.7342, 'tau_s2': 16, 'k_s': 2.0994, 'u_s': 0.9087, 'tau_si': 1.8875, 'tau_winf': 0.175, 'w_infstar': 0.9}, 'TNNP': {'u0': 0, 'u_u': 1.58, 'theta_v': 0.3, 'theta_w': 0.015, 'theta_vm': 0.015, 'theta_0': 0.006, 'tau_v1m': 60, 'tau_v2m': 1150, 'tau_vp': 1.4506, 'tau_w1m': 70, 'tau_w2m': 20, 'k_wm': 65, 'u_wm': 0.03, 'tau_wp': 280, 'tau_fi': 0.11, 'tau_o1': 6, 'tau_o2': 6, 'tau_so1': 43, 'tau_so2': 0.2, 'k_so': 2, 'u_so': 0.65, 'tau_s1': 2.7342, 'tau_s2': 3, 'k_s': 2.0994, 'u_s': 0.9087, 'tau_si': 2.8723, 'tau_winf': 0.07, 'w_infstar': 0.94}}, 'example discretisation': {'dt': 0.025, 'dx': 0.26, 'stimulus': 0.41}, 'units': {'t': 'ms', 'x': 'mm', 'u': 1}, 'code': 'const Real Hthvm = (u - theta_vm > 0) ? 1 : 0;\nconst Real Hthw = (u - theta_w > 0) ? 1 : 0;\nconst Real Hth0 = (u - theta_0 > 0) ? 1 : 0;\nconst Real Hthv = (u - theta_v > 0) ? 1 : 0;\n\nconst Real Hkm = (1 + tanh(k_wm * (u-u_wm))) / 2;\nconst Real Hko = (1 + tanh(k_so * (u-u_so))) / 2;\nconst Real Hks = (1 + tanh(k_s * (u-u_s))) / 2;\n\nconst Real tau_vm = tau_v1m + Hthvm*(tau_v2m-tau_v1m);\nconst Real tau_wm = tau_w1m + (tau_w2m-tau_w1m)*Hkm;\nconst Real tau_so = tau_so1 + (tau_so2-tau_so1)*Hko;\nconst Real tau_s = tau_s1 + Hthw*(tau_s2-tau_s1);\nconst Real tau_o = tau_o1 + Hth0*(tau_o2-tau_o1);\n\nconst Real vinf = 1 - Hthvm;\nconst Real winf = (1-Hth0)*(1-u/tau_winf) + Hth0*w_infstar;\n\nconst Real Jfi = -v*Hthv*(u-theta_v)*(u_u-u)/tau_fi;\nconst Real Jso = (theta_w>u) ? (u-u0)/tau_o : 1.0/tau_so;\nconst Real Jsi = -Hthw*w*s/tau_si;\n\nconst Real U = -(Jfi + Jso + Jsi);\nconst Real V = (theta_v>u) ? (vinf-v)/tau_vm : - v/tau_vp;\nconst Real W = (theta_w>u) ? (winf-w)/tau_wm : - w/tau_wp;\nconst Real S = (Hks-s)/tau_s;\n\n*_new_u = u + dt * (U + _diffuse_u);\n*_new_v = v + dt * V;\n*_new_w = w + dt * W;\n*_new_s = s + dt * S;\n'}, 'courtemanche1998ionic': {'name': 'Courtemanche et al. 1998', 'description': 'The human atrial electrophysiology model by Courtemanche, Ramirez and Nattel\n1998 is widely used in both single-cell and tissue-level simulations,\nparticularly in studies of atrial fibrillation and action potential dynamics.\nAs one of the first detailed and extensively validated atrial model, it is\nconsidered a benchmark in the field of cardiac electrophysiology.\n\nSuggested parameters: dt = 0.005ms, dx = 0.25mm, diffusivity = 0.1544 mm^2/ms.\n', 'dois': ['https://doi.org/10.1152/ajpheart.1998.275.1.H301'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human', 'atria'], 'diffusivity': {'V': 1.0}, 'variables': {'V': -81.18, 'Na_i': 11.17, 'K_i': 139.0, 'Ca_i': 0.0001013, 'Ca_up': 1.488, 'Ca_rel': 1.488, 'm': 0.002908, 'h': 0.9649, 'j': 0.9775, 'oa': 0.03043, 'oi': 0.9992, 'ua': 0.004966, 'ui': 0.9986, 'xr': 3.296e-05, 'xs': 0.01869, 'd': 0.0001367, 'f': 0.9996, 'f_Ca': 0.7755, 'u': 0.0, 'v': 1.0, 'w': 0.9992}, 'parameters': {'T': 310.0, 'F': 96.4867, 'R': 8.3143, 'Cm': 100.0, 'V_rel': 96.48, 'V_i': 13668.0, 'V_up': 1109.52, 'sigma': 1.0009103049457284, 'Ca_o': 1.8, 'K_o': 5.4, 'Na_o': 140.0, 'g_Na': 7.8, 'g_K1': 0.09, 'g_to': 0.1652, 'K_Q10': 3.0, 'g_Kr': 0.029411765, 'g_Ks': 0.12941176, 'g_Ca_L': 0.12375, 'ical_f_Ca_tau': 2.0, 'i_NaK_max': 0.59933874, 'Km_Na_i': 10.0, 'Km_K_o': 1.5, 'I_NaCa_max': 1600.0, 'inaca_gamma': 0.35, 'K_mNa': 87.5, 'K_mCa': 1.38, 'K_sat': 0.1, 'g_B_Na': 0.0006744375, 'g_B_Ca': 0.001131, 'g_B_K': 0.0, 'i_PCa_max': 0.275, 'I_up_max': 0.005, 'K_up': 0.00092, 'Ca_up_max': 15.0, 'cajsr_u_tau': 8.0, 'tau_tr': 180.0, 'K_rel': 30.0, 'CMDN_max': 0.05, 'CSQN_max': 10.0, 'TRPN_max': 0.07, 'Km_CMDN': 0.00238, 'Km_CSQN': 0.8, 'Km_TRPN': 0.0005}, 'extra parameters': {'V_cell': 20100.0}, 'example discretisation': {'dt': 0.029, 'dx': 0.48, 'stimulus': 35.0}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}, 'code': '// extracellular currents\n// calculate i_Na\nconst Real ina_j_beta = ((V < -40.0) ? 0.1212 * exp(-0.01052 * V) / (1.0 + exp(-0.1378 * (V + 40.14))) : 0.3 * exp(-2.535e-07 * V) / (1.0 + exp(-0.1 * (V + 32.0))));\nconst Real ina_j_alpha = ((V < -40.0) ? (-127140.0 * exp(0.2444 * V) - 3.474e-05 * exp(-0.04391 * V)) * (V + 37.78) / (1.0 + exp(0.311 * (V + 79.23))) : 0.0);\nconst Real ina_j_tau = 1.0 / (ina_j_alpha + ina_j_beta);\nconst Real ina_j_inf = ina_j_alpha / (ina_j_alpha + ina_j_beta);\n*_new_j = ina_j_inf + (j - ina_j_inf)*exp(-dt/ina_j_tau);\n\nconst Real ina_m_beta = 0.08 * exp(-V / 11.0);\n// (singularity)\nconst Real ina_m_alpha = ((fabs(V + 47.13) < 1e-5) ? 3.2 : 0.32 * (V + 47.13) / (1.0 - exp(-0.1 * (V + 47.13))));\nconst Real ina_m_inf = ina_m_alpha / (ina_m_alpha + ina_m_beta);\nconst Real ina_m_tau = 1.0 / (ina_m_alpha + ina_m_beta);\n*_new_m = ina_m_inf + (m - ina_m_inf)*exp(-dt/ina_m_tau);\n\nconst Real ina_h_alpha = ((V < -40.0) ? 0.135 * exp((V + 80.0) / -6.8) : 0.0);\nconst Real ina_h_beta = ((V < -40.0) ? 3.56 * exp(0.079 * V) + 310000.0 * exp(0.35 * V) : 1.0 / (0.13 * (1.0 + exp((V + 10.66) / -11.1))));\nconst Real ina_h_inf = ina_h_alpha / (ina_h_alpha + ina_h_beta);\nconst Real ina_h_tau = 1.0 / (ina_h_alpha + ina_h_beta);\n*_new_h = ina_h_inf + (h - ina_h_inf)*exp(-dt/ina_h_tau);\n\nconst Real E_Na = R * T / F * log(Na_o / Na_i);\nconst Real i_Na =  Cm * g_Na * m*m*m * h * j * (V - E_Na);\n\n// calculate i_K1\nconst Real E_K = R * T / F * log(K_o / K_i);\nconst Real i_K1 = Cm * g_K1 * (V - E_K) / (1.0 + exp(0.07 * (V + 80.0)));\n\n// calculate i_to\nconst Real ito_oi_beta = pow(35.56 + 1.0 * exp((V - -10.0 - 8.74) / -7.44), -1.0);\nconst Real ito_oi_alpha = pow(18.53 + 1.0 * exp((V - -10.0 + 103.7) / 10.95), -1.0);\nconst Real ito_oi_inf = pow(1.0 + exp((V - -10.0 + 33.1) / 5.3), -1.0);\nconst Real ito_oi_tau = pow(ito_oi_alpha + ito_oi_beta, -1.0) / K_Q10;\n*_new_oi = ito_oi_inf + (oi - ito_oi_inf)*exp(-dt/ito_oi_tau);\n\nconst Real ito_oa_alpha = 0.65 / (exp((V - -10.0) / -8.5) + exp((V - -10.0 - 40.0) / -59.0));\nconst Real ito_oa_beta = 0.65 / (2.5 + exp((V - -10.0 + 72.0) / 17.0));\nconst Real ito_oa_inf = pow(1.0 + exp((V - -10.0 + 10.47) / -17.54), -1.0);\nconst Real ito_oa_tau = pow(ito_oa_alpha + ito_oa_beta, -1.0) / K_Q10;\n*_new_oa = ito_oa_inf + (oa - ito_oa_inf)*exp(-dt/ito_oa_tau);\n\nconst Real i_to = Cm * g_to * oa*oa*oa * oi * (V - E_K);\n\n// calculate i_Kur\nconst Real ikur_ua_inf = pow(1.0 + exp((V - -10.0 + 20.3) / -9.6), -1.0);\nconst Real ikur_ua_beta = 0.65 / (2.5 + exp((V - -10.0 + 72.0) / 17.0));\nconst Real ikur_ua_alpha = 0.65 / (exp((V - -10.0) / -8.5) + exp((V - -10.0 - 40.0) / -59.0));\nconst Real ikur_ua_tau = pow(ikur_ua_alpha + ikur_ua_beta, -1.0) / K_Q10;\n*_new_ua = ikur_ua_inf + (ua - ikur_ua_inf)*exp(-dt/ikur_ua_tau);\n\nconst Real ikur_ui_inf = pow(1.0 + exp((V - -10.0 - 109.45) / 27.48), -1.0);\nconst Real ikur_ui_tau_alpha = pow(21.0 + 1.0 * exp((V - -10.0 - 195.0) / -28.0), -1.0);\nconst Real ikur_ui_tau_beta = 1.0 / exp((V - -10.0 - 168.0) / -16.0);\nconst Real ikur_ui_tau = pow(ikur_ui_tau_alpha + ikur_ui_tau_beta, -1.0) / K_Q10;\n*_new_ui = ikur_ui_inf + (ui - ikur_ui_inf)*exp(-dt/ikur_ui_tau);\n\nconst Real g_Kur = 0.005 + 0.05 / (1.0 + exp((V - 15.0) / -13.0));\n\nconst Real i_Kur = Cm * g_Kur * ua*ua*ua * ui * (V - E_K);\n\n// calculate i_Kr\nconst Real ikr_xr_inf = pow(1.0 + exp((V + 14.1) / -6.5), -1.0);\n// (singularity)\nconst Real ikr_xr_tau_beta = ((fabs(V - 3.3328) < 1e-5) ? 3.7836118e-04 : 7.3898e-05 * (V - 3.3328) / (exp((V - 3.3328) / 5.1237) - 1.0));\nconst Real ikr_xr_tau_alpha = ((fabs(V + 14.1) < 1e-5) ? 0.0015 : 0.0003 * (V + 14.1) / (1.0 - exp((V + 14.1) / -5.0)));\nconst Real ikr_xr_tau = pow(ikr_xr_tau_alpha + ikr_xr_tau_beta, -1.0);\n*_new_xr = ikr_xr_inf + (xr - ikr_xr_inf)*exp(-dt/ikr_xr_tau);\n\nconst Real i_Kr = Cm * g_Kr * xr * (V - E_K) / (1.0 + exp((V + 15.0) / 22.4));\n\n// calculate i_Ks\nconst Real iks_xs_inf = pow(1.0 + exp((V - 19.9) / -12.7), -0.5);\n// (singularity)\nconst Real iks_xs_tau_beta = ((fabs(V - 19.9) < 1e-5) ? 0.000315 : 3.5e-05 * (V - 19.9) / (exp((V - 19.9) / 9.0) - 1.0));\nconst Real iks_xs_tau_alpha = ((fabs(V - 19.9) < 1e-5) ? 0.00068 : 4e-05 * (V - 19.9) / (1.0 - exp((V - 19.9) / -17.0)));\nconst Real iks_xs_tau = 0.5 / (iks_xs_tau_alpha + iks_xs_tau_beta);\n*_new_xs = iks_xs_inf + (xs - iks_xs_inf)*exp(-dt/iks_xs_tau);\nconst Real i_Ks = Cm * g_Ks * xs*xs * (V - E_K);\n\n// calculate i_Ca_L\nconst Real ical_f_inf = exp(-(V + 28.0) / 6.9) / (1.0 + exp(-(V + 28.0) / 6.9));\nconst Real ical_f_tau = 9.0 * pow(0.0197 * exp(-pow(0.0337, 2.0) * pow(V + 10.0, 2.0)) + 0.02, -1.0);\n*_new_f = ical_f_inf + (f - ical_f_inf)*exp(-dt/ical_f_tau);\n\nconst Real ical_f_Ca_inf = pow(1.0 + Ca_i / 0.00035, -1.0);\n*_new_f_Ca = ical_f_Ca_inf + (f_Ca - ical_f_Ca_inf)*exp(-dt/ical_f_Ca_tau);\n\nconst Real ical_d_inf = pow(1.0 + exp((V + 10.0) / -8.0), -1.0);\nconst Real ical_d_tau = ((fabs(V + 10.0) < 1e-10) ? 4.579 / (1.0 + exp((V + 10.0) / -6.24)) : (1.0 - exp((V + 10.0) / -6.24)) / (0.035 * (V + 10.0) * (1.0 + exp((V + 10.0) / -6.24))));\n*_new_d = ical_d_inf + (d - ical_d_inf)*exp(-dt/ical_d_tau);\n\nconst Real i_Ca_L = Cm * g_Ca_L * d * f * f_Ca * (V - 65.0);\n\n// calculate I_B_*\nconst Real E_Ca = R * T / (2.0 * F) * log(Ca_o / Ca_i);\nconst Real i_B_K = Cm * g_B_K * (V - E_K);\nconst Real i_B_Ca = Cm * g_B_Ca * (V - E_Ca);\nconst Real i_B_Na = Cm * g_B_Na * (V - E_Na);\n\n// calculate i_NaK\nconst Real f_NaK = pow(1.0 + 0.1245 * exp(-0.1 * F * V / (R * T)) + 0.0365 * sigma * exp(-F * V / (R * T)), -1.0);\nconst Real i_NaK = Cm * i_NaK_max * f_NaK * 1.0 / (1.0 + pow(Km_Na_i / Na_i, 1.5)) * K_o / (K_o + Km_K_o);\n\n// calculate i_PCa\nconst Real i_PCa = Cm * i_PCa_max * Ca_i / (0.0005 + Ca_i);\n\n// calculate i_NaCa\nconst Real i_NaCa = Cm * I_NaCa_max * (exp(inaca_gamma * F * V / (R * T)) * Na_i*Na_i*Na_i * Ca_o - exp((inaca_gamma - 1.0) * F * V / (R * T)) * Na_o*Na_o*Na_o * Ca_i) / ((K_mNa*K_mNa*K_mNa + Na_o*Na_o*Na_o) * (K_mCa + Ca_o) * (1.0 + K_sat * exp((inaca_gamma - 1.0) * V * F / (R * T))));\n\n// misc\nconst Real i_up = I_up_max / (1.0 + K_up / Ca_i);\nconst Real i_up_leak = I_up_max * Ca_up / Ca_up_max;\nconst Real i_tr = (Ca_up - Ca_rel) / tau_tr;\n\n// intracellular Ca-currents\nconst Real i_rel = K_rel * u*u * v * w * (Ca_rel - Ca_i);\nconst Real cajsr_w_inf = 1.0 - pow(1.0 + exp(-(V - 40.0) / 17.0), -1.0);\nconst Real cajsr_w_tau = (fabs(V - 7.9) < 1e-4) ? 6.0 * 0.2 / 1.3 : 6.0 * (1.0 - exp(-(V - 7.9) / 5.0)) / ((1.0 + 0.3 * exp(-(V - 7.9) / 5.0)) * 1.0 * (V - 7.9));\n*_new_w = cajsr_w_inf + (w - cajsr_w_inf)*exp(-dt/cajsr_w_tau);\n\nconst Real Fn = 1000.0 * (1e-15 * V_rel * i_rel - 1e-15 / (2.0 * F) * (0.5 * i_Ca_L - 0.2 * i_NaCa));\nconst Real cajsr_v_inf = 1.0 - pow(1.0 + exp(-(Fn - 6.835e-14) / 1.367e-15), -1.0);\nconst Real cajsr_v_tau = 1.91 + 2.09 / (1.0 + exp(-(Fn - 3.4175e-13) / 1.367e-15));\n*_new_v = cajsr_v_inf + (v - cajsr_v_inf)*exp(-dt/cajsr_v_tau);\n\nconst Real cajsr_u_inf = pow(1.0 + exp(-(Fn - 3.4175e-13) / 1.367e-15), -1.0);\n*_new_u = cajsr_u_inf + (u - cajsr_u_inf)*exp(-dt/cajsr_u_tau);\n\n// total current\nconst Real i_ion = i_Na + i_K1 + i_to + i_Kur + i_Kr + i_Ks + i_B_Na + i_B_Ca + i_NaK + i_PCa + i_NaCa + i_Ca_L;\n\n// update concentrations\n*_new_Na_i = Na_i + dt * ((-3.0 * i_NaK - (3.0 * i_NaCa + i_B_Na + i_Na)) / (V_i * F));\n*_new_K_i = K_i + dt * ((2.0 * i_NaK - (i_K1 + i_to + i_Kur + i_Kr + i_Ks + i_B_K)) / (V_i * F));\n*_new_Ca_rel = Ca_rel + dt * ((i_tr - i_rel) * pow(1.0 + CSQN_max * Km_CSQN / pow(Ca_rel + Km_CSQN, 2.0), -1.0));\n*_new_Ca_up = Ca_up + dt * (i_up - (i_up_leak + i_tr * V_rel / V_up));\n*_new_Ca_i = Ca_i + dt * ((2.0 * i_NaCa - (i_PCa + i_Ca_L + i_B_Ca)) / (2.0 * V_i * F) + (V_up * (i_up_leak - i_up) + i_rel * V_rel) / V_i) / (1.0 + TRPN_max * Km_TRPN / pow(Ca_i + Km_TRPN, 2.0) + CMDN_max * Km_CMDN / pow(Ca_i + Km_CMDN, 2.0));\n\n// update voltage\n*_new_V = V + dt * (_diffuse_V - i_ion/Cm);\n'}, 'fenton1998vortex': {'name': 'Fenton & Karma 1998', 'description': 'A simplified ionic model with three membrane currents that approximates well\nthe restitution properties and spiral wave behavior of more complex ionic\nmodels of cardiac action potential (Beeler-Reuter and others)\n\nThe transmembrane potential can be found using the relation:\n``Vm = V_0 + u * (V_fi - V_0)``.\n', 'dois': ['https://doi.org/10.1063/1.166311'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'phenomenological'], 'variables': {'u': 0, 'v': 1, 'w': 1}, 'diffusivity': {'u': 1}, 'extra parameters': {'V_0': -85, 'V_fi': 15, 'g_fi_max': 'C_m/tau_d', 'C_m': 1}, 'metadata for parameter sets': {'BR': {'name': 'Beeler Reuter', 'dois': ['https://doi.org/10.1113/jphysiol.1977.sp011853', 'https://doi.org/10.1063/1.166311']}, 'MBR': {'name': 'Modified Beeler Reuter', 'dois': ['https://doi.org/10.1113/jphysiol.1977.sp011853', 'https://doi.org/10.1063/1.166311']}, 'MLR-I': {'name': 'Luo Rudy', 'dois': ['https://doi.org/10.1161/01.RES.68.6.1501', 'https://doi.org/10.1063/1.166311']}, 'GP': {'name': 'Girouard guinea pig', 'dois': ['https://doi.org/10.1161/01.CIR.93.3.603', 'https://doi.org/10.1063/1.166311']}, 'others': {'name': 'More parameters sets from Fenton et al. 2022.', 'note': 'In this paper, `tau_vm1` and `tau_vm2` have swapped names.\n', 'dois': ['https://doi.org/10.1063/1.1504242']}}, 'parameter sets': {'BR': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.25, 'tau_r': 33, 'tau_si': 30, 'tau_vm1': 1250, 'tau_vm2': 19.6, 'tau_vp': 3.33, 'tau_wm': 41, 'tau_wp': 870, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.04, 'C_si': 1}, 'MBR': {'k': 10, 'tau_0': 8.3, 'tau_d': 0.25, 'tau_r': 50, 'tau_si': 45, 'tau_vm1': 1000, 'tau_vm2': 19.2, 'tau_vp': 3.33, 'tau_wm': 11, 'tau_wp': 667, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.055, 'C_si': 1}, 'MLR-I': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.172, 'tau_r': 130, 'tau_si': 127, 'tau_vm1': 18.2, 'tau_vm2': 18.2, 'tau_vp': 10, 'tau_wm': 80, 'tau_wp': 1020, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0, 'C_si': 1}, 'GP': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.115, 'tau_r': 25, 'tau_si': 22, 'tau_vm1': 333, 'tau_vm2': 40, 'tau_vp': 10, 'tau_wm': 65, 'tau_wp': 1000, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.025, 'C_si': 1}, 'Set 1': {'k': 10, 'tau_0': 8.3, 'tau_d': 0.42, 'tau_r': 50, 'tau_si': 45, 'tau_vm1': 1000, 'tau_vm2': 19.6, 'tau_vp': 3.33, 'tau_wm': 11, 'tau_wp': 667, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.055, 'C_si': 1}, 'Set 2': {'k': 10, 'tau_0': 10, 'tau_d': 0.25, 'tau_r': 190, 'tau_si': 45, 'tau_vm1': 10, 'tau_vm2': 10, 'tau_vp': 10, 'tau_wm': 11, 'tau_wp': 667, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.055, 'C_si': 0}, 'Set 3': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.25, 'tau_r': 33.33, 'tau_si': 29, 'tau_vm1': 1250, 'tau_vm2': 19.6, 'tau_vp': 3.33, 'tau_wm': 41, 'tau_wp': 870, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.04, 'C_si': 1}, 'Set 4': {'k': 15, 'tau_0': 9, 'tau_d': 0.407, 'tau_r': 34, 'tau_si': 26.5, 'tau_vm1': 5, 'tau_vm2': 15.6, 'tau_vp': 3.33, 'tau_wm': 80, 'tau_wp': 350, 'u_c': 0.15, 'u_csi': 0.45, 'u_v': 0.04, 'C_si': 1}, 'Set 5': {'k': 15, 'tau_0': 5, 'tau_d': 0.362, 'tau_r': 33.33, 'tau_si': 29, 'tau_vm1': 2, 'tau_vm2': 12, 'tau_vp': 3.33, 'tau_wm': 100, 'tau_wp': 1000, 'u_c': 0.13, 'u_csi': 0.7, 'u_v': 0.04, 'C_si': 1}, 'Set 6': {'k': 15, 'tau_0': 9, 'tau_d': 0.395, 'tau_r': 33.33, 'tau_si': 29, 'tau_vm1': 8, 'tau_vm2': 9, 'tau_vp': 3.33, 'tau_wm': 60, 'tau_wp': 250, 'u_c': 0.13, 'u_csi': 0.5, 'u_v': 0.04, 'C_si': 1}, 'Set 7': {'k': 15, 'tau_0': 12, 'tau_d': 0.25, 'tau_r': 100, 'tau_si': 29, 'tau_vm1': 7, 'tau_vm2': 7, 'tau_vp': 10, 'tau_wm': 60, 'tau_wp': 250, 'u_c': 0.13, 'u_csi': 0.5, 'u_v': 0.04, 'C_si': 0}, 'Set 8': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.45, 'tau_r': 33.25, 'tau_si': 29, 'tau_vm1': 1250, 'tau_vm2': 19.6, 'tau_vp': 13.03, 'tau_wm': 40, 'tau_wp': 800, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.04, 'C_si': 1}, 'Set 9': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.25, 'tau_r': 28, 'tau_si': 29, 'tau_vm1': 2, 'tau_vm2': 15, 'tau_vp': 3.33, 'tau_wm': 61, 'tau_wp': 670, 'u_c': 0.13, 'u_csi': 0.45, 'u_v': 0.05, 'C_si': 1}, 'Set 10': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.115, 'tau_r': 25, 'tau_si': 22.22, 'tau_vm1': 333, 'tau_vm2': 40, 'tau_vp': 10, 'tau_wm': 65, 'tau_wp': 1000, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.025, 'C_si': 1}}, 'parameters': {'k': 10, 'tau_0': 12.5, 'tau_d': 0.25, 'tau_r': 33.33, 'tau_si': 29, 'tau_vm1': 1250, 'tau_vm2': 19.6, 'tau_vp': 3.33, 'tau_wm': 41, 'tau_wp': 870, 'u_c': 0.13, 'u_csi': 0.85, 'u_v': 0.04, 'C_si': 1}, 'example discretisation': {'dt': 0.21, 'dx': 1.3, 'stimulus': 0.2}, 'units': {'t': 'ms', 'x': 'mm', 'u': 1}, 'code': 'const Real tc = u >= u_c;\nconst Real tv = u >= u_v;\nconst Real tc_ = 1.0 - tc;\nconst Real tv_ = 1.0 - tv;\nconst Real tau_vm = tv * tau_vm1 + tv_ * tau_vm2;\nconst Real Jfi = -v * tc * (1.0 - u) * (u - u_c) / tau_d;\nconst Real Jsi = C_si * ( -w * (1.0 + tanh(k * (u - u_csi))) / (2.0 * tau_si));\nconst Real Jso = u * tc_ / tau_0 + tc / tau_r;\n*_new_u = u + dt*(_diffuse_u - (Jfi + Jso + Jsi));\n*_new_v = v + dt*(tc_ * (1.0 - v) / tau_vm - tc * v / tau_vp);\n*_new_w = w + dt*(tc_ * (1.0 - w) / tau_wm - tc * w / tau_wp);\n'}, 'gray1983autocatalytic': {'name': 'Gray & Scott 1982', 'description': 'One of the two variable reaction-diffusion models presented in the article\n"Autocatalytic reactions in the isothermal, continuous stirred tank\nreactor: isolas and other forms of multistability". Depending on the\nparameters, different patterns can be seen to form in its solutions.\n\nIt describes the chemical reactions:\n\n.. math::\n\n  U + 2V &\\to 3V\n  \\\\\n  V &\\to P\n\n- ``u``, ``v``: concentrations of :math:`U`, :math:`V`.\n- ``k``: rate of conversion of :math:`V` to :math:`P`.\n- ``f``: rate of the process that feeds :math:`U` and\n  drains :math:`U`, :math:`V`, and :math:`P`.\n', 'keywords': ['pattern formation'], 'dois': ['https://doi.org/10.1016/0009-2509(83)80132-8'], 'variables': {'u': 1.0, 'v': 0.0}, 'diffusivity': {'u': 1, 'v': 0.5}, 'parameters': {'f': 0.055, 'k': 0.062}, 'example discretisation': {'dt': 0.1, 'dx': 1.0, 'stimulus': 0.4}, 'units': {'t': 1, 'x': 1, 'u': 1}, 'code': 'const Real uvv = u * v * v;\nconst Real U = -uvv + f * (1 - u);\nconst Real V = uvv - (f + k) * v;\n\n*_new_u = u + dt * (U + _diffuse_u);\n*_new_v = v + dt * (V + _diffuse_v);\n'}, 'hodgkin1952quantitative': {'name': 'Hodgkin & Huxley 1952', 'description': 'This model describes the electrical conduction in giant nerve fibre of\nsquids. It is one of the first mathematical models of electrophysiology.', 'dois': ['https://doi.org/10.1113/jphysiol.1952.sp004764'], 'variables': {'V': -75.0, 'n': 0.317, 'm': 0.05, 'h': 0.595}, 'parameters': {'engine_pace': 0.0, 'leak_Eleak': -64.387, 'leak_g_max': 0.3, 'potassium_Ek': -87.0, 'potassium_g_max': 36.0, 'sodium_ENa': 40.0, 'sodium_g_max': 120.0, 'membrane_A': 100.0, 'membrane_C': 1.0, 'membrane_Vhold': -60.0}, 'keywords': ['excitable media', 'electrophysiology', 'squid'], 'diffusivity': {'V': 1.0}, 'code': '// leak\nconst Real leak_i = leak_g_max * (V - leak_Eleak);\n\n// potassium\nconst Real potassium_n_a = 0.01 * (-V - 65.0) / ((fabs(exp((-V - 65.0) / 10.0) - 1.0) < VERY_SMALL_NUMBER) ? ((exp((-V - 65.0) / 10.0) - 1.0 < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : exp((-V - 65.0) / 10.0) - 1.0);\nconst Real potassium_n_b = 0.125 * exp((-V - 75.0) / 80.0);\n*_new_n = n + dt*(potassium_n_a * (1.0 - n) - potassium_n_b * n);\nconst Real potassium_i = potassium_g_max * pow(n, 4.0) * (V - potassium_Ek);\n\n// sodium\nconst Real sodium_h_a = 0.07 * exp((-V - 75.0) / 20.0);\nconst Real sodium_h_b = 1.0 / ((fabs(exp((-V - 45.0) / 10.0) + 1.0) < VERY_SMALL_NUMBER) ? ((exp((-V - 45.0) / 10.0) + 1.0 < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : exp((-V - 45.0) / 10.0) + 1.0);\n*_new_h = h + dt*(sodium_h_a * (1.0 - h) - sodium_h_b * h);\nconst Real sodium_m_a = 0.1 * (-V - 50.0) / ((fabs(exp((-V - 50.0) / 10.0) - 1.0) < VERY_SMALL_NUMBER) ? ((exp((-V - 50.0) / 10.0) - 1.0 < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : exp((-V - 50.0) / 10.0) - 1.0);\nconst Real sodium_m_b = 4.0 * exp((-V - 75.0) / 18.0);\n*_new_m = m + dt*(sodium_m_a * (1.0 - m) - sodium_m_b * m);\nconst Real sodium_i = sodium_g_max * pow(m, 3.0) * h * (V - sodium_ENa);\n\n// membrane\nconst Real membrane_i_stim = (V - membrane_Vhold) * membrane_A * engine_pace;\n*_new_V = V + dt*(-(1.0 / membrane_C) * (sodium_i + potassium_i + leak_i + membrane_i_stim) + _diffuse_V);', 'extra parameters': {'engine_time': 0.0}, 'example discretisation': {'dt': 0.005, 'dx': 0.2, 'stimulus': 15.0}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}}, 'kabus2024fast': {'name': 'Kabus et al. 2024', 'description': 'This data-driven model was trained on optical voltage mapping data\nof human conditionally immortalised atrial myocyte (hiAM) monolayers.\nIt uses a simple polynomial, a standard-deviation-based approximation for the\ngradient, and an exponential moving average to predict the updated value\nof the signal. As it can work with much higher time steps, it is computationally\ncheaper than the reaction-diffusion based models.\n', 'dois': ['https://doi.org/10.1016/j.compbiomed.2024.107949'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'data-driven'], 'variables': {'u': 0.02, 'a': 0.1, 'g': 0.0}, 'diffusivity': {}, 'parameter sets': {'aliev1996simple': {'umin': 0.0, 'umax': 1.0, 'alpha': 0.03, 'dist': 5, 'wagu': -0.22407, 'wag': -0.82589, 'wau': 0.0054601, 'wa': 0.021655, 'wgu': 0.31082, 'wg': 0.23077, 'wu': -0.0081478, 'w': -0.009711}, 'optical': {'umin': -0.5, 'umax': 1.25, 'alpha': 0.008, 'dist': 8, 'wagu': -0.413919278037366, 'wgu': 0.193407562922741, 'wau': 0.0263083048287399, 'wa': 0.00109492883763741, 'wag': -0.318420911707539, 'wg': 0.153524735108221, 'wu': -0.0141740647636319, 'w': -0.00448181394403335}}, 'parameters': {'umin': -0.5, 'umax': 1.25, 'alpha': 0.008, 'dist': 8, 'wagu': -0.413919278037366, 'wgu': 0.193407562922741, 'wau': 0.0263083048287399, 'wa': 0.00109492883763741, 'wag': -0.318420911707539, 'wg': 0.153524735108221, 'wu': -0.0141740647636319, 'w': -0.00448181394403335}, 'code': 'const Real f = wagu*a*g*u + wag*a*g + wau*a*u + wa*a + wgu*g*u + wg*g + wu*u + w;\n\n*_new_u = u + dt * f;\n\nif(*_new_u < umin) { *_new_u = umin; }\nif(*_new_u > umax) { *_new_u = umax; }\n\nconst Real alpha_= alpha/dt;\n*_new_a = alpha_*(*_new_u) + (1 - alpha_)*a;\n\nconst Int dist_ = dist + 0.5;\nSize sum0 = 0;\nReal sum1 = 0;\nReal sum2 = 0;\nfor(Int iy=-dist_; iy<=dist_; iy++) {\n  for(Int ix=-dist_; ix<=dist_; ix++) {\n    if((iy*iy + ix*ix) <= dist*dist) {\n      const Real u_ = _r(_x(ix, _y(iy, states_old)));\n      if(isfinite(u_)) {\n        sum0 += 1;\n        sum1 += u_;\n        sum2 += u_*u_;\n      }\n    }\n  }\n}\nif(sum0 > 0) {\n  const Real avg = sum1/sum0;\n  const Real var = sum2/sum0 - avg*avg;\n  *_new_g = sqrt(var > 0.0 ? var : 0.0);\n} else {\n  *_new_g = 0.0;\n}\n'}, 'luo1991model': {'name': 'Luo & Rudy 1991', 'description': 'This model is a significant update of the Beeler-Reuter mammalian ventricular\nmodel (1977), and like the Beeler-Reuter model, the Luo-Rudy I model uses\nHodgkin-Huxley type equations to calculate ionic currents.\n', 'dois': ['https://doi.org/10.1161/01.res.68.6.1501'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human', 'ventricle'], 'variables': {'V': -84.3801107371, 'm': 0.00171338077730188, 'h': 0.982660523699656, 'j': 0.989108212766685, 'd': 0.00302126301779861, 'f': 0.999967936476325, 'X': 0.0417603108167287, 'Cai': 0.00017948816388306}, 'diffusivity': {'V': 1.0}, 'parameters': {'background_current_E_b': -59.87, 'background_current_g_b': 0.03921, 'environment_time': 0.0, 'membrane_C': 1.0, 'membrane_stim_amplitude': -25.5, 'membrane_stim_duration': 2.0, 'membrane_stim_end': 9000.0, 'membrane_stim_period': 1000.0, 'membrane_stim_start': 100.0, 'fast_sodium_current_E_Na': 54.79446393509185, 'fast_sodium_current_g_Na': 23.0, 'slow_inward_current_g_si': 0.09, 'time_dependent_potassium_current_g_K': 0.282, 'time_dependent_potassium_current_E_K': -77.56758438531939, 'time_independent_potassium_current_E_K1': -87.8929017138025, 'time_independent_potassium_current_g_K1': 0.6047, 'plateau_potassium_current_E_Kp': -87.8929017138025, 'plateau_potassium_current_g_Kp': 0.0183, 'ionic_concentrations_Ko': 5.4}, 'extra parameters': {'ionic_concentrations_Ki': 145.0, 'ionic_concentrations_Nai': 18.0, 'ionic_concentrations_Nao': 140.0, 'membrane_F': 96484.6, 'membrane_R': 8314.0, 'membrane_T': 310.0, 'time_dependent_potassium_current_PR_NaK': 0.01833}, 'example discretisation': {'dt': 0.016, 'dx': 0.48, 'stimulus': 60.4}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}, 'code': '// background_current\nconst Real background_current_i_b = background_current_g_b * (V - background_current_E_b);\n\n// fast_sodium_current_h_gate\nconst Real fast_sodium_current_h_gate_alpha_h = ((V < -40.0) ? 0.135 * exp((80.0 + V) / -6.8) : 0.0);\nconst Real fast_sodium_current_h_gate_beta_h = ((V < -40.0) ? 3.56 * exp(0.079 * V) + 310000.0 * exp(0.35 * V) : 1.0 / ((fabs(0.13 * (1.0 + exp((V + 10.66) / -11.1))) < VERY_SMALL_NUMBER) ? ((0.13 * (1.0 + exp((V + 10.66) / -11.1)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 0.13 * (1.0 + exp((V + 10.66) / -11.1))));\nconst Real tau_h = 1.0 / (fast_sodium_current_h_gate_alpha_h + fast_sodium_current_h_gate_beta_h);\nconst Real h_inf = fast_sodium_current_h_gate_alpha_h * tau_h;\n*_new_h = h_inf + (h - h_inf) * exp(-dt / tau_h);\n\n// fast_sodium_current_j_gate\nconst Real fast_sodium_current_j_gate_alpha_j = ((V < -40.0) ? (-127140.0 * exp(0.2444 * V) - 3.474e-05 * exp(-0.04391 * V)) * (V + 37.78) / ((fabs(1.0 + exp(0.311 * (V + 79.23))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(0.311 * (V + 79.23)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(0.311 * (V + 79.23))) : 0.0);\nconst Real fast_sodium_current_j_gate_beta_j = ((V < -40.0) ? 0.1212 * exp(-0.01052 * V) / ((fabs(1.0 + exp(-0.1378 * (V + 40.14))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(-0.1378 * (V + 40.14)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(-0.1378 * (V + 40.14))) : 0.3 * exp(-2.535e-07 * V) / ((fabs(1.0 + exp(-0.1 * (V + 32.0))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(-0.1 * (V + 32.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(-0.1 * (V + 32.0))));\nconst Real tau_j = 1.0 / (fast_sodium_current_j_gate_alpha_j + fast_sodium_current_j_gate_beta_j);\nconst Real j_inf = fast_sodium_current_j_gate_alpha_j * tau_j;\n*_new_j = j_inf + (j - j_inf) * exp(-dt / tau_j);\n\n// fast_sodium_current_m_gate\nconst Real fast_sodium_current_m_gate_alpha_m = 0.32 * (V + 47.13) / ((fabs(1.0 - exp(-0.1 * (V + 47.13))) < VERY_SMALL_NUMBER) ? ((1.0 - exp(-0.1 * (V + 47.13)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 - exp(-0.1 * (V + 47.13)));\nconst Real fast_sodium_current_m_gate_beta_m = 0.08 * exp(-V / 11.0);\nconst Real tau_m = 1.0 / (fast_sodium_current_m_gate_alpha_m + fast_sodium_current_m_gate_beta_m);\nconst Real m_inf = fast_sodium_current_m_gate_alpha_m * tau_m;\n*_new_m = m_inf + (m - m_inf) * exp(-dt / tau_m);\n\n// slow_inward_current\nconst Real slow_inward_current_E_si = 7.7 - 13.0287 * log(Cai / 1.0);\nconst Real slow_inward_current_i_si = slow_inward_current_g_si * d * f * (V - slow_inward_current_E_si);\n\n// slow_inward_current_d_gate\nconst Real slow_inward_current_d_gate_alpha_d = 0.095 * exp(-0.01 * (V - 5.0)) / ((fabs(1.0 + exp(-0.072 * (V - 5.0))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(-0.072 * (V - 5.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(-0.072 * (V - 5.0)));\nconst Real slow_inward_current_d_gate_beta_d = 0.07 * exp(-0.017 * (V + 44.0)) / ((fabs(1.0 + exp(0.05 * (V + 44.0))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(0.05 * (V + 44.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(0.05 * (V + 44.0)));\nconst Real tau_d = 1.0 / (slow_inward_current_d_gate_alpha_d + slow_inward_current_d_gate_beta_d);\nconst Real d_inf = slow_inward_current_d_gate_alpha_d * tau_d;\n*_new_d = d_inf + (d - d_inf) * exp(-dt / tau_d);\n\n// slow_inward_current_f_gate\nconst Real slow_inward_current_f_gate_alpha_f = 0.012 * exp(-0.008 * (V + 28.0)) / ((fabs(1.0 + exp(0.15 * (V + 28.0))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(0.15 * (V + 28.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(0.15 * (V + 28.0)));\nconst Real slow_inward_current_f_gate_beta_f = 0.0065 * exp(-0.02 * (V + 30.0)) / ((fabs(1.0 + exp(-0.2 * (V + 30.0))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(-0.2 * (V + 30.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(-0.2 * (V + 30.0)));\nconst Real tau_f = 1.0 / (slow_inward_current_f_gate_alpha_f + slow_inward_current_f_gate_beta_f);\nconst Real f_inf = slow_inward_current_f_gate_alpha_f * tau_f;\n*_new_f = f_inf + (f - f_inf) * exp(-dt / tau_f);\n\n// time_dependent_potassium_current_X_gate\nconst Real time_dependent_potassium_current_X_gate_alpha_X = 0.0005 * exp(0.083 * (V + 50.0)) / ((fabs(1.0 + exp(0.057 * (V + 50.0))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(0.057 * (V + 50.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(0.057 * (V + 50.0)));\nconst Real time_dependent_potassium_current_X_gate_beta_X = 0.0013 * exp(-0.06 * (V + 20.0)) / ((fabs(1.0 + exp(-0.04 * (V + 20.0))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(-0.04 * (V + 20.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(-0.04 * (V + 20.0)));\nconst Real tau_X = safe_divide(1.0, time_dependent_potassium_current_X_gate_alpha_X + time_dependent_potassium_current_X_gate_beta_X);\nconst Real X_inf = time_dependent_potassium_current_X_gate_alpha_X * tau_X;\n*_new_X = X_inf + (X - X_inf) * exp(-safe_divide(dt, tau_X));\n\n// time_dependent_potassium_current_Xi_gate\nconst Real time_dependent_potassium_current_Xi_gate_Xi = ((V > -100.0) ? 2.837 * (exp(0.04 * (V + 77.0)) - 1.0) / ((fabs((V + 77.0) * exp(0.04 * (V + 35.0))) < VERY_SMALL_NUMBER) ? (((V + 77.0) * exp(0.04 * (V + 35.0)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : (V + 77.0) * exp(0.04 * (V + 35.0))) : 1.0);\n\n// intracellular_calcium_concentration\n*_new_Cai = Cai + dt*(-0.0001 / 1.0 * slow_inward_current_i_si + 0.07 * (0.0001 - Cai));\n\n// membrane\nconst Real membrane_I_stim = ((((environment_time >= membrane_stim_start) && (environment_time <= membrane_stim_end)) && (environment_time - membrane_stim_start - floor((environment_time - membrane_stim_start) / membrane_stim_period) * membrane_stim_period <= membrane_stim_duration)) ? membrane_stim_amplitude : 0.0);\n\n// fast_sodium_current\nconst Real fast_sodium_current_i_Na = fast_sodium_current_g_Na * pow(m, 3.0) * h * j * (V - fast_sodium_current_E_Na);\n\n// time_dependent_potassium_current\nconst Real time_dependent_potassium_current_i_K = time_dependent_potassium_current_g_K * sqrt(ionic_concentrations_Ko/5.4) * X * time_dependent_potassium_current_Xi_gate_Xi * (V - time_dependent_potassium_current_E_K);\n\n// time_independent_potassium_current_K1_gate\nconst Real time_independent_potassium_current_K1_gate_alpha_K1 = 1.02 / ((fabs(1.0 + exp(0.2385 * (V - time_independent_potassium_current_E_K1 - 59.215))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(0.2385 * (V - time_independent_potassium_current_E_K1 - 59.215)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(0.2385 * (V - time_independent_potassium_current_E_K1 - 59.215)));\nconst Real time_independent_potassium_current_K1_gate_beta_K1 = (0.49124 * exp(0.08032 * (V + 5.476 - time_independent_potassium_current_E_K1)) + 1.0 * exp(0.06175 * (V - (time_independent_potassium_current_E_K1 + 594.31)))) / ((fabs(1.0 + exp(-0.5143 * (V - time_independent_potassium_current_E_K1 + 4.753))) < VERY_SMALL_NUMBER) ? ((1.0 + exp(-0.5143 * (V - time_independent_potassium_current_E_K1 + 4.753)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp(-0.5143 * (V - time_independent_potassium_current_E_K1 + 4.753)));\nconst Real time_independent_potassium_current_K1_gate_K1_infinity = time_independent_potassium_current_K1_gate_alpha_K1 / ((fabs(time_independent_potassium_current_K1_gate_alpha_K1 + time_independent_potassium_current_K1_gate_beta_K1) < VERY_SMALL_NUMBER) ? ((time_independent_potassium_current_K1_gate_alpha_K1 + time_independent_potassium_current_K1_gate_beta_K1 < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : time_independent_potassium_current_K1_gate_alpha_K1 + time_independent_potassium_current_K1_gate_beta_K1);\n\n// plateau_potassium_current\nconst Real plateau_potassium_current_Kp = 1.0 / ((fabs(1.0 + exp((7.488 - V) / 5.98)) < VERY_SMALL_NUMBER) ? ((1.0 + exp((7.488 - V) / 5.98) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 1.0 + exp((7.488 - V) / 5.98));\nconst Real plateau_potassium_current_i_Kp = plateau_potassium_current_g_Kp * plateau_potassium_current_Kp * (V - plateau_potassium_current_E_Kp);\n\n// *remaining*\nconst Real time_independent_potassium_current_i_K1 = time_independent_potassium_current_g_K1 * sqrt(ionic_concentrations_Ko/5.4) * time_independent_potassium_current_K1_gate_K1_infinity * (V - time_independent_potassium_current_E_K1);\n*_new_V = V + dt*(-1.0 / membrane_C * (membrane_I_stim + fast_sodium_current_i_Na + slow_inward_current_i_si + time_dependent_potassium_current_i_K + time_independent_potassium_current_i_K1 + plateau_potassium_current_i_Kp + background_current_i_b) + _diffuse_V);\n'}, 'luo1994dynamic': {'name': 'Luo & Rudy 1994', 'description': 'This model provides the basis for the study of arrhythmogenic activity of the\nsingle myocyte including afterdepolarizations and triggered activity (by\nincluding descriptions of Ca2+ regulated currents). It can simulate cellular\nresponses under different degrees of Ca2+ overload.\n', 'dois': ['https://doi.org/10.1161/01.res.74.6.1071'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human', 'ventricle'], 'variables': {'V': -84.624, 'm': 0.0, 'h': 1.0, 'j': 1.0, 'd': 0.0, 'f': 1.0, 'X': 0.0, 'Nai': 10.0, 'Cai': 0.00012, 'Ki': 145.0, 'Ca_JSR': 1.8, 'Ca_NSR': 1.8}, 'diffusivity': {'V': 1.0}, 'parameters': {'f_Ca_Km_Ca': 0.0006, 'I_up': 0.005, 'K_mup': 0.00092, 'tau_tr': 180.0, 'K_leak': 0.0003333333333333333, 'G_rel': -0.0, 'I_pCa': 0.0115, 'K_mpCa': 0.0005, 'P_Ca': 5.4e-06, 'P_K': 1.93e-09, 'P_Na': 6.75e-09, 'gamma_Cai': 1.0, 'gamma_Cao': 0.34, 'gamma_Ki': 0.75, 'gamma_Ko': 0.75, 'gamma_Nai': 0.75, 'gamma_Nao': 0.75, 'K_NaCa': 20.0, 'K_mCa': 1.38, 'K_mNa': 87.5, 'K_sat': 0.1, 'eta': 0.35, 'g_Cab': 3.016e-05, 'g_Na': 0.16, 'Am': 200.0, 'Cao': 1.8, 'Ko': 5.4, 'Nao': 140.0, 'V_JSR': 0.0048, 'V_NSR': 0.0552, 'V_myo': 0.68, 'Cm': 0.01, 'F': 96845.0, 'R': 8314.5, 'T': 310.0, 'K_m_ns_Ca': 0.0012, 'P_ns_Ca': 1.75e-09, 'g_Kp': 0.000183, 'g_Nab': 1.41e-05, 'I_NaK': 0.015, 'K_mKo': 1.5, 'K_mNai': 10.0, 'sigma': 1.0009103049457284, 'PR_NaK': 0.01833, 'g_K': 0.00282, 'g_K1': 0.0075}, 'extra parameters': {'Ca_NSR_max': 15.0, 'G_rel_max': 60.0, 'K_mrel': 0.0008, 'delta_Ca_i2': 0.0, 'delta_Ca_ith': 0.00018, 't_CICR': 0.0, 'tau_off': 2.0, 'tau_on': 2.0, 'G_rel_peak': 0.0, 'g_K_max': 0.00282, 'g_K1_max': 0.0075}, 'example discretisation': {'dt': 0.017, 'dx': 0.76, 'stimulus': 60.9}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}, 'code': '// L type Ca channel d gate\nconst Real d_inf = 1.0 / (1.0 + exp(-((V + 10.0) / 6.24)));\nconst Real tau_d = d_inf * safe_divide(1.0 - exp(-((V + 10.0) / 6.24)), 0.035 * (V + 10.0));\n*_new_d = d_inf + (d - d_inf) * exp(-safe_divide(dt, tau_d));\n\n// L type Ca channel f Ca gate\nconst Real f_Ca_f_Ca = 1.0 / (1.0 + pow(Cai / f_Ca_Km_Ca, 2.0));\n\n// L type Ca channel f gate\nconst Real f_inf = 1.0 / (1.0 + exp((V + 35.06) / 8.6)) + 0.6 / (1.0 + exp((50.0 - V) / 20.0));\nconst Real tau_f = 1.0 / (0.0197 * exp(-pow(0.0337 * (V + 10.0), 2.0)) + 0.02);\n*_new_f = f_inf + (f - f_inf) * exp(-dt / tau_f);\n\n// calcium fluxes in the SR\nconst Real i_tr = (Ca_NSR - Ca_JSR) / tau_tr;\nconst Real i_up = I_up * (Cai / (Cai + K_mup));\nconst Real i_leak = K_leak * Ca_NSR;\nconst Real i_rel = G_rel * (Ca_JSR - Cai);\n\n// fast sodium current h gate\nconst Real alpha_h = ((V < -40.0) ? 0.135 * exp((80.0 + V) / -6.8) : 0.0);\nconst Real beta_h = ((V < -40.0) ? 3.56 * exp(0.079 * V) + 310000.0 * exp(0.35 * V) : 1.0 / (0.13 * (1.0 + exp((V + 10.66) / -11.1))));\nconst Real tau_h = 1.0 / (alpha_h + beta_h);\nconst Real h_inf = alpha_h * tau_h;\n*_new_h = h_inf + (h - h_inf) * exp(-dt / tau_h);\n\n// fast sodium current j gate\nconst Real alpha_j = ((V < -40.0) ? (-127140.0 * exp(0.2444 * V) - 3.474e-05 * exp(-0.04391 * V)) * ((V + 37.78) / (1.0 + exp(0.311 * (V + 79.23)))) : 0.0);\nconst Real beta_j = ((V < -40.0) ? 0.1212 * exp(-0.01052 * V) / (1.0 + exp(-0.1378 * (V + 40.14))) : 0.3 * exp(-2.535e-07 * V) / (1.0 + exp(-0.1 * (V + 32.0))));\nconst Real tau_j = 1.0 / (alpha_j + beta_j);\nconst Real j_inf = alpha_j * tau_j;\n*_new_j = j_inf + (j - j_inf) * exp(-dt / tau_j);\n\n// fast sodium current m gate\nconst Real alpha_m = 0.32 * safe_divide(V + 47.13, 1.0 - exp(-0.1 * (V + 47.13)));\nconst Real beta_m = 0.08 * exp(-V / 11.0);\nconst Real tau_m = 1.0 / (alpha_m + beta_m);\nconst Real m_inf = alpha_m * tau_m;\n*_new_m = m_inf + (m - m_inf) * exp(-dt / tau_m);\n\n// sarcolemmal calcium pump\nconst Real i_p_Ca = I_pCa * (Cai / (K_mpCa + Cai));\n\n// time dependent potassium current X gate\nconst Real alpha_X = 7.19e-05 * safe_divide(V + 30.0, 1.0 - exp(-0.148 * (V + 30.0)));\nconst Real beta_X = 0.000131 * safe_divide(V + 30.0, -1.0 + exp(0.0687 * (V + 30.0)));\nconst Real tau_X = safe_divide(1.0, alpha_X + beta_X);\nconst Real X_inf = alpha_X * tau_X;\n*_new_X = X_inf + (X - X_inf) * exp(-safe_divide(dt, tau_X));\n\n// time dependent potassium current Xi gate\nconst Real Xi = 1.0 / (1.0 + exp((V - 56.26) / 32.1));\n\n// ionic concentrations\n*_new_Ca_NSR = Ca_NSR + dt*(-(i_leak + i_tr - i_up));\n*_new_Ca_JSR = Ca_JSR + dt*(-(i_rel - i_tr * (V_NSR / V_JSR)));\n\n// non specific calcium activated current\nconst Real EnsCa = R * T / F * log((Ko + Nao) / (Ki + Nai));\nconst Real Vns = V - EnsCa;\nconst Real I_ns_K = P_ns_Ca * (Vns * F * F / (R * T)) * safe_divide(gamma_Ki * Ki * exp(Vns * F / (R * T)) - gamma_Ko * Ko, exp(Vns * F / (R * T)) - 1.0);\nconst Real I_ns_Na = P_ns_Ca * (Vns * F * F / (R * T)) * safe_divide(gamma_Nai * Nai * exp(Vns * F / (R * T)) - gamma_Nao * Nao, exp(Vns * F / (R * T)) - 1.0);\nconst Real i_ns_K = I_ns_K * (1.0 / (1.0 + pow(K_m_ns_Ca / Cai, 3.0)));\nconst Real i_ns_Na = I_ns_Na * (1.0 / (1.0 + pow(K_m_ns_Ca / Cai, 3.0)));\nconst Real i_ns_Ca = i_ns_Na + i_ns_K;\n\n// plateau potassium current\nconst Real Kp = 1.0 / (1.0 + exp((7.488 - V) / 5.98));\n\n// sodium potassium pump\nconst Real f_NaK = 1.0 / (1.0 + 0.1245 * exp(-0.1 * (V * F / (R * T))) + 0.0365 * sigma * exp(-(V * F / (R * T))));\nconst Real i_NaK = I_NaK * f_NaK * (1.0 / (1.0 + pow(K_mNai / Nai, 1.5))) * (Ko / (Ko + K_mKo));\n\n// time dependent potassium current\nconst Real E_K = R * T / F * log((Ko + PR_NaK * Nao) / (Ki + PR_NaK * Nai));\nconst Real i_K = g_K * X * X * Xi * (V - E_K);\n\n// time independent potassium current\nconst Real E_K1 = R * T / F * log(Ko / Ki);\n\n// time independent potassium current K1 gate\nconst Real alpha_K1 = 1.02 / (1.0 + exp(0.2385 * (V - E_K1 - 59.215)));\nconst Real beta_K1 = (0.49124 * exp(0.08032 * (V + 5.476 - E_K1)) + exp(0.06175 * (V - (E_K1 + 594.31)))) / (1.0 + exp(-0.5143 * (V - E_K1 + 4.753)));\nconst Real K1_inf = alpha_K1 / (alpha_K1 + beta_K1);\n\n// *remaining*\nconst Real I_CaCa = P_Ca * 4.0 * (V * F * F / (R * T)) * safe_divide(gamma_Cai * Cai * exp(2.0 * V * F / (R * T)) - gamma_Cao * Cao, exp(2.0 * V * F / (R * T)) - 1.0);\nconst Real I_CaK = P_K * (V * F * F / (R * T)) * safe_divide(gamma_Ki * Ki * exp(V * F / (R * T)) - gamma_Ko * Ko, exp(V * F / (R * T)) - 1.0);\nconst Real I_CaNa = P_Na * (V * F * F / (R * T)) * safe_divide(gamma_Nai * Nai * exp(V * F / (R * T)) - gamma_Nao * Nao, exp(V * F / (R * T)) - 1.0);\nconst Real i_NaCa = K_NaCa * (1.0 / (K_mNa * K_mNa * K_mNa + Nao * Nao * Nao)) * (1.0 / (K_mCa + Cao)) * (1.0 / (1.0 + K_sat * exp((eta - 1.0) * V * (F / (R * T))))) * (exp(eta * V * (F / (R * T))) * Nai * Nai * Nai * Cao - exp((eta - 1.0) * V * (F / (R * T))) * Nao * Nao * Nao * Cai);\nconst Real E_CaN = R * T / (2.0 * F) * log(Cao / Cai);\nconst Real E_Na = R * T / F * log(Nao / Nai);\nconst Real E_Kp = E_K1;\nconst Real i_K1 = g_K1 * K1_inf * (V - E_K1);\nconst Real i_CaCa = d * f * f_Ca_f_Ca * I_CaCa;\nconst Real i_CaK = d * f * f_Ca_f_Ca * I_CaK;\nconst Real i_CaNa = d * f * f_Ca_f_Ca * I_CaNa;\nconst Real i_Ca_b = g_Cab * (V - E_CaN);\nconst Real i_Na = g_Na * m * m * m * h * j * (V - E_Na);\nconst Real i_Kp = g_Kp * Kp * (V - E_Kp);\nconst Real E_NaN = E_Na;\nconst Real i_Ca_L = i_CaCa + i_CaK + i_CaNa;\n*_new_Cai = Cai + dt*(-(i_CaCa + i_p_Ca + i_Ca_b - i_NaCa) * (Am / (2.0 * V_myo * F)) + i_rel * (V_JSR / V_myo) + (i_leak - i_up) * (V_NSR / V_myo));\n*_new_Ki = Ki + dt*(-(i_CaK + i_K + i_K1 + i_Kp + i_ns_K + -(i_NaK * 2.0)) * (Am / (V_myo * F)));\nconst Real i_Na_b = g_Nab * (V - E_NaN);\n*_new_Nai = Nai + dt*(-(i_Na + i_CaNa + i_Na_b + i_ns_Na + i_NaCa * 3.0 + i_NaK * 3.0) * (Am / (V_myo * F)));\nconst Real dV_dt = -(i_Na + i_Ca_L + i_K + i_K1 + i_Kp + i_NaCa + i_p_Ca + i_Na_b + i_Ca_b + i_NaK + i_ns_Ca) / Cm;\n*_new_V = V + dt*(dV_dt + _diffuse_V);\n\n// check for unphysical values\nif(*_new_Nai <= 0.0) { *_new_Nai = VERY_SMALL_NUMBER; }\nif(*_new_Cai <= 0.0) { *_new_Cai = VERY_SMALL_NUMBER; }\nif(*_new_Ki <= 0.0) { *_new_Ki = VERY_SMALL_NUMBER; }\nif(*_new_Ca_JSR <= 0.0) { *_new_Ca_JSR = VERY_SMALL_NUMBER; }\nif(*_new_Ca_NSR <= 0.0) { *_new_Ca_NSR = VERY_SMALL_NUMBER; }\n'}, 'majumder2016mathematical': {'name': 'Majumder et al. 2016', 'description': 'This model was designed to closely correspond to monolayers of neonatal rat\natrial cardiomyocytes (NRAMs) observed via optical mapping.\nIt is based on several existing cardiac cell models; key changes include\nincorporation of a constitutively active IKACh, fitting to neonatal\nrat atrial patch-clamp data, and inclusion of myofibroblasts and cellular\nheterogeneity. The model reproduces action potential dynamics, restitution\ncurves, and spiral wave behavior, supporting studies of atrial\narrhythmogenesis.\n\nThe voltage- and light-sensitive Channelrhodopsin-2 ion channel as proposed by\nWilliams et al. (2013) has been added to this model.\n', 'dois': ['https://doi.org/10.1371/journal.pcbi.1004946', 'https://doi.org/10.1371/journal.pcbi.1003220'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'rat', 'atria'], 'variables': {'V': -70.0, 'm': 0.001729, 'h': 0.624946, 'j': 0.624946, 'd': 0.000109, 'f': 0.999929, 'fCa': 1.001951, 'r': 0.003223, 's': 0.999969, 's_slow': 0.999969, 'y': 0.562306, 'b': 0.000708, 'g': 0.914717, 'ua': 0.000554, 'ui': 1.0, 'P_o1': 0.002247, 'Ca_JSR': 790.502388, 'Ca_NSR': 794.054383, 'Ca_i': 0.137822, 'Xr': 0.025742210977, 'Xs1': 0.012668791315, 'Xs2': 0.028399873909, 'O1': 0.0, 'O2': 0.0, 'C1': 1.0, 'C2': 0.0, 'p': 0.1}, 'diffusivity': {'V': 1.0}, 'parameters': {'light': 0.0, 'F': 96.5, 'R': 8.314, 'T': 310.0, 'C_m': 1.0, 'Q10Na': 1.8, 'Q10Ca': 1.8, 'Q10K': 1.8, 'r_SR': 6.0, 'r_SL': 10.5, 'G_ChR2': 2.0, 'Ogamma': 0.1, 'Ee': 3.0, 'tau_ChR2': 1.3, 'lambda': 470, 'G_d1': 0.1, 'G_d2': 0.05, 'G_r': 0.004, 'phi0': 0.024, 'EChR2': 0.0, 'Ca_o': 1796.0, 'Na_o': 154578.0, 'K_o': 5400.0, 'Na_i': 13818.5982638, 'K_i': 130953.3914836, 'k_NCX': 1.134e-16, 'd_NCX': '1e-16', 'gamma': 0.5, 'INaK_max': 3.1993, 'K_mNai': 18600.0, 'n_NaK': 3.2, 'K_mKo': 1500.0, 'P_NaK': 0.01833, 'ACh': 1.0, 'Vmaxf': 0.9996, 'Vmaxr': 0.9996, 'K_mf': 0.5, 'K_mr': 3500.0, 'Hf': 2.0, 'Hr': 2.0, 'k_leak': '5e-6', 'tau_tr': 200, 'TRPN_tot': 35.0, 'K_mTRPN': 0.5, 'CMDN_tot': 50.0, 'K_mCMDN': 2.38, 'CSQN_tot': 24750.0, 'K_mCSQN': 800.0, 'N': 4, 'nu1': 0.01, 'k_a_plus': 1, 'k_a_minus': 0.16, 'G_CaL': 8e-05, 'G_CaT': 0.0054, 'G_Cab': 0.0008, 'G_Nab': 0.0039, 'G_Kb': 0.001, 'G_Kur': 0.02, 'G_f': 0.021, 'G_to': 0.007, 'G_Na': 150.0}, 'extra parameters': {'w_loss': 0.76, 'eps1': 0.8535, 'eps2': 0.14, 'k_f': 0.023761, 'k_b': 0.036778, 'IpCa_max': 0.2, 'K_mpCa': 0.5, 'k_RyR': 0.005, 'k_open': 1.0, 'k_close': 0.16, 'K_mup': 0.5, 'delta_r': 0.1, 'D_Ca': 7.0, 'G_Kv': 0.25, 'G_bNaf': 0.0095}, 'example discretisation': {'dt': 0.008, 'dx': 0.52, 'stimulus': 45.5}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}, 'code': '// derived parameters\nconst Real RT_F = (R * T) / F;\nconst Real F_RT = 1.0 / RT_F;\nconst Real A_cap = 4.0 * M_PI * r_SL * r_SL * 1e-8; // cm^2\nconst Real V_SR = 0.043 * 1.5 * 1.4; // pl\nconst Real V_NSR = 0.9 * V_SR; // pl\nconst Real V_JSR = V_SR - V_NSR; // pl\nconst Real V_myo = (4.0 * M_PI * (r_SL * r_SL * r_SL - r_SR * r_SR * r_SR)) / 3000.0; // pl\nconst Real S0 = 0.5 * (1 + tanh(120 * (Ee - 0.1)));\nconst Real e12 = 0.011 + 0.005 * log10(Ee / phi0); // Trayanova\nconst Real e21 = 0.008 + 0.004 * log10(Ee / phi0); // Trayanova\nconst Real tau_fCa = 10.0 / Q10Ca;\n\n// reversal potentials\nconst Real ECa = 0.5 * RT_F * log(Ca_o / Ca_i);\nconst Real EK = RT_F * log(K_o / K_i);\nconst Real ENa = RT_F * log(Na_o / Na_i);\nconst Real EKs = RT_F * log((K_o + P_NaK * Na_o) / (K_i + P_NaK * Na_i));\n\n// gating variables for fast sodium current\nconst Real alpha_m = 0.32 * safe_divide(V + 47.13, 1.0 - exp(-0.1 * (V + 47.13)));\nconst Real beta_m = 0.056 * exp(-V / 11.0);\n\nReal alpha_h = 0.0;\nReal beta_h = 1.0 / (0.13 * (1 + exp(-(V + 10.66) / 11.1)));\nReal alpha_j = 0.0;\nReal beta_j = (0.3 * exp(-2.535e-7 * V)) / (1.0 + exp(-0.1 * (V + 32.0)));\nif (V < -40.0) {\n  alpha_h = 0.135 * exp(-(V + 70.0) / 6.8);\n  beta_h = 3.56 * exp(0.079 * V) + 3.1e5 * exp(0.35 * V);\n  alpha_j = (2.0 * (-1.2714e5 * exp(0.2444 * V) - 3.474e-5 * exp(-0.04391 * V)) * (V + 37.78)) / (1.0 + exp(0.311 * (V + 79.23)));\n  beta_j = (0.1212 * exp(-0.01052 * V)) / (1 + exp(-0.1378 * (V + 40.14)));\n}\n\nconst Real m_inf = 1.0 / (1.0 + exp((37.0 + V) / -6.8));\nconst Real h_inf = 1.0 / (1.0 + exp((78.0 + V) / 7.8));\nReal tau_m = 1.0 / (alpha_m + beta_m);\nReal tau_h = V < -40.0 ? 0.06 / (alpha_h + beta_h) + 1.5 : 0.75 / (alpha_h + beta_h) + 0.15;\nReal tau_j = 1.0 / (alpha_j + beta_j);\nconst Real j_inf = h_inf;\n\n// gating variables for hyperpolarization activated current\nconst Real y_inf = 1.0 / (1.0 + exp((V + 78.65) / 6.33));\nconst Real tau_y = 1000.0 / (0.11885 * exp((V + 75.0) / 28.37) + 0.56236 * exp((V + 75.0) / -14.19));\n\n// gating variables for ultra-rapid K+ current\nconst Real ua_inf = 1.0 / (1.0 + exp(-(V + 12.5) / 25.0));\nReal tau_ua = 0.493 * exp(-0.0629 * V) + 2.058;\nconst Real ui_inf = 1.0 / (1.0 + exp((V - 100.0) / 5.7));\nReal tau_ui = 1200.0 - 170.0 / (1 + exp((V + 45.2) / 5.7));\n\n// gating variables for slow delayed rectifier K+ current\nconst Real Xs1_inf = 1.0 / (1.0 + exp(-(V - 10.0) / 20.0));\nconst Real Xs2_inf = Xs1_inf;\nReal tau_Xs1 = safe_divide(1.0, safe_divide(7.19e-5 * (V + 30.0), 1.0 - exp(-0.148 * (V + 30.0))) + safe_divide(1.31e-4 * (V + 30.0), exp(0.0687 * (V + 30.0)) - 1.0));\nReal tau_Xs2 = 4.0 * tau_Xs1;\n\n// gating variables for rapid delayed rectifier K+ current\nconst Real Xr_inf = 1.0 / (1.0 + exp(-(V + 12.5) / 10.0));\nReal tau_Xr = safe_divide(1.0, safe_divide(0.00138 * (V + 14.2), 1.0 - exp(-0.123 * (V + 14.2))) + safe_divide(0.00061 * (V + 38.9), exp(0.145 * (V + 38.9)) - 1.0));\nconst Real Rr = 1.0 / (1.0 + exp((V + 9.0) / 22.4));\n\n// gating variables for transient-outward K+ current\nconst Real r_inf = 1.0 / (1.0 + exp(-(V + 3.0) / 12.0));\nconst Real s_inf = 1.0 / (1.0 + exp((V + 31.97156) / 4.64291));\nconst Real sslow_inf = s_inf;\nconst Real tau_r = 1000.0 / (45.16 * exp(0.03577 * (V + 50.0)) + 98.9 * exp(-0.1 * (V + 38.0)));\nconst Real tau_s = 1000.0 * (0.35 * exp(-1.0 * pow((V + 70.0) / 15.0, 2)) + 0.035) - 26.9;\nconst Real tau_sslow = 1000.0 * (3.7 * exp(-1.0 * pow((V + 70.0) / 30.0, 2)) + 0.035) + 37.4;\n\n// gating variables for L-type Ca2+ current\nconst Real d_inf = 1.0 / (1.0 + exp((-1.8 - V) / 8.6));\nconst Real a_d = 0.25 + 1.4 / (1.0 + exp((-35.0 - V) / 13.0));\nconst Real b_d = 1.4 / (1.0 + exp((V + 5.0) / 5.0));\nconst Real c_d = 1.0 / (1.0 + exp((50.0 - V) / 20.0));\nReal tau_d = a_d * b_d + c_d + 10.0;\nconst Real f_inf = 1.0 / (1.0 + exp((22.0 + V) / 6.1));\nReal tau_f = 562.5 * exp((-1.0 * pow(V + 27.0, 2)) / 1000.0) + 10.0 / (1.0 + exp((25.0 - V) / 1.0)) + 10.0;\nconst Real a_fCa = 1.0 / (1.0 + pow(Ca_i / 0.325, 8));\nconst Real b_fCa = 0.1 / (1.0 + exp((Ca_i - 0.5) / 0.1));\nconst Real c_fCa = 0.2 / (1.0 + exp((Ca_i - 0.75) / 0.8));\nconst Real fCa_inf = (a_fCa + b_fCa + c_fCa + 0.23) / 1.46;\nconst Real k = (fCa_inf > fCa && V > -60.0) ? 0.0 : 1.0;\n\n// gating variables for T-type Ca2+ current\nconst Real b_inf = 1.0 / (1.0 + exp(-(V + 36.0) / 6.1));\nconst Real tau_b = 0.6 + 5.4 / (1.0 + exp(0.03 * (V + 100.0)));\nconst Real g_inf = 1.0 / (1.0 + exp((V + 66.0) / 6.0));\nconst Real tau_g = 1.0 + 40.0 / (1.0 + exp(0.08 * (V + 65.0)));\n\n// gating variables for Na+/K+ ATPase\nconst Real sigma = (exp(Na_o / 67300.0) - 1.0) / 7.0;\nconst Real fNaK = 1.0 / (1.0 + 0.1245 * exp(-0.1 * V * F_RT) + 0.0365 * sigma * exp(-V * F_RT));\n\n// Q10 compensation\ntau_m = tau_m / Q10Na;\ntau_h = tau_h / Q10Na;\ntau_j = tau_j / Q10Na;\ntau_d = tau_d / Q10Ca;\ntau_f = tau_f / Q10Ca;\ntau_ua = tau_ua / Q10K;\ntau_ui = tau_ui / Q10K;\ntau_Xs1 = tau_Xs1 / Q10K;\ntau_Xs2 = tau_Xs2 / Q10K;\ntau_Xr = tau_Xr / Q10K;\n\n// photocurrent parameters\nReal k1 = 0.0;\nReal k2 = 0.0;\nif (light > 0.5) { // if Lit == 1 && light_on <= t && t <= light_off\n  const Real k0 = Ee * lambda * p;\n  k1 = 3.89196e-05 * k0;\n  k2 = 6.384e-06 * k0;\n}\n\n// fast Na+ current\nconst Real INa = G_Na * m * m * m * h * j * (V - ENa);\n\n// hyperpolarization-activated current\nconst Real IfNa = G_f * y * (0.2 * (V - ENa));\nconst Real IfK = G_f * y * (0.8 * (V - EK));\nconst Real If = IfNa+IfK;\n\n// ultra-rapid outward K+ current\nconst Real IKur = G_Kur * ua * ui * (V - EK);\n\n// slow delayed rectifier K+ current\nconst Real G_Ks = 0.0866 * (1.0 + 0.6 / (1.0 + pow(0.000038 / Ca_i, 1.4)));\nconst Real IKs = G_Ks * Xs1 * Xs2 * (V - EKs);\n\n// rapid delayed rectifier K+ current\nconst Real G_Kr = 0.0005228 * sqrt(K_o / 5.4);\nconst Real IKr = G_Kr * Xr * Rr * (V - EK);\n\n// sustained outward K+ current\nconst Real IKsus = 0.001 * (IKur + IKs + IKr);\n\n// time-independent K+ current\nconst Real IK1 = 0.8 * ((0.0515 * K_o / (K_o + 210.0) * (V - EK - 10)) / (0.5 + exp(0.025 * (V - EK - 10))));\n\n// transient outward K+ current\nconst Real Ito = 0.01 * G_to * r * (0.706 * s + 0.294 * s_slow) * (V - EK);\n\n// L-type Ca2+ current\nconst Real ICaL = safe_divide(0.8 * 4.0 * G_CaL * d * f * fCa * V * F * F_RT * (Ca_i * exp(2.0 * V * F_RT) - 0.341 * Ca_o), exp(2.0 * V * F_RT) - 1.0);\n\n// T-type Ca2+ current\nconst Real ICaT = G_CaT * b * g * (V - ECa + 106.5);\n\n// Na+/Ca2+ exchanger current\nconst Real INCX = (0.6 * k_NCX * (Na_i * Na_i * Na_i * Ca_o * exp(0.03743 * gamma * V) - Na_o * Na_o * Na_o * Ca_i * exp(0.03743 * (gamma - 1) * V))) / (1.0 + d_NCX * (Na_o * Na_o * Na_o * Ca_i + Na_i * Na_i * Na_i * Ca_o));\n\n// background Ca2+ and Na+ currents\nconst Real ICab = G_Cab * (V - ECa);\nconst Real INab = 0.01 * G_Nab * (V - ENa);\nconst Real IKb = 0.001 * G_Kb * (V - EK);\n\n// Na+/K+ ATPase\nconst Real INaK = 1.2 * INaK_max * fNaK / ((1.0 + pow(K_mNai / Na_i, n_NaK)) * (1.0 + K_mKo / K_o));\n\n// constitutively active KACh current\nconst Real IKACh = 5.5 / (1.0 + 9.13652 / pow(ACh, 0.477811)) * (0.0517 + 0.4516 / (1.0 + exp((V + 105.0) / 17.18))) * (V - EK);\n\n// photocurrent (if Lit == 1)\nconst Real IChR2 = light > 0.25 ? G_ChR2 * (V - EChR2) * (O1 + Ogamma * O2) : 0.0;\n\n// calcium fluxes\nconst Real J_rel = nu1 * P_o1 * (Ca_JSR - Ca_i);\nconst Real J_leak = k_leak * (Ca_NSR - Ca_i);\nconst Real J_tr = (Ca_NSR - Ca_JSR) / tau_tr;\n\n// Ca2+ buffering\nconst Real beta_SR = 1.0 / (1.0 + CSQN_tot * K_mCSQN / pow(Ca_JSR + K_mCSQN, 2));\n\n// ryanodine receptor gating\nconst Real K_mRyR = 3.51 / (1.0 + exp((Ca_JSR - 530.0) / 200.0)) + 0.25;\nconst Real P_C1 = 1 - P_o1;\n\n// SERCA\nconst Real s1 = pow(Ca_i / K_mf, Hf);\nconst Real s2 = pow(Ca_NSR / K_mr, Hr);\nconst Real J_up = (Vmaxf * s1 - Vmaxr * s2) / (1.0 + s1 + s2);\nconst Real J_CaSR = J_rel - J_up + J_leak;\nconst Real J_CaSL = (2.0 * INCX - ICaL - ICaT - ICab) * A_cap * C_m / (2.0e-6 * F);\n\n// total ion current\nconst Real I_ion = ICaL + ICaT + INCX + ICab + INab + INaK + INa + If + IK1 + Ito + IKsus + IKb + IKACh + IChR2;\n\n// time evolution of variables\n*_new_V = V + dt * (_diffuse_V - I_ion / C_m);\n*_new_m = m_inf + (m - m_inf) * exp(-dt / tau_m);\n*_new_h = h_inf + (h - h_inf) * exp(-dt / tau_h);\n*_new_j = j_inf + (j - j_inf) * exp(-dt / tau_j);\n*_new_d = d_inf + (d - d_inf) * exp(-dt / tau_d);\n*_new_f = f_inf + (f - f_inf) * exp(-dt / tau_f);\n*_new_fCa = (dt * k * (fCa_inf - fCa)) / tau_fCa + fCa;\n*_new_b = b_inf + (b - b_inf) * exp(-dt / tau_b);\n*_new_g = g_inf + (g - g_inf) * exp(-dt / tau_g);\n*_new_y = y_inf + (y - y_inf) * exp(-dt / tau_y);\n*_new_r = r_inf + (r - r_inf) * exp(-dt / tau_r);\n*_new_s = s_inf + (s - s_inf) * exp(-dt / tau_s);\n*_new_s_slow = sslow_inf + (s_slow - sslow_inf) * exp(-dt / tau_sslow);\n*_new_ua = ua_inf + (ua - ua_inf) * exp(-dt / tau_ua);\n*_new_ui = ui_inf + (ui - ui_inf) * exp(-dt / tau_ui);\n*_new_Xr = Xr_inf + (Xr - Xr_inf) * exp(-dt / tau_Xr);\n*_new_Xs1 = Xs1_inf + (Xs1 - Xs1_inf) * exp(-dt / tau_Xs1);\n*_new_Xs2 = Xs2_inf + (Xs2 - Xs2_inf) * exp(-dt / tau_Xs2);\n*_new_P_o1 = P_o1 + dt * (k_a_plus * pow(Ca_i, N) / (pow(Ca_i, N) + pow(K_mRyR, N)) * P_C1 - k_a_minus * P_o1);\n\n// calcium equations\n*_new_Ca_NSR = Ca_NSR + dt * (J_up - J_leak - J_tr) / V_NSR;\n*_new_Ca_JSR = Ca_JSR + dt * beta_SR * (-J_rel + J_tr) / V_JSR;\n\n// Channelrhodopsin\n*_new_O1 = (k1 * C1 - (G_d1 + e12) * O1 + e21 * O2) * dt + O1;\n*_new_O2 = (k2 * C2 - (G_d2 + e21) * O2 + e12 * O1) * dt + O2;\n*_new_C1 = (G_r * C2 + G_d1 * O1 - k1 * C1) * dt + C1;\n*_new_C2 = (G_d2 * O2 - (k2 + G_r) * C2) * dt + C2;\n*_new_p = p + dt * ((S0 - p) / tau_ChR2);\n\n// for spherical core structure\nconst Real beta_Cai = 1.0 / (1.0 + TRPN_tot * K_mTRPN / pow(Ca_i + K_mTRPN, 2.0) + CMDN_tot * K_mCMDN / pow(Ca_i + K_mCMDN, 2.0));\nconst Real dCai_dt = beta_Cai * (J_CaSR + J_CaSL) / V_myo;\n*_new_Ca_i = Ca_i + dt * dCai_dt;\n'}, 'maleckar2008mathematical': {'name': 'Maleckar et al. 2008', 'description': 'A recently developed mathematical model of the human atrial myocyte including\nheterogeneous cell-cell interaction on the action potential of the human\natrium. This model provides a basis for beginning to assess the utility of\nmathematical modeling in understanding detailed cell-cell interactions within\nthe complex paracrine environment of the human atrial myocardium.\n', 'dois': ['https://doi.org/10.1016/j.pbiomolbio.2009.01.010'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human', 'atria'], 'variables': {'V': -74.031982, 'Ca_c': 1.815768, 'Ca_d': 7.1e-05, 'Ca_i': 6.5e-05, 'Ca_rel': 0.632613, 'Ca_up': 0.649195, 'K_c': 5.560224, 'K_i': 129.485991, 'Na_c': 130.022096, 'Na_i': 8.516766, 'F1': 0.470055, 'F2': 0.002814, 'O': 1.38222, 'O_C': 0.026766, 'O_Calse': 0.431547, 'O_TC': 0.012922, 'O_TMgC': 0.190369, 'O_TMgMg': 0.714463, 'a_ur': 0.000367, 'd_L': 1.4e-05, 'f_L1': 0.998597, 'f_L2': 0.998586, 'h1': 0.877202, 'h2': 0.873881, 'i_ur': 0.96729, 'm': 0.003289, 'n': 0.004374, 'pa': 5.3e-05, 'r': 0.001089, 's': 0.948597}, 'diffusivity': {'V': 1.0}, 'parameters': {'Cm': 50.0, 'Ca_b': 1.8, 'E_Ca_app': 60.0, 'K_NaCa': 0.0374842, 'K_NaK_K': 1.0, 'K_b': 5.4, 'Mg_i': 2.5, 'Na_b': 130.0, 'ACh': 1e-24, 'F': 96487.0, 'R': 8314.0, 'T': 306.15, 'I_up_max': 2800.0, 'P_Na': 0.0018, 'Vol_c': 0.000800224, 'Vol_d': 0.00011768, 'Vol_i': 0.005884, 'Vol_rel': 4.41e-05, 'Vol_up': 0.0003969, 'alpha_rel': 200000.0, 'd_NaCa': 0.0003, 'g_B_Ca': 0.078681, 'g_B_Na': 0.060599, 'g_Ca_L': 6.75, 'g_K1': 3.1, 'g_Kr': 0.5, 'g_Ks': 1.0, 'g_Kur': 2.25, 'g_t': 8.25, 'gamma_Na': 0.45, 'i_CaP_max': 4.0, 'i_NaK_max': 68.55, 'k_Ca': 0.025, 'k_CaP': 0.0002, 'k_cyca': 0.0003, 'k_rel_d': 0.003, 'k_rel_i': 0.0003, 'k_srca': 0.5, 'k_xcs': 0.4, 'phi_Na_en': 0.0, 'pow_K_NaK_Na_15': 36.4829, 'r_recov': 0.815, 'tau_Ca': 24.7, 'tau_K': 10.0, 'tau_Na': 14.3, 'tau_di': 0.01, 'tau_tr': 0.01}, 'example discretisation': {'dt': 4.8e-05, 'dx': 0.022, 'stimulus': 36.3}, 'units': {'t': 's', 'x': 'm', 'u': 'mV'}, 'code': '// r gate\nconst Real r_infinity = 1.0 / (1.0 + exp((V - 1.0) / -11.0));\nconst Real tau_r = 0.0035 * exp(-V * V / 30.0 / 30.0) + 0.0015;\n*_new_r = r_infinity + (r - r_infinity) * exp(-(dt / tau_r));\n\n// s gate\nconst Real s_factor = (V + 52.45) / 15.8827;\nconst Real s_infinity = 1.0 / (1.0 + exp((V + 40.5) / 11.5));\nconst Real tau_s = 0.025635 * exp(-s_factor * s_factor) + 0.01414;\n*_new_s = s_infinity + (s - s_infinity) * exp(-(dt / tau_s));\n\n// L type Ca channel\nconst Real f_Ca = Ca_d / (Ca_d + k_Ca);\nconst Real i_Ca_L = g_Ca_L * d_L * (f_Ca * f_L1 + (1.0 - f_Ca) * f_L2) * (V - E_Ca_app);\n\n// d_L gate\nconst Real d_L_factor = (V + 35.0) / 30.0;\nconst Real d_L_infinity = 1.0 / (1.0 + exp((V + 9.0) / -5.8));\nconst Real tau_d_L = 0.0027 * exp(-d_L_factor * d_L_factor) + 0.002;\n*_new_d_L = d_L_infinity + (d_L - d_L_infinity) * exp(-(dt / tau_d_L));\n\n// f_L1 gate\nconst Real f_L_factor = V + 40.0;\nconst Real f_L_infinity = 1.0 / (1.0 + exp((V + 27.4) / 7.1));\nconst Real tau_f_L1 = 0.161 * exp(-f_L_factor * f_L_factor / 14.4 / 14.4) + 0.01;\n*_new_f_L1 = f_L_infinity + (f_L1 - f_L_infinity) * exp(-(dt / tau_f_L1));\n\n// n gate\nconst Real n_factor = (V - 20.0) / 20.0;\nconst Real n_infinity = 1.0 / (1.0 + exp((V - 19.9) / -12.7));\nconst Real tau_n = 0.7 + 0.4 * exp(-n_factor * n_factor);\n*_new_n = n_infinity + (n - n_infinity) * exp(-(dt / tau_n));\n\n// pa gate\nconst Real pa_infinity = 1.0 / (1.0 + exp((V + 15.0) / -6.0));\nconst Real pa_factor = (V + 20.1376) / 22.1996;\nconst Real tau_pa = 0.03118 + 0.21718 * exp(-pa_factor * pa_factor);\n*_new_pa = pa_infinity + (pa - pa_infinity) * exp(-(dt / tau_pa));\n\n// pi gate\nconst Real pi = 1.0 / (1.0 + exp((V + 55.0) / 24.0));\n\n// intracellular Ca buffering\nconst Real J_O_C = 200000.0 * Ca_i * (1.0 - O_C) - 476.0 * O_C;\nconst Real J_O_TC = 78400.0 * Ca_i * (1.0 - O_TC) - 392.0 * O_TC;\nconst Real J_O_TMgC = 200000.0 * Ca_i * (1.0 - O_TMgC - O_TMgMg) - 6.6 * O_TMgC;\n*_new_O_C = O_C + dt*(J_O_C);\n*_new_O_TC = O_TC + dt*(J_O_TC);\n*_new_O_TMgC = O_TMgC + dt*(J_O_TMgC);\nconst Real J_O = 0.08 * J_O_TC + 0.16 * J_O_TMgC + 0.045 * J_O_C;\nconst Real J_O_TMgMg = 2000.0 * Mg_i * (1.0 - O_TMgC - O_TMgMg) - 666.0 * O_TMgMg;\n*_new_O = O + dt*(J_O);\n*_new_O_TMgMg = O_TMgMg + dt*(J_O_TMgMg);\n\n// sarcolemmal calcium pump current\nconst Real i_CaP = i_CaP_max * Ca_i / (Ca_i + k_CaP);\n\n// h1 gate\nconst Real h_factor = 1.0 / (1.0 + exp((V + 35.1) / 3.2));\nconst Real h_infinity = 1.0 / (1.0 + exp((V + 63.6) / 5.3));\nconst Real tau_h1 = 0.03 * h_factor + 0.0003;\n*_new_h1 = h_infinity + (h1 - h_infinity) * exp(-(dt / tau_h1));\n\n// m gate\nconst Real m_factor = (V + 25.57) / 28.8;\nconst Real m_infinity = 1.0 / (1.0 + exp((V + 27.12) / -8.21));\nconst Real tau_m = 4.2e-05 * exp(-m_factor * m_factor) + 2.4e-05;\n*_new_m = m_infinity + (m - m_infinity) * exp(-(dt / tau_m));\n\n// sodium potassium pump\nconst Real pow_Na_i_15 = pow(Na_i, 1.5);\nconst Real i_NaK = i_NaK_max * K_c / (K_c + K_NaK_K) * pow_Na_i_15 / (pow_Na_i_15 + pow_K_NaK_Na_15) * (V + 150.0) / (V + 200.0);\n\n// a_ur gate\nconst Real a_ur_infinity = 1.0 / (1.0 + exp(-(V + 6.0) / 8.6));\nconst Real tau_a_ur = 0.009 / (1.0 + exp((V + 5.0) / 12.0)) + 0.0005;\n*_new_a_ur = a_ur_infinity + (a_ur - a_ur_infinity) * exp(-(dt / tau_a_ur));\n\n// i_ur gate\nconst Real i_ur_infinity = 1.0 / (1.0 + exp((V + 7.5) / 10.0));\nconst Real tau_i_ur = 0.59 / (1.0 + exp((V + 60.0) / 10.0)) + 3.05;\n*_new_i_ur = i_ur_infinity + (i_ur - i_ur_infinity) * exp(-(dt / tau_i_ur));\n\n// f_L2 gate\nconst Real tau_f_L2 = 1.3323 * exp(-f_L_factor * f_L_factor / 14.2 / 14.2) + 0.0626;\n*_new_f_L2 = f_L_infinity + (f_L2 - f_L_infinity) * exp(-(dt / tau_f_L2));\n\n// h2 gate\nconst Real tau_h2 = 0.12 * h_factor + 0.003;\n*_new_h2 = h_infinity + (h2 - h_infinity) * exp(-(dt / tau_h2));\n\n// membrane\nconst Real Q_tot = 0.05 * V;\n\n// sodium current\nconst Real E_Na = R * T / F * log(Na_c / Na_i);\nconst Real i_Na =\n  P_Na * m * m * m * (0.9 * h1 + 0.1 * h2) * Na_c * F * F / (R * T) *\n  (fabs(V) < 1e-3\n    ? R * T * (exp((-E_Na * F) / (R * T)) - 1.0) / F\n    : V * (exp((V - E_Na) * F / (R * T)) - 1.0)\n        / (exp(V * F / (R * T)) - 1.0)\n  );\n\n// Ca independent transient outward K current\nconst Real E_K = R * T / F * log(K_c / K_i);\nconst Real i_t = g_t * r * s * (V - E_K);\n\n// ultra rapid K current\nconst Real i_Kur = g_Kur * a_ur * i_ur * (V - E_K);\n\n// inward rectifier\nconst Real i_K1 = g_K1 * pow(K_c / 1.0, 0.4457) * (V - E_K) / (1.0 + exp(1.5 * (V - E_K + 3.6) * F / (R * T)));\n\n// delayed rectifier K currents\nconst Real i_Kr = g_Kr * pa * pi * (V - E_K);\nconst Real i_Ks = g_Ks * n * (V - E_K);\n\n// background currents\nconst Real E_Ca = R * T / (2.0 * F) * log(Ca_c / Ca_i);\nconst Real i_B_Ca = g_B_Ca * (V - E_Ca);\nconst Real i_B_Na = g_B_Na * (V - E_Na);\n\n// Na/Ca ion exchanger current\nconst Real i_NaCa = K_NaCa * (Na_i * Na_i * Na_i * Ca_c * exp(F * V * gamma_Na / (R * T)) - Na_c * Na_c * Na_c * Ca_i * exp((gamma_Na - 1.0) * V * F / (R * T))) / (1.0 + d_NaCa * (Na_c * Na_c * Na_c * Ca_i + Na_i * Na_i * Na_i * Ca_c));\n\n// ACh dependent K current\nconst Real i_KACh = 10.0 / (1.0 + 9.13652 / pow(ACh, 0.477811)) * (0.0517 + 0.4516 / (1.0 + exp((V + 59.53) / 17.18))) * (V - E_K) * Cm;\n\n// intracellular ion concentrations\n*_new_K_i = K_i + dt*(-(i_t + i_Kur + i_K1 + i_Ks + i_Kr - 2.0 * i_NaK) / (Vol_i * F));\n*_new_Na_i = Na_i + dt*(-(i_Na + i_B_Na + 3.0 * i_NaCa + 3.0 * i_NaK + phi_Na_en) / (Vol_i * F));\nconst Real i_di = (Ca_d - Ca_i) * 2.0 * Vol_d * F / tau_di;\n*_new_Ca_d = Ca_d + dt*(-(i_Ca_L + i_di) / (2.0 * Vol_d * F));\n\n// cleft space ion concentrations\n*_new_Ca_c = Ca_c + dt*((Ca_b - Ca_c) / tau_Ca + (i_Ca_L + i_B_Ca + i_CaP - 2.0 * i_NaCa) / (2.0 * Vol_c * F));\n*_new_K_c = K_c + dt*((K_b - K_c) / tau_K + (i_t + i_Kur + i_K1 + i_Ks + i_Kr - 2.0 * i_NaK) / (Vol_c * F));\n*_new_Na_c = Na_c + dt*((Na_b - Na_c) / tau_Na + (i_Na + i_B_Na + 3.0 * i_NaCa + 3.0 * i_NaK + phi_Na_en) / (Vol_c * F));\n\n// Ca handling by the SR\nconst Real J_O_Calse = 480.0 * Ca_rel * (1.0 - O_Calse) - 400.0 * O_Calse;\nconst Real i_rel_f2 = F2 / (F2 + 0.25);\nconst Real i_rel_factor = i_rel_f2 * i_rel_f2;\nconst Real i_tr = (Ca_up - Ca_rel) * 2.0 * Vol_rel * F / tau_tr;\nconst Real i_up = I_up_max * (Ca_i / k_cyca - k_xcs * k_xcs * Ca_up / k_srca) / ((Ca_i + k_cyca) / k_cyca + k_xcs * (Ca_up + k_srca) / k_srca);\nconst Real r_Ca_d_term = Ca_d / (Ca_d + k_rel_d);\nconst Real r_Ca_i_term = Ca_i / (Ca_i + k_rel_i);\n*_new_O_Calse = O_Calse + dt*(J_O_Calse);\nconst Real i_rel = alpha_rel * i_rel_factor * (Ca_rel - Ca_i);\nconst Real r_Ca_d_factor = r_Ca_d_term * r_Ca_d_term * r_Ca_d_term * r_Ca_d_term;\nconst Real r_Ca_i_factor = r_Ca_i_term * r_Ca_i_term * r_Ca_i_term * r_Ca_i_term;\n*_new_Ca_up = Ca_up + dt*((i_up - i_tr) / (2.0 * Vol_up * F));\nconst Real r_act = 203.8 * (r_Ca_i_factor + r_Ca_d_factor);\nconst Real r_inact = 33.96 + 339.6 * r_Ca_i_factor;\n*_new_Ca_rel = Ca_rel + dt*((i_tr - i_rel) / (2.0 * Vol_rel * F) - 31.0 * J_O_Calse);\n*_new_F1 = F1 + dt*(r_recov * (1.0 - F1 - F2) - r_act * F1);\n*_new_F2 = F2 + dt*(r_act * F1 - r_inact * F2);\n\n// remaining\nconst Real I = (i_Na + i_Ca_L + i_t + i_Kur + i_K1 + i_Kr + i_Ks + i_B_Na + i_B_Ca + i_NaK + i_CaP + i_NaCa + i_KACh) / Cm;\n*_new_Ca_i = Ca_i + dt*((i_di + i_rel + 2.0 * i_NaCa - i_B_Ca - i_CaP - i_up) / (2.0 * Vol_i * F) - 1.0 * J_O);\n*_new_V = V + dt*(_diffuse_V - I * 1000.0);\n\n// check for unphysical values\nif(*_new_Ca_c <= 0.0) { *_new_Ca_c = VERY_SMALL_NUMBER; }\nif(*_new_Ca_d <= 0.0) { *_new_Ca_d = VERY_SMALL_NUMBER; }\nif(*_new_Ca_i <= 0.0) { *_new_Ca_i = VERY_SMALL_NUMBER; }\nif(*_new_Ca_rel <= 0.0) { *_new_Ca_rel = VERY_SMALL_NUMBER; }\nif(*_new_Ca_up <= 0.0) { *_new_Ca_up = VERY_SMALL_NUMBER; }\nif(*_new_K_c <= 0.0) { *_new_K_c = VERY_SMALL_NUMBER; }\nif(*_new_K_i <= 0.0) { *_new_K_i = VERY_SMALL_NUMBER; }\nif(*_new_Na_c <= 0.0) { *_new_Na_c = VERY_SMALL_NUMBER; }\nif(*_new_Na_i <= 0.0) { *_new_Na_i = VERY_SMALL_NUMBER; }\n'}, 'marcotte2017dynamical': {'name': 'Marcotte & Grigoriev 2017', 'description': 'Smoothed version of the Karma model as published by Marcotte & Grigoriev in 2017.\nIn it, a single spiral wave breaks up into spiral wave chaos due to amplification\nof the alternans instability. It can be used as a model of the transition from\ntachycardia to fibrillation.\n', 'dois': ['https://doi.org/10.1063/1.5003259', 'https://doi.org/10.1063/1.4915143', 'https://doi.org/10.1103/PhysRevLett.71.1103', 'https://doi.org/10.1063/1.166024'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'phenomenological'], 'variables': {'u': 0.0, 'v': 0.0}, 'diffusivity': {'u': 1.0, 'v': 0.05}, 'parameters': {'beta': 1.389, 'eps': 0.01, 'ustar': 1.5415}, 'example discretisation': {'dt': 0.037, 'dx': 0.92, 'stimulus': 1.11}, 'units': {'t': 1, 'x': 1, 'u': 1}, 'code': 'const Real e = exp(2. * (1.2571 * (u - 1.)));\nconst Real V = eps * (beta * ((1. + (e - 1.) / (e + 1.)) / 2.) + (1. + (exp(2. * (1.2571 * (v - 1.))) - 1.) / (exp(2. * (1.2571 * (v - 1.))) + 1.)) / 2. * (v - 1.) - v);\nconst Real U = (ustar - v * v * v * v) * (1. - (exp(2. * (u - 3.)) - 1.) / (exp(2. * (u - 3.)) + 1.)) * u * u / 2. - u;\n*_new_u = u + dt * (U + _diffuse_u);\n*_new_v = v + dt * (V + _diffuse_v);\n'}, 'mitchell2003two': {'name': 'Mitchell & Schaeffer 2003', 'description': 'A model for electrical activity of cardiac membrane which incorporates only\nan inward and an outward current. This model is useful for three reasons: (1)\nIts simplicity, comparable to the FitzHugh-Nagumo model, makes it useful in\nnumerical simulations, especially in two or three spatial dimensions where\nnumerical efficiency is so important. (2) It can be understood analytically\nwithout recourse to numerical simulations. This allows us to determine rather\ncompletely how the parameters in the model affect its behavior which in turn\nprovides insight into the effects of the many parameters in more realistic\nmodels. (3) It naturally gives rise to a one-dimensional map which specifies\nthe action potential duration as a function of the previous diastolic interval.\nFor certain parameter values, this map exhibits a new phenomenon--subcritical\nalternans--that does not occur for the commonly used exponential map.\n', 'dois': ['https://doi.org/10.1016/S0092-8240(03)00041-7'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'phenomenological'], 'variables': {'V': 0.0, 'h': 0.9}, 'diffusivity': {'V': 1.0}, 'parameters': {'V_gate': 0.13, 'tau_in': 0.3, 'tau_out': 6.0, 'tau_open': 120.0, 'tau_close': 150.0}, 'example discretisation': {'dt': 0.23, 'dx': 3.3, 'stimulus': 0.087}, 'units': {'t': 'ms', 'x': 'mm', 'u': 1}, 'code': 'const Real J_in = h * (V*V * (1.0 - V)) / tau_in;\nconst Real J_out = -V / tau_out;\n*_new_h = h + dt*(((V < V_gate) ? (1.0 - h) / tau_open : -h / tau_close));\n*_new_V = V + dt*(J_in + J_out + _diffuse_V);\n'}, 'nygren1998mathematical': {'name': 'Nygren et al. 1998', 'description': 'A mathematical model of the human atrial myocyte based on averaged\nvoltage-clamp data recorded from isolated single myocytes. This model\nconsists of a Hodgkin-Huxley–type equivalent circuit for the sarcolemma,\ncoupled with a fluid compartment model, which accounts for changes in ionic\nconcentrations in the cytoplasm as well as in the sarcoplasmic reticulum.\nThis formulation can reconstruct action potential data that are\nrepresentative of recordings from a majority of human atrial cells and\ntherefore provides a biophysically based account of the underlying ionic\ncurrents.\n', 'dois': ['https://doi.org/10.1161/01.RES.82.1.63'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human', 'atria'], 'variables': {'V': -74.2525, 'Ca_c': 1.8147, 'Ca_d': 7.2495e-05, 'Ca_i': 6.729e-05, 'Ca_rel': 0.6465, 'Ca_up': 0.6646, 'K_c': 5.3581, 'K_i': 129.435, 'Na_c': 130.011, 'Na_i': 8.5547, 'F1': 0.4284, 'F2': 0.0028, 'O_C': 0.0275, 'O_Calse': 0.4369, 'O_TC': 0.0133, 'O_TMgC': 0.1961, 'O_TMgMg': 0.7094, 'd_L': 1.3005e-05, 'f_L1': 0.9986, 'f_L2': 0.9986, 'h1': 0.8814, 'h2': 0.8742, 'm': 0.0032017, 'n': 0.0048357, 'p_a': 0.0001, 'r': 0.0010678, 'r_sus': 0.00015949, 's': 0.949, 's_sus': 0.9912}, 'diffusivity': {'V': 1.0}, 'parameters': {'Cm': 0.05, 'Ca_b': 1.8, 'K_b': 5.4, 'Mg_i': 2.5, 'Na_b': 130.0, 'E_Ca_app': 60.0, 'F': 96487.0, 'I_up_max': 2800.0, 'P_Na': 0.0016, 'R': 8314.0, 'T': 306.15, 'Vol_c': 0.000800224, 'Vol_d': 0.00011768, 'Vol_i': 0.005884, 'Vol_rel': 4.41e-05, 'Vol_up': 0.0003969, 'alpha_rel': 200000.0, 'd_NaCa': 0.0003, 'g_B_Ca': 0.078681, 'g_B_Na': 0.060599, 'g_Ca_L': 6.75, 'g_K1': 3.0, 'g_Kr': 0.5, 'g_Ks': 1.0, 'g_sus': 2.75, 'g_t': 7.5, 'gamma': 0.45, 'i_CaP_max': 4.0, 'i_NaK_max': 70.8253, 'k_Ca': 0.025, 'k_CaP': 0.0002, 'k_NaCa': 0.0374842, 'k_NaK_K': 1.0, 'k_NaK_Na': 11.0, 'k_cyca': 0.0003, 'k_rel_d': 0.003, 'k_rel_i': 0.0003, 'k_srca': 0.5, 'k_xcs': 0.4, 'phi_Na_en': -1.68, 'r_recov': 0.815, 'tau_Ca': 24.7, 'tau_K': 10.0, 'tau_Na': 14.3, 'tau_di': 0.01, 'tau_tr': 0.01}, 'example discretisation': {'dt': 5.8e-05, 'dx': 0.044, 'stimulus': 34.1}, 'units': {'t': 's', 'x': 'm', 'u': 'mV'}, 'code': '// r gate\nconst Real r_inf = 1.0 / (1.0 + exp((V - 1.0) / -11.0));\nconst Real tau_r = 0.0035 * exp(-pow(V / 30.0, 2.0)) + 0.0015;\n*_new_r = r_inf + (r - r_inf) * exp(-(dt / tau_r));\n\n// s gate\nconst Real s_inf = 1.0 / (1.0 + exp((V + 40.5) / 11.5));\nconst Real tau_s = 0.4812 * exp(-pow((V + 52.45) / 14.97, 2.0)) + 0.01414;\n*_new_s = s_inf + (s - s_inf) * exp(-(dt / tau_s));\n\n// L type Ca channel\nconst Real f_Ca = Ca_d / (Ca_d + k_Ca);\nconst Real i_Ca_L = g_Ca_L * d_L * (f_Ca * f_L1 + (1.0 - f_Ca) * f_L2) * (V - E_Ca_app);\n\n// d_L gate\nconst Real d_L_inf = 1.0 / (1.0 + exp((V + 9.0) / -5.8));\nconst Real tau_d_L = 0.0027 * exp(-pow((V + 35.0) / 30.0, 2.0)) + 0.002;\n*_new_d_L = d_L_inf + (d_L - d_L_inf) * exp(-(dt / tau_d_L));\n\n// f_L1 gate\nconst Real f_L_inf = 1.0 / (1.0 + exp((V + 27.4) / 7.1));\nconst Real tau_f_L1 = 0.161 * exp(-pow((V + 40.0) / 14.4, 2.0)) + 0.01;\n*_new_f_L1 = f_L_inf + (f_L1 - f_L_inf) * exp(-(dt / tau_f_L1));\n\n// n gate\nconst Real n_inf = 1.0 / (1.0 + exp((V - 19.9) / -12.7));\nconst Real tau_n = 0.7 + 0.4 * exp(-pow((V - 20.0) / 20.0, 2.0));\n*_new_n = n_inf + (n - n_inf) * exp(-(dt / tau_n));\n\n// pa gate\nconst Real p_a_inf = 1.0 / (1.0 + exp((V + 15.0) / -6.0));\nconst Real tau_p_a = 0.03118 + 0.21718 * exp(-pow((V + 20.1376) / 22.1996, 2.0));\n*_new_p_a = p_a_inf + (p_a - p_a_inf) * exp(-(dt / tau_p_a));\n\n// pi gate\nconst Real p_i = 1.0 / (1.0 + exp((V + 55.0) / 24.0));\n\n// intracellular Ca buffering\nconst Real dot_O_C = 200000.0 * Ca_i * (1.0 - O_C) - 476.0 * O_C;\nconst Real dot_O_TC = 78400.0 * Ca_i * (1.0 - O_TC) - 392.0 * O_TC;\nconst Real dot_O_TMgC = 200000.0 * Ca_i * (1.0 - O_TMgC - O_TMgMg) - 6.6 * O_TMgC;\n*_new_O_C = O_C + dt*dot_O_C;\n*_new_O_TC = O_TC + dt*dot_O_TC;\n*_new_O_TMgC = O_TMgC + dt*dot_O_TMgC;\n*_new_O_TMgMg = O_TMgMg + dt*(2000.0 * Mg_i * (1.0 - O_TMgC - O_TMgMg) - 666.0 * O_TMgMg);\n\n// sarcolemmal calcium pump current\nconst Real i_CaP = i_CaP_max * Ca_i / (Ca_i + k_CaP);\n\n// h1 gate\nconst Real h_inf = 1.0 / (1.0 + exp((V + 63.6) / 5.3));\nconst Real tau_h1 = 0.03 / (1.0 + exp((V + 35.1) / 3.2)) + 0.0003;\n*_new_h1 = h_inf + (h1 - h_inf) * exp(-(dt / tau_h1));\n\n// m gate\nconst Real m_inf = 1.0 / (1.0 + exp((V + 27.12) / -8.21));\nconst Real tau_m = 4.2e-05 * exp(-pow((V + 25.57) / 28.8, 2.0)) + 2.4e-05;\n*_new_m = m_inf + (m - m_inf) * exp(-(dt / tau_m));\n\n// sodium potassium pump\nconst Real i_NaK = i_NaK_max * K_c / (K_c + k_NaK_K) * pow(Na_i, 1.5) / (pow(Na_i, 1.5) + pow(k_NaK_Na, 1.5)) * safe_divide(V + 150.0, V + 200.0);\n\n// r_sus gate\nconst Real r_sus_inf = 1.0 / (1.0 + exp((V + 4.3) / -8.0));\nconst Real tau_r_sus = 0.009 / (1.0 + exp((V + 5.0) / 12.0)) + 0.0005;\n*_new_r_sus = r_sus_inf + (r_sus - r_sus_inf) * exp(-(dt / tau_r_sus));\n\n// s_sus gate\nconst Real s_sus_inf = 0.4 / (1.0 + exp((V + 20.0) / 10.0)) + 0.6;\nconst Real tau_s_sus = 0.047 / (1.0 + exp((V + 60.0) / 10.0)) + 0.3;\n*_new_s_sus = s_sus_inf + (s_sus - s_sus_inf) * exp(-(dt / tau_s_sus));\n\n// f_L2 gate\nconst Real tau_f_L2 = 1.3323 * exp(-pow((V + 40.0) / 14.2, 2.0)) + 0.0626;\n*_new_f_L2 = f_L_inf + (f_L2 - f_L_inf) * exp(-(dt / tau_f_L2));\n\n// h2 gate\nconst Real tau_h2 = 0.12 / (1.0 + exp((V + 35.1) / 3.2)) + 0.003;\n*_new_h2 = h_inf + (h2 - h_inf) * exp(-(dt / tau_h2));\n\n// Ca handling by the SR\nconst Real dot_O_Calse = 480.0 * Ca_rel * (1.0 - O_Calse) - 400.0 * O_Calse;\nconst Real i_rel = alpha_rel * pow(F2 / (F2 + 0.25), 2.0) * (Ca_rel - Ca_i);\nconst Real i_up = I_up_max * (Ca_i / k_cyca - k_xcs * k_xcs * Ca_up / k_srca) / ((Ca_i + k_cyca) / k_cyca + k_xcs * (Ca_up + k_srca) / k_srca);\nconst Real r_act = 203.8 * (pow(Ca_i / (Ca_i + k_rel_i), 4.0) + pow(Ca_d / (Ca_d + k_rel_d), 4.0));\nconst Real r_inact = 33.96 + 339.6 * pow(Ca_i / (Ca_i + k_rel_i), 4.0);\n*_new_O_Calse = O_Calse + dt*dot_O_Calse;\n*_new_F1 = F1 + dt*(r_recov * (1.0 - F1 - F2) - r_act * F1);\n*_new_F2 = F2 + dt*(r_act * F1 - r_inact * F2);\n\n// sodium current\nconst Real E_Na = R * T / F * log(Na_c / Na_i);\nconst Real i_Na =\n  P_Na * m * m * m * (0.9 * h1 + 0.1 * h2) * Na_c * F * F / (R * T) *\n  (fabs(V) < 1e-3\n    ? R * T * (exp((-E_Na * F) / (R * T)) - 1.0) / F\n    : V * (exp((V - E_Na) * F / (R * T)) - 1.0)\n        / (exp(V * F / (R * T)) - 1.0)\n  );\n\n// remaining\nconst Real i_tr = (Ca_up - Ca_rel) * 2.0 * F * Vol_rel / tau_tr;\nconst Real E_K = R * T / F * log(K_c / K_i);\nconst Real i_NaCa = k_NaCa * (Na_i * Na_i * Na_i * Ca_c * exp(gamma * F * V / (R * T)) - Na_c * Na_c * Na_c * Ca_i * exp((gamma - 1.0) * V * F / (R * T))) / (1.0 + d_NaCa * (Na_c * Na_c * Na_c * Ca_i + Na_i * Na_i * Na_i * Ca_c));\nconst Real E_Ca = R * T / (2.0 * F) * log(Ca_c / Ca_i);\nconst Real i_B_Na = g_B_Na * (V - E_Na);\nconst Real i_di = (Ca_d - Ca_i) * 2.0 * F * Vol_d / tau_di;\n*_new_Ca_rel = Ca_rel + dt*((i_tr - i_rel) / (2.0 * Vol_rel * F) - 31.0 * dot_O_Calse);\n*_new_Ca_up = Ca_up + dt*((i_up - i_tr) / (2.0 * Vol_up * F));\nconst Real i_t = g_t * r * s * (V - E_K);\nconst Real i_B_Ca = g_B_Ca * (V - E_Ca);\n*_new_Na_c = Na_c + dt*((Na_b - Na_c) / tau_Na + (i_Na + i_B_Na + 3.0 * i_NaK + 3.0 * i_NaCa + phi_Na_en) / (Vol_c * F));\nconst Real i_Kr = g_Kr * p_a * p_i * (V - E_K);\nconst Real i_Ks = g_Ks * n * (V - E_K);\n*_new_Ca_d = Ca_d + dt*(-(i_Ca_L + i_di) / (2.0 * Vol_d * F));\n*_new_Na_i = Na_i + dt*(-(i_Na + i_B_Na + 3.0 * i_NaK + 3.0 * i_NaCa + phi_Na_en) / (Vol_i * F));\nconst Real i_K1 = g_K1 * pow(K_c / 1.0, 0.4457) * (V - E_K) / (1.0 + exp(1.5 * (V - E_K + 3.6) * F / (R * T)));\nconst Real i_sus = g_sus * r_sus * s_sus * (V - E_K);\n*_new_Ca_c = Ca_c + dt*((Ca_b - Ca_c) / tau_Ca + (i_Ca_L + i_B_Ca + i_CaP - 2.0 * i_NaCa) / (2.0 * Vol_c * F));\n*_new_K_c = K_c + dt*((K_b - K_c) / tau_K + (i_t + i_sus + i_K1 + i_Kr + i_Ks - 2.0 * i_NaK) / (Vol_c * F));\n*_new_Ca_i = Ca_i + dt*(-(-i_di + i_B_Ca + i_CaP - 2.0 * i_NaCa + i_up - i_rel) / (2.0 * Vol_i * F) - (0.08 * dot_O_TC + 0.16 * dot_O_TMgC + 0.045 * dot_O_C));\n*_new_K_i = K_i + dt*(-(i_t + i_sus + i_K1 + i_Kr + i_Ks - 2.0 * i_NaK) / (Vol_i * F));\n*_new_V = V + dt*(_diffuse_V - (i_Na + i_Ca_L + i_t + i_sus + i_K1 + i_Kr + i_Ks + i_B_Na + i_B_Ca + i_NaK + i_CaP + i_NaCa) / Cm);\n\n// check for unphysical values\nif(*_new_Ca_c <= 0.0) { *_new_Ca_c = VERY_SMALL_NUMBER; }\nif(*_new_Ca_d <= 0.0) { *_new_Ca_d = VERY_SMALL_NUMBER; }\nif(*_new_Ca_i <= 0.0) { *_new_Ca_i = VERY_SMALL_NUMBER; }\nif(*_new_Ca_rel <= 0.0) { *_new_Ca_rel = VERY_SMALL_NUMBER; }\nif(*_new_Ca_up <= 0.0) { *_new_Ca_up = VERY_SMALL_NUMBER; }\nif(*_new_K_c <= 0.0) { *_new_K_c = VERY_SMALL_NUMBER; }\nif(*_new_K_i <= 0.0) { *_new_K_i = VERY_SMALL_NUMBER; }\nif(*_new_Na_c <= 0.0) { *_new_Na_c = VERY_SMALL_NUMBER; }\nif(*_new_Na_i <= 0.0) { *_new_Na_i = VERY_SMALL_NUMBER; }\n'}, 'paci2013computational': {'name': 'Paci et al. 2013', 'description': 'This model comprises two electrophysiological models of human induced\npluripotent stem cell-derived cardiomyocytes (hiPSC-CMs), distinguishing\nbetween ventricular-like and atrial-like phenotypes.\nBased on experimental data from Ma et al. (2011), the models reproduce\nspontaneous action potentials and responses to current blockers. They were\ndeveloped to investigate the immature electrophysiological characteristics of\nhiPSC-CMs and the ionic mechanisms underlying their spontaneous activity and\nlong AP durations. The model uses a Hodgkin–Huxley framework and was\nconstructed to support drug testing and cardiac maturation studies.\nThe default parameters are based on the ventricular-like formulation, with an\nincreased IK1 to disable spontaneous activity, as suggested by the authors.\n', 'dois': ['https://doi.org/10.1007/s10439-013-0833-3'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human'], 'diffusivity': {'Vm': 1.0}, 'parameters': {'calcium_dynamics_Buf_C': 0.25, 'calcium_dynamics_Buf_SR': 10.0, 'calcium_dynamics_Kbuf_C': 0.001, 'calcium_dynamics_Kbuf_SR': 0.3, 'calcium_dynamics_Kup': 0.00025, 'calcium_dynamics_V_leak': 0.00044444, 'calcium_dynamics_VmaxUp': 0.56064, 'calcium_dynamics_a_rel': 16.464, 'calcium_dynamics_b_rel': 0.25, 'calcium_dynamics_c_rel': 8.232, 'calcium_dynamics_g_factor': 0.0411, 'calcium_dynamics_tau_g': 0.002, 'electric_potentials_E_K': -0.08880285397707481, 'electric_potentials_PkNa': 0.03, 'i_CaL_d_gate_offset_d': 9.1, 'i_CaL_f1_gate_offset_f1': 26.0, 'i_CaL_f2_gate_constf2': 1.0, 'i_CaL_f2_gate_offset_f2': 35.0, 'i_CaL_fCa_gate_tau_fCa': 0.002, 'i_CaL_g_CaL': 8.635702e-05, 'i_K1_g_K1': 50.0, 'i_Kr_E4031_coeff': 1.0, 'i_Kr_Xr1_gate_V_half': -20.69505995297709, 'i_Kr_g_Kr': 29.8667, 'i_Ks_Chromanol_coeff': 1.0, 'i_Ks_g_Ks': 2.041, 'i_NaCa_KmCa': 1.38, 'i_NaCa_KmNai': 87.5, 'i_NaCa_Ksat': 0.1, 'i_NaCa_alpha': 2.8571432, 'i_NaCa_gamma': 0.35, 'i_NaCa_kNaCa': 4900.0, 'i_NaK_Km_K': 1.0, 'i_NaK_Km_Na': 40.0, 'i_NaK_PNaK': 1.841424, 'i_Na_TTX_coeff': 1.0, 'i_Na_g_Na': 3671.2302, 'i_PCa_KPCa': 0.0005, 'i_PCa_g_PCa': 0.4125, 'i_b_Ca_g_b_Ca': 0.69264, 'i_b_Na_g_b_Na': 0.9, 'i_f_E_f': -0.017, 'i_f_g_f': 30.10312, 'i_to_g_to': 29.9038, 'model_parameters_Cao': 1.8, 'model_parameters_Cm': 9.87109e-11, 'model_parameters_F': 96485.3415, 'model_parameters_Ki': 150.0, 'model_parameters_Ko': 5.4, 'model_parameters_Nao': 151.0, 'model_parameters_R': 8.314472, 'model_parameters_T': 310.0, 'model_parameters_V_SR': 583.73, 'model_parameters_Vc': 8800.0}, 'initial values': {'ventricular': {'Vm': -0.0743340057623841, 'm': 0.102953468725004, 'h': 0.786926637881461, 'j': 0.253943221774722, 'd': 8.96088425225182e-05, 'f1': 0.970411811263976, 'f2': 0.999965815466749, 'fCa': 0.998925296531804, 'Xr1': 0.00778547011240132, 'Xr2': 0.432162576531617, 'Xs': 0.0322944866983666, 'Xf': 0.100615100568753, 'q': 0.839295925773219, 'r': 0.00573289893326379, 'Nai': 10.9248496211574, 'Cai': 1.80773974140477e-05, 'Ca_SR': 0.2734234751931, 'g': 0.999999981028517}, 'ventricular resting': {'Vm': -0.0743340057623841, 'm': 0.102953468725004, 'h': 0.786926637881461, 'j': 0.253943221774722, 'd': 8.96088425225182e-05, 'f1': 0.970411811263976, 'f2': 0.999965815466749, 'fCa': 0.998925296531804, 'Xr1': 0.00778547011240132, 'Xr2': 0.432162576531617, 'Xs': 0.0322944866983666, 'Xf': 0.100615100568753, 'q': 0.839295925773219, 'r': 0.00573289893326379, 'Nai': 10.9248496211574, 'Cai': 1.80773974140477e-05, 'Ca_SR': 0.2734234751931, 'g': 0.999999981028517}, 'atrial': {'Vm': -0.068733823452164, 'm': 0.141183142078492, 'h': 0.642108593994587, 'j': 0.173566329483423, 'd': 0.000127632520741878, 'f1': 0.98038400433601, 'f2': 0.999953006710394, 'fCa': 0.997346890768643, 'Xr1': 0.0257889110986083, 'Xr2': 0.405046678739985, 'Xs': 0.0447460799149437, 'Xf': 0.0607988713874682, 'q': 0.776163826643278, 'r': 0.000503296941001262, 'Nai': 14.4424010544424, 'Cai': 4.49232909234503e-05, 'Ca_SR': 0.149980051221604, 'g': 1.0}}, 'parameter sets': {'ventricular': {'calcium_dynamics_VmaxUp': 0.56064, 'calcium_dynamics_g_factor': 0.0411, 'i_CaL_d_gate_offset_d': 9.1, 'i_CaL_f1_gate_offset_f1': 26.0, 'i_CaL_f2_gate_constf2': 1.0, 'i_CaL_f2_gate_offset_f2': 35.0, 'i_K1_g_K1': 28.1492, 'i_NaCa_kNaCa': 4900.0, 'i_NaK_PNaK': 1.841424, 'i_Na_g_Na': 3671.2302, 'i_to_g_to': 29.9038, 'model_parameters_Cm': 9.87109e-11, 'model_parameters_V_SR': 583.73, 'model_parameters_Vc': 8800.0}, 'atrial': {'calcium_dynamics_VmaxUp': 0.22, 'calcium_dynamics_g_factor': 0.0556, 'i_CaL_d_gate_offset_d': 5.986, 'i_CaL_f1_gate_offset_f1': 25.226, 'i_CaL_f2_gate_constf2': 2.0, 'i_CaL_f2_gate_offset_f2': 31.226, 'i_K1_g_K1': 19.1925, 'i_NaCa_kNaCa': 2450.0, 'i_NaK_PNaK': 1.4731392, 'i_Na_g_Na': 6646.185, 'i_to_g_to': 59.8077, 'model_parameters_Cm': 7.86671e-11, 'model_parameters_V_SR': 465.2, 'model_parametegs_Vc': 7012.0}}, 'variables': {'Vm': -0.0743340057623841, 'm': 0.102953468725004, 'h': 0.786926637881461, 'j': 0.253943221774722, 'd': 8.96088425225182e-05, 'f1': 0.970411811263976, 'f2': 0.999965815466749, 'fCa': 0.998925296531804, 'Xr1': 0.00778547011240132, 'Xr2': 0.432162576531617, 'Xs': 0.0322944866983666, 'Xf': 0.100615100568753, 'q': 0.839295925773219, 'r': 0.00573289893326379, 'Nai': 10.9248496211574, 'Cai': 1.80773974140477e-05, 'Ca_SR': 0.2734234751931, 'g': 0.999999981028517}, 'example discretisation': {'dt': 0.00024, 'dx': 0.074, 'stimulus': 0.021}, 'units': {'t': 's', 'x': 'm', 'u': 'V'}, 'code': '// i_CaL_d_gate\nconst Real i_CaL_d_gate_alpha_d = 0.25 + 1.4 / (1.0 + exp((-Vm * 1000.0 - 35.0) / 13.0));\nconst Real i_CaL_d_gate_beta_d = 1.4 / (1.0 + exp((Vm * 1000.0 + 5.0) / 5.0));\nconst Real i_CaL_d_gate_d_infinity = 1.0 / (1.0 + exp(-(Vm * 1000.0 + i_CaL_d_gate_offset_d) / 7.0));\nconst Real i_CaL_d_gate_gamma_d = 1.0 / (1.0 + exp((-Vm * 1000.0 + 50.0) / 20.0));\nconst Real i_CaL_d_gate_tau_d = (i_CaL_d_gate_alpha_d * i_CaL_d_gate_beta_d + i_CaL_d_gate_gamma_d) * 1.0 / 1000.0;\n*_new_d = i_CaL_d_gate_d_infinity + (d - i_CaL_d_gate_d_infinity) * exp(-(dt / i_CaL_d_gate_tau_d));\n\n// i_CaL_f1_gate\nconst Real i_CaL_f1_gate_f1_inf = 1.0 / (1.0 + exp((Vm * 1000.0 + i_CaL_f1_gate_offset_f1) / 3.0));\nconst Real i_CaL_f1_gate_constf1 = ((i_CaL_f1_gate_f1_inf - f1 > 0.0) ? 1.0 + 1433.0 * (Cai - 50.0 * 1e-06) : 1.0);\nconst Real i_CaL_f1_gate_tau_f1 = (20.0 + (1102.5 * exp(-pow(pow(Vm * 1000.0 + 27.0, 2.0) / 15.0, 2.0)) + (200.0 / (1.0 + exp((13.0 - Vm * 1000.0) / 10.0)) + 180.0 / (1.0 + exp((30.0 + Vm * 1000.0) / 10.0))))) * i_CaL_f1_gate_constf1 / 1000.0;\n*_new_f1 = i_CaL_f1_gate_f1_inf + (f1 - i_CaL_f1_gate_f1_inf) * exp(-(dt / i_CaL_f1_gate_tau_f1));\n\n// i_CaL_f2_gate\nconst Real i_CaL_f2_gate_f2_inf = 0.33 + 0.67 / (1.0 + exp((Vm * 1000.0 + i_CaL_f2_gate_offset_f2) / 4.0));\nconst Real i_CaL_f2_gate_tau_f2 = (600.0 * exp(-pow(Vm * 1000.0 + 25.0, 2.0) / 170.0) + (31.0 / (1.0 + exp((25.0 - Vm * 1000.0) / 10.0)) + 16.0 / (1.0 + exp((30.0 + Vm * 1000.0) / 10.0)))) * i_CaL_f2_gate_constf2 / 1000.0;\n*_new_f2 = i_CaL_f2_gate_f2_inf + (f2 - i_CaL_f2_gate_f2_inf) * exp(-(dt / i_CaL_f2_gate_tau_f2));\n\n// i_CaL_fCa_gate\nconst Real i_CaL_fCa_gate_alpha_fCa = 1.0 / (1.0 + pow(Cai / 0.0006, 8.0));\nconst Real i_CaL_fCa_gate_beta_fCa = 0.1 / (1.0 + exp((Cai - 0.0009) / 0.0001));\nconst Real i_CaL_fCa_gate_gamma_fCa = 0.3 / (1.0 + exp((Cai - 0.00075) / 0.0008));\nconst Real i_CaL_fCa_gate_fCa_inf = (i_CaL_fCa_gate_alpha_fCa + (i_CaL_fCa_gate_beta_fCa + i_CaL_fCa_gate_gamma_fCa)) / 1.3156;\nconst Real i_CaL_fCa_gate_constfCa = (((Vm > -0.06) && (i_CaL_fCa_gate_fCa_inf > fCa)) ? 0.0 : 1.0);\n*_new_fCa = fCa + dt*(i_CaL_fCa_gate_constfCa * (i_CaL_fCa_gate_fCa_inf - fCa) / i_CaL_fCa_gate_tau_fCa);\n\n// i_Kr_Xr2_gate\nconst Real i_Kr_Xr2_gate_Xr2_infinity = 1.0 / (1.0 + exp((Vm * 1000.0 + 88.0) / 50.0));\nconst Real i_Kr_Xr2_gate_alpha_Xr2 = 3.0 / (1.0 + exp((-60.0 - Vm * 1000.0) / 20.0));\nconst Real i_Kr_Xr2_gate_beta_Xr2 = 1.12 / (1.0 + exp((-60.0 + Vm * 1000.0) / 20.0));\nconst Real i_Kr_Xr2_gate_tau_Xr2 = 1.0 * (i_Kr_Xr2_gate_alpha_Xr2 * i_Kr_Xr2_gate_beta_Xr2) / 1000.0;\n*_new_Xr2 = i_Kr_Xr2_gate_Xr2_infinity + (Xr2 - i_Kr_Xr2_gate_Xr2_infinity) * exp(-(dt / i_Kr_Xr2_gate_tau_Xr2));\n\n// i_Ks_Xs_gate\nconst Real i_Ks_Xs_gate_Xs_infinity = 1.0 / (1.0 + exp((-Vm * 1000.0 - 20.0) / 16.0));\nconst Real i_Ks_Xs_gate_alpha_Xs = 1100.0 / (sqrt(1.0 + exp((-10.0 - Vm * 1000.0) / 6.0)));\nconst Real i_Ks_Xs_gate_beta_Xs = 1.0 / (1.0 + exp((-60.0 + Vm * 1000.0) / 20.0));\nconst Real i_Ks_Xs_gate_tau_Xs = 1.0 * (i_Ks_Xs_gate_alpha_Xs * i_Ks_Xs_gate_beta_Xs) / 1000.0;\n*_new_Xs = i_Ks_Xs_gate_Xs_infinity + (Xs - i_Ks_Xs_gate_Xs_infinity) * exp(-(dt / i_Ks_Xs_gate_tau_Xs));\n\n// i_Na_h_gate\nconst Real i_Na_h_gate_alpha_h = ((Vm < -0.04) ? 0.057 * exp(-(Vm * 1000.0 + 80.0) / 6.8) : 0.0);\nconst Real i_Na_h_gate_beta_h = ((Vm < -0.04) ? 2.7 * exp(0.079 * (Vm * 1000.0)) + 3.1 * (pow(10.0, 5.0) * exp(0.3485 * (Vm * 1000.0))) : 0.77 / ((fabs(0.13 * (1.0 + exp((Vm * 1000.0 + 10.66) / -11.1))) < VERY_SMALL_NUMBER) ? ((0.13 * (1.0 + exp((Vm * 1000.0 + 10.66) / -11.1)) < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : 0.13 * (1.0 + exp((Vm * 1000.0 + 10.66) / -11.1))));\nconst Real i_Na_h_gate_h_inf = 1.0 / (sqrt(1.0 + exp((Vm * 1000.0 + 72.1) / 5.7)));\nconst Real i_Na_h_gate_tau_h = ((Vm < -0.04) ? 1.5 / ((i_Na_h_gate_alpha_h + i_Na_h_gate_beta_h) * 1000.0) : 2.542 / 1000.0);\n*_new_h = i_Na_h_gate_h_inf + (h - i_Na_h_gate_h_inf) * exp(-(dt / i_Na_h_gate_tau_h));\n\n// i_Na_j_gate\nconst Real i_Na_j_gate_alpha_j = ((Vm < -0.04) ? (-25428.0 * exp(0.2444 * (Vm * 1000.0)) - 6.948 * (pow(10.0, -6.0) * exp(-0.04391 * (Vm * 1000.0)))) * (Vm * 1000.0 + 37.78) / (1.0 + exp(0.311 * (Vm * 1000.0 + 79.23))) : 0.0);\nconst Real i_Na_j_gate_beta_j = ((Vm < -0.04) ? 0.02424 * exp(-0.01052 * (Vm * 1000.0)) / (1.0 + exp(-0.1378 * (Vm * 1000.0 + 40.14))) : 0.6 * exp(0.057 * (Vm * 1000.0)) / (1.0 + exp(-0.1 * (Vm * 1000.0 + 32.0))));\nconst Real i_Na_j_gate_j_inf = 1.0 / (sqrt(1.0 + exp((Vm * 1000.0 + 72.1) / 5.7)));\nconst Real i_Na_j_gate_tau_j = 7.0 / ((i_Na_j_gate_alpha_j + i_Na_j_gate_beta_j) * 1000.0);\n*_new_j = i_Na_j_gate_j_inf + (j - i_Na_j_gate_j_inf) * exp(-(dt / i_Na_j_gate_tau_j));\n\n// i_Na_m_gate\nconst Real i_Na_m_gate_alpha_m = 1.0 / (1.0 + exp((-Vm * 1000.0 - 60.0) / 5.0));\nconst Real i_Na_m_gate_beta_m = 0.1 / (1.0 + exp((Vm * 1000.0 + 35.0) / 5.0)) + 0.1 / (1.0 + exp((Vm * 1000.0 - 50.0) / 200.0));\nconst Real i_Na_m_gate_m_inf = 1.0 / (pow(1.0 + exp((-Vm * 1000.0 - 34.1) / 5.9), 1.0 / 3.0));\nconst Real i_Na_m_gate_tau_m = 1.0 * (i_Na_m_gate_alpha_m * i_Na_m_gate_beta_m) / 1000.0;\n*_new_m = i_Na_m_gate_m_inf + (m - i_Na_m_gate_m_inf) * exp(-(dt / i_Na_m_gate_tau_m));\n\n// i_PCa\nconst Real i_PCa_i_PCa = i_PCa_g_PCa * Cai / (Cai + i_PCa_KPCa);\n\n// i_f\nconst Real i_f_i_f = i_f_g_f * (Xf * (Vm - i_f_E_f));\n\n// i_f_Xf_gate\nconst Real i_f_Xf_gate_Xf_infinity = 1.0 / (1.0 + exp((Vm * 1000.0 + 77.85) / 5.0));\nconst Real i_f_Xf_gate_tau_Xf = 1900.0 / (1.0 + exp((Vm * 1000.0 + 15.0) / 10.0)) / 1000.0;\n*_new_Xf = i_f_Xf_gate_Xf_infinity + (Xf - i_f_Xf_gate_Xf_infinity) * exp(-(dt / i_f_Xf_gate_tau_Xf));\n\n// i_to_q_gate\nconst Real i_to_q_gate_q_inf = 1.0 / (1.0 + exp((Vm * 1000.0 + 53.0) / 13.0));\nconst Real i_to_q_gate_tau_q = (6.06 + 39.102 / (0.57 * exp(-0.08 * (Vm * 1000.0 + 44.0)) + 0.065 * exp(0.1 * (Vm * 1000.0 + 45.93)))) / 1000.0;\n*_new_q = i_to_q_gate_q_inf + (q - i_to_q_gate_q_inf) * exp(-(dt / i_to_q_gate_tau_q));\n\n// i_to_r_gate\nconst Real i_to_r_gate_r_inf = 1.0 / (1.0 + exp(-(Vm * 1000.0 - 22.3) / 18.75));\nconst Real i_to_r_gate_tau_r = (2.75352 + 14.40516 / (1.037 * exp(0.09 * (Vm * 1000.0 + 30.61)) + 0.369 * exp(-0.12 * (Vm * 1000.0 + 23.84)))) / 1000.0;\n*_new_r = i_to_r_gate_r_inf + (r - i_to_r_gate_r_inf) * exp(-(dt / i_to_r_gate_tau_r));\n\n// electric_potentials\nconst Real electric_potentials_E_Ca = 0.5 * (model_parameters_R * model_parameters_T) / model_parameters_F * log(model_parameters_Cao / (Cai));\nconst Real electric_potentials_E_Na = model_parameters_R * model_parameters_T / model_parameters_F * log(model_parameters_Nao / (Nai));\nconst Real electric_potentials_E_Ks = model_parameters_R * model_parameters_T / model_parameters_F * log((model_parameters_Ko + electric_potentials_PkNa * model_parameters_Nao) / (model_parameters_Ki + electric_potentials_PkNa * Nai));\n\n// i_CaL\nconst Real i_CaL_i_CaL = i_CaL_g_CaL * (4.0 * (Vm * pow(model_parameters_F, 2.0))) / (model_parameters_R * model_parameters_T) * (Cai * exp(2.0 * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)) - 0.341 * model_parameters_Cao) / ((fabs(exp(2.0 * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)) - 1.0) < VERY_SMALL_NUMBER) ? ((exp(2.0 * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)) - 1.0 < 0.0) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : exp(2.0 * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)) - 1.0) * (d * (f1 * (f2 * fCa)));\n\n// i_Kr_Xr1_gate\nconst Real i_Kr_Xr1_gate_alpha_Xr1 = 450.0 / (1.0 + exp((-45.0 - Vm * 1000.0) / 10.0));\nconst Real i_Kr_Xr1_gate_beta_Xr1 = 6.0 / (1.0 + exp((30.0 + Vm * 1000.0) / 11.5));\nconst Real i_Kr_Xr1_gate_tau_Xr1 = 1.0 * (i_Kr_Xr1_gate_alpha_Xr1 * i_Kr_Xr1_gate_beta_Xr1) / 1000.0;\nconst Real i_Kr_Xr1_gate_Xr1_inf = 1.0 / (1.0 + exp((i_Kr_Xr1_gate_V_half - Vm * 1000.0) / 4.9));\n*_new_Xr1 = i_Kr_Xr1_gate_Xr1_inf + (Xr1 - i_Kr_Xr1_gate_Xr1_inf) * exp(-(dt / i_Kr_Xr1_gate_tau_Xr1));\n\n// i_NaCa\nconst Real i_NaCa_i_NaCa = i_NaCa_kNaCa * (exp(i_NaCa_gamma * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)) * (pow(Nai, 3.0) * model_parameters_Cao) - exp((i_NaCa_gamma - 1.0) * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)) * (pow(model_parameters_Nao, 3.0) * (Cai * i_NaCa_alpha))) / ((pow(i_NaCa_KmNai, 3.0) + pow(model_parameters_Nao, 3.0)) * ((i_NaCa_KmCa + model_parameters_Cao) * (1.0 + i_NaCa_Ksat * exp((i_NaCa_gamma - 1.0) * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)))));\n\n// i_NaK\nconst Real i_NaK_i_NaK = i_NaK_PNaK * model_parameters_Ko / (model_parameters_Ko + i_NaK_Km_K) * Nai / (Nai + i_NaK_Km_Na) / (1.0 + (0.1245 * exp(-0.1 * (Vm * model_parameters_F) / (model_parameters_R * model_parameters_T)) + 0.0353 * exp(-Vm * model_parameters_F / (model_parameters_R * model_parameters_T))));\n\n// i_K1\nconst Real i_K1_alpha_K1 = 3.91 / (1.0 + exp(0.5942 * (Vm * 1000.0 - electric_potentials_E_K * 1000.0 - 200.0)));\nconst Real i_K1_beta_K1 = (-1.509 * exp(0.0002 * (Vm * 1000.0 - electric_potentials_E_K * 1000.0 + 100.0)) + exp(0.5886 * (Vm * 1000.0 - electric_potentials_E_K * 1000.0 - 10.0))) / (1.0 + exp(0.4547 * (Vm * 1000.0 - electric_potentials_E_K * 1000.0)));\nconst Real i_K1_XK1_inf = i_K1_alpha_K1 / (i_K1_alpha_K1 + i_K1_beta_K1);\nconst Real i_K1_i_K1 = i_K1_g_K1 * (i_K1_XK1_inf * ((Vm - electric_potentials_E_K) * sqrt(model_parameters_Ko / 5.4)));\n\n// i_Kr\nconst Real i_Kr_i_Kr = i_Kr_E4031_coeff * (i_Kr_g_Kr * ((Vm - electric_potentials_E_K) * (Xr1 * (Xr2 * sqrt(model_parameters_Ko / 5.4)))));\n\n// i_Ks\nconst Real i_Ks_i_Ks = i_Ks_Chromanol_coeff * (i_Ks_g_Ks * ((Vm - electric_potentials_E_Ks) * (pow(Xs, 2.0) * (1.0 + 0.6 / (1.0 + pow(3.8 * 1e-05 / (Cai), 1.4))))));\n\n// i_Na\nconst Real i_Na_i_Na = i_Na_TTX_coeff * (i_Na_g_Na * (pow(m, 3.0) * (h * (j * (Vm - electric_potentials_E_Na)))));\n\n// i_b_Ca\nconst Real i_b_Ca_i_b_Ca = i_b_Ca_g_b_Ca * (Vm - electric_potentials_E_Ca);\n\n// i_b_Na\nconst Real i_b_Na_i_b_Na = i_b_Na_g_b_Na * (Vm - electric_potentials_E_Na);\n\n// i_to\nconst Real i_to_i_to = i_to_g_to * ((Vm - electric_potentials_E_K) * (q * r));\n\n// Membrane\n*_new_Vm = Vm + dt*(_diffuse_Vm - (i_K1_i_K1 + i_to_i_to + i_Kr_i_Kr + i_Ks_i_Ks + i_CaL_i_CaL + i_NaK_i_NaK + i_Na_i_Na + i_NaCa_i_NaCa + i_PCa_i_PCa + i_f_i_f + i_b_Na_i_b_Na + i_b_Ca_i_b_Ca));\n\n// calcium_dynamics\nconst Real calcium_dynamics_g_inf = ((Cai <= 0.00035) ? 1.0 / (1.0 + pow(Cai / 0.00035, 6.0)) : 1.0 / (1.0 + pow(Cai / 0.00035, 16.0)));\nconst Real calcium_dynamics_Ca_SR_bufSR = 1.0 / (1.0 + calcium_dynamics_Buf_SR * calcium_dynamics_Kbuf_SR / (pow(Ca_SR + calcium_dynamics_Kbuf_SR, 2.0)));\nconst Real calcium_dynamics_Cai_bufc = 1.0 / (1.0 + calcium_dynamics_Buf_C * calcium_dynamics_Kbuf_C / (pow(Cai + calcium_dynamics_Kbuf_C, 2.0)));\nconst Real calcium_dynamics_const2 = (((calcium_dynamics_g_inf > g) && (Vm > -0.06)) ? 0.0 : 1.0);\nconst Real calcium_dynamics_i_leak = (Ca_SR - Cai) * calcium_dynamics_V_leak;\nconst Real calcium_dynamics_i_rel = (calcium_dynamics_c_rel + calcium_dynamics_a_rel * pow(Ca_SR, 2.0) / (pow(calcium_dynamics_b_rel, 2.0) + pow(Ca_SR, 2.0))) * (d * (g * calcium_dynamics_g_factor));\nconst Real calcium_dynamics_i_up = calcium_dynamics_VmaxUp / (1.0 + pow(calcium_dynamics_Kup, 2.0) / (pow(Cai, 2.0)));\n*_new_Ca_SR = Ca_SR + dt*(calcium_dynamics_Ca_SR_bufSR * model_parameters_Vc / model_parameters_V_SR * (calcium_dynamics_i_up - (calcium_dynamics_i_rel + calcium_dynamics_i_leak)));\n*_new_Cai = Cai + dt*(calcium_dynamics_Cai_bufc * (calcium_dynamics_i_leak - calcium_dynamics_i_up + calcium_dynamics_i_rel - (i_CaL_i_CaL + (i_b_Ca_i_b_Ca + i_PCa_i_PCa) - 2.0 * i_NaCa_i_NaCa) * model_parameters_Cm / (2.0 * (model_parameters_Vc * (model_parameters_F * 1e-18)))));\n*_new_g = g + dt*(calcium_dynamics_const2 * (calcium_dynamics_g_inf - g) / calcium_dynamics_tau_g);\n\n// sodium_dynamics\n*_new_Nai = Nai + dt*(-model_parameters_Cm * (i_Na_i_Na + (i_b_Na_i_b_Na + (3.0 * i_NaK_i_NaK + 3.0 * i_NaCa_i_NaCa))) / (model_parameters_F * (model_parameters_Vc * 1e-18)));\n\n// check for unphysical values\nif(*_new_Nai <= 0.0) { *_new_Nai = VERY_SMALL_NUMBER; }\nif(*_new_Cai <= 0.0) { *_new_Cai = VERY_SMALL_NUMBER; }\nif(*_new_Ca_SR <= 0.0) { *_new_Ca_SR = VERY_SMALL_NUMBER; }\n'}, 'tentusscher2006alternans': {'name': 'Ten Tusscher et al. 2006', 'description': 'This detailed human ventricular cell model was developed to investigate the\nmechanisms of electrical instability, alternans, and spiral wave breakup in\ncardiac tissue. It builds on their 2004 model by incorporating a more\ncomprehensive description of intracellular calcium dynamics, including\nsubspace calcium compartments and a Markov model of the ryanodine receptor\nfor calcium-induced calcium release (CICR). The model also includes both fast\nand slow voltage-dependent inactivation gates for the L-type calcium current,\nenabling more accurate simulation of calcium handling and its role in\narrhythmogenesis. It reproduces a wide range of experimentally observed APD\nrestitution slopes (see the parameter sets ``slope``, default ``slope[1.1]``)\nand explores the interaction between sodium current recovery dynamics and\ntissue-level instability. The model is suited for studying reentry,\nalternans, and ventricular fibrillation mechanisms in human cardiac tissue.\nThe model also has different parameter sets for epicardial (parameter set\n``epi``, default), endocardial (``endo``), and midmyocardial cells (``m``).\n', 'dois': ['https://doi.org/10.1152/ajpheart.00109.2006', 'https://doi.org/10.1152/ajpheart.00794.2003'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human', 'ventricle'], 'variables': {'V': -85.23, 'Ca_SR': 3.64, 'Ca_i': 0.000126, 'Ca_ss': 0.00036, 'K_i': 136.89, 'Na_i': 8.604, 'Rbar': 0.9073, 'Xr1': 0.00621, 'Xr2': 0.4712, 'Xs': 0.0095, 'd': 3.373e-05, 'f2': 0.9755, 'f': 0.7888, 'fCass': 0.9953, 'h': 0.7444, 'j': 0.7045, 'm': 0.00172, 'r': 2.42e-08, 's': 0.999998}, 'initial values': {'epi': {'V': -85.23, 'Ca_SR': 3.64, 'Ca_i': 0.000126, 'Ca_ss': 0.00036, 'K_i': 136.89, 'Na_i': 8.604, 'Rbar': 0.9073, 'Xr1': 0.00621, 'Xr2': 0.4712, 'Xs': 0.0095, 'd': 3.373e-05, 'f2': 0.9755, 'f': 0.7888, 'fCass': 0.9953, 'h': 0.7444, 'j': 0.7045, 'm': 0.00172, 'r': 2.42e-08, 's': 0.999998}, 'endo': {'V': -86.709, 'Ca_SR': 3.715, 'Ca_i': 0.00013, 'Ca_ss': 0.00036, 'K_i': 138.4, 'Na_i': 10.355, 'Rbar': 0.9068, 'Xr1': 0.00448, 'Xr2': 0.476, 'Xs': 0.0087, 'd': 3.164e-05, 'f2': 0.9778, 'f': 0.8009, 'fCass': 0.9953, 'h': 0.7573, 'j': 0.7225, 'm': 0.00155, 'r': 2.235e-08, 's': 0.3212}, 'm': {'V': -85.423, 'Ca_SR': 4.272, 'Ca_i': 0.000153, 'Ca_ss': 0.00042, 'K_i': 138.52, 'Na_i': 10.132, 'Rbar': 0.8978, 'Xr1': 0.0165, 'Xr2': 0.473, 'Xs': 0.0174, 'd': 3.288e-05, 'f2': 0.9526, 'f': 0.7026, 'fCass': 0.9942, 'h': 0.749, 'j': 0.6788, 'm': 0.00165, 'r': 2.347e-08, 's': 0.999998}}, 'diffusivity': {'V': 1.0}, 'parameters': {'Buf_c': 0.2, 'Buf_sr': 10.0, 'Buf_ss': 0.4, 'C_m': 185.0, 'Ca_o': 2.0, 'EC': 1.5, 'F': 96.485, 'K_buf_c': 0.001, 'K_buf_sr': 0.3, 'K_buf_ss': 0.00025, 'K_mCa': 1.38, 'K_mNa': 40.0, 'K_mNa_i': 87.5, 'K_mk': 1.0, 'K_o': 5.4, 'K_pCa': 0.0005, 'K_up': 0.00025, 'Na_o': 140.0, 'P_NaK': 2.724, 'R': 8.314, 'T': 310.0, 'V_c': 16404.0, 'V_leak': 0.00036, 'V_maxup': 0.006375, 'V_rel': 0.102, 'V_sr': 1094.0, 'V_ss': 54.68, 'V_xfer': 0.0038, 'alpha': 2.5, 'factor_f_tau': 1.0, 'factor_g_Kr': 1.0, 'factor_g_Ks': 1.0, 'factor_g_pCa': 1.0, 'factor_g_pK': 1.0, 'g_CaL': 0.0398, 'g_K1': 5.405, 'g_Kr': 0.153, 'g_Ks': 0.392, 'g_Na': 14.838, 'g_bCa': 0.000592, 'g_bNa': 0.00029, 'g_pCa': 0.1238, 'g_pK': 0.0146, 'g_to': 0.294, 'gamma': 0.35, 'k1_prime': 0.15, 'k2_prime': 0.045, 'k3': 0.06, 'k4': 0.005, 'k_NaCa': 1000.0, 'k_sat': 0.1, 'max_sr': 2.5, 'min_sr': 1.0, 'p_KNa': 0.03, 's_offset': 20.0, 's_variant': 0.0}, 'parameter sets': {'slope': {0.7: {'factor_g_Kr': 0.8758169934640524, 'factor_g_Ks': 0.6887755102040817, 'factor_g_pCa': 0.5, 'factor_g_pK': 5.0, 'factor_f_tau': 0.6}, 1.1: {'factor_g_Kr': 1.0, 'factor_g_Ks': 1.0, 'factor_g_pCa': 1.0, 'factor_g_pK': 1.0, 'factor_f_tau': 1.0}, 1.4: {'factor_g_Kr': 1.1241830065359477, 'factor_g_Ks': 1.125, 'factor_g_pCa': 3.0, 'factor_g_pK': 0.5, 'factor_f_tau': 1.5}, 1.8: {'factor_g_Kr': 1.1241830065359477, 'factor_g_Ks': 1.125, 'factor_g_pCa': 7.0, 'factor_g_pK': 0.15, 'factor_f_tau': 2.0}}, 'epi': {'g_Ks': 0.392, 'g_to': 0.294, 's_offset': 20.0, 's_variant': 0.0}, 'endo': {'g_Ks': 0.392, 'g_to': 0.073, 's_offset': 28.0, 's_variant': 1.0}, 'm': {'g_Ks': 0.098, 'g_to': 0.294, 's_offset': 20.0, 's_variant': 0.0}}, 'example discretisation': {'dt': 0.021, 'dx': 0.84, 'stimulus': 47.5}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}, 'code': '// i_CaL: gating variable d\nconst Real d_alpha = 1.4 / (1. + exp((-35. - V) / 13.)) + 0.25;\nconst Real d_beta = 1.4 / (1. + exp((V + 5.) / 5.));\nconst Real d_inf = 1. / (1. + exp((-8. - V) / 7.5));\nconst Real d_gamma = 1. / (1. + exp((50. - V) / 20.));\nconst Real d_tau = 1. * d_alpha * d_beta + d_gamma;\n*_new_d = d_inf + (d - d_inf) * exp(-(dt / d_tau));\n\n// i_CaL: gating variable f2\nconst Real f2_inf = 0.67 / (1. + exp((V + 35.) / 7.)) + 0.33;\nconst Real f2_tau = 562. * exp(-pow(V + 27., 2.) / 240.) + 31. / (1. + exp((25. - V) / 10.)) + 80. / (1. + exp((V + 30.) / 10.));\n*_new_f2 = f2_inf + (f2 - f2_inf) * exp(-(dt / f2_tau));\n\n// i_CaL: gating variable fCass\nconst Real fCass_inf = 0.6 / (1. + pow(Ca_ss / 0.05, 2.)) + 0.4;\nconst Real fCass_tau = 80. / (1. + pow(Ca_ss / 0.05, 2.)) + 2.;\n*_new_fCass = fCass_inf + (fCass - fCass_inf) * exp(-(dt / fCass_tau));\n\n// i_CaL: gating variable f\nconst Real f_inf = 1. / (1. + exp((V + 20.) / 7.));\nconst Real f_tau = 1102.5 * exp(-pow(V + 27., 2.) / 225.) + 200. / (1. + exp((13. - V) / 10.)) + 180. / (1. + exp((V + 30.) / 10.)) + 20.;\n*_new_f = f_inf + (f - f_inf) * exp(-(dt / (factor_f_tau * f_tau)));\n\n// i_pCa\nconst Real i_pCa = factor_g_pCa * g_pCa * Ca_i / (Ca_i + K_pCa);\n\n// i_Na: gating variable h\nconst Real h_alpha = ((V < -40.) ? 0.057 * exp(-(V + 80.) / 6.8) : 0.);\nconst Real h_beta = ((V < -40.) ? 2.7 * exp(0.079 * V) + 310000. * exp(0.3485 * V) : 0.77 / (0.13 * (1. + exp((V + 10.66) / -11.1))));\nconst Real h_inf = 1. / (pow(1. + exp((V + 71.55) / 7.43), 2.));\nconst Real h_tau = 1. / (h_alpha + h_beta);\n*_new_h = h_inf + (h - h_inf) * exp(-(dt / h_tau));\n\n// i_Na: gating variable j\nconst Real j_alpha = ((V < -40.) ? (-25428. * exp(0.2444 * V) - 6.948e-06 * exp(-0.04391 * V)) * (V + 37.78) / 1. / (1. + exp(0.311 * (V + 79.23))) : 0.);\nconst Real j_beta = ((V < -40.) ? 0.02424 * exp(-0.01052 * V) / (1. + exp(-0.1378 * (V + 40.14))) : 0.6 * exp(0.057 * V) / (1. + exp(-0.1 * (V + 32.))));\nconst Real j_inf = 1. / (pow(1. + exp((V + 71.55) / 7.43), 2.));\nconst Real j_tau = 1. / (j_alpha + j_beta);\n*_new_j = j_inf + (j - j_inf) * exp(-(dt / j_tau));\n\n// i_Na: gating variable m\nconst Real m_alpha = 1. / (1. + exp((-60. - V) / 5.));\nconst Real m_beta = 0.1 / (1. + exp((V + 35.) / 5.)) + 0.1 / (1. + exp((V - 50.) / 200.));\nconst Real m_inf = 1. / (pow(1. + exp((-56.86 - V) / 9.03), 2.));\nconst Real m_tau = 1. * m_alpha * m_beta;\n*_new_m = m_inf + (m - m_inf) * exp(-(dt / m_tau));\n\n// i_Kr: gating variable Xr1\nconst Real Xr1_alpha = 450. / (1. + exp((-45. - V) / 10.));\nconst Real Xr1_beta = 6. / (1. + exp((V + 30.) / 11.5));\nconst Real Xr1_inf = 1. / (1. + exp((-26. - V) / 7.));\nconst Real Xr1_tau = 1. * Xr1_alpha * Xr1_beta;\n*_new_Xr1 = Xr1_inf + (Xr1 - Xr1_inf) * exp(-(dt / Xr1_tau));\n\n// i_Kr: gating variable Xr2\nconst Real Xr2_alpha = 3. / (1. + exp((-60. - V) / 20.));\nconst Real Xr2_beta = 1.12 / (1. + exp((V - 60.) / 20.));\nconst Real Xr2_inf = 1. / (1. + exp((V + 88.) / 24.));\nconst Real Xr2_tau = 1. * Xr2_alpha * Xr2_beta;\n*_new_Xr2 = Xr2_inf + (Xr2 - Xr2_inf) * exp(-(dt / Xr2_tau));\n\n// i_Ks: gating variable Xs\nconst Real Xs_alpha = 1400. / (sqrt(1. + exp((5. - V) / 6.)));\nconst Real Xs_beta = 1. / (1. + exp((V - 35.) / 15.));\nconst Real Xs_inf = 1. / (1. + exp((-5. - V) / 14.));\nconst Real Xs_tau = 1. * Xs_alpha * Xs_beta + 80.;\n*_new_Xs = Xs_inf + (Xs - Xs_inf) * exp(-(dt / Xs_tau));\n\n// i_to: gating variable r\nconst Real r_inf = 1. / (1. + exp((20. - V) / 6.));\nconst Real r_tau = 9.5 * exp(-pow(V + 40., 2.) / 1800.) + 0.8;\n*_new_r = r_inf + (r - r_inf) * exp(-(dt / r_tau));\n\n// i_to: gating variable s\nconst Real s_inf = 1. / (1. + exp((V + s_offset) / 5.));\nReal s_tau = 0;\nif(s_variant > 0.5) {\n    s_tau = 1000. * exp(-pow(V + 67., 2.) / 1000.) + 8.;\n} else {\n    s_tau = 85. * exp(-pow(V + 45., 2.) / 320.) + 5. / (1. + exp((V - 20.) / 5.)) + 3.;\n}\n*_new_s = s_inf + (s - s_inf) * exp(-(dt / s_tau));\n\n// dynCa\nconst Real f_JCa_i_free = 1. / (1. + Buf_c * K_buf_c / (pow(Ca_i + K_buf_c, 2.)));\nconst Real f_JCa_sr_free = 1. / (1. + Buf_sr * K_buf_sr / (pow(Ca_SR + K_buf_sr, 2.)));\nconst Real f_JCa_ss_free = 1. / (1. + Buf_ss * K_buf_ss / (pow(Ca_ss + K_buf_ss, 2.)));\nconst Real i_leak = V_leak * (Ca_SR - Ca_i);\nconst Real i_up = V_maxup / (1. + pow(K_up, 2.) / (pow(Ca_i, 2.)));\nconst Real i_xfer = V_xfer * (Ca_ss - Ca_i);\nconst Real kcasr = max_sr - (max_sr - min_sr) / (1. + pow(EC / (Ca_SR), 2.));\nconst Real k1 = k1_prime / (kcasr);\nconst Real k2 = k2_prime * kcasr;\nconst Real O = k1 * pow(Ca_ss, 2.) * Rbar / (k3 + k1 * pow(Ca_ss, 2.));\n*_new_Rbar = Rbar + dt*(-k2 * Ca_ss * Rbar + k4 * (1. - Rbar));\nconst Real i_rel = V_rel * O * (Ca_SR - Ca_ss);\nconst Real ddt_Ca_sr_total = i_up - (i_rel + i_leak);\n*_new_Ca_SR = Ca_SR + dt*(ddt_Ca_sr_total * f_JCa_sr_free);\n\n// *remaining*\nconst Real E_Ca = 0.5 * R * T / F * log(Ca_o / (Ca_i));\nconst Real E_K = R * T / F * log(K_o / (K_i));\nconst Real E_Ks = R * T / F * log((K_o + p_KNa * Na_o) / (K_i + p_KNa * Na_i));\nconst Real E_Na = R * T / F * log(Na_o / (Na_i));\nconst Real i_CaL = g_CaL * d * f * f2 * fCass * 4. * (V - 15.) * pow(F, 2.) / (R * T) * (0.25 * Ca_ss * exp(2. * (V - 15.) * F / (R * T)) - Ca_o) / ((fabs(exp(2. * (V - 15.) * F / (R * T)) - 1.) < VERY_SMALL_NUMBER) ? ((exp(2. * (V - 15.) * F / (R * T)) - 1. < 0.) ? -VERY_SMALL_NUMBER : VERY_SMALL_NUMBER) : exp(2. * (V - 15.) * F / (R * T)) - 1.);\nconst Real i_NaK = P_NaK * K_o / (K_o + K_mk) * Na_i / (Na_i + K_mNa) / (1. + 0.1245 * exp(-0.1 * V * F / (R * T)) + 0.0353 * exp(-V * F / (R * T)));\nconst Real i_NaCa = k_NaCa * (exp(gamma * V * F / (R * T)) * pow(Na_i, 3.) * Ca_o - exp((gamma - 1.) * V * F / (R * T)) * pow(Na_o, 3.) * Ca_i * alpha) / ((pow(K_mNa_i, 3.) + pow(Na_o, 3.)) * (K_mCa + Ca_o) * (1. + k_sat * exp((gamma - 1.) * V * F / (R * T))));\nconst Real i_K1_alpha_K1 = 0.1 / (1. + exp(0.06 * (V - E_K - 200.)));\nconst Real i_K1_beta_K1 = (3. * exp(0.0002 * (V - E_K + 100.)) + exp(0.1 * (V - E_K - 10.))) / (1. + exp(-0.5 * (V - E_K)));\nconst Real i_Kr = factor_g_Kr * g_Kr * sqrt(K_o / 5.4) * Xr1 * Xr2 * (V - E_K);\nconst Real i_Ks = factor_g_Ks * g_Ks * pow(Xs, 2.) * (V - E_Ks);\nconst Real i_Na = g_Na * pow(m, 3.) * h * j * (V - E_Na);\nconst Real i_bNa = g_bNa * (V - E_Na);\nconst Real i_bCa = g_bCa * (V - E_Ca);\nconst Real i_to = g_to * r * s * (V - E_K);\nconst Real i_pK = factor_g_pK * g_pK * (V - E_K) / (1. + exp((25. - V) / 5.98));\nconst Real ddt_Ca_ss_total = -i_CaL * C_m / (2. * V_ss * F) + i_rel * V_sr / V_ss - i_xfer * V_c / V_ss;\nconst Real i_K1_xK1_inf = i_K1_alpha_K1 / (i_K1_alpha_K1 + i_K1_beta_K1);\nconst Real ddt_Ca_i_total = -(i_bCa + i_pCa - 2. * i_NaCa) * C_m / (2. * V_c * F) + (i_leak - i_up) * V_sr / V_c + i_xfer;\n*_new_Ca_ss = Ca_ss + dt*(ddt_Ca_ss_total * f_JCa_ss_free);\n*_new_Na_i = Na_i + dt*(-(i_Na + i_bNa + 3. * i_NaK + 3. * i_NaCa) / (V_c * F) * C_m);\nconst Real i_K1 = g_K1 * i_K1_xK1_inf * sqrt(K_o / 5.4) * (V - E_K);\n*_new_Ca_i = Ca_i + dt*(ddt_Ca_i_total * f_JCa_i_free);\n*_new_V = V + dt*(-(i_K1 + i_to + i_Kr + i_Ks + i_CaL + i_NaK + i_Na + i_bNa + i_NaCa + i_bCa + i_pK + i_pCa) + _diffuse_V);\n*_new_K_i = K_i + dt*(-(i_K1 + i_to + i_Kr + i_Ks + i_pK - 2. * i_NaK) / (V_c * F) * C_m);\n'}, 'tomek2019development': {'name': 'Tomek et al. 2019', 'description': 'A human-based ventricular model (ToR-Ord, endocardial, epicardial,\nmidmyocardial) for simulations of electrophysiology and\nexcitation-contraction coupling, from ionic to whole-organ dynamics,\nincluding the electrocardiogram. Validation based on substantial multiscale\nsimulations supports the credibility of the ToR-ORd model under healthy and\nkey disease conditions, as well as drug blockade. In addition, the process\nuncovers new theoretical insights into the biophysical properties of the\nL-type calcium current, which are critical for sodium and calcium dynamics.\nThese insights enable the reformulation of L-type calcium current, as well as\nreplacement of the hERG current model.\n', 'dois': ['https://doi.org/10.7554/eLife.48890'], 'keywords': ['excitable media', 'electrophysiology', 'heart', 'human', 'ventricle'], 'initial conditions': {'endo': {'V': -88.7638, 'CaMKt': 0.0111, 'Nai': 12.1025, 'Nass': 12.1029, 'Ki': 142.3002, 'Kss': 142.3002, 'Cass': 7.0305e-05, 'Cansr': 1.5211, 'Cajsr': 1.5214, 'Cai': 8.1583e-05, 'm': 0.00080572, 'h': 0.8286, 'j': 0.8284, 'hp': 0.6707, 'jp': 0.8281, 'mL': 0.0001629, 'hL': 0.5255, 'hLp': 0.2872, 'a': 0.00095098, 'iF': 0.9996, 'iS': 0.5936, 'ap': 0.00048454, 'iFp': 0.9996, 'iSp': 0.6538, 'd': 8.1084e-09, 'ff': 1.0, 'fs': 0.939, 'fcaf': 1.0, 'fcas': 0.9999, 'jca': 1.0, 'ffp': 1.0, 'fcafp': 1.0, 'nca_ss': 0.00066462, 'nca_i': 0.0012, 'C1': 0.00070344, 'C2': 0.00085109, 'C3': 0.9981, 'I': 1.3289e-05, 'O': 0.00037585, 'xs1': 0.248, 'xs2': 0.00017707, 'Jrel_np': 1.6129e-22, 'Jrel_p': 1.2475e-20}, 'epi': {'V': -89.14, 'CaMKt': 0.0129, 'Nai': 12.8363, 'Nass': 12.8366, 'Ki': 142.6951, 'Kss': 142.6951, 'Cass': 5.7672e-05, 'Cansr': 1.8119, 'Cajsr': 1.8102, 'Cai': 6.6309e-05, 'm': 0.00074303, 'h': 0.836, 'j': 0.8359, 'hp': 0.6828, 'jp': 0.8357, 'mL': 0.00015166, 'hL': 0.5401, 'hLp': 0.3034, 'a': 0.00092716, 'iF': 0.9996, 'iS': 0.9996, 'ap': 0.0004724, 'iFp': 0.9996, 'iSp': 0.9996, 'd': 0.0, 'ff': 1.0, 'fs': 0.9485, 'fcaf': 1.0, 'fcas': 0.9999, 'jca': 1.0, 'ffp': 1.0, 'fcafp': 1.0, 'nca_ss': 0.00030853, 'nca_i': 0.00053006, 'C1': 0.00067941, 'C2': 0.00082869, 'C3': 0.9982, 'I': 9.5416e-06, 'O': 0.00027561, 'xs1': 0.2309, 'xs2': 0.00016975, 'Jrel_np': 2.8189e-24, 'Jrel_p': 0.0}, 'mid': {'V': -89.1704, 'CaMKt': 0.0192, 'Nai': 15.0038, 'Nass': 15.0043, 'Ki': 143.0403, 'Kss': 143.0402, 'Cass': 6.5781e-05, 'Cansr': 1.9557, 'Cajsr': 1.9593, 'Cai': 8.166e-05, 'm': 0.00073818, 'h': 0.8365, 'j': 0.8363, 'hp': 0.6838, 'jp': 0.8358, 'mL': 0.00015079, 'hL': 0.5327, 'hLp': 0.2834, 'a': 0.00092527, 'iF': 0.9996, 'iS': 0.5671, 'ap': 0.00047143, 'iFp': 0.9996, 'iSp': 0.6261, 'd': 0.0, 'ff': 1.0, 'fs': 0.92, 'fcaf': 1.0, 'fcas': 0.9998, 'jca': 1.0, 'ffp': 1.0, 'fcafp': 1.0, 'nca_ss': 0.00051399, 'nca_i': 0.0012, 'C1': 0.0006956, 'C2': 0.00082672, 'C3': 0.9979, 'I': 1.8784e-05, 'O': 0.00054206, 'xs1': 0.2653, 'xs2': 0.00016921, 'Jrel_np': 0.0, 'Jrel_p': 0.0}}, 'variables': {'V': -88.7638, 'CaMKt': 0.0111, 'Nai': 12.1025, 'Nass': 12.1029, 'Ki': 142.3002, 'Kss': 142.3002, 'Cass': 7.0305e-05, 'Cansr': 1.5211, 'Cajsr': 1.5214, 'Cai': 8.1583e-05, 'm': 0.00080572, 'h': 0.8286, 'j': 0.8284, 'hp': 0.6707, 'jp': 0.8281, 'mL': 0.0001629, 'hL': 0.5255, 'hLp': 0.2872, 'a': 0.00095098, 'iF': 0.9996, 'iS': 0.5936, 'ap': 0.00048454, 'iFp': 0.9996, 'iSp': 0.6538, 'd': 8.1084e-09, 'ff': 1.0, 'fs': 0.939, 'fcaf': 1.0, 'fcas': 0.9999, 'jca': 1.0, 'ffp': 1.0, 'fcafp': 1.0, 'nca_ss': 0.00066462, 'nca_i': 0.0012, 'C1': 0.00070344, 'C2': 0.00085109, 'C3': 0.9981, 'I': 1.3289e-05, 'O': 0.00037585, 'xs1': 0.248, 'xs2': 0.00017707, 'Jrel_np': 1.6129e-22, 'Jrel_p': 1.2475e-20}, 'diffusivity': {'V': 1.0}, 'parameter sets': {'endo': {'CaMKo': 0.05, 'KmCaM': 0.0015, 'KmCaMK': 0.15, 'aCaMK': 0.05, 'bCaMK': 0.00068, 'GpCa': 0.0005, 'KmCap': 0.0005, 'Acap': 0.00015335760000000003, 'vjsr': 1.8237120000000002e-07, 'vmyo': 2.583592000000001e-05, 'vnsr': 2.0972688000000006e-06, 'vss': 7.598800000000002e-07, 'tauCa': 0.2, 'tauK': 2.0, 'tauNa': 2.0, 'celltype': 0.0, 'cao': 1.8, 'ko': 5.0, 'nao': 140.0, 'F': 96485.0, 'R': 8314.0, 'T': 310.0, 'zca': 2.0, 'zk': 1.0, 'zna': 1.0, 'Jup_b': 1.0, 'upScale': 1.0, 'BSLmax': 1.124, 'BSRmax': 0.047, 'KmBSL': 0.0087, 'KmBSR': 0.00087, 'cli': 24.0, 'csqnmax': 10.0, 'kmcmdn': 0.00238, 'kmcsqn': 0.8, 'kmtrpn': 0.0005, 'trpnmax': 0.07, 'cmdnmax': 0.05, 'ECl': -48.95253676506265, 'PKNa': 0.01833, 'fkatp': 0.0, 'gkatp': 4.3195, 'akik': 1.0, 'bkik': 0.015384615384615385, 'GNa': 11.7802, 'thL': 200.0, 'GNaL': 0.0279, 'thLp': 600.0, 'EKshift': 0.0, 'Gto': 0.16, 'Aff': 0.6, 'ICaL_fractionSS': 0.8, 'Kmn': 0.002, 'k2n': 500.0, 'offset': 0.0, 'tjca': 75.0, 'vShift': 0.0, 'Afs': 0.4, 'PCa': 8.3757e-05, 'constA': 0.5238190247282047, 'PCaK': 2.99347518e-08, 'PCaNa': 1.0469625000000001e-07, 'PCap': 9.213270000000001e-05, 'gamma_cao': 0.6117017520062547, 'gamma_ko': 0.8843718923169582, 'gamma_nao': 0.8843718923169582, 'PCaKp': 3.292822698000001e-08, 'PCaNap': 1.1516587500000002e-07, 'alpha_1': 0.154375, 'beta_1': 0.1911, 'GKr': 0.0321, 'GKs': 0.0011, 'GK1': 0.6992, 'INaCa_fractionSS': 0.35, 'KmCaAct': 0.00015, 'kcaon': 1500000.0, 'kna1': 15.0, 'kna2': 5.0, 'kna3': 88.12, 'qca': 0.167, 'qna': 0.5224, 'wca': 60000.0, 'wna': 60000.0, 'wnaca': 5000.0, 'Gncx': 0.0034, 'k2_i': 5000.0, 'k2_ss': 5000.0, 'k5_i': 5000.0, 'k5_ss': 5000.0, 'h11_i': 0.9196480938416423, 'h11_ss': 0.9196480938416423, 'k1_i': 9501.466275659823, 'k1_ss': 9501.466275659823, 'H': 1e-07, 'Khp': 1.698e-07, 'Kki': 0.5, 'Kko': 0.3582, 'Kmgatp': 1.698e-07, 'Knai0': 9.073, 'Knao0': 27.78, 'Knap': 224.0, 'Kxkur': 292.0, 'MgATP': 9.8, 'delta': -0.155, 'eP': 4.2, 'k1p': 949.5, 'k2m': 39.4, 'k3m': 79300.0, 'k3p': 1899.0, 'k4m': 40.0, 'Pnak': 15.4509, 'a2': 687.2, 'a4': 638.9999889283472, 'b1': 9.120000000000001, 'GKb': 0.0189, 'PNab': 1.9239e-09, 'PCab': 5.9194e-08, 'Fjunc': 1.0, 'GClCa': 0.2843, 'GClb': 0.00198, 'KdClCa': 0.1, 'Jrel_b': 1.5378, 'bt': 4.75, 'cajsr_half': 1.7, 'a_rel': 2.375, 'btp': 5.9375, 'a_relp': 2.96875}, 'epi': {'CaMKo': 0.05, 'KmCaM': 0.0015, 'KmCaMK': 0.15, 'aCaMK': 0.05, 'bCaMK': 0.00068, 'GpCa': 0.0005, 'KmCap': 0.0005, 'Acap': 0.00015335760000000003, 'vjsr': 1.8237120000000002e-07, 'vmyo': 2.583592000000001e-05, 'vnsr': 2.0972688000000006e-06, 'vss': 7.598800000000002e-07, 'tauCa': 0.2, 'tauK': 2.0, 'tauNa': 2.0, 'celltype': 1.0, 'cao': 1.8, 'ko': 5.0, 'nao': 140.0, 'F': 96485.0, 'R': 8314.0, 'T': 310.0, 'zca': 2.0, 'zk': 1.0, 'zna': 1.0, 'Jup_b': 1.0, 'upScale': 1.3, 'BSLmax': 1.124, 'BSRmax': 0.047, 'KmBSL': 0.0087, 'KmBSR': 0.00087, 'cli': 24.0, 'csqnmax': 10.0, 'kmcmdn': 0.00238, 'kmcsqn': 0.8, 'kmtrpn': 0.0005, 'trpnmax': 0.07, 'cmdnmax': 0.065, 'ECl': -48.95253676506265, 'PKNa': 0.01833, 'fkatp': 0.0, 'gkatp': 4.3195, 'akik': 1.0, 'bkik': 0.015384615384615385, 'GNa': 11.7802, 'thL': 200.0, 'GNaL': 0.01674, 'thLp': 600.0, 'EKshift': 0.0, 'Gto': 0.32, 'Aff': 0.6, 'ICaL_fractionSS': 0.8, 'Kmn': 0.002, 'k2n': 500.0, 'offset': 0.0, 'tjca': 75.0, 'vShift': 0.0, 'Afs': 0.4, 'PCa': 0.00010050840000000001, 'constA': 0.5238190247282047, 'PCaK': 3.5921702160000004e-08, 'PCaNa': 1.2563550000000001e-07, 'PCap': 0.00011055924000000001, 'gamma_cao': 0.6117017520062547, 'gamma_ko': 0.8843718923169582, 'gamma_nao': 0.8843718923169582, 'PCaKp': 3.951387237600001e-08, 'PCaNap': 1.3819905000000003e-07, 'alpha_1': 0.154375, 'beta_1': 0.1911, 'GKr': 0.041729999999999996, 'GKs': 0.00154, 'GK1': 0.83904, 'INaCa_fractionSS': 0.35, 'KmCaAct': 0.00015, 'kcaon': 1500000.0, 'kna1': 15.0, 'kna2': 5.0, 'kna3': 88.12, 'qca': 0.167, 'qna': 0.5224, 'wca': 60000.0, 'wna': 60000.0, 'wnaca': 5000.0, 'Gncx': 0.0037400000000000003, 'k2_i': 5000.0, 'k2_ss': 5000.0, 'k5_i': 5000.0, 'k5_ss': 5000.0, 'h11_i': 0.9196480938416423, 'h11_ss': 0.9196480938416423, 'k1_i': 9501.466275659823, 'k1_ss': 9501.466275659823, 'H': 1e-07, 'Khp': 1.698e-07, 'Kki': 0.5, 'Kko': 0.3582, 'Kmgatp': 1.698e-07, 'Knai0': 9.073, 'Knao0': 27.78, 'Knap': 224.0, 'Kxkur': 292.0, 'MgATP': 9.8, 'delta': -0.155, 'eP': 4.2, 'k1p': 949.5, 'k2m': 39.4, 'k3m': 79300.0, 'k3p': 1899.0, 'k4m': 40.0, 'Pnak': 13.90581, 'a2': 687.2, 'a4': 638.9999889283472, 'b1': 9.120000000000001, 'GKb': 0.01134, 'PNab': 1.9239e-09, 'PCab': 5.9194e-08, 'Fjunc': 1.0, 'GClCa': 0.2843, 'GClb': 0.00198, 'KdClCa': 0.1, 'Jrel_b': 1.5378, 'bt': 4.75, 'cajsr_half': 1.7, 'a_rel': 2.375, 'btp': 5.9375, 'a_relp': 2.96875}, 'mid': {'CaMKo': 0.05, 'KmCaM': 0.0015, 'KmCaMK': 0.15, 'aCaMK': 0.05, 'bCaMK': 0.00068, 'GpCa': 0.0005, 'KmCap': 0.0005, 'Acap': 0.00015335760000000003, 'vjsr': 1.8237120000000002e-07, 'vmyo': 2.583592000000001e-05, 'vnsr': 2.0972688000000006e-06, 'vss': 7.598800000000002e-07, 'tauCa': 0.2, 'tauK': 2.0, 'tauNa': 2.0, 'celltype': 2.0, 'cao': 1.8, 'ko': 5.0, 'nao': 140.0, 'F': 96485.0, 'R': 8314.0, 'T': 310.0, 'zca': 2.0, 'zk': 1.0, 'zna': 1.0, 'Jup_b': 1.0, 'upScale': 1.0, 'BSLmax': 1.124, 'BSRmax': 0.047, 'KmBSL': 0.0087, 'KmBSR': 0.00087, 'cli': 24.0, 'csqnmax': 10.0, 'kmcmdn': 0.00238, 'kmcsqn': 0.8, 'kmtrpn': 0.0005, 'trpnmax': 0.07, 'cmdnmax': 0.05, 'ECl': -48.95253676506265, 'PKNa': 0.01833, 'fkatp': 0.0, 'gkatp': 4.3195, 'akik': 1.0, 'bkik': 0.015384615384615385, 'GNa': 11.7802, 'thL': 200.0, 'GNaL': 0.0279, 'thLp': 600.0, 'EKshift': 0.0, 'Gto': 0.32, 'Aff': 0.6, 'ICaL_fractionSS': 0.8, 'Kmn': 0.002, 'k2n': 500.0, 'offset': 0.0, 'tjca': 75.0, 'vShift': 0.0, 'Afs': 0.4, 'PCa': 0.000167514, 'constA': 0.5238190247282047, 'PCaK': 5.98695036e-08, 'PCaNa': 2.0939250000000001e-07, 'PCap': 0.00018426540000000003, 'gamma_cao': 0.6117017520062547, 'gamma_ko': 0.8843718923169582, 'gamma_nao': 0.8843718923169582, 'PCaKp': 6.585645396000002e-08, 'PCaNap': 2.3033175000000005e-07, 'alpha_1': 0.154375, 'beta_1': 0.1911, 'GKr': 0.025679999999999998, 'GKs': 0.0011, 'GK1': 0.9089600000000001, 'INaCa_fractionSS': 0.35, 'KmCaAct': 0.00015, 'kcaon': 1500000.0, 'kna1': 15.0, 'kna2': 5.0, 'kna3': 88.12, 'qca': 0.167, 'qna': 0.5224, 'wca': 60000.0, 'wna': 60000.0, 'wnaca': 5000.0, 'Gncx': 0.0047599999999999995, 'k2_i': 5000.0, 'k2_ss': 5000.0, 'k5_i': 5000.0, 'k5_ss': 5000.0, 'h11_i': 0.9196480938416423, 'h11_ss': 0.9196480938416423, 'k1_i': 9501.466275659823, 'k1_ss': 9501.466275659823, 'H': 1e-07, 'Khp': 1.698e-07, 'Kki': 0.5, 'Kko': 0.3582, 'Kmgatp': 1.698e-07, 'Knai0': 9.073, 'Knao0': 27.78, 'Knap': 224.0, 'Kxkur': 292.0, 'MgATP': 9.8, 'delta': -0.155, 'eP': 4.2, 'k1p': 949.5, 'k2m': 39.4, 'k3m': 79300.0, 'k3p': 1899.0, 'k4m': 40.0, 'Pnak': 10.81563, 'a2': 687.2, 'a4': 638.9999889283472, 'b1': 9.120000000000001, 'GKb': 0.0189, 'PNab': 1.9239e-09, 'PCab': 5.9194e-08, 'Fjunc': 1.0, 'GClCa': 0.2843, 'GClb': 0.00198, 'KdClCa': 0.1, 'Jrel_b': 1.5378, 'bt': 4.75, 'cajsr_half': 1.7, 'a_rel': 2.375, 'btp': 5.9375, 'a_relp': 2.96875}}, 'extra parameters': {'L': 0.01, 'rad': 0.0011, 'Ageo': 7.667880000000002e-05, 'vcell': 3.799400000000001e-05, 'clo': 150.0, 'zcl': -1.0, 'cmdnmax_b': 0.05, 'A_atp': 2.0, 'K_atp': 0.25, 'K_o_n': 5.0, 'GNaL_b': 0.0279, 'Gto_b': 0.16, 'Io': 0.15109999999999998, 'PCa_b': 8.3757e-05, 'dielConstant': 74.0, 'GKr_b': 0.0321, 'GKs_b': 0.0011, 'GK1_b': 0.6992, 'Gncx_b': 0.0034, 'kasymm': 12.5, 'kcaoff': 5000.0, 'h10_i': 284.1666666666667, 'h10_ss': 284.1666666666667, 'h12_i': 0.003519061583577712, 'h12_ss': 0.003519061583577712, 'MgADP': 0.05, 'Pnak_b': 15.4509, 'k1m': 182.4, 'k2p': 687.2, 'k4p': 639.0, 'GKb_b': 0.0189}, 'parameters': {'CaMKo': 0.05, 'KmCaM': 0.0015, 'KmCaMK': 0.15, 'aCaMK': 0.05, 'bCaMK': 0.00068, 'GpCa': 0.0005, 'KmCap': 0.0005, 'Acap': 0.00015335760000000003, 'vjsr': 1.8237120000000002e-07, 'vmyo': 2.583592000000001e-05, 'vnsr': 2.0972688000000006e-06, 'vss': 7.598800000000002e-07, 'tauCa': 0.2, 'tauK': 2.0, 'tauNa': 2.0, 'celltype': 0.0, 'cao': 1.8, 'ko': 5.0, 'nao': 140.0, 'F': 96485.0, 'R': 8314.0, 'T': 310.0, 'zca': 2.0, 'zk': 1.0, 'zna': 1.0, 'Jup_b': 1.0, 'upScale': 1.0, 'BSLmax': 1.124, 'BSRmax': 0.047, 'KmBSL': 0.0087, 'KmBSR': 0.00087, 'cli': 24.0, 'csqnmax': 10.0, 'kmcmdn': 0.00238, 'kmcsqn': 0.8, 'kmtrpn': 0.0005, 'trpnmax': 0.07, 'cmdnmax': 0.05, 'ECl': -48.95253676506265, 'PKNa': 0.01833, 'fkatp': 0.0, 'gkatp': 4.3195, 'akik': 1.0, 'bkik': 0.015384615384615385, 'GNa': 11.7802, 'thL': 200.0, 'GNaL': 0.0279, 'thLp': 600.0, 'EKshift': 0.0, 'Gto': 0.16, 'Aff': 0.6, 'ICaL_fractionSS': 0.8, 'Kmn': 0.002, 'k2n': 500.0, 'offset': 0.0, 'tjca': 75.0, 'vShift': 0.0, 'Afs': 0.4, 'PCa': 8.3757e-05, 'constA': 0.5238190247282047, 'PCaK': 2.99347518e-08, 'PCaNa': 1.0469625000000001e-07, 'PCap': 9.213270000000001e-05, 'gamma_cao': 0.6117017520062547, 'gamma_ko': 0.8843718923169582, 'gamma_nao': 0.8843718923169582, 'PCaKp': 3.292822698000001e-08, 'PCaNap': 1.1516587500000002e-07, 'alpha_1': 0.154375, 'beta_1': 0.1911, 'GKr': 0.0321, 'GKs': 0.0011, 'GK1': 0.6992, 'INaCa_fractionSS': 0.35, 'KmCaAct': 0.00015, 'kcaon': 1500000.0, 'kna1': 15.0, 'kna2': 5.0, 'kna3': 88.12, 'qca': 0.167, 'qna': 0.5224, 'wca': 60000.0, 'wna': 60000.0, 'wnaca': 5000.0, 'Gncx': 0.0034, 'k2_i': 5000.0, 'k2_ss': 5000.0, 'k5_i': 5000.0, 'k5_ss': 5000.0, 'h11_i': 0.9196480938416423, 'h11_ss': 0.9196480938416423, 'k1_i': 9501.466275659823, 'k1_ss': 9501.466275659823, 'H': 1e-07, 'Khp': 1.698e-07, 'Kki': 0.5, 'Kko': 0.3582, 'Kmgatp': 1.698e-07, 'Knai0': 9.073, 'Knao0': 27.78, 'Knap': 224.0, 'Kxkur': 292.0, 'MgATP': 9.8, 'delta': -0.155, 'eP': 4.2, 'k1p': 949.5, 'k2m': 39.4, 'k3m': 79300.0, 'k3p': 1899.0, 'k4m': 40.0, 'Pnak': 15.4509, 'a2': 687.2, 'a4': 638.9999889283472, 'b1': 9.120000000000001, 'GKb': 0.0189, 'PNab': 1.9239e-09, 'PCab': 5.9194e-08, 'Fjunc': 1.0, 'GClCa': 0.2843, 'GClb': 0.00198, 'KdClCa': 0.1, 'Jrel_b': 1.5378, 'bt': 4.75, 'cajsr_half': 1.7, 'a_rel': 2.375, 'btp': 5.9375, 'a_relp': 2.96875}, 'example discretisation': {'dt': 0.02, 'dx': 0.98, 'stimulus': 50.7}, 'units': {'t': 'ms', 'x': 'mm', 'u': 'mV'}, 'code': '// CaMK\nconst Real CaMKb = CaMKo * (1.0 - CaMKt) / (1.0 + KmCaM / (Cass));\nconst Real CaMKa = CaMKb + CaMKt;\n*_new_CaMKt = CaMKt + dt*(aCaMK * CaMKb * (CaMKb + CaMKt) - bCaMK * CaMKt);\n\n// IpCa\nconst Real IpCa = GpCa * Cai / (KmCap + Cai);\n\n// diff\nconst Real Jdiff = (Cass - Cai) / tauCa;\nconst Real JdiffK = (Kss - Ki) / tauK;\nconst Real JdiffNa = (Nass - Nai) / tauNa;\n\n// trans_flux\nconst Real Jtr = (Cansr - Cajsr) / 60.0;\n\n// SERCA\nconst Real Jleak = 0.0048825 * Cansr / 15.0;\nconst Real fJupp = 1.0 / (1.0 + KmCaMK / (CaMKa));\nconst Real Jupnp = upScale * 0.005425 * Cai / (Cai + 0.00092);\nconst Real Jupp = upScale * 2.75 * 0.005425 * Cai / (Cai + 0.00092 - 0.00017);\nconst Real Jup = Jup_b * ((1.0 - fJupp) * Jupnp + fJupp * Jupp - Jleak);\n\n// membrane\nconst Real vffrt = V * F * F / (R * T);\nconst Real vfrt = V * F / (R * T);\n\n// intracellular_ions\n*_new_Cansr = Cansr + dt*(Jup - Jtr * vjsr / vnsr);\nconst Real Bcajsr = 1.0 / (1.0 + csqnmax * kmcsqn / (pow(kmcsqn + Cajsr, 2.0)));\nconst Real Bcass = 1.0 / (1.0 + BSRmax * KmBSR / (pow(KmBSR + Cass, 2.0)) + BSLmax * KmBSL / (pow(KmBSL + Cass, 2.0)));\nconst Real Bcai = 1.0 / (1.0 + cmdnmax * kmcmdn / (pow(kmcmdn + Cai, 2.0)) + trpnmax * kmtrpn / (pow(kmtrpn + Cai, 2.0)));\n\n// reversal_potentials\nconst Real EK = R * T / (zk * F) * log(ko / (Ki));\nconst Real ENa = R * T / (zna * F) * log(nao / (Nai));\nconst Real EKs = R * T / (zk * F) * log((ko + PKNa * nao) / (Ki + PKNa * Nai));\n\n// I_katp\nconst Real I_katp = fkatp * gkatp * akik * bkik * (V - EK);\n\n// INa\nconst Real ah = ((V >= -40.0) ? 0.0 : 0.057 * exp(-(V + 80.0) / 6.8));\nconst Real aj = ((V >= -40.0) ? 0.0 : (-25428.0 * exp(0.2444 * V) - 6.948e-06 * exp(-0.04391 * V)) * (V + 37.78) / (1.0 + exp(0.311 * (V + 79.23))));\nconst Real bh = ((V >= -40.0) ? 0.77 / (0.13 * (1.0 + exp(-(V + 10.66) / 11.1))) : 2.7 * exp(0.079 * V) + 310000.0 * exp(0.3485 * V));\nconst Real bj = ((V >= -40.0) ? 0.6 * exp(0.057 * V) / (1.0 + exp(-0.1 * (V + 32.0))) : 0.02424 * exp(-0.01052 * V) / (1.0 + exp(-0.1378 * (V + 40.14))));\nconst Real fINap = 1.0 / (1.0 + KmCaMK / (CaMKa));\nconst Real hss = 1.0 / (pow(1.0 + exp((V + 71.55) / 7.43), 2.0));\nconst Real hssp = 1.0 / (pow(1.0 + exp((V + 77.55) / 7.43), 2.0));\nconst Real mss = 1.0 / (pow(1.0 + exp(-(V + 56.86) / 9.03), 2.0));\nconst Real tm = 0.1292 * exp(-pow((V + 45.79) / 15.54, 2.0)) + 0.06487 * exp(-pow((V - 4.823) / 51.12, 2.0));\nconst Real INa = GNa * (V - ENa) * pow(m, 3.0) * ((1.0 - fINap) * h * j + fINap * hp * jp);\nconst Real jss = hss;\nconst Real th = 1.0 / (ah + bh);\nconst Real tj = 1.0 / (aj + bj);\n*_new_m = mss + (m - mss) * exp(-(dt / tm));\nconst Real tjp = 1.46 * tj;\n*_new_h = hss + (h - hss) * exp(-(dt / th));\n*_new_hp = hssp + (hp - hssp) * exp(-(dt / th));\n*_new_j = jss + (j - jss) * exp(-(dt / tj));\n*_new_jp = jss + (jp - jss) * exp(-(dt / tjp));\n\n// INaL\nconst Real fINaLp = 1.0 / (1.0 + KmCaMK / (CaMKa));\nconst Real hLss = 1.0 / (1.0 + exp((V + 87.61) / 7.488));\nconst Real hLssp = 1.0 / (1.0 + exp((V + 93.81) / 7.488));\nconst Real mLss = 1.0 / (1.0 + exp(-(V + 42.85) / 5.264));\nconst Real tmL = 0.1292 * exp(-pow((V + 45.79) / 15.54, 2.0)) + 0.06487 * exp(-pow((V - 4.823) / 51.12, 2.0));\n*_new_hL = hLss + (hL - hLss) * exp(-(dt / thL));\n*_new_mL = mLss + (mL - mLss) * exp(-(dt / tmL));\nconst Real INaL = GNaL * (V - ENa) * mL * ((1.0 - fINaLp) * hL + fINaLp * hLp);\n*_new_hLp = hLssp + (hLp - hLssp) * exp(-(dt / thLp));\n\n// Ito\nconst Real fItop = 1.0 / (1.0 + KmCaMK / (CaMKa));\nconst Real AiF = 1.0 / (1.0 + exp((V + EKshift - 213.6) / 151.2));\nconst Real ass = 1.0 / (1.0 + exp(-(V + EKshift - 14.34) / 14.82));\nconst Real assp = 1.0 / (1.0 + exp(-(V + EKshift - 24.34) / 14.82));\nconst Real delta_epi = ((celltype == 1.0) ? 1.0 - 0.95 / (1.0 + exp((V + EKshift + 70.0) / 5.0)) : 1.0);\nconst Real dti_develop = 1.354 + 0.0001 / (exp((V + EKshift - 167.4) / 15.89) + exp(-(V + EKshift - 12.23) / 0.2154));\nconst Real dti_recover = 1.0 - 0.5 / (1.0 + exp((V + EKshift + 70.0) / 20.0));\nconst Real iss = 1.0 / (1.0 + exp((V + EKshift + 43.94) / 5.711));\nconst Real ta = 1.0515 / (1.0 / (1.2089 * (1.0 + exp(-(V + EKshift - 18.4099) / 29.3814))) + 3.5 / (1.0 + exp((V + EKshift + 100.0) / 29.3814)));\nconst Real tiF_b = 4.562 + 1.0 / (0.3933 * exp(-(V + EKshift + 100.0) / 100.0) + 0.08004 * exp((V + EKshift + 50.0) / 16.59));\nconst Real tiS_b = 23.62 + 1.0 / (0.001416 * exp(-(V + EKshift + 96.52) / 59.05) + 1.78e-08 * exp((V + EKshift + 114.1) / 8.079));\nconst Real AiS = 1.0 - AiF;\nconst Real tiF = tiF_b * delta_epi;\nconst Real tiS = tiS_b * delta_epi;\n*_new_a = ass + (a - ass) * exp(-(dt / ta));\n*_new_ap = assp + (ap - assp) * exp(-(dt / ta));\nconst Real i = AiF * iF + AiS * iS;\nconst Real ip = AiF * iFp + AiS * iSp;\nconst Real tiFp = dti_develop * dti_recover * tiF;\nconst Real tiSp = dti_develop * dti_recover * tiS;\n*_new_iF = iss + (iF - iss) * exp(-(dt / tiF));\n*_new_iS = iss + (iS - iss) * exp(-(dt / tiS));\nconst Real Ito = Gto * (V - EK) * ((1.0 - fItop) * a * i + fItop * ap * ip);\n*_new_iFp = iss + (iFp - iss) * exp(-(dt / tiFp));\n*_new_iSp = iss + (iSp - iss) * exp(-(dt / tiSp));\n\n// ICaL\nconst Real Afcaf = 0.3 + 0.6 / (1.0 + exp((V - 10.0) / 10.0));\nconst Real Ii = 0.5 * (Nai + Ki + cli + 4.0 * Cai) / 1000.0;\nconst Real Iss = 0.5 * (Nass + Kss + cli + 4.0 * Cass) / 1000.0;\nconst Real dss = ((V >= 31.4978) ? 1.0 : 1.0763 * exp(-1.007 * exp(-0.0829 * V)));\nconst Real fICaLp = 1.0 / (1.0 + KmCaMK / (CaMKa));\nconst Real fss = 1.0 / (1.0 + exp((V + 19.58) / 3.696));\nconst Real jcass = 1.0 / (1.0 + exp((V + 18.08) / 2.7916));\nconst Real km2n = jca * 1.0;\nconst Real tfcaf = 7.0 + 1.0 / (0.04 * exp(-(V - 4.0) / 7.0) + 0.04 * exp((V - 4.0) / 7.0));\nconst Real tfcas = 100.0 + 1.0 / (0.00012 * exp(-V / 3.0) + 0.00012 * exp(V / 7.0));\nconst Real tff = 7.0 + 1.0 / (0.0045 * exp(-(V + 20.0) / 10.0) + 0.0045 * exp((V + 20.0) / 10.0));\nconst Real tfs = 1000.0 + 1.0 / (3.5e-05 * exp(-(V + 5.0) / 4.0) + 3.5e-05 * exp((V + 5.0) / 6.0));\nconst Real Afcas = 1.0 - Afcaf;\nconst Real anca_i = 1.0 / (k2n / (km2n) + pow(1.0 + Kmn / (Cai), 4.0));\nconst Real anca_ss = 1.0 / (k2n / (km2n) + pow(1.0 + Kmn / (Cass), 4.0));\nconst Real fcass = fss;\nconst Real td = offset + 0.6 + 1.0 / (exp(-0.05 * (V + vShift + 6.0)) + exp(0.09 * (V + vShift + 14.0)));\nconst Real tfcafp = 2.5 * tfcaf;\nconst Real tffp = 2.5 * tff;\n*_new_ff = fss + (ff - fss) * exp(-(dt / tff));\n*_new_fs = fss + (fs - fss) * exp(-(dt / tfs));\n*_new_jca = jcass + (jca - jcass) * exp(-(dt / tjca));\nconst Real f = Aff * ff + Afs * fs;\nconst Real fca = Afcaf * fcaf + Afcas * fcas;\nconst Real fcap = Afcaf * fcafp + Afcas * fcas;\nconst Real fp = Aff * ffp + Afs * fs;\nconst Real gamma_cai = exp(-constA * 4.0 * (sqrt(Ii) / (1.0 + sqrt(Ii)) - 0.3 * Ii));\nconst Real gamma_cass = exp(-constA * 4.0 * (sqrt(Iss) / (1.0 + sqrt(Iss)) - 0.3 * Iss));\nconst Real gamma_ki = exp(-constA * (sqrt(Ii) / (1.0 + sqrt(Ii)) - 0.3 * Ii));\nconst Real gamma_kss = exp(-constA * (sqrt(Iss) / (1.0 + sqrt(Iss)) - 0.3 * Iss));\nconst Real gamma_nai = exp(-constA * (sqrt(Ii) / (1.0 + sqrt(Ii)) - 0.3 * Ii));\nconst Real gamma_nass = exp(-constA * (sqrt(Iss) / (1.0 + sqrt(Iss)) - 0.3 * Iss));\n*_new_d = dss + (d - dss) * exp(-(dt / td));\n*_new_fcaf = fcass + (fcaf - fcass) * exp(-(dt / tfcaf));\n*_new_fcafp = fcass + (fcafp - fcass) * exp(-(dt / tfcafp));\n*_new_fcas = fcass + (fcas - fcass) * exp(-(dt / tfcas));\n*_new_ffp = fss + (ffp - fss) * exp(-(dt / tffp));\n*_new_nca_i = nca_i + dt*(anca_i * k2n - nca_i * km2n);\n*_new_nca_ss = nca_ss + dt*(anca_ss * k2n - nca_ss * km2n);\nconst Real PhiCaK_i = vffrt * safe_divide(gamma_ki * Ki * exp(vfrt) - gamma_ko * ko, exp(vfrt) - 1.0);\nconst Real PhiCaK_ss = vffrt * safe_divide(gamma_kss * Kss * exp(vfrt) - gamma_ko * ko, exp(vfrt) - 1.0);\nconst Real PhiCaL_i = 4.0 * vffrt * safe_divide(gamma_cai * Cai * exp(2.0 * vfrt) - gamma_cao * cao, exp(2.0 * vfrt) - 1.0);\nconst Real PhiCaL_ss = 4.0 * vffrt * safe_divide(gamma_cass * Cass * exp(2.0 * vfrt) - gamma_cao * cao, exp(2.0 * vfrt) - 1.0);\nconst Real PhiCaNa_i = vffrt * safe_divide(gamma_nai * Nai * exp(vfrt) - gamma_nao * nao, exp(vfrt) - 1.0);\nconst Real PhiCaNa_ss = vffrt * safe_divide(gamma_nass * Nass * exp(vfrt) - gamma_nao * nao, exp(vfrt) - 1.0);\nconst Real ICaK_i = (1.0 - ICaL_fractionSS) * ((1.0 - fICaLp) * PCaK * PhiCaK_i * d * (f * (1.0 - nca_i) + jca * fca * nca_i) + fICaLp * PCaKp * PhiCaK_i * d * (fp * (1.0 - nca_i) + jca * fcap * nca_i));\nconst Real ICaK_ss = ICaL_fractionSS * ((1.0 - fICaLp) * PCaK * PhiCaK_ss * d * (f * (1.0 - nca_ss) + jca * fca * nca_ss) + fICaLp * PCaKp * PhiCaK_ss * d * (fp * (1.0 - nca_ss) + jca * fcap * nca_ss));\nconst Real ICaL_i = (1.0 - ICaL_fractionSS) * ((1.0 - fICaLp) * PCa * PhiCaL_i * d * (f * (1.0 - nca_i) + jca * fca * nca_i) + fICaLp * PCap * PhiCaL_i * d * (fp * (1.0 - nca_i) + jca * fcap * nca_i));\nconst Real ICaL_ss = ICaL_fractionSS * ((1.0 - fICaLp) * PCa * PhiCaL_ss * d * (f * (1.0 - nca_ss) + jca * fca * nca_ss) + fICaLp * PCap * PhiCaL_ss * d * (fp * (1.0 - nca_ss) + jca * fcap * nca_ss));\nconst Real ICaNa_i = (1.0 - ICaL_fractionSS) * ((1.0 - fICaLp) * PCaNa * PhiCaNa_i * d * (f * (1.0 - nca_i) + jca * fca * nca_i) + fICaLp * PCaNap * PhiCaNa_i * d * (fp * (1.0 - nca_i) + jca * fcap * nca_i));\nconst Real ICaNa_ss = ICaL_fractionSS * ((1.0 - fICaLp) * PCaNa * PhiCaNa_ss * d * (f * (1.0 - nca_ss) + jca * fca * nca_ss) + fICaLp * PCaNap * PhiCaNa_ss * d * (fp * (1.0 - nca_ss) + jca * fcap * nca_ss));\nconst Real ICaK = ICaK_ss + ICaK_i;\nconst Real ICaL = ICaL_ss + ICaL_i;\nconst Real ICaNa = ICaNa_ss + ICaNa_i;\n\n// IKr\nconst Real alpha = 0.1161 * exp(0.299 * vfrt);\nconst Real alpha_2 = 0.0578 * exp(0.971 * vfrt);\nconst Real alpha_C2ToI = 5.2e-05 * exp(1.525 * vfrt);\nconst Real alpha_i = 0.2533 * exp(0.5953 * vfrt);\nconst Real beta = 0.2442 * exp(-1.604 * vfrt);\nconst Real beta_2 = 0.000349 * exp(-1.062 * vfrt);\nconst Real beta_i = 0.06525 * exp(-0.8209 * vfrt);\nconst Real beta_ItoC2 = beta_2 * beta_i * alpha_C2ToI / (alpha_2 * alpha_i);\n*_new_C2 = C2 + dt*(alpha * C3 + beta_1 * C1 - (beta + alpha_1) * C2);\n*_new_C3 = C3 + dt*(beta * C2 - alpha * C3);\n*_new_O = O + dt*(alpha_2 * C1 + beta_i * I - (beta_2 + alpha_i) * O);\nconst Real IKr = GKr * sqrt(ko / 5.0) * O * (V - EK);\n*_new_C1 = C1 + dt*(alpha_1 * C2 + beta_2 * O + beta_ItoC2 * I - (beta_1 + alpha_2 + alpha_C2ToI) * C1);\n*_new_I = I + dt*(alpha_C2ToI * C1 + alpha_i * O - (beta_ItoC2 + beta_i) * I);\n\n// IKs\nconst Real KsCa = 1.0 + 0.6 / (1.0 + pow(3.8e-05 / (Cai), 1.4));\nconst Real txs1 = 817.3 + 1.0 / (0.0002326 * exp((V + 48.28) / 17.8) + 0.001292 * exp(-(V + 210.0) / 230.0));\nconst Real txs2 = 1.0 / (0.01 * exp((V - 50.0) / 20.0) + 0.0193 * exp(-(V + 66.54) / 31.0));\nconst Real xs1ss = 1.0 / (1.0 + exp(-(V + 11.6) / 8.932));\nconst Real xs2ss = xs1ss;\n*_new_xs1 = xs1ss + (xs1 - xs1ss) * exp(-(dt / txs1));\nconst Real IKs = GKs * KsCa * xs1 * xs2 * (V - EKs);\n*_new_xs2 = xs2ss + (xs2 - xs2ss) * exp(-(dt / txs2));\n\n// IK1\nconst Real aK1 = 4.094 / (1.0 + exp(0.1217 * (V - EK - 49.934)));\nconst Real bK1 = (15.72 * exp(0.0674 * (V - EK - 3.257)) + exp(0.0618 * (V - EK - 594.31))) / (1.0 + exp(-0.1629 * (V - EK + 14.207)));\nconst Real K1ss = aK1 / (aK1 + bK1);\nconst Real IK1 = GK1 * sqrt(ko / 5.0) * K1ss * (V - EK);\n\n// INaCa\nconst Real allo_i = 1.0 / (1.0 + pow(KmCaAct / (Cai), 2.0));\nconst Real allo_ss = 1.0 / (1.0 + pow(KmCaAct / (Cass), 2.0));\nconst Real h4_i = 1.0 + Nai / kna1 * (1.0 + Nai / kna2);\nconst Real h4_ss = 1.0 + Nass / kna1 * (1.0 + Nass / kna2);\nconst Real hca = exp(qca * vfrt);\nconst Real hna = exp(qna * vfrt);\nconst Real h1_i = 1.0 + Nai / kna3 * (1.0 + hna);\nconst Real h1_ss = 1.0 + Nass / kna3 * (1.0 + hna);\nconst Real h5_i = Nai * Nai / (h4_i * kna1 * kna2);\nconst Real h5_ss = Nass * Nass / (h4_ss * kna1 * kna2);\nconst Real h6_i = 1.0 / (h4_i);\nconst Real h6_ss = 1.0 / (h4_ss);\nconst Real h7_i = 1.0 + nao / kna3 * (1.0 + 1.0 / (hna));\nconst Real h7_ss = 1.0 + nao / kna3 * (1.0 + 1.0 / (hna));\nconst Real h2_i = Nai * hna / (kna3 * h1_i);\nconst Real h2_ss = Nass * hna / (kna3 * h1_ss);\nconst Real h3_i = 1.0 / (h1_i);\nconst Real h3_ss = 1.0 / (h1_ss);\nconst Real h8_i = nao / (kna3 * hna * h7_i);\nconst Real h8_ss = nao / (kna3 * hna * h7_ss);\nconst Real h9_i = 1.0 / (h7_i);\nconst Real h9_ss = 1.0 / (h7_ss);\nconst Real k6_i = h6_i * Cai * kcaon;\nconst Real k6_ss = h6_ss * Cass * kcaon;\nconst Real k3p_i = h9_i * wca;\nconst Real k3p_ss = h9_ss * wca;\nconst Real k3pp_i = h8_i * wnaca;\nconst Real k3pp_ss = h8_ss * wnaca;\nconst Real k4p_i = h3_i * wca / (hca);\nconst Real k4p_ss = h3_ss * wca / (hca);\nconst Real k4pp_i = h2_i * wnaca;\nconst Real k4pp_ss = h2_ss * wnaca;\nconst Real k7_i = h5_i * h2_i * wna;\nconst Real k7_ss = h5_ss * h2_ss * wna;\nconst Real k8_i = h8_i * h11_i * wna;\nconst Real k8_ss = h8_ss * h11_ss * wna;\nconst Real k3_i = k3p_i + k3pp_i;\nconst Real k3_ss = k3p_ss + k3pp_ss;\nconst Real k4_i = k4p_i + k4pp_i;\nconst Real k4_ss = k4p_ss + k4pp_ss;\nconst Real x1_i = k2_i * k4_i * (k7_i + k6_i) + k5_i * k7_i * (k2_i + k3_i);\nconst Real x1_ss = k2_ss * k4_ss * (k7_ss + k6_ss) + k5_ss * k7_ss * (k2_ss + k3_ss);\nconst Real x2_i = k1_i * k7_i * (k4_i + k5_i) + k4_i * k6_i * (k1_i + k8_i);\nconst Real x2_ss = k1_ss * k7_ss * (k4_ss + k5_ss) + k4_ss * k6_ss * (k1_ss + k8_ss);\nconst Real x3_i = k1_i * k3_i * (k7_i + k6_i) + k8_i * k6_i * (k2_i + k3_i);\nconst Real x3_ss = k1_ss * k3_ss * (k7_ss + k6_ss) + k8_ss * k6_ss * (k2_ss + k3_ss);\nconst Real x4_i = k2_i * k8_i * (k4_i + k5_i) + k3_i * k5_i * (k1_i + k8_i);\nconst Real x4_ss = k2_ss * k8_ss * (k4_ss + k5_ss) + k3_ss * k5_ss * (k1_ss + k8_ss);\nconst Real E1_i = x1_i / (x1_i + x2_i + x3_i + x4_i);\nconst Real E1_ss = x1_ss / (x1_ss + x2_ss + x3_ss + x4_ss);\nconst Real E2_i = x2_i / (x1_i + x2_i + x3_i + x4_i);\nconst Real E2_ss = x2_ss / (x1_ss + x2_ss + x3_ss + x4_ss);\nconst Real E3_i = x3_i / (x1_i + x2_i + x3_i + x4_i);\nconst Real E3_ss = x3_ss / (x1_ss + x2_ss + x3_ss + x4_ss);\nconst Real E4_i = x4_i / (x1_i + x2_i + x3_i + x4_i);\nconst Real E4_ss = x4_ss / (x1_ss + x2_ss + x3_ss + x4_ss);\nconst Real JncxCa_i = E2_i * k2_i - E1_i * k1_i;\nconst Real JncxCa_ss = E2_ss * k2_ss - E1_ss * k1_ss;\nconst Real JncxNa_i = 3.0 * (E4_i * k7_i - E1_i * k8_i) + E3_i * k4pp_i - E2_i * k3pp_i;\nconst Real JncxNa_ss = 3.0 * (E4_ss * k7_ss - E1_ss * k8_ss) + E3_ss * k4pp_ss - E2_ss * k3pp_ss;\nconst Real INaCa_i = (1.0 - INaCa_fractionSS) * Gncx * allo_i * (zna * JncxNa_i + zca * JncxCa_i);\nconst Real INaCa_ss = INaCa_fractionSS * Gncx * allo_ss * (zna * JncxNa_ss + zca * JncxCa_ss);\n\n// INaK\nconst Real Knai = Knai0 * exp(delta * vfrt / 3.0);\nconst Real Knao = Knao0 * exp((1.0 - delta) * vfrt / 3.0);\nconst Real P = eP / (1.0 + H / Khp + Nai / Knap + Ki / Kxkur);\nconst Real a1 = k1p * pow(Nai / (Knai), 3.0) / (pow(1.0 + Nai / (Knai), 3.0) + pow(1.0 + Ki / Kki, 2.0) - 1.0);\nconst Real a3 = k3p * pow(ko / Kko, 2.0) / (pow(1.0 + nao / (Knao), 3.0) + pow(1.0 + ko / Kko, 2.0) - 1.0);\nconst Real b2 = k2m * pow(nao / (Knao), 3.0) / (pow(1.0 + nao / (Knao), 3.0) + pow(1.0 + ko / Kko, 2.0) - 1.0);\nconst Real b3 = k3m * P * H / (1.0 + MgATP / Kmgatp);\nconst Real b4 = k4m * pow(Ki / Kki, 2.0) / (pow(1.0 + Nai / (Knai), 3.0) + pow(1.0 + Ki / Kki, 2.0) - 1.0);\nconst Real x1 = a4 * a1 * a2 + b2 * b4 * b3 + a2 * b4 * b3 + b3 * a1 * a2;\nconst Real x2 = b2 * b1 * b4 + a1 * a2 * a3 + a3 * b1 * b4 + a2 * a3 * b4;\nconst Real x3 = a2 * a3 * a4 + b3 * b2 * b1 + b2 * b1 * a4 + a3 * a4 * b1;\nconst Real x4 = b4 * b3 * b2 + a3 * a4 * a1 + b2 * a4 * a1 + b3 * b2 * a1;\nconst Real E1 = x1 / (x1 + x2 + x3 + x4);\nconst Real E2 = x2 / (x1 + x2 + x3 + x4);\nconst Real E3 = x3 / (x1 + x2 + x3 + x4);\nconst Real E4 = x4 / (x1 + x2 + x3 + x4);\nconst Real JnakK = 2.0 * (E4 * b1 - E3 * a1);\nconst Real JnakNa = 3.0 * (E1 * a3 - E2 * b3);\nconst Real INaK = Pnak * (zna * JnakNa + zk * JnakK);\n\n// IKb\nconst Real xkb = 1.0 / (1.0 + exp(-(V - 10.8968) / 23.9871));\nconst Real IKb = GKb * xkb * (V - EK);\n\n// INab\nconst Real INab = PNab * vffrt * safe_divide(Nai * exp(vfrt) - nao, exp(vfrt) - 1.0);\n\n// ICab\nconst Real ICab = PCab * 4.0 * vffrt * safe_divide(gamma_cai * Cai * exp(2.0 * vfrt) - gamma_cao * cao, exp(2.0 * vfrt) - 1.0);\n\n// ICl\nconst Real IClCa_junc = Fjunc * GClCa / (1.0 + KdClCa / (Cass)) * (V - ECl);\nconst Real IClCa_sl = (1.0 - Fjunc) * GClCa / (1.0 + KdClCa / (Cai)) * (V - ECl);\nconst Real IClb = GClb * (V - ECl);\nconst Real IClCa = IClCa_junc + IClCa_sl;\n\n// ryr\nconst Real fJrelp = 1.0 / (1.0 + KmCaMK / (CaMKa));\nconst Real Jrel = Jrel_b * ((1.0 - fJrelp) * Jrel_np + fJrelp * Jrel_p);\nconst Real tau_rel_b = bt / (1.0 + 0.0123 / (Cajsr));\nconst Real Jrel_inf_b = -a_rel * ICaL_ss / 1.0 / (1.0 + pow(cajsr_half / (Cajsr), 8.0));\nconst Real tau_rel = ((tau_rel_b < 0.001) ? 0.001 : tau_rel_b);\nconst Real tau_relp_b = btp / (1.0 + 0.0123 / (Cajsr));\nconst Real Jrel_inf = ((celltype == 2.0) ? Jrel_inf_b * 1.7 : Jrel_inf_b);\nconst Real Jrel_infp_b = -a_relp * ICaL_ss / 1.0 / (1.0 + pow(cajsr_half / (Cajsr), 8.0));\nconst Real tau_relp = ((tau_relp_b < 0.001) ? 0.001 : tau_relp_b);\n*_new_Jrel_np = Jrel_inf + (Jrel_np - Jrel_inf) * exp(-(dt / tau_rel));\nconst Real Jrel_infp = ((celltype == 2.0) ? Jrel_infp_b * 1.7 : Jrel_infp_b);\n*_new_Jrel_p = Jrel_infp + (Jrel_p - Jrel_infp) * exp(-(dt / tau_relp));\n\n// *remaining*\n*_new_V = V + dt*(-(INa + INaL + Ito + ICaL + ICaNa + ICaK + IKr + IKs + IK1 + INaCa_i + INaCa_ss + INaK + INab + IKb + IpCa + ICab + IClCa + IClb + I_katp) + _diffuse_V);\n*_new_Cai = Cai + dt*(Bcai * (-(ICaL_i + IpCa + ICab - 2.0 * INaCa_i) * Acap / (2.0 * F * vmyo) - Jup * vnsr / vmyo + Jdiff * vss / vmyo));\n*_new_Cajsr = Cajsr + dt*(Bcajsr * (Jtr - Jrel));\n*_new_Cass = Cass + dt*(Bcass * (-(ICaL_ss - 2.0 * INaCa_ss) * Acap / (2.0 * F * vss) + Jrel * vjsr / vss - Jdiff));\n*_new_Ki = Ki + dt*(-(Ito + IKr + IKs + IK1 + IKb + I_katp - 2.0 * INaK + ICaK_i) * Acap / (F * vmyo) + JdiffK * vss / vmyo);\n*_new_Kss = Kss + dt*(-ICaK_ss * Acap / (F * vss) - JdiffK);\n*_new_Nai = Nai + dt*(-(INa + INaL + 3.0 * INaCa_i + ICaNa_i + 3.0 * INaK + INab) * Acap / (F * vmyo) + JdiffNa * vss / vmyo);\n*_new_Nass = Nass + dt*(-(ICaNa_ss + 3.0 * INaCa_ss) * Acap / (F * vss) - JdiffNa);\n'}, 'trivial': {'name': 'Trivial model', 'description': 'This model encodes only diffusion, with a zero reaction term.\n', 'dois': [], 'keywords': ['diffusion'], 'variables': {'u': 0.0}, 'diffusivity': {'u': 1.0}, 'parameters': {}, 'code': '*_new_u = u + dt * _diffuse_u;\n', 'example discretisation': {'dt': 0.004, 'dx': 0.2, 'stimulus': 1.0}, 'units': {'t': 'ms', 'x': 'mm', 'u': 1}}}