Setting M.clock.dt between run() commands

I want to change the dt of a monitor between run() commands. However I get a value error.

Minimal code to reproduce problem

from brian2 import *

t_0 = 0.5*second
t_1 = 2*second

#some neuron model
num_inputs = 100
input_rate = 10*Hz
weight = 0.1
tau = 1*ms

P = PoissonGroup(num_inputs, rates=input_rate)
eqs = '''
dv/dt = -v/tau : 1
'''
G = NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='exact')
S = Synapses(P, G, on_pre='v += weight')
S.connect()

#run with different dt for the monitor
M = StateMonitor(G, 'v', record=True, dt=t_0/2)
run(t_0)
print(M.t)
M.clock.dt = t_1/2
run(t_1)
print(M.t)

The error I get is

ValueError: Cannot set dt from 250. ms to 1. s, the time 0.5 s is not a multiple of 1. s.

Why is it necessary that the old time t_0 is a multiple of the new dt? Is there a way around this other than creating a differnt monitor?

Hi @clemenge. I see how this is not intuitive for a monitor, but unfortunately I do not see an easy solution to workaround this limitation at the moment (but I’ll open an issue about fixing this in future versions).

The problem is that the Clock mechanism is underlying not only monitors but all simulation objects, such as NeuronGroup and Synapses. If you imagine you did the same dt change for NeuronGroup, you’d end up with a situation where after the first run, you’ve simulated the neuron for two timesteps, the [0ms–250ms] and the [250ms–500ms] timesteps. You then ask to switch the dt to 1s. Internally, the time is represented as an integer times dt, so the simulation can only continue at 0s or at 1s – but both would be wrong! In the first case, we’d go back in time, in the second one we’d skip the 500ms–1s time period. As mentioned in the beginning, the Clock mechanism is generic, the check that raises the error you are seeing is not aware that it is only used in a monitor.

With the current code, you could only create a new monitor, or make the first simulation go until 1s (or any other multiple of dt).

I am not sure whether this is really a big enough issue that it merits fixing – maybe you could give more details as to why running until 1s in your example is not an option. I am seeing two potential fixes:

  1. Somehow detecting if a clock is only used in monitors, and skip the check in such cases (i.e. in your example, the next value the monitor records would be at 1s)
  2. Get rid of the need for this check by storing a time offset in addition to the integer time step and dt – in your example, this would mean that the monitor would record at 0.5s, 1.5s, etc.

Hope that clears things up a bit!