Switching synaptic connections in nested for loop

Moderator: wwlytton

Post Reply
neuromancer
Posts: 10
Joined: Mon Apr 13, 2020 4:42 pm

Switching synaptic connections in nested for loop

Post by neuromancer »

Hello, I have a question about switching synaptic connections in a nested for loop while collecting membrane potential time series. It seems that after running my loop, the membrane time series for both connection arrangements are exactly the same. Let me describe a bit more my model here:

I am modeling a biophysical network composed of two subnetworks. The neurons are instantiated in class objects for cells, cell types, and a network structure. Within the cells and cell types classes, I am recording membrane potential time series and within the network class I am storing netcons for external spike input and intra-subnetwork synapses.(very similar to the ball and stick python tutorial on the neuron documentation website). I am using jupyter notebook.

I have functions that defines a spike input with vecstim. And I have a function that creates two subnetworks and connects them with new synapses and netcons.

I put this all together to run like so:

Code: Select all

network_arrangment_1 = []
network_arrangement_2 = []
for spotdiameter in np.arange(1,2,0.5):

    t = 10
    rate_array = createRate(spotdiameter, t)
    subnetwork1_input = createPoissonInputs(rate_array, t)
    
    t = 10
    d = 10 # always full field spot diameter for second network
    rate_array = createRate(d,t)
    subnetwork2_input = createPoissonInputs(rate_array, t)
    
    for x in range(0,2):
        if x==0:
            netarrangement = 'type1' #inter-subnetwork arrangement 
            ring, ring2 = create2Rings(numberofcells=5, radiusofnetwork=100, subnetwork1_input, subnetwork2_input, netarrangement)
            t = h.Vector().record(h._ref_t)
            ring._netstim.number = 0 # just turning off netstim within the ring classes
            ring2._netstim.number = 0 # just turning off netstim within the ring classes
            h.v_init = -65
            h.tstop = 22
            h.celsius = 34
            h.run();

            vertstack = np.vstack((ring.IN_1.soma_v,
            ring.TCcells[0].soma_v))
            network_arrangement_1.append(vertstack)

        else:
            netarrangment = 'type2'
            ring, ring2 = create2Rings(numberofcells=5, radiusofnetwork=100, subnetwork1_input, subnetwork2_input, netarrangement)
            t = h.Vector().record(h._ref_t)
            ring._netstim.number = 0
            ring2._netstim.number = 0
            h.v_init = -65
            h.tstop = 22
            h.celsius = 34
            h.run();

            vertstack = np.vstack((ring.IN_1.soma_v,
            ring.TCcells[0].soma_v))
            network_arrangement_2.append(vertstack)
So this code loops through 2 spot diameters (this creates two different spike input patterns). Within each spot diameter, there is a loop to switch between two inter-subnetwork connectivity patterns. Before I combined everything into funtions and loops, I was able to set up these two network connectivity arrangements and get different membrane time series for the two network connectivity arrangements. I would espect network_arrangement_1 and network_arrangement_2 to contain different voltage time series, but these two arrays are exactly the same. I must have made some sort of mistake when I made my code shorter any help here would be appreciated, thank you.
neuromancer
Posts: 10
Joined: Mon Apr 13, 2020 4:42 pm

Re: Switching synaptic connections in nested for loop

Post by neuromancer »

update: vstack isn't the issue, I think it may actually be the nested for loop. I just realized doing a for loop for the two different network arrangements isn't necessary. going to remove it and see if it solves my problem of identical arrays. can ignore text below.

Just tried separating the internal for loop by putting them in separate cells and removing the whole bit with "vertstack". I think perhaps the problem is coming from:

Code: Select all

   
   	    vertstack = np.vstack((ring.IN_1.soma_v,
            ring.TCcells[0].soma_v))
            network_arrangement_1.append(vertstack)
            
            
Maybe I'm not using this properly. Maybe somehow it's getting "overwritten" by network_arrangement_2
Last edited by neuromancer on Wed Apr 29, 2020 6:16 am, edited 1 time in total.
neuromancer
Posts: 10
Joined: Mon Apr 13, 2020 4:42 pm

Re: Switching synaptic connections in nested for loop

Post by neuromancer »

Removing the nested for loop did not solve the issue. The following code has the same issue:

Code: Select all

network_arrangment_1 = []
network_arrangement_2 = []
for spotdiameter in np.arange(1,2,0.5):

    t = 10
    rate_array = createRate(spotdiameter, t)
    subnetwork1_input = createPoissonInputs(rate_array, t)
    
    t = 10
    d = 10 # always full field spot diameter for second network
    rate_array = createRate(d,t)
    subnetwork2_input = createPoissonInputs(rate_array, t)
    
    netarrangement = 'type1' #inter-subnetwork arrangement 
    ring, ring2 = create2Rings(numberofcells=5, radiusofnetwork=100, subnetwork1_input, subnetwork2_input, netarrangement)
    t = h.Vector().record(h._ref_t)
    ring._netstim.number = 0 # just turning off netstim within the ring classes
    ring2._netstim.number = 0 # just turning off netstim within the ring classes
    h.v_init = -65
    h.tstop = 22
    h.celsius = 34
    h.run();
    vertstack = np.vstack((ring.IN_1.soma_v,
    ring.TCcells[0].soma_v))
    network_arrangement_1.append(vertstack)

    netarrangment = 'type2'
    ring, ring2 = create2Rings(numberofcells=5, radiusofnetwork=100, subnetwork1_input, subnetwork2_input, netarrangement)
    t = h.Vector().record(h._ref_t)
    ring._netstim.number = 0
    ring2._netstim.number = 0
    h.v_init = -65
    h.tstop = 22
    h.celsius = 34
    h.run();
    vertstack = np.vstack((ring.IN_1.soma_v,
    ring.TCcells[0].soma_v))
    network_arrangement_2.append(vertstack)
            
   
However, separating the two network arrangements and "h.run()" solves the issue:

Code: Select all

network_arrangement_1 = []
for spotdiameter in np.arange(1,2,0.5):

    t = 10
    rate_array = createRate(spotdiameter, t)
    subnetwork1_input = createPoissonInputs(rate_array, t)
    
    t = 10
    d = 10 # always full field spot diameter for second network
    rate_array = createRate(d,t)
    subnetwork2_input = createPoissonInputs(rate_array, t)
    
    netarrangement = 'type1' #inter-subnetwork arrangement 
    ring, ring2 = create2Rings(numberofcells=5, radiusofnetwork=100, subnetwork1_input, subnetwork2_input, netarrangement)
    t = h.Vector().record(h._ref_t)
    ring._netstim.number = 0 # just turning off netstim within the ring classes
    ring2._netstim.number = 0 # just turning off netstim within the ring classes
    h.v_init = -65
    h.tstop = 22
    h.celsius = 34
    h.run();
    vertstack = np.vstack((ring.IN_1.soma_v,
    ring.TCcells[0].soma_v))
    network_arrangement_1.append(vertstack)

Code: Select all

network_arrangement_2 = []
for spotdiameter in np.arange(1,2,0.5):

    t = 10
    rate_array = createRate(spotdiameter, t)
    subnetwork1_input = createPoissonInputs(rate_array, t)
    
    t = 10
    d = 10 # always full field spot diameter for second network
    rate_array = createRate(d,t)
    subnetwork2_input = createPoissonInputs(rate_array, t)
    
    netarrangment = 'type2'
    ring, ring2 = create2Rings(numberofcells=5, radiusofnetwork=100, subnetwork1_input, subnetwork2_input, netarrangement)
    t = h.Vector().record(h._ref_t)
    ring._netstim.number = 0
    ring2._netstim.number = 0
    h.v_init = -65
    h.tstop = 22
    h.celsius = 34
    h.run();
    vertstack = np.vstack((ring.IN_1.soma_v,
    ring.TCcells[0].soma_v))
    network_arrangement_2.append(vertstack)
I think perhaps I don't fully understand how simulation runs work and why they need to be on separate jupyter notebook cells. Do you know of any references or documentation that could help? I'm currently looking this up now
neuromancer
Posts: 10
Joined: Mon Apr 13, 2020 4:42 pm

Re: Switching synaptic connections in nested for loop

Post by neuromancer »

Update: It seems the problem is coming from my function that is creating my two subnetworks and interconnecting them (create2Rings()). If I get rid of this function and just have jupyter notebook cells that creates the subnetwork with either one arrangement type or the other before I run the simulations, then I am able to get unique time series for both arrangements.

However, now I have a strange issue in which I get a weird response for my very first simulation. If I run the simulation quickly (even just 1ms) and then run it again, the response is normal. Here is what I mean:

Weird response for first simulation run (left two columns only):
Image
link to image: https://imgur.com/IR8TIk9
Normal response after running the simulation for 1ms (left two columns only):
Image
link to image: https://imgur.com/DTbCuc0

Any idea what this weird response is coming from? Thanks!
ted
Site Admin
Posts: 5795
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Switching synaptic connections in nested for loop

Post by ted »

I get a weird response for my very first simulation. If I run the simulation quickly (even just 1ms) and then run it again, the response is normal.
How do you know which result is "normal"? Both look abnormal to me, in that no cell appears to be initialized to steady state, nor does any cell settle to steady state before the start of the "stimulus." Furthermore, the pre-stimulus trajectories of the first and second runs differ. These are symptoms of incorrect initialization.

Here are some questions that might help you discover the cause(s) of the problem(s).

1. Is randomization involved in your mode? e.g. pseudorandom spike trains, initial assignment of membrane potentials, synaptic weights or other model parameters? If so, does the problem go away if you eliminate stochasticity? And if that works, are the pseudorandom number streams in your model properly initialized at the start of each run?

2. Have you tested each individual cell class to verify that it is properly initialized? For each class, an instance of that class simulated all by itself (maybe with a single current pulse stimulus) must produce identical results on each call to h.run(). The state of the model at the end of one run must not affect what happens in the next run. If either of these criteria fails, the first place to look for problems is in the INITIAL blocks of the mod files that specify the cell's channels or ion transport or accumulation mechanisms.

It is not absolutely necessary that every model cell be initialized to steady state; in fact, that might be a totally incorrect initialization for a model cell that is supposed to be spontaneously active, e.g. pacemaker or burster. But it can sure save a lot of wall clock time if you don't have to wait for the cells in a network to go through a long "warmup" interval before things settle down, and there are principled ways to achieve that goal.

3. Have you tested the individual subnetworks to verify that each one is properly initialized? i.e. it should produce identical results on each call to h.run(), and the state of the model at the end of one run must not affect what happens in the next run. One potential source of problems is failure to properly initialize parameters (e.g. synaptic weights or channel densities) that are controlled by "learning rules."
neuromancer
Posts: 10
Joined: Mon Apr 13, 2020 4:42 pm

Re: Switching synaptic connections in nested for loop

Post by neuromancer »

Thanks Ted, I will look into what you just said!

1. There are pseudorandom spike trains (no other randomization involved in the network). But during this period of testing, I'm saving spike trains and using the same ones to look at outcomes.
2. My colleague who optimized these single model cells told me to let the simulation run initially for 100-200ms to let the cells "warm up". Maybe this is the issue like you mentioned. I will discuss with my colleague a bit more and look into this.
3. I have not tested individual subnetworks to verify each one is properly initialized. I will also look into this. thanks!
ted
Site Admin
Posts: 5795
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Switching synaptic connections in nested for loop

Post by ted »

My colleague who optimized these single model cells told me to let the simulation run initially for 100-200ms to let the cells "warm up".
That may not be long enough if ion accumulation is involved.

Another type of initialization problem is "carryover" of something from the end of one simulation to the beginning of the next. One test for carryover is to set up a toy experiment in which a cell model is driven by an IClamp so that it fires one or more spikes. Set tstop so that the simulation ends while t is far from resting potential. Run a few simulations (2 or 3 should be enough) and see if there is any difference from one run to the next. Now change tstop (so that the cell will end at a different point in its trajectory) and run one more simulation. If this last simulation differs from the previous one, then intialization is incomplete--some variable that changes in the course of a simulation is retaining its value from the end of one simulation to the beginning of the next. This is usually caused by an error in a mod file's INITIAL block, but there can be other causes as well (e.g. a faulty attempt to implement plasticity or homeostasis).
neuromancer
Posts: 10
Joined: Mon Apr 13, 2020 4:42 pm

Re: Switching synaptic connections in nested for loop

Post by neuromancer »

Thank you, I tested before to see if one run changes from the previous. I just saw this reply so now I will check also with changing tstop.
Post Reply