// THIS SCRIPT FACILITATES INTERPLAY BETWEEN ANATOMICAL DATA AND COMPUTATIONAL // HANDLING OF ANATOMICAL DATA. // Some of the importing procedure can be complicated by the fact that individual // cables (as defined within NEURON) do not give a perfect one-to-one // correspondence with branches; for example, a given branch (as viewed // strictly by morphology) may be composed of several branches (ie, sections in // NEURON) each only having a single daughter. Need a way to construct an "effective" // morphology so that the statistics used for synapse placement truly reflects // the morphology, rather than the NEURON partitioning of the morphology. // First, for all neurites, construct an array of SectionLists that correspond // to effectively one branch. // // The implementation is the following: // 1. Start a given section. Extract a subtree, and identify whether the // longest arc along the subtree is sufficiently close to the whole // length of the subtree. If this is the case, keep it. objref brEff[1000] // preallocate a large number maxDistDiff = 20 // distance, in microns, to allow the max path length dist // to vary from the total length and still create an "effective" // branch. numEffBr = 0 // number of effective branches. // 050815: write a script that organises all sections into a hierarchy. This // is relevant for constructing the effective branches below; when interating // over the morphology, need to do so in a somato-centric way (ie proceeding // from parents to children) because the algorithm iterates down family trees, // and will not properly work if daughter branches are visited before parent // branches. objref orgSecList orgSecList = new SectionList() soma.sec { orgSecList.subtree() } // ORGANISE TUFT INTO EFFECTIVE SECTIONS. objref curTree,tempSecList,curSec bifThres = 5 tempSecList = new SectionList() // will contain all the sections to iterate over tempLen = 0 forsec orgSecList { curSec = new SectionRef() // Check if current section is previously added to an effective branch; // if so, break. isUsed=0 for ii=1,numEffBr{ if(sectionRefInList(curSec,brEff[ii-1])){ isUsed=1 } } if(isUsed<0.1){ // proceed down parent dendrite, appending all sections until // encounter a bifurcation with both branches > threshold. brEff[numEffBr] = new SectionList() tempSecList.append() numSecList = 1 while(numSecList>0.1){ forsec tempSecList { // remove from section list, add to branch tree curSec = new SectionRef() tempSecList.remove() brEff[numEffBr].append() // check out outstanding tree. if(curSec.nchild<0.1){ // childless, do nothing }else{ if(curSec.nchild<1.1){ // one daugheter. add. curSec.child[0] { tempSecList.append() } }else{ // two+ children. dont take if each have length > bifThres; // otherwise, add to tree and keep going... minLen = 100000 for nn=1,curSec.nchild(){ curSec.child[nn-1] { tempLen = L // if(tempLenbifThres){ // all daughters created longer than bifThres distance. // do nothing. }else{ minLen = 100000 for nn=1,curSec.nchild(){ curSec.child[nn-1] { tempLen = L tempSecList.append() } } } } } } numSecList = 0 forsec tempSecList { numSecList += 1 } } numEffBr+=1 } } //print "The number of effective branches is ",numEffBr // Implement a check to see the number of sections assigned to clusters, and // make sure it covers all sections. numInClust = 0 numInClustExpect = 0 for ii=1,numEffBr{ forsec brEff[ii-1] { numInClust = numInClust + 1 } } forall { numInClustExpect = numInClustExpect + 1 } if(abs(numInClust-numInClustExpect)>0.1){ print "The number of sections in effective branches does not equal the total number of sections. Halting." stop } // Implement a check to make sure that there is no overlap in the elements of clusters. overlapFlag=0 for ii=1,numEffBr-1{ forsec brEff[ii-1] { curSec = new SectionRef() for jj=ii+1,numEffBr{ if(sectionRefInList(curSec,brEff[jj-1])){ overlapFlag=1 } } } } if(overlapFlag){ print "There is overlap in sections found across different effective branches. Halting." stop } // Create features associated with effective branches. forall { insert eff L_eff = -1 // effective length d_eff = -1 // effective distance along length x_eff = -1 // effective x value } // create features associated with effective branches. do just lengths at this // point, as this is how things are typically processed. for nn=1,numEffBr{ lEffKeeper = 0 // effective length visitedFirst = 0 // have visited first section? forsec brEff[nn-1] { if(visitedFirst<0.1){ visitedFirst = 1 distance() for(x,0){ d_eff(x) = x*L } lEffKeeper = L // effective branch length maxDist = L }else{ for(x,0){ d_eff(x) = distance(x) } lEffKeeper += L if(distance(1)>maxDist){ maxDist = distance(1) } } } forsec brEff[nn-1] { L_eff = maxDist for(x,0){ x_eff(x) = distance(x)/maxDist } } } //// 091715: added in printing of parameters of morphologies. //print "Delete this in processMorph.hoc later" //for nn=1,numEffBr{ // print // forsec brEff[nn-1] { // print "\t",secname()," ",L_eff // } //} // function that determines whether a given sectionlist is terminal. By the // way the effective branches were created, this evaluates to whether all of // the daughter branches of the given sectionlist are also contained within // the sectionlist. // $o1: SectionList instance to examine. // OUTPUT: logical representing whether the sectionlist is termina.. func isTermEff() {local withinList localobj tempSecKeeper,theTempSec // First, iterate over all sections and extract daughters. tempSecKeeper = new SectionList() forsec $o1 { tempSecKeeper.children() } allWithinList = 1 // Next, check if every child was part of the original list. forsec tempSecKeeper { theTempSec = new SectionRef() withinList = sectionRefInList(theTempSec,$o1) if(withinList<0.1){ allWithinList=0 } } return allWithinList } // assign terminal identify for nn=1,numEffBr { forsec brEff[nn-1] { isTerm_id = isTermEff(brEff[nn-1]) } } // proofread some terminal IDs that get screened: load_file("getBranchOrder.hoc") Cell[0].dend[36] {isTerm_id=1} Cell[0].dend[37] {isTerm_id=1} assignBranchOrder(soma,0)