Modeling a Toggle Switch

Moderator: wwlytton

Post Reply
hmasood

Modeling a Toggle Switch

Post by hmasood »

Hi,

We're trying to build a network with just three neurons, one pacemaker and two simple neurons(N1 and N2). The pacemaker is connected to both N1 and N2, and N1 and N2 are connected to each other. The idea is to excite both neurons with the pacemaker cells, and then let them cross-repress each other. We thought the appropriate transfer function to use would be IntFire4.

We first built the network using ExpSyn to test our connections and plotted our results. We got pulse trains from the pacemaker (generated using clamps) to transfer to N1 and N2 as pulse trains. However, when we tried to change the transfer function to any of Exp2Syn, IntFire1, IntFire2 or IntFire4, it would not run to end time. In each case, the only thing we changed in the code was the transfer function (Does the variable 'syn' necessarily need to be changed to 'c' for IntFire4?).

Is it possible there are some parameters that need to be changed for the other transfer functions to work, or is there something we're missing altogether? The relevant sections of code are given below. We hope someone can help us out. Thanks!

objectvar syn[num_synapses]
objectvar net_con[num_synapses]

N1_dendrite[0] syn[0] = new ExpSyn(0)
N2_dendrite[0] syn[1] = new ExpSyn(0)

N1_dendrite[1] syn[2] = new ExpSyn(0) /*Code stops working when this is changed to any of Exp2Syn, IntFire1, IntFire2, IntFire4*/
N2_dendrite[1] syn[3] = new ExpSyn(0) /*Code stops working when this is changed to any of Exp2Syn, IntFire1, IntFire2, IntFire4*/

pacemaker_axon net_con[0] = new NetCon(&v(axon_loc), syn[0], apt, delay, sw_excite)
pacemaker_axon net_con[1] = new NetCon(&v(axon_loc), syn[1], apt, delay, sw_excite)

N2_axon net_con[2] = new NetCon(&v(axon_loc), syn[2], apt, delay, sw_inhibit)
N1_axon net_con[3] = new NetCon(&v(axon_loc), syn[3], apt, delay, sw_inhibit)
ted
Site Admin
Posts: 6302
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Modeling a Toggle Switch

Post by ted »

All of the IntFire classes are artificial spiking cells, not synaptic mechanisms. There is no point in trying to attach an instance of any IntFire class to a section, because doing so will have no functional consequence (for all I know, it may generate an error message; if no error message occurs, shame on hoc--it still won't do anything useful).

The code excerpt in your message contains no clue as to why the model doesn't work when Exp2Syn is used instead of ExpSyn.
Does the variable 'syn' necessarily need to be changed to 'c' for IntFire4?
So I guess you ran into some old code from the time when artificial spiking cells had to be "hosted" by a section, in which there was a statement of the form
sectionname c = new IntFire4()
This requirement is no longer the case. Artificial spiking cells can and should be free standing.

The answer to the question is that IntFire4 is an artificial spiking cell class, so it would make perfect sense to use "c" as the name of the objref because it suggests "cell." There is nothing special about "c" except that it falls into the set of "convenient, mnemonically suggestive strings." syn would be a poor choice from that perspective.


Other comments:
NetStim is a convenient source of events. With two NetStims it is easy to create a source of periodic spike bursts.
hmasood

Re: Modeling a Toggle Switch

Post by hmasood »

Thanks for the quick response. However, we are unsure of how to proceed.

Does the fact that the IntFire class is one of artificial cells, mean that we can just connect these cells to the pacemaker directly, and to each other, rather than creating the synapses?

For AplhaSynapse, the code looks like:

objectvar syn[num_synapses]
objectvar net_con[num_synapses]

N1_dendrite[0] syn[0] = new ExpSyn(0)
N2_dendrite[0] syn[1] = new ExpSyn(0)

N1_dendrite[1] syn[2] = new AlphaSynapse(0) /* ExpSyn replaced with AlphaSynapse */
N2_dendrite[1] syn[3] = new AlphaSynapse(0) /* ExpSyn replaced with AlphaSynapse*/

pacemaker_axon net_con[0] = new NetCon(&v(axon_loc), syn[0], apt, delay, sw_excite)
pacemaker_axon net_con[1] = new NetCon(&v(axon_loc), syn[1], apt, delay, sw_excite)
N2_axon net_con[2] = new NetCon(&v(axon_loc), syn[2], apt, delay, sw_inhibit)
N1_axon net_con[3] = new NetCon(&v(axon_loc), syn[3], apt, delay, sw_inhibit)

The error message we got was:
/Applications/NEURON-6.2/nrn/umac/bin/nrniv.app/Contents/MacOS/nrniv: No NET_RECEIVE in target PointProcess: AlphaSynapse[0]
in simple_test_1.nrn near line 83
N2_axon net_con[2] = new NetCon(&v(axon_loc), syn[2], apt, delay, sw_inhibit)
^
NetCon(..., AlphaSynapse[0], -20, 1, -2)
ted
Site Admin
Posts: 6302
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Modeling a Toggle Switch

Post by ted »

In NEURON, artificial spiking cells can generate and receive events. This means that they can be used as spike sources, and also as spike targets (no need to attach a synaptic mechanism, which wouldn't make sense anyway). Read the source code for any of the IntFire classes and you will see that it contains a NET_RECEIVE block that specifies what happens when an event is received, and how it decides when to generate an event. This is all spelled out in The NEURON Book, and in
Hines, M.L. and Carnevale, N.T.
Discrete event simulation in the NEURON environment.
Neurocomputing 58-60:1117-1122, 2004.
which is available from http://www.neuron.yale.edu/neuron/bib/nrnpubs.html

AlphaSynapse is an old synaptic mechanism that produces a single conductance change transient at a predefined time. Read its source code and you will discover that it lacks a NET_RECEIVE block, so it cannot respond to events and it cannot be used as the target of a NetCon. It would be a good idea to read and/or reread the documentation of the NetCon class; I see that the first sentence of the 4th paragraph should be revised to state that the target of a NetCon must be a point process that has a NET_RECEIVE block, or an artificial spiking cell (which by definition will have a NET_RECEIVE block).
hmasood

Re: Modeling a Toggle Switch

Post by hmasood »

Thanks for the reply. I'm trying something simpler, but I can't seem to get the syntax right; I get a parsing error. Here's the initialization in my file, where I'm trying to form a pacemaker cell that connects with two IntFire1 'neurons'. I get a parse error when I declare N1.

num_dendrites = 2
num_synapses = 2

apt = -20 /* action potential threshold (mV) */
delay = 1 /* delay (ms) */
sw_excite = 2.0 /* synaptic weight for excitatory synapse */
sw_inhibit = -2.0 /* synaptic weight for inhibitory synapse */
axon_loc = 0.5 /* location of synaptic connection on the axon */

/* */
/* Variables */
/* */
objref s

/* */
/* create the neuronal topology */
/* */
create pacemaker_soma
create pacemaker_axon
create pacemaker_dendrite[num_dendrites]


/* connect each soma to its axon and dendrites */
connect pacemaker_axon(0), pacemaker_soma(0)
for (i=0;i<num_dendrites;i=i+1) {
connect pacemaker_dendrite(0), pacemaker_soma(1)
}

/* connect pacemaker to IntFire1 neurons */

objectvar net_con[num_synapses]
N1 = new IntFire1(0)
N2 = new IntFire1(1)

for (i=0;i<num_connections;i++) {
pacemaker_axon net_con = new NetCon(&v(axon_loc), IntFire1(i), apt, delay, sw_excite)
}
ted
Site Admin
Posts: 6302
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Modeling a Toggle Switch

Post by ted »

All variables are scalars by default. A variable must be declared to be an objref before it can be used as an objref. In your code example, N1 is a scalar, not an objref.

A minor suggestion:
On this Forum, code will "look more like code" if you select it, then click on the "Code" button above the text entry area.
hmasood

Re: Modeling a Toggle Switch

Post by hmasood »

Thanks for all your help. What the model now looks like is a pacemaker connected to two IntFire4's, which mutually inhibit each other. Were it to behave like a toggle switch, here would be one test case (written in the code). N1 is initially inhibited for a short while, and then both N1 and N2 receive excitatory inputs from the pacemaker. We want N1 to remain inhibited, but instead it still fires, and continues to inhibit N2.

We plotted the membrane potential, and while we thought it was supposed to remain between 0 and 1, that was not observed. What could be the reason for that, and how can we change the current behavior of the model to match our expected results?

Code: Select all

/*
 * simple_test_3.nrn
 *
 */

ret = load_file("nrngui.hoc")

/*                      */
/* Simulation paramters */
/*                      */
time_step     =   0.5
end_time      = 350

num_synapses  = 4
num_dendrites = 2

apt         = -20   /* action potential threshold for pacemaker (mV) */
apt_intfire =  35.0 /* action potential threshold for N1 and N2 inhibition (mV) */
delay       =   1   /* delay (ms) */
sw_excite   =   0.5 /* synaptic weight for excitatory synapse */
sw_inhibit  =  -0.5 /* synaptic weight for inhibitory synapse */
axon_loc    =   0.5 /* location of synaptic connection on the axon */

/*           */
/* Variables */
/*           */
objref s 
objref N1, N2
objref f_out
objref f_events

/*                              */
/* create the neuronal topology */
/*                              */
create pacemaker_soma
create pacemaker_axon
create pacemaker_dendrite[num_dendrites]

create startup_soma
create startup_axon
create startup_dendrite[num_dendrites]


/* connect each soma to its axon and dendrites */
connect pacemaker_axon(0), pacemaker_soma(0)
for (i=0;i<num_dendrites;i=i+1) {
  connect pacemaker_dendrite[i](0), pacemaker_soma(1)
}

connect startup_axon(0), startup_soma(0)
for (i=0;i<num_dendrites;i=i+1) {
  connect startup_dendrite[i](0), startup_soma(1)
}


/*                                                */
/* connect pacemaker to N1 and N2 (IntFire4)	  */
/*                                                */

objectvar net_con[num_synapses]

N1 = new IntFire4()
N2 = new IntFire4()

/*
N1.taue  =  0.5
N1.taui1 =  2.0
N1.taui2 =  5.0
N1.taum  = 10.0

N2.taue  =  0.5
N2.taui1 =  2.0
N2.taui2 =  5.0
N2.taum  = 10.0
*/

pacemaker_axon net_con[0] = new NetCon(&v(axon_loc), N1, apt, delay, sw_excite) /* Pacemaker to N1, excitatory */
pacemaker_axon net_con[1] = new NetCon(&v(axon_loc), N2, apt, delay, sw_excite) /* Pacemaker to N2, excitatory */

N1 net_con[2] = new NetCon(&v(axon_loc), N2, apt_intfire, delay, sw_inhibit)    /* N1 to N2, inhibitory */
N2 net_con[3] = new NetCon(&v(axon_loc), N1, apt_intfire, delay, sw_inhibit)    /* N2 to N2, inhibitory */

/*                                */
/* connect startup to N1          */
/*                                */
objectvar net_con_startup[1]

startup_axon net_con_startup[0] = new NetCon(&v(axon_loc), N1, apt_intfire, delay, sw_inhibit) 


/*                                      */
/* set parameters for neuronal sections */
/*                                      */

/* Pacemaker */
pacemaker_soma {nseg=01 diam=18.8 L=0018.8 Ra=123.0 insert hh}
pacemaker_axon {nseg=20 diam=05.0 L=1000            insert hh }
for (i=0;i<num_dendrites;i=i+1) {
   pacemaker_dendrite[i] {nseg=5 L=200 diam(0:1)=10:3 insert pas e_pas=-65 g_pas=.001 }
}

/* Startup */
startup_soma {nseg=01 diam=18.8 L=0018.8 Ra=123.0 insert hh}
startup_axon {nseg=20 diam=05.0 L=1000            insert hh }
for (i=0;i<num_dendrites;i=i+1) {
   startup_dendrite[i] {nseg=5 L=200 diam(0:1)=10:3 insert pas e_pas=-65 g_pas=.001 }
}

access pacemaker_soma 

/*                   */
/* setup stimulation */
/*                   */
num_stims     = 20
clamp_pos     =  0.5
initial_delay = 10

objectvar stim[num_stims]

for (j=0;j<num_stims;j=j+1) {
  stim[j] = new IClamp(clamp_pos)

  stim[j].del =  j*20 + initial_delay
  stim[j].dur =   5
  stim[j].amp =  10.0 
}

/*               */
/* setup startup */
/*               */
access startup_soma 

num_stims_startup     = 2
clamp_pos             = 0.5
initial_startup_delay = 2

objectvar stim_startup[num_stims_startup]

for (j=0;j<num_stims_startup;j=j+1) {
  stim_startup[j] = new IClamp(clamp_pos)

  stim_startup[j].del =  j*20 + initial_startup_delay
  stim_startup[j].dur =   5
  stim_startup[j].amp =  10.0 /* original = 0.1 */
}


/*                       */
/* Main simulation loop  */
/*                       */
f_out    = new File()
f_events = new File()

ret   = f_out.wopen("out.dat")
ret   = f_events.wopen("netcon_events.dat")

for (i=0;i<end_time;i=i+time_step) {
    tstop = i
    run()
    ret   = f_out.printf("%g %g %g %g %g %g\n", t, pacemaker_soma.v, N1.M, N1.m, N2.M, N2.m) 
    print "time = ", t
}

/* record events (only for the last run, for now) */
ret = net_con[0].record("event_netcon_0()")
ret = net_con[1].record("event_netcon_1()") /* note that the pacemaker makes the event */
ret = net_con[2].record("event_netcon_2()") 
ret = net_con[3].record("event_netcon_3()")
  
proc event_netcon_0() {
  f_events.printf("0 %g\n", t)
}

proc event_netcon_1() {
  f_events.printf("1 %g\n", t)
}

proc event_netcon_2() {
  f_events.printf("2 %g\n", t)
}

proc event_netcon_3() {
  f_events.printf("3 %g\n", t)
}

/* run one last time, and record events */
tstop = end_time
run()
ret   = f_out.printf("%g %g %g %g %g %g\n", t, pacemaker_soma.v, N1.M, N1.m, N2.M, N2.m) 


print "Finished simulation to time ", end_time
print "Simulation output stored in ", f_out.getname()

ret = f_out.close()  
ret = f_events.close()  

ret = quit()

Also, in the NEURON book, the chapter on artificial spiking cells mentions that pacemakers have also been modeled this way. Could you please let me know where such a pacemaker model can be found? Thank you so much for all the help you've given!
ted
Site Admin
Posts: 6302
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Modeling a Toggle Switch

Post by ted »

What could be the reason for that, and how can we change the current behavior of the model to match our expected results?
Well put. After one has solved the problems of formulatiing a hypothesis, and then determining how to express that hypothesis in computational form, one is often left with these questions:
--understanding how a model works
--understanding why it does something different from what one expected
--knowing what to do to bring its behavior into line with one's expectations (or what to do to bring one's expectations into line with the model's behavior)

Without running or examining your code, in my role as kibitzer I'd guess that maybe the postsynaptic inhibitiory effect is too small and decays too rapidly, and the presynaptic cell fires too slowly, for the inhibited to stay inhibited.

A hint for how you might more easily debug the operation of your model: try examining the time course of "membrane potential" (the "activation variable"). Maybe also look at the time course of the "synaptic currents."

A suggestion: I know that everyone believes in the soundness of their own code, and "the fundamental rigor of writing code as opposed to playing around with a GUI," but NEURON's GUI works by executing hoc statements, and it is far more convenient for exploratory modeling. In the world of commercial software, GUI tools for building and running programs are called "rapid application development environments" or "RAD tools." Application developers pay big bucks for RAD tools, which can save lots of time and effort. With the Network Builder it's easy to throw a toy net like this together, manage model properties via a GUI that provides immediate reminders of current parameter values, and visualize results in the form of raster plots. With the NEURON Main Menu toolbar one can also bring up graphs that show the time course of "membrane potential" (activation) in the network's cells, and soon discover why any cell escapes inhibition or remains inhibited. Finally, when the model is debugged, the Network Builder can generate and write hoc code to a human-readable text file that, when executed by NEURON, will reinstantiate the model (sans GUI).
in the NEURON book, the chapter on artificial spiking cells mentions that pacemakers have also been modeled this way. Could you please let me know where such a pacemaker model can be found?
Easy to build yourself. As I mentioned in an earlier post
NetStim is a convenient source of events. With two NetStims it is easy to create a source of periodic spike bursts.
For example, a single NetStim can be configured to generate any number of events that occur at regular or irregular intervals. To get a source of periodic bursts, configure one NetStim to produce the desired number of events in one burst, at the desired interspike interval. Configure the other to produce a train of individual events spaced uniformly at intervals of 1000/(burst frequency in Hz), where "burst frequency" is # of bursts/second.
Post Reply