Progress measure
It would good to be able to measure, or display, the progress of a running simulation.
This could, for example, happen through a string that contains the current progress percentage and that is written to an output stream specified by an argument of arbor.simulation.run(). A more sophisticated solution would be a Python function that would be called periodically and that receives the progress percentage as an argument.
As @schmitts pointed out, inspiration could also come from Brian2: https://brian2.readthedocs.io/en/stable/user/running.html#progress-reporting.
I propose adding a callback slot on each epoch (including at t=0) that takes as arguments information like: current time, start time, end time, simulation time, number of spikes, etc).
We could then provide a simple text based callback, with text output something like:
75% [|||||||||||||||||||||||||||||||||||||||||| ] time: 1500 ms spikes: 273
@jlubo, is that the sort of thing you are looking for?
Yeah, that would be great!
@jlubo try out #1873 and give your feedback.
I have a simulation where I don't exchange spikes but have many cells with different parameters. This is solved in one epoch, which makes the progress bar go from 0 to 100% without intermediate values. It would be nice, if I could get progress reporting also for this setup.
So, in endeffect you propose to make the call back time dependent? Example:
auto sim = arb.simulation();
sim.set_progress_callback(0.5, []() { return called_every_05ms; });
This?
0.5 ms in simulation time? Then yes. In wall-clock time, then no.
Cf. https://brian2.readthedocs.io/en/stable/advanced/scheduling.html#progress-reporting
Yes, simulated time.
Hey,
I took a look at this, I am sorry, but this is not possible. To explain why, I have to go into the details of how Arbor
works internally. We leverage the fact that sub-populations of cells are decoupled on a time scale $\Delta t$ by
virtue of the spike delay. These populations are grouped into containers called cell_groups and each evolves
indendently for the epoch time. Thus, the common join point is at the end of an epoch and this is where we execute
the existing epoch callback. Essentially we have
for epoch in epochs {
for group in groups {
group.advance(epoch.time)
}
epoch_callback(...)
}
If we were to add a more fine grained callback, we would have to execute that in one and only one group and also modify the interface for all group implementations which seems like a disproportional effort. In addition, a group might a analyitically integrating its state over the full epoch, so we are never calling the provided function. LIF does that AFAIK.
If you desperately need such a callback, you could add a connection with the desired delay but weight zero. This forces the epoch time to the proper value and should have no effect on your simulation.
With a suggestion for a workaround and the explanation on why it's not feasible, I consider this closed as 'not going to implement'.