: $Id: snsarr.inc,v 1.63 1998/10/07 15:06:12 billl Exp $ COMMENT manage arrays used in sns.inc ENDCOMMENT NEURON { RANGE maxsyn, nsyn, qlen : scalars RANGE lpst, queu : SynS bzw. QueU structures RANGE begsyn, endsyn, newspk GLOBAL SPKSTORE, CHAINLEN RANGE qptr : QptR structure } PARAMETER { SPKSTORE = 50 : max number of spikes expected during max delay CHAINLEN = 1 : how many extra entries in a chain lpst = 0 : pointer to postsynaptic array } ASSIGNED { maxsyn : max and counter for this array nsyn queu : the postsyn queu qlen : its length (maxsyn*SPKSTORE) begsyn : index into queu that tells time to start endsyn : index into queu that tells time to end newspk : index into queu to place spk time + delay (tail) qptr : will point to the queu, its tail and its length } INCLUDE "snshead.inc" : QptR qptr; /* governs access to the postsyn queue */ : PreL prel; /* governs access to the presyn list */ : takes 1-3 arguments: location, post code, maxsyn CONSTRUCTOR { VERBATIM { qptr = (double)((unsigned long)ecalloc(1, (sizeof(QptR)))); /* qptr allows presynaptic cell to easily manipulate the post queu */ QPRCAST->qln = &qlen; QPRCAST->nspk = &newspk; QPRCAST->head = &begsyn; nsyn = maxsyn = qlen = lpst = queu = 0.; if (ifarg(2)) { QPRCAST->cpost = (int)*getarg(2); } else { QPRCAST->cpost = -1; } if (ifarg(3)) { init_arrays(*getarg(3)); } } ENDVERBATIM } DESTRUCTOR { VERBATIM { int ii; free(QUECAST); if (lpst != 0) { for (ii=0;ii<nsyn*CHAINLEN;ii+=CHAINLEN) { /* nullize pointers */ *(PSTCAST[ii].back) = (SynS *)NULL; /* remove old pre-post pointer */ } free(PSTCAST); free(QPRCAST); } nsyn = maxsyn = qlen = 0.; lpst = queu = qptr = 0.; } ENDVERBATIM } PROCEDURE init_arrays(num) { VERBATIM { int ii, msn; if (_lnum == maxsyn) { printf("Clearing array\n"); for (ii=0;ii<nsyn*CHAINLEN;ii+=CHAINLEN) { /* nullize pointers */ *(PSTCAST[ii].back) = (SynS *)NULL; /* remove old pre-post pointer */ } nsyn = 0; } else { maxsyn = (double)((int)_lnum); msn = maxsyn*CHAINLEN; qlen = SPKSTORE*msn; if (lpst == 0) { nsyn = 0.; lpst = (double)((unsigned long)ecalloc(msn,(sizeof(SynS)))); queu = (double)((unsigned long)ecalloc(((int)qlen), (sizeof(QueU)))); } else { if (nsyn > maxsyn) { printf("Shrinking array\n"); for (ii=maxsyn;ii<nsyn*CHAINLEN;ii+=CHAINLEN) { /* nullize pointers */ /* remove old pre-post pointer */ *(PSTCAST[ii].back) = (SynS *)NULL; } nsyn = maxsyn; } else { printf("Expanding array %09d\n",QPRCAST->cpost); } lpst = (double)((unsigned long)erealloc((PSTCAST),((int)(msn*sizeof(SynS))))); queu = (double)((unsigned long)erealloc((QUECAST),((int)(qlen*sizeof(QueU))))); for (ii=0;ii<(int)nsyn*CHAINLEN;ii+=CHAINLEN) { *(PSTCAST[ii].back) = &(PSTCAST[ii]); /* restore old pre pointers */ } } /* printf("Initializing arrays: Syn= %d bytes,Queue= %d bytes.\n", (int)msn*sizeof(SynS),(int)qlen, sizeof(QueU)); */ QPRCAST->qq = QUECAST; } } ENDVERBATIM } VERBATIM static void hshake(SynS*, PreL*, int, double*, double*); ENDVERBATIM : 3 arguments - presyn link, presyn nsyn, presyn maxsyn PROCEDURE setlink() { VERBATIM { int ii, x, new_; SynS *sns; double ptemp; PreL *ppsyn; x = nsyn; ptemp = *getarg(1); double* p_nsyn = getarg(2); double* p_maxsyn = getarg(3); if (x >= maxsyn) { init_arrays(maxsyn+POSTINC); /* #DEFINE POSTINC 5 */ } if (x > nsyn) { hoc_execerror("Can't leave empty pointers: see nsyn for current array index.", 0); } sns = &(PSTCAST[x*(int)CHAINLEN]); /* postsynaptic entry */ if ((ppsyn = (PreL *)((unsigned long)ptemp)) == (PreL *)NULL) { /* presyn loc */ hoc_execerror("Presyn not initialized.", 0); } if (ppsyn->link2 != ptemp) { hoc_execerror("Invalid (changed) link.", 0); } if (x == nsyn) { nsyn++; /* a new_ entry */ new_ = 1; } else { /* should generate error if try to change something in middle of chain */ if (sns->chainlen == -2) { hoc_execerror("Internal error: Index used must be multiple of CHAINLEN.", 0); } new_ = 0; } hshake(sns, ppsyn, new_, p_nsyn, p_maxsyn); x *= (int)CHAINLEN; for (ii=x;ii < x + CHAINLEN;ii++) { sns = &(PSTCAST[ii]); /* access the entry */ /* initialize postsyn stuff to reasonable values */ /* delay, gmax and all codes should be initialized separately */ sns->del = DELAY; sns->ucode = -1; sns->chainlen = (ii==x)?CHAINLEN:-2; sns->pgm = 1.0; /* initialize the presynaptic stuff */ /* Rcurr and last will be initialized with init */ sns->index = x; sns->qpt = QPRCAST; } } ENDVERBATIM } : manipulate the presynaptic list remotely VERBATIM /* ls will be a pointer to presyn cell's array of pointers */ /* flag == 1 if this is a brand new entry */ static void hshake(SynS* ss, PreL* pl, int flag, double* nn, double* mx) { int ii; /* erase presyn pointer if this has been set before */ if (flag == 0) { /* an old entry */ /* fall out of loop if a pointer exists already */ for (ii=0;ii<(*nn) && (pl->plst[ii])!=ss;ii++); /* no body */ if (ii < (*nn)) { /* fell out of loop */ printf("Maintaining pointers.\n"); } else { flag = 1; /* now we do have to create a new pointer */ printf("Erasing pointer (C%09d,Pr%09d,Po%09d).\n", ss->ucode,*(ss->pcpre),QPRCAST->cpost); *(ss->back) = (SynS *)NULL; /* remove old pre-post pointer */ } } if (flag == 1) { /* create a new pointer */ /* if necessary, allocate space for the pointer system */ if ((*nn) == 0.) { (*mx) = PREINC; /* #DEFINE PREINC 50 */ pl->plst = (SynS **)ecalloc(((int)(*mx)), sizeof(SynS *)); } else if ((*nn) == (*mx)) { /* need to create more space */ (*mx) += PREINC; pl->plst = (SynS **)realloc(pl->plst,((int)(*mx)) * sizeof(SynS *)); /* reassign all back pointers */ for (ii=0;ii<(*nn);ii++) { (pl->plst[ii])->back = &(pl->plst[ii]); } } /* the handshake */ pl->plst[(int)(*nn)] = ss; /* pre -> post */ ss->back = &(pl->plst[(int)(*nn)]); /* post -> pre */ ss->pcpre = &(pl->cpre); /* post -> precode */ (*nn)++; } } ENDVERBATIM : 1 or 2 args, get bzw. set user code FUNCTION code() { VERBATIM { int ii; if (ifarg(1)) { ii = (int)*getarg(1); if (ii < 0) { ii = nsyn+ii; } if (ii >= nsyn || ii < 0) {hoc_execerror("array index out of bounds", 0);} if (ifarg(2)) { /* look for a second arg to do a set */ (PSTCAST[ii*(int)CHAINLEN]).ucode = (int)*getarg(2); } _lcode = (PSTCAST[ii*(int)CHAINLEN]).ucode; } else { for (ii=0;ii<nsyn*CHAINLEN;ii+=CHAINLEN) { printf("%d,%09d ",ii,(PSTCAST[ii]).ucode); } _lcode = 1.0; }} ENDVERBATIM } : 2 args => set postsyn code FUNCTION post() { VERBATIM { if (ifarg(2)) { QPRCAST->cpost = (int)*getarg(2); } _lpost = QPRCAST->cpost; } ENDVERBATIM } : 1 or 2 args, get bzw. set delay FUNCTION delay() { VERBATIM { int ii,jj; if (ifarg(1)) { ii = (int)*getarg(1); if (ii < 0) { ii = nsyn+ii; } if (ii >= nsyn || ii < 0) {hoc_execerror("array index out of bounds", 0);} if (ifarg(2)) { /* look for a second arg to do a set */ for (jj=ii*CHAINLEN;jj<(ii+1)*CHAINLEN;jj++) { (PSTCAST[jj]).del = *getarg(2) + DELAY; }} _ldelay = (PSTCAST[ii*(int)CHAINLEN]).del; } else { for (ii=0;ii<nsyn*CHAINLEN;ii+=CHAINLEN) { printf("%d,%g ",ii,(PSTCAST[ii]).del); } _ldelay = 1.0; }} ENDVERBATIM } : 1 or 2 args, get bzw. set individual percent gmax : user expects to see a gmax in uS, but what is stored is a : fraction of the total gmax (a global variable) : therefore can turn off all GABAA with gmax_GABAA = 0 FUNCTION gmax() { VERBATIM { int ii,jj; if (ifarg(1)) { ii = (int)*getarg(1); if (ii < 0) { ii = nsyn+ii; } if (ii >= nsyn || ii < 0) {hoc_execerror("array index out of bounds", 0);} if (ifarg(2)) { /* look for a second arg to do a set */ for (jj=ii*CHAINLEN;jj<(ii+1)*CHAINLEN;jj++) { (PSTCAST[jj]).pgm = *getarg(2); }} _lgmax = (PSTCAST[ii*(int)CHAINLEN]).pgm; } else { printf("Multiply by %g to get effective gmax.\n",GMAX); for (ii=0;ii<nsyn*CHAINLEN;ii+=CHAINLEN) { printf("%d,%g ",ii,(PSTCAST[ii]).pgm); } _lgmax = 1.0; }} ENDVERBATIM } : called with 0,1 or 2 args : 0 => print out info about all the presyns : 1 (index) => use as index to return this pre code : -1 => print out pointer structure : 2 (index,code )=> set precode for this index FUNCTION pre() { VERBATIM { int x,ii; x = -2; /* flag -> -1 then print out pointers */ if (ifarg(1)) { x = (int)*getarg(1); } if (x >= 0) { if (x >= nsyn) { hoc_execerror("array index out of bounds", 0);} x *= CHAINLEN; _lpre = *((PSTCAST[x]).pcpre); } else { for (ii=0;ii<nsyn*CHAINLEN;ii+=CHAINLEN) { printf("%1d Del:%-2g Gmax: %-4g Cd:%09d Pre:%09d Post:%09d\n", (PSTCAST[ii]).index, (PSTCAST[ii]).del, (PSTCAST[ii]).pgm, (PSTCAST[ii]).ucode, *((PSTCAST[ii]).pcpre), QPRCAST->cpost); if (x == -1 || &(PSTCAST[ii]) != *((PSTCAST[ii]).back)) { printf("\t\t%s: %p -> %p\n", ((&(PSTCAST[ii])==*((PSTCAST[ii]).back))?"OK":"POINTER MISMATCH"), &(PSTCAST[ii]), (PSTCAST[ii]).back); } } _lpre = 1.0; } } ENDVERBATIM } : return link for matching with presyn FUNCTION link(ii) { VERBATIM { if (_lii >= nsyn) { hoc_execerror("array index out of bounds", 0);} _llink = (double)(unsigned long)(PSTCAST[(int)_lii]).pcpre; } ENDVERBATIM } FUNCTION check() { VERBATIM { int ii; for (ii=0; ii<nsyn*CHAINLEN && _lcheck==1.; ii+=CHAINLEN) { if (&(PSTCAST[ii]) != *((PSTCAST[ii]).back)) { printf("****************************************************************\n"); printf("ERROR:: Index:%3d,C%09d,Pr%09d,Po%09d, Delay:%6g (%p->%p->%p)\n", (PSTCAST[ii]).index, (PSTCAST[ii]).ucode, *((PSTCAST[ii]).pcpre), QPRCAST->cpost, (PSTCAST[ii]).del, &(PSTCAST[ii]), (PSTCAST[ii]).back, *((PSTCAST[ii]).back)); printf("****************************************************************\n"); _lcheck = -1.; } } _lcheck = nsyn; /* all pointers have to be active */ } ENDVERBATIM } PROCEDURE initq() { VERBATIM { int ii; QPRCAST->dead = Cdur + Deadtime; begsyn = endsyn = newspk = 0.; for (ii=0;ii<qlen;ii++) { QUECAST[ii].time = 1.e20; QUECAST[ii].index = -1; } QPRCAST->qterm = -1.e2; for (ii=0;ii<nsyn*CHAINLEN;ii++) { PSTCAST[ii].Rcurr = 0.; PSTCAST[ii].last = -1.e2; PSTCAST[ii].spkt = -1.e2; if (PSTCAST[ii].chainlen > 1) { PSTCAST[ii].chainptr = -1; } } } ENDVERBATIM } : begsyn is the top of the line when the spike is first utilized to generate synapse : updates the value in the queue so endsyn can detect the end of the syn pulse : doesn't return value (since in a struct) PROCEDURE popqh1(aug) { VERBATIM { if (QUECAST[(int)begsyn].time == 1e20) { printf("%p %g %g ",QUECAST,newspk,qlen); hoc_execerror("Error: queue exhausted.\n",0); } else { /* augment the time by Cdur */ QUECAST[(int)begsyn].time += _laug; begsyn++; if (begsyn == qlen) { begsyn = 0.; } } } ENDVERBATIM } : endsyn is queried for the termination time of the synaptic square wave PROCEDURE popqh2() { VERBATIM { QUECAST[(int)endsyn].time = 1.e20; /* clear the entry */ endsyn++; if (endsyn == qlen) { endsyn = 0.; } } ENDVERBATIM } : DEBUGGING ROUTINES FUNCTION getdbx(c,x) { VERBATIM { switch ((int)_lc) { case 1: _lgetdbx = (PSTCAST[(int)_lx]).last; break; case 2: _lgetdbx = (PSTCAST[(int)_lx]).Rcurr; break; case 3: _lgetdbx = (PSTCAST[(int)_lx]).spkt; break; case 4: _lgetdbx = (QUECAST[(int)_lx]).time; break; case 5: _lgetdbx = (QUECAST[(int)_lx]).index; break; case 6: _lgetdbx = QPRCAST->qterm; break; case 7: _lgetdbx = QPRCAST->dead; break; case 8: _lgetdbx = (PSTCAST[(int)_lx]).chainlen; break; case 9: _lgetdbx = (PSTCAST[(int)_lx]).chainptr; break; default: hoc_execerror("UNAVAILABLE IN DBX",0); _lgetdbx = -1; break; }} ENDVERBATIM } PROCEDURE prq() { VERBATIM { int ii; printf("new:%g beg:%g end:%g /%g\n",newspk,begsyn,endsyn,qlen); for (ii=endsyn;ii!=newspk;ii=((ii==qlen-1)?0:ii+1)) { printf("%d %8g%8d\n",ii,(QUECAST[ii]).time,(QUECAST[ii]).index); } } ENDVERBATIM }