Activating a synapse at recorded or precomputed times
Moderator: wwlytton
Activating a synapse at recorded or precomputed times
Hi Ted,
I have a question related to this post
Driving a synapse with recorded or precomputed spike events
viewtopic.php?f=28&t=2117
I have 1000 vectors of event time and I want to apply these synapses to 1000 selected points on a dendritic tree. In a for loop I select a section in random and now I don't know how to apply spikes on the selected section. Do I need to use Vector.play()? Your help is really appreciated.
Thanks
-Mahmood
I have a question related to this post
Driving a synapse with recorded or precomputed spike events
viewtopic.php?f=28&t=2117
I have 1000 vectors of event time and I want to apply these synapses to 1000 selected points on a dendritic tree. In a for loop I select a section in random and now I don't know how to apply spikes on the selected section. Do I need to use Vector.play()? Your help is really appreciated.
Thanks
-Mahmood
-
- Site Admin
- Posts: 6384
- Joined: Wed May 18, 2005 4:50 pm
- Location: Yale University School of Medicine
- Contact:
Re: Activating a synapse at recorded or precomputed times
One doesn't apply spikes to a section. Spike events are to be delivered to a mechanism that knows what to do when it receives an event, e.g. an artificial spiking cell, or a synaptic mechanism described by NMODL code that has a NET_RECEIVE block (like an ExpSyn or Exp2Syn).Rivaldo wrote:I don't know how to apply spikes on the selected section.
The simplest algorithm for doing this is this loop, written in pseudocode for the sake of clarity:
Code: Select all
REPEAT
pick a location on a model cell
attach a synaptic mechanism to this location
specify that this mechanism will be activated at times contained in a Vector
UNTIL done
The second step is also easy, once you know which segment on which section is to get the new synapse.
The third step is just to create a new instance of the VecStim class, make a NetCon that will deliver the events it generates to the newly created synapse, and finally to tell the VecStim which Vector contains the times at which it should generate events.
Assuming that your spike time vectors were created with code that is equivalent to these statements
Code: Select all
NSTVECS = 1000
objref stvec[NSTVECS]
for i = 0,NSTVECS-1 fill stvec[i] with spike times
How to make all those NetCons? Prior to entering the REPEAT . . . UNTIL loop, declare
Code: Select all
objref vslist, nclist
vslist = new List()
nclist = new List()
Code: Select all
make a new instance of the VecStim class and append it to vslist
tell this new VecStim that it is to generate events at the times contained in stvec[i]
make a new instance of the NetCon class that connects the new VecStim to the new synaptic mechanism, and append this NetCon to nclist
specify the weight of the new NetCon
Re: Activating a synapse at recorded or precomputed times
Thank you so much for the thorough answer. Here I pasted a part of the code in the case someone need it and/or for you to check it.
However, I got this error saying " if arg 1 is an object it must be a point process or NULLObject". Can you help me on this?
Thanks,
However, I got this error saying " if arg 1 is an object it must be a point process or NULLObject". Can you help me on this?
Thanks,
Code: Select all
BEGINSECTION= 0
ENDSECTION= TOTALDEND - 1
printf ("*********** Total number of dendrites: %g ***********", ENDSECTION+1)
objref rc, rd
rc = new Random()
rc.MCellRan4(highindex+250)
rc.uniform(BEGINSECTION, ENDSECTION)
rd = new Random()
totSyn = 1000
objref Ens[totSyn], syn[totSyn], nc[totSyn]
double synWt[totSyn]
access soma
soma distance()
for (i=0; i <= totSyn-1; i +=1) {
count = 1
/*---------generate a syn at random section and random segment--*/
flag=0
while (flag==0) {
comp=int(rc.repick()+0.5)
/* NOTE1: Here I approximated a roughly uniform distribution over the cell, meaning
that synapses are generated regardless of the length of each segment. So long and
short dendrites have equal probability of receiving synapses. If you want to take
into account this factor, add an if statement here to accept "comp" with the
probability of (section length/max section length).
NOTE2: Multiple synapses are allowed to attach to a single segment.
*/
dend[comp].sec {
rd.MCellRan4(highindex+i*15)
rd.uniform(1, nseg+1)
count = 0
while (count <= nseg && flag==0) {
tmpnseg = int( rd.repick())
count += 1
tmp = (2*tmpnseg - 1)/(2*nseg)
flag=1
}
}
}//now right section, right segment has been found
dend[comp].sec {
syn[i] = new Exp2Syn(tmp)
syn[i].e=0
syn[i].tau1 = TAU1
syn[i].tau2 = TAU2
nc[i] = new NetCon(PreInputs[i], syn[i]) //PreInputs[i] contains ith event times
nc[i].weight =(A*dist*dist+B)/1e+06 // A and B are some constants.
}
}
-
- Site Admin
- Posts: 6384
- Joined: Wed May 18, 2005 4:50 pm
- Location: Yale University School of Medicine
- Contact:
Re: Activating a synapse at recorded or precomputed times
In debugging, the first task is to locate the cause of the problem. The hoc parser is particularly good at pinpointing syntax errors: it quotes the statement in which it found the error occurred. A run time error can be more difficult to pinpoint, because the error message is often generated many execution steps after the programming mistake that caused it.Rivaldo wrote:I got this error saying " if arg 1 is an object it must be a point process or NULLObject".
The error message you report looks to me like a syntax error caused it. Did I guess correctly, and do you see why it occurred?
-
- Site Admin
- Posts: 6384
- Joined: Wed May 18, 2005 4:50 pm
- Location: Yale University School of Medicine
- Contact:
Re: Activating a synapse at recorded or precomputed times
Code: Select all
/* NOTE1: Here I approximated a roughly uniform distribution over the cell, meaning
that synapses are generated regardless of the length of each segment. So long and
short dendrites have equal probability of receiving synapses.
Code: Select all
to_be_done = nsyn
func onepass() { local p, num
for each section to which a new synapse might be attached {
for (x,0) {
if (to_be_done>0) {
determine the likelihood p that this segment will get a new synapse
pick a number num from the uniform distribution over the interval 0...1, excluding 0 and 1
if num <= p {
attach a new synapse to this location
decrease to_be_done by 1
}
}
}
}
}
// there is no guarantee that all synapses will be placed
// in a single pass
while (to_be_done>0) onepass()
1. "for each section to which a new synapse might be attached"
In advance, create a SectionList called innervated.
Append to it all sections that might be innervated.
Then
forsec innervated
is the statement that iterates over these sections.
2. "pick a number num from the uniform distribution over the interval 0...1, excluding 0 and 1"
Locations 0 and 1 are not associated with length or surface area, so the probability of attaching a synapse to either one of them is 0.
So instead of just picking a value for num, do this
Code: Select all
repeat
num = value from the interval [0,1]
until ((num>0) && (num<1))
If you want to specify synaptic density in terms of synapses per micron length, in advance calculate the total length of all sections in innervated.
total_length = 0
forsec innervated total_length+=L
Then synaptic density is nsyn/total_length, and the probability that any particular segment will be innervated is
p = (L/nseg)*(nsyn/total_length)
If you prefer to specify synaptic density in terms of synapses per square micron surface area, in advance calculate the total area of all sections in innervated
total_area = 0
forsec innervated for (x,0) total_area+=area(x)
Then synaptic density is nsyn/total_area, and the probability that any particular segment will be innervated is
p = area(x)*nsyn/total_area
-
- Site Admin
- Posts: 6384
- Joined: Wed May 18, 2005 4:50 pm
- Location: Yale University School of Medicine
- Contact:
Re: Activating a synapse at recorded or precomputed times
Not so mathematically sound after all, because it has a source of bias: what I'll call the "first in line" effect. That is, the sections that appear earlier in the SectionList are more likely to have synapses attached to them than those that are closer to the end of the SectionList. This will happen because, once the final synapse has been attached, none of the remaining sections in the SectionList will have a chance to get a new synapse. This is guaranteed to happen. The severity of the resulting bias depends inversely on how many passes are made through the SectionList before the last synapse is placed.
One could abandon the idea of attaching a fixed number nsyn of synapses to the model, and simply make a single pass through the SectionList, realizing that the actual number of synapses attached may not be exactly the number that one wanted, but that if one created several models using the same morphology each time, but seeding the random number generator differently on each run, the number of synapses averaged over all the models would be nsyn.
If one insists on attaching exactly nsyn synapses, an alternative strategy is required. An approach that would work would be:
1. Map all sections to adjacent intervals on the real number line over the range 0...total_length. That is, the first section in the SectionList would correspond to the interval 0...L0 where L0 is the length of this section, the second section would correspond to the interval L0...L0+L1, the third to L0+L1...L0+L1+L2 etc.
2. Execute this loopThis will attach exactly nsyn synapses to the model. Of course, "draw the number num" should test to make sure that the value of num does not lie exactly on one of the boundaries between section intervals on the number line.
One could abandon the idea of attaching a fixed number nsyn of synapses to the model, and simply make a single pass through the SectionList, realizing that the actual number of synapses attached may not be exactly the number that one wanted, but that if one created several models using the same morphology each time, but seeding the random number generator differently on each run, the number of synapses averaged over all the models would be nsyn.
If one insists on attaching exactly nsyn synapses, an alternative strategy is required. An approach that would work would be:
1. Map all sections to adjacent intervals on the real number line over the range 0...total_length. That is, the first section in the SectionList would correspond to the interval 0...L0 where L0 is the length of this section, the second section would correspond to the interval L0...L0+L1, the third to L0+L1...L0+L1+L2 etc.
2. Execute this loop
Code: Select all
for i=0,nsyn-1 {
draw a number num from the uniform distribution over the range 0..total_length
discover the section foo that corresponds to num (i.e. the section that corresponds to the interval on the number line that contains num)
discover x which is defined as the the relative location of num in the interval that contains num
attach a new synapse to foo at location x e.g. foo syn = new Exp2Syn(x)
}
-
- Site Admin
- Posts: 6384
- Joined: Wed May 18, 2005 4:50 pm
- Location: Yale University School of Medicine
- Contact:
Re: Activating a synapse at recorded or precomputed times
here's one way to do it, assuming that synaptic density is specified as # synapses/micron length; if density is in # synapses/square micron, the approach would be similar in broad outline but different in some significant details.If one insists on attaching exactly nsyn synapses
Append all the sections that are to be innervated to a SectionList called innervated.
Calculate total_length, which is the total length of all of these sections.
Draw nsyn numbers > 0 from the uniform distribution over 0...total_length and append them to a Vector called sites.
Sort sites in ascending order.
Then
Code: Select all
forsec innervated {
if any synapses are to be attached to the currently accessed section
attach them to the appropriate positions on this section
}
Assumes that sites has nsyn elements that are > 0, and has been sorted in ascending order.
Code: Select all
min = 0
max = 0
objref loci
loci = new Vector()
objref synlist
synlist = new List() // to hold the new synapse instances
forsec innervated {
min = max
max += L
// synaptic locations that lie in the currently accessed section
// will be elements of sites whose values are > min and <= max
// i.e. those that lie in the half open interval (min,max]
loci.indvwhere(sites, "(]", min, max)
if (loci.size()>0) {
loci.sub(min).div(L) // elements should now lie in (0,1]
// make sure they do
// if largest locus is >= 1 force it to lie in last segment
if (loci.max()>=1) loci.x[loci.size()-1] = 1 - 0.1/nseg
// if first element is 0, discard it (will have been mapped to previous section in innervated)
if (loci.x[0]<=0) loci.remove(0) // discard the first element if it is 0
for i=0,loci.size()-1 {
synlist.append(new Exp2Syn(loci.x[i]))
}
}
}
print "created ", synlist.count(), " synapses"
Re: Activating a synapse at recorded or precomputed times
Hello,
Thanks for your posts. I got it to work and at least I don't get any syntax error now. But it doesn't spike at all no matter what the input firings are. Here is the pesudocode :
Am I dong something horribly wrong here?
Thanks a lot.
Thanks for your posts. I got it to work and at least I don't get any syntax error now. But it doesn't spike at all no matter what the input firings are. Here is the pesudocode :
Code: Select all
SPECIFY ALL THE PARAMETERS AND OBJECTS
totSyn = 1000
objref syn[totSyn], nc[totSyn]
double synWt[totSyn]
objref vslist, nclist, StimVector[totSyn]
vslist = new List()
nclist = new List()
access soma
soma distance()
for (i=0; i <= totSyn-1; i +=1) {
StimVector[i] = new VecStim()
StimVector[i].play(PreInputs[i]) // PreInputs[i] holds event times for ith syn mechanism
vslist.append(StimVector[i])
GENERATE A SYN AT RANDOM SECTION AND SEGMENT WITH ALL THE CONSIDERATIONS
SELECTED SECTION {
dist = distance(tmp)
syn[i] = new Exp2Syn(tmp)
syn[i].e=0
syn[i].tau1 = TAU1
syn[i].tau2 = TAU2
nc[i] = new NetCon(StimVector[i], syn[i])
nclist.apend(nc[i])
nc[i].weight=SOME FUNCTION OF DISTANCE
}
}
Thanks a lot.
-
- Site Admin
- Posts: 6384
- Joined: Wed May 18, 2005 4:50 pm
- Location: Yale University School of Medicine
- Contact:
Re: Activating a synapse at recorded or precomputed times
Pseudocode is important, but so is incremental development and testing.
Suggest you take a big step back from your current code and do this:
1. Make a single compartment passive model cell, attach a single synapse to it, and drive that synapse with events at times that are specified in a single Vector. To make this toy model as easy to work with as possible, use a short run time (5 or 10 ms at most) and only two or three synaptic activation times.
When that works properly,
2. Using the same model cell, attach two synapses, and drive each with its own unique event stream.
3. Switch to a ball and stick model cell (soma and dend) where soma.nseg is 1 and dend.nseg is 3. Attach a synapse to each compartment, and drive each synapse with its own event stream.
It will be easiest to write scalable code if you organize your code into procedures and use Lists to manage collections of objects. Eventually you'll end up with code that looks something like the following examples:where your first version of makesyn() would be
You could set up the activation time vectors, the VecStims, and the NetCons that attach the VecStims to the synapses in a similar way.where maketvec() is an obfunc that returns a Vector of activation times, and it expects an argument $1 that it uses to determine what file to read or that governs an algorithm that creates the numerical values that are contained in that Vector. Then you could
for ii=0,tvecs.count()-1 connect_stream(tvecs.o(ii))
where connect_stream() is a proc that looks like this
Suggest you take a big step back from your current code and do this:
1. Make a single compartment passive model cell, attach a single synapse to it, and drive that synapse with events at times that are specified in a single Vector. To make this toy model as easy to work with as possible, use a short run time (5 or 10 ms at most) and only two or three synaptic activation times.
When that works properly,
2. Using the same model cell, attach two synapses, and drive each with its own unique event stream.
3. Switch to a ball and stick model cell (soma and dend) where soma.nseg is 1 and dend.nseg is 3. Attach a synapse to each compartment, and drive each synapse with its own event stream.
It will be easiest to write scalable code if you organize your code into procedures and use Lists to manage collections of objects. Eventually you'll end up with code that looks something like the following examples:
Code: Select all
objref synlist
synlist = new List()
forall for (x,0) synlist.append(makesyn(x)) // attach a new synapse to each internal node in your model
Code: Select all
// attaches a new synapse to location $1 on currently accessed section
// and returns an objref that points to it
obfunc makesyn() { localobj tobj
tobj = new ExpSyn($1) // or whatever other synaptic mechanism you want
. . . statements that set params of tobj . . .
return tobj
}
Code: Select all
objref tvecs
tvecs = new List()
for ii=0,synlist.count()-1 tvecs.append(maketvec(ii))
for ii=0,tvecs.count()-1 connect_stream(tvecs.o(ii))
where connect_stream() is a proc that looks like this
Code: Select all
objref vslist, nclist
vslist = new List()
nclist = new List()
// $o1 is a Vector of activation times
// $o2 is an objref that points to an event-driven synaptic mechanism
// creates a new VecStim, and appends to vslist
// associates the new VecStim with $o1
// creates a new NetCon that delivers the VecStim's events to $o2
// appends the new NetCon to nclist
proc connect_stream() {
. . . fill in the blanks . . .
}