: $Id: intf.mod,v 1.392 2006/06/30 22:40:28 billl Exp $
:* main COMMENT
COMMENT
artificial cell incorporating 4 input weights with different time constants and signs
typically a fast AMPA, slow NMDA, fast GABAA, slow GABAB
features:
1. Mg dependence for NMDA activation
2. "G-protein" cooperativity for GABAB activation
3. depolarization blockade
4. AHP affects both Vm and refractory period (adaptation)
5. decrementing excitatory and/or inhibitory activity post spk (another adaptation)
since artificial cells only do calculations when they receive events, a set of vec
pointers are maintained to allow state var information storage when event arrives
(see initrec() and record())
ENDCOMMENT
:* main VERBATIM block
VERBATIM
extern void* vector_arg();
extern FILE* hoc_obj_file_arg(int narg);
extern int list_vector_px2 (Object *ob, int i, double** px, void** vv);
extern Object** hoc_objgetarg();
extern int ivoc_list_count(Object*);
extern Object* ivoc_list_item(Object*, int);
static void hxe() { hoc_execerror("",0); }
#if defined(t)
static void initmodel();
#else
static initmodel();
#endif
extern int stoprun;
extern double hoc_epsilon;
#define PI 3.141592653589793115997963468544
#define UINT_MAX 4294967295U // from /usr/include/limits.h
#define nil 0
#define SOP (((id0*) _p_sop)->vp)
#define IDP (*((id0**) &(_p_sop)))
#define NSW 20 // just store voltages
#define WSW 0 // unused; left over from old wrecord() for states
#define WSZ 1000000 // use internal vectors statt external
#define NSV 7 // 6 state variables (+ 1 for time)
typedef struct VPT {
unsigned int id;
unsigned int size;
unsigned int p;
double* vvo[NSV];
void* vv[NSV];
} vpt;
typedef struct ID0 {
vpt* vp;
float wscale;
unsigned int id;
unsigned int rvb;
unsigned int rvi;
int rve;
unsigned char type; // only use first 3 letters with iflset() -- see iflags
unsigned char col;
unsigned char record;
unsigned char wrec;
unsigned char jitter;
unsigned char input;
unsigned char vinflg;
unsigned char invl0;
signed char dbx;
unsigned char vbr; // when adding flags also augment iflags, iflnum
} id0;
// globals -- range vars must be malloc'ed in the CONSTRUCTOR
static vpt* vp; // vp and ip are used as temporary pointers
static id0* ip;
static char *name;
static char iflags[100]="typ col rec wre jit inp vin inv dbx vbr "; // use to find flags above
static char iflnum=10;
static int errflag, vspn; // turn on after generating an error message
static double *isp, *vsp, *wsp, *jsp, *invlp; // accessed by all INTF
static unsigned int jtpt,jitmax;
static double vii[NSV]; // temp storage
static unsigned int wwpt,wwsz,wwaz; // pointer, size for shared ww vectors
FILE *wf1, *wf2;
void* ww[NSW];
double* wwo[NSW];
float wwt[WSZ]; float www[WSZ]; unsigned int wwi[WSZ]; char wws[WSZ];
ENDVERBATIM
:* NEURON, PARAMETER, ASSIGNED blocks
NEURON {
ARTIFICIAL_CELL INTF
RANGE VAM, VNM, VGA, VGB, AHP :::: cell state variables
RANGE tauAM, tauNM, tauGA, tauGB, tauahp, ahpwt :::: time constants and AHP weight
RANGE VGBdel,tGB,VGBa,rebound,rebob,offsetGB :::: GABAB and rebound
RANGE RMP,VTH,Vm,Vblock,refractory :::: Vblock for depol blockade
RANGE taum,invl,oinvl,WINV,invlt :::: interval bursting params
RANGE t0,tg,twg,tGB,refrac,Vbrefrac :::: t0,tg,tGB save times for analytic calc
RANGE nbur,tbur,cbur,AHP2REF,WEX :::: burst size, interval and statevar
POINTER sop :::: Structure pointer for other range vars
GLOBAL AMdec,NMdec,GAdec,GBdec :::: decrement exc bzw inh activations after a spike
GLOBAL vdt,next,mg,RES,ESIN,Bb,Psk :::: table look up values for exp,sin,NMDA-Mg dep
GLOBAL tauGBGP,wGBGP,GPkd,Gn :::: GABAB G-protein dependence (cooperativity)
GLOBAL EAM, ENM, EGA, EGB, spkht :::: "reverse potential" distance from rest
GLOBAL prnum,wwwid,wwht,nsw,rebeg :::: for debugging moves; width/ht for pop spikes
GLOBAL subsvint
}
PARAMETER {
tauAM = 10 (ms)
tauNM = 300 (ms)
tauGA = 10 (ms)
tauGB = 300 (ms)
tauGBGP = 50 (ms) : drop off for burst effect on GABAB (G-protein)
taum = 10 (ms)
invl = 100 (ms)
WINV = 0
wGBGP = 1 (ms) : augmentation of G-protein with a spike
GPkd = 100 : maintain between 50 and 500 since table only up to 10 spikes (with wGBGP=1)
ahpwt = 0
tauahp= 10 (ms)
refrac = 5 (ms)
Vbrefrac = 20 (ms)
wwwid = 10
wwht = 10
VTH = -45 : fixed spike threshold
Vblock = -20 : level of depolarization blockade
vdt = 0.1 : time step for saving state var
mg = 1 : for NMDA Mg dep.
sop=0
AMdec=1 : default is no fall-off
NMdec=1
GAdec=1
GBdec=1
nbur=1
tbur=2
VGBdel=0
rebound=0.01 : the is param for one GB mech
offsetGB=0
RMP=-65
EAM = 65
ENM = 90
EGA = -15
EGB = -30
spkht = 50
prnum = -1
nsw=0
AHP2REF=0.1
rebeg=0
subsvint=0
}
ASSIGNED {
VAM
VNM
VGA
VGB
VGBa
AHP
t0(ms)
tGB(ms)
tg(ms)
twg(ms)
refractory
next
WEX
RES
ESIN
Gn
Bb
Psk
cbur
Vm
invlt
oinvl
rebob
}
:* CONSTRUCTOR, DESTRUCTOR, INITIAL
: create a structure to save the identity of this unit and char integer flags
CONSTRUCTOR {
VERBATIM
{ int lid,lty,lco;
if (ifarg(1)) { lid=(int) *getarg(1); } else { lid= UINT_MAX; }
if (ifarg(2)) { lty=(int) *getarg(2); } else { lty= -1; }
if (ifarg(3)) { lco=(int) *getarg(3); } else { lco= -1; }
_p_sop = (double*)ecalloc(1, sizeof(id0));
ip = IDP;
ip->id=lid; ip->type=lty; ip->col=lco;
ip->invl0 = ip->record = ip->jitter = ip->input = 0; // all flags off
ip->vbr=0;
ip->rve=-1;
}
ENDVERBATIM
}
DESTRUCTOR {
VERBATIM {
free(IDP);
}
ENDVERBATIM
}
INITIAL {
VAM = 0
VNM = 0
VGA = 0
VGB = 0
VGBa = 0
t0 = t
tGB = t
tg = 0
twg = 0
offsetGB=0
AHP=0
rebob=-1e9
invlt = -1
VERBATIM
jtpt=0; // ok to initialize since not altered during init
errflag=0;
ENDVERBATIM
refractory = 0 : 1 means cell is absolute refractory
: init with vinset(0) if will turn on via a NetCon with w5=1
if (vinflag()) { randspk() net_send(next,2)}
if (recflag()) { recini() } : recini() resets for recording, cf recinit()
rebeg=0 : will reset this to restart storage for rec,wrec
}
:* NET_RECEIVE
NET_RECEIVE (wAM,wNM,wGA,wGB,wflg) { LOCAL tmp
INITIAL { wNM=wNM wGA=wGA wGB=wGB wflg=0}
: intra-burst, generate next spike as needed
VERBATIM
ip = IDP; //@ for the flags, NB @ means VERBATIM block
ENDVERBATIM
VERBATIM
if (ip->dbx>2)
ENDVERBATIM
{
pid()
printf("DB0: flag=%g Vm=%g",flag,VAM+VNM+VGA+VGB+RMP+AHP)
if (flag==0) { printf(" (%g %g %g %g %g)",wAM,wNM,wGA,wGB,wflg) }
printf("\n")
}
: causes of spiking: between VTH and Vblock, random from vsp (flag 2), within burst
if (flag==4) { : mid-burst
cbur=cbur-1 : count down the spikes
if (cbur>0) {
net_send(tbur,4)
} else {
net_send(refrac-AHP*AHP2REF, 3) : AHP doubles as a refrac period extender
}
tmp=t
VERBATIM
if (ip->jitter)
ENDVERBATIM
{ tmp= t+jitter()/10 }
net_event(tmp)
VERBATIM
if (ip->dbx>0)
ENDVERBATIM
{ pid() printf("DBA: mid-burst event at %g, %g\n",tmp,cbur) }
VERBATIM
if (ip->record)
ENDVERBATIM
{ recspk(tmp) }
VERBATIM
if (ip->wrec)
ENDVERBATIM
{ wrecord(t) }
: if (wrec) { wrecordOLD(tmp,-1,0) }
: start reading random spike times (or burst times) from vsp vector pointer
: this is signaled externally from a netstim with wflg=1, will turn off on next stim
: (NB wflg used in completely different context for GABAB)
: this is bad -- should use a special netcon that just handles signals
} else if (flag==0 && wGB==0 && wflg==1) {
VERBATIM
ip->input=1; //@
ENDVERBATIM
wflg=2 : set flag to turn off next time an external event comes from here
randspk()
net_send(next,2)
} else if (flag==0 && wGB==0 && wflg==2) { : flag to stop random spikes
VERBATIM
ip->input=0; //@ inputs that are read from a vector of times -- see randspk()
ENDVERBATIM
wflg=1 : flag to turn on next time
} else { : external input
VERBATIM
if (ip->record)
ENDVERBATIM
{ record() }
VERBATIM
if (ip->wrec)
ENDVERBATIM
{ wrecord(1e9) }
: update all statevars
if (VAM>hoc_epsilon) { VAM = VAM*EXP(-(t - t0)/tauAM) } else { VAM=0 } :AMPA
if (VNM>hoc_epsilon) { VNM = VNM*EXP(-(t - t0)/tauNM) } else { VNM=0 } :NMDA
if (VGA< -hoc_epsilon){ VGA = VGA*EXP(-(t - t0)/tauGA) } else { VGA=0 } :GABAA
if (VGBdel>0) {
VGB = esinr(t-tGB) :VGB has to update each t but calc based on triggering tGB and val VGBa
} else {
if (VGB< -hoc_epsilon){
VGB = VGB*EXP(-(t - t0)/tauGB) } else { VGB=0 }
}
if (AHP< -hoc_epsilon){ AHP = AHP*EXP(-(t-t0)/tauahp) } else { AHP=0 } : adaptation
t0 = t : finished using t0
: for debugging if (VGA<EGA) { pid() printf("CC: %g %g %g %g\n",VGA,wGA,EGA,Vm) }
Vm = VAM+VNM+VGA+VGB+AHP : membrane deviation from rest
if (Vm>100||Vm<-60){ pid()
printf("ERR_A: Vm=%g (%g,%g,%g,%g,%g)\n",Vm,VAM,VNM,VGA,VGB,AHP)
stoprun=1
}
if (flag==0) { : only add weights if an external excitation
: AMPA Erev=0 (0-RMP==65 mV above rest)
if (wAM>0) {
if (rebob!=1e9 && rebob!=-1e9) {
VERBATIM
cbur=floor(rebound*rebob/EGB); //@
ENDVERBATIM
VERBATIM
if (ip->dbx==-1)
ENDVERBATIM
{ pid() printf("C: %g %g\n",cbur,rebob) }
net_send(tbur,4)
rebob=1e9
}
if (VAM<EAM) {
tmp = wAM*(1-Vm/EAM)
VAM = VAM + tmp
}
}
: NMDA; Mg effect based on total activation in rates()
if (wNM>0 && VNM<ENM) { rates(RMP+Vm)
tmp = wNM*Bb*(1-Vm/ENM)
VNM = VNM + tmp
: if (wrec) { wrecordOLD(t,1,tmp) }
}
if (VNM>1.2*ENM) { pid() : signal if some nasty number creeps in here
: allow it to creep over by a little which can happend with coincident spikes
printf("ERR_B: VNM=%g wNM=%g ENM=%g Vm=%g\n",VNM,wNM,ENM,Vm)
stoprun=1
}
: GABAA and GABAB: note that all wts are positive
if (wGA>0 && VGA>EGA) {
tmp = wGA*(1-Vm/EGA)
VGA = VGA - tmp
: if (wrec) { wrecordOLD(t,2,tmp) }
}
if (wGB>1e-6) {
if (VGBdel>0) { net_send(VGBdel,5) : delayed effect
} else { : handle wGB immediately
: wflg will augment each time there is spike coming in through this line
wflg=wflg*EXP(-(t-tGB)/tauGBGP)+wGBGP
coop(wflg) : cooperativity -- need mult presyn spikes to activate
tmp = wGB*(1-Vm/EGB)*Gn
VGB = VGB - tmp
if (VGB<rebob && rebob!=1e9 && rebob!=-1e9) { rebob=VGB }
}
}
VERBATIM
if (ip->invl0)
ENDVERBATIM
{
Vm = RMP+VAM+VNM+VGA+VGB+AHP
if (invlt==-1) { : activate for first time
if (Vm>RMP) {
oinvl=invl
invlt=t
net_send(invl,1)
}
} else {
tmp=shift(Vm)
if (tmp!=0) {
net_move(tmp)
if (id()<prnum) {
pid() printf("**** MOVE t=%g to %g Vm=%g %g,%g\n",t,tmp,Vm,invlt,oinvl) }
}
}
}
} else if (flag==5) { : flag==5 to set GABAB weight after a delay
offsetGB = VGB : current position
: wflg overloaded; tauGBGP for GB cooperativity
: wflg will augment each time there is spike coming in through this line
wflg=wflg*EXP(-(t-tGB)/tauGBGP)+wGBGP
coop(wflg) : cooperativity -- need mult presyn spikes to activate
: calculate separately based on VGBa and tGB
if (VGB>EGB) {
tmp = wGB*(1-Vm/EGB)*Gn
VGB = VGB - tmp
: if (wrec) { wrecordOLD(t,3,tmp) }
}
VGBa= VGB
tGB=t : restart for VGB
: flag==2 -- read off external vec (vsp) for next random spike time
} else if (flag==2) {
VERBATIM
if (ip->input==0)
ENDVERBATIM
{ flag=-1 }
if (flag==2) { : else for @VERBATIM
VERBATIM
if (ip->dbx>1)
ENDVERBATIM
{pid() printf("DBBa: randspk called: %g,%g\n",WEX,next)}
if (WEX<0) {
net_event(t) : bypass activation calculation
VERBATIM
if (ip->dbx>0)
ENDVERBATIM
{pid() printf("DBB: randspk event\n")}
if (WEX<-1) { cbur=-WEX net_send(tbur,4) }
VERBATIM
if (ip->record)
ENDVERBATIM
{ recspk(t) }
VERBATIM
if (ip->wrec)
ENDVERBATIM
{ wrecord(t) }
: if (wrec) { wrecordOLD(t,-1,0) }
} else if (WEX>0) {
tmp = WEX*(1-Vm/EAM)
VAM = VAM + tmp
: if (wrec) { wrecordOLD(t,0,tmp) }
}
randspk() : will set WEX for next time
if (next>0) { net_send(next,2) }
}
} else if (flag==1) {
: Vm=RMP+VAM+VNM+VGA+VGB+AHP
if (WINV<0) {
net_event(t) : bypass activation calculation
VERBATIM
if (ip->dbx>0)
ENDVERBATIM
{pid() printf("DBC: interval event\n")}
VERBATIM
if (ip->record)
ENDVERBATIM
{ recspk(t) }
VERBATIM
if (ip->wrec)
ENDVERBATIM
{ wrecord(t) }
: if (wrec) { wrecordOLD(t,-1,0) }
} else {
tmp = WINV*(1-Vm/EAM)
VAM = VAM + tmp :: activate interval depolarization
: if (wrec) { wrecordOLD(t,0,tmp) }
}
oinvl=invl
invlt=t
net_send(invl,1)
} else if (flag==3) {
refractory = 0 :end of refractory period
}
Vm = VAM+VNM+VGA+VGB+RMP+AHP
if (refractory==0 && Vm>VTH) {
VERBATIM
if (!ip->vbr && Vm>Vblock) return; //@ do nothing
ENDVERBATIM
AHP = AHP - ahpwt
tmp=t
VERBATIM
if (ip->jitter)
ENDVERBATIM
{ tmp= t+jitter() }
net_event(tmp)
VERBATIM
if (ip->dbx>0)
ENDVERBATIM
{pid() printf("DBD: %g>VTH event at %g\n",Vm,tmp)}
VERBATIM
if (ip->record)
ENDVERBATIM
{ recspk(tmp) }
VERBATIM
if (ip->wrec)
ENDVERBATIM
{ wrecord(tmp) }
: if (wrec) { wrecordOLD(tmp,-2,0) }
VAM=VAM*AMdec VNM=VNM*NMdec
VGA=VGA*GAdec VGB=VGB*GBdec
if (nbur>1) {
cbur=nbur-1 net_send(tbur,4)
VERBATIM
return; //@ done
ENDVERBATIM
} else if (rebob==1e9) { rebob=0 }
refractory = 1
VERBATIM
if (ip->vbr && Vm>Vblock)
ENDVERBATIM
{
net_send(Vbrefrac,3)
VERBATIM
if (ip->dbx>0)
ENDVERBATIM
{pid() printf("DBE: %g %g\n",Vbrefrac,Vm)}
VERBATIM
return; //@ done
ENDVERBATIM
}
net_send(refrac-AHP*AHP2REF, 3) : AHP doubles as a refrac period extender
}
}
}
:* ancillary functions
:** randspk() sets next to next val in vector, this vector is handled globally
PROCEDURE randspk () {
VERBATIM
ip=IDP;
if (ip->rvi > ip->rve) { // pointers go from rvi to rve inclusive
ip->input=0; // turn off
next=-1.;
} else {
// absolute times in vector -> interval
while ((next=vsp[ip->rvi++]-t)<=1e-6) if (ip->rvi > ip->rve) {
printf("randspk() ERRA: "); chk(2.); hxe(); }
WEX=wsp[ip->rvi-1]; // rvi was incremented
if (ip->dbx== -1) { printf("randspk() DBXA: %d %g %g",ip->rvi,next,WEX); chk(2.); }
}
ENDVERBATIM
: net_send(next,2) : must be called from appropriate blocks
}
:** vers gives version
PROCEDURE vers () {
printf("$Id: intf.mod,v 1.392 2006/06/30 22:40:28 billl Exp $\n")
}
:** val(t,tstart) fills global vii[] to pass values back to record() (called from record())
VERBATIM
void val(double xx, double ta) {
vii[1]=VAM*EXP(-(xx - ta)/tauAM);
vii[2]=VNM*EXP(-(xx - ta)/tauNM);
vii[3]=VGA*EXP(-(xx - ta)/tauGA);
if (VGBdel>0) {
vii[4]=esinr(xx-tGB);
} else {
vii[4]=VGB*EXP(-(xx - ta)/tauGB);
}
vii[5]=AHP*EXP(-(xx - ta)/tauahp);
vii[6]=vii[1]+vii[2]+vii[3]+vii[4]+vii[5];
}
ENDVERBATIM
:** valps(t,tstart) like val but builds voltages for pop spike
VERBATIM
void valps(double xx, double ta) {
vii[1]=VAM*EXP(-(xx - ta)/tauAM);
vii[2]=VNM*EXP(-(xx - ta)/tauNM);
vii[3]=VGA*EXP(-(xx - ta)/tauGA);
// vii[4]=esinr(xx-tGB);
// vii[5]=AHP*EXP(-(xx - ta)/tauahp);
vii[6]=vii[1]+vii[2]+vii[3]; // exclude GABAB for now vii[4];
}
ENDVERBATIM
:** record() stores values since last tg into appropriate vecs
PROCEDURE record () {
VERBATIM {
int k; double ti;
vp = SOP;
if (tg>=t) return 0;
if (vp->p >= vp->size) {
if (errflag) return 0;
printf("**** WARNING out of recording room for INTF type%d id%d at %g****\n",IDP->type,IDP->id,t);
printf("**************** WARNING: No further WARNINGS ****************\n");
errflag=1;
return 0;
}
for (ti=tg;ti<=t && vp->p < vp->size;ti+=vdt,vp->p++) {
val(ti,tg);
vp->vvo[0][vp->p]=ti;
for (k=1;k<NSV;k++) if (vp->vvo[k]!=0) { // not nil pointer
vp->vvo[k][vp->p]=vii[k]+RMP;
}
}
tg=t;
}
ENDVERBATIM
}
:** recspk() records a spike by writing a 10 into the main VM vector
PROCEDURE recspk (x) {
VERBATIM { int k;
vp = SOP;
record();
if (vp->p >= vp->size || vp->vvo[6]==0) {
return 0;
}
vp->vvo[0][vp->p-1]=_lx;
vp->vvo[6][vp->p-1]=spkht; // the spike
tg=_lx;
}
ENDVERBATIM
}
:** recclr() clear the vectors pointers
PROCEDURE recclr () {
VERBATIM
{int k;
if (IDP->record) {
if (SOP!=nil) {
vp = SOP;
vp->size=0; vp->p=0;
for (k=0;k<NSV;k++) { vp->vv[k]=nil; vp->vvo[k]=nil; }
} else printf("INTF recclr ERR: nil pointer\n");
}
IDP->record=0;
}
ENDVERBATIM
}
:** recfree() free the vpt pointer memory
PROCEDURE recfree () {
VERBATIM
if (SOP!=nil) {
free(SOP);
SOP=nil;
} else printf("INTF recfree ERR: nil pointer\n");
IDP->record=0;
ENDVERBATIM
}
:** initvspks() sets up vector from which to read random spike times
: this is a range procedure to set up pieces of a global vector
: all cells share one vector but read from different locations
: (CHANGED from intervals and global proc in v224)
PROCEDURE initvspks () {
VERBATIM
{int max, i,err;
double last;
if (! ifarg(1)) {printf("Return initvspks(ivspks,vspks,wvspks)\n"); return 0.;}
ip=IDP; err=0;
i = vector_arg_px(1, &isp); // could just set up the pointers once
max=vector_arg_px(2, &vsp);
if (max!=i) {err=1; printf("initvspks ERR: vecs of different size\n");}
if (max==0) {err=1; printf("initvspks ERR: vec not initialized\n");}
max=vector_arg_px(3, &wsp);
if (max!=i) {err=1; printf("initvspks ERR: 3rd vec is of different size\n");}
vspn=max;
ip->vinflg=1;
for (i=0; i<max && (int)isp[i] != ip->id ; i++); // move forward to first
if (i==max) {
printf("initvspks WARN: %d not found in ivspks\n",ip->id);
ip->vinflg=0; ip->rve=-1;
return(0.);
}
ip->rvb=ip->rvi=i;
last=vsp[i++];
for (; i<max && (int)isp[i] == ip->id ; i++) { // move forward to last
if (vsp[i]<=last) { err=1;
printf("initvspks ERR: nonmonotonic for cell#%d: %g %g\n",ip->id,last,vsp[i]); }
last=vsp[i];
}
ip->rve=i-1;
if (subsvint>0) {
vsp[ip->rve] = vsp[ip->rvb]+subsvint;
wsp[ip->rve] = wsp[ip->rvb];
}
if (err) { ip->rve=0; hoc_execerror("",0); }
}
ENDVERBATIM
}
: trvsp gets called globally to go through the vector
: first pass (arg 1) it replaces terminal values with 1e9
: second pass (arg 2) it replaces terminal values with first+subsvint
PROCEDURE trvsp ()
{
VERBATIM
int i, flag;
double ind, t0_local;
ip=IDP;
flag=(int) *getarg(1);
if (subsvint==0.) {printf("trvsp"); return(0.);}
ind=isp[0]; t0_local=vsp[0];
if (flag==1) {
for (i=0; i<vspn; i++) {
if (isp[i]!=ind) {
vsp[i-1]=1.e9;
ind=isp[i];
}
}
vsp[vspn-1]=1.e9;
} else if (flag==2) {
for (i=0; i<vspn; i++) {
if (isp[i]!=ind) {
vsp[i-1] = t0_local + subsvint;
ind = isp[i];
t0_local = vsp[i];
}
}
vsp[vspn-1] = t0_local + subsvint;
} else {printf("trvsp flag %d not recognized\n",flag); hxe();}
ENDVERBATIM
}
:** initjitter() sets up vector from which to read jitter
: this is a global not a range procedure -- just call once
PROCEDURE initjitter () {
VERBATIM
{int max, i, err=0;
jtpt=0;
if (! ifarg(1)) {printf("Return initjitter(vec)\n"); return(0.);}
max=vector_arg_px(1, &jsp);
if (max==0) {err=1; printf("initjitter ERR: vec not initialized\n");}
for (i=0; i<max; i++) if (jsp[i]<=0) {err=1;
printf("initjitter ERR: vec should be >0: %g\n",jsp[i]);}
if (err) { jsp=nil; jitmax=0.; return(0.); }// hoc_execerror("",0);
if (max != jitmax) {
printf("WARNING: resetting jitmax_INTF to %d\n",max); jitmax=max; }
}
ENDVERBATIM
}
:* initinvl() sets up vector from which to read intervals
: this is a global not a range procedure -- just call once
PROCEDURE initinvl () {
printf("initinvl() NOT BEING USED\n")
}
: invlflag() used internally; can't set from here; use initinvl() and range invlset()
FUNCTION invlflag () {
VERBATIM
ip=IDP;
if (ip->invl0==1 && invlp==nil) { // err
printf("INTF invlflag ERR: pointer not initialized\n"); hoc_execerror("",0);
}
_linvlflag= (double)ip->invl0;
ENDVERBATIM
}
:** shift() returns the appropriate shift
FUNCTION shift (vl) {
VERBATIM
double expand, tmp, min, max;
//if (invlp==nil) {printf("INTF invlflag ERRa: pointer not initialized\n"); hoc_execerror("",0);}
if ((t<(invlt-invl)+invl/2) && invlt != -1) { // don't shift if less than halfway through
_lshift=0.; // flag for no shift
} else {
expand = -(_lvl-(-65))/20; // expand positive if hyperpolarized
if (expand>1.) expand=1.; if (expand<-1.) expand=-1.;
if (expand>0.) { // expand interval
max=1.5*invl;
tmp=oinvl+0.8*expand*(max-oinvl); // the amount we can add to the invl
} else {
min=0.5*invl;
tmp=oinvl+0.8*expand*(oinvl-min); // the amount we can reduce current invl
}
if (invlt+tmp<t+2) { // getting too near spike time
_lshift=0.;
} else {
oinvl=tmp; // new interval
_lshift=invlt+oinvl;
}
}
ENDVERBATIM
}
:* recini() called from INITIAL block to set vp->p to zero and open up vectors
PROCEDURE recini () {
VERBATIM
{ int k;
if (SOP==nil) {
printf("INTF record ERR: but pointer not initialized\n"); hoc_execerror("",0);
} else {
vp = SOP;
vp->p=0;
// open up the vector maximally before writing into it; will correct size in fini
for (k=0;k<NSV;k++) if (vp->vvo[k]!=0) vector_resize(vp->vv[k], vp->size);
}}
ENDVERBATIM
}
:** fini() to finish up recording -- should be called from FinishMisc()
PROCEDURE fini () {
VERBATIM
{int k;
// initialization for next round, this will not be set if job terminates prematurely
IDP->rvi=IDP->rvb; // -- see vinset()
if (IDP->wrec) { wrecord(1e9); }
if (IDP->record) {
record(); // finish up
for (k=0;k<NSV;k++) if (vp->vvo[k]!=0) { // not nil pointer
vector_resize(vp->vv[k], vp->p);
}
}}
ENDVERBATIM
}
:** chk([flag]) with flag=1 prints out info on the record structure
: flag=2 prints out info on the global vectors
PROCEDURE chk (f) {
VERBATIM
{int i,lfg;
lfg=(int)_lf;
ip=IDP;
printf("ID:%d; typ: %d; rec:%d wrec:%d inp:%d jit:%d invl:%d\n",ip->id,ip->type,ip->record,ip->wrec,ip->input,ip->jitter,ip->invl0);
if (lfg==1) {
if (SOP!=nil) {
vp = SOP;
printf("p %d size %d tg %g\n",vp->p,vp->size,tg);
for (i=0;i<NSV;i++) printf("%d %x %x;",i,vp->vv[i],vp->vvo[i]);
} else printf("Recording pointers not initialized");
}
if (lfg==2) {
printf("Global vectors for input and jitter: \n");
if (vsp!=nil) printf("VSP: %x (%d/%d-%d)\n",vsp,ip->rvi,ip->rvb,ip->rve); else printf("no VSP\n");
if (jsp!=nil) printf("JSP: %x (%d/%d)\n",jsp,jtpt,jitmax); else printf("no JSP\n");
}
if (lfg==3) {
if (vsp!=nil) { printf("VSP: (%d/%d-%d)\n",ip->rvi,ip->rvb,ip->rve);
for (i=ip->rvb;i<=ip->rve;i++) printf("%d:%g ",i,vsp[i]);
printf("\n");
} else printf("no VSP\n");
}
if (lfg==4) { // was used to give invlp[],invlmax
}
if (lfg==5) {
printf("wwpt %d wwsz %d\n WW vecs: ",wwpt,wwsz);
printf("wwwid %g wwht %d nsw %g\n WW vecs: ",wwwid,(int)wwht,nsw);
for (i=0;i<NSW;i++) printf("%d %x %x;",i,ww[i],wwo[i]);
}}
ENDVERBATIM
}
:** id() and pid() identify the cell -- printf and function return
FUNCTION pid () {
VERBATIM
printf("INTF%d(%d/%d@%g) ",IDP->id,IDP->type,IDP->col,t);
_lpid = (double)IDP->id;
ENDVERBATIM
}
FUNCTION id () {
VERBATIM
_lid = (double)IDP->id; //@
ENDVERBATIM
}
FUNCTION type () {
VERBATIM
_ltype = (double)IDP->type; //@
ENDVERBATIM
}
FUNCTION col () {
VERBATIM
ip = IDP;
if (ifarg(1)) ip->col = (unsigned char) *getarg(1);
_lcol = (double)ip->col;
ENDVERBATIM
}
FUNCTION dbx () {
VERBATIM
ip = IDP;
if (ifarg(1)) ip->dbx = (unsigned char) *getarg(1);
_ldbx = (double)ip->dbx;
ENDVERBATIM
}
:** initrec(name,vec) sets up recording of name (see varnum for list) into a vector
PROCEDURE initrec () {
VERBATIM
{int i; void *vv;
name = gargstr(1);
if (SOP==nil) {
IDP->record=1;
SOP = (vpt*)ecalloc(1, sizeof(vpt));
SOP->size=0;
}
if (IDP->record==0) {
recini();
IDP->record=1;
}
vp = SOP;
i=(int)varnum();
if (i==-1) {printf("INTF record ERR %s not recognized\n",name); hoc_execerror("",0); }
vp->vv[i]=vector_arg(2);
vector_arg_px(2, &(vp->vvo[i]));
if (vp->size==0) { vp->size=(unsigned int)vector_buffer_size(vp->vv[i]);
} else if (vp->size != (unsigned int)vector_buffer_size(vp->vv[i])) {
printf("INTF initrec ERR vectors not all same size: %d vs %d",vp->size,vector_buffer_size(vp->vv[i]));
hoc_execerror("", 0);
}}
ENDVERBATIM
}
:** varnum(statevar_name) returns index number associated with particular variable name
: called by initrec() using global name
FUNCTION varnum () { LOCAL i
i=-1
VERBATIM
if (strcmp(name,"time")==0) { _li=0.;
} else if (strcmp(name,"VAM")==0) { _li=1.;
} else if (strcmp(name,"VNM")==0) { _li=2.;
} else if (strcmp(name,"VGA")==0) { _li=3.;
} else if (strcmp(name,"VGB")==0) { _li=4.;
} else if (strcmp(name,"AHP")==0) { _li=5.;
} else if (strcmp(name,"V")==0) { _li=6.;
} else if (strcmp(name,"VM")==0) { _li=6.; // 2 names for V
}
ENDVERBATIM
varnum=i
}
:** vecname(INDEX) prints name when given an index
PROCEDURE vecname () {
VERBATIM
int i;
i = (int)*getarg(1);
if (i==0) printf("time\n");
else if (i==1) printf("VAM\n");
else if (i==2) printf("VNM\n");
else if (i==3) printf("VGA\n");
else if (i==4) printf("VGB\n");
else if (i==5) printf("AHP\n");
else if (i==6) printf("V\n");
ENDVERBATIM
}
:* rebuild() -- build the vvo vectors from stored wwo information
PROCEDURE rebuild () { LOCAL s0,w0,wwaz,ii,wflg,tmp
VERBATIM
int ii,jj; double i0,tstop;
ip = IDP; vp=SOP; // grab all the flags
ip->record=1; ip->input=0; i0=wwo[1][0];
initmodel(); _lwwaz=wwaz; _lii=0.;
tstop=(ifarg(1))?(*getarg(1)):0.;
ENDVERBATIM
WHILE (ii<wwaz) { : no 'for' loop in NMODL
VERBATIM
int ii=(int)_lii;
if (wwo[1][ii]!=i0) {
printf("ERROR wrong id at %d %g not %g\n",ii,wwo[1][ii],i0); hoc_execerror("", 0);}
t=wwo[0][ii]; _ls0=wwo[2][ii]; _lw0=wwo[3][ii];
ENDVERBATIM
record()
: update all statevars
if (VAM>hoc_epsilon) { VAM = VAM*EXP(-(t - t0)/tauAM) } else { VAM=0 } :AMPA
if (VNM>hoc_epsilon) { VNM = VNM*EXP(-(t - t0)/tauNM) } else { VNM=0 } :NMDA
if (VGA< -hoc_epsilon){ VGA = VGA*EXP(-(t - t0)/tauGA) } else { VGA=0 } :GABAA
VGB = esinr(t-tGB) : VGB has to update each t but calc based on triggering tGB and val VGBa
if (AHP< -hoc_epsilon){ AHP = AHP*EXP(-(t-t0)/tauahp) } else { AHP=0 } : adaptation
if (s0==0) { VAM = VAM + w0 }
if (s0==1) { VNM = VNM + w0 }
if (s0==2) { VGA = VGA - w0 }
if (s0==3) {
offsetGB = VGB : current position
VGB = VGB - w0
VGBa= VGB
tGB=t
}
if (s0==-2) {
recspk(t)
AHP = AHP - ahpwt
VAM=VAM*AMdec VNM=VNM*NMdec
VGA=VGA*GAdec VGB=VGB*GBdec
}
if (s0==-1) { recspk(t) }
t0 = t
ii = ii+1
}
if (tstop>0) {
VERBATIM
t=tstop; // not allowed to set t in a mod file
ENDVERBATIM
record()
}
}
:* wrec block
:** initwrecOLD(vec1,vec2,vec3,vec4) sets up recording of external events
PROCEDURE initwrecOLD () {
VERBATIM
{int k;
if (! ifarg(4)) { // assign 2 files
wwsz=WSZ;
wf1 = hoc_obj_file_arg(1);
wf2 = hoc_obj_file_arg(2);
} else if (! ifarg(8)) { // assign 4 vectors
if (WSW!=4) {
printf("INTF initwrec ERR w-vecs compiled for 4 args\n");
hoc_execerror("",0); }
IDP->wrec=1;
for (k=0;k<WSW;k++) {
ww[k]=vector_arg(k+1);
wwaz=vector_arg_px(k+1, &(wwo[k]));
}
if (wwsz==0) wwsz=(unsigned int)vector_buffer_size(ww[0]);
for (k=0;k<WSW;k++) if (wwsz!=(unsigned int)vector_buffer_size(ww[k])) {
printf("INTF initwrec ERR w-vecs size err: %d,%d,%d",k,wwsz,vector_buffer_size(ww[k]));
}
} else { // assign 8 vectors
if (WSW!=8) {
printf("INTF initwrec ERR w-vecs compiled for 8 args\n");
hoc_execerror("",0); }
IDP->wrec=1;
for (k=0;k<WSW;k++) {
ww[k]=vector_arg(k+1);
wwaz=vector_arg_px(k+1, &(wwo[k]));
}
if (wwsz==0) wwsz=(unsigned int)vector_buffer_size(ww[0]);
for (k=0;k<WSW;k++) if (wwsz!=(unsigned int)vector_buffer_size(ww[k])) {
printf("INTF initwrec ERR w-vecs size err: %d,%d,%d",k,wwsz,vector_buffer_size(ww[k]));
}
}}
ENDVERBATIM
}
:** initwrec(name,vec) sets up recording of name (see varnum for list) into a vector
PROCEDURE initwrec () {
VERBATIM
{int i, k, num, cap; Object* ob;
ob = *hoc_objgetarg(1); // list of vectors
num = ivoc_list_count(ob);
if (num>NSW) { printf("INTF initwrec() WARN: can only store %d ww vecs\n",NSW); hxe();}
nsw=(double)num;
for (k=0;k<num;k++) {
cap = list_vector_px2(ob, k, &wwo[k], &ww[k]);
if (k==0) wwsz=cap; else if (wwsz!=cap) {
printf("INTF initwrec ERR w-vecs size err: %d,%d,%d",k,wwsz,cap); hxe(); }
}
}
ENDVERBATIM
}
:** wrecord()
PROCEDURE wrecordOLD (t,s0,w0) {
VERBATIM {
int k; double id = (double)IDP->id;
if (wwpt >= wwsz) {
wwpt=0;
fprintf(wf1,"//b8 %d INTF %g %d\n",WSZ,_lt,ftell(wf2));
fwrite(&wwt,sizeof(float),WSZ,wf2); // write out the size
fwrite(&wwi,sizeof(int),WSZ,wf2); // write out the size
fwrite(&wws,sizeof(char),WSZ,wf2); // write out the size
fwrite(&www,sizeof(float),WSZ,wf2); // write out the size
}
// wwo[0][wwpt]=_lt; wwo[1][wwpt]=id; wwo[2][wwpt]=_ls0; wwo[3][wwpt]=_lw0; wwpt++;
wwt[wwpt]=(float)_lt;
wwi[wwpt]=(unsigned int)IDP->id;
wws[wwpt]=(char)_ls0;
www[wwpt]=(float)_lw0;
wwpt++;
}
ENDVERBATIM
}
: popspk() is paste on gaussian for a pop spk: with vdt=0.1 -20 to 20 is 4 ms
: needs to be above location where is actively accessed
PROCEDURE popspk (x) {
TABLE Psk DEPEND wwwid,wwht FROM -40 TO 40 WITH 81
Psk = -wwht*exp(-2.*x*x/wwwid/wwwid)
}
PROCEDURE pskshowtable () {
VERBATIM
int j;
printf("_tmin_popspk:%g -_tmin_popspk:%g\n",_tmin_popspk,-_tmin_popspk);
for (j=0;j<=-2*(int)_tmin_popspk+1;j++) printf("%g ",_t_Psk[j]);
printf("\n");
ENDVERBATIM
}
:** wrecord() records voltages onto single global vector
PROCEDURE wrecord (te) {
VERBATIM
{int j,k,max,wrp; double ti,scale;
wrp=(int)IDP->wrec-1; // wrp: index for multiple field recordings
scale=(double)IDP->wscale;
if (_lte<1.e9) { // a spike recording
max=-(int)_tmin_popspk; // max of table max=-min
k=(int)floor((_lte-rebeg)/vdt+0.5);
for (j= -max;j<=max && k+j>0 && k+j<wwsz;j++) {
wwo[wrp][k+j] += scale*_t_Psk[j+max]; // direct copy from the Psk table
}
} else if (twg>=t) {
return 0;
} else {
for (ti=twg,k=(int)floor((twg-rebeg)/vdt+0.5);ti<=t && k<wwsz;ti+=vdt,k++) {
valps(ti,twg); // valps() for pop spike calculation
wwo[wrp][k]+=scale*vii[6];
}
twg=ti;
}
}
ENDVERBATIM
}
FUNCTION wrec () {
VERBATIM
ip=IDP;
if (ifarg(1)) ip->wrec = (unsigned char) *getarg(1);
if (ifarg(2)) ip->wscale = (float) *getarg(2); else ip->wscale=1.;
_lwrec=(double)ip->wrec;
ENDVERBATIM
}
FUNCTION wwszset () {
VERBATIM
if (ifarg(1)) wwsz = (unsigned int) *getarg(1);
_lwwszset=(double)wwsz;
ENDVERBATIM
}
:** wwfree()
FUNCTION wwfree () {
VERBATIM
int k;
IDP->wrec=0;
wwsz=0; wwpt=0; nsw=0.;
for (k=0;k<NSW;k++) { ww[k]=nil; wwo[k]=nil; }
ENDVERBATIM
}
:* jitter
:** jitter() reads out of a noise vector (call from NET_RECEIVE block)
FUNCTION jitter () {
if (jitmax>0 && jtpt>=jitmax) { jtpt=0
printf("Warning, cycling through jitter vector at t=%g\n",t) }
if (jitmax>0) {
VERBATIM
_ljitter = jsp[jtpt++];
ENDVERBATIM
} else { jitter=0 }
}
:** initialize globals shared by all INTFs
PROCEDURE global_init () {
popspk(0) : recreate table if any change in wid or ht
VERBATIM
int j,k;
if (nsw>0. && wwo[0]!=0) { // do just once
printf("Initializing ww to record for %g (%g)\n",vdt*wwsz,vdt);
wwpt=0;
for (k=0;k<(int)nsw;k++) {
vector_resize(ww[k], wwsz);
for (j=0;j<wwsz;j++) wwo[k][j]=0.;
}
} else printf("global_init WARNING: wrec not initialized\n");
ENDVERBATIM
}
PROCEDURE global_fini () {
VERBATIM
int k;
for (k=0;k<(int)nsw;k++) vector_resize(ww[k], (int)floor(t/vdt+0.5));
ENDVERBATIM
}
PROCEDURE global_finiOLD () {
VERBATIM
{int k;
if (IDP->wrec) {
if (wwo[0]!=0) {
for (k=0;k<WSW;k++) vector_resize(ww[k], wwpt);
} else {
fprintf(wf1,"//b8 %d INTF %g %d\n",wwpt,t,ftell(wf2));
fwrite(&wwt,sizeof(float),wwpt,wf2); // write out the size
fwrite(&wwi,sizeof(int),wwpt,wf2); // write out the size
fwrite(&wws,sizeof(char),wwpt,wf2); // write out the size
fwrite(&www,sizeof(float),wwpt,wf2); // write out the size
printf("Closing file with wwpt=%d at location %d\n",wwpt,ftell(wf2));
fclose(wf1); fclose(wf2);
}
} else {
printf("WARNING: global_fini() called from %d:%d with no wrec pointers\n",IDP->type,IDP->id);
}}
ENDVERBATIM
}
:** setting and getting flags: fflag, record,input,jitter
FUNCTION fflag () { fflag=1 }
FUNCTION thresh () { thresh=VTH-RMP }
: reflag() used internally; can't set from here; use recinit()
FUNCTION recflag () {
VERBATIM
_lrecflag= (double)IDP->record;
ENDVERBATIM
}
: vinflag() used internally; can't set from here; use global initvspks() and range vinset()
FUNCTION vinflag () {
VERBATIM
ip=IDP;
if (ip->vinflg==0 && vsp==nil) { // do nothing
} else if (ip->vinflg==1 && ip->rve==-1) {
printf("INTF vinflag ERR: pointer not initialized\n"); hoc_execerror("",0);
} else if (ip->rve >= 0) {
if (vsp==nil) {
printf("INTF vinflag ERR1: pointer not initialized\n"); hoc_execerror("",0);
}
ip->rvi=ip->rvb;
ip->input=1;
}
_lvinflag= (double)ip->vinflg;
ENDVERBATIM
}
: jitset([val]) set or get the jitter flag
FUNCTION jitset () {
VERBATIM
ip=IDP;
if (ifarg(1)) ip->jitter = (unsigned char) *getarg(1);
_ljitset=(double)ip->jitter;
ENDVERBATIM
}
: flag(name,[val]) set or get the a flag
: seek names from iflags[] and look at location &ip->type -- beginning of flags
FUNCTION flag () {
VERBATIM
char *sf; int ii;
ip = IDP;
sf = gargstr(1);
for (ii=0;ii<iflnum && strncmp(sf, &iflags[ii*4], 3)!=0;ii++) ;
if (ii==10) {printf("INTF ERR: %s not found as a flag (%s)\n",sf,iflags); hxe();}
if (ifarg(2)) (&ip->type)[ii] = (unsigned char) *getarg(2);
_lflag=(double)(unsigned char)(&ip->type)[ii];
ENDVERBATIM
}
: invlset([val]) set or get the invl flag
FUNCTION invlset () {
VERBATIM
ip=IDP;
if (ifarg(1)) ip->invl0 = (unsigned char) *getarg(1);
_linvlset=(double)ip->invl0;
ENDVERBATIM
}
: vinset([val]) set or get the input flag (for using shared input from a vector)
FUNCTION vinset () {
VERBATIM
ip=IDP;
if (ifarg(1)) ip->vinflg = (unsigned char) *getarg(1);
if (ip->vinflg==1) {
ip->input=1;
ip->rvi = ip->rvb;
}
_lvinset=(double)ip->vinflg;
ENDVERBATIM
}
:* TABLES
PROCEDURE EXPo (x) {
TABLE RES FROM -20 TO 0 WITH 5000
RES = exp(x)
}
FUNCTION EXP (x) {
EXPo(x)
EXP = RES
}
FUNCTION esinr (x) {
ESINo(PI*x/tauGB)
if (x<tauGB) { esinr= (VGBa-offsetGB)*ESIN +offsetGB
} else if (x>2*tauGB) { esinr= 0
} else { esinr= rebound*VGBa*ESIN }
}
PROCEDURE ESINo (x) {
TABLE ESIN FROM 0 TO 2*PI WITH 3000 : one cycle
ESIN = sin(x)
}
PROCEDURE rates(vv) {
TABLE Bb DEPEND mg FROM -100 TO 50 WITH 300
: from Stevens & Jahr 1990a,b
Bb = 1 / (1 + exp(0.062 (/mV) * -vv) * (mg / 3.57 (mM)))
}
PROCEDURE coop (x) {
TABLE Gn DEPEND GPkd FROM 0 TO 10 WITH 100
: from Destexhe and Sejnowski, PNAS 92:9515 1995
Gn = (x^4)/(x^4+GPkd) : n=4; kd=100
}