1 /*
2  *  recording_device.cpp
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 // Includes from libnestutil:
24 #include "compose.hpp"
25 #include "kernel_manager.h"
26 
27 #include "recording_device.h"
28 
RecordingDevice()29 nest::RecordingDevice::RecordingDevice()
30   : DeviceNode()
31   , Device()
32   , P_()
33   , backend_params_( new Dictionary )
34 {
35 }
36 
RecordingDevice(const RecordingDevice & rd)37 nest::RecordingDevice::RecordingDevice( const RecordingDevice& rd )
38   : DeviceNode( rd )
39   , Device( rd )
40   , P_( rd.P_ )
41   , backend_params_( new Dictionary( *rd.backend_params_ ) )
42 {
43 }
44 
45 void
set_initialized_()46 nest::RecordingDevice::set_initialized_()
47 {
48   kernel().io_manager.enroll_recorder( P_.record_to_, *this, backend_params_ );
49 }
50 
51 void
calibrate(const std::vector<Name> & double_value_names,const std::vector<Name> & long_value_names)52 nest::RecordingDevice::calibrate( const std::vector< Name >& double_value_names,
53   const std::vector< Name >& long_value_names )
54 {
55   Device::calibrate();
56   kernel().io_manager.set_recording_value_names( P_.record_to_, *this, double_value_names, long_value_names );
57 }
58 
59 const std::string&
get_label() const60 nest::RecordingDevice::get_label() const
61 {
62   return P_.label_;
63 }
64 
Parameters_()65 nest::RecordingDevice::Parameters_::Parameters_()
66   : label_()
67   , record_to_( names::memory )
68 {
69 }
70 
71 void
get(DictionaryDatum & d) const72 nest::RecordingDevice::Parameters_::get( DictionaryDatum& d ) const
73 {
74   ( *d )[ names::label ] = label_;
75   ( *d )[ names::record_to ] = LiteralDatum( record_to_ );
76 }
77 
78 void
set(const DictionaryDatum & d)79 nest::RecordingDevice::Parameters_::set( const DictionaryDatum& d )
80 {
81   updateValue< std::string >( d, names::label, label_ );
82 
83   std::string record_to;
84   if ( updateValue< std::string >( d, names::record_to, record_to ) )
85   {
86     if ( not kernel().io_manager.is_valid_recording_backend( record_to ) )
87     {
88       std::string msg = String::compose( "Unknown recording backend '%1'", record_to );
89       throw BadProperty( msg );
90     }
91 
92     record_to_ = record_to;
93   }
94 }
95 
State_()96 nest::RecordingDevice::State_::State_()
97   : n_events_( 0 )
98 {
99 }
100 
101 void
get(DictionaryDatum & d) const102 nest::RecordingDevice::State_::get( DictionaryDatum& d ) const
103 {
104   size_t n_events = 0;
105   updateValue< long >( d, names::n_events, n_events );
106   ( *d )[ names::n_events ] = n_events + n_events_;
107 }
108 
109 void
set(const DictionaryDatum & d)110 nest::RecordingDevice::State_::set( const DictionaryDatum& d )
111 {
112   size_t n_events = 0;
113   if ( updateValue< long >( d, names::n_events, n_events ) )
114   {
115     if ( n_events != 0 )
116     {
117       throw BadProperty( "Property n_events can only be set to 0 (which clears all stored events)." );
118     }
119 
120     n_events_ = 0;
121   }
122 }
123 
124 void
set_status(const DictionaryDatum & d)125 nest::RecordingDevice::set_status( const DictionaryDatum& d )
126 {
127   if ( kernel().simulation_manager.has_been_prepared() )
128   {
129     throw BadProperty( "Recorder parameters cannot be changed while inside a Prepare/Run/Cleanup context." );
130   }
131 
132   Parameters_ ptmp = P_; // temporary copy in case of errors
133   ptmp.set( d );         // throws if BadProperty
134 
135   State_ stmp = S_; // temporary copy in case of errors
136   stmp.set( d );    // throws if BadProperty
137 
138   Device::set_status( d );
139 
140   if ( get_node_id() == 0 ) // this is a model prototype, not an actual instance
141   {
142     DictionaryDatum backend_params = DictionaryDatum( new Dictionary );
143 
144     // copy all properties not previously accessed from d to backend_params
145     for ( auto kv_pair = d->begin(); kv_pair != d->end(); ++kv_pair )
146     {
147       if ( not kv_pair->second.accessed() )
148       {
149         ( *backend_params )[ kv_pair->first ] = kv_pair->second;
150       }
151     }
152 
153     kernel().io_manager.check_recording_backend_device_status( ptmp.record_to_, backend_params );
154 
155     // cache all properties accessed by the backend in private member
156     backend_params_->clear();
157     for ( auto kv_pair = backend_params->begin(); kv_pair != backend_params->end(); ++kv_pair )
158     {
159       if ( kv_pair->second.accessed() )
160       {
161         ( *backend_params_ )[ kv_pair->first ] = kv_pair->second;
162         d->lookup( kv_pair->first ).set_access_flag();
163       }
164     }
165   }
166   else
167   {
168     kernel().io_manager.enroll_recorder( ptmp.record_to_, *this, d );
169   }
170 
171   // if we get here, temporaries contain consistent set of properties
172   P_ = ptmp;
173   S_ = stmp;
174 }
175 
176 void
get_status(DictionaryDatum & d) const177 nest::RecordingDevice::get_status( DictionaryDatum& d ) const
178 {
179   P_.get( d );
180   S_.get( d );
181 
182   Device::get_status( d );
183 
184   ( *d )[ names::element_type ] = LiteralDatum( names::recorder );
185 
186   if ( get_node_id() == 0 ) // this is a model prototype, not an actual instance
187   {
188     // first get the defaults from the backend
189     kernel().io_manager.get_recording_backend_device_defaults( P_.record_to_, d );
190 
191     // then overwrite with cached parameters
192     for ( auto kv_pair = backend_params_->begin(); kv_pair != backend_params_->end(); ++kv_pair )
193     {
194       ( *d )[ kv_pair->first ] = kv_pair->second;
195     }
196   }
197   else
198   {
199     kernel().io_manager.get_recording_backend_device_status( P_.record_to_, *this, d );
200   }
201 }
202 
203 bool
is_active(Time const & T) const204 nest::RecordingDevice::is_active( Time const& T ) const
205 {
206   const long stamp = T.get_steps();
207 
208   return get_t_min_() < stamp && stamp <= get_t_max_();
209 }
210 
211 void
write(const Event & event,const std::vector<double> & double_values,const std::vector<long> & long_values)212 nest::RecordingDevice::write( const Event& event,
213   const std::vector< double >& double_values,
214   const std::vector< long >& long_values )
215 {
216   kernel().io_manager.write( P_.record_to_, *this, event, double_values, long_values );
217   S_.n_events_++;
218 }
219