concord-model-jansen-rit

Classic 3-population cortical column model (Jansen & Rit, 1995)

Role in the system The first implemented neural mass model. Takes a ParameterVector, integrates the Jansen-Rit ODEs using RK4, and produces a ModelOutput containing the simulated SEEG signal plus all internal state variables. Registered via entry_points as concord.models:jansen_rit.

For a conceptual introduction to neural mass models and the Jansen-Rit equations, see Neural Mass Models (background reading).

Package Structure

concord-model-jansen-rit/
  src/concord_model_jansen_rit/
    __init__.py       exports JansenRit
    equations.py      pure derivative function (6 ODEs)
    model.py          JansenRit class implementing Model ABC

equations.py

fnjansen_rit_derivatives(y, t, p_input, A, B, a, b, C1, C2, C3, C4, e0, v0, r) → ndarray

Compute derivatives of the 6-variable Jansen-Rit ODE system. This is a pure numerical function with no Model ABC knowledge — it can be called directly for testing or used by the integrator.

ParameterDescription
yState vector, shape (6,). [y0, y1, y2, y3, y4, y5]
tCurrent time (kept for integrator interface)
p_inputInstantaneous external input (mean + noise sample)
A, BMax EPSP / IPSP amplitude (mV)
a, bEPSP / IPSP time constants (1/s)
C1..C4Connectivity constants
e0, v0, rSigmoid parameters

State variable mapping: y0 = excitatory PSP on pyramidal cells, y1 = PSP from external + feedback on excitatory interneurons, y2 = inhibitory PSP on pyramidal cells. y3, y4, y5 are their time derivatives. Output signal = y1 - y2.

model.py — JansenRit

ABCJansenRit(Model)

Implements the Model ABC. Single-node cortical column producing alpha-band (~10 Hz) oscillations at default parameters.

ConstructorTypeDescription
dtfloatInternal integration time step in seconds. Default 1e-4 (0.1 ms).
propertyJansenRit.name → str

Returns "jansen_rit".

fnJansenRit.default_parameters() → ParameterVector

Returns a ParameterVector with 10 named parameters, their default values, and bounds:

NameDefaultLowerUpperUnits
A3.251.010.0mV
B22.05.050.0mV
a100.050.0200.01/s
b50.010.0100.01/s
C135.050.0500.0
e02.51.05.01/s
v06.03.012.0mV
r0.560.11.01/mV
p220.00.0500.0Hz
sigma22.00.0100.0Hz

Connectivity constants are derived from C: C1 = C, C2 = 0.8C, C3 = 0.25C, C4 = 0.25C.

fnJansenRit.simulate(parameters, duration_s, fs, seed=None) → ModelOutput

Run the simulation and return a ModelOutput.

ParameterTypeDescription
parametersParameterVectorModel parameters (from default_parameters() or modified)
duration_sfloatSimulation duration in seconds
fsfloatOutput sampling rate in Hz
seedint | NoneRandom seed for reproducibility. None = non-reproducible.

Integration uses RK4 at the internal time step (default 0.1 ms). External input noise is pre-generated for the full duration. After integration, the output is downsampled to the requested fs using scipy.signal.decimate.

The returned ModelOutput contains:

  • data — shape (1, n_samples): the simulated signal (y1 - y2)
  • state_variables — dict with keys "y0" through "y5", each shape (1, n_samples)
  • time_axis — time stamps in seconds
  • node_labels — ["node_0"]

Entry Point Registration

In pyproject.toml:

[project.entry-points."concord.models"]
jansen_rit = "concord_model_jansen_rit:JansenRit"

This allows concord-fit (and other discovery tools) to find the model without hard imports. See Python Entry Points for how discovery works.

Usage Example

from concord_model_jansen_rit import JansenRit

model = JansenRit()
params = model.default_parameters()

# Simulate 3 seconds at 1024 Hz
result = model.simulate(params, duration_s=3.0, fs=1024.0, seed=42)

# The output signal
signal = result.data[0, :]          # shape (n_samples,)
times = result.time_axis             # shape (n_samples,)

# Modify a parameter
p_idx = params.names.index("p")
params.values[p_idx] = 300.0        # higher input → more spiking
result2 = model.simulate(params, duration_s=3.0, fs=1024.0, seed=42)