NEST  2.6.0,not_revisioned_source_dir@0
universal_data_logger_impl.h
Go to the documentation of this file.
1 /*
2  * universal_data_logger_impl.h
3  *
4  * This file is part of NEST.
5  *
6  * Copyright (C) 2004 The NEST Initiative
7  *
8  * NEST is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * NEST is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with NEST. If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "universal_data_logger.h"
24 #include "nest_time.h"
25 #include "network.h"
26 #include "node.h"
27 
28 
29 template <typename HostNode>
30 nest::UniversalDataLogger<HostNode>::UniversalDataLogger(HostNode& host)
31 : host_(host),
32  data_loggers_()
33 {}
34 
35 template <typename HostNode>
36 void nest::UniversalDataLogger<HostNode>::reset()
37 {
38  for ( DLiter_ it = data_loggers_.begin() ; it != data_loggers_.end() ; ++it )
39  it->reset();
40 }
41 
42 template <typename HostNode>
43 void nest::UniversalDataLogger<HostNode>::init()
44 {
45  for ( DLiter_ it = data_loggers_.begin() ; it != data_loggers_.end() ; ++it )
46  it->init();
47 }
48 
49 template <typename HostNode>
50 void nest::UniversalDataLogger<HostNode>::record_data(long_t step)
51 {
52  for ( DLiter_ it = data_loggers_.begin() ; it != data_loggers_.end() ; ++it )
53  it->record_data(host_, step);
54 }
55 
56 template <typename HostNode>
57 void nest::UniversalDataLogger<HostNode>::handle(const DataLoggingRequest& dlr)
58 {
59  const rport rport = dlr.get_rport();
60  assert(rport >= 1);
61  assert(static_cast<size_t>(rport) <= data_loggers_.size());
62  data_loggers_[rport-1].handle(host_, dlr);
63 }
64 
65 template <typename HostNode>
66 void nest::UniversalDataLogger<HostNode>::DataLogger_::reset()
67 {
68  data_.clear();
69  next_rec_step_ = -1; // flag as uninitialized
70 }
71 
72 template <typename HostNode>
73 void nest::UniversalDataLogger<HostNode>::DataLogger_::init()
74 {
75  if ( num_vars_ < 1 )
76  return; // not recording anything
77 
78  // Next recording step is in current slice or beyond, indicates that
79  // buffer is properly initialized.
80  if ( next_rec_step_ >= Node::network()->get_slice_origin().get_steps() )
81  return;
82 
83  // If we get here, the buffer has either never been initialized or has
84  // been dormant during a period when the host node was frozen. We then
85  // (re-)initialize.
86  data_.clear();
87 
88  // store recording time in steps
89  rec_int_steps_ = recording_interval_.get_steps();
90 
91  // set next recording step to first multiple of rec_int_steps_
92  // beyond current time, shifted one to left, since rec_step marks
93  // left of update intervals, and we want time stamps at right end of
94  // update interval to be multiples of recording interval
95  next_rec_step_ =
96  ( Node::network()->get_time().get_steps() / rec_int_steps_ + 1 ) * rec_int_steps_ - 1;
97 
98  // number of data points per slice
99  const long_t recs_per_slice =
100  static_cast<long_t>(std::ceil(Node::network()->get_min_delay()
101  / static_cast<double>(rec_int_steps_)));
102 
103  data_.resize(2,
104  DataLoggingReply::Container(recs_per_slice,
105  DataLoggingReply::Item(num_vars_)
106  )
107  );
108 
109  next_rec_.resize(2); // just for safety's sake
110  next_rec_[0] = next_rec_[1] = 0; // start at beginning of buffer
111 }
112 
113 template <typename HostNode>
114 void nest::UniversalDataLogger<HostNode>::DataLogger_::record_data(const HostNode& host, long_t step)
115 {
116  if ( num_vars_ < 1 || step < next_rec_step_ )
117  return;
118 
119  const size_t wt = Node::network()->write_toggle();
120 
121  assert(wt < next_rec_.size());
122  assert(wt < data_.size());
123 
124  /* The following assertion may fire if the multimeter connected to
125  this logger is frozen. In that case, handle() is not called and
126  next_rec_[wt] never reset. The assert() prevents error propagation.
127  This is not an exception, since I consider the chance of users
128  freezing multimeters very slim.
129  See #464 for details.
130  */
131  assert(next_rec_[wt] < data_[wt].size());
132 
133  DataLoggingReply::Item& dest = data_[wt][next_rec_[wt]];
134 
135  // set time stamp: step is left end of update interval, so add 1
136  dest.timestamp = Time::step(step + 1);
137 
138  // obtain data through access functions, calling via pointer-to-member
139  for ( size_t j = 0 ; j < num_vars_ ; ++j )
140  dest.data[j] = ((host).*(node_access_[j]))();
141 
142  next_rec_step_ += rec_int_steps_;
143 
144  /* We just increment. Construction ensures that we cannot overflow,
145  and read-out resets.
146  Overflow is possible if the multimeter is frozen, see #464.
147  In that case, the assertion above will trigger.
148  */
149  ++next_rec_[wt];
150 }
151 
152 template <typename HostNode>
153 void nest::UniversalDataLogger<HostNode>::DataLogger_::handle(HostNode& host,
154  const DataLoggingRequest& request)
155 {
156  if ( num_vars_ < 1 )
157  return; // nothing to do
158 
159  // The following assertions will fire if the user forgot to call init()
160  // on the data logger.
161  assert(next_rec_.size() == 2);
162  assert(data_.size() == 2);
163 
164  // get read toggle and start and end of slice
165  const size_t rt = Node::network()->read_toggle();
166  assert(not data_[rt].empty());
167 
168  // Check if we have valid data, i.e., data with time stamps within the
169  // past time slice. This may not be the case if the node has been frozen.
170  // In that case, we still reset the recording marker, to prepare for the next
171  // round.
172  if ( data_[rt][0].timestamp <= Node::network()->get_previous_slice_origin() )
173  {
174  next_rec_[rt] = 0;
175  return;
176  }
177 
178  // If recording interval and min_delay are not commensurable,
179  // the last entry of data_ will not contain useful data for every
180  // other slice. We mark this by time stamp -infinity.
181  // Applying this mark here is less work than initializing all time stamps
182  // to -infinity after each call to this function.
183  if ( next_rec_[rt] < data_[rt].size() )
184  data_[rt][next_rec_[rt]].timestamp = Time::neg_inf();
185 
186  // now create reply event and rigg it
187  DataLoggingReply reply(data_[rt]);
188 
189  // "clear" data
190  next_rec_[rt] = 0;
191 
192  reply.set_sender(host);
193  reply.set_sender_gid(host.get_gid());
194  reply.set_receiver(request.get_sender());
195  reply.set_port(request.get_port());
196 
197  // send it off
198  host.network()->send_to_node(reply);
199 }
Declarations for base class Node.
long_t rport
Connection port number to distinguish incoming connections, also called receiver port.
Definition: nest.h:147
assert(pNet!=0)
Declarations for class Network.
long long_t
Integer number with at least 32 bit.
Definition: nest.h:96