Ticket #160: vecstim.mod

File vecstim.mod, 4.9 KB (added by mschmucker, 2 years ago)
Line 
1COMMENT
2This mechanism emits spike events at the times given in a supplied Vector.
3
4Example usage:
5    objref vs
6    vs = new VecStim(.5)
7    vs.play(spikevec)   
8
9This is a modified version of the original vecstim.mod (author unknown?) which
10allows multiple vectors to be used sequentially. This saves memory in a long
11simulation, as the same storage can be reused.
12
13The mechanism checks at intervals `ping` whether a new vector has been provided
14using the play() procedure and if so resets its pointer to the first element
15in the new vector. Note that any spikes remaining in the first vector will be
16lost. Any spiketimes in the new vector that are earlier than the current time
17are ignored.
18
19The mechanism actually checks slightly after the ping interval, to avoid play()
20and the ping check occurring at the same time step but in the wrong order.
21
22
23Extracts from the comments on the original vecstim:
24
25The idiom for getting a  Vector argument in a model description is encapsulated
26in the "play" procedure. There are potentially many VecStim instances and so the
27Vector pointer must be stored in the space allocated for the particular instance
28when "play" is called. The assigned variable "space" gives us space for a double
29precision number, 64 bits, which is sufficient to store an opaque pointer.
30The "element" procedure uses this opaque pointer to make sure that the requested
31"index" element is within the size of the vector and assigns the "etime" double
32precision variable to the value of that element. Since index is defined at the
33model description level it is a double precision variable as well and must be
34treated as such in the VERBATIM block. An index value of -1 means that no
35further events should be sent from this instance. Fortunately, space for model
36data is cleared when it is first allocated. So if play is not called, the
37pointer will be 0 and the test in the element procedure would turn off the
38VecStim by setting index to -1. Also, because the existence of the first
39argument is checked in the "play" procedure, one can turn off the VecStim with
40    vs.play()
41No checking is done if the stimvec is destroyed (when the reference count for
42the underlying Vector becomes 0). Continued use of the VecStim instance in this
43case would cause a memory error. So it is up to the user to call vs.play() or to
44destroy the VecStim instance before running another simulation.
45
46The strategy of the INITIAL and NET_RECEIVE blocks is to send a self event
47(with flag 1) to be delivered at the time specified by the index of the Vector
48starting at index 0. When the self event is delivered to the NET_RECEIVE block,
49it causes an immediate input event on every NetCon which has this VecStim as its
50source. These events, would then be delivered to their targets after the
51appropriate delay specified for each NetCon.
52ENDCOMMENT
53
54
55: Vector stream of events
56
57NEURON {
58    ARTIFICIAL_CELL VecStim
59    RANGE ping
60}
61
62PARAMETER {
63    ping = 1 (ms)
64}
65
66ASSIGNED {
67    index
68    etime (ms)
69    space
70}
71
72INITIAL {
73    index = 0
74    element()
75    if (index > 0) {
76        net_send(etime - t, 1)
77    }
78    if (ping > 0) {
79        net_send(ping, 2)
80    }
81}
82
83NET_RECEIVE (w) {
84    if (flag == 1) {
85        net_event(t)
86        element()
87        if (index > 0) {
88            if (etime < t) {
89                printf("Warning in VecStim: spike time (%g ms) before current time (%g ms)\n",etime,t)
90            } else {
91                net_send(etime - t, 1)
92            }
93        }
94    } else if (flag == 2) { : ping - reset index to 0
95        :printf("flag=2, etime=%g, t=%g, ping=%g, index=%g\n",etime,t,ping,index)
96        if (index == -2) { : play() has been called
97            :printf("Detected new vector\n")
98            index = 0
99            : the following loop ensures that if the vector
100            : contains spiketimes earlier than the current
101            : time, they are ignored.
102            while (etime < t && index >= 0) {
103                element()
104                :printf("element(): index=%g, etime=%g, t=%g\n",index,etime,t)
105            }
106            if (index > 0) {
107                net_send(etime - t, 1)
108            }
109        }
110        net_send(ping, 2)
111    }
112}
113
114
115VERBATIM
116extern double* vector_vec();
117extern int vector_capacity();
118extern void* vector_arg();
119ENDVERBATIM     
120
121PROCEDURE element() {
122VERBATIM
123    { void* vv; int i, size; double* px;
124        i = (int)index;
125        if (i >= 0) {
126            vv = *((void**)(&space));
127            if (vv) {
128                size = vector_capacity(vv);
129                px = vector_vec(vv);
130                if (i < size) {
131                    etime = px[i];
132                    index += 1.;
133                } else {
134                    index = -1.;
135                }
136            } else {
137                index = -1.;
138            }
139        }
140    }
141ENDVERBATIM
142}
143
144PROCEDURE play() {
145VERBATIM
146    void** vv;
147    vv = (void**)(&space);
148    *vv = (void*)0;
149    if (ifarg(1)) {
150        *vv = vector_arg(1);
151    }
152    index = -2;
153ENDVERBATIM
154}