// -----------------------------------------------------------------------------------
// Authors: Ronald van Elburg
//
//
//
// Affiliations:
// Department of Artificial Intelligence
// Groningen University
//
// Department for Experimental Neurophysiology
// Vrije Universiteit Amsterdam
//
// Purpose: Overcoming the need to write code to implement standard for loops
// for parameter space exploration, generating output files and defining
// protocols.
//
// Author: Ronald van Elburg (RonaldAJ at vanElburg eu)
//
// This code was first published on http://senselab.med.yale.edu/modeldb/,
// accession number 114359 accompanying the paper:
// Ronald A.J. van Elburg and Arjen van Ooyen (2010) `Impact of dendritic size and
// dendritic topology on burst firing in pyramidal cells',
// PLoS Comput Biol 6(5): e1000781. doi:10.1371/journal.pcbi.1000781.
// Please cite both the paper and the ModelDB entry when you use
// this software to prepare a publication.
//
// This software is released under the GNU GPL version 3:
// http://www.gnu.org/copyleft/gpl.html
//
// Other Contributions:
// The file nrn_vread.m for reading neuron binaries into matlab was first
// published by Konstantin Miller on the Neuron forum.
//
// Other Files Needed:
// OutputHandlers (new Handlers should be added to MRC_OutParamHandlerContainer):
// MRC_TimeSeriesHandler.hoc
// MRC_SpikeTrainHandler.hoc
// MRC_ScalarHandler.hoc
//
// It is assumed that this file is loaded from MultipleRunControl.hoc which will load:
// MRC_all_in_list.hoc defines an iterator for lists
// nrngui.hoc standard GUI components
//
//
//
// Output: outputfiles defined by users
// initial version: Matlab
//
// normal session files support
//
// Required Mechanisms:
//
// Warnings:
//
// Initial Creation Date: 2005-11-01
// ChangeNo Date ChangedBy Description of Changes
//
// ----------------------------------------------------------------------------------//
if(name_declared("cvode")==0){
dialog_outcome= boolean_dialog("CVode not loaded, cannot continue! ","Quit","Continue Anyway")
if(1==dialog_outcome){
quit()
}
}
// These functions need to be defined for MRC to work properly, but to allow for easy overwriting them we first check if they are not defined already.
isDefined=name_declared("MRC_Run")
if(isDefined!=1){
execute1("proc MRC_Run(){run()}")
}
isDefined=name_declared("MRC_PrepareModel")
if(isDefined!=1){
execute1("proc MRC_PrepareModel(){ }")
}
MRC_SliceNo=0
isDefined=name_declared("MRC_SliceIndex")
if(isDefined!=5){
double MRC_SliceIndex[1]
}
isDefined=name_declared("MRC_StepsInSlice")
if(isDefined!=5){
double MRC_StepsInSlice[1]
}
isDefined=name_declared("MRC_NoOfSlices")
if(isDefined!=5){
double MRC_NoOfSlices[1]
}
if(name_declared("MRC_Slice")==5){
MRC_SliceNo=MRC_Slice
}
//if(name_declared("MRC_GetIndex")!=1){
// execute1( "func MRC_GetIndex(){return -1}")
//}
func MRC_GetRemainder(){local remainder, index, sliceno,sliceSize, remainderInSliceAbove
depth=$1
sliceno=$2
fulldepth=$3
sliceSize=1
remainderInSliceAbove=MRC_GetRemainder(depth-1,sliceno,fulldepth)
for j=depth+1, fulldepth {
sliceSize=sliceSize*MRC_NoOfSlices[j-1]
}
index=int(remainderInSliceAbove/sliceSize)
remainder=remainderInSliceAbove-index*sliceSize
return remainder
}
func MRC_GetIndex(){local index, sliceno,sliceSize, remainderInSliceAbove
depth=$1
sliceno=$2
fulldepth=$3
sliceSize=1
if(depth=1){
remainderInSliceAbove=sliceno
}else{
remainderInSliceAbove=MRC_GetRemainder(depth-1,sliceno,fulldepth)
}
for j=depth+1, fulldepth {
sliceSize=sliceSize*MRC_NoOfSlices[j-1]
}
index=int(remainderInSliceAbove/sliceSize)
return index
}
begintemplate MRC_LoopParameter
public name, displaytext, use
public set, get,get_sessionstr
public toggle,restart_at
external MRC_SliceNo, MRC_SliceIndex, MRC_StepsInSlice,MRC_NoOfSlices,MRC_GetIndex
strdef name, displaytext, tstr
proc init() {
if(0!=numarg()){
lower_limit=0
upper_limit=0
stepsize=0
use=1
restart=0
restart_at=lower_limit
end_before=upper_limit
name=$s1
setdisplaytext()
}
}
proc set() {
lower_limit=$1
upper_limit=$2
stepsize=$3
restart=$4
restart_at=$5
end_before=$6
if(numarg()>6){
use=$7%2
}
setdisplaytext()
}
proc get() {
$&1=lower_limit
$&2=upper_limit
$&3=stepsize
$&4=restart
$&5=restart_at
$&6=end_before
if(numarg()>6){
$&7=use
}
}
proc setdisplaytext(){
if (use) {
sprint(displaytext,"+ %s %g %g %g %g %g %g", name, lower_limit, upper_limit, stepsize, restart, restart_at, end_before)
}else{
sprint(displaytext,"- %s %g %g %g %g %g %g", name, lower_limit, upper_limit, stepsize, restart, restart_at, end_before)
}
}
proc toggle() {
use = (use+1)%2
setdisplaytext()
}
proc get_sessionstr(){
// Because there is no way of knowing whether a block is open or closed we adopted the convention that
// get_sessionstr only returns closed blocks and we make the calling code responsible for closing and
// opening blocks before and after the current blocks.
$s1=""
sprint(tstr,"{tobj=new MRC_LoopParameter()}") $o2.save(tstr)
sprint(tstr,"\t{object_push(tobj)}") $o2.save(tstr)
sprint(tstr,"\t{") $o2.save(tstr)
sprint(tstr,"\t\tname=\"%s\"",name) $o2.save(tstr)
sprint(tstr,"\t\tlower_limit=%g",lower_limit) $o2.save(tstr)
sprint(tstr,"\t\tupper_limit=%g",upper_limit) $o2.save(tstr)
sprint(tstr,"\t\tstepsize=%g",stepsize) $o2.save(tstr)
sprint(tstr,"\t\tuse=%d",use) $o2.save(tstr)
sprint(tstr,"\t\tsetdisplaytext()") $o2.save(tstr)
sprint(tstr,"\t}") $o2.save(tstr)
sprint(tstr,"\t{object_pop()}") $o2.save(tstr)
}
endtemplate MRC_LoopParameter
begintemplate MRC_OutputVariableType
public gettype, gettypestr,loadhandlerclass,createhandler, virtual
strdef typestr
objref handlerclass, nil
public settypeindex,gettypeindex
external MRC_debugmode
proc init(){
typestr=$s1
virtual=$2
handlerclassloaded=0
typeindex=0
}
proc gettypestr(){
$s1=typestr
}
proc settypestr(){
typestr=$s1
}
proc settypeindex(){
typeindex=$1
}
func gettypeindex(){
return typeindex
}
proc loadhandlerclass(){
handlerclass=$o1
if(nil!=handlerclass){
handlerclassloaded=1
}
}
obfunc createhandler(){
if(1==handlerclassloaded && 2==numarg()){
//print "handlerclass:", handlerclass
return handlerclass.createhandler($o1,$o2)
}else{
if(1==MRC_debugmode){
if(1!=handlerclassloaded){
printf("Handlerclass not loaded!")
}
if(2!=numarg()){
printf("In correct number of arguments for createhandler() in object:%s",this)
}
}
return nil
}
}
endtemplate MRC_OutputVariableType
begintemplate MRC_OutputVariable
public name, displaytext, inuse
public settype, gettype, gethandler, getprotocol,setprotocol
public setdisplaytext, toggle
public get_sessionstr
objref nil,this
objref type, handler, protocol
strdef useicon, name, displaytext, tstr
external MRC_debugmode
proc init(){
if(0!=numarg()){
use=1
if(MRC_debugmode==1 && numarg()!=3){
printf("Incorrect initialization of MRC_OutputVariable")
}
name=$s1
// Don't change the order of the setprotocol and settype statements,
// settype requires that the protocol is known because protocol is passed
// to the newly instantiated handler.
setprotocol($o3)
settype($o2)
setdisplaytext()
}
}
proc settype(){
if(numarg()==1){
type=$o1
createhandler()
}else{
if(MRC_debugmode==1 ){
printf("MRC_OutputVariable:settype, Incorrect number of parameters")
}
}
//print "MRC_OutputVariable,type: " , type
}
proc setprotocol(){
protocol=$o1
}
obfunc getprotocol(){
return protocol
}
proc createhandler(){
if(1!=type.virtual){
objref handler
handler=type.createhandler(this,protocol)
setdisplaytext()
}
}
obfunc gethandler(){
return handler
}
obfunc gettype(){
return type
}
proc toggle() {
use = (use+1)%2
setdisplaytext()
}
func inuse() {
return use
}
proc setdisplaytext(){
//print "MRC_OutputVariable,setdisplaytext: " , type
type.gettypestr(tstr)
if (use) {
useicon="+"
}else{
useicon="-"
}
sprint(displaytext,"%s %s %s",useicon,name, tstr)
}
proc get_sessionstr(){
// Because there is no way of knowing whether a block is open or closed we adopted the convention that
// get_sessionstr only returns closed blocks and we make the calling code responsible for closing and
// opening blocks before and after the current blocks.
$s1=""
//sprint(tstr,"\n{tobj.setprotocol(protocol)}")
sprint(tstr,"{tobj1=types_outpar.gettypefromindex(%d)}",type.gettypeindex()) $o2.save(tstr)
sprint(tstr,"{tobj=new MRC_OutputVariable(\"%s\",tobj1,protocol)}",name) $o2.save(tstr)
sprint(tstr,"\t{object_push(tobj)}") $o2.save(tstr)
sprint(tstr,"\t{") $o2.save(tstr)
sprint(tstr,"\t\tuse=%d",use) $o2.save(tstr)
sprint(tstr,"\t\tsetdisplaytext()") $o2.save(tstr)
sprint(tstr,"\t}") $o2.save(tstr)
sprint(tstr,"\t{object_pop()}") $o2.save(tstr)
if(1!=type.virtual){
sprint(tstr,"{tobj1=tobj.gethandler()}") $o2.save(tstr)
sprint(tstr,"\t{object_push(tobj1)}") $o2.save(tstr)
handler.get_sessionstr(tstr, $o2)
sprint(tstr,"\t{object_pop()}") $o2.save(tstr)
}
}
proc unref(){local refcount
refcount=$1
//print "MRC_OutputVariable,unref: " , type
if(1==refcount){
//remove references
objref handler
}
}
endtemplate MRC_OutputVariable
begintemplate MRC_Protocol
public output_matlab_mfile, output_neuronbinary, output_axontextfile,get_sessionstr, edit
objref vbox
strdef tstr
proc init(){
output_matlab_mfile=1 // text format for matlab
output_neuronbinary=0 // See Konstantin Miller's contribution the NEURON forum
// about possibilities to import this into matlab:
// http://www.neuron.yale.edu/phpBB2/viewtopic.php?p=289&highlight=&sid=c2249fea8c8a6f51d76b5f56c9150921#289
// Supported precisions:'double','float32','int'
output_axontextfile=0 // For love of the ascii format, and to pay experimenters in their own currency.
// Requires a proper protocol class
dialog_outcome=0
loutput_matlab_mfile=output_matlab_mfile
loutput_neuronbinary=output_neuronbinary
loutput_axontextfile=output_axontextfile
}
proc createeditwindow(){
vbox=new VBox()
vbox.intercept(1)
xpanel("")
xcheckbox("Make printtofile generate matlab output",&loutput_matlab_mfile)
xcheckbox("Make printtofile generate neuron binary output",&loutput_neuronbinary)
//xcheckbox("Use indexing (sections only)",&loutput_axontextfile)
xpanel()
vbox.intercept(0)
doNotify()
dialog_outcome=vbox.dialog("Protocol Settings ","Accept","Cancel")
}
proc edit(){
dialog_outcome=0
loutput_matlab_mfile=output_matlab_mfile
loutput_neuronbinary=output_neuronbinary
loutput_axontextfile=output_axontextfile
createeditwindow()
if(1==dialog_outcome){
output_matlab_mfile=loutput_matlab_mfile
output_neuronbinary=loutput_neuronbinary
output_axontextfile=loutput_axontextfile
}
}
proc savetofile(){
}
proc get_sessionstr(){
// Because there is no way of knowing whether a block is open or closed we adopted the convention that
// get_sessionstr only returns closed blocks and we make the calling code responsible for closing and
// opening blocks before and after the current blocks.
$s1=""
sprint(tstr,"{tobj=new MRC_Protocol()}") $o2.save(tstr)
sprint(tstr,"\t{object_push(tobj)}") $o2.save(tstr)
sprint(tstr,"\t{") $o2.save(tstr)
sprint(tstr,"\t\toutput_matlab_mfile=%d",output_matlab_mfile) $o2.save(tstr)
sprint(tstr,"\t\toutput_neuronbinary=%d",output_neuronbinary) $o2.save(tstr)
sprint(tstr,"\t\toutput_axontextfile=%d",output_axontextfile) $o2.save(tstr)
sprint(tstr,"\t}") $o2.save(tstr)
sprint(tstr,"\t{object_pop()}") $o2.save(tstr)
}
endtemplate MRC_Protocol
//Here you can define classes for handling output, which will be used to for future extension of the number of handler classes
obfunc MRC_CreateOutParamHandler(){localobj nil
return nil
}
strdef MRC_ListGenerator_Str, MRC_tstr1,MRC_tstr2
objref MRC_ListGenerator_DummyObject, MRC_ListGenerator_NetCon, nil
obfunc MRC_GetObjectFromName() {localobj returnobj
if(0!=name_declared($s1)){
sprint(MRC_ListGenerator_Str,"MRC_ListGenerator_DummyObject=%s",$s1)
execute1(MRC_ListGenerator_Str)
returnobj=MRC_ListGenerator_DummyObject
} else {
MRC_SeparateSecAndIndex($s1,MRC_tstr1,MRC_tstr2,"[","]")
if(0!=name_declared(MRC_tstr1)){
sprint(MRC_ListGenerator_Str,"MRC_ListGenerator_DummyObject=%s",$s1)
execute1(MRC_ListGenerator_Str)
returnobj=MRC_ListGenerator_DummyObject
}
}
return returnobj
}
obfunc MRC_OutvecListGenerator() {local listtype,index localobj outveclist,outvec,netcon,netconlist, sources, seclist
listtype=$1
isart=$2
//listname=$s3
//sectionname=$s4
//membername=$s5
netconlist=$o6
//shortname=$s7
useindexing=$8
outveclist= new List()
//Just a reminder about the correspondence
// "List", "llisttype=0"
// "Section/Set of sections", "llisttype=2"
// "SectionList", "llisttype=3"
if(0==listtype ){
sources=MRC_GetObjectFromName($s3)
if(0==listtype){
for all_in_list (sources,&index){
outvec =new Vector()
if(0==isart){
sprint(MRC_ListGenerator_Str,"%s.object(%d).%s MRC_ListGenerator_NetCon= new NetCon(&%s,nil)" ,$s3,index,$s4,$s5)
}else{
sprint(MRC_ListGenerator_Str,"MRC_ListGenerator_NetCon= new NetCon(%s.object(%d),nil)" ,$s3,index)
}
execute1(MRC_ListGenerator_Str)
netcon=MRC_ListGenerator_NetCon
netconlist.append(netcon)
netcon.record(outvec)
outveclist.append(outvec)
//sprint(MRC_ListGenerator_Str,"%s_%d" ,$s7,index)
sprint(MRC_ListGenerator_Str,"%s{%d}" ,$s7,index+1)
outvec.label(MRC_ListGenerator_Str)
}
}
}else if(2==listtype || 3==listtype){
if(2==listtype){
seclist =new SectionList()
forsec $s3 {
seclist.append()
}
}
if(3==listtype){
seclist = MRC_GetObjectFromName($s3)
}
index=0
forsec seclist {
outvec =new Vector()
sprint(MRC_ListGenerator_Str,"MRC_ListGenerator_NetCon= new NetCon(&%s,nil)" ,$s5)
execute1(MRC_ListGenerator_Str)
netcon=MRC_ListGenerator_NetCon
netconlist.append(netcon)
netcon.record(outvec)
outveclist.append(outvec)
if(1==useindexing){
sprint(MRC_ListGenerator_Str,"%s_%d" ,$s7,index)
}else{
sprint(MRC_ListGenerator_Str,"%s_%s" ,$s7,secname())
}
outvec.label(MRC_ListGenerator_Str)
index=index+1
}
}else if(4==listtype){
outvec =new Vector()
sprint(MRC_ListGenerator_Str,"MRC_ListGenerator_NetCon= new NetCon(%s,nil)" ,$s3)
execute1(MRC_ListGenerator_Str)
netcon=MRC_ListGenerator_NetCon
netconlist.append(netcon)
netcon.record(outvec)
outveclist.append(outvec)
sprint(MRC_ListGenerator_Str,"%s",$s7)
outvec.label(MRC_ListGenerator_Str)
}else{
if(1==isart){
outvec =new Vector()
sprint(MRC_ListGenerator_Str,"MRC_ListGenerator_NetCon= new NetCon(&%s,nil)" ,$s3,index)
execute1(MRC_ListGenerator_Str)
netcon=MRC_ListGenerator_NetCon
netconlist.append(netcon)
netcon.record(outvec)
outveclist.append(outvec)
sprint(MRC_ListGenerator_Str,"%s_%d" ,$s7,index)
outvec.label(MRC_ListGenerator_Str)
}else{
if(1==MRC_debugmode){
printf("Use a section list, to specify the information needed for building a list.")
}
}
}
return outveclist
}
proc MRC_SeparateSecAndIndex(){local BraIndex, KetIndex, Length localobj StrFies
StrFies= new StringFunctions()
$s2=$s1
$s3=""
BraIndex=StrFies.substr($s1, $s4)
if(BraIndex>=0){
KetIndex=StrFies.substr($s1, $s5)
$s3=$s1
StrFies.left($s2,BraIndex)
StrFies.left($s3,KetIndex)
StrFies.right($s3,BraIndex+1)
}
}
begintemplate UndefinedOutParamHandler
public editsettings, createhandler,edit,preparerun,printtofile,show,get_sessionstr
objref nil
objref vbox
external MRC_debugmode
proc init(){
if(1==MRC_debugmode && numarg()>0){
printf("Cannot initialize undefined class with an MRC_OutputVariable or other object, please set properties again after picking the outpoutvariable type!")
}
}
obfunc createhandler(){
if(1==MRC_debugmode){
printf("Cannot create new instance of the undefined class, its supposed to be a singleton!")
}
return nil
}
func editsettings(){
vbox=new VBox()
vbox.intercept(1)
dialog_outcome=vbox.dialog("Define a type first!","Accept","or Accept anyway!")
vbox.intercept(0)
return 0
}
proc edit(){
//Stub
}
proc preparerun(){
//Stub
}
proc printtofile(){
//Stub
}
proc show(){
//Stub
}
proc get_sessionstr(){
}
endtemplate UndefinedOutParamHandler
load_file("MRC_TimeSeriesHandler.hoc")
load_file("MRC_SpikeTrainHandler.hoc")
load_file("MRC_ScalarHandler.hoc")
begintemplate MRC_OutParamHandlerContainer
public get_undefined_type
public gettypefromindex, object, count // List member functions
objref undefined_type, undefined_obj // variables for the one and only instance of the UndefinedOutParam
objref defined_type, defined_obj
objref types
// Procedure to create types, the types are later used to instantiate
// handler from th eassociated types, because the session file mechanism
// relies on the index in the list "types" new handler classes should be added at
// the bottom of the procedure.
proc init(){localobj type
types =new List()
type_index=-1
// Undefined type
undefined_type =new MRC_OutputVariableType("--Undefined--",1)
undefined_obj=new UndefinedOutParamHandler()
undefined_type.loadhandlerclass(undefined_obj)
type_index=types.append(undefined_type)-1
undefined_type.settypeindex(type_index)
// Time Series
defined_type = new MRC_OutputVariableType(" Time Series ",0)
defined_obj = new TimeSeriesHandler()
defined_type.loadhandlerclass(defined_obj)
type_index=types.append(defined_type)-1
defined_type.settypeindex(type_index)
// Spiketrain
defined_type = new MRC_OutputVariableType(" Spiketrain ",0)
defined_obj = new SpikeTrainHandler()
defined_type.loadhandlerclass(defined_obj)
type_index=types.append(defined_type)-1
defined_type.settypeindex(type_index)
// Scalar
defined_type = new MRC_OutputVariableType(" Scalar ",0)
defined_obj = new ScalarHandler()
defined_type.loadhandlerclass(defined_obj)
type_index=types.append(defined_type)-1
defined_type.settypeindex(type_index)
}
obfunc gettypefromindex(){ // for readable code
return object($1)
}
obfunc object(){ // for use with all_in_list iterator
return types.object($1)
}
obfunc get_undefined_type(){
return undefined_type
}
func count(){
return types.count()
}
endtemplate MRC_OutParamHandlerContainer