Unfortunately, this is not possible at the moment in any clean kind of way. This is one of the things that the store
/restore
method deals with (Running a simulation — Brian 2 2.5.4 documentation) which is not available for C++ standalone.
But if your issue is only the memory usage of the monitors, then I think an easier solution would be to use C++ code to write your recordings directly to disk instead of keeping them in memory. For a SpikeMonitor
, you can find a solution here: Real Time Monitor - #2 by mstimberg
For a StateMonitor
, you can use a function like this:
def disk_writer(filename, size, name):
code = '''
double %name%(int index, double value) {
static std::ofstream outfile("%filename%", ios::binary | ios::out);
static double data_container[%size%]; // stores data for one timestep
data_container[index] = value;
if (index == %size% - 1) { //write to disk when last value has been written
outfile.write(reinterpret_cast<char*>(data_container), %size%*sizeof(double));
}
return 0.0;
}
'''.replace('%name%', name).replace('%filename%', filename).replace('%size%', str(size))
@implementation('cpp', code)
@check_units(index=1, value=1, result=1)
def disk_writer(index, value):
raise NotImplementedError('C++ only')
return disk_writer
This can then be used in a run_regularly
operation to replace a StateMonitor
:
store_v = disk_writer(file_name, len(group), 'store_v')
group.run_regularly('dummy = store_v(i, v)')
After the run, you can reload the data like this:
v_values = np.fromfile(file_name)
v_values = v_values.reshape((-1, len(group))).T
Here’s a full example demonstrating that it records the same thing as the StateMonitor
:
Full code example
import os
from brian2 import *
set_device('cpp_standalone')
group = NeuronGroup(2, 'dv/dt = -v/(10*ms) + 0.1/sqrt(5*ms)*xi : 1', method='euler')
mon = StateMonitor(group, 'v', record=True)
def disk_writer(filename, size, name):
code = '''
double %name%(int index, double value) {
static std::ofstream outfile("%filename%", ios::binary | ios::out);
static double data_container[%size%]; // stores data for one timestep
data_container[index] = value;
if (index == %size% - 1) { //write to disk when last value has been written
outfile.write(reinterpret_cast<char*>(data_container), %size%*sizeof(double));
}
return 0.0;
}
'''.replace('%name%', name).replace('%filename%', filename).replace('%size%', str(size))
@implementation('cpp', code)
@check_units(index=1, value=1, result=1)
def disk_writer(index, value):
raise NotImplementedError('C++ only')
return disk_writer
file_name = '/tmp/v_values.npy'
store_v = disk_writer(file_name, len(group), 'store_v')
group.run_regularly('dummy = store_v(i, v)')
run(100*ms, report='text')
v_values = np.fromfile(file_name)
v_values = v_values.reshape((-1, len(group))).T
fig, axs = plt.subplots(2, 1, sharex=True, sharey=True)
axs[0].plot(mon.t/ms, mon.v.T)
axs[1].plot(mon.t/ms, v_values.T)
plt.show()