// gcelldata.hoc -- routines for processing the empirical data used by the
// simulation (gcell = Gordon (Shepherd) cell).
// Globals and routines pertaining to the empirical data used from
// (Weiler et al., 2008) and other Gordon Shepherd projects.
//
// Last update: 3/12/11 (georgec)
//* Globals
numgcs = 0 // number of Gordon cells (set later)
numgcxs = 16 // number of horizontal bins in Gordon cell conv data
xbinwid = 100 // x bin width (in microns)
numzs = 16 // number of depth bins
zbinwid = 100 // z (depth) bin width (in microns)
lambeg = 0 // the first z bin for a cell layer (set in proc)
lamend = 0 // the last z bin for a cell layer (set in proc)
sigub = -15.0 // significant upper bound (in pA) for the data values
objref wdnq // (Weiler et al., 2008) data NQS table
objref hupnq // hookup NQS table
objref convnq // test cell convergence NQS table (made from hupnq)
strdef gsprepdir // directory for Gordon Shepherd preprocessed data
gsprepdir = "."
GCELLTYPE_NORMAL = 0 // normal Gordon cell type (otherwise unlabeled)
GCELLTYPE_CXSPINAL = 1 // corticospinal layer 5 cell
GCELLTYPE_CXSTRIATAL = 2 // contralateral corticostriatal layer 5 cell
//* Routines
//** simdatainit() -- load and/or preprocess Gordon cell data
proc simdatainit () { local a,ii,tnumgcs localobj v1,v2,v3
// Allocate temporary vectors.
a = allocvecs(v1,v2,v3)
// Load the NQS tables for Gordon's data.
{sprint(tstr,"%s/gmgs102.nqs",gsprepdir)}
rdnqss(tstr)
// Load the appropriate preprocessed cells data table.
wdnq = new NQS()
// {sprint(tstr,"%s/wdmaps.nqs",gsprepdir)} // culled cells with no preprocessing
{sprint(tstr,"%s/wdmaps2.nqs",gsprepdir)} // culled cells with interpolation applied
wdnq.rd(tstr) // culled cells with interpolation applied
// Set the number of Gordon cells.
numgcs = wdnq.m
// Make a new NQS table for only cells with neg responses over a cuttoff.
// wdnq = cullcells(raw, sigub)
// Create the hookup table.
mkhuptable()
// Scale hookup table weights (clip Gordon cell values between the negatives
// of the first 2 values, then scale these values to the last 2 values.
scalehupwts(0,50,0,5)
// scalehupwts(0,50,0,5) // original
// Add new columns to the cells table for (Gordon) cell number, Gordon
// cell type, and z bin.
tnumgcs = cells.size
v1.resize(tnumgcs)
v2.resize(tnumgcs)
v3.resize(tnumgcs)
v1.indgen(0,tnumgcs-1,1)
v2.fill(GCELLTYPE_NORMAL) // all cells are normal Gordon cells for now
for ii=0,tnumgcs-1 {
v3.x(ii) = gcellnum2zbin(ii)
}
cells.resize("cellnum",v1,"gcelltyp",v2,"zbin",v3)
// Deallocate the temporary vectors.
dealloc(a)
}
//** gcellnum2zbin(gordon_cell_type) -- translate Gordon cell number to z
// (depth) bin
func gcellnum2zbin () { local a,ii,zbin,ysoma localobj vv1
a = allocvecs(vv1)
// Get the micron distance of the cell from the pia.
ysoma = cells.v[2].x($1)
vv1.indgen(zbinwid,zbinwid * numzs,zbinwid)
zbin = -1
ii = numzs-1
while (ii >= 0) {
if (ysoma <= vv1.x(ii)) {
zbin = ii
}
ii -= 1
}
dealloc(a)
return zbin
}
//** getlambin(model_cell type) - get the first and last laminar bin for cell
// type
proc getlambin () { local lyr
lyr=GetLyr($1)
if (lyr == 2) {
lambeg = 1
lamend = 4
} else if (lyr == 5) {
lambeg = 5
lamend = 10
} else if (lyr == 6) {
lambeg = 11
lamend = 13
} else {
print "ERROR: Cannot find laminar bins for cell type #", $1
}
}
//** cullcells() -- make a new NQS table for cells only above neg. cutoff
obfunc cullcells () { local a,cutoff,cullcount localobj iq,oq,v1
iq = $o1 // input nq (with 102 cells)
cutoff = $2 // cutoff value for minimum
oq = new NQS() // output nq
a = allocvecs(v1) // alloc vector for keeping culled cell ID nums
// Loop over all column vectors of the NQS table...
for ii=0,iq.m-1 {
// If the minimum data value is below the cutoff value (e.g. -20 pA)...
if (iq.v[ii].min < cutoff) {
oq.resize(iq.s[ii].s,iq.v[ii])
v1.append(ii)
}
}
// Copy the cull cell ID numbers into the .x vector of the table
oq.x.copy(v1)
// Deallocate vectors.
dealloc(a)
return oq
}
//** chkgapcontig() -- check for occurences of places in data where
// points were removed because of closeness to soma
proc chkgapcontig () { local a,ii,jj localobj v1,v2
// Allocate vectors
a = allocvecs(v1,v2)
// Loop over all of the cells in the table...
for ii=0,wdnq.m-1 {
// print "Cell #", ii
// Loop over the 16 rows of the raw data matrix...
for jj=0,15 {
// printf("Row #%d: ", jj)
v1.resize(16)
v2.resize(16)
v1.mrow(wdnq.v[ii],jj,16) // put the jjth row in v1
v2.indvwhere(v1,"==",1e-9) // pull out indices where number = 1e-9
if (v2.size > 0) {
iscontig = v2.ismono(3) // set true if indices are consecutive
if (iscontig) {
// print "contiguous"
} else {
// print "NONCONTIGUOUS"
// if (v1.min() < -10.0) {
printf("Cell #%d, Row #%d: ",ii,jj)
vlk(v1)
// }
}
} else {
// print "no gap"
}
}
// print "------"
}
// Dealloc vectors.
dealloc(a)
}
//** lininterp() -- linear interpolation function, returning a vector
obfunc lininterp () { local val1,val2,veclen,intstep localobj vint
val1 = $1
val2 = $2
veclen = $3
vint = new Vector(veclen)
// Calculate a (positive-valued) even step.
intstep = abs(val2 - val1) / (veclen - 1)
// If 2nd value higher, do normal indgen.
if (val2 > val1) {
vint.indgen(val1,val2,intstep)
// If 1st value higher, flip value, do indgen, and flip result.
} else if (val1 > val2) {
vint.indgen(val2,val1,intstep)
vint.reverse()
// If values equal, just fill with the first value.
} else {
vint.fill(val1)
}
return vint
}
//** interpgaps() -- interpolate through the "infinity" gaps in the data
proc interpgaps () { local a,ii,jj,kk,val,infbin,srb,erb,intstp localobj v1,v2,v3
// Allocate vectors
a = allocvecs(v1,v2,v3)
// Loop over all of the cells in the table...
for ii=0,wdnq.m-1 {
// print "Cell #", ii
// Loop over the 16 rows of the raw data matrix...
for jj=0,15 {
// printf("Row #%d: ", jj)
v1.resize(16)
v2.resize(16)
v1.mrow(wdnq.v[ii],jj,16) // put the jjth row in v1
v2.indvwhere(v1,"==",1e-9) // pull out indices where number = 1e-9
// Only worry about rows where we have 1e-9...
if (v2.size > 0) {
srb = -1
erb = -1
for kk=0,v2.size-1 {
// Get the index of the inf (1e-9) bin.
infbin = v2.x(kk)
// Deal with the edge case where bin 0 is 1e-9.
// Note: if we had runs of more than 1, we'd need to deal with that.
if (infbin == 0) {
v1.x(0) = v1.x(1) // Set to the next bin
// Deal with the edge case where bin 15 is 1e-9.
// Note: if we had runs of more than 1, we'd need to deal with that.
} else if (infbin == 15) {
v1.x(15) = v1.x(14) // Set to the previous bin
// If we have not started a run of Infs yet, start a new run
} else if (srb == -1) {
srb = infbin - 1
erb = infbin + 1
// If we have started a run and the new bin contig with the run
} else if (infbin == erb) {
erb += 1
// If the next bin is not contiguous with the latest run
} else {
// Linearly interpolate for the run.
// printf("Cell #%d, Row #%d (%d to %d): ",ii,jj,srb,erb)
// printf("interp between %f and %f\n",v1.x(srb),v1.x(erb))
// vlk(v2)
v3 = lininterp(v1.x(srb),v1.x(erb),erb-srb+1)
v1.copy(v3,srb) // copy linear interpolation vector back to row
// vlk(v1)
// Start a new run.
srb = infbin - 1
erb = infbin + 1
}
// If we're at the end of the list of inf bins, and have started a
// run, output.
if ((kk == v2.size-1) && (srb != -1)) {
// Linearly interpolate for the run.
// printf("Cell #%d, Row #%d (%d to %d): ",ii,jj,srb,erb)
// printf("interp between %f and %f\n",v1.x(srb),v1.x(erb))
// vlk(v2)
v3 = lininterp(v1.x(srb),v1.x(erb),erb-srb+1)
v1.copy(v3,srb) // copy linear interpolation vector back to row
// vlk(v1)
}
}
// Put row v1 back in the NQS data (saving changes).
v1.msetrow(wdnq.v[ii],jj,16)
}
}
// print "------"
}
// Dealloc vectors.
dealloc(a)
}
//** mkhuptable() -- make a hookup NQS table from wdnq.
proc mkhuptable () { local a,ii,jj,kk,cz localobj vv1
// Allocate scratch vectors.
a = allocvecs(vv1)
// Make the NQS table.
hupnq = new NQS("srcz","destcell","destxshift","destz","wt")
// Loop over all of the depth bins...
for ii=0,numzs-1 {
// Loop over all "Gordon cells"...
for jj=0,wdnq.m-1 {
// Grab row ii, the row corresponding to the depth bin we're at.
vv1.mrow(wdnq.v[jj],ii,numgcxs) // numgcxs = 16 now
// Loop over all x bins in the row...
for kk=0,vv1.size-1 {
// If the value is less than the significant upper bound...
if (vv1.x(kk) < sigub) {
// Record the entry (source z bin, destination cell #,
// destination x shift, destination z bin (with respect to
// 7.5), weight).
cz = gcellnum2zbin(wdnq.x.x(jj)) // get the cell's z bin
hupnq.append(ii, wdnq.x.x(jj), 7.5-kk, cz, vv1.x(kk))
}
} // for kk
} // for jj
} // for ii
// Deallocate scratch vectors.
dealloc(a)
}
//** scalehupwts() -- scale the hookup table weights so they are converted
// from -pA values to sensible weight values
proc scalehupwts () { local a,ii,gvmin,gvmax,wvmin,wvmax localobj vv1
gvmin = $1
gvmax = $2
wvmin = $3
wvmax = $4
// Allocate scratch vectors.
a = allocvecs(vv1)
// Read the old Gordon cell weights.
vv1 = hupnq.getcol("wt")
// Make the weights positive.
vv1.mul(-1)
// Clip the Gordon cell weights between gvmin and gvmax.
for ii=0,vv1.size-1 {
if (vv1.x(ii) < gvmin) vv1.x(ii) = gvmin
if (vv1.x(ii) > gvmax) vv1.x(ii) = gvmax
}
// Scale between wvmin and wvmax.
vv1.scale(wvmin,wvmax)
// Set the new weights.
// hupnq.setcol("wt",vv1)
// Deallocate scratch vectors.
dealloc(a)
}
//** huptable2cellconv() -- test function for showing that huptable has
// all significant convergence info
obfunc huptable2cellconv () { local a,ii,jj localobj v1
// Allocate vectors.
a = allocvecs(v1)
// Create the new empty convergence table.
convnq = new NQS()
convnq.cp(wdnq) // copy from original table
for ii=0,convnq.m-1 { // zero out all data
convnq.v[ii].fill(0)
}
// Loop over all "Gordon" cells...
for ii=0,numgcs-1 {
// Select just the rows of the hupnq corresponding to the desired cell.
hupnq.select("destcell",wdnq.x.x(ii))
// Loop over all found rows for the desired cell...
for jj=0,hupnq.size-1 {
v1 = hupnq.getrow(jj)
// Set the convergence matrix for cell ii.
convnq.v[ii].mset(v1.x(0),int(v1.x(2)-7.5),numgcxs,v1.x(4))
} // for jj
} // for ii
// Toggle back to the full table for hupnq.
hupnq.tog
// Deallocate scratch vectors.
dealloc(a)
return convnq
}