You want the initialization for the first run to do what unmodified proc init() does; only initializations for the subsequent runs may use SaveState restore().
The "brute force" way to do this is with inline code, i.e. a program organized like so:
(presumes biology and instrumentation--stimulators, graphs, Vector recording etc.--have all been done prior to this point)
Code: Select all
objref r,f, svstate
strdef filename
svstate = new SaveState()
f = new File()
r = new Vector()
r.play(&IClamp...) // do this only once,
// and do it before any SaveState save or restore
filename = "stim1.dat"
f.ropen(filename)
r.scanf(f)
run() // first pass uses NEURON's built-in proc init()
svstate.save()
// now declare your custom proc init()
// just as in the example you provided
proc init() { . . .
// finally your for loop, but starting with i = 2
for (i = 2; . . .
That isn't elegant but it should work.
A more sophisticated strategy would employ a single custom init procedure that expects an argument that specifies whether or not to to use SaveState restore()--in other words, whether or not the first run in a series of runs has already been executed. Something like the following should work:
Code: Select all
objref r,f, svstate
strdef filename
f = new File()
r = new Vector()
r.play(&IClamp...) // do this only once
svstate = new SaveState()
proc myinit() {
finitialize(v_init)
if (!$1) { // this is not the first run in a series
svstate.restore()
t = 0 // t is one of the "states"
if (cvode.active()) {
cvode.re_init()
} else {
fcurrent()
}
frecord_init()
}
}
proc mystdinit() {
realtime=0
startsw()
setdt()
myinit($1)
initPlot()
}
proc myrun() {
mystdinit($1)
continuerun(tstop)
}
proc batchrun() { local firstrun
firstrun = 1
for(i = 1; i <= $1; i = i + 1) {
sprint(filename, "stim%d.dat", i)
f.ropen(filename)
r.scanf(f)
f.close()
myrun(firstrun)
svstate.save()
firstrun = 0
}
}
Then you can call batchrun() with an integer argument that specifies how many passes to make.
Comments on this implementation:
batchrun() contains the main administrative loop--which launches a series of simulations. During the first pass, the firstrun is 1. The value of this variable controls whether or not states are restored from a SaveState object. This means the value of firstrun must be passed to the custom init procedure. I could have made firstrun be a variable with global scope, but it is safer to pass its value as an argument. In NEURON's standard run system the call chain from run to init is
run() -> stdinit() -> init()
so passing firstrun's value as an argument requires customization of not only init but also stdinit and run. Rather than overwrite the standard run time library's run, stdinit, and init, I decided to add my own procs with similar (but unique) names. This leaves the standard run system remains intact, so I can use the RunControl panel for exploratory/development/debugging purposes.
One more comment--note that it is only necessary to call Vector play() once. Vector play() remains in effect until the Vector is destroyed, which it is not (you're just reading new values from a series of files). Also, not knowing the implementational details of SaveState save(), I would hesitate to call Vector play() _between_ a SaveState save() and a subsequent restore().