print "Loading writedata.hoc..."
// writedata.hoc
// Mark Rowan, School of Computer Science, University of Birmingham, UK
// March 2012

// Writes data in vit (and, possibly later, printlist and nqLFP) to disk
// periodically and flushes data from RAM, to enable very long simulations
// Data is stored in grvec format

// ***************************************************************************
// REQUIREMENTS:
// * run.hoc should have SPKSZ at least large enough to hold all the spikes
// generated by the network in "buffertime" ms.
//
// For the Alzheimer's tests, 1600s of ~20Hz stimulus to 470 cells produces > 3
// million spikes, so SPKSZ should be at least 3500e3 elements, and preferably
// a lot larger (given available RAM) in case there are periods with lots of spikes.
//
// This may take some experimentation as setting the Vector too large will result in
// running out of memory, but setting it too small means some spikes won't be recorded.
// Check your rasters and see if they contain spikes from start to end.
//
// * run.hoc should have the last line as prl(0,1) as currently printlist and
// nqLFP writing is not implemented, otherwise RAM usage will grow steadily as
// nqLFP / printlist object lists grow.
//
// * params.hoc should have "declare("use_nqLFP",0)" to prevent massive nqLFP
// vectors being initialised within each cell in run.hoc:wrecon().
// ***************************************************************************

// Set frequency of write operations
declare("buffertime", 1600e3) //16e3 // Write data to disk every buffertime ms of sim time



// Define objects
objref vitindexfile, vitdatafile // printlistvecfile, printlisttvecfile, nqLFPfile
strdef vitindexfilename, vitdatafilename // printlistvecfilename, printlisttvecfilename, nqLFPfilename
//strdef filepath // Needed if not passing filepath on the commandline. However, must be commented out if passing filepath on the commandline, or the supplied filepath will be overwritten by the strdef!

// Set up filenames
declare("filepath", "data") // Default save path (pass alternative paths to nrniv using '-c "filepath=..."' and ensure that 'strdef filepath' above is commented out)
sprint(vitindexfilename, "%s/%s", filepath, ".spks")
sprint(vitdatafilename, "%s/%s", filepath, "spks")
//sprint(printlistvecfilename, "%s%s%s", filepath, "printlist-vec", datetime)
//sprint(printlisttvecfilename, "%s%s%s", filepath, "printlist-tvec", datetime)
//sprint(nqLFPfilename, "%s%s%s", filepath, "nqLFP", datetime)

// Create files
vitindexfile = new File(vitindexfilename)
vitdatafile = new File(vitdatafilename)
//printlistvecfile = new File(printlistvecfilename)
//printlisttvecfile = new File(printlisttvecfilename)
//nqLFPfile = new File(nqLFPfilename)


proc writedata() { localobj vec

  // Open files for appending
  vitindexfile.aopen()
  vitdatafile.aopen()
  //printlistvecfile.aopen()
  //printlisttvecfile.aopen()
  //nqLFPfile.aopen()
  
  // Debug printouts (comment out for extra speed during write operations):
  printf("vit.vec has %d elements\n", vit.vec.size())
  vec = vit.vec.where("!=", 0)
  printf("writing %d elements\n", vec.size())

  // Write vitem object to file using grvec format
  // Can't just resize or delete/re-create Vectors, as the Vector pointers
  // are held by intf6.mod and are not reset to zero (so after x elements are
  // written and the Vector is resized, the next element will still be written
  // index x rather than beginning again at index 0).
  // Fortunately, intf6 provides a custom spike-to-file proc spkoutf:
  col.ce.o(0).spkoutf(vitindexfile,vitdatafile) // print spike and time data to file
  col.ce.o(0).spkoutf() // empty the spike data vectors and resize

  // printlist contains vitem objects (just like vit) so we need to loop through
  // printlist and write each object to file.
  // Currently not implemented as this requires a similar mechanism to
  // col.ce.o(0).spkoutf (above) but applied to the printlist objects.
  // nqLFP also currently not implemented.

  // Close files
  vitindexfile.close()
  vitdatafile.close()
  //printlistvecfile.close()
  //printlisttvecfile.close()
  //nqLFPfile.close()

  // Resize vit vectors to SPKSZ so they don't constantly shrink
  vit.resize(SPKSZ)

  // Empty each of the printlist and nqLFP vectors and reclaim memory
  //prlclr() // Call prlclr() in run.hoc to clear printlist -- may also stop recording though?
  //nqLFP.remove_all()
  //wrecon() // Call wrecon() in run.hoc which reinitialises nqLFP. Is this correct?

 // Put next data write event onto queue to occur after t + buffertime
 cvode.event(t + buffertime,"writedata()") 
}


//* seteventqueue - starts off the event queue
proc seteventqueue() {
  // If mytstop is not a direct multiple of buffertime, then some data will remain
  // unsaved at the end of the simulation. So we find the amount by which we bring
  // forward the first write operation, so that the last write operation occurs at
  // the same time as the end of the simulation, meaning that all data is saved.
  // mytstop % buffertime ensures that we catch all the data
  cvode.event(t + buffertime + (mytstop % buffertime),"writedata()") 
}
declare("fith",new FInitializeHandler("seteventqueue()")) // Called as soon as INIT finishes