Error with restore() and run()

Description of problem

Hi, I want to use store() / restore() in brian2 to save the connectivity and reloaded in a different simulation, but I get an error when I try to run simulations with the restored connectivity.
If I don’t run a simulation and just store the connectivity and restore it after, then the restore function works well. But when I try to restore the connectivity while I also use run() to run a simulation I get the error below. I hope someone can help me with this. I can copy part of the code too if that is helpful to understand the problem.

I have been having problems with Cython that seemed to be solved now, I am not sure up to what point this error could also be related with Cython.

Error:

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/codegen/runtime/cython_rt/cython_rt.py”, line 160, in run_block
return compiled_code.main(self.namespace)

File “_cython_magic_ccb3d62751e600698487f83f290437ab.pyx”, line 57, in _cython_magic_ccb3d62751e600698487f83f290437ab.main

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/synapses/synapses.py”, line 347, in initialise_queue
raise TypeError(("Synapses object ‘%s’ does not do anything, since "

TypeError: Synapses object ‘C1’ does not do anything, since it has not created synapses with ‘connect’. Set its active attribute to False if you intend to do only do this for a subsequent run.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/network.py”, line 901, in before_run
obj.before_run(run_namespace)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/base.py”, line 279, in device_override_decorated_function
return func(*args, **kwds)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/synapses/synapses.py”, line 319, in before_run
super(SynapticPathway, self).before_run(run_namespace)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/groups/group.py”, line 1143, in before_run
super(CodeRunner, self).before_run(run_namespace)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/base.py”, line 169, in before_run
codeobj.before_run()

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/codegen/codeobject.py”, line 123, in before_run
return self.run_block(‘before_run’)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/codegen/runtime/cython_rt/cython_rt.py”, line 164, in run_block
raise BrianObjectException(message, self.owner) from exc

BrianObjectException: Error encountered with object named “C1_pre”.
Object was created here (most recent call only, full details in debug log):
File “/Users/saraibanez/Desktop/Brian_Hansel&Mato/Brian2/balancedRing_b2_new_copia_copia.py”, line 201, in run_sims
C1 = Synapses(networkE, networkE,

An exception occured during the execution of the before_run block of code object C1_pre_push_spikes.
(See above for original error message and traceback.)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):

File “/Users/saraibanez/Desktop/Brian_Hansel&Mato/Brian2/balancedRing_b2_new_copia_copia.py”, line 339, in
run_sims()

File “/Users/saraibanez/Desktop/Brian_Hansel&Mato/Brian2/balancedRing_b2_new_copia_copia.py”, line 296, in run_sims
run(stim_on,report=‘text’)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/units/fundamentalunits.py”, line 2430, in new_f
result = f(*args, **kwds)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/magic.py”, line 374, in run
return magic_network.run(duration, report=report, report_period=report_period,

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/magic.py”, line 232, in run
Network.run(self, duration, report=report, report_period=report_period,

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/base.py”, line 279, in device_override_decorated_function
return func(*args, **kwds)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/units/fundamentalunits.py”, line 2430, in new_f
result = f(*args, **kwds)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/network.py”, line 1012, in run
self.before_run(namespace)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/base.py”, line 279, in device_override_decorated_function
return func(*args, **kwds)

File “/Users/saraibanez/opt/anaconda3/envs/brian2_good/lib/python3.9/site-packages/brian2/core/network.py”, line 903, in before_run
raise BrianObjectException(“An error occurred when preparing an object.”, obj) from ex

BrianObjectException: Error encountered with object named “C1_pre”.
Object was created here (most recent call only, full details in debug log):
File “/Users/saraibanez/Desktop/Brian_Hansel&Mato/Brian2/balancedRing_b2_new_copia_copia.py”, line 201, in run_sims
C1 = Synapses(networkE, networkE,

An error occurred when preparing an object. (See above for original error message and traceback.)

Does the code run successfully without store() and restore()?
I’d try that first with only one parameter setting (meaning comment out the loop you’ve set up to sweep across multiple parameters, and try running the network once)

And yeah the part of the code at least between line 201:
C1 = Synapses( ...
and the run() command might be helpful to see here

Hi Adam,
see below a short example. set make_network = True to store. then, you should get the error when setting it to False.

without store / restore it works fine.

####### CODE:

from brian2 import *
start_time = time.time()
make_network = True

NE = 500
fE = 1
sigma = 36.0 # sigma in [deg]
sigma = sigma / 360.0 #* NE # convert sigma

G = NeuronGroup(NE, ‘v:1’, threshold=‘v>1’, name=‘G’)
S = Synapses(G, G, on_pre=‘v += 1’, name=‘S’)

if make_network:
S.connect(p = 'fE * exp(-(i/NE-j/NE)2 / (2*sigma2)) * (int( (i/NE-j/NE)sign(i/NE-j/NE) <= 0.5)) + fE * exp(-(abs(i/NE-j/NE)-1)**2 / (2sigma**2)) * (int( (i/NE-j/NE)*sign(i/NE-j/NE) > 0.5)) ')
store(filename = ‘my_network’)

else:
restore(filename = ‘my_network’,restore_random_state=False)

# visualize resulting connectivity matrix

C=zeros((NE,NE))
C[S.i,S.j] = 1
imshow(C)

run(100*ms,report=‘text’)

print(‘sim finished’)
print(time.time() - start_time)

so this runs for me if I set make_network = True

debugging what happens with make_network=False now …

Okay. I think the issue is you need to unconditionally connect the synapses.

Note that the store() / restore() mechanism does not re-create the network as such, you still need to construct all the NeuronGroup , Synapses , StateMonitor , … objects, restoring will only restore all the state variable values (membrane potential, conductances, synaptic connections/weights/delays, …).

from Running a simulation

so try this code:

from brian2 import *
start_time = time.time()
make_network = False

NE = 500
fE = 1
sigma = 36.0 # sigma in [deg]
sigma = sigma / 360.0 #* NE # convert sigma

G = NeuronGroup(NE, 'v:1', threshold='v>1', name='G')
S = Synapses(G, G, on_pre='v += 1', name='S')
S.connect(p = 'fE * exp(-(i/NE-j/NE) **2 / (2*sigma** 2)) * (int( (i/NE-j/NE) *sign(i/NE-j/NE) <= 0.5)) + fE * exp(-(abs(i/NE-j/NE)-1)**2 / (2* sigma**2)) * (int( (i/NE-j/NE)*sign(i/NE-j/NE) > 0.5)) ')

if make_network:
    store(filename = 'my_network')
else:
    restore(filename = 'my_network',restore_random_state=False)

###### # visualize resulting connectivity matrix

C=zeros((NE,NE))
C[S.i,S.j] = 1
imshow(C)

run(100*ms,report='text')

print('sim finished')
print(time.time() - start_time)

Hi Adam,

this works fine, thanks!

1 Like

Hi @SIbanez , hi @adam . Actually, it turns out that you found a bug in Brian!
Your error message states that Synapses object ‘C1’ does not do anything, since it has not created synapses with ‘connect’. This is a check that Brian does to give a useful error message in case a user created a Synapses object, but forgot to call Synapses.connect (which means that the Synapses object does not do anything). Brian thinks that this is the case in your original example, since for make_network=False you never call Synapses.connect. However, your synapses do get restored correctly, Brian just fails to realize that the synapses have been created this way instead of via a Synapses.connect call. As a workaround, you can add a dummy Synapses.connect(False) after your restore call, which will add 0 synapses but will make Brian think that all is good since you called Synapses.connect.

Regarding the code proposed by @adam in the last comment: this works, but note that it will regenerate the synapses independently in each simulation. If I understood correctly, you want to have the exact same connection pattern in both simulations, this is not the case here.

Final comment: if you only want to store the synaptic connections, you do not necessarily have to use store/restore which also store everything else (all the state variables, parameters, etc.). Another option would be to use the standard numpy methods to save/load data, e.g.:

if make_network:
    S.connect(p = '...')
    np.savez('my_network.npz', i=S.i[:], j=S.j[:])
else:
    connections = np.load('my_network.npz')
    S.connect(i=connections['i'], j=connections['j'])

Best,
Marcel

1 Like

Hi Marcel,

interesting that we found this!

I need to use store/restore because I will later need to store other variables like delays, etc.

Regarding Adam’s solution, I think you are right that it is not what I need, so thanks for point it out. however it is not clear to me how restore would be working here. I would be regenerating new connectivities (this is clear), and then, does ‘‘restore’’ restore anything?

Thanks for your solution as well.

Um, I think I have to apologize, this actually might do what you wanted, only in a slightly inefficient way. In @adam’s solution, the Synapses.connect(...) will generate two different connection patterns in the two calls, but with the restore call, this connection pattern will be overwritten with the original one, so you should actually end up with everything working as expected. The only downside is that for make_network = True, it will unnecessarily generate connections that will not be used, and generating connections can take quite a while for big networks.

Just to confirm what I said in my previous post, here’s a simplified example:

from brian2 import *
make_network = True

G = NeuronGroup(5, '')
S = Synapses(G, G)
S.connect(p=0.5)
print('Connections after S.connect: ')
print(list(zip(S.i, S.j)))

if make_network:
    store(filename='my_network')
else:
    restore(filename='my_network')

print('Connections after store/restore:')
print(list(zip(S.i, S.j)))

After the first run with make_network = True I get (of course this will be different for you):

Connections after S.connect
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2), (3, 3), (3, 4), (4, 0), (4, 4)]
Connections after store/restore:
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2), (3, 3), (3, 4), (4, 0), (4, 4)]

After running it again with make_network = False:

Connections after S.connect: 
[(0, 0), (0, 2), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (3, 0), (4, 3), (4, 4)]
Connections after store/restore:
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2), (3, 3), (3, 4), (4, 0), (4, 4)]

As you can see, the second run first generates a different connection pattern but then restores the original one.

Thank you Marcel.
I will stick then to using " Synapses.connect(False)".