Changing synaptic conductance during a sequence of events

Anything that doesn't fit elsewhere.
Post Reply
maria diamantaki

Changing synaptic conductance during a sequence of events

Post by maria diamantaki » Fri Jun 14, 2013 3:53 pm

Hi, I am a new user of NEURON and I need some help. First of all, what I have is a simple model of a single neuron, with two dendrites (with branches) and an axon. The model has only passive properties and a non-linear leakage current. In one branch of each dendrite I have two synapses, one AMPA and one NMDA.

What I want to do is to have a specific sequence of events, which I did with this code (I found in an older post)

Code: Select all

objref fih
fih = new FInitializeHandler("loadqueue()")
proc loadqueue() { local ii
  for ii=0,syntimes.size()-1 nc[0].event(syntimes.x[ii])
}
and during this sequence of events, to change the synaptic conductance by changing gmax. I know there are some similar threads, and I have already read them (maybe not all of them, but those that I found), but I'm quite confused.

Is it possible to do it in hoc or I should change the mod file? What is the best and simplest approach I can use, as my experience in NEURON is in basic level. Any recommendations and corrections are welcome and I apologize in case I repeat an already answered question.

Thanks
Maria

ted
Site Admin
Posts: 5592
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Changing synaptic conductance during a sequence of event

Post by ted » Sat Jun 15, 2013 11:58 am

maria diamantaki wrote:In one branch of each dendrite I have two synapses, one AMPA and one NMDA.
First, a comment. The code excerpt you provide contains a single NetCon; for each synaptic mechanism instance you will need a separate NetCon, and each activation of each synapse is going to require that you stuff a corresponding event into the event queue. If the number of synapses and activations are both small, it's probably OK to use the "loadqueue" strategy. However, your code will be cleaner and your model will scale better (handle a larger number of synapses and events more efficiently) if you use a single VecStim object as the spike source.
What I want to do is to have a specific sequence of events . . . and during this sequence of events, to change the synaptic conductance by changing gmax.
So am I right to presume you're not using NEURON's built-in ExpSyn or Exp2Syn? Most event driven synaptic mechanisms that I have seen, and certainly any that can handle multiple convergent afferent streams, do not have a gmax parameter. Instead the amplitude of the synaptic conductance change is specified by the weight of the NetCon that delivers the event. Indeed, in my experience most event driven synaptic mechanisms with a gmax parameter are rather limited in their capabilities if not downright buggy. If you're using something you found in ModelDB, please point me to the file(s) so I can see for myself. If it's code that isn't in ModelDB and you want me to look at it, zip it up and email to
ted dot carnevale at yale dot edu
and I'll check it out.

Back to your original question in its most general form: how to specify a temporal sequence of synaptic activations so that each activation occurs at a precomputed time and causes a precomputed perturbation of synaptic conductance. Suppose the event times t0..tn-1 are contained in Vector stvec and the corresponding perturbations of synaptic conductance w0..wn-1 are contained in Vector swvec, and the synaptic mechanisms have been appended to a List called slist, here's a strategy expressed in pseudocode that will force the synapses to be activated at the times specified in stvec.

Code: Select all

create a VecStim that generates events at the times specified in stvec
attach the VecStim to each synapse and set the NetCon's delay to 0
The next question is how to force the desired synaptic strengths. For each synaptic activation, the weights must be changed to their new values _before_ the activation occurs. Here's pseudocode for how to do that:

Code: Select all

find the shortest interevent interval in stvec; call this mindel
subtract mindel/2 from the elements of stvec (now contains t0-mindel/2, t1-mindel/2 etc.)
create a VecStim that generates events at the times specified in stvec
attach the VecStim to each synapse and set the NetCon's delay to mindel/2
// at this point, each synapse will be activated at t0 - mindel/2 + mindel/2, t1 - mindel/2 + mindel/2 etc.
set up an FInitializeHandler that sets a global variable called "count" to 0
set up proc setweights() that, when called, sets the synaptic weights to swvec.x[count] and increments count by 1
create a NetCon that is driven by the VecStim, has delay set to 0, and uses its event() method to call setweights()
Now in the course of a run, the synaptic weights will be set to the desired values at times t0-mindel/2, t1-mindel/2 . . . and the synapses will be activated at times t0, t1 . . .

Of course the devil is in the details, and I'll be able to provide those when I know more about the synaptic mechanisms you're using.

maria diamantaki

Re: Changing synaptic conductance during a sequence of event

Post by maria diamantaki » Sat Jun 15, 2013 3:39 pm

Hi ted, thanks for the reply.
ted wrote:First, a comment. The code excerpt you provide contains a single NetCon; for each synaptic mechanism instance you will need a separate NetCon, and each activation of each synapse is going to require that you stuff a corresponding event into the event queue. If the number of synapses and activations are both small, it's probably OK to use the "loadqueue" strategy. However, your code will be cleaner and your model will scale better (handle a larger number of synapses and events more efficiently) if you use a single VecStim object as the spike source.
I should have quoted my code instead of the one I used as a "model" and yes I have two separate NetCons, one for each synapse. Also the number of events I want to simulate now it's small enough, just 5, but I guess in the future I will probably have to run longer simulations, so thanks for the advice to use VecStim.
ted wrote:So am I right to presume you're not using NEURON's built-in ExpSyn or Exp2Syn?
Actually, I am using the AMPA synapse from NEURON book, and an NMDA which is the same with AMPA but with an Mg block added like in Destexhe et al. 1998
http://senselab.med.yale.edu/modeldb/sh ... 5Cnmda.mod

I will try to implement what you suggest with VecStim, but it will take me a while since I haven't used VecStim before. Also I was wondering what is a better approach in changing the synaptic conductance, change the weights or the gmax of the synapse?

If it's not a trouble I can send you my codes, so you can see for yourself, because I'm not sure if I have explained everything clearly.

Thanks a lot for the help.
maria

ted
Site Admin
Posts: 5592
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Changing synaptic conductance during a sequence of event

Post by ted » Sun Jun 16, 2013 10:41 am

I am using the AMPA synapse from NEURON book, and an NMDA which is the same with AMPA but with an Mg block added like in Destexhe et al. 1998
Fine if you're referring to the AMPA_S mechanism described in the saturating synapse example i.e. example 10.6.
what is a better approach in changing the synaptic conductance, change the weights or the gmax of the synapse?
The question isn't relevant to AMPA_S or mechanisms based on it, because those don't have a gmax parameter; synaptic strength is specified by the NetCon's weight. It is not a good idea to include a synaptic strength parameter in an event-driven synaptic mechanism that is capable of handling more than one stream of afferent events, because changing that parameter would affect the response to events from all inputs that converge onto the mechanism.

Here's some code that should implement the strategy outlined in my previous message. Be sure to test it, in case it contains an error. I did make a mistake in my previous message where I wrote about using a NetCon's event() method to call setweights(). I meant to say "use its record() method".

Code: Select all

/*
assumptions:
1.  synlist is a List that contains the synapses that are to be driven.
2.  stvec is a Vector that contains the times at which the synapse are to be activated.
The first event time is > 0,
subsequent times are in monotonically increasing order, 
and there are no repeated values.
3.  swvec is a Vector that specifies the synaptic weight for each synaptic activation time.
*/
// find the shortest interevent interval in stvec and divide that by 2
objref tmpvec
tmpvec = stvec.c
tmpvec.deriv
actdel = tmpvec.min/2 // interval between the times at which weights are changed
  // and the times at which the synapses are to be activated
if (stvec.x[0] < actdel) { // prevent making event times < 0
  actdel = stvec.x[0] / 2
}
stvec.sub(actdel) // shift the "spike times" earlier by amount equal to actdel

// create a VecStim that generates events at the times specified in stvec
objref vecstim
vecstim = new VecStim()
vecstim.play(stvec)

// attach the VecStim to each synapse and set the NetCon delays to actdel
objref nclist
nclist = new List()
for ii=0,synlist.count()-1 {
  nclist.append(new NetStim(vecstim, synlist.o(ii))
  nclist.o(ii).delay = actdel
}
// at this point, each synapse will be activated at the times specified in the original stvec

// set up an FInitializeHandler that sets a global variable called "count" to 0
count = 0 // so it exists before we use it
objref fih
fih = new FInitializeHandler("count = 0")

// each time setweights is called, the synaptic weights are set
// to the value they should have when the synapses receive their next event
proc setweights() { local ii
  for ii=0,nclist.count()-1 nclist.weight = swvec.x[count]
  count+=1
}

// ncx is driven by the VecStim, has delay set to 0
// and uses its record() method to call setweights()
objref ncx, nil
ncx = new NetCon(vecstim, nil)
ncx.delay = 0
ncx.record("setweights()")

maria diamantaki

Re: Changing synaptic conductance during a sequence of event

Post by maria diamantaki » Sun Jun 16, 2013 11:22 pm

Hi ted,

Thanks for the reply again! It was really helpful and now my code works as I was expecting. However I would like to ask you something more..

First of all, I had to do some small changes in the code you quoted since I was getting some errors and I want to confirm that I didn't do something wrong.
ted wrote:for ii=0,synlist.count()-1 {
  nclist.append(new NetStim(vecstim, synlist.o(ii))
  nclist.o(ii).delay = actdel
}
In this part of the code I changed the 2nd line with the following:

Code: Select all

nclist.append(new NetCon(vecstim,synlist.o(ii).syn)
cause I got the error: "delay is not public in NetStim", so I thought this way to fix it.

Also here
ted wrote:proc setweights() { local ii
  for ii=0,nclist.count()-1 nclist.weight = swvec.x[count]
  count+=1
}
I added o(ii) in the weight expression like: nclist.o(ii).weight =...

Both these changes look correct to me and I hope they are.

Furthermore I want to ask you again, about changing gmax or weighting. In case we have an AMPA like the one in NEURON book, but we have added a gmax value so that BREAKPOINT becomes:

Code: Select all

BREAKPOINT {
	SOLVE release METHOD cnexp
	g = (Ron + Roff)*gmax
	i = g*(v - Erev)
}
would it be easier or preferable to change gmax (and how, hoc or NMODL?), or is it something which is better to avoid?

Thank you very very much once again!

maria

ted
Site Admin
Posts: 5592
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Changing synaptic conductance during a sequence of event

Post by ted » Mon Jun 17, 2013 12:28 am

Well, just as always, it's important to check anyone's code to make sure there isn't an error. And that goes for mine too.
maria diamantaki wrote:I had to do some small changes in the code you quoted since I was getting some errors and I want to confirm that I didn't do something wrong.
ted wrote:for ii=0,synlist.count()-1 {
  nclist.append(new NetStim(vecstim, synlist.o(ii))
  nclist.o(ii).delay = actdel
}
In this part of the code I changed the 2nd line with the following:

Code: Select all

nclist.append(new NetCon(vecstim,synlist.o(ii).syn)
cause I got the error: "delay is not public in NetStim", so I thought this way to fix it.
I agree with your change except for the .syn part. I was thinking about setting up a NetCon connection between the vecstim and each of the synapses, but wrote "NetStim" instead. If the elements in synlist are instances of NMODL-defined synaptic mechanisms, the fix is to change
nclist.append(new NetStim(vecstim, synlist.o(ii))
to
nclist.append(new NetCon(vecstim, synlist.o(ii))
If you're writing
synlist.o(ii).syn
instead of
synlist.o(ii)
then I can only guess that your synaptic mechanisms are wrapped inside a template. Did I guess correctly?
Also here
ted wrote:proc setweights() { local ii
  for ii=0,nclist.count()-1 nclist.weight = swvec.x[count]
  count+=1
}
I added o(ii) in the weight expression like: nclist.o(ii).weight =...
Yes, another case of sloppy code written by me, found and corrected by someone else. Well, at least I pointed you in the right direction.
I want to ask you again, about changing gmax or weighting. In case we have an AMPA like the one in NEURON book, but we have added a gmax value so that BREAKPOINT becomes:

Code: Select all

BREAKPOINT {
	SOLVE release METHOD cnexp
	g = (Ron + Roff)*gmax
	i = g*(v - Erev)
}
BIG mistake. You really, really don't want to do that. I can thiink of at least two reasons.

Here's one. Imagine a model of a cell that has two or more identical synapses that are electrically close to each other. You want to be able to adjust their strengths independently of each other. With a properly written event-driven synaptic mechanism, you can represent all those synapses with a single mechanism instance--just create a single instance of the mechanism and attach as many NetCons to it as there are synapses your conceptual model--and you can adjust the strength of each of the synapses independently of all the others simply by changing the weight that belongs to the corresponding NetCon. Not so with the "gmax" parameter--gmax changes the impact of _all_ synaptic inputs, regardless of the presynaptic spike source. The fancy way of saying this is "gmax introduces artifactual heterosynaptic interactions."

Here's another. Changing gmax violates causality. Consider what happens during ampaergic synaptic transmission. Transmitter release from the presynaptic terminal is extremely fast. The slow decaying phase of synaptic conductance reflects the dynamics of transmitter concentration and transmitter-receptor interactions in the synaptic cleft. Suppose at t0 a synapse is activated, then at some later t1 you increase gmax. That's going to affect whatever remains of the conductance transient from the activation at t0, but not by any biologically plausible mechanism.

The notion of heterosynaptic acausality does have a certain appeal, rather like the infinite improbability drive.

maria diamantaki

Re: Changing synaptic conductance during a sequence of event

Post by maria diamantaki » Mon Jun 17, 2013 5:09 am

ted wrote:If you're writing
synlist.o(ii).syn
instead of
synlist.o(ii)
then I can only guess that your synaptic mechanisms are wrapped inside a template. Did I guess correctly?
Actually, when I wrote just synlist.o(ii) in the NetCon, I got an error saying that the 2nd argument should be a point process. So I added .syn to refer to each point process.. but no I don't have a template.

Also, thanks a lot for the information and the advice about gmax.

maria

ted
Site Admin
Posts: 5592
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Changing synaptic conductance during a sequence of event

Post by ted » Mon Jun 17, 2013 10:16 am

maria diamantaki wrote:
ted wrote:If you're writing
synlist.o(ii).syn
instead of
synlist.o(ii)
then I can only guess that your synaptic mechanisms are wrapped inside a template. Did I guess correctly?
Actually, when I wrote just synlist.o(ii) in the NetCon, I got an error saying that the 2nd argument should be a point process. So I added .syn to refer to each point process.. but no I don't have a template.
Then something strange is going on. A synaptic mechanism defined by NMODL is not going to have a public member called syn. I generated the following output by starting NEURON, then typing a sequence of statements at the oc> prompt. NEURON generates the oc> prompts and all the lines that do NOT start with an oc>

Code: Select all

oc>create soma
oc>objref exc
oc>soma exc = new ExpSyn(0.5)
oc>exc
	ExpSyn[0] 
oc>exc.syn
syn not a public member of ExpSyn
/usr/local/nrn/i686/bin/nrniv: ExpSyn syn
 near line 5
 exc.syn
        ^
Save the following code to a file called testsyn.hoc, then use NEURON to execute testsyn.hoc.

Code: Select all

NSYN = 3

objref ns
ns = new NetStim()
create soma

objref slist
slist = new List()
soma for ii=0,NSYN-1 slist.append(new ExpSyn(0.5))

objref nclist
nclist = new List()
for ii=0,slist.count()-1 nclist.append(new NetCon(ns, slist.o(ii)))
print "if you see this, nclist was created successfully"

print "trying to append items to nclist2"
objref nclist2
nclist2 = new List()
for ii=0,slist.count()-1 nclist2.append(new NetCon(ns, slist.o(ii).syn))
print "if you see this, nclist2 was created successfully"
You should get this output:

Code: Select all

if you see this, slist was created successfully
if you see this, nclist was created successfully
trying to append items to nclist2
syn not a public member of ExpSyn
/usr/local/nrn/i686/bin/nrniv: ExpSyn syn
 in testlist.hoc near line 35
 for ii=0,slist.count()-1 nclist2.append(new NetCon(ns, slist.o(ii).syn))
                                                                         ^
My turn to look for the bug in your code, if you'll zip up just enough to create the nclist and send it to
ted dot carnevale at yale dot edu

ted
Site Admin
Posts: 5592
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Changing synaptic conductance during a sequence of event

Post by ted » Wed Jun 19, 2013 7:41 pm

The problem was that the List of synaptic mechanisms was actually a list of NetCons because it had been set up with a statement similar to this:
synlist.append (new NetCon(spikesource, synapticmechanism))
So the elements of synlist were really NetCons, not synaptic mechanisms.
The fix is to build synlist by appending the desired synaptic mechanism instances to it.

Post Reply