setuptime = startsw()
{load_file("nrngui.hoc")}

// Defines ParallelNetManager class.
{load_file("netparmpi.hoc")}  // in nrn/lib/hoc

// Defines RandomStream class, used to create and manage randomized spike streams.
{load_file("ranstream.hoc")}  // in common

// Will become instances of ParallelNetManager, ParallelContext, 
// List of RandomStream objects, an FInitializeHandler (to report progress), 
// and a Graph for the raster plot.
objref pnm, pc, ranlist, fih, grspk

// If program was launched by executing mosinit.hoc,
// there is already a variable called mosinit with value 1.
// If this variable does not exist, create it and set its value to 0.
// mosinit controls reporting of results--see
// procs finish_setup(), collect_results(), and output_results() below.
if (!name_declared("mosinit")) {mosinit = 0}

ncell = 4000
ranlist = new List()
random_stream_offset_ = 500 // Adjacent streams will be correlated by this offset.
// Seeds for network architecture and stimulus trains.
connect_random_low_start_ = 1  // Used in net.hoc.
run_random_low_start_ = 2  // Used in coba|cobahh|cuba|cubadv/init.hoc

// The ParallelNetManager class provides routines and variables 
// for managing distributed network simulations
// in a parallel computing environment.
pnm = new ParallelNetManager(ncell)
// One of the ParallelNetManager's public members is a ParallelContext object.
pc = pnm.pc

// iterator pcitr() manages round robin style distribution of cells on CPUs.
//   There are pc.nhost CPUs, numbered 0 to pc.nhost-1, where 0 is the "master" CPU
//   and ncell cells, numbered 0 to ncell-1
//   CPU i creates cells i+j*pc.nhost where j=0,1,2,... and i+j*pc.nhost < ncell
// pcitr is called four times with different iterator_statements:
//   twice in common/net.hoc, to distribute cells and set up synapses
//   once in netstim.hoc, to set up stimulation of a specified number of cells
//   once in perfrun.hoc, to set up spike recording from all cells
// Note that the outer loop of pcitr is over the the target cells, and,
// when setting up synaptic connections, the inner loop will be over the source cells.
// This minimizes setup time, which is an issue if the number of possible connections 
// is ~ 10^4 x 10^4 or greater
iterator pcitr() {local i1, i2
        i1 = 0
        for (i2=pc.id; i2 < ncell; i2 += pc.nhost) {
                $&1 = i1
                $&2 = i2
                iterator_statement
                i1 += 1
        }
}

// Create the model.
{load_file("net.hoc")}  // in common
// Set up the stimulus sources (streams of afferent spike events).
{load_file("netstim.hoc")}  // in common

// Simulation control parameters.
tstop = 1000 //5000	//(ms)
dt = 0.1	//(ms) time step
steps_per_ms = 1/dt
v_init = -60
celsius = 36

// Variables and procedures used for 
// performance and statistics measurement and reporting.
{load_file("perfrun.hoc")}  // in common

proc finish_setup() {
	// Record all spikes in the net.
	want_all_spikes()  // in common/perfrun.hoc
	// Keep track of spike exchanges.
	mkhist(100)  // in common/perfrun.hoc

	setuptime = startsw() - setuptime
	if (pc.id == 0) {print "SetupTime: ", setuptime}
	// mosinit==1 means "demo mode," i.e. show results during the simulation.
	if (mosinit == 1) {
		mosrt = startsw()
		// Make proc mosprogress() be an event handler
		// that will be responsible for progress reports and raster plot updates,
		// and send the event that will trigger the first report and update
		fih = new FInitializeHandler("cvode.event(0, \"mosprogress()\")")
		grspk = new Graph(0)  // Graph of spike rasters.
		grspk.size(0,tstop,0,pnm.ncell)
		grspk.view(0, 0, 1000, 4000, 50, 100, 750, 500)
		plt_so_far = 0
		xpanel("Stop simulation")
		xbutton("Stop", "stoprun = 1")
		xpanel(380, 10)
	}
}

// This event handler reports progress, updates the raster plot, 
// and sends another event that will trigger the next progress report and plot update.
proc mosprogress() {local i
	if (t == 0) { grspk.erase_all }
	printf("runtime=%g\t t=%g\t nspike=%d\n", startsw() - mosrt, t, pnm.spikevec.size)
	cvode.event(t+mosinvl, "mosprogress()")
	for i=plt_so_far, pnm.spikevec.size-1 {
		grspk.mark(pnm.spikevec.x[i], pnm.idvec.x[i], "|", 5,1,1)
	}
	plt_so_far = pnm.spikevec.size
	grspk.flush()
	doNotify()
}

proc collect_results() {
	// "demo mode" so show final progress report.
	if (mosinit == 1) {
		mosprogress()
	}
	pnm.prstat(1)
	// Get each cpu's performance stats.
	getstat()  // in common/perfrun.hoc
	// Get the spike times.
	pnm.gatherspikes()
	// Display histogram of # spikes vs # exchanges, and print stats.
	prhist()  // in common/perfrun.hoc
	print_spike_stat_info()  // in common/perfrun.hoc
}

// output_results() is the last statement in the coba|cobahh|cuba|cubadv/init.hoc files.
// Since only the pc.id==0 process returns from pc.runworker,
// only the master will call output_results().
proc output_results() {
	// If "demo mode," don't bother writing performance and spike data
	if (mosinit == 1) {return}

	perf2file()  // in common/perfun.hoc
	spike2file()  // in common/perfun.hoc
	quit()
}