// Threshold spacetests using a binary search method. // // Program flow: // Takes location range, Gaussian width for time distribution, and location increments. // Also takes type of run: AMPA only, NMDA only, or both. // Records number of synapses at which a single action potential is fired. // Also may record voltage at soma (later) // Updated to take a starting seed and to work with a cell template instead of the old ball and stick. // Updated to use variable AMPA conductance. strdef filename proc ThreshSpace() { local AMPAc,UPPERLIM,resetHere,locRange,gaussTime,repStat,incrBy,found,branchLength,toggle,matInd,jvar,stSeed localobj search_ind,finMat,floovec,cell // Runs the whole test. // Inputs: // $1: locRange is the range to be uniformly sampled in space // $2: gaussTime is the width of the Gaussian to be sampled for timing // $3: repStat is the number of repetitions for each location, to collect statistics in variation // $4: incrBy is the distance in microns each trial is separated by. // $5: branchLength is the number of spines on the tested branch. // $6: toggle is the kind of synapse: 0 BOTH, 1 AMPA, 2 NMDA // $s7: filename. // $8: the starting seed // $o9: the cell itself // $10: AMPA conductance, with normal .0005 umho UPPERLIM = 10000 // If the number of synapses goes above this, the trial moves on. locRange = $1 gaussTime = $2 repStat = $3 incrBy = $4 branchLength = $5 toggle = $6 filename = $s7 stSeed = $8 cell = $o9 AMPAc = $10 // The binary search vector holding indices. Order: lower bound, current test number, upper bound. search_ind = resetVec(200) floovec = new Vector(1,((branchLength-locRange)/incrBy)+1) // For the (test) case where incrBy is larger than locRange if (incrBy >= locRange) { floovec = new Vector(1,(branchLength/incrBy)) } floovec.floor() finMat = new Matrix(floovec.x[0]-1,repStat) for r_ind = 0,repStat-1 { seed = (stSeed+r_ind)*(r_ind+stSeed) matInd = -1 for (l_ind=0;l_ind<(branchLength-locRange);l_ind=l_ind+incrBy) { // For each run, search_ind starts from the previous threshold level found = 0 matInd = matInd+1 if (search_ind.x[1] == -1) { resetHere = UPPERLIM-1 } else { resetHere = search_ind.x[1] } search_ind = resetVec(resetHere) while (found != 1) { // found variable is 1 when AP is fired at synnum n+1 but not at synnum n found = testSyns(search_ind.x[1],locRange,gaussTime,toggle,seed,l_ind,cell,AMPAc) // Sees if this synapse number works print search_ind.x[1] // Setting an upper limit for # synapses tested if (search_ind.x[1] > UPPERLIM) { found = 1 search_ind.x[1] = -1 } search_ind = binSearch(search_ind,found) // If synapse number doesn't work, changes the search index and upper limit } finMat.x[matInd][r_ind] = search_ind.x[1] + 1 // Saves final synapse number to the matrix jvar = printf("Iter %d, loc %d: %d\n",r_ind,l_ind,search_ind.x[1]) } } saveSpace(finMat,filename) } /*------------------ MAIN FUNCTIONS ----------------------*/ func testSyns() { local AMPAc, search_ind, locRange, gaussTime, toggle, seed, l_ind, found localobj r2, tlist, tlist2, apc // If an AP fires at search_ind and search_ind+1, returns 2. // If no AP fires at either, returns 0. // If AP fired at search_ind+1 and not search_ind (it's at threshold), returns 1. // // Inputs: // $1: search_ind is how many synapses to use // $2: locRange is the testing range // $3: gaussTime is the width of the Gaussian for the time distribution // $4: toggle is the usual synapse type ID // $5: seed is for the norm dist for time and the unif dist for space. // $6: l_ind is where the test is starting. // $o7: the cell // $8: AMPA conductance (normal .0005 umho) search_ind = $1 locRange = $2 gaussTime = $3 toggle = $4 seed = $5 l_ind = $6 AMPAc = $8 r2 = new Vector(2,0) // Runs for search_ind and search_ind+1 for ts_ind = 0,1 { tlist = new List() tlist2 = new List() tlist = setSyns(search_ind+ts_ind,locRange,gaussTime,toggle,seed,l_ind,$o7,AMPAc) if (toggle==0) { tlist2 = setSyns(search_ind+ts_ind,locRange,gaussTime,2,seed,l_ind,$o7,AMPAc) } // Puts an APCount object at the axon $o7.axon { apc = new APCount(0.5) apc.thresh = 0 apc.n = 0 } //Takes tlist to adjust tstop. runTest(tlist) // Sees if an AP fired if (apc.n > 0) { if (ts_ind==0) { return 2 } else { r2.x[ts_ind] = 1 } } } return r2.sum() } obfunc binSearch() { // Adjusts the searchVec based on results from testSyns. // // Inputs: // $o1: search_ind is a vector; the first element is the number of synapses being tested // $2: found tells what to do with the search vector. 0 is none, 1 is threshold, 2 is both. // If too low if ($2 == 0) { $o1.x[0] = $o1.x[1] if ($o1.x[2] == $o1.x[1]) { $o1.x[1] = $o1.x[1]*2 $o1.x[2] = $o1.x[1] } else { $o1.x[1] = (($o1.x[2]-$o1.x[1])/2)+$o1.x[1] $o1.floor() } } // If too high if ($2 == 2) { $o1.x[2] = $o1.x[1] $o1.x[1] = (($o1.x[1]-$o1.x[0])/2)+$o1.x[0] $o1.floor() } return $o1 } proc saveSpace() { localobj mat, f // Takes a matrix and saves it. // // Inputs: // $o1: the matrix to be saved (rows are location, columns are trial) // $s2: filename with the full directory mat = $o1 f = new File() f.wopen($s2) mat.fprint(f, " %g") f.close() } obfunc resetVec() { localobj vec // Gives the index vector given some general starting point. It's a 3-element vector where the // first element is the lower bound, middle is current index, last is upper bound. The function // starts the upper bound at the current index value, since the search pattern works by doubling. // // Input: // $1: the number of synapses to start out with. vec = new Vector(3,0) vec.x[1] = $1 vec.x[2] = $1 return vec } /*------------------ SUB FUNCTIONS -----------------------*/ // In testSyns() obfunc setSyns() { local s_ind localobj tlist,r,normr,svec,tvec // Creates a list of placed and timed synapses. Does not deal with BOTH case (creates AMPA for // 0 and 1 toggle and NMDA for 2) because that's taken care of in testSyns(). // // Inputs: // $1: synapse number. // $2: locRange, how widely synapses are distributed. // $3: gaussTime, the width of the Gaussian used in sampling onset times. // $4: toggle is explained above; slightly different for this function since it does one at a time. // $5: seed // $6: l_ind is the spine this test is starting on. // $o7: the cell // $8: AMPA conductance (normal .0005 umho), used only when toggle is 0 or 1 // Output: // A single list of one kind of synapse; preset locations and firing times. tlist = makeSyns($4,$1) r = new Random($5) r.uniform($6,$6+$2) normr = new Random($5*10) normr.normal(0,$3) svec = new Vector($1) tvec = new Vector($1) svec.setrand(r) svec.floor() tvec.setrand(normr) tvec.add((-1)*tvec.min()+2) for s_ind = 0, $1-1 { $o7.spine_head[svec.x[s_ind]] { tlist.o(s_ind).loc(.5) tlist.o(s_ind).onset() = tvec.x[s_ind] if ($4!=2) { tlist.o(s_ind).gmax() = $8 } } } return tlist } // In testSyns() proc runTest() { local i localobj vec // Initializes cell and runs to tstop, which is 100 + last firing time. // Input: // $o1: tlist. vec = giveTimes($o1) init() tstop = vec.max() + 100 while (t