CARLsim  6.1.0
CARLsim: a GPU-accelerated SNN simulator
neuron_monitor_core.cpp
Go to the documentation of this file.
1 /* * Copyright (c) 2016 Regents of the University of California. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * 3. The names of its contributors may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *********************************************************************************************** *
31 * CARLsim
32 * created by: (MDR) Micah Richert, (JN) Jayram M. Nageswaran
33 * maintained by:
34 * (MA) Mike Avery <averym@uci.edu>
35 * (MB) Michael Beyeler <mbeyeler@uci.edu>,
36 * (KDC) Kristofor Carlson <kdcarlso@uci.edu>
37 * (TSC) Ting-Shuo Chou <tingshuc@uci.edu>
38 * (HK) Hirak J Kashyap <kashyaph@uci.edu>
39 *
40 * CARLsim v1.0: JM, MDR
41 * CARLsim v2.0/v2.1/v2.2: JM, MDR, MA, MB, KDC
42 * CARLsim3: MB, KDC, TSC
43 * CARLsim4: TSC, HK
44 * CARLsim5: HK, JX, KC
45 * CARLsim6: LN, JX, KC, KW
46 *
47 * CARLsim available from http://socsci.uci.edu/~jkrichma/CARLsim/
48 * Ver 05/24/2017
49 */
50 
51 #include <neuron_monitor_core.h>
52 
53 #include <snn.h> // CARLsim private implementation
54 #include <snn_definitions.h> // KERNEL_ERROR, KERNEL_INFO, ...
55 
56 #include <algorithm> // std::sort
57 
58 NeuronMonitorCore::NeuronMonitorCore(SNN* snn, int monitorId, int grpId) {
59  snn_ = snn;
60  grpId_= grpId;
61  monitorId_ = monitorId;
62  nNeurons_ = -1;
63  neuronFileId_ = NULL;
64  recordSet_ = false;
65  neuronMonLastUpdated_ = 0;
66 
67  persistentData_ = false;
68  userHasBeenWarned_ = false;
69  needToWriteFileHeader_ = true;
70  neuronFileSignature_ = 206661979;
71  neuronFileVersion_ = 0.1f;
72 
73  // defer all unsafe operations to init function
74  init();
75 }
76 
77 void NeuronMonitorCore::init() {
78  nNeurons_ = std::min(MAX_NEURON_MON_GRP_SZIE, snn_->getGroupNumNeurons(grpId_));
79  assert(nNeurons_>0);
80 
81  // so the first dimension is neuron ID
82  vectorV_.resize(nNeurons_+1); // reserve the record last for mean
83  vectorU_.resize(nNeurons_+1);
84  vectorI_.resize(nNeurons_+1);
85 
86  clear();
87 
88  // use KERNEL_{ERROR|WARNING|etc} typesetting (const FILE*)
89  fpInf_ = snn_->getLogFpInf();
90  fpErr_ = snn_->getLogFpErr();
91  fpDeb_ = snn_->getLogFpDeb();
92  fpLog_ = snn_->getLogFpLog();
93 }
94 
96  if (neuronFileId_!=NULL) {
97  fclose(neuronFileId_);
98  neuronFileId_ = NULL;
99  }
100 }
101 
103  assert(!isRecording());
104  recordSet_ = false;
105  userHasBeenWarned_ = false;
106  startTime_ = -1;
107  startTimeLast_ = -1;
108  stopTime_ = -1;
109  accumTime_ = 0;
110  totalTime_ = -1;
111 
112  for (int i=0; i<=nNeurons_; i++){ // including mean
113  vectorV_[i].clear();
114  vectorU_[i].clear();
115  vectorI_[i].clear();
116  }
117 }
118 
119 void NeuronMonitorCore::pushNeuronState(int neurId, float V, float U, float I) {
120  assert(isRecording());
121 
122  if (neurId >= MAX_NEURON_MON_GRP_SZIE)
123  return; // ignore values as the are empty anyway (see buffer transfer)
124 
125  vectorV_[neurId].push_back(V);
126  vectorU_[neurId].push_back(U);
127  vectorI_[neurId].push_back(I);
128 
129  // update mean
130  const int n = vectorV_[neurId].size();
131  if (vectorV_[nNeurons_].size() < n) {
132  // set first element
133  vectorV_[nNeurons_].push_back(V / nNeurons_);
134  vectorU_[nNeurons_].push_back(U / nNeurons_);
135  vectorI_[nNeurons_].push_back(I / nNeurons_);
136  }
137  else {
138  // mean record was appended by other neuron
139  vectorV_[nNeurons_][n-1] += V / nNeurons_;
140  vectorU_[nNeurons_][n-1] += U / nNeurons_;
141  vectorI_[nNeurons_][n-1] += I / nNeurons_;
142  }
143 }
144 
146  assert(!isRecording());
147 
148  if (!persistentData_) {
149  // if persistent mode is off (default behavior), automatically call clear() here
150  clear();
151  }
152 
153  // call updateNeuronMonitor to make sure neuron state file and neuron state vector are up-to-date
154  // Caution: must be called before recordSet_ is set to true!
155  snn_->updateNeuronMonitor(grpId_);
156 
157  recordSet_ = true;
158  long int currentTime = snn_->getSimTimeSec()*1000+snn_->getSimTimeMs();
159 
160  if (persistentData_) {
161  // persistent mode on: accumulate all times
162  // change start time only if this is the first time running it
163  startTime_ = (startTime_<0) ? currentTime : startTime_;
164  startTimeLast_ = currentTime;
165  accumTime_ = (totalTime_>0) ? totalTime_ : 0;
166  }
167  else {
168  // persistent mode off: we only care about the last probe
169  startTime_ = currentTime;
170  startTimeLast_ = currentTime;
171  accumTime_ = 0;
172  }
173 }
174 
176  assert(isRecording());
177  assert(startTime_>-1 && startTimeLast_>-1 && accumTime_>-1);
178 
179  // call updateNeuronMonitor to make sure neuron state file and neuron state vector are up-to-date
180  // Caution: must be called before recordSet_ is set to false!
181  snn_->updateNeuronMonitor(grpId_);
182 
183  recordSet_ = false;
184  userHasBeenWarned_ = false;
185  stopTime_ = snn_->getSimTimeSec()*1000+snn_->getSimTimeMs();
186 
187  // total time is the amount of time of the last probe plus all accumulated time from previous probes
188  totalTime_ = stopTime_-startTimeLast_ + accumTime_;
189  assert(totalTime_>=0);
190 }
191 
192 // returns the total accumulated time.
194  return accumTime_;
195 }
196 
197 void NeuronMonitorCore::setNeuronFileId(FILE* neuronFileId) {
198  assert(!isRecording());
199 
200  // close previous file pointer if exists
201  if (neuronFileId_!=NULL) {
202  fclose(neuronFileId_);
203  neuronFileId_ = NULL;
204  }
205 
206  // set it to new file id
207  neuronFileId_=neuronFileId;
208 
209  if (neuronFileId_==NULL)
210  needToWriteFileHeader_ = false;
211  else {
212  // file pointer has changed, so we need to write header (again)
213  needToWriteFileHeader_ = true;
215  }
216 }
217 
218 // write the header section of the neuron state file
220  if (!needToWriteFileHeader_)
221  return;
222 
223  // write file signature
224  if (!fwrite(&neuronFileSignature_,sizeof(int),1,neuronFileId_))
225  KERNEL_ERROR("NeuronMonitorCore: writeNeuronFileHeader has fwrite error");
226 
227  // write version number
228  if (!fwrite(&neuronFileVersion_,sizeof(float),1,neuronFileId_))
229  KERNEL_ERROR("NeuronMonitorCore: writeNeuronFileHeader has fwrite error");
230 
231  // write grid dimensions
232  Grid3D grid = snn_->getGroupGrid3D(grpId_);
233  int tmpInt = grid.numX;
234  if (!fwrite(&tmpInt,sizeof(int),1,neuronFileId_))
235  KERNEL_ERROR("NeuronMonitorCore: writeNeuronFileHeader has fwrite error");
236 
237  tmpInt = grid.numY;
238  if (!fwrite(&tmpInt,sizeof(int),1,neuronFileId_))
239  KERNEL_ERROR("NeuronMonitorCore: writeNeuronFileHeader has fwrite error");
240 
241  tmpInt = grid.numZ;
242  if (!fwrite(&tmpInt,sizeof(int),1,neuronFileId_))
243  KERNEL_ERROR("NeuronMonitorCore: writeNeuronFileHeader has fwrite error");
244 
245  // write MAX_NEURON_MON_GRP_SZIE
246  int max_neuron_mon_group_size = MAX_NEURON_MON_GRP_SZIE;
247  if (!fwrite(&max_neuron_mon_group_size,sizeof(int),1,neuronFileId_))
248  KERNEL_ERROR("NeuronMonitorCore: writeNeuronFileHeader has fwrite error");
249 
250  needToWriteFileHeader_ = false;
251 }
252 
254  long int bufferSize=0; // in bytes
255  for(int i=0; i<vectorV_.size();i++){
256  bufferSize+=vectorV_[i].size()*sizeof(int);
257  }
258  return 3 * bufferSize;
259 }
260 
261 // check if the state vector is getting large. If it is, return true once until
262 // stopRecording is called.
264  if(userHasBeenWarned_)
265  return false;
266  else {
267  //check if buffer is too big
269  userHasBeenWarned_=true;
270  return true;
271  }
272  else {
273  return false;
274  }
275  }
276 }
277 
278 std::vector<std::vector<float> > NeuronMonitorCore::getVectorV(){
279  assert(!isRecording());
280  return vectorV_;
281 }
282 
283 std::vector<std::vector<float> > NeuronMonitorCore::getVectorU(){
284  assert(!isRecording());
285  return vectorU_;
286 }
287 
288 std::vector<std::vector<float> > NeuronMonitorCore::getVectorI(){
289  assert(!isRecording());
290  return vectorI_;
291 }
292 
293 void NeuronMonitorCore::print(bool meanOnly) {
294  assert(!isRecording());
295 
296  // how many spike times to display per row
297  int dispVoltsPerRow = 7;
298 
299  // spike times only available in AER mode
300  KERNEL_INFO("| Neur ID | volt");
301  KERNEL_INFO("|- - - - -|- - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - -")
302 
303  for (int i=meanOnly?nNeurons_:0; i<=nNeurons_; i++) { // with mean
304  char buffer[100];
305  if (i < nNeurons_) {
306 #if defined(WIN32) || defined(WIN64)
307  _snprintf(buffer, 100, "| %7d | ", i);
308 #else
309  snprintf(buffer, 100, "| %7d | ", i);
310 #endif
311  }
312  else {
313 #if defined(WIN32) || defined(WIN64)
314  _snprintf(buffer, 100, "| %7s | ", "mean");
315 #else
316  snprintf(buffer, 100, "| %7s | ", "mean");
317 #endif
318  }
319  int nV = vectorV_[i].size();
320  for (int j=0; j<nV; j++) {
321  char volts[10];
322 #if defined(WIN32) || defined(WIN64)
323  _snprintf(volts, 10, "%4.4f ", vectorV_[i][j]);
324 #else
325  snprintf(volts, 10, "%4.4f ", vectorV_[i][j]);
326 #endif
327  strcat(buffer, volts);
328  if (j%dispVoltsPerRow == dispVoltsPerRow-1 && j<nV-1) {
329  KERNEL_INFO("%s",buffer);
330  strcpy(buffer,"| |");
331  }
332  }
333  KERNEL_INFO("%s",buffer);
334  }
335 
336 }
void pushNeuronState(int neurId, float V, float U, float I)
inserts a (time,neurId) tupel into the D Neuron State vector
#define MAX_NEURON_MON_BUFFER_SIZE
int getSimTimeSec()
Definition: snn.h:668
~NeuronMonitorCore()
destructor, cleans up all the memory upon object deletion
bool isRecording()
returns recording status
NeuronMonitorCore(SNN *snn, int monitorId, int grpId)
constructor (called by CARLsim::setNeuronMonitor)
void print(bool meanOnly)
prints neuron states in human-readable format
#define MAX_NEURON_MON_GRP_SZIE
#define KERNEL_ERROR(formatc,...)
long int getBufferSize()
returns the approximate size of the state vectors in bytes
void updateNeuronMonitor(int grpId=ALL)
copy required neuron state values from ??? buffer to ??? buffer
std::vector< std::vector< float > > getVectorV()
returns the Neuron state vector
Grid3D getGroupGrid3D(int grpId)
#define KERNEL_INFO(formatc,...)
A struct to arrange neurons on a 3D grid (a primitive cubic Bravais lattice with cubic side length 1)...
void stopRecording()
stops recording Neuron state
const FILE * getLogFpLog()
returns file pointer to log file
Definition: snn.h:602
std::vector< std::vector< float > > getVectorU()
std::vector< std::vector< float > > getVectorI()
void setNeuronFileId(FILE *neuronFileId)
sets pointer to Neuron file
void clear()
deletes data from the neuron state vector
const FILE * getLogFpErr()
returns file pointer to error log
Definition: snn.h:598
Contains all of CARLsim&#39;s core functionality.
Definition: snn.h:138
void startRecording()
starts recording Neuron state
bool isBufferBig()
returns true if state buffers are close to maxAllowedBufferSize
int getSimTimeMs()
Definition: snn.h:669
const FILE * getLogFpDeb()
returns file pointer to debug log
Definition: snn.h:600
int getGroupNumNeurons(int gGrpId)
Definition: snn.h:641
long int getAccumTime()
returns the total accumulated time
const FILE * getLogFpInf()
function writes population weights from gIDpre to gIDpost to file fname in binary.
Definition: snn.h:596