NEST main@caf0ae8
 
Loading...
Searching...
No Matches
universal_data_logger.h
Go to the documentation of this file.
1/*
2 * universal_data_logger.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#ifndef UNIVERSAL_DATA_LOGGER_H
24#define UNIVERSAL_DATA_LOGGER_H
25
26// C++ includes:
27#include <algorithm>
28#include <vector>
29
30// Includes from nestkernel:
31#include "event.h"
32#include "nest_time.h"
33#include "nest_types.h"
34#include "recordables_map.h"
35
36namespace nest
37{
111template < typename HostNode >
112class UniversalDataLogger
113{
114
115public:
119 UniversalDataLogger( HostNode& );
120
133 size_t connect_logging_device( const DataLoggingRequest&, const RecordablesMap< HostNode >& );
134
145 void handle( const DataLoggingRequest& );
146
157 void record_data( long );
158
160 void reset();
161
167 void init();
168
169private:
177 class DataLogger_
178 {
179 public:
180 DataLogger_( const DataLoggingRequest&, const RecordablesMap< HostNode >& );
181 size_t
182 get_mm_node_id() const
183 {
184 return multimeter_;
185 }
186 void handle( HostNode&, const DataLoggingRequest& );
187 void record_data( const HostNode&, long );
188 void reset();
189 void init();
190
191 private:
192 size_t multimeter_;
193 size_t num_vars_;
194
195 Time recording_interval_;
196 Time recording_offset_;
197 long rec_int_steps_;
198 long next_rec_step_;
199
201 std::vector< typename RecordablesMap< HostNode >::DataAccessFct > node_access_;
202
211 std::vector< DataLoggingReply::Container > data_;
212
214 std::vector< size_t > next_rec_;
215 };
216
217 HostNode& host_;
218
224 std::vector< DataLogger_ > data_loggers_;
225 typedef typename std::vector< DataLogger_ >::iterator DLiter_;
226
228 UniversalDataLogger( const UniversalDataLogger& );
229
231 UniversalDataLogger const& operator=( const UniversalDataLogger& );
232};
233
234// must be defined in this file, since it is required by check_connection(),
235// which typically is in h-files.
236template < typename HostNode >
237size_t
238UniversalDataLogger< HostNode >::connect_logging_device( const DataLoggingRequest& req,
239 const RecordablesMap< HostNode >& rmap )
240{
241 // rports are assigned consecutively, the caller may not request specific
242 // rports.
243 if ( req.get_rport() != 0 )
244 {
245 throw IllegalConnection( "Connections from multimeter to node must request rport 0." );
246 }
247
248 // ensure that we have not connected this multimeter before
249 const size_t mm_node_id = req.get_sender().get_node_id();
250
251 const auto item = std::find_if( data_loggers_.begin(),
252 data_loggers_.end(),
253 [ & ]( const DataLogger_& dl ) { return dl.get_mm_node_id() == mm_node_id; } );
254
255 if ( item != data_loggers_.end() )
256 {
257 throw IllegalConnection( "Each multimeter can only be connected once to a given node." );
258 }
259
260 // we now know that we have no DataLogger_ for the given multimeter, so we
261 // create one and push it
262 data_loggers_.push_back( DataLogger_( req, rmap ) );
263
264 // rport is index plus one, i.e., size
265 return data_loggers_.size();
266}
267
268template < typename HostNode >
269UniversalDataLogger< HostNode >::DataLogger_::DataLogger_( const DataLoggingRequest& req,
270 const RecordablesMap< HostNode >& rmap )
271 : multimeter_( req.get_sender().get_node_id() )
272 , num_vars_( 0 )
273 , recording_interval_( Time::neg_inf() )
274 , recording_offset_( Time::ms( 0. ) )
275 , rec_int_steps_( 0 )
276 , next_rec_step_( -1 ) // flag as uninitialized
277 , node_access_()
278 , data_()
279 , next_rec_( 2, 0 )
280{
281 const std::vector< std::string >& recvars = req.record_from();
282 for ( size_t j = 0; j < recvars.size(); ++j )
283 {
284 typename RecordablesMap< HostNode >::const_iterator rec = rmap.find( recvars[ j ] );
285
286 if ( rec == rmap.end() )
287 {
288 // delete all access information again: the connect either succeeds
289 // for all entries in recvars, or it fails, leaving the logger untouched
290 node_access_.clear();
291 throw IllegalConnection( "Cannot connect with unknown recordable " + recvars[ j ] );
292 }
293
294 node_access_.push_back( rec->second );
295 }
296
297 num_vars_ = node_access_.size();
298
299 if ( num_vars_ > 0 and req.get_recording_interval() < Time::step( 1 ) )
300 {
301 throw IllegalConnection( "Recording interval must be >= resolution." );
302 }
303
304 recording_interval_ = req.get_recording_interval();
305 recording_offset_ = req.get_recording_offset();
306}
307
308
371template < typename HostNode >
372class DynamicUniversalDataLogger
373{
374
375public:
379 DynamicUniversalDataLogger( HostNode& );
380
393 size_t connect_logging_device( const DataLoggingRequest&, const DynamicRecordablesMap< HostNode >& );
394
405 void handle( const DataLoggingRequest& );
406
417 void record_data( long );
418
420 void reset();
421
427 void init();
428
429private:
437 class DataLogger_
438 {
439 public:
440 DataLogger_( const DataLoggingRequest&, const DynamicRecordablesMap< HostNode >& );
441 size_t
442 get_mm_node_id() const
443 {
444 return multimeter_;
445 }
446 void handle( HostNode&, const DataLoggingRequest& );
447 void record_data( const HostNode&, long );
448 void reset();
449 void init();
450
451 private:
452 size_t multimeter_;
453 size_t num_vars_;
454
455 Time recording_interval_;
456 Time recording_offset_;
457 long rec_int_steps_;
458 long next_rec_step_;
459
461 std::vector< const typename DynamicRecordablesMap< HostNode >::DataAccessFct* > node_access_;
462
471 std::vector< DataLoggingReply::Container > data_;
472
474 std::vector< size_t > next_rec_;
475 };
476
477 HostNode& host_;
478
483 std::vector< DataLogger_ > data_loggers_;
484 typedef typename std::vector< DataLogger_ >::iterator DLiter_;
485
487 DynamicUniversalDataLogger( const DynamicUniversalDataLogger& );
488
490 DynamicUniversalDataLogger const& operator=( const DynamicUniversalDataLogger& );
491};
492
493
494// must be defined in this file, since it is required by check_connection(),
495// which typically is in h-files.
496template < typename HostNode >
497size_t
498DynamicUniversalDataLogger< HostNode >::connect_logging_device( const DataLoggingRequest& req,
499 const DynamicRecordablesMap< HostNode >& rmap )
500{
501 // rports are assigned consecutively, the caller may not request specific
502 // rports.
503 if ( req.get_rport() != 0 )
504 {
505 throw IllegalConnection( "Connections from multimeter to node must request rport 0." );
506 }
507
508 // ensure that we have not connected this multimeter before
509 const size_t mm_node_id = req.get_sender().get_node_id();
510 const size_t n_loggers = data_loggers_.size();
511 size_t j = 0;
512 while ( j < n_loggers and data_loggers_[ j ].get_mm_node_id() != mm_node_id )
513 {
514 ++j;
515 }
516 if ( j < n_loggers )
517 {
518 throw IllegalConnection( "Each multimeter can only be connected once to a given node." );
519 }
520
521 // we now know that we have no DataLogger_ for the given multimeter, so we
522 // create one and push it
523 data_loggers_.push_back( DataLogger_( req, rmap ) );
524
525 // rport is index plus one, i.e., size
526 return data_loggers_.size();
527}
528
529template < typename HostNode >
530DynamicUniversalDataLogger< HostNode >::DataLogger_::DataLogger_( const DataLoggingRequest& req,
531 const DynamicRecordablesMap< HostNode >& rmap )
532 : multimeter_( req.get_sender().get_node_id() )
533 , num_vars_( 0 )
534 , recording_interval_( Time::neg_inf() )
535 , recording_offset_( Time::ms( 0. ) )
536 , rec_int_steps_( 0 )
537 , next_rec_step_( -1 )
538 , // flag as uninitialized
539 node_access_()
540 , data_()
541 , next_rec_( 2, 0 )
542{
543 const std::vector< std::string >& recvars = req.record_from();
544 for ( size_t j = 0; j < recvars.size(); ++j )
545 {
546 typename DynamicRecordablesMap< HostNode >::const_iterator rec = rmap.find( recvars[ j ] );
547
548 if ( rec == rmap.end() )
549 {
550 // delete all access information again: the connect either succeeds
551 // for all entries in recvars, or it fails, leaving the logger untouched
552 node_access_.clear();
553 throw IllegalConnection( "Cannot connect with unknown recordable " + recvars[ j ] );
554 }
555
556 node_access_.push_back( &( rec->second ) );
557 }
558
559 num_vars_ = node_access_.size();
560
561 if ( num_vars_ > 0 and req.get_recording_interval() < Time::step( 1 ) )
562 {
563 throw IllegalConnection( "Recording interval must be >= resolution." );
564 }
565
566 recording_interval_ = req.get_recording_interval();
567 recording_offset_ = req.get_recording_offset();
568}
569
570} // namespace nest
571
572#endif /* #ifndef UNIVERSAL_DATA_LOGGER_H */
Namespace for the NEST simulation kernel.
Definition beta_normalization_factor.h:33