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