Signal integration in LGN cells (Briska et al 2003)

 Download zip file   Auto-launch 
Help downloading and running models
Accession:29942
Computer models were used to investigate passive properties of lateral geniculate nucleus thalamocortical cells and thalamic interneurons based on in vitro whole-cell study. Two neurons of each type were characterized physiologically and morphologically. Differences in the attenuation of propagated signals depend on both cell morphology and signal frequency. See the paper for details.
Reference:
1 . Briska AM, Uhlrich DJ, Lytton WW (2003) Computer model of passive signal integration based on whole-cell in vitro studies of rat lateral geniculate nucleus. Eur J Neurosci 17:1531-41 [PubMed]
Model Information (Click on a link to find other models with that property)
Model Type: Neuron or other electrically excitable cell;
Brain Region(s)/Organism:
Cell Type(s): Thalamus geniculate nucleus (lateral) principal neuron;
Channel(s):
Gap Junctions:
Receptor(s):
Gene(s):
Transmitter(s):
Simulation Environment: NEURON;
Model Concept(s): Influence of Dendritic Geometry;
Implementer(s): Lytton, William [billl at neurosim.downstate.edu];
Search NeuronDB for information about:  Thalamus geniculate nucleus (lateral) principal neuron;
// Created 10/09/03 08:18:39 by /usr/site/scripts/loadfiles
//================================================================
// INSERTED cells.hoc
// $Id: cells.hoc,v 1.15 2003/10/09 12:18:33 billl Exp $

// load_file("modeldb/cells.hoc")
load_file("stdgui.hoc")
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/setup.hoc
// $Id: setup.hoc,v 1.17 2003/07/23 17:44:26 billl Exp $
// variables normally controlled by SIMCTRL

// load_file("setup.hoc")

show_panel=0
proc setup () {}
strdef simname, filename, output_file, datestr, uname, comment, section, osname
objref tmpfile,nil,graphItem
tmpfile = new File()
simname = "sim"      // helpful if running multiple simulations simultaneously
runnum = 2           // updated at end of run
datestr = "99aug01"  // updated at end of day
output_file = "data/99aug01.01"  // assumes a subdir called data
comment = "current comment for saving sim"
uname = "i686"  // keep track of type of machine for byte compatibility
osname = "Linux"  // will want to grab this from env
printStep = 0.25 // time interval for saving to vector
graph_flag=1
xwindows = 1     // can still save but not look without xwindows

// load_file("nrnoc.hoc")
// END /usr/site/nrniv/local/hoc/setup.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/nrnoc.hoc
// $Id: nrnoc.hoc,v 1.58 2003/10/01 13:01:01 billl Exp $

proc nrnoc () {}

// Users should not edit nrnoc.hoc or default.hoc.  Any local 
// changes to these files should be made in local.hoc.

// key '*&*' is picked up by to indicate command for emacs
proc elisp () { printf("*&* %s\n",$s1) }
// if (not exists(simname)) { strdef simname, output_file, datestr, comment }

// Simctrl.hoc will automatically load stdgraph.hoc which automatically
// loads stdrun.hoc
strdef temp_string_, user_string_  // needed for simctrl
/* Global variable default values.  NOTE that stdrun.hoc, stdgraph.hoc
and simctrl.hoc all contain variable definitions and thus default.hoc
should be loaded after these files */
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/default.hoc
// $Id: default.hoc,v 1.5 2003/07/08 16:16:52 billl Exp $
/* This file contains various global defaults for hoc

** Users should not edit nrnoc.hoc or default.hoc.  Any local 
changes to these files should be made in local.hoc.
----------------------------------------------------------------*/

/*------------------------------------------------------------
Object defaults
------------------------------------------------------------*/

/*** Define a "nil" object ***/
objectvar nil

/*------------------------------------------------------------
String defaults
------------------------------------------------------------*/

/*** "Section" is used if errors are found in the initializiations ***/
strdef section

/*** Misc defines used by graphic routines ***/
temp_string_ = "t"
tempvar = 0

/*------------------------------------------------------------
Simulation defaults
------------------------------------------------------------*/

                        /* To be consistent w/the nmodl values */
FARADAY = 96520.        /* Hoc default = 96484.56 */
PI      = 3.14159       /* Hoc default = 3.1415927 */

                        /* 0=off, 1=on */
print_flag  = 0         /* Write to output file */
graph_flag  = 1         /* Plot output */
iv_flag     = 1         /* Using Interviews plotting */
batch_flag  = 0         /* Using batch_run() */
compress_flag = 0       /* Compress output file when saved */
stoprun     = 0         /* 0=running, 1=stopped */
iv_loaded   = 0         /* Load initial iv stuff on once */

init_seed   = 830529
run_seed    = 680612

t           = 0         /* msec */
dt          = .01       /* msec */
tstop       = 100       /* msec */
printStep   = 0.1       /* msec */
plotStep    = 0.1       /* msec */
flushStep   = 0.1       /* msec */
eventStep   = 50        /* Number of nstep's before a doEvent */

secondorder = 0

celsius     = 6.3       /* degC */

v_init      = -70       /* (mV) */
global_ra   = 200       /* (ohm-cm) specific axial resisitivity */

/*** Ion parameters ***/
ca_init     = 50e-6     /* mM */
na_init     = 10        /* mM */
k_init      = 54.4      /* mM */

// END /usr/site/nrniv/simctrl/hoc/default.hoc
//================================================================

/* Allows arrays of strings */
objref hoc_obj_[2]
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/simctrl.hoc
// $Id: simctrl.hoc,v 1.14 2000/11/27 21:59:33 billl Exp $
// Graphic routines for neuremacs simulation control

proc sim_panel () {
    xpanel(simname)
          xvarlabel(output_file)
  	xbutton("Init", "stdinit()")
  	xbutton("Init & Run", "run()")
  	xbutton("Stop", "stoprun=1")
  	xbutton("Continue till Tstop", "continueRun(tstop)")
  	xvalue("Continue till", "runStopAt", 1, "{continueRun(runStopAt) stoprun=1}", 1, 1)
  	xvalue("Continue for", "runStopIn", 1, "{continueRun(t + runStopIn) stoprun=1}", 1,1)
  	xbutton("Single Step", "steprun()")
  	xvalue("Tstop", "tstop", 1, "tstop_changed()", 0, 1)
  	graphmenu()
  	sim_menu_bar()
  	misc_menu_bar()
    xpanel()
  }

proc misc_menu_bar() {
    xmenu("Miscellaneous")
      xbutton("Label Graphs", "labelgrs()")
      xbutton("Label With String", "labelwith()")
      xbutton("Label Panel", "labelpanel()")
  	xbutton("Parameterized Function", "load_template(\"FunctionFitter\") makefitter()")
    xmenu()
  }

proc sim_menu_bar() {
    xmenu("Simulation Control")
      xbutton("File Vers", "elisp(\"sim-current-files\")")
      xbutton("File Status...", "elisp(\"sim-rcs-status\")")
      xbutton("Sim Status", "elisp(\"sim-portrait\")")
      xbutton("Load Current Files", "elisp(\"sim-load-sim\")")
      xbutton("Load Templates", "elisp(\"sim-load-templates\")") 
      xbutton("Load File...", "elisp(\"sim-load-file\")") 
      xbutton("Save Sim...", "elisp(\"sim-save-sim\")")
      xbutton("Set File Vers...", "elisp(\"sim-set-file-ver\")")
      xbutton("Read Current Vers From Index", "elisp(\"sim-read-index-file\")")
      xbutton("Read Last Saved Vers", "elisp(\"sim-read-recent-versions\")")
      xbutton("Output to sim buffer", "elisp(\"sim-direct-output\")")
    xmenu()
  }

proc labelpanel() {
    xpanel(simname,1)
  	xvarlabel(output_file)
    xpanel()
  }

proc labels () {
    labelwith($s1)
    labelgrs()
  }

proc labelgrs () { local i, j, cnt
    for j=0,n_graph_lists-1 {
        cnt = graphList[j].count() - 1
        for i=0,cnt labelgr(graphList[j].object(i))
      }
  }

proc labelwith () { local i, j, cnt
    temp_string_ = user_string_  // save the old one
    if (numarg() == 1) { /* interactive mode */  
        user_string_ = $s1
      } else {
        string_dialog("write what?", user_string_)
      }
    for j=0,n_graph_lists-1 {
        cnt = graphList[j].count() - 1
        for i=0,cnt {
            graphList[j].object(i).color(0)
            graphList[j].object(i).label(0.5,0.9,temp_string_)
            graphList[j].object(i).color(1)
            graphList[j].object(i).label(0.5,0.9,user_string_)
          }
      }
  }

proc labelgr () { local i
    $o1.color(0)  // white overwrite
    for (i=0;i<10;i=i+1) { // erase every possible runnum for this date
        sprint(temp_string_,"%s %d%d",datestr,i,i)
        $o1.label(0.1,0.7,temp_string_) }
    $o1.color(1) // back to basic black
    sprint(temp_string_,"%s %02d",datestr,runnum)
    $o1.label(0.1,0.7,temp_string_)
  }

// END /usr/site/nrniv/simctrl/hoc/simctrl.hoc
//================================================================

proc run () {
  
    stdinit()
  
    if (batch_flag == 1) {
        cvode.solve(tstop)
      } else {
        continueRun(tstop)
      }
    finish()
  }

proc continueRun () { local eventCount
    eventCount=0
    eventslow=1
    stoprun = 0
  
    if (cvode_active()) cvode.event($1)
  
    while (t < tstop && stoprun == 0) { 
        advance()
        outputData()
        if (graph_flag) { fastflushPlot() doEvents() }
      }
  }

proc advance () { fadvance() }

proc stdinit() {
    realtime=0 startsw()
    t = 0
    stoprun = 0
  
    if (batch_flag == 1) {
      }
  
    init()
  
    if (graph_flag == 1) { 
        if (iv_flag == 1) {
            initPlot()
          } else {
            initGraph() 
          }
      }
  
    if (print_flag == 1) { initPrint() }
  }


proc init () {
    initMech()
    initMisc1()
  
    // Initialize state vars then calculate currents
    // If user hand-set v in initMisc1() then v_init should be > 1000,
    // else all compartments will be set to v_init
    if (v_init < 1000) {
        finitialize(v_init)
      } else {
        finitialize()
      }
    fcurrent()
  
    // Set ca pump and leak channel for steady state
    setMemb()
  
    // Recalculate currents with new pump and leak kinetics
    fcurrent()
    fcurrent()
  
    initMisc2()
    if (cvode_active()) cvode.re_init()
  }

// Initialization of mechanism variables
// NOTE: if any changes are made to the NEURON block of any local mod
// file, the user must add the necessary inits to initMisc1()
proc initMech () { 
    forall {
        if ((!ismembrane("pas")) && (!ismembrane("Passive"))) { 
            // Allow for either pas or Passive mod file usage
            // errorMsg("passive not inserted") 
          }
    
        if (ismembrane("na_ion")) { 
            nai = na_init
            nai0_na_ion = na_init
          }
        
        if (ismembrane("k_ion")) {
            ki = k_init
            ki0_k_ion = k_init
          }
        
        if (ismembrane("ca_ion")) { 
            cai = ca_init
            cai0_ca_ion = ca_init
          }
      }
  }

//* setMemb complex -- multiple names for passive mech
//** declarations
iterator scase() { local i
    for i = 1, numarg() { temp_string_ = $si iterator_statement }}
objref paslist,pasvars[3],XO
double pasvals[2],x[1]
paslist = new List()
for ii=0,2 pasvars[ii]= new String()
for scase("pas","Pass","Passive") paslist.append(new String(temp_string_))

//** getval(),setval() -- return/set the hoc value of a string
func retval () { return getval($s1) }
func getval () { 
    sprint(temp_string2_,"x=%s",$s1)
    execute(temp_string2_)
    return x
  }
proc setval () { 
    sprint(temp_string2_,"%s=%g",$s1,$2)
    execute(temp_string2_)
  }

//** findpas()
// assumes that we are starting in a live section since looks for pass mech there
qx_=0
proc findpas () {
    for ii=0,paslist.count-1 {
        XO=paslist.object(ii)
        if (ismembrane(XO.s)) {
            // print XO.s,"found"
            pasvars[2].s=XO.s
            sprint(pasvars[0].s,"g_%s(qx_)",XO.s)
            for scase("e","erev","XXXX") {  // look for the proper prefix
                sprint(temp_string_,"%s_%s",temp_string_,XO.s)
                if (name_declared(temp_string_)==1) break
              }
            if (name_declared(temp_string_)==0) { // not found
                printf("SetMemb() in nrnoc.hoc: Can't find proper 'erev' prefix for %s\n",XO.s)
              } else {
                sprint(pasvars[1].s,"%s(qx_)",temp_string_)
              }
          }
      }
  }

proc setMemb () {
    findpas() // assume that passive name is the same in all sections
    forall for (qx_) {  // will eventually want 'for (x)' to handle all the segments
        if (ismembrane(pasvars[2].s)) {
              for ii=0,1 pasvals[ii]=getval(pasvars[ii].s)
              setmemb2()
              for ii=0,1 setval(pasvars[ii].s,pasvals[ii])
          }
      }
  }

func setother () {return 0} // callback stub
proc setmemb2 () { local iSum, ii, epas, gpas
    gpas=pasvals[0] epas=pasvals[1]
    // Setup steady state voltage using leak channel
    iSum = 0.0
    if (ismembrane("na_ion")) { iSum += ina(qx_) }
    if (ismembrane("k_ion"))  { iSum += ik(qx_)  }
    if (ismembrane("ca_ion")) { iSum += ica(qx_) }
    iSum += setother()
    // print iSum
  
    if (iSum == 0) {        // Passive cmp so set e_pas = v
        epas = v
      } else {
        if (gpas > 0) {    // Assume g set by user, calc e
            epas = v + iSum/gpas
      
          } else {            // Assume e set by user, calc g
            if (epas != v) {
                gpas = iSum/(epas - v)
              } else { gpas=0 }
          }
        if (gpas < 0) errorMsg("bad g", gpas)
        if (epas < -100 || epas > 0) {
            printf(".")
            // printf("%s erev: %g %g %g\n",secname(),e_pas,ina,ik)
          }
      }
    pasvals[0]=gpas pasvals[1]=epas
  }

proc finish() {
    /* Called following completion of continueRun() */
  
  finishMisc()
  
  if (graph_flag == 1) {
      if (iv_flag == 1) {
          flushPlot()
          doEvents()
        } else {
          graphmode(-1)
          plt(-1)
        }
    }
  
  if (print_flag == 1) {
      wopen("")
    }
  }

/*------------------------------------------------------------
User definable GRAPHICS and PRINTING routines
------------------------------------------------------------*/

proc outputData() {
    // Default procedure - if outputData() doesn't exist in the run file
  
    if (graph_flag == 1) {
        if (iv_flag == 1) {
            Plot()
            rt = stopsw()
            if (rt > realtime) {
                realtime = rt
                fastflushPlot()
                doNotify()
                if (realtime == 2 && eventcount > 50) {
                    eventslow = int(eventcount/50) + 1
                  }
                eventcount = 0
              }else{
                eventcount = eventcount + 1
                if ((eventcount%eventslow) == 0) {
                    doEvents()
                  }
              }
      
          } else {
            graph(t)
          }
      }
  
    if (print_flag == 1) { 
        if (t%printStep <= printStep) { printOut() }
      }
  }

proc printOut() {
    /* Default procedure - if printOut() doesn't exist in the run file */
  }

proc initGraph() {
    /* Default procedure - if initGraph() doesn't exist in the run file */
  
  graph()
  }

proc initPrint() {
    /* Default procedure - if initPrint() doesn't exist in the run file */
  
  wopen(output_file)
  }

/*------------------------------------------------------------
User definable BATCH RUN routines
------------------------------------------------------------*/

proc nextrun() {
    // Called from finishmisc() following completion of batch in an autorun
    wopen("")   
    runnum = runnum + 1
    sprint(output_file,"data/b%s.%02d", datestr, runnum)
  }                       

// commands for emacs
proc update_runnum() { 
    runnum = $1
    sprint(output_file,"data/%s.%02d", datestr, runnum)
    print "^&^ (progn (sim-index-revert)(setq sim-runnum ",runnum,"))" }
proc nrn_write_index() { printf("&INDEX& %s\n",$s1) }
proc nrn_update () { elisp("nrn-update") }
proc nrn_message () { printf("!&! %s\n",$s1) } 

/*------------------------------------------------------------
User definable INITIALIZATION and FINISH routines
------------------------------------------------------------*/

// Default procedure - if initMisc1() doesn't exist in the run file 
// Initializations performed prior to finitialize() 
// This should contain point process inits and inits for any changes 
//        made to the NEURON block of any local mod file 
proc initMisc1() { }

// Default procedure - if initMisc2() doesn't exist in the run file 
// Initializations performed after finitialize() 
proc initMisc2() { }

// Default procedure - if finishMisc() doesn't exist in the run file 
proc finishMisc() { }

/*------------------------------------------------------------
Miscellaneous routines
------------------------------------------------------------*/

proc errorMsg() {
    /* Print warning, assumes arg1 is string and arg2 if present is a
    variable value */
  
  sectionname(section)
  
  if (numarg() == 0) {
      printf("ERROR in errorMsg(): Needs at least 1 argument.\n")
    } else if (numarg() == 1) {
      printf("ERROR: %s in section %s.\n", $s1, section)
    } else {
      printf("ERROR: %s in section %s (var=%g).\n", $s1, section, $2)
    }
  }

proc clear() {
    /* Clear non-interviews plot window */
  plt(-3)
  }

func mod() { local x, y
    /* Mod function for non-integers */
  
  x=$1
  y=$2
  
  return (x/y - int(x/y))
  }

proc whatSection() { print secname() }

proc print_pp_location() { local x //arg1 must be a point process
     x = $o1.get_loc()
     sectionname(temp_string_)
     printf("%s located at %s(%g)\n", $o1, temp_string_, x)
     pop_section()
  }

//* set method with method()
proc method () {
    if (strcmp($s1,"global")==0) {
        cvode_active(1)
      } else if (strcmp($s1,"local")==0) {
        cvode_local(1)
      } else if (strcmp($s1,"implicit")==0) {
        secondorder=0
        cvode_active(0)
      } else if (strcmp($s1,"CN")==0) {
        secondorder=2
        cvode_active(1) // this turns off local
        cvode_active(0)
      } else {
        printf("Integration method %s not recognized\n",$s1)
      }
  }

//* Load local modifications to nrnoc.hoc and default.hoc
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/local.hoc
//  $Header: /usr/site/nrniv/simctrl/hoc/RCS/local.hoc,v 1.15 2003/02/13 15:32:06 billl Exp $
//
//  This file contains local modifications to nrnoc.hoc and default.hoc
//
//  Users should not edit nrnoc.hoc or default.hoc.  Any local 
//  changes to these files should be made in this file.

// ------------------------------------------------------------
//* MODIFICATIONS TO NRNOC.HOC
// The procedures declared here will overwrite any duplicate
// procedures in nrnoc.hoc.
// ------------------------------------------------------------

//*MODIFICATIONS TO DEFAULT.HOC
//
// Vars added here may not be handled properly within nrnoc.hoc
//------------------------------------------------------------

//** String defaults

//** Simulation defaults

long_dt     = .001      // msec 

objref sfunc,tmpfile
sfunc = hoc_sf_   // needed to use is_name()
tmpfile = new File()  // check for existence before opening a user's local.hoc file

proc write_comment () {
    tmpfile.aopen("index")
    tmpfile.printf("%s\n",$s1)
    tmpfile.close()  
  }

func asin () { return atan($1/sqrt(1-$1*$1)) }
func acos () { return atan(sqrt(1-$1*$1)/$1) }

objref mt[2]
mt = new MechanismType(0)
proc uninsert_all () { local ii
    forall for ii=0,mt.count()-1 {
        mt.select(ii)
        mt.selected(temp_string_)
        if (strcmp(temp_string_,"morphology")==0) continue
        if (strcmp(temp_string_,"capacitance")==0) continue
        if (strcmp(temp_string_,"extracellular")==0) continue
        if (sfunc.substr(temp_string_,"_ion")!=-1) continue
        mt.remove()
        // print ii,temp_string_
      }
  }

condor_run = 0  // define for compatability
// END /usr/site/nrniv/simctrl/hoc/local.hoc
//================================================================

if (xwindows && graph_flag) { nrnmainmenu() } // pwman_place(50,50)

print "Init complete.\n"
// END /usr/site/nrniv/simctrl/hoc/nrnoc.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/grvec.hoc
// $Id: grvec.hoc,v 1.337 2003/09/27 14:35:27 billl Exp $

// 0 -> double, ie $1
// 1 -> object, ie $o1
// 2 -> string, ie $s1
// 3 -> address,ie $&1

// main panel is 'vecpanel()'
proc grvec () {}
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/declist.hoc
// $Id: declist.hoc,v 1.51 2003/10/08 17:51:45 billl Exp $

strdef mchnms
objref tmplist,tmplist2,tmpobj,stack,SO,aa
tmplist = new List()
stack = new List()
proc declist() {}

//* Declarations

begintemplate String2
public s,t,append,prepend,exec
strdef s,t
proc init() {
    if (numarg() == 1) { s=$s1 }
    if (numarg() == 2) { s=$s1 t=$s2 }
  }
proc append () { local i
    if (argtype(1)==2) sprint(t,"%s%s",s,$s1)
    for i=2,numarg() sprint(t,"%s%s",t,$si)
  }
proc prepend () { local i
    if (argtype(1)==2) sprint(t,"%s%s",$s1,s)
    for i=2,numarg() sprint(t,"%s%s",$si,t)
  }
proc exec () {
    if (numarg()==1) sprint(t,"%s%s",$s1,s)
    execute(t)
  }
endtemplate String2

//* SNO: generic template to store strings numbers and objects
begintemplate SNO
public s,t,u,n,o,set
public ov,ol,set,get,pr,init
strdef s,t,u,tstr
objref o[3],this
double n[3]

proc init() {
    if (numarg() >= 2) {s=$s1 n[0]=$2}
    if (numarg() >= 4) {t=$s3 n[1]=$4}
    if (numarg() == 6) {u=$s5 n[2]=$6}
  }

proc ov () { local a,sz
    if (numarg()>=1) a=$1 else a=0
    if (numarg()==1) sz=$2 else sz=100
    o[a]=new Vector(sz)
  }
proc ol () { 
    if (numarg()==1) a=$1 else a=0
    o[a]=new List() 
  }
proc set () { local ii
    if (numarg()==1) ii=$1 else ii=0
    if (ii==0) tstr=s else if (ii==1) tstr=t else if (ii==2) tstr=u else {
        printf("ERROR: only 3 items in SNO: %s\n",this) return } 
    sprint(tstr,"%s = %s.n[%d]",tstr,this,ii)
    execute(tstr)
  }
proc get () { local ii
    if (numarg()==1) ii=$1 else ii=0
    if (ii==0) {
        sprint(tstr,"%s.n[%d] = %s",this,ii,this.s)
      } else   if (ii==1) {
        sprint(tstr,"%s.n[%d] = %s",this,ii,this.t)
      } else   if (ii==2) {
        sprint(tstr,"%s.n[%d] = %s",this,ii,this.u)
      } else { printf("ERROR: only 3 items in SNO: %s\n",this) return } 
    execute(tstr)
  }
proc pr () { local ii
    if (numarg()==1) ii=$1 else ii=0
    if (ii==0) {
        sprint(tstr,"print %s.s,\" \",%s,\" \",%s.n[%d]",this,s,this,ii)
      } else   if (ii==1) {
        sprint(tstr,"print %s.t,\" \",%s,\" \",%s.n[%d]",this,t,this,ii)
      } else   if (ii==2) {
        sprint(tstr,"print %s.u,\" \",%s,\" \",%s.n[%d]",this,u,this,ii)
      } else { printf("ERROR: only 3 items in SNO: %s\n",this) return } 
    execute(tstr)
  }
endtemplate SNO

//* list iterator ltr
// usage 'for ltr(tmplist) { print XO }' :: 1 arg, assumes XO as dummy
// usage 'for ltr(YO, tmplist) { print YO }' 2 arg, specify dummy
// usage 'for ltr(XO, tmplist, &x) { print XO,x }' :: 3 args, define counter (else i1 default)
//                                                 :: note that x, i1 must be defined
iterator ltr () { local i
    if (numarg()==3) {$&3=0} else {i1 = 0}
    if (numarg()==1) {
        for i = 0, $o1.count() - 1 {
            XO = $o1.object(i)
            iterator_statement
            i1+=1
          }
        tmpobj=$o1
      } else {
        for i = 0, $o2.count() - 1 {
            $o1 = $o2.object(i)
            iterator_statement
            if (numarg()==3) { $&3+=1 } else { i1+=1 }
          }
        tmpobj=$o2
        $o1 = nil
      }
  }

// lswap(list,#1,#2) swap items on a list
proc lswap () { local a,b
    if ($2<$3) {a=$2 b=$3} else {a=$3 b=$2}
    $o1.insrt(a,$o1.object(b))
    $o1.remove(b+1)
    $o1.insrt(b+1,$o1.object(a+1))
    $o1.remove(a+1)
  }

// proc shl() show a list
proc shl () { 
    if (numarg()==1) tmpobj=$o1 else tmpobj=tmplist 
    if (tmpobj.count==0) return
    if (isstring(tmpobj.object(0),tstr)) {
        for ltr(XO,tmpobj) print XO.s
      } else for ltr(XO,tmpobj) print XO
  }
// lfu() = ltr follow-up, pick out a single item from the last ltr request
// lfu(list,num[,obj])
proc lfu () { 
    if (numarg()==1) { 
        if (argtype(1)==0) XO=tmpobj.object($1)
        if (argtype(1)==1) tmpobj=$o1
      }
    if (numarg()==2) {
        if (argtype(1)==1 && argtype(2)==0) {tmpobj=$o1 XO=$o1.object($2)}
        if (argtype(1)==0 && argtype(2)==1) {$o2=tmpobj.object($1)}
      }
    if (numarg()==3) {
        if (argtype(1)==1 && argtype(2)==0 && argtype(3)==1) { tmpobj=$o1 $o3=$o1.object($2) }
      }
    if (numarg()==4) {
        $o2=tmpobj.object($1)  $o4=tmpobj.object($3) 
      }
  }
  
//* list iterator ltr2
// usage 'for ltr2(XO, YO, list1, list2) { print XO,YO }'
iterator ltr2() { local i
    if (numarg()==5) $&5=0 else i1=0
    if ($o3.count != $o4.count) { print "ltr2 ERROR: lists have different lengths" return }
    for i = 0, $o3.count() - 1 {
        $o1 = $o3.object(i)
        $o2 = $o4.object(i)
        iterator_statement
        if (numarg()==5) { $&5+=1 } else { i1+=1 }
      }
    $o1=nil $o2=nil
  }

//* list pairwise iterator ltrp
// usage 'for ltrp(XO, YO, list) { print XO,YO }' takes them pairwise
iterator ltrp() { local i
    if (numarg()==4) {$&4=0} else {i1 = 0}
    for (i=0;i<$o3.count()-1;i+=2) {
        $o1 = $o3.object(i) $o2 = $o3.object(i+1)
        iterator_statement
        if (numarg()==4) { $&4+=1 } else { i1+=1 }
      }
    $o1=nil $o2=nil
  }

//* list iterator sltr
// usage 'for sltr(XO, string) { print XO }'
iterator sltr() { local i
    tmplist = new List($s2)
    if (numarg()==3) {$&3=0} else {i1=0}
    for i = 0, tmplist.count() - 1 {
        $o1 = tmplist.object(i)
        iterator_statement
        if (numarg()==3) { $&3+=1 } else { i1+=1 }
      }
    $o1 = nil
  }

//* listedit() allows you to remove things by clicking
proc listedit () {
    if (numarg()==0) { print "listedit(list,str) gives browser(list,str) for removing items" return}
    if (numarg()==1) {
      if (! isstring($o1.object(0),temp_string_)) {print "Give name for string of object?" return }
        sprint(temp_string_,"proc ledt1 () {sprint(temp_string_,%s,hoc_ac_,%s.object(hoc_ac_).%s)}","\"%d:%s\"",$o1,"s")
      } else {
        sprint(temp_string_,"proc ledt1 () {sprint(temp_string_,%s,hoc_ac_,%s.object(hoc_ac_).%s)}","\"%d:%s\"",$o1,$s2)
      }
    execute1(temp_string_)
    $o1.browser("Double click on item to remove",temp_string_,"ledt1()")
    sprint(temp_string_,"%s.remove(hoc_ac_)",$o1)
    $o1.accept_action(temp_string_)
  }


//* listXO() connects stuff to XO from a list
proc listXO () {
    if (numarg()==1) {
        $o1.browser("Double click")
        sprint(temp_string_,"print hoc_ac_,\":XO -> \",%s.object(hoc_ac_) XO = %s.object(hoc_ac_)",$o1,$o1)
        $o1.accept_action(temp_string_)
      } else if (numarg()==2) {
        $o1.browser($s2)
        sprint(temp_string_,"XO = %s.object(hoc_ac_) print %s.object(hoc_ac_).%s",$o1,$o1,$s2)
        $o1.accept_action(temp_string_)
      } else if (numarg()==3) {
        $o1.browser($s2)
        sprint(temp_string_,"XO = %s.object(hoc_ac_) print %s.object(hoc_ac_).%s,%s.object(hoc_ac_).%s",$o1,$o1,$s2,$o1,$s3)
        $o1.accept_action(temp_string_)
      }
  }

//* lcatstr(list,s1,s2,...) make new List("s1") new List("s2") ... in one list
proc lcatstr() { local i
    if (numarg()<3) { print "lcatstr(l1,s1,s2,...) puts new Lists into l1" return }
    $o1 = new List($s2)
    for i=3,numarg() {
        tmplist2 = new List($si)
        for ltr(XO,tmplist2) { $o1.append(XO) }  
      }
  }

//* sublist() places a sublist in LIST0 from LIST1 index BEGIN to END inclusive
proc sublist () { local ii
    $o1.remove_all
    for ii=$3,$4 {
        $o1.append($o2.object(ii))
      }
  }

//* catlist() concats LIST2...LISTN on end of LIST1
proc catlist () { local i
    for i = 2, numarg() {
        for ltr(YO,$oi) {
            $o1.append(YO)
          }
      }
  }  

//* mechlist() creates a LIST of all this CELL type's TEMPLATE type
// list, cell, template
// make a list of mechanisms belonging to a certain template
proc mechlist () { local num,ii
  //  mchnms = ""  // not a good storage since runs out of room
    if (numarg()==0) { print "mechlist(list, cell, template)" return}
    $o1 = new List($s2)
    num = $o1.count
    for ii=0,num-1 {
        sprint(temp_string_,"%s.append(%s.%s)",$o1,$o1.object(ii),$s3)
        execute(temp_string_)
        sprint(mchnms,"%s/%d/%s.%s",mchnms,ii,$o1.object(ii),$s3)
      }
    for (ii=num-1;ii>=0;ii=ii-1) { $o1.remove(ii) }
  }

//* lp() loop through a list running command in object's context
// assumes list in tmplist
// with 1 args run $o1.object().obj_elem
// with 2 args run comm($o1.object().obj_elem)
proc lp () {
    for ii=0,tmplist.count-1 {
        printf("%s ",tmplist.object(ii))
        if (numarg()==2) {
            sprint(temp_string_,"%s(%s.%s)",$s2,tmplist.object(ii),$s1)
          } else {
            sprint(temp_string_,"%s.%s",tmplist.object(ii),$s1)
          }
        execute(temp_string_)
      }
  }

//* prlp() loop through a list printing object name and result of command
proc prlp () {
    for ii=0,tmplist.count-1 {
        printf("%s ",tmplist.object(ii))
        if (numarg()==1) {
            sprint(temp_string_,"print %s.%s",tmplist.object(ii),$s1)
            execute(temp_string_)
          } else { print "" }
      }
  }

//** repl_str(str,stra,strb,scratch): replace stra with strb in string
// will only replace first string match
proc repl_str() {
    if (sfunc.substr($s1,$s2) == -1) { print $s2," not in ",$s1  return }
    sfunc.tail($s1,$s2,$s4)
    sprint($s4,"%s%s",$s3,$s4)
    sfunc.head($s1,$s2,$s1)
    sprint($s1,"%s%s",$s1,$s4)
  }

proc aaaa () { local flag
    if (numarg()==2) { tmpfile.ropen($s1) aa=$o2 flag=0
      } else if (numarg()==1) { tmpfile.ropen($s1) flag=1
      } else { tmpfile.ropen("aa") flag=1 }
    if (flag==1) if (isobj(aa,"List")) { aa.remove_all() } else { aa=new List() }
    while (tmpfile.gets(temp_string_)>0) {
        chop(temp_string_)
        tmpobj=new String(temp_string_)
        aa.append(tmpobj)
      }
    tmpobj=nil
  }

//* var2obj() and canobj() -- find true object names
// var2obj("tstr"[,"objvar"]) replaces variable name with actual name of the object
// default into XO; optional second arg allows to place somewhere else
// eg tstr="TC[0].ampa" var2obj(tstr) -> AMPA[0]
proc var2obj () { local flag
    if (numarg()==1) flag=1 else flag=0
    if (flag) sprint($s1,"XO=%s",$s1) else sprint($s1,"%s=%s",$s2,$s1)
    execute($s1) // change variable name to object name
    if (flag) sprint($s1,"%s",XO) else sprint($s1,"%s",$s2)
  }

//** objnum(OBJ) -- find object number
func objnum () {
    sprint(temp_string_,"%s",$o1)
    if (sscanf(temp_string_,"%*[^[][%d]",&x) != 1) x=-1
    return x
  }

//** canobj(obj[,"OBJVAR"]) -- default will assign to XO
// canonical object -- return canonical identity for an object
// eg canobj(tc,"YO") -- figure out what tc is and assign it to YO
proc canobj () { local flag
    if (numarg()==1) flag=1 else flag=0
    if (flag) sprint(tstr,"XO=%s",$o1) else sprint(tstr,"%s=%s",$s2,$o1)
    execute(tstr) // change variable name to object name
    sprint(tstr,"%s",$o1)
  }

//* push() and pop() for objects -- returns
proc push () { local i
    for i=1,numarg() stack.append($oi)
  }

proc pop () { local i
    if ((numarg()>0 && stack.count<numarg()) || stack.count==0) {
        print "ERR: stack underflow" return
      } 
    if (numarg()>=1) {
        for i=1,numarg() {
            $oi=stack.object(stack.count-1)
            stack.remove(stack.count-1) 
          }
      } else { 
        SO=stack.object(stack.count-1) 
        stack.remove(stack.count-1) 
      }
  }

proc time () { local tti
    prtime()
    if (numarg()==1) execute1($s1) else execute1("run()")
    tti=prtime()
    if (tti<60) print tti,"s" else print tti/60,"m"
  }
// END /usr/site/nrniv/local/hoc/declist.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/decvec.hoc
// $Id: decvec.hoc,v 1.118 2003/10/08 17:46:54 billl Exp $

proc decvec() {}

//* Declarations
objref ind, tvec, vec, vec0, vec1, tmpvec, vrtmp, veclist, veccollect
objref tmpobj, XO, YO, rdm, dir
dir = new List()
print "Loading decvec"

{ MSONUM=100 MSOSIZ=100 msomax=0 msoptr=0 objref mso[MSONUM] }
double x[4],y[4]
xx=0 // declare a scalar 
ind = new Vector(100)
tvec = new Vector(100)
vec = new Vector(100)
vec0 = new Vector()
vec1 = new Vector()
vrtmp = new Vector()
veclist = new List()
veccollect = new List()
rdm = new Random()

if (!(xwindows && name_declared("xwindows"))) {
    xwindows=0
    objref graphItem
    strdef temp_string_, temp_string2_
  }
strdef xtmp,space
if (wopen("xtmp")) xtmp = "xtmp" else xtmp="/tmp/xtmp"  // scratch file to save system output to

//* stuff that doesn't belong here
//** dired(list,file) - put together list of files matching 'file', calls 'ls -1 file'
//   dired(list,file,1) file name to read for list of files
proc dired () {
    if (numarg()==0) { print "dired(list,filename) adds the filename to list (use wildcards)"
        return }
    if (numarg()==3) { 
        tmpfile.ropen($s2)
      } else {
        sprint(temp_string_,"ls -1R %s > %s",$s2,xtmp) // list in order of creation time
        system(temp_string_)
        tmpfile.ropen(xtmp)
      }
    while (tmpfile.scanstr(temp_string_) != -1) {
        tmpobj=new String()
        tmpobj.s=temp_string_
        $o1.append(tmpobj)
        tmpfile.gets(temp_string_)  // get rid of the rest of the line
      }
  }

//** lbrw(list,action) is used to put up a browser
// note action given without '()'
proc lbrw () {
    $o1.browser($s2,"s")
    sprint($s2,"%s()",$s2)
    $o1.accept_action($s2)
  }

//** l2v(S1,S2) makes a list(S1) and puts all the XO.S2 into vec
// eg l2v("IClamp","amp")
proc l2v () {
    tmpobj=new List($s1)
    if (numarg()==3) YO=$o3 else YO=vec
    YO.resize(tmpobj.count) YO.resize(0)
    for ltr(tmpobj) {
        sprint(tstr,"YO.append(%s.%s)",XO,$s2)
        execute(tstr)
      }
  }

//* vector iterator vtr
// usage 'for vtr(&x, vec) { print x }'
iterator vtr() { local i
    if (numarg()==3) {$&3=0} else {i1 = 0}
    if (numarg()==1) {
        for i = 0,$o1.size()-1 {  
            x  = $o1.x[i]  
            iterator_statement 
            i1+=1
          }
      } else {
        for i = 0,$o2.size()-1 { 
            $&1 = $o2.x[i]  
            iterator_statement 
            if (numarg()==3) { $&3+=1 } else { i1+=1 }
          }
      }
  }

//* vector iterator vtr2, treat two vectors as pairs
// usage 'for vtr2(&x, &y, vec1, vec2) { print x,y }'
iterator vtr2() { local i,pairwise,noi1
    noi1=pairwise=0
    if (numarg()==3) { pairwise=1 i1=0 }
    if (numarg()==4) if (argtype(4)==3) { pairwise=1 $&4=0 noi1=1}
    if (pairwise) if ($o3.size%2!=0) { print "vtr2 ERROR: vec not even sized." return }
    if (! pairwise) {
        if ($o3.size != $o4.size) { print "vtr2 ERROR: sizes differ." return }
        if (numarg()==5) {$&5=0 noi1=1} else {i1 = 0}
      }
    for i = 0,$o3.size()-1 {
        $&1 = $o3.x[i]
        if (pairwise) $&2=$o3.x[i+=1] else $&2=$o4.x[i]
        iterator_statement
        if (noi1) { if (pairwise) $&4+=1 else $&5+=1 } else i1+=1
      }
  }

//* iterator lvtr, step through a list and a vector together
// usage 'for lvtr(XO, &x, list, vec) { print XO,x }'
iterator lvtr() { local i
    if ($o3.count <  $o4.size) { printf("lvtr ERROR: vecsize > listsize: list %d,vec %d.\n",$o3.count,$o4.size) return }
    if ($o3.count != $o4.size) { printf("lvtr WARNING: sizes differ: list %d,vec %d.\n",$o3.count,$o4.size) }
    if (numarg()==5) {$&5=0} else {i1 = 0}
    for i = 0, $o4.size()-1 {
        $o1 = $o3.object(i)
        $&2 = $o4.x[i]
        iterator_statement
        if (numarg()==5) { $&5+=1 } else { i1+=1 }
      }
  }

//* other iterators: case, scase, ocase
iterator case() { local i
    i1 = 0
    for i = 2, numarg() {
        $&1 = $i
        iterator_statement
        i1+=1
      }
  }

iterator scase() { local i
    i1 = 0
    for i = 1, numarg() {
        temp_string_ = $si
        iterator_statement
        i1+=1
      }
  }

// eg for scase2("a","b","c","d","e","f") print tmpobj.s,tmpobj.t
iterator scase2() { local i
    i1 = 0
    if (numarg()%2==1) {print "ERROR: scase2 needs even number of args" return }
    for i = 1, numarg() {
        tmpobj=new String2()
        tmpobj.s=$si i+=1  tmpobj.t=$si
        iterator_statement
        i1+=1
      }
  }

iterator ocase() { local i
    i1 = 0
    for i = 1, numarg() {
        XO = $oi
        iterator_statement
      }
    i1+=1
  }

//* strm(STR,REGEXP) == regexp string match 
func strm () { return sfunc.head($s1,$s2,"")!=-1 }

//* nind(targ,data,ind) fill the target vector with data NOT index by ind (opposite of v.index)
proc nind () { 
    if (! eqobj($o1,$o2)) $o1.copy($o2)
    $o1.indset($o3,-1e20)
    $o1.where($o1,">",-1e20)
  }

//* vlk(vec)
// vlk(vec,max)
// vlk(vec,min,max)
// prints out a segment of a vector
vlk_width=20
space=" "
proc vlk () { local i,j,min,max,dual,wdh,nonl
    j=dual=0 nl=1 wdh=vlk_width
    if (numarg()==1) { min=0 max=$o1.size-1 }
    if (numarg()==2) {
        if (argtype(2)==0) {
            if ($2==0) { 
                nl=min=0 max=$o1.size-1 // vlk(vec,0) flag to suppress new lines
              } else if ($2>0) { min=0 max=$2-1 } else { min=$o1.size+$2 max=$o1.size-1 }
          } else { dual=1 min=0 max=$o1.size-1 }
      }
    if (numarg()==3) {
        if (argtype(2)==0) if ($3>-1) { min=$2 max=$3 }
        if (argtype(2)==1) { dual=1
            if ($3>=0) { min=0 max=$3 } else { min=$o1.size+$3 max=$o1.size-1 }
          }
      }
    if (numarg()==4) { min=$3 max=$4 dual=1 }
    if (min<0) min=0
    if (max>$o1.size-1) { max=$o1.size-1 printf("vlk: max beyond $o1 size\n") }
    if (dual) if (max>$o2.size-1) { max=$o2.size-1 printf("vlk: max beyond $o2 size\n") }
    for i=min,max { 
        if (dual) printf("%g:%g%s",$o1.x[i],$o2.x[i],"\n") else printf("%g%s",$o1.x[i],space)
        if ((j=j+1)%vlk_width==0 && nl && strcmp(space," ")==0) { print "" }
      }
    if (nl) print ""
  }

//* vprf() prints 1,2 or 3 vectors in parallel to output file
proc vprf () { local x2
    if (! tmpfile.isopen()) {
        print "Writing to temp file 'temp'"
        tmpfile.wopen("temp")
      }
    if (numarg()==1) { 
        for vtr(&x,$o1) { tmpfile.printf("%g\n",x) }
      } else if (numarg()==2) { 
        for vtr2(&x,&y,$o1,$o2) { tmpfile.printf("%g %g\n",x,y) }
      } else if (numarg()==3) { 
        for vtr2(&x,&y,$o1,$o2,&ii) { x2=$o3.x[ii] tmpfile.printf("%g %g %g\n",x,y,x2) }
      }
    tmpfile.close
  }

//* vpr() prints 1,2 or 3 vectors in parallel to STDOUT
proc vpr () { local x2
    if (numarg()==1) { 
        for vtr(&x,$o1) { printf("%g ",x) }
      } else if (numarg()==2) { 
        for vtr2(&x,&y,$o1,$o2) { printf("%g:%g ",x,y) }
      } else if (numarg()==3) { 
        for vtr2(&x,&y,$o1,$o2,&ii) { x2=$o3.x[ii] printf("%g:%g:%g ",x,y,x2) }
      }
    print ""
  }

//* readvec(vec) read from line
proc readvec () { 
    $o1.resize(0)
    while (read(xx)) $o1.append(xx)
    vlk($o1)
  }
  
//* popvec(), savenums, readnums, vecsprint, savevec, savestr
proc pushvec () { local i // same as .append, retained for compatability
    for i=2, numarg() $o1.append($i)
  }

proc insvec () { local i // insert a value into the vector
    for i=2, numarg() $o1.append($i)
  }

proc revec () { local i // clear vector then append
    if (! isobj($o1,"Vector")) $o1 = new Vector()
    $o1.resize(0)
    if (numarg()>1) if (argtype(2)==1) { 
        for i=2, numarg() $oi.resize(0) 
      } else {
        for i=2, numarg() $o1.append($i)
      }
  }

// vrsz() -- vector resize -- to size of first arg
proc vrsz () { local i,sz
    if (argtype(1)==1) sz=$o1.size else sz=$1
    for i=2, numarg() $oi.resize(sz) 
  }

proc zvec () { local i // make vectors zero size
    for i=1, numarg() $oi.resize(0)
  }

// savenums(x[,y,...]) save numbers to tmpfile via a vector
proc savenums () { local vv,i
    vv=allocvecs(1)
    for i=1, numarg() mso[vv].append($i)
    mso[vv].vwrite(tmpfile)
    dealloc(vv)
  }

// readnums(&x[,&y...]) recover nums from tmpfile via a vector
proc readnums () { local vv,i
    vv=allocvecs(1)
    mso[vv].vread(tmpfile)
    if (numarg()!=mso[vv].size) printf("readnums WARNING: args=%d;vec.size=%d\n",numarg(),mso[vv].size)
    for i=1,numarg() if (i<=mso[vv].size) $&i = mso[vv].x[i-1]
    dealloc(vv)
  }

//** wrvstr(str) save string to a file by converting to ascii
proc wrvstr () { local vv,i
    vv=allocvecs(1)
    str2v($s1,mso[vv])
    mso[vv].vwrite(tmpfile)
    dealloc(vv)
  }

// rdvstr(str) read string from a file via vread and conversion
proc rdvstr () { local vv,i
    vv=allocvecs(1)
    mso[vv].vread(tmpfile)
    if (numarg()==1) v2str(mso[vv],$s1) else v2str(mso[vv],tstr)
    // print tstr
    dealloc(vv)
  }

// str2v() overwrites temp_string2_
proc str2v () { 
    $o2.resize(0)
    temp_string2_=$s1
    while (sfunc.len(temp_string2_)>0) {
        sscanf(temp_string2_,"%c%*s",&x)
        sfunc.right(temp_string2_,1)
        $o2.append(x)
      }
  }
    
proc v2str () {
    $s2=""
    for vtr(&x,$o1) sprint($s2,"%s%c",$s2,x)
  }

//* remove last entry
func popvec () { local sz, ret
    sz = $o1.size-1
    ret = $o1.x[sz]
    $o1.resize[sz]
    return ret
  }

//* chkvec (look at last entry)
func chkvec () { if ($o1.size>0) return $o1.x[$o1.size-1] else return -1e10 }

// vecsprint(strdef,vec)
proc vecsprint () { local ii
    if ($o2.size>100) { return }
    for ii=0,$o2.size-1 { sprint($s1,"%s %g ",$s1,$o2.x[ii]) }
  }

// savevec([list,]vec1[,vec2,...]) add vector onto veclist or other list if given as 1st arg
// don't throw out vectors
proc savevec () { local i,flag,beg
    if (isobj($o1,"List")) beg=2 else beg=1
    for i=beg, numarg() { 
        if (veccollect.count>0) { // grab a vector from garbage collection
            tmpvec=veccollect.object(veccollect.count-1)
            veccollect.remove(veccollect.count-1)
          } else tmpvec = new Vector($oi.size)
        tmpvec.copy($oi)
        if (beg==2) $o1.append(tmpvec) else veclist.append(tmpvec)
        tmpvec = nil
      }
  }

proc prveclist () {
    if (tmpfile.ropen($s1)) {
        printf("%s exists; save anyway? (y/n) ",$s1)
        getstr(temp_string_) chop(temp_string_)
        if (strcmp(temp_string_,"y")!=0) return
      }
    tmpfile.wopen($s1)
    if (numarg()==2) {
        for ltr(XO,$o2) XO.vwrite(tmpfile)
      } else {
        for ltr(XO,veclist) XO.vwrite(tmpfile)
      }
    tmpfile.close()
  }

proc rdveclist () { local flag,a
    flag=0
    a=allocvecs(1)
    if (numarg()==1) { flag=1 clrveclist() } else $o2.remove_all
    tmpfile.ropen($s1)
    while (mso[a].vread(tmpfile)) {
        if (flag) savevec(mso[a]) else savevec($o2,mso[a])
      }
    tmpfile.close()
    tmpobj=veclist
    dealloc(a)
  }
  
proc rdxy () { local a
    a = allocvecs(1)
    revec(ind,vec)
    tmpfile.ropen("aa")
    mso[a].scanf(tmpfile)
    if (mso[a].size%2!=0) {print "rdxy ERR1 ",mso[a].size return}
    for vtr2(&x,&y,mso[a]) {ind.append(x) vec.append(y)}
    print ind.size," points read from aa into ind and vec"
    dealloc(a)
  }

// closest(vec,num) -- return ind for vec member closest to num
func closest () { local a,ret
    a=allocvecs(1)
    mso[a].copy($o1) mso[a].sub($2) mso[a].abs
    ret=mso[a].min_ind
    dealloc(a)
    return ret
  }

proc clrveclist () { 
    for ltr(XO,veclist) { XO.resize(0) veccollect.append(XO) }
    veclist.remove_all()
  }

// savestr(str1...) add string obj onto tmplist
proc savestr () { local i
    if (argtype(1)==1) for i=2, numarg() $o1.append(new String($si)) else {
        for i=1, numarg() tmplist.append(new String($si))
      }
  }

// redund with v.count in vecst.mod
func vcount () { local val,sum
    val=$2 sum=0
    for vtr(&x,$o1) if (x==val) sum+=1
    return sum
  }

// tvecl() -- transpose veclist
proc tvecl () { local cnt,sz,err,ii,p
    err = 0
    cnt = veclist.count
    sz = veclist.object(0).size
    for ltr(XO,veclist) if (XO.size!=sz) err=i1
    if (err) { print "Wrong size vector is #",i1 return }
    p = allocvecs(1,cnt)  mso[p].resize(cnt)
    for ii=0,sz-1 {
        for jj=0,cnt-1 {
            XO=veclist.object(jj)
            mso[p].x[jj] = XO.x[ii]
          }
        savevec(mso[p])
      }
    for (jj=cnt-1;jj>=0;jj-=1) { veccollect.append(veclist.object(jj)) veclist.remove(jj) }
  }  

//* vinsect(v1,v2,v3) -- v1 gets intersection (common members) of v2,v3
//  replaced by v.insct() in vecst.mod
proc vinsect () {
    $o1.resize(0)
    for vtr(&x,$o2) for vtr(&y,$o3) if (x==y) $o1.append(x)
  }

//* vecsplit(vec,vec1,vec2[,vec3,...])
// splits vec into other vecs given
proc vecsplit () { local num,ii,i
    num = numarg()-1 // how many
    for i=2,numarg() $oi.resize(0)
    for (ii=0;ii<$o1.size;ii+=num) {
        for i=2,numarg() if (ii+i-2<$o1.size) $oi.append($o1.x[ii+i-2])
      }
  }

//* vecsort(vec,vec1,vec2[,vec3,...])
// sorts n vecs including first vec by first one
proc vecsort () { local i,inv,scr,narg
    narg=numarg()
    if (narg<2 || narg>10) {print "Wrong #args in decvec.hoc:vecsort" return}
    scr=inv=allocvecs(2) scr+=1
    $o1.sortindex(mso[inv])
    mso[scr].resize(mso[inv].size)
    sprint(temp_string_,"%s.fewind(%s,%s,%s",mso[scr],mso[inv],$o1,$o2)
    for i=3,narg sprint(temp_string_,"%s,%s",temp_string_,$oi)
    sprint(temp_string_,"%s)",temp_string_)
    execute(temp_string_)
    dealloc(inv)
  }

//* vdelind()  -- delete a single index
proc vdelind () { local i,iin
    iin = $2
    if (iin<0) iin=$o1.size+iin
    if (iin>$o1.size-1 || iin<0) {
        printf("vdelind Error: index %d doesn't exist.\n",iin) return }
    if (iin<$o1.size-1) $o1.copy($o1,iin,iin+1,$o1.size-1)
    $o1.resize($o1.size-1)
  }

//* mkveclist(num[,sz]) recreate veclist to have NUM vecs each of size SZ (or MSOSIZ)
proc mkveclist () { local ii,num,sz,diff
    num=$1 
    diff = num-veclist.count
    if (numarg()==2) { sz=$2 } else { sz = MSOSIZ }
    if (diff>0) {
        for ii=0,diff-1 {
          tmpvec = new Vector(sz)
          veclist.append(tmpvec)
          }
      } else if (diff<0) {
        for (ii=veclist.count-1;ii>=num;ii=ii-1) { veclist.remove(ii) }
      }
    for ltr(XO,veclist) { XO.resize(sz) }
  }

//* allocvecs
// create temp set of vectors on mso
// returns starting point on mso 
// eg p = allocvecs(3)
// access these vectors by mso[p+0] ... [p+2]
func allocvecs () { local ii, llen, sz, newv
    if (numarg()==0) { print "p=allocvecs(#), access with mso[p], mso[p+1]..." return 0}
    newv = $1
    if (numarg()==2) { sz=$2 } else { sz=MSOSIZ }
    llen = msoptr
    for ii=msomax,msoptr+newv-1 { // may need new vectors
        if (ii>=MSONUM) { print "alloc ERROR: MSONUM exceeded." return 0 }
        mso[ii] = new Vector(sz)
      }
    for ii=0,newv-1 {
        mso[msoptr].resize(0)
        msoptr = msoptr+1
      }
    if (msomax<msoptr) msomax = msoptr
    return llen
  }

//** dealloc(start)
// remove temp set of vectors from mso
proc dealloc () { local ii,min
    if (numarg()==0) { min = 0 } else { min = $1 }
    msomax = msoptr
    msoptr = min
  }

//* vecconcat(vec1,vec2,...)
// destructive: concatenates all vecs onto vec1
proc vecconcat () { local i
    if (numarg()<2) { print "vecconcat(v1,v2,...) puts all into v1" return }
    for i=2,numarg() {
        $o1.copy($oi,$o1.size)
      }
  }
  
//** vecelim(v1,v2)  eliminates items in v1 given by index vec v2
proc vecelim () {
    for vtr(&x,$o2) { $o1.x[x]= -1e20 }
    $o1.where($o1,"!=",-1e20)
  }

//** vwh() returns a v.where(==)
func vwh() { return $o1.indwhere("==",$2) }

//** redundout(vec) eliminates sequential redundent entries
// destructive
proc redundout () { local x,ii,p1
    p1=allocvecs(1)
    $o1.sort
    x = $o1.x[0]
    for ii=1,$o1.size-1 {
        if ($o1.x[ii]==x) { $o1.x[ii]=-1e20 } else { x=$o1.x[ii] }
      }
    mso[p1].where($o1,">",-1e20)
    $o1.copy(mso[p1])
    dealloc(p1)
  }

// vecconv() convert $o1 by replacing instances in $o2 by corresponding instances in $o3
proc vecconv () { local a,b
    a=b=allocvecs(2) b+=1
    vrsz($o1,mso[b])
    for vtr2(&x,&y,$o2,$o3) { // x -> y
        mso[a].indvwhere($o1,"==",x)
        mso[b].indset(mso[a],y)
      }
    $o1.copy(mso[b])
  }

//** veceq()  like vec.eq but don't have to be same size and shows discrepency
func veceq () { local sz1,sz2,eq,beg,ii,jj,kk
    sz1=$o1.size sz2=$o2.size
    if (numarg()==3) beg=$3 else beg=0
    if (sz1!=sz2) printf("%s %d; %s %d\n",$o1,sz1,$o2,sz2)
    ii=0 jj=beg
    while (ii<sz1 && jj<sz2) {
        if ($o1.x[ii]!=$o2.x[jj]) { 
            eq=0
            printf("Differ at %d %d\n",ii,jj) 
            for kk=-10,10 if ((ii+kk)>=0 && (ii+kk)<sz1 && (jj+kk)>=0 && (jj+kk)<sz2) {
                printf("(%d)%g:(%d)%g ",(ii+kk),$o1.x[ii+kk],(jj+kk),$o2.x[jj+kk])  }
            print ""
            break 
          } else eq=1
        ii+=1 jj=ii+beg
      }
    return eq
  }

//* isstring() determine if object $o1 is of type string, if so return the string in [$s2]
func isstring () {
    sprint(tstr,"%s",$o1)
    if (sfunc.substr(tstr,"String")==0) {
        if (numarg()==2) sprint($s2,"%s",$o1.s)
        return 1
      } else {
        if (numarg()==2) sprint($s2,"%s",$o1)
        return 0
      }
  }

//** isassigned() checks whether an object is Null
func isassigned () {
    sprint(temp_string_,"%s",$o1)
    if (sfunc.substr(temp_string_,"NULLobject")==0) {
        return 0
      } else {
        return 1
      }
  }

//** isit() like isassigned() but takes a string instead
func isit () {
    sprint(temp_string_,"XO=%s",$s1)
    execute(temp_string_) // XO points to the thing
    sprint(temp_string_,"%s",XO) // what is XO
    if (sfunc.substr(temp_string_,"NULLobject")==0) {
        return 0
      } else {
        return 1
      }
  }

//** isob(s1,s2) like isobj but takes string statt obj
func isob () {
    sprint(temp_string_,"XO=%s",$s1)
    execute(temp_string_) // XO points to the thing
    sprint(temp_string_,"%s",XO)
    if (sfunc.substr(temp_string_,$s2)==0) {
        return 1
      } else {
        return 0
      }
  }

//** eqobj(o1,o2) checks whether 2 objects are the same
func eqobj () {	return object_id($o1) == object_id($o2) }

//** isobj(o1,s2) checks whether object $o1 is of type $s2
func isobj () {
    sprint(temp_string_,"%s",$o1)
    if (sfunc.substr(temp_string_,$s2)==0) {
        return 1
      } else {
        return 0
      }
  }

// destructive of $s1
func str2num () { local ii
    sscanf($s1,"%d",&x)
    return x
  }

// like perl chop -- removes the last character
proc chop () { sfunc.left($s1,sfunc.len($s1)-1) }
proc concat () { local i
    for i=2,numarg() sprint($s1,"%s%s",$s1,$si)
  }
proc concat () { local i
    for i=2,numarg() sprint($s1,"%s%s",$s1,$si)
  }

// eg split("534,  43 , 2, 1.4, 34",vec)
proc split () { 
    revec($o2)  temp_string2_=$s1
    while (sfunc.len(temp_string2_)>0) {
        sscanf(temp_string2_,"%lf",&x) $o2.append(x)
        if (numarg()==3) sfunc.tail(temp_string2_,$s3,temp_string2_) else {
                           sfunc.tail(temp_string2_,",",temp_string2_) }
      }
  }

// intervals(TRAIN,OUTPUT)
proc intervals () { local a
    if ($o1.size<=1) { printf("%s size <2 in intervals()\n",$o1) return }
    $o2.deriv($o1,1,1)
  }

proc downcase () { local len,ii,let,diff,min,max
    diff=32 min=65 max=90
    if (numarg()==2) { diff=-diff min=97 max=122 } // if flag -> upcase
    len = sfunc.len($s1)
    for ii=1,len {
        sscanf($s1,"%c%*s",&x)
        sfunc.right($s1,1)
        if (x>=min&&x<=max) {
            sprint($s1,"%s%c",$s1,x+diff)
          } else sprint($s1,"%s%c",$s1,x) // just rotate the letter
      }
  }

// newlst() puts a newline in the middle of a string
proc newlst () { local l
    if (numarg()>1) l=$2 else l=int(sfunc.len($s1)/2)
    temp_string_=$s1
    temp_string2_=$s1
    sfunc.left(temp_string_,l)
    sfunc.right(temp_string2_,l)
    sprint($s1,"%s\n%s",temp_string_,temp_string2_)
  }

//* hist(g,vec,max,width)
proc hist () { local a,b,c,max,wid,ii,jj
    max=$3 wid=$4
    a=b=c=allocvecs(3) b+=1 c+=2
    $o1.erase()
    mso[c].hist($o2,0,int((max+wid)/wid),wid)
    mso[a].resize(2*mso[c].size())
    mso[a].indgen(.5) 
    mso[a].apply("int") 
    mso[b].index(mso[c], mso[a]) 
    mso[a].mul(wid)
    mso[b].rotate(1)
    mso[b].x[0] = 0 
    mso[b].append(mso[b].x[mso[b].size-1],0)
    mso[a].append(max,max)
    mso[b].plot($o1, mso[a])
    jj=-1
    for (ii=0;ii<max;ii+=wid) { 
        $o1.beginline() $o1.line(ii,0) $o1.line(ii,mso[c].x[jj+=1]) 
        if (mso[c].x[jj]!=0) $o1.mark(ii+wid/2,mso[c].x[jj],"O",6,2,2)
      }
    $o1.flush()
    $o1.size(0,max,0,mso[b].max)
    dealloc(a)
  }
// END /usr/site/nrniv/local/hoc/decvec.hoc
//================================================================
strdef grep // LINUX grep requires -a to handle a binary file 
strdef ddir,msg,symb
if (sfunc.substr(osname,"inux")==1) grep="grep -a" else grep="grep"
ddir = "data"
symb = "O"
gvmarkflag=gveraseflag=0

//* abbreviated proc alls
proc pwpl () { pwman_place(500,500) }
proc vp () { vecpanel() }
proc ap () {if (numarg()==1) attrpanl($1) else attrpanl(0) }
proc wp () {if (numarg()==1) wvpanl($1) else wvpanl(0) }
proc gp () {if (numarg()==1) rpanel($1) else pbrgr("Graph","gv") }
proc tog (){if (numarg()==0) print gvmarkflag=1-gvmarkflag else print $&1=1-$&1}

//* templates
//** attrpanl(attribute panel) template stores the information about
// the attributes of a particular set of graphs including line colors,
// world coordinates, ...
// glist is a list of all graphs created from this panel
// llist is a list of available names and associated vectors or locations
begintemplate panattr
  public color,line,super,curcol,graph,filename,comment
  public glist,llist,tvec,size,shift,vsz,vjmp,tloc,vloc,remote
  public printStep,entries,segments,bytes
  public clear
  double color[1],line[1],super[1],curcol[1],printStep[1],remote[1]
  double size[4],entries[1],segments[1],bytes[1],shift[1]
  double vsz[2],tloc[1],vloc[1],vjmp[1]
  objref glist,llist,tvec
  strdef filename,comment
  proc init() {
      if (numarg()==1) filename = $s1
      color=1 line=1 curcol=1 tloc=-1 super=0 bytes=0 vjmp=50 entries=1 segments=1
      vsz[0] = 300  vsz[1] = 200
      glist = new List()
      llist = new List()
      tvec  = new Vector(0)
    }
  proc remgrs () {
      glist.remove_all
      glist = nil
      glist = new List()
    }
  proc clear() {
      bytes=0 entries=1 segments=1
      comment = ""
      llist.remove_all()
    }
endtemplate panattr

//** vfile_line (vector file line) template gives information about a line
//  in a file that gives a vector: name, size and location
begintemplate vfile_line
  public name, size, loc, num
  strdef name
  double size[1],loc[1],num[1],tvec[1]
  proc init () { 
      name=$s1 size=$2 num=$4
      double loc[num],tvec[num]
      loc[0] = $3
    }
endtemplate vfile_line

//** vitem (vector item) is an internal vector used to store output from 
// new vitem(var_name,vec_size,friendly_name)
// new vitem(var_name,vec_size,1) -- force tvec creation even if not cvode_local
// a simulation holds the name and the vector itself
begintemplate vitem
  external cvode_local
  public tvec,vec,var
  objref tvec,vec // vector
  strdef var // variable name
  proc init () { local tvflag
      var=$s1  tvflag=0
      if (cvode_local()==1) tvflag=1 else { 
          // print "WARNING CVODE LOCAL IS NOT SET" 
        }
      vec=new Vector($2)
      // NB label is labile
      vec.label("") // use label for friendly name
      if (numarg()==3) {
          if (argtype(3)==2) vec.label($s3)
          if (argtype(3)==0) if ($3==1) tvflag=1
        }
      if (tvflag=1) tvec=new Vector($2) 
    }
endtemplate vitem

//* object declarations
objref vite, scob, printlist, panobj, panobjl, szstr[4], g[10]
panobj = new panattr(simname)
panobjl = new List()
proc pno () { panobj=panobjl.object($1) }
printlist = new List()
panobjl.append(panobj) // global graphing attributes
panobj.llist = printlist 
tmpfile = new File()
strdef filename, recstr, grvecstr, readtag
readtag = "^//[:pbCM ]"  // regexp used to identify header in mixed binary files
for ii=0,3 { szstr[ii] = new String() }
{ szstr[0].s="Set xmin" szstr[1].s="Set xmax" szstr[2].s="Set ymin" szstr[3].s="Set ymax" }
multi_files = 1 // set 0 to show individual segments of multi-seg files
dec_runnum = 1  // whether to decrement runnum when saving a new file
byte_store = 4  // store as ascii (0), byte (1), int (2), float (3), double (4)
tvec_bytesize = 4  // always store tvecs with more precision
show_panel = 1  // whether or not to put a full panel up when a file is read
outvecint = 0     // dump vectors every outvecint time if not 0
outvect = 0     // time for next vec dump
labelm = 1       // set to 0 to turn off labeling
strdef rvvec_name
rvvec_name = "vec"

//* store cvode state in a double in form active.local
func cvode_status () { return cvode_active() + cvode_local()/10 }
ulvflag=1
proc ulv () { 
    if (ulvflag || numarg()==1) { // else leave these other flags alone
        using_cvode_ = cvode_active() 
        use_lvardt_ = cvode_active() && cvode_local()
      }
  } 
cvode_state = cvode_status()

//** return true and update cvode_state if cvode state has changed
func cvode_change () { 
    if (cvode_state!=cvode_status()) {
        cvode_state=cvode_status() return 1
      } else { return 0 }
  }

//** verbose form of cvode_change
func cvode_what () { local act,loc,newstat,newact,newloc
    act=int(cvode_state)  loc=(cvode_state-act)*10
    newstat = cvode_status()
    if (cvode_state!=newstat) {
        newact=int(newstat)  newloc=(newstat-newact)*10
        printf("Updating active/local from %d/%d to %d/%d\n",act,loc,newact,newloc)
        cvode_state=cvode_status() return 1
      } else {
        printf("cvode_state: active %d, local %d\n",act,loc)
        return 0	
      }
  }

if (xwindows) scob = new SymChooser()

//* vecpanel() main panel
proc vecpanel() {
    fchooser_flag = 0  // used to initialize the file chooser
    sprint(temp_string_,"%s Vectors",simname)
    xpanel(temp_string_)
    xbutton("Graph from file","fchooser(-1)")
    xbutton("Graph vector","pbrgr(\"Graph\",\"gv\")")
    xbutton("Archive to file:","pbrgr(\"Archive\",\"pv\")")
    xbutton("Archive all to output_file","pvall()")
    xstatebutton("Superimpose",&panobjl.object(0).super)
    xbutton("Attributes","attrpanl(0)")
    redo_printlist()
    redo_attrlist()
    xpanel()
  }

//* pbrgr(browser name,action) is used to put up a browser
// note action given without '()'
proc pbrgr () {
    if (printlist.count == 1) {
        gv(0)
      } else if (printlist.count <= 8) {
        mkpanel("Vector",$s1,$s2)
      } else {
        sprint(temp_string_,"%s:%s",simname,$s1)
        printlist.browser(temp_string_,"var")
        sprint(temp_string2_,"%s()",$s2)
        printlist.accept_action(temp_string2_)
      }
  }

//* record(list,what,vecptr) from items in $o1 object(ii).$s2 in vectors
// $o1 is the list arg $s2 is the thing to be recorded [eg soma.v(0.5)]
// optional $3 is the name of an object belonging to list items that will
// serve as a pointer to the recording vector
proc record () { local ii, dur, na3
    for ltr(XO,$o1) {
        sprint(recstr,"%s.%s",XO,$s2)
        new_printlist_item(recstr) 
        if (numarg()==3) { 
            sprint(temp_string_,"%s.%s=printlist.object(printlist.count-1).vec",XO,$s3)
            execute(temp_string_) // only way to get call by ref for object
          }
      }
  }

//* record_spks(list[,what]) takes a list of netcons and puts in printlist objects for them
// assumes that the PP will be called pp
proc record_spks () { local ii,flag
    ulv(1)
    for ltr(XO,$o1) {
        flag=1
        if (cvode.netconlist(XO, "", "").count>0) {
            YO=cvode.netconlist(XO, "", "").object(0)
            sprint(recstr,"%s%s",YO.precell,"_spks")
          } else if (cvode.netconlist(XO.pp, "", "").count>0) {
            YO=cvode.netconlist(XO.pp, "", "").object(0) 
            sprint(recstr,"%s%s",YO.pre,"_spks")
          } else { printf("%s not connected.\n",XO) flag=0 }
        if (flag) {
            vite = new vitem(recstr,100)
            if (use_lvardt_) { YO.record(vite.tvec) vite.vec.resize(0) } else YO.record(vite.vec)
            printlist.append(vite)
          }
      }
    YO=nil
  }

//* redo_printlist() menu allows removal or addition of inidividual items
proc redo_printlist() {
    xmenu("Print list")
    xbutton("Add var to printlist","redolist(0)")
    xbutton("Clear printlist","printlist.remove_all()")
    xbutton("Remove item from printlist","redolist(1)")
    xbutton("Vector.op","redolist(2)")
    xbutton("Proc(vector)","redolist(6)")
    xbutton("Link XO->vec,YO->tvec","redolist(7)")
    xbutton("Graph vector","redolist(4)")
    xbutton("Save printlist","redolist(5)")
    xbutton("Add all obj's of this type to printlist","redolist(3)")
    xmenu()
  }

//* redolist() set of functions for altering the printlist called by redo_printlist()
proc redolist () { local ii,flag
    flag = $1  rdstr = 1
    if (numarg()==2) { recstr=$s2  rdstr=0 }
    if (flag==0) {
        if (scob.run()) {
            scob.text(temp_string_)
            new_printlist_item(temp_string_)
          }
      } else if (flag==1) { // remove item
        printlist.browser("Double click on item to remove","var")
        printlist.accept_action("printlist.remove(hoc_ac_)")
      } else if (flag==2) { // .op
        if (rdstr) string_dialog("Enter operation to be run on vec",recstr)
        temp_string_ = "\"%s.%s = %g\\n\""
        sprint(temp_string_,"printf(%s,printlist.object(hoc_ac_).var,\"%s\",x=printlist.object(hoc_ac_).vec.%s)",temp_string_,recstr,recstr)
        printlist.browser(recstr,"var")
        printlist.accept_action(temp_string_)
      } else if (flag==3) { // put another set of things on list
        if (rdstr) string_dialog("String to be used as suffix for all items on list",recstr)
        scob.run()
        scob.text(temp_string_)
        tmplist = new List(temp_string_)
        record(tmplist,recstr)
      } else if (flag==4) { // show it
        pbrgr("Graph","gv")
      } else if (flag==5) {
        fchooser_flag = 0
        tmpfile.chooser("a","Add printlist to file")
        if (tmpfile.chooser()==1) {
            tmpfile.printf("\nproc make_printlist() { \n")
              tmpfile.printf("  printlist.remove_all()\n")
              for ii=0,printlist.count-1 {
                  tmpfile.printf("  new_printlist_item(\"%s\")\n",printlist.object(ii).var)
                }
              tmpfile.printf("}\nmake_printlist()\n")
            tmpfile.close()
          }
      } else if (flag==6) { // proc(vec)
        if (rdstr) string_dialog("Enter procedure name \"proc\",called as proc(vec,var,num)",recstr)
        printlist.browser(recstr,"var")
        sprint(temp_string_,"%s(printlist.object(hoc_ac_).vec,printlist.object(hoc_ac_).var,hoc_ac_)",recstr)
        printlist.accept_action(temp_string_)
      } else if (flag==7) { // XO is pointer to vec
        printlist.browser("XO","var")
        sprint(temp_string_,"{tmpobj=printlist.object(hoc_ac_) print hoc_ac_,tmpobj.var XO=tmpobj.vec YO=tmpobj.tvec}")
        printlist.accept_action(temp_string_)
      } 
  }

//** lkprl([num]) link X0 to vector in printlist, optional arg can be pos or neg
proc lkprl () { local num,cnt
    cnt = printlist.count
    if (numarg()==1) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
    if (num>cnt-1 || num<0) {
        printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
      }
    print num,":XO -> ",printlist.object(num).var
    XO = printlist.object(num).vec
    YO = printlist.object(num).tvec
  }

//** cpplitem([num]) copy X0 to new item in printlist, optional arg can be pos or neg
proc cpplitem () { local num,cnt
    cnt = printlist.count
    if (numarg()>0) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
    if (num>cnt-1 || num<0) {
        printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
      }
    if (numarg()>1) grvecstr=$s2 else sprint(grvecstr,"Copy_of_%s",printlist.object(num).var)
    new_printlist_item(grvecstr,printlist.object(num).vec)
    print printlist.count-1,":XO -> ",grvecstr
    XO = printlist.object(printlist.count-1).vec
  }


//** cpplitem([num]) copy X0 to new item in printlist, optional arg can be pos or neg
proc chgplname () { local num,cnt
    cnt = printlist.count
    if (numarg()>0) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
    if (num>cnt-1 || num<0) {
        printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
      }
    printlist.object(num).var=$s2
  }

//* new_printlist_item(name) adds this item to the printlist
//  new_printlist_item(name,vec) adds this vec to the printlist
//  new_printlist_item(name,num,vec) adds this vec to the printlist under name_num0,name_num1,...
proc new_printlist_item () { local dur,pln
    ulv(1)
    panobj = panobjl.object(0)  
    if (outvecint == 0) dur = tstop else dur = outvecint
    grvecstr = $s1
    remove_spaces(grvecstr,temp_string2_) // splits on '/'
    // eg new_printlist_item(name,ii,vec)
    if (numarg()>=3) { // allows formation of tags on the fly
        sprint(temp_string_,"%s%s",grvecstr,":%d")
        sprint(temp_string_,temp_string_,$2)
        vite = new vitem(temp_string_,$o3.size,temp_string2_)
        vite.vec.copy($o3)
        if (numarg()==4) vite.tvec.copy($o4)
        printlist.append(vite)
        return
      }
    if (numarg()==2) { // second arg is a vector to store
        if (argtype(2)==1) {
            vite = new vitem(grvecstr,$o2.size,temp_string2_)
            vite.vec.copy($o2)
            printlist.append(vite)
            return
          } else if (argtype(2)==2) sprint(grvecstr,"%s%s",grvecstr,$s2)
      }
    if (use_lvardt_) { 
        if (isobj(panobj.tvec,"Vector")) if (panobj.tvec.size!=0) { panobj.tvec.resize(0) panobj.tvec.play_remove() }
        vite = new vitem(grvecstr,dur/printStep+10,temp_string2_)
        panobj.printStep=-2
      } else if (using_cvode_) { 
        vite = new vitem(grvecstr,dur/printStep+10,temp_string2_)
        panobj.printStep=-1
        if (panobj.tvec.buffer_size==0) { 
            panobj.tvec.resize(dur/printStep+10) panobj.tvec.resize(0)
          }
        panobj.tvec.record(&t) 
      } else { 
        if (panobj.tvec.size!=0) { panobj.tvec.resize(0) panobj.tvec.play_remove()}
        panobj.printStep=printStep 
        vite = new vitem(grvecstr,dur/printStep+10,temp_string2_)
      }
    printlist.append(vite)
    pln = printlist.count-1 // current printlist number
    if (numarg()==2) $o2=vite.vec // allow user to assign a pointer
    vite = nil
    if (use_lvardt_) {
        printlist.object(pln).vec.resize(dur/printStep+10)
        printlist.object(pln).tvec.resize(dur/printStep+10)
        find_secname(grvecstr,temp_string_)
        sprint(temp_string_,\
               "%s {cvode.record(&%s,printlist.object(%d).vec,printlist.object(%d).tvec)}",\
               temp_string_,grvecstr,pln,pln)
      } else if (using_cvode_) { // don't give an explicit printStep
        printlist.object(pln).vec.resize(dur/printStep+10)
        sprint(temp_string_,\
               "{printlist.object(%d).vec.record(&%s)}",pln,grvecstr)
      } else {
        sprint(temp_string_,\
               "printlist.object(%d).vec.record(&%s,%g)",pln,grvecstr,printStep)
      }
    execute(temp_string_)
  }

// new_pri(NAME,TVEC,VEC) quick and dirty new_printlist_item
proc new_pri () {
    vite = new vitem($s1,$o2.size)
    if (numarg()==3) { vite.tvec.copy($o2) vite.vec.copy($o3) } else vite.vec.copy($o2)
    printlist.append(vite)
    vite=nil
  }

//* prlexp(sz) expands all the vectors in printlist to size sz
proc prlexp () { 
    sz = $1
    tvec.resize(sz)
    for ltr(XO,printlist) { XO.vec.resize(sz) }
  }


//* redo_attrlist() menu allows removal or addition of inidividual items
proc redo_attrlist() {
    xmenu("Attribute panels")
    xbutton("Read file","attrlist(0)")
    xbutton("Remove","attrlist(1)")
    xbutton("Show","attrlist(2)")
    xbutton("Clear list","attrlist(3)")
    xbutton("New","attrlist(4)")
    xmenu()
  }

//* attrlist() set of functions for altering panobjl (list of graph attributes)
proc attrlist() { local ii
    if ($1==0) {
        fchooser(-1)
      } else if ($1==1) { // remove item
        panobjl.browser("Double click on item to remove","filename")
        panobjl.accept_action("panobjl.remove(hoc_ac_)")
      } else if ($1==2) {
        panobjl.browser("Double click on item",temp_string_,"numovecs()")
        panobjl.accept_action("attrpanl(hoc_ac_)")    
      } else if ($1==3) { // clear but leave #0
        for (ii=panobjl.count-1;ii>0;ii=ii-1) { panobjl.remove(ii) }
      } else if ($1==4) { // create a new one without reading a file in
        panobj = new panattr()
        panobj.filename = "EMPTY"
        panobjl.append(panobj)
        panobj.remote = panobjl.count()-1
        attrpanl(panobjl.count()-1)
      } else if ($1==5) { // create one with given num and name
        for ii=panobjl.count,$2 { // create more if needed
            panobj = new panattr()
            panobjl.append(panobj)
            panobj.remote = ii
          }
        panobj = panobjl.object($2)
        panobj.filename = $s3
        panobj.comment = $s4
        panobj.printStep = $5
      }
  }

// show the number of vectors as well as the name of the file
proc numovecs() { local num
    if (hoc_ac_==0) num=printlist.count() else num=panobjl.object(hoc_ac_).llist.count() 
    sprint(temp_string_,"#%d %s: %d",hoc_ac_,panobjl.object(hoc_ac_).filename,num)
  }

//* fchooser(attrnum) finds file and then create panel from it using rpanel
proc fchooser () { local attr0
    attr0=$1
    if (fchooser_flag == 0) {  // create panel first time only
        sprint(temp_string_,"v0*")
        tmpfile.chooser("","Read from a file",temp_string_)
      }
    fchooser_flag = 1
    if (tmpfile.chooser() == 1) {
        // find out whether this is a vector file or not
        tmpfile.getname(filename)
        sfunc.tail(filename,"/data.*/",grvecstr) // just take the file name without the leading stuff
        attrnum = read_vfile(attr0)
        if (attrnum == 0) {print "ERROR in fchooser" return }// error
        // a new one so should show something
        if (attr0==-1) if (show_panel) rpanel(attrnum) else attrpanl(attrnum)
      }
  }

//* routines for reading in a vector file

//** read_vfile(attrnum) creates a panattr object from information in a file
// (uses grep to avoid loading big file)
// assumes file in tmpfile
func read_vfile () { local flag, ii, sz, loc, mult, sze, cloc, segs
    if (numarg()==0) { print "read_vfile(attrnum,filename)" return 0 }
    if (numarg()==2) filename = $s2
    read_findattr($1) // set panobj and attrnum
    // grab hold of the different lines using grep
    file_with_dot(filename,temp_string_,temp_string2_) // put .filename into temp_string_
    if (!tmpfile.ropen(temp_string_)) {
        if (! tmpfile.ropen(filename)) { print "E1: Can't open ",filename // avoid grep error
            return 0 }
        sprint(temp_string2_,"%s '%s' %s > %s",grep,readtag,filename,temp_string_)
        system(temp_string2_)
        tmpfile.close()
        if (! tmpfile.ropen(temp_string_)) { print "E2: Can't open ",temp_string_," (",filename,")" 
            return 0 }
        flag = 0
      } else flag = 1 // signifies that .file exists to use as key
    while ((numr = tmpfile.scanstr(temp_string_)) != -1) {  // throw out the leading '//'
        // read the line
        cloc = tmpfile.tell - numr // location of the beginning of this line
        if (sfunc.head(temp_string_,"//[^b]",temp_string2_)==0) {
            read_vinfo()  // a line giving info about the file (eg comment)
          } else {   // NB: code in v60:516 to pickup byte_store value
            if (panobj.bytes==0 && \
                sfunc.head(temp_string_,"//b[1-9]",temp_string2_)==0) { panobj.bytes = 1 }
            if (flag && panobj.entries>1) { // a .file with MULTI segs
                tmpfile.seek(-numr,1) // backup to beginning of line
                read_vdotfile()
              } else if (panobj.segments > 1) { // mult segs: different times for same var
                tmpfile.seek(-numr,1) // backup to beginning of line
                panobj.segments = read_vsegs()
              } else {  // read each line in for itself
                tmpfile.scanstr(temp_string_) // name of a var
                sze = tmpfile.scanvar()   // size of the vector or time it was dumped
                loc = tmpfile.scanvar()   // location of the vector
                if (panobj.bytes) { tmpfile.seek(cloc) // go back and measure the line length
                    loc = loc + tmpfile.gets(temp_string2_) }
                // create the item
                if (! strcmp(temp_string_,"tvec")==0) {
                    tmpobj = new vfile_line(temp_string_,sze,loc,1)
                    panobjl.object(attrnum).llist.append(tmpobj)
                    tmpobj = nil
                  } else {
                    panobj.tvec.resize(0)
                    panobj.printStep=-1
                    panobj.tloc = loc // where to find tvec later
                  }
              }
          }
      }
    if (panobj.entries==1) panobj.entries = panobj.llist.count
    if (! flag && panobj.segments>1) write_vsegs()  // create key .file
    if (! tmpfile.ropen(panobj.filename)) { print "E3: Can't open ",panobj.filename
        return 0 }
    if (panobj.printStep==-1) { rtvec(attrnum) // code for cvode_active()
      } else if (panobj.printStep==0) panobj.printStep = printStep
    return attrnum
  }

//** read_findattr()
// see if want to use old attributes or start new ones
proc read_findattr () { 
    if ($1 > -1 && $1 < panobjl.count()) {
        attrnum = $1
        panobj = panobjl.object(attrnum)
        panobj.clear()
        panobj.filename = filename
      } else {   // create a new panel attribute object to hold color and line type
        panobj = new panattr(filename)
        panobjl.append(panobj)
        panobj.remote = panobjl.index(panobj)
        attrnum = panobjl.index(panobj)
      }
  }

//** read_vinfo()
// fill in panobj entries based on an information line in a vector file
proc read_vinfo () {
    if (strcmp(temp_string_,"//printStep")==0) {
        panobj.printStep = tmpfile.scanvar() // printstep==-1 means cvode
      } else if (strcmp(temp_string_,"//:")==0) { // a comment
        tmpfile.gets(temp_string_)
        sfunc.head(temp_string_,"\n",panobj.comment) // chop final newline
      } else if (strcmp(temp_string_,"//CPU")==0) { // the machine type for byte storage
        tmpfile.scanstr(temp_string_)
        if (strcmp(temp_string_,uname)!=0) {
            printf("%s written from %s\n",filename,temp_string_)
          }
      } else if (strcmp(temp_string_,"//MULTI")==0) { // multiple lines for each entry
        panobj.entries = tmpfile.scanvar()
        if (multi_files) { panobj.segments = tmpfile.scanvar() }
      } else {
        printf("Line:\t%s\n\tnot recognized in %s\n",temp_string_,panobj.filename)
        tmpfile.seek(-1,1)
        tmpfile.gets(temp_string_) // clear this line out
      }
  }

//** read_vdotfile() read .file in abbreviated format (see write_vsegs)
proc read_vdotfile() { local loc,entries,segments,ii
    entries=panobj.entries segments=panobj.segments
    panobj.bytes = 1
    for i=1,entries {  // read this abbreviated file version (much faster)
        tmpfile.scanstr(temp_string_)
        loc = tmpfile.scanvar()
        tmpobj = new vfile_line(temp_string_,-1,loc,segments) // don't set size
        panobj.llist.append(tmpobj)
        for ii=1,segments-1 { tmpobj.loc[ii] = tmpfile.scanvar() }
      }
  }

//** read_vsegs() read a file that is segmented with diff vectors at diff times
// (see outvecs)
func read_vsegs () { local segments,entries,i,ii,jj,sze,loc,ret,cloc,clocend,llen
    entries=panobj.entries segments=panobj.segments ret=1
    for i=1,entries { // usually will be the number of cells recorded
        cloc = tmpfile.tell()   // starting location in the file
        tmpfile.scanstr(temp_string_)
        tmpfile.scanstr(temp_string_) // name of a var
        sze = tmpfile.scanvar()   // size of the vector or time it was dumped
        loc = tmpfile.scanvar() + (tmpfile.tell() - cloc) // add line length
        cloc = tmpfile.tell()  // a location where a vec begins
        tmpobj = new vfile_line(temp_string_,sze,loc,segments)
        panobj.llist.append(tmpobj)
        for ii=1,segments-1 {  // go through all the different time segs
            for jj=1,entries-1 { // go through all the cells
                if ((ret = tmpfile.gets(temp_string_))==-1) { break } // EOF error
              }
            clocend = tmpfile.tell()  // loc of end of this seg
            tmpfile.scanstr(temp_string_) tmpfile.scanstr(temp_string_) // name of a var
            if (strcmp(temp_string_,tmpobj.name)!=0) {  // name should match
                printf("ERROR: %d not %d segs found (%s)\n",ii,segments,tmpobj.name) 
                segments = ii
                break
              }
            tmpfile.scanvar()  // a time 
            tmpobj.loc[ii] = tmpfile.scanvar()+(tmpfile.tell()-clocend) // where the vector starts
            clocend = tmpfile.tell()
          }
        tmpfile.seek(cloc)   // go back for next entry
      }
    tmpfile.seek(clocend)  // go to end of all this stuff
    return segments
  }

//** write_vsegs()
// write out names of all entries along with locations where the vecs start
proc write_vsegs () { local ii
    file_with_dot(filename,temp_string_,temp_string2_) // put .filename into temp_string_
    sprint(temp_string2_,"grep '^//[^bM]' %s > %s",xtmp,temp_string_)
    system(temp_string2_)  // copy the non-location lines into the new file
    tmpfile.aopen(temp_string_)
    tmpfile.printf("//MULTI %d %d\n",panobj.entries,panobj.segments) // redo in case differs
    for ltr(XO,panobj.llist) {
        tmpfile.printf("%s ",XO.name)
        for ii=0,panobj.segments-1 { tmpfile.printf("%d ",XO.loc[ii]) }
        tmpfile.printf("\n")
      }
    tmpfile.close()
  }

//** make_vdot_files() go through a list of filenames to convert into .file format
proc make_vdot_files () { local ii,sav,cnt
    cnt = panobjl.count()
    for ltr(XO,$o1) {
        filename = XO.s
        print "Processing ",filename
        read_vfile(cnt) // don't overwrite one that's being used
      }
  }

//* print out the CPU name
proc vfcpu () {
    sprint(temp_string_,"%s '^//CPU' %s",grep,$s1)
    system(temp_string_)
  }

//* rpanel() creates a panel from information in llist
proc rpanel () { local ii
    print $1
    attrnum = $1
    panobj = panobjl.object(attrnum)  
    if (panobj.llist.count > 8) { rlist($1) return }
    sprint(temp_string_,"#%d:%s ",attrnum,simname)
    xpanel(temp_string_)
    xlabel(panobj.filename)
  
    for ii=0,panobj.llist.count-1 {
        sprint(temp_string2_,"rv(%d,%d)",attrnum,ii)
        xbutton(panobj.llist.object(ii).name,temp_string2_)
      }
    sprint(temp_string_,"attrpanl(%d)",attrnum)
    xbutton("Attributes",temp_string_)
    sprint(temp_string_,"lpvec(filename,vrtmp,%g)",panobj.printStep)
    xbutton("Print last vec",temp_string_)
    xbutton("Erase","ge()")
    xpanel()
  }

//* rlist(): like rpanel() but puts up a browser list instead of a panel
proc rlist () {
    panobjl.object($1).llist.browser(panobjl.object($1).filename,"name")
    sprint(temp_string_,"rv(%d,hoc_ac_)",$1)
    panobjl.object($1).llist.accept_action(temp_string_)
  }

//* rvlist(): like rpanel() but puts up a browser list instead of a panel
proc rvlist () { local flag,attrnum,rdstr
    rdstr = 1
    flag = $1 attrnum = $2 
    if (numarg()==3) { recstr=$s3  rdstr=0 }
    if (flag==0) {
        panobjl.object(attrnum).llist.browser(panobjl.object(attrnum).filename,"name")
        sprint(temp_string_,"rvec(%d,hoc_ac_)",attrnum)
        panobjl.object(attrnum).llist.accept_action(temp_string_)
      } else if (flag==1) { // proc(vec)
        if (rdstr) string_dialog("Procedure name: proc, called as proc(vec)",recstr)
        panobjl.object(attrnum).llist.browser(recstr,"name")
        sprint(temp_string_,"{rvec(%d,hoc_ac_) %s(%s)}",attrnum,recstr,rvvec_name)
        panobjl.object(attrnum).llist.accept_action(temp_string_)
        print attrnum,":",recstr,":",temp_string_,":",rvvec_name
      } else if (flag==2) { // vec.command
        if (rdstr) string_dialog("comm: print vec.comm",recstr)
        panobjl.object(attrnum).llist.browser(recstr,"name")
        sprint(temp_string_,"{rvec(%d,hoc_ac_) print %s.%s}",attrnum,rvvec_name,recstr)
        panobjl.object(attrnum).llist.accept_action(temp_string_)
      }
  }

proc disptray() { print "Must load boxes.hoc to get trays" }
//* attrpanl() gives attributes for a set of graphs
proc attrpanl () { local ii,jj
    attrnum = $1 // use global for xbuttn
    sfunc.tail(panobjl.object(attrnum).filename,"data.*/",grvecstr)
    sprint(temp_string_,"#%d:%s:%s (ATTRPANL)",attrnum,simname,grvecstr)
    xpanel(temp_string_)
    xvarlabel(panobjl.object(attrnum).filename)
    xvarlabel(msg)  msg = panobjl.object(attrnum).comment
    sprint(temp_string_,"panobjl.object(%d).color",attrnum)
    xvalue("Color(-1=multi)",temp_string_,1)
    sprint(temp_string_,"panobjl.object(%d).line",attrnum)
    xvalue("Line",temp_string_,1)
    xstatebutton("Superimpose",&panobjl.object(attrnum).super,"gnum=-1")
    xvalue("Superimpose - Graph[#]","gnum",1)
    xbuttn("Graph limits","wvpanl(")
    xmenu("Manipulate graphs")
    xbutton("Mark","gvmarkflag=-(gvmarkflag-1) sprint(msg,\"Mark: %d\",gvmarkflag)")
    xbutton("Erase/redraw","gveraseflag=-(gveraseflag-1) sprint(msg,\"Erase: %d\",gveraseflag)")
    xbuttn("Label graphs","lblall(")
    xbuttn("Erase graphs","geall(")
    xbuttn("Remove graphs","remgrs(")
    sprint(temp_string2_,"disptray(%d)",attrnum)
    xbutton("Make tray",temp_string2_)
    sprint(temp_string2_,"setrange(%d,3)",attrnum)
    xbutton("Erase axes",temp_string2_)
    sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"View = plot\")",attrnum)
    xbutton("View = plot",temp_string2_)
    sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Crosshair\")",attrnum)
    xbutton("Crosshair",temp_string2_)
    sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"NewView\")",attrnum)
    xbutton("New view",temp_string2_)
    sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Delete\")",attrnum)
    xbutton("Delete Text",temp_string2_)
    sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Move Text\")",attrnum)
    xbutton("Move Text",temp_string2_)
    sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Change Text\")",attrnum)
    xbutton("Change Text",temp_string2_)
    xmenu()
    sprint(temp_string_,"panobjl.object(%d).remote",attrnum)
    sprint(temp_string2_,"grall(%d)",attrnum)
    xvalue("Graph all",temp_string_,0,temp_string2_)
    if (attrnum != 0) {
        xmenu("Manipulate vectors")
        xbutton("Vector name","string_dialog(\"Change Vector name\",rvvec_name)")
        xbuttn("Write to vector","rvlist(0,")
        xbuttn("Proc(vector)","rvlist(1,")
        xbuttn("vector.command","rvlist(2,")
        xmenu()
        xbuttn("Show full panel","rpanel(")
        xbuttn("Change file","fchooser(")
      } else {
        xbutton("Show full panel","pbrgr(\"Graph\",\"gv\")")
      }
    xpanel()
  }

// allows inclusion of attrnum for each item
proc xbuttn () { sprint(temp_string2_,"%s%d)",$s2,attrnum)  xbutton($s1,temp_string2_) }

//* set something for attrpanl() to value
func attrset () { local attrnum, ii
    if (numarg()==0) { printf("attrset(attrnum,\"thing\",val)\n") 
      } else if (numarg()==2) {
        sprint(temp_string_,"tempvar = panobjl.object(%d).%s",$1,$s2)
        execute(temp_string_)
        return tempvar
      } else { 
        sprint(temp_string_,"panobjl.object(%d).%s=%g",$1,$s2,$3)
        execute(temp_string_) 
        return $3
      }
  }

proc wvpanl () { local attrnum, ii
    attrnum = $1
    sfunc.tail(panobjl.object(attrnum).filename,"data.*/",grvecstr)
    sprint(temp_string_,"#%d:%s:%s (WVPANL)",attrnum,simname,grvecstr)
    xpanel(temp_string_)
    sprint(temp_string_,"%d Vectors",panobjl.object(attrnum).llist.count)
    xlabel(temp_string_)
    for ii=0,3 {
         sprint(temp_string_,"panobjl.object(%d).size[%d]",attrnum,ii)
         sprint(temp_string2_,"chrange(%d,%d)",attrnum,ii)
         xvalue(szstr[ii].s,temp_string_,0,temp_string2_)
      }
    sprint(temp_string_,"panobjl.object(%d).shift",attrnum)
    sprint(temp_string2_,"chrange(%d,-2)",attrnum)
    xvalue("Shift L/R",temp_string_,0,temp_string2_)
    sprint(temp_string2_,"chrange(%d,%d)",attrnum,-1)
    xmenu("Other")
    xbutton("Clear/Set to G0",temp_string2_)
    sprint(temp_string2_,"viewplot(%d)",attrnum)
    xbutton("View=plot",temp_string2_)
    sprint(temp_string2_,"setrange(%d,0,tstop,-90,50)",attrnum)
    xbutton("0,tstop,-90,50",temp_string2_)
    xbutton("Clean graph list","collapsegrs()")
    sprint(temp_string2_,"attrpanl(%d)",attrnum)
    xbutton("Attributes",temp_string2_)
    xmenu()
    xpanel()
    for ii=0,3 if (panobj.size[ii]==0) panobj.size[ii]=panobj.glist.object(0).size(ii+1)
  }

//* remgrs() gets rid of all of the graphs (called from attrpanl)
proc remgrs () { local ii,cnt
    if (isobj(graphItem,"Graph")) { graphItem.unmap graphItem = nil }
    panobj = panobjl.object($1)
    for ltr (XO,panobj.glist) XO.unmap()
    panobj.glist.remove_all
  }

//* collapsegrs () take off of glist graphs that have been closed on screen
proc collapsegrs () { local ii
    if (numarg()==0) { panobj = panobjl.object(0)
      } else { panobj = panobjl.object($1) }
    for (ii=panobj.glist.count-1;ii>=0;ii-=1) {
        if (panobj.glist.object(ii).view_count() == 0) { 
            panobj.glist.remove(ii)
          }
      }
  }

//* viewplot() set the world for each graph correctly
proc viewplot () { local cnt,ii,flag,sz1,sz2,sz3,sz4
    if (numarg()==2) flag=$2 else flag=-1
    if (flag==0) { sz1=sz3=1e10 sz2=sz4=-1e10 }
    panobj = panobjl.object($1)
    for ltr(XO,panobj.glist) {
        XO.size(&x[0])
        if (flag==0) { 
            if (x[0]<sz1) sz1=x[0]
            if (x[1]>sz2) sz2=x[1]
            if (x[2]<sz3) sz3=x[2]
            if (x[3]>sz4) sz4=x[3]
          } else if (flag==9) {
            XO.size(0,tstop,x[2],x[3])
          } else { XO.size(x[0],x[1],x[2],x[3]) }
      }
    if (flag==9) { panobj.size[0]=0 panobj.size[1]=tstop }
    if (flag==0) for ltr(XO,panobj.glist) XO.size(sz1,sz2,sz3,sz4)
  }

//* nvwall() changes the size of the graphs
proc nvwall () { local cnt,ii,sz1,sz2,sz3,sz4,wd,ht
    panobj = panobjl.object($1)
    if (numarg()==3) { wd=$2 ht=$3 } else { wd=panobj.vsz[0] ht=panobj.vsz[1] }
    cnt = panobj.glist.count()
    for (ii=cnt-1;ii>=0;ii=ii-1) { 
        if (panobj.glist.object(ii).view_count()==0) {panobj.glist.remove(ii)
          } else {
            sz1 = panobj.glist.object(ii).size(1)
            sz2 = panobj.glist.object(ii).size(2)
            sz3 = panobj.glist.object(ii).size(3)
            sz4 = panobj.glist.object(ii).size(4)
            panobj.glist.object(ii).unmap()
            panobj.vloc = panobj.vloc+panobj.vjmp
            if (panobj.vloc > 700) { panobj.vloc = 0 }
            panobj.glist.object(ii).view(sz1,sz3,sz2-sz1,sz4-sz3,0,panobj.vloc,wd,ht)
          }
      }
  }

//* geall() erases all of the graphs
proc geall () { local cnt,ii
    panobj = panobjl.object($1)
    cnt = panobj.glist.count()
    for ii=0,cnt-1 { 
        panobj.glist.object(ii).erase_all()
      }
  }

//* lblall(attrnum,label,#,xloc,yloc) put label on all of the graphs
// arg3 tells which single graph to put it on
proc lblall () { local cnt,ii,min,max,attrnum,lx,ly
    if (numarg()==0) { printf("lblall(attrnum[,loc])\n")  return }
    attrnum = $1 panobj = panobjl.object(attrnum)
    cnt = panobj.glist.count()
    if (numarg()>2) { min=max=$3 } else { min=0 max=cnt-1 }
    if (numarg()==5) { lx=$4 ly=$5 } else { lx=0.1 ly=0.8 }
    if (numarg()>1) { if (sfunc.len($s2)>0) { temp_string_ = $s2
        }} else if (attrnum==0) { temp_string_ = comment 
      } else sprint(temp_string_,"%s",panobjl.object(0).comment)
    for ii=min,max { 
        panobj.glist.object(ii).color(panobj.color)
        panobj.glist.object(ii).label(lx,ly,temp_string_)
        // if (attrnum!=0&&ii<panobj.llist.count()) panobj.glist.object(ii).label(panobj.llist.object(ii).name)
      }
  }

//* relbl() put appropriate label on all of the graphs
proc relbl () { local cnt,ii,min,max,attrnum,lx,ly
    if (numarg()==0) { printf("relbl(attrnum[,str])\n")  return }
    attrnum = $1 panobj = panobjl.object(attrnum)
    cnt = panobj.glist.count()
    if (numarg()==4) { lx=$3 ly=$4 } else { lx=0.1 ly=0.8 }
    if (numarg()>1) panobj.glist.object(0).label($s2)
    for ltr2(XO,YO,panobj.glist,panobj.llist) {
        XO.color(0)
        if (attrnum==0) XO.label(0.,.9,YO.var) else XO.label(0.,.9,YO.name) 
        XO.color(panobj.color)
        XO.label(lx,ly,YO.vec.label)
      }
  }

//* grall() graphs all of the lines from the file
// use vector $o2 as indices for vectors (see tposvec)
proc grall () { local attrnum,cnt,ii,min,max,gr,skip,iskp,vind
    if (numarg()==0) {printf("grall(attrnum[,min,max,remote,gr_offset,skipgr,iskp]): graph vectors.\n")
        return }
    attrnum=$1  vind=0
    panobj = panobjl.object(attrnum)
    if (attrnum == 0) cnt = printlist.count() else cnt = panobj.llist.count()
    // will reset max if is vector with numarg()==2
    if (numarg()>2) { min=$2 max=$3 } else { min=0 max=cnt-1 }
    // with 2 args, vector $o2 gives indices for vectors (see tposvec)
    if (numarg()>=2) if (argtype(2)==1) { vind=1 min=0 max=$o2.size-1 }
    if (numarg()>3) { panobj.super=1 panobj.remote=$4 }
    if (numarg()>4) gr=$5 else gr=0
    if (numarg()>5) skip=$6 else skip=1
    if (numarg()>6) iskp=$7 else iskp=1
    if (iskp==0) iskp=1 if (skip==0) skip=1
    if (panobj.super==1 && panobj.remote==attrnum && panobj.glist.count==0) { 
        remgrs(attrnum)
        print "Creating plot"
        skip=0
        newPlot(0,tstop,-100,100) panobj.glist.append(graphItem)}
    if (panobj.super==0 && panobj.glist.count==0) panobj.size[1]=0
    for (ii=min;ii<=max;ii+=iskp) {
        if (panobj.super == 1) { 
            if (gr >= panobjl.object(panobj.remote).glist.count()) break
            graphItem = panobjl.object(panobj.remote).glist.object(gr) 
            gr=gr+skip
          }
        if (vind) rv($1,$o2.x[ii]) else rv($1,ii)
      }
  }

// tposvec(rows,cols): generate the indices for a transposed matrix of rows x cols
proc tposvec () { local rows,cols,i,j
    rows=$2 cols=$3
    $o1.resize($2*$3)
    for (i=0;i<rows;i+=1) for (j=0;j<cols;j+=1) $o1.x[j*rows+i]=i*cols+j
  }

// fliptb(rows,cols): generate the indices for a transposed matrix of rows x cols
proc fliptb () { local rows,cols,i,j,p
    rows=$2 cols=$3
    if ($o1.size != $2*$3) {print "Wrong size vector in fliptb()" return}
    p = allocvecs(1) mso[p].resize(rows)
    for (j=0;j<cols;j+=1) {
        mso[p].copy($o1,j*rows,(j+1)*rows-1)
        mso[p].reverse
        $o1.copy(mso[p],j*rows)
      }
  }

//* setrange() sets the range
// setrange(attrnum,x0,x1,y0,y1)
proc setrange () { local i,ii
    if (numarg()==0){print "setrange(attrnum,x0,x1,y0,y1)\n setrange(attrnum,3) erases axes" return}
    panobj = panobjl.object($1)
    if (numarg()==1) { for ltr(XO,panobj.glist) XO.size(0,tstop,-100,50)
      } else if (numarg()==2) { for ltr(XO,panobj.glist) XO.xaxis(3)
      } else if (numarg()==3) { for ltr(XO,panobj.glist) XO.size(0,tstop,$2,$3)
      } else {
        panobj.size[0]=$2
        for ltr(XO,panobj.glist) XO.size($2,$3,$4,$5)
        for i=2,5 panobj.size[i-2]=$i
      }
    for ii=0,3 if (panobj.size[ii]==0) panobj.size[ii]=panobj.glist.object(0).size(ii+1)
  }

//* grransel() -- graph range select
proc setgrransel () { local attrnum
    attrnum=$1
    panobj = panobjl.object(attrnum)
    for ltr(XO,panobj.glist) { 
        XO.menu_remove("REVIEW")
        sprint(tstr,"proc p%d%d(){grransel($1,$2,$3,$4,%d,%d,%s)}",attrnum,i1,attrnum,i1,XO)
        execute1(tstr)
        sprint(tstr,"p%d%d",attrnum,i1)
        XO.menu_tool("REVIEW", tstr)
        XO.exec_menu("REVIEW")
      }
  }
  
//** grransel(): CTL-hit == Crosshair
//               SHT-hit == resize
//               hit-drag-release == show in square
//               SHT-hit-drag-release == show new thing there
// Type: press (2), drag (1), release (3)
// Keystate: META-SHT-CTL eg 101=5 is META-CTL
grrcnt=-1
proc grransel () { local type, x0, y0, keystate, ii, attrnum, gr
    type=$1 x0=$2 y0=$3 keystate=$4 attrnum=$5 gr=$6
    graphItem=$o7 // = panobj.glist.object(gr)
    panobj=panobjl.object(attrnum)
    if (keystate==1 && type==2) { graphItem.exec_menu("Crosshair") // CTL-MOUSE-1
      } else if (keystate==3 && type==3) { 
        print grrcnt
        if (grrcnt>-1) { printf("Graphing %s\n",printlist.object(grrcnt).var)
            graphItem.erase_all()
            rv(attrnum,grrcnt) 
            graphItem.exec_menu("View = plot")
          }
        graphItem.size(panobj.size[0],panobj.size[1],panobj.size[2],panobj.size[3])
      } else if (keystate==2 && type==2) { grrcnt=-1
      } else if (keystate==2 && type==1) { 
        x+=1 // slow it down five-fold
        if (x>5) { grrcnt=(grrcnt+1)%printlist.count
            printf("%d: %s\n",grrcnt,printlist.object(grrcnt).var)
            x=0
          }
      } else if (keystate==0 && type==2) { x=x0 y=y0 } else if (keystate==0 && type==3) {
        graphItem.size(x,x0,y,y0) // resize to chosen square
      } 
  }

//* chrange() changes range for a set of graphs (called from attrpanl)
luprd=0
proc chrange () { local cnt, flag, ii, sz1, sz2, sz3, sz4
    if (numarg()==2) { flag = $2 } else { flag = -1 }
    panobj = panobjl.object($1)
    cnt = panobj.glist.count()
    for (ii=cnt-1;ii>=0;ii=ii-1) if (panobj.glist.object(ii).view_count() == 0) panobj.glist.remove(ii)
    cnt = panobj.glist.count() // check again after removing any with no views
    if (cnt==0) { for ii=0,3 panobj.size[ii]=0 return }
    // flag -1 means set everything from the first graph
    if (flag==-1) for ii=0,3 panobj.size[ii] = panobj.glist.object(0).size(ii+1)
    if (flag==-2) for ii=0+luprd,1+luprd panobj.size[ii] += panobj.shift // shift right or left
    if (flag==5) { panobj.size[0]=0 panobj.size[1]=tstop } // just set x
    // for each of the graphs
    for ltr(XO,panobj.glist) {
        sz1=XO.size(1) sz2=XO.size(2) sz3=XO.size(3) sz4=XO.size(4)
        if (flag==0) XO.size(panobj.size[0],sz2,sz3,sz4)
        if (flag==1) XO.size(sz1,panobj.size[1],sz3,sz4)
        if (flag==2) XO.size(sz1,sz2,panobj.size[2],sz4)
        if (flag==3) XO.size(sz1,sz2,sz3,panobj.size[3])
        if (flag==-1 || flag==4) XO.size(panobj.size[0],panobj.size[1],panobj.size[2],panobj.size[3])
        if ((flag==-2 && !luprd) || flag==5) XO.size(panobj.size[0],panobj.size[1],sz3,sz4)
        if (flag==-2 && luprd) XO.size(sz1,sz2,panobj.size[2],panobj.size[3])
      }
    for ii=0,3 if (panobj.size[ii]==0) panobj.size[ii]=panobj.glist.object(0).size(ii+1)
  }

//* rtvec() reads tvec if it exists, returns -1 if it doesn't
// rtvec(attrnum)
func rtvec () { local attrnum,inx,inx2
    attrnum = $1
    panobj = panobjl.object(attrnum)
    if (panobj.tloc > 0) {
        tmpfile.seek(panobj.tloc)
        panobj.tvec.vread(tmpfile)
        return 1
      } else {
        return 0
      }
  }

//* rv() reads line of vector file into IV graph via vector
// rv(attrnum,llist_ind1[,llist_ind2])
func round () { if ($1>0) return int($1+0.5) else return int($1-0.5) } // round off to nearest integer
// rvaltdisp(tvec,vec,name)
func rvaltdisp () { return 0 } // if returns 1 means there is an alternate display for rv
proc rv2 () { }  // stub for manipulating the vectors before graphing
proc rv () { local attrnum,inx,inx2
    // open the file and go to correct position
    if (numarg() == 0) { print "rv(attrnum,ind1,ind2) reads into vrtmp bzw vec" return }
    attrnum = $1
    inx = $2
    if (panobj.printStep>0 && numarg() > 2) { inx2 = $3 } else { inx2 = -1 }
    if (attrnum==0) { gv(inx) return }
    rv_readvec(attrnum,inx,vrtmp)  // will set panobj
    rv2(vrtmp)
    // create a new plot if necessary and set color
    nvplt(vrtmp)
    if (vrtmp.size==0) { // assume this is a spike train in tvec
        ind.resize(panobj.tvec.size) ind.fill(0)
        ind.mark(graphItem,panobj.tvec,"O",panobj.line+4,panobj.curcol)
        // grrtsize()
      } else if (inx2>-1) {
        rv_readvec(attrnum,inx2,vec)
        graphItem.size(0,vrtmp.max,0,vec.max)
        if (numarg() > 3) {
            vec.mark(graphItem,vrtmp,$s4,6,panobj.curcol)
          } else {
            vec.mark(graphItem,vrtmp,"O",6,panobj.curcol)
          }
      } else if (panobj.printStep<0) {
        if (gvmarkflag) {
            if (! rvaltdisp(panobj.tvec,vrtmp,panobj.llist.object(inx).name)) {
                vrtmp.mark(graphItem,panobj.tvec,"O",4,panobj.curcol,panobj.line) 
                graphItem.exec_menu("View = plot")
              }
          } else if (numarg() >= 3) {
            vrtmp.apply("round") // round off this index vector
            vrtmp.mark(graphItem,panobj.tvec,"O",$3,panobj.curcol,panobj.line) 
          } else {
            vrtmp.line(graphItem,panobj.tvec,panobj.curcol,panobj.line) }
      } else {
        vrtmp.line(graphItem,panobj.printStep,panobj.curcol,panobj.line) }
    // graph it and label the graph
    if (sfunc.substr(panobj.filename,"batch")!=-1 || \
        sfunc.substr(panobj.filename,"data")==-1) {
        grvecstr = panobj.filename
        } else { sfunc.tail(panobj.filename,"data",grvecstr) }
    sprint(grvecstr,"%s:%s",grvecstr,panobj.llist.object(inx).name)
    if (panobj.super == 0 && labelm) { graphItem.label(0,0.9,grvecstr)
      } else if (labelm) graphItem.label(0.5,0.9,grvecstr)
  }

// rv_readvec(attrnum,index,vec)
// read vector #index from file associated with attrnum into vector vec
proc rv_readvec () { local size,attrnum,inx,ii
    attrnum = $1
    inx = $2
    panobj = panobjl.object(attrnum)
    tmpfile.getname(temp_string_)
    if (strcmp(temp_string_,panobj.filename)!=0 || tmpfile.isopen()==0) {
        if (! tmpfile.ropen(panobj.filename)) { 
            print "ERROR rv() can't read ",panobj.filename return }}
    tmpfile.seek(panobj.llist.object(inx).loc)
    if (panobj.bytes) { 
        if (panobj.printStep==-2) { panobj.tvec.vread(tmpfile) }
        if (numarg()==4) { $o3.vread(tmpfile) $o4.vread(tmpfile) } else {
            $o3.vread(tmpfile) }
        if (panobj.segments>1) {
            tmpvec = new Vector($o3.size)
            for ii=1,panobj.segments-1 {
                tmpfile.seek(panobj.llist.object(inx).loc[ii])
                tmpvec.vread(tmpfile)
                $o3.copy(tmpvec,$o3.size)
              }
            tmpvec = nil
          }
      } else {
        tmpfile.scanstr(temp_string_) // get rid of '//'
        size = tmpfile.scanvar()
        tmpfile.scanvar() // get rid of the seek number
        $o3.scanf(tmpfile,size)
      }
  }

//* read vector iterator rvtr
// usage 'for rvtr(vec,#) XO.vec.printf' where # is attrpanl#
// not debugged for presence of tvec in cvode
iterator rvtr() { local i
    if (numarg()==3) {$&3=0} else {i1 = 0}
    attrnum=$2
    panobj=panobjl.object(attrnum)
    for i = 0, panobj.entries - 1 {
        rv_readvec(attrnum,i,$o1)    
        iterator_statement
        if (numarg()==3) { $&3+=1 } else { i1+=1 }
      }
  }

//* rvec(attrnum,num[,vec]) writes to vec, or contents of rvvec_name or
//  to vector of same name if rvvec_name is empty
proc rvec () { local flag,ln,on
    flag=0 ln=$1
    if (sfunc.len(rvvec_name)==0) flag=1
    if (numarg()<2) on=hoc_ac_ else on=$2
    if (numarg()>2) sprint(rvvec_name,"%s",$o3)
    if (sfunc.len(rvvec_name)==0) rvvec_name=panobjl.object(ln).llist.object(on).name 
    printf("Copying %s to %s\n",panobjl.object(ln).llist.object(on).name,rvvec_name) 
    sprint(temp_string_,"rv_readvec(%d,%d,%s)",ln,on,rvvec_name)
    if (flag) rvvec_name="" // clear it again
    if (! execute1(temp_string_)) print "ERROR: Declare target as a vector"
    if (numarg()==4) $o4.copy(panobj.tvec)
  }

//* rvl() reads line of vector file into IV graph via vector
// rvl(attrnum,name,pos[,pos2,pos3,...])
proc rvl () { local i
    // open the file and go to correct position
    panobj=panobjl.object($1)
    tmpfile.getname(temp_string_)
    if (strcmp(temp_string_,panobj.filename)!=0 || tmpfile.isopen()==0) {
        tmpfile.ropen(panobj.filename) }  // only open if necessary
    if (tmpfile.isopen==0) { printf("ERROR: %s not found.\n",panobj.filename)
          return }
    if (numarg() == 3) { 
        tmpfile.seek($3)
        tmpfile.gets(temp_string_) // throw away line
        vrtmp.vread(tmpfile)
      } else {
        tmpvec = new Vector()
        for i=3,numarg() {
            tmpfile.seek($i)
            tmpvec.vread(tmpfile)
            vrtmp.copy(tmpvec,vrtmp.size)
          } 
      }
    tmpvec = nil
    nvplt(vrtmp)
    vrtmp.line(graphItem,panobj.printStep,panobj.curcol,panobj.line)
    // graph it and label the graph
    if (sfunc.substr(panobj.filename,"batch")!=-1) { grvecstr = panobj.filename
      } else { sfunc.tail(panobj.filename,"data",grvecstr) }
    sprint(grvecstr,"%s:%s",grvecstr,$s2)
    if (panobj.super==0 && labelm) { graphItem.label(0,0.9,grvecstr)
      } else if (labelm) graphItem.label(grvecstr)
  }

//* read_file(file,cols[,length]): read multicolumn file
//  see /u/billl/nrniv/jun/tidata/proc.hoc for improved version
func read_file() { local ii,cols,pt,length
    if (numarg()==0) { print "\tread_file(\"file\",cols)"
        print "\t(must set tstop and printStep.)"
        return 0
      }
    panobjl.object(0).printStep = use_lvardt_ = using_cvode_ = 0
    print "WARNING: Turning off cvode."
    if (numarg()==3) { length = $3 } else { length=tstop/printStep }
    cols = $2
    if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) return 0}
    printlist.remove_all()
    tmpfile.scanstr(temp_string_)  pt = 0
    // skip over a comment line; note that this will skip extra line if comment line is
    // just one word long
    while (sfunc.head(temp_string_,"[^-+0-9.e]",temp_string2_) != -1) {
        tmpfile.gets(temp_string_)  // first word in line was not a number so next line
        pt = tmpfile.tell()         // location at next line
        tmpfile.scanstr(temp_string_) // get first word here
        print temp_string2_
      }
    for ii=1,cols { // pick up all of the columns
        tmpfile.seek(pt)
        vrtmp.scanf(tmpfile,length,ii,cols)
        new_printlist_item("col",ii,vrtmp)
      }
    return 1
  }

//* read_rfile(file): read multirow file
//  use col2row to transpose columnar file first
proc read_rfile() { local num
    if (numarg()==0) { print "\tread_rfile(\"file\")" return }
    if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) return}
    printlist.remove_all()
    while (tmpfile.scanstr(temp_string_) != -1) {  // read lines
        num = tmpfile.scanvar() // pick up number of items in col
        vrtmp.scanf(tmpfile,num)
        new_printlist_item(temp_string_,vrtmp)
      }
  }

// restore_plist() restores the plist from a file in an attrnum
proc restore_plist () { local cnt,ii,attrnum,savlvar
    printlist.remove_all
    attrnum = $1
    panobj=panobjl.object(attrnum)
    panobjl.object(0).printStep=panobj.printStep
    if (panobj.printStep == -2) use_lvardt_=1 else use_lvardt=0
    cnt = panobj.llist.count()
    for ii=0,cnt-1 {
        vite = new vitem(panobj.llist.object(ii).name,0)
        rv_readvec(attrnum,ii,vite.vec)
        if (use_lvardt_) vite.tvec.copy(panobj.tvec)
        printlist.append(vite)
        vite=nil
      }
    if (use_lvardt_) tstop=panobj.tvec.max
  }

//* sgv() print out spikes from IF recordings like spkt()
proc sgv () {  local cl
    if (numarg()==1) cl=$1 else cl=1
    sgv1()
    nvplt(ind)
    panobj.curcol=cl
    // g.erase_all()
    vec.mark(graphItem,ind,"O",panobj.line+4,panobj.curcol,4)
    graphItem.size(0,ind.max+1,0,tstop)
  }

proc sgv1 () { 
    revec(ind) revec(vec)
    for ltr(XO,printlist) if (XO.vec.size==0) {
        szt=XO.tvec.size
        if (szt>0) {
            szi=ind.size 
            vec.append(XO.tvec)
            ind.resize(szi+szt)
            ind.fill(i1,szi,szi+szt-1)
          }
      }
  }

//* gv(vnum) graphs vector
proc gv () {  local inx
    ulv()
    inx=-1
    if (numarg()==0) { inx = hoc_ac_ } else { 
        if (argtype(1)==0) inx = $1
        if (argtype(1)==2) {
            for ltr(XO,printlist) if (strm(XO.var,$s1)) inx=i1
            if (inx==-1) {print $s1," not found" return }}
      }
    panobj = panobjl.object(0)
    if (use_lvardt_) { panobj.tvec = printlist.object(inx).tvec }
    XO = printlist.object(inx).vec
    if (XO.size==0) { // assume that this is spk trace
        if (panobj.tvec.size==0) { printf("\tNO SPIKES IN %s\n",printlist.object(inx).var)
          } else {
            nvplt(panobj.tvec)
            ind.resize(panobj.tvec.size) ind.fill(1)
            ind.mark(graphItem,panobj.tvec,"O",panobj.line+3,panobj.curcol)
            // grrtsize()
          }
        return
      } else nvplt(XO)
    if (gvmarkflag) {
        XO.mark(graphItem,panobj.tvec,"O",panobj.line+3,panobj.curcol)
        graphItem.exec_menu("View = plot")
      } else if (using_cvode_) {
        XO.line(graphItem,panobj.tvec,panobj.curcol,panobj.line)
      } else {
        XO.line(graphItem,printStep,panobj.curcol,panobj.line)
      }
    if (labelm) graphItem.label(0.,0.9,printlist.object(inx).var)
  }
proc gvmt () { gvmarkflag=-(gvmarkflag-1) printf("gv Mark: %d\n",gvmarkflag) }

//* dispspks() display spike times
proc dispspks () { local attrnum,n
    attrnum = $1  n=0
    panobj=panobjl.object(attrnum)
    if (panobj.super == 1) { 
        graphItem = panobj.glist.object(panobj.glist.count-1)
      } else {
        newPlot(0,1,0,1)
        panobj.glist.append(graphItem)
      }
    if (attrnum==0) {for ltr(XO,printlist) dispspks2(XO.var,XO.tvec,i1)
      } else for ltr(XO,panobj.llist) {
        rv_readvec(attrnum,i1,ind) // ind is scratch here since info in tvec
        dispspks2(XO.name,panobj.tvec,i1) 
      }
    grrtsize()
  }

// $s1 name, $o2 tvec, $3 n
proc dispspks2 () { local n,col
    n=$3
    col = panobj.curcol
    if (sfunc.substr($s1,"_spks")) {
        if ($o2.size>0) {
            ind.resize($o2.size) ind.fill(n)
            if (sfunc.substr($s1,"NetStim")!=-1) col+=1
            ind.mark(graphItem,$o2,"O",panobj.line+4,col)
          }
      }
  }

//** grrtsize() use view=plot and then pad a little
proc grrtsize () { local h,w,frac
    if (numarg()>=1) tmpobj=$o1 else tmpobj=graphItem
    if (numarg()>=2) frac = $2 else frac=.05
    tmpobj.exec_menu("View = plot")
    tmpobj.size(&x)
    w=frac*(x[1]-x[0])  h=frac*(x[3]-x[2])
    x[0]-=2*w x[1]+=w x[2]-=4*h x[3]+=h // need extra padding on bottom
    tmpobj.size(x[0],x[1],x[2],x[3])
  }

//* gvv() like gv() but give it vector statt vnum
proc gvv () {  local inx
    nvplt($o1)
    if (numarg()==1) {
        $o1.line(graphItem,printStep,panobj.curcol,panobj.line)
      } else { 
        $o1.line(graphItem,$o2,panobj.curcol,panobj.line)
        graphItem.size($o2.min,$o2.max,$o1.min,$o1.max)
      }
  }

//* ge() erases IV graph
proc ge () { if (numarg()==0) graphItem.erase_all() else g[$1].erase_all }

//* pvall() dumps all vectors to output_file
// Save logic:
// 1) Interactive mode: you're watching simulations while printing out
// data.  You see something you like and save it - the runnum in the
// index file then corrsponds to the number on the data file, it is
// subsequently augmented
// 2) Batch mode: you're running very long sims and saving directly to
// vector files.  You put together a simulation you want and save it
// immediately rather than waiting for the sim to return (in 1 or 2
// days).  To correspond, the data file (v*) must then be numbered
// 'runnum-dec_runnum'
proc pvall () { 
    sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum)
    while (tmpfile.ropen(output_file)) { runnum = runnum+1
        sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum) 
      }
    if (numarg()>0) { comment = $s1 // a comment
      } else {
        sprint(temp_string_,"%s.%02d",datestr,runnum-dec_runnum) 
        if (sfunc.substr(comment,temp_string_) == -1) { comment = "" } // clear comment
      }
    printf("Saving to %s\n",output_file)
    pvplist(output_file,comment)
    sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum)
  }

// pvplist(file,comment) print out the printlist with comment at head
proc pvother () {}  // user can dump other vectors at top with prvec()
proc pvplist () { local inx
    ulv()
    file_with_dot($s1,temp_string_,temp_string2_) // put .filename into temp_string_
    if (tmpfile.ropen(temp_string_)) { printf("WARNING: removing %s\n",temp_string_)
        sprint(temp_string_,"rm %s",temp_string_) system(temp_string_) }
    if (tmpfile.wopen($s1)==0) { print "Can't open ",$s1  return}
    tmpfile.printf("//: %s\n",$s2) // comment
    pvplist1()
    if (byte_store) {tmpfile.printf("//CPU %s\n",uname)}
    pvout()
    tmpfile.close()
  }

proc pvplist1 () {
    if (use_lvardt_) {
        tmpfile.printf("//printStep -2\n")
      } else if (using_cvode_) {
        tmpfile.printf("//printStep -1\n")
      } else {
        tmpfile.printf("//printStep %g\n",printStep)
      }
  }

// pvnext() append another printlist set to same file
proc pvnext() { local ii
    if ($1==0) { 
        pvall(comment)
        sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-1) // decrement back to name
        return
      }
    tmpfile.aopen(output_file)
    pvout()
    printf("Append to %s\n",output_file)
    tmpfile.close()
  }

// prout() called by pvplist() and pvnext(), actually puts out the vecs
proc pvout () {
    ulv()
    if (!use_lvardt_ && using_cvode_) { prvec("tvec",panobjl.object(0).tvec,tvec_bytesize) } // save precise times
    pvother()
    for ltr(XO,printlist) { // no whitespace allowed
        if (sfunc.len(XO.vec.label)>0) sprint(temp_string_,"%s__(%s)",XO.vec.label,XO.var) else {
            temp_string_=XO.var } 
        if (byte_store) {
            tmpfile.printf("//b%d %s %d %d\n",byte_store,temp_string_,XO.vec.size,tmpfile.tell())
            if (use_lvardt_==1) if (eqobj(XO.tvec,nil)) { 
                print "ERROR: can't save under cvode_local, must recreate printlist\n" 
                return 
              } else { XO.tvec.vwrite(tmpfile,tvec_bytesize) }
            XO.vec.vwrite(tmpfile,byte_store)
            tmpfile.printf("\n")
          } else {
            tmpfile.printf("// %s %d %d\n",temp_string_,XO.vec.size,tmpfile.tell())
            XO.vec.printf(tmpfile)
          }
      }
  }

// prvec(name,vec,byte_flag[,file])  byte_flag=0 means printf
proc prvec () { local bflag
    if (numarg()==0) { print "prvec(name,vec,byte_flag[,file])" return}
    if (numarg()>3) { tmpfile.aopen($s4) }
    bflag = $3
    tmpfile.printf("//b%d %s %d %d\n",bflag,$s1,$o2.size,tmpfile.tell())
    if (bflag==0) {
        $o2.printf(tmpfile)    
      } else { $o2.vwrite(tmpfile,bflag) tmpfile.printf("\n") }
    if (numarg()>3) { tmpfile.close() }
  }

//* pv() dumps a single vector into output_file
proc pv () { local inx
    sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum)
    if (numarg()==0) { inx = hoc_ac_ } else { inx = $1 }
    printf("Printing %s to %s\n",printlist.object(inx).var,output_file)
    temp_string_ = printlist.object(inx).var
    // string_dialog("Name for saved vector",temp_string_)
    if (tmpfile.ropen(output_file)) { // file exists already
        tmpfile.close()
        tmpfile.aopen(output_file)
        printf("Appending to ",output_file)
      } else {
        tmpfile.wopen(output_file)
        tmpfile.printf("//: %s\n",comment)
        pvplist1()
      }
    if (byte_store) {
        tmpfile.printf("//b%d %s %d %d\n",byte_store,temp_string_,\
                       printlist.object(inx).vec.size,tmpfile.tell())
        if (use_lvardt_==1) if (eqobj(printlist.object(inx).tvec,nil)) { 
            print "ERROR: can't save under cvode_local, must recreate printlist\n" 
            return 
          } else { printlist.object(inx).tvec.vwrite(tmpfile,tvec_bytesize) }
        printlist.object(inx).vec.vwrite(tmpfile,byte_store)
        tmpfile.printf("\n")
      } else {
        tmpfile.printf("// %s %d %d\n",temp_string_,\
                       printlist.object(inx).vec.size,tmpfile.tell())
        printlist.object(inx).vec.printf(tmpfile)
      }
    tmpfile.close()
  }

//* lpv() calls lpvec from printlist
proc lpv () { local inx
    if (numarg()==0) { inx = hoc_ac_ } else { inx = $1 }
    sprint(temp_string_,"%s.%02d:%s",datestr,runnum-dec_runnum,printlist.object(inx).var)
    lpvec(temp_string_,printlist.object(inx).vec,printStep)
  }

//* lpvec(title,vector,printstep) dumps a single vector onto the printer using jgraph
proc lpvec () { local inx,ii
    tmpfile.wopen("lptmp")
    tmpfile.printf("newgraph\nnewcurve pts\n")
    for ii = 0,$o2.size-1 {
        tmpfile.printf("%g ",ii*$3)
        $o2.printf(tmpfile,"%g",ii,ii)
      }
    tmpfile.printf("marktype none\nlinetype solid\ntitle : %s\n",$s1)
    tmpfile.close()
    system("jgraph -P lptmp > lptmp2")
    system("lpt lptmp2")
  }

//* phase planes
//** gppl(n1,n2) graph phase planes from printlist
proc gppl () {
    newPlot(0,1,0,1)
    panobjl.object(0).glist.append(graphItem)
    printlist.object($2).vec.line(graphItem,printlist.object($1).vec)
  }

//* routines for printing out in sections

//** outvec_init([output_file,comment])
proc outvec_init() { local segs
    if (numarg()>0) { output_file = $s1 } else {
        sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum)
        while (tmpfile.ropen(output_file)) { runnum = runnum+1 // don't allow an overwrite
            sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum) }
      }
    if (numarg()>1) { comment = $s2 }
    print "\nOutput to ",output_file
    if (print_flag) { print "WARNING: print_flag=1 --> 0\n"
        print_flag = 0 }
    if (outvecint==0 || outvecint>tstop) {
        printf("WARNING: outvecint being set to tstop\n")
        outvecint = tstop }
    outvect = outvecint
    segs = int(tstop/outvecint)
    if (tstop/outvecint > segs) { segs=segs+1 }
    tmpfile.wopen(output_file)
    if (strcmp(comment,"")!=0) { tmpfile.printf("//: %s\n",comment) }
    tmpfile.printf("//printStep %g\n",printStep)
    tmpfile.printf("//MULTI %d %d\n",printlist.count,segs)
    tmpfile.close()
  }

//** outvecs()  : print out the vectors and reset them for recording
proc outvecs () { local ii
    if (t<outvect || outvecint == 0) { return }
    tmpfile.aopen(output_file)
    for ii=0,printlist.count-1 {
        tmpfile.printf("//b%d %s %d %d\n",byte_store,printlist.object(ii).var,t-outvecint,tmpfile.tell())
        printlist.object(ii).vec.vwrite(tmpfile,byte_store)
        tmpfile.printf("\n")
        printlist.object(ii).vec.play_remove()
        sprint(temp_string_,"printlist.object(%d).vec.record(&%s,%g)",\
               ii,printlist.object(ii).var,printStep)
        execute(temp_string_)
      }
    tmpfile.close
    outvect = outvect+outvecint
  }

//** outvec_finish () : put out the last section if needed, update the output_file name
proc outvec_finish() {
    if (t > outvect-outvecint+2*dt) {
        tmpfile.aopen(output_file)
        for ii=0,printlist.count-1 {
            tmpfile.printf("//b%d %s %d %d\n",byte_store,printlist.object(ii).var,t-outvecint,tmpfile.tell())
            printlist.object(ii).vec.vwrite(tmpfile,byte_store)
            tmpfile.printf("\n")
          }
        tmpfile.close()
      }
  }

//* utility programs (not all used)
gnum=-1
proc nvplt () { local xs,ys,flag
    if (panobj.super == 0) flag=1 else {
        if (gnum>-1) {
            sprint(tstr,"x=Graph[%d].view_count",gnum)
            if (execute1(tstr,0)) if (x>0) {  // use Graph[gnum] if exists and has views
                graphItem=Graph[gnum] flag=0
              }                                 // else use graphItem if has views
          } else if (isobj(graphItem,"Graph")) if (graphItem.view_count() > 0) { 
            flag=0
          } else { flag=1 }                   // else need new graph
      }
    if (flag) {
        if (panobj.printStep==0) { panobj.printStep=printStep }
        if (panobj.size[1] != 0) { // xmax is set
            newpl(panobj.size[0],panobj.size[1],panobj.size[2],panobj.size[3])
          } else if (panobj.printStep<0) {
            newpl(0,panobj.tvec.max,$o1.min,$o1.max)
          } else {
            newpl(0,$o1.size()*panobj.printStep,$o1.min,$o1.max)
          }
        panobj.glist.append(graphItem)
      } else if (gveraseflag) graphItem.erase_all
    if (panobj.color == -1) {
        panobj.curcol += 1
        if (panobj.curcol == 0 || panobj.curcol>7) panobj.curcol = 1 
      } else panobj.curcol = panobj.color
    graphItem.color(panobj.curcol)
    g=graphItem
  }

double wvloc[4]
{wvloc[0]=50 wvloc[1]=50 wvloc[2]=800 wvloc[3]=150}
proc newpl () { local w,h
    if (numarg()==5) newPlot($1,$2,$3,$4) // 5th arg is flag
    if (numarg()==8) {wvloc[0]=$5 wvloc[1]=$6 wvloc[2]=$7 wvloc[3]=$8}
    graphItem = new Graph(0)
    graphItem.xaxis()	// view axis for x and y
    graphItem.view($1,$3,$2-$1,$4-$3,wvloc[0],wvloc[1],wvloc[2],wvloc[3])
  }

proc gs () { g=Graph[$1] graphItem=g }
proc gg () { local ii,na,a1,a2,a3,newgr,clr
    na=a1=a2=a3=-1  newgr=1
    clr=panobj.color lne=panobj.line
    na=numarg()  if (na>=1) a1=argtype(1)  if (na>=2) a2=argtype(2)  if (na>=3) a3=argtype(3)
    if (a1==0) ii=$1 else ii=0
    if (a1==0 && isassigned(g[ii])) if (g[ii].view_count>0) newgr=0
    if (newgr) g[ii]=new Graph()
    graphItem=g[ii]
    graphList[0].append(g[ii])  panobj.glist.append(g[ii])
    if (gvmarkflag) tstr="mark" else tstr="line"
    if (na==1 && a1==1) sprint(tstr,"%s.%s(%s,%s",$o1,tstr,g[ii],"1")   // gg(vec)
    if (na==2) { 
        if (a1==0 && a2==1) sprint(tstr,"%s.%s(%s,1",$o2,tstr,g[ii])      // gg(g[i],vec) 
        if (a1==1 && a2==0) sprint(tstr,"%s.%s(%s,%g",$o1,tstr,g[ii],$2)  // gg(vec,step)
        if (a1==1 && a2==1) sprint(tstr,"%s.%s(%s,%s",$o1,tstr,g[ii],$o2) // gg(vec,ind)
      }
    if (na>=3) { 
        if (a2==1 && a3==1) sprint(tstr,"%s.%s(%s,%s",$o2,tstr,g[ii],$o3)   // gg(g[i],vec,ind)
        if (a2==1 && a3==0) sprint(tstr,"%s.%s(%s,%g",$o2,tstr,g[ii],$3)   // gg(g[i],vec,step)
      }
    if (na>=4) { clr=$4 } if (na>=5) { lne=$5 } if (na>=6) { symb=$s6 }
    if (sfunc.len(tstr)>4) {
        if (gvmarkflag) { sprint(tstr,"%s,\"%s\",%d,%d,1)",tstr,symb,lne+5,clr)
          } else { sprint(tstr,"%s,%d,%d)",tstr,clr,lne) }
        execute1(tstr)
      }
  }

//** remove_spaces(string,scratch) removes spaces and splits on '/'
// ie remove_spaces(temp_string_,temp_string2_)
proc remove_spaces () {
    $s2=""  // clear it out
    while (sfunc.substr($s1," ") != -1) { // still have spaces
        sfunc.tail($s1," ",$s2)
        sfunc.head($s1," ",$s1)
        sprint($s1,"%s%s",$s1,$s2)
      }
    if (sfunc.substr($s1,"/") != -1) { // split it up
        sfunc.tail($s1,"/",$s2)
        sfunc.head($s1,"/",$s1)
      }
  }

//** dirname(full,path) filname(full,file) splits up path/file
// eg filname("/home/billl/nrniv/thal/params.hoc",temp_string_)
//    temp_string_ => params.hoc
proc dirname () { sfunc.head($s1,"[^/]+$",$s2) }
proc filname () { local ii,cnt
    cnt = 0
    $s2=$s1  while (sfunc.tail($s2,"/",$s2) != -1) cnt += 1
    $s2=$s1  for ii=1,cnt sfunc.tail($s2,"/",$s2)
  }

//** file_with_dot(filename,result,scratch): put .filename into result
proc file_with_dot() {
    if (sfunc.substr($s1,"/") == -1) {
        sprint($s2,".%s",$s1)
      } else {
        sfunc.tail($s1,".*/",$s3)
        sfunc.head($s1,"/[^/]+$",$s2)
        sprint($s2,"%s/.%s",$s2,$s3)
      }
  }

//** find_secname(variable,result): put secname into result
proc find_secname() { 
    sfunc.head($s1,"\.[_a-z]+$",$s2) // strip off stuff after terminal .
    if (    strm($s1,"\.[_a-z]+[(][0-9.]+[)]$")) {  // form eg v(0.5)
        sfunc.head($s1,"\.[_a-z]+[(][0-9.]+[)]$",$s2)
      } else if (isit($s2)) {  // the the stem an obj
        XO.get_loc() // isit sets XO
        sectionname($s2)
        pop_section()
      } else {
        printf("grvec.hoc:f_s ERR0: Can't find sec: %s\n",$s1) err() 
      }
    if (sfunc.len($s2)==0) { printf("grvec.hoc:f_s ERR: %s\n",$s1) err() }
  }

//** mkmenu(title,action,proc) makes a menu from printlist
proc mkmenu () { local ii
    xmenu($s1)
    for ii=0,printlist.count-1 {
        sprint(temp_string_,"%s %s",$s2,printlist.object(ii).var)
        sprint(temp_string2_,"%s(%d)",$s3,ii)
        xbutton(temp_string_,temp_string2_)
      }
    sprint(temp_string_,"mkpanel(\"%s\",\"%s\",\"%s\")",$s1,$s2,$s3)
    xbutton("Leave up",temp_string_)
    xmenu()
  }

//** mkpanel(title,action,proc) makes a panel from printlist
proc mkpanel () { local ii
    sprint(temp_string_,"%s:%s",simname,$s1)
    xpanel(temp_string_)
    for ii=0,printlist.count-1 {
        sprint(temp_string_,"%s %s",$s2,printlist.object(ii).var)
        sprint(temp_string2_,"%s(%d)",$s3,ii)
        xbutton(temp_string_,temp_string2_)
      }
    xpanel()
  }

//** drline(x0,y0,x1,y1,OPT graph) 
proc drline () {
    if (numarg()==0) { print "drline(x0,y0,x1,y1,OPT graph)"
        return }
    if (numarg()>4) { graphItem = $o5 }
    graphItem.beginline(panobj.color,panobj.line)
    graphItem.line($1,$2)
    graphItem.line($3,$4)
    graphItem.flush()
  }

//** seevec(varname,min,max) -- uses a stringmatch to find a particular vector
proc shprl () { 
    if (numarg()==1) {
        print panobjl.object($1).filename
        for ltr(XO,panobjl.object($1).llist) print i1," ",XO.name
      } else for ltr(XO,printlist) print i1," ",XO.var,XO.vec,XO.tvec
  }

proc remprl () { local flag
    flag=0
    if (numarg()==2) flag=1 else print "LISTING ONLY; rerun with 2 args to remove"
    for (ii=printlist.count-1;ii>=0;ii-=1) {
        XO=printlist.object(ii)
        if (strm(XO.var,$s1)) if (flag) printlist.remove(ii) else print XO.var
      }
  }

//** seevec(regexp,flag)
// flag: 1 savevec, 2 save sections
proc seevec2 () {} // stub
proc seevec () { local min,max,flag,a,b,n
    flag=0
    if (numarg()==2) flag=$2
    if (numarg()==3) { min=$2 max=$3 flag=2 b=a=allocvecs(2) b+=1}
    if (flag==1 || flag==2) clrveclist()
    for ltr(XO,printlist) {
        if (strm(XO.var,$s1)) {
            printf("%d %s: %s/%s\n",i1,XO.var,printlist.object(i1).vec,printlist.object(i1).tvec)
            if (flag==3) seevec2(XO)
            if (flag==1) savevec(XO.vec,XO.tvec)
            if (flag==2) {
                mso[b].indvwhere(XO.tvec,"()",min,max)
                mso[a].index(XO.vec,mso[b])
                mso[b].where(XO.tvec,"()",min,max)
                savevec(mso[a],mso[b])
              } 
            n+=1
          }
      }
    if (flag==2) dealloc(a)
  }

//** file_len(fname): retrieve file length; uses global x
func file_len () { 
    sprint(temp_string_,"wc %s",$s1)
    sassign(temp_string_,temp_string_)
    sscanf(temp_string_,"%d",&x)
    return x
  }

//** count_substr(str,sub): count occurences of substring in str
func count_substr () { local cnt
    cnt = 0
    while (sfunc.tail($s1,$s2,$s1) != -1) { cnt += 1}
    return cnt
  }

// for ltr(XO,panobj.glist) { print XO,XO.view_count }

//** xgetargs(panel_name,command,arg1[,arg2,...],defaults)
// eg xgetargs("Random session","newrand","# of patts","patt size  ","overlap   ","5,33,7")
objref argvl,argv
argvl = new List()
strdef mesg
proc xgetargs () { local i,args
    args=numarg()-3  i=numarg()
    argv = new Vector(args)
    argvl.append(argv)
    argv.resize(0)
    sprint(temp_string_,"argv.append(%s)",$si)
    execute(temp_string_)
    if (argv.size!=args) argv.resize(args)
    xpanel($s1)
    mesg=""  xvarlabel(mesg)
    for i=3,numarg()-1 {
        sprint(temp_string_,"%s.x[%d]",argv,i-3)
        xvalue($si,temp_string_)
      }
    sprint(temp_string_,"xgetexec(\"%s\",%d,%s)",$s2,args,argv)
    xbutton($s1,temp_string_)
    xpanel()
  }

proc xgetexec () { local i,args
    args = $2
    if ($o3.size!=args) { mesg="Error-close & relaunch panel" return }
    sprint(temp_string_,"%s(",$s1)
    for i=0,args-2 sprint(temp_string_,"%s%g,",temp_string_,$o3.x[i])
    sprint(temp_string_,"%s%g)",temp_string_,$o3.x[i])
    // print temp_string_
    execute(temp_string_)
  }
  
//** procbutt() put up a single proc in a button
proc procbutt () {
    xpanel($s1)
    xbutton($s1,$s1)
    xpanel(500,500)
  }

proc prlclr () {
    for ltr(XO,printlist) {
        cvode.record_remove(XO.vec)
      }
    printlist.remove_all
  }

// op([obj,list],num) -- create object pointer
proc op () {
    if (numarg()==1) {             XO=tmpobj.object($1) } else\
    if (numarg()==2) { tmpobj=$o1  XO=tmpobj.object($2) } else\
    if (numarg()==3) { tmpobj=$o2 $o1=tmpobj.object($3) }
  }
// END /usr/site/nrniv/local/hoc/grvec.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/shape.hoc
// $Id: shape.hoc,v 1.83 2003/09/29 12:35:35 billl Exp $

// load_file("shape.hoc")

objref pls,sh,sl,rvpl,rvp,sec,dl[1]
rvpl = new List() // list of RangeVarPlot's
d=0

proc newshp () {
    objref sh
    forall ifsec "soma" distance()
    sh = new Shape()
    sh.color_all(1)
    sh.menu_tool("test", "p")
    sh.exec_menu("test")
  }

//* template TRE
begintemplate TRE
  public sec,xv,dv,min,max,iv,n,ypv,xpv,zpv,sf,par,chl,codes,name,i
  objref sec,xv,dv,ypv,xpv,zpv,chl,codes
  double min[1],max[1],n[1],sf[1],par[1],i[1]
  strdef name

  proc init () {
      sec=new SectionRef()
      name=secname()
      par=-1
      xv=new Vector(0) dv=xv.c ypv=xv.c xpv=xv.c zpv=xv.c chl=xv.c codes=xv.c
      sf=0
      if (issection(".*soma.*")) sf=1
      if (issection(".*axon.*")) sf=-1
      for (x) { xv.append(x) 
          dv.append(distance(x)) 
          if (n3d()>0) {
              xpv.append(x3d(int(x*(n3d()-1)))) 
              ypv.append(y3d(int(x*(n3d()-1)))) 
              zpv.append(z3d(int(x*(n3d()-1))))
            } 
        }
      min=distance(0) max=distance(1)
      n=xv.size-1
    }
  
  iterator iv () { local ii
      sec.sec {
          for ii=0,n {
              if (numarg()>=2) { $&1=xv.x[ii] $&2=dv.x[ii] } 
              if (numarg()>=3) $&3=ypv.x[ii] 
              if (numarg()>=4) $&4=xpv.x[ii] 
              if (numarg()==5) $&5=zpv.x[ii] 
              iterator_statement
            }
        }
    }
endtemplate TRE

// trifsec(TRE_list,string)
proc trifsec () {
    for ltr(XO,$o1) XO.sec.sec if (strm(secname(),$s2)) YO=XO
    if (isassigned(YO)) XO=YO else print $s2," not found"
  }
// trifloc(TRE_list,code) -- looks for that code
func trifloc () { local flag,ret,loc
    flag=1  loc=$2
    for ltr(XO,$o1) if (flag) for vtr2(&x,&y,XO.codes) if (x==loc) { flag=0 ret=y YO=XO}
    XO=YO
    return ret
  }


// trl(XO,TRE_list,regexp)
iterator trl () { local ii,flag
    flag=0
    for ii=0,$o2.count-1 {
        $o1=$o2.object(ii) 
        if (strm($o1.name,$s3)) $o1.sec.sec {
            flag+=1
            iterator_statement
          }
      }
    if (!flag) print $s3," not found (trl)"
    if (flag>1) printf("%s matched %d secs (trl)\n",$s3,flag)
  }

//** trm(XO,TRE_list,str) same as trl() except string-match is exact
iterator trm () { local ii,flag
    flag=0
    for ii=0,$o2.count-1 {
        $o1=$o2.object(ii) 
        if (strcmp($o1.name,$s3)==0) $o1.sec.sec {
            flag+=1
            iterator_statement
          }
      }
    if (!flag) print $s3," not found (trm)"
    if (flag>1) printf("%s matched %d secs (trm)\n",$s3,flag)
  }

//* trunc() build a database of distances throughout tree
// trunc(seclist,list)
proc trunc () { local flag,ii
    $o2.remove_all
    if (isassigned($o1)) {
        tmpobj=$o1
        forsec tmpobj ifsec "soma" distance()
        forsec tmpobj $o2.append(new TRE())
      } else {
        forall ifsec "soma" distance()
        forall $o2.append(new TRE())
      }
    // second pass sets up children and parents
    for ltr(XO,$o2) {
        XO.i=i1
        if (XO.sec.has_parent) {
            XO.sec.parent tstr=secname()
            flag=1
            for ltr(YO,$o2,&y) if (flag) {
                if (strcmp(tstr,YO.name)==0) { 
                    XO.par=y flag=0 } // break
              }
          }
        for ii=0,XO.sec.nchild-1 {
            XO.sec.child(ii) tstr=secname()
            flag=1
            for ltr(YO,$o2,&y) if (flag) {
                if (strcmp(tstr,YO.name)==0) { 
                    XO.chl.append(y) flag=0 } // break
              }
          }
      }
  }

//* trak(mainLIST,LOC,outputLIST) -- track() rewritten to use TRE statt seclist
// give location as a regular expression for strm()
// puts the indices for the track into vec
proc trak () { 
    $o3.remove_all
    for trl(XO,$o1,$s2) {
        $o3.append(XO)
        while (XO.par>-1) { // till reach soma
            XO=$o1.object(XO.par)
            $o3.append(XO)
          }
      }
  }

//* bktrak(mainLIST,LOC,dist) -- back track for dist distance
// func returns index with associated TRE in XO
// eg bktrak(dl[ee],"\\[21",100) returns 3 then XO.xv.x[3] is closest
func bktrak () { local dist,loc,flag,ret
    dist=$3 flag=1
    for trl(XO,$o1,$s2) {
        loc = XO.dv.max-dist // location being sought
        if (loc<0) { print "bktrak ERR1: too far" flag=0 ret=-1}
        while (flag) { // till reach soma
            if (loc>=XO.dv.min && loc<=XO.dv.max) {
                flag=0 ret=closest(XO.dv,loc) YO=XO
              }
            if (XO.par==-1) {flag=0 ret=-1}
            XO=$o1.object(XO.par)
          }
      }
    XO=YO
    return ret
  }

//* track from recording site down to soma
// start at location with sec=new SectionRef()
proc track () { 
    $o1.remove($o1)
    sec = new SectionRef()
    sec.sec $o1.append()
    while (sec.has_parent) { 
        sec.parent sec = new SectionRef()
        if (sec.has_parent) sec.sec $o1.append()
      }
  }

//* prune(SECLIST,NUM,NEWSECLIST) grab NUM separated sections from SECLIST and add to NEWSECLIST
proc prune () { local sum,ii,jj,n,skp,keep
    n=$2 sum=0
    forsec $o1 sum+=1
    skp=int(sum/(n+1))
    printf("Keeping every %d of %d secs in %s\n",skp,sum,$o1)
    ii=0 jj=0 keep=skp
    forsec $o1 {
        if (ii==keep && jj<n) { 
            $o3.append()
            print "Keeping ",secname()
            keep+=skp
            jj+=1 // counter for those kept
          }
        ii+=1  // counter through SECLIST
      }
  }

// for dsr(DISTLIST)
// eg for dsr(list) gmax_kdr(dix)=dis/max * val
// dis will be distance and dix will be location on the sec
//   distance, location, sec count,  seg count
double dis[1],  dix[1],   secn[1],     segn[1]
iterator dsr () { 
    max=-1
    for secn=0,$o1.count-1 if ($o1.object(secn).dv.max>max) max=$o1.object(secn).dv.max
    for secn=0,$o1.count-1 for segn=0,$o1.object(secn).dv.size-1 {
        dis=$o1.object(secn).dv.x[segn]
        dix=$o1.object(secn).xv.x[segn]
        $o1.object(secn).sec.sec { iterator_statement }
      }
  }

// find the point in the sectionlist that's furthest -- must set distance()
func maxdist () { local max
    max=-1e10
    forsec $o1 if (distance(1)>max) max=distance(1) // find the end of the list
    return max
  }

// dcls(SECLIST,TARG) 
// eg for dcls(seclist,0.72) printf("%s(%.2f) @ %.2f\n",secname(),i1,distance(i1))
iterator dcls () { local targ,min,max,n,dist,sc
    tmpobj=$o1
    if (numarg()==3) { max=$3 } else {
        max=-1e10
        forsec tmpobj if (distance(1)>max) max=distance(1) // find the end of the list
      }
    targ=$2*max  min=1e10 x=0 n=0 // targ is target distance
    forsec tmpobj { n+=1    // loop to find closest point
        for (x) {          // sc=n is sect count, i1=x is seg loc
            dist=distance(x)
            if (abs(dist-targ)<min) { min=abs(dist-targ) i1=x sc=n }
          }}
    n=0
    forsec tmpobj { n+=1    // count to find the same sec
        if (n==sc) {
            printf("%s(%.2f) @ %.2f ~ %.2f\n",secname(),i1,distance(i1),targ)
            iterator_statement  // do something here
          }
      }
  }

//** markloc()
proc markloc () { local colr
    if (isobj($o1,"List")) {
        if (numarg()==4) colr=$4 else colr=2
        $o1.object($2).sec.sec tmpobj=new PointProcessMark($o1.object($2).xv.x[$3])
      } else {
        if (numarg()==3) colr=$3 else colr=2
        $o1.sec.sec tmpobj=new PointProcessMark($o1.xv.x[$2])
      }
    sh.point_mark(tmpobj,colr)
    tmplist.append(tmpobj) 
    tmpobj=nil
  }  

//* p()
proc p () { local d, a, l
    if ($1 == 2) {
        sh.color_all(1)
        sh.point_mark_remove()
        d = sh.nearest($2,$3) 
        a = sh.push_selected()
        if (a >= 0) {
            sh.select()
            l=a*(n3d()-1)
            sh.erase
            XO = new PointProcessMark(0)
            sh.point_mark(XO,2)
            YO = new PointProcessMark(1)
            sh.point_mark(YO,3)
            printf("%s(%g): %d,%g,%g,%g,%d\n", secname(), a, l, x3d(l), y3d(l), z3d(l),distance(a))
            // printf("%s(%g): %g,%g,%g - %g,%g,%g\n", secname(), a, x3d(0), y3d(0), z3d(0), x3d(n3d()-1), y3d(n3d()-1), z3d(n3d()-1))                               // x,y,z coordinates
            printf("%s L=%g diam=%g-%g\n",secname(),L,diam(0),diam(1))              // L and diam
            // printf("%s: %g -> %g\n", secname(), z3d(0), z3d(n3d()-1)) // z coordinates
            // printf("%s d(0)=%g d(1)=%g nseg=%d\n",secname(),distance(0),distance(1),nseg)// distance
            pop_section()
          }
      }
  }

//* proc psec -- modified psection()
proc psec () { local d,l
    if (numarg()==1) { sprint(tstr,"%s sec = new SectionRef()",$s1)
        execute(tstr) } else sec = new SectionRef()
    // if (sec.has_parent()) sec.parent sprint(tstr,"%s",secname())
    sec.sec printf("%s->%s:  %g x %g\n",tstr,secname(),L,diam)
    // sec.sec printf("%s->%s:  %.2f\n",tstr,secname(),diam)
    // sec.sec printf("%g %g %g\n",x3d(0),y3d(0),z3d(0))
    // sec.sec printf("%s: %g,%g,%g -> %g,%g,%g\n", secname(), x3d(0), y3d(0), z3d(0), x3d(n3d()-1), y3d(n3d()-1), z3d(n3d()-1))
    vec.resize(0)
    for ii=0,sec.nchild-1 sec.child[ii] { vec.append(diam(0)) print secname() }
    vec.sort
    sec.sec printf("%s has %d branches (%.1f): ",secname(),sec.nchild,vec.sum)
    vlk(vec)
    sec=nil
  }

//* move cells around, crm(), translate(), zrotate()
// $o1 is sectionlist for this neuron, $2 is theta in degrees
proc crm () { local theta,ii
    if (numarg()==0) {print "crm(SECLIST,ROT_DEG)" return }
    tmpobj=$o1
    theta = $2
    ind.resize(0)  vec.resize(0)
    forsec tmpobj for ii=0,n3d()-1 { ind.append(x3d(ii)) vec.append(y3d(ii)) } 
    forsec tmpobj translate(-ind.mean,-vec.mean)
    forsec tmpobj zrotate(theta)
  }

//** rotate and translate
// zrotate(seclist,theta) OR forsec seclist zrotate(theta)
proc zrotate () { local theta,ii
    if (numarg()==2) { // include the list as 1st arg
        theta= -$2/360*2*PI  // don't know why it is negative here
        forsec $o1 for ii=0,n3d()-1 pt3dchange(ii,x3d(ii)*cos(theta) -  y3d(ii)*sin(theta),\
                                               y3d(ii)*cos(theta) +  x3d(ii)*sin(theta),\
                                               z3d(ii), diam3d(ii))
      } else {
        theta= -$1/360*2*PI  // don't know why it is negative here
        for ii=0,n3d()-1 pt3dchange(ii,x3d(ii)*cos(theta) -  y3d(ii)*sin(theta),\
                                    y3d(ii)*cos(theta) +  x3d(ii)*sin(theta),\
                                    z3d(ii), diam3d(ii))
      }
  }

//** translate in x,y plane
// translate(seclist,x,y) OR forsec seclist translate(x,y)
proc translate () { local x,y,ii
    if (numarg()==2) {
        x=$1 y=$2  
        for ii=0,n3d()-1 pt3dchange(ii,x3d(ii)+x,y3d(ii)+y,z3d(ii), diam3d(ii))
      } else { 
        x=$2 y=$3
        forsec $o1 for ii=0,n3d()-1 pt3dchange(ii,x3d(ii)+x,y3d(ii)+y,z3d(ii), diam3d(ii))
      }
  }

//* graphics -- space plot to graph v from one location to another

//* newspaceplot("SECNAME1","SECNAME2"[,TRE_LIST]) -- 3rd arg optional for back compatability
proc newspaceplot () {
    if (numarg()==3) tmpobj=$o3 else tmpobj=dl[ee] // assume location of TRE_LIST
    rvp = new RangeVarPlot("v")
    rvpl.append(rvp)
    for trm(XO,tmpobj,$s1) XO.sec.sec rvp.begin(1)
    for trm(XO,tmpobj,$s2) XO.sec.sec rvp.end(1)
    rvp.origin(0)
  }

//** grspaceplot(g,rvp)
proc grspaceplot () {
    $o1.addobject($o2, 2, 1, 0.8, 0.9)
    $o1.size(-600,600,-80,40)
    $o1.view(-600, -80, 1200, 120, 150, 40, 450, 300)
  }

//** drawspace("SECNAME1","SECNAME2",TRE_LIST) will trak from both directions to draw rvp locs on shape
proc drawspace () { local colr
    if (numarg()==4) colr=$4 else colr=2
    for trm(XO,$o3,$s1) while (XO.par>-1) {
          XO.sec.sec sh.color(colr)
          XO=$o3.object(XO.par)
      }
    for trm(XO,$o3,$s2) while (XO.par>-1) {
          XO.sec.sec sh.color(colr)
          XO=$o3.object(XO.par)
      }
    sh.flush()
  }

//* grdm(cel# or obj,graph,label) graph diameters
proc grdm () { local a,b,cel
    cel=$1 
    g=$o2
    a=b=allocvecs(2) b+=1
    g.erase
    for ltr(XO,dl[cel],&y) if (XO.chl.size==0) {
        mso[a].resize(0) mso[b].resize(0)
        YO=dl[cel].object(XO.par) // parent
        YO.sec.sec {
           for vtr(&x,YO.xv) mso[a].append(diam(x))
           mso[b].append(YO.dv)
          }
        XO.sec.sec {
            for vtr(&x,XO.xv) mso[a].append(diam(x))
            mso[b].append(XO.dv)
          }
        if (XO.ypv.min<-10) mso[b].mul(-1) // show basal dends
        mso[a].line(g,mso[b],y%9+1,2)
      }
    if (numarg()==3) g.label(0.8,0.8,$s3)
    g.size(0,800,0.1,1)
    dealloc(a)
  }
// END /usr/site/nrniv/local/hoc/shape.hoc
//================================================================

tstop=300
objref ce[4]

//* template SWC
begintemplate SWC
  public soma,dend,ndend,name,file,sl
  create soma, dend[1]
  objref sl
  double ndend[1], soma_L[1], soma_diam[1]
  strdef name,file
  external filname,sfunc

proc init () {
    file=$s1
    filname($s1,name)
    sfunc.head(name,"\\.",name) // strip off the .hoc
    xopen(file)
    sl=new SectionList()
    soma sl.wholetree()
  }

endtemplate SWC

for scase("rlgncb54_99jan20.hoc","rlgntc5-10-95.hoc","rlgnI8-4-95.hoc","rlgnti4-13-96.hoc") ce[i1] = new SWC(temp_string_)   
proc movece () {
    crm(ce[2].sl,270)
    translate(ce[2].sl,0,500)  // top cell in A , TI
    crm(ce[3].sl,90)
    translate(ce[3].sl,0,100)  // bottom cell in A, TI
    crm(ce[0].sl,-90)
    translate(ce[0].sl,-50,-180) // top cell in B, TC
    translate(ce[1].sl,-30,-400) // bottom cell in B, TC
  }

movece()
sh = new Shape()
objref stim[4]
for ii=0,3 ce[ii].soma stim[ii]=new IClamp(0.5)
for ii=0,1 { // TCs
    stim[ii].amp=-.05
    stim[ii].dur=tstop
    forsec ce[ii].sl {
        Ra=100 Cm=0.85
        insert pas  e_pas=-62.7  g_pas=1/30.3e3
        v=-62.7
      }
  }
for ii=2,3 { // TCs
    stim[ii].amp=-.0125
    stim[ii].dur=tstop
    forsec ce[ii].sl {
        Ra=70 Cm=1
        insert pas  e_pas=-54.5  g_pas=1/95.2e3
        v=-54.5
      }
  }

newPlotV()
g=graphItem
g.erase_all
g.size(0,tstop,-90,-50)
for ii=0,3 {
    sprint(tstr,"ce[%d].soma.v(0.5)",ii) g.addvar(tstr,ii+1,2) 
    forsec ce[ii].sl sh.color(ii+1) // match colors on shape
  }

tstop=400
cvode_local(1)
v_init=1e4 // prevent v from being reset
run()

// END cells.hoc
//================================================================

Briska AM, Uhlrich DJ, Lytton WW (2003) Computer model of passive signal integration based on whole-cell in vitro studies of rat lateral geniculate nucleus. Eur J Neurosci 17:1531-41[PubMed]

References and models cited by this paper

References and models that cite this paper

Bal T, von Krosigk M, McCormick DA (1995) Role of the ferret perigeniculate nucleus in the generation of synchronized oscillations in vitro. J Physiol 483 ( Pt 3):665-85 [PubMed]

Bernander O, Douglas RJ, Martin KA, Koch C (1991) Synaptic background activity influences spatiotemporal integration in single pyramidal cells. Proc Natl Acad Sci U S A 88:11569-73 [PubMed]

Bloomfield SA, Sherman SM (1989) Dendritic current flow in relay cells and interneurons of the cat's lateral geniculate nucleus. Proc Natl Acad Sci U S A 86:3911-4 [PubMed]

Briska A, Uhlrich DJ, Lytton WW (1999) Passive properties and signal synergy in thalamic cells. Soc Neurosci Abstr 25:8483

Budde T, Munsch T, Pape HC (1998) Distribution of L-type calcium channels in rat thalamic neurones. Eur J Neurosci 10:586-97 [PubMed]

Chitwood RA, Hubbard A, Jaffe DB (1999) Passive electrotonic properties of rat hippocampal CA3 interneurones. J Physiol 515 ( Pt 3):743-56 [PubMed]

   [66 reconstructed morphologies on NeuroMorpho.Org]

Cox CL, Sherman SM (2000) Control of dendritic outputs of inhibitory interneurons in the lateral geniculate nucleus. Neuron 27:597-610 [PubMed]

Cox CL, Zhou Q, Sherman SM (1998) Glutamate locally activates dendritic outputs of thalamic interneurons. Nature 394:478-82 [PubMed]

Hamos JE, Van Horn SC, Raczkowski D, Uhlrich DJ, Sherman SM (2000) Synaptic connectivity of a local circuit neurone in lateral geniculate nucleus of the cat. Nature 317:618-21 [PubMed]

Hines M (1993) NEURON--a program for simulation of nerve equations. Neural Systems: Analysis And Modeling, Eeckman F, ed. pp.127

Hines M (1993) The NEURON simulation program. Neural Network Simulation Environments, Skrzypek J, ed.

Jaffe DB, Carnevale NT (1999) Passive normalization of synaptic integration influenced by dendritic architecture. J Neurophysiol 82:3268-85 [Journal] [PubMed]

   [66 reconstructed morphologies on NeuroMorpho.Org]

Jones EG (1985) The Thalamus

Kapur A, Lytton WW, Ketchum KL, Haberly LB (1997) Regulation of the NMDA component of EPSPs by different components of postsynaptic GABAergic inhibition: computer simulation analysis in piriform cortex. J Neurophysiol 78:2546-59 [Journal] [PubMed]

Kapur A, Pearce RA, Lytton WW, Haberly LB (1997) GABAA-mediated IPSCs in piriform cortex have fast and slow components with different properties and locations on pyramidal cells. J Neurophysiol 78:2531-45 [Journal] [PubMed]

Major G, Evans JD, Jack JJ (1993) Solutions for transients in arbitrarily branching cables: I. Voltage recording with a somatic shunt. Biophys J 65:423-49 [PubMed]

Major G, Evans JD, Jack JJ (1993) Solutions for transients in arbitrarily branching cables: II. Voltage clamp theory. Biophys J 65:450-68 [PubMed]

Mastronarde DN (1987) Two classes of single-input X-cells in cat lateral geniculate nucleus. I. Receptive-field properties and classification of cells. J Neurophysiol 57:357-80 [Journal] [PubMed]

Neubig M (1999) Variation in GABA mini amplitude in thalamocortical neurons: contrasting experimental data and computational analyses Faculté De Medecine

Neubig M, Destexhe A (2001) Dendritic organization in thalamocortical neurons and state-dependent functions of inhibitory synaptic inputs. Thalamus And Related Systems 1:39-52

Pasik P, Pasik T, Hamori J (1976) Synapses between interneurons in the lateral geniculate nucleus of monkeys. Exp Brain Res 25:1-13 [PubMed]

Sherman SM, Guillery RW (1996) Functional organization of thalamocortical relays. J Neurophysiol 76:1367-95 [Journal] [PubMed]

Staley KJ, Otis TS, Mody I (1992) Membrane properties of dentate gyrus granule cells: comparison of sharp microelectrode and whole-cell recordings. J Neurophysiol 67:1346-58 [Journal] [PubMed]

Steriade M, Deschaenes M, Domich L, Mulle C (1985) Abolition of spindle oscillations in thalamic neurons disconnected from nucleus reticularis thalami. J Neurophysiol 54:1473-97 [Journal] [PubMed]

Steriade M, Jones EG, Llinas RR (1990) Thalamic Oscillations And Signalling

Storm JF (1990) Why is the input conductance of hippocampal neurones impaled with microelectrodes so much higher than when giga-seal patch pipettes are used? Soc Neurosci Abstr 16:506

Stuart G, Spruston N (1998) Determinants of voltage attenuation in neocortical pyramidal neuron dendrites. J Neurosci 18:3501-10 [PubMed]

   [13 reconstructed morphologies on NeuroMorpho.Org]
   Pyramidal Neuron Deep: attenuation in dendrites (Stuart, Spruston 1998) [Model]

Usrey WM, Reppas JB, Reid RC (1998) Paired-spike interactions and synaptic efficacy of retinal inputs to the thalamus. Nature 395:384-7 [PubMed]

von Krosigk M, Bal T, McCormick DA (1993) Cellular mechanisms of a synchronized oscillation in the thalamus. Science 261:361-4 [PubMed]

Wathey JC, Lytton WW, Jester JM, Sejnowski TJ (1992) Computer simulations of EPSP-spike (E-S) potentiation in hippocampal CA1 pyramidal cells. J Neurosci 12:607-18 [PubMed]

Wilson JR, Friedlander MJ, Sherman SM (1984) Fine structural morphology of identified X- and Y-cells in the cat's lateral geniculate nucleus. Proc R Soc Lond B Biol Sci 221:411-36 [PubMed]

Zhu JJ, Lytton WW, Xue JT, Uhlrich DJ (1999) An intrinsic oscillation in interneurons of the rat lateral geniculate nucleus. J Neurophysiol 81:702-11 [Journal] [PubMed]

   Thalamic interneuron multicompartment model (Zhu et al. 1999) [Model]

Zhu JJ, Uhlrich DJ, Lytton WW (1999) Properties of a hyperpolarization-activated cation current in interneurons in the rat lateral geniculate nucleus. Neuroscience 92:445-57 [PubMed]

Zhu JJ, Uhlrich DJ, Lytton WW (1999) Burst firing in identified rat geniculate interneurons. Neuroscience 91:1445-60 [Journal] [PubMed]

   Thalamic interneuron multicompartment model (Zhu et al. 1999) [Model]

Allken V, Chepkoech J-L, Einevoll GT, Halnes G (2014) The subcellular distribution of T-type Ca++ channels in interneurons of the lateral geniculate nucleus PLoS ONE 9(9):e107780 [Journal] [PubMed]

   The subcellular distribution of T-type Ca2+ channels in LGN interneurons (Allken et al. 2014) [Model]

Carnevale NT, Morse TM (1996-2009) Research reports that have used NEURON Web published citations at the NEURON website [Journal]

Casale AE, McCormick DA (2011) Active action potential propagation but not initiation in thalamic interneuron dendrites. J Neurosci 31:18289-302 [Journal] [PubMed]

   Active dendritic action potential propagation (Casale & McCormick 2011) [Model]

Connelly WM, Crunelli V, Errington AC (2015) The Global Spike: Conserved Dendritic Properties Enable Unique Ca2+ Spike Generation in Low-Threshold Spiking Neurons. J Neurosci 35:15505-22 [Journal] [PubMed]

   Rat LGN Thalamocortical Neuron (Connelly et al 2015, 2016) [Model]

Connelly WM, Crunelli V, Errington AC (2016) Passive Synaptic Normalization and Input Synchrony-Dependent Amplification of Cortical Feedback in Thalamocortical Neuron Dendrites. J Neurosci 36:3735-54 [Journal] [PubMed]

   Rat LGN Thalamocortical Neuron (Connelly et al 2015, 2016) [Model]

Halnes G, Augustinaite S, Heggelund P, Einevoll GT, Migliore M (2011) A Multi-Compartment Model for Interneurons in the Dorsal Lateral Geniculate Nucleus PLoS Comp. Biol. 7(9):e1002160 [Journal] [PubMed]

   [3 reconstructed morphologies on NeuroMorpho.Org]
   A multi-compartment model for interneurons in the dLGN (Halnes et al. 2011) [Model]

Perreault MC, Raastad M (2006) Contribution of morphology and membrane resistance to integration of fast synaptic signals in two thalamic cell types. J Physiol 577:205-220 [PubMed]

(41 refs)