1 /*
2 * io_manager.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 #include "io_manager.h"
24
25 // Generated includes:
26 #include "config.h"
27
28 // C includes:
29 #include <dirent.h>
30 #include <errno.h>
31 #include <sys/types.h>
32
33 // C++ includes:
34 #include <cstdlib>
35
36 // Includes from libnestutil:
37 #include "compose.hpp"
38 #include "logging.h"
39
40 // Includes from nestkernel:
41 #include "kernel_manager.h"
42 #include "recording_backend_ascii.h"
43 #include "recording_backend_memory.h"
44 #include "recording_backend_screen.h"
45 #ifdef HAVE_MPI
46 #include "recording_backend_mpi.h"
47 #include "stimulation_backend_mpi.h"
48 #endif
49 #ifdef HAVE_SIONLIB
50 #include "recording_backend_sionlib.h"
51 #endif
52
53 // Includes from sli:
54 #include "dictutils.h"
55 #include <string>
56
57 namespace nest
58 {
59
IOManager()60 IOManager::IOManager()
61 : overwrite_files_( false )
62 {
63 register_recording_backends_();
64 register_stimulation_backends_();
65 }
66
~IOManager()67 IOManager::~IOManager()
68 {
69 for ( auto& it : recording_backends_ )
70 {
71 delete it.second;
72 }
73 for ( auto& it : stimulation_backends_ )
74 {
75 delete it.second;
76 }
77 }
78
79 void
set_data_path_prefix_(const DictionaryDatum & dict)80 IOManager::set_data_path_prefix_( const DictionaryDatum& dict )
81 {
82 std::string tmp;
83 if ( updateValue< std::string >( dict, names::data_path, tmp ) )
84 {
85 DIR* testdir = opendir( tmp.c_str() );
86 if ( testdir != NULL )
87 {
88 data_path_ = tmp; // absolute path & directory exists
89 closedir( testdir ); // we only opened it to check it exists
90 }
91 else
92 {
93 std::string msg;
94
95 switch ( errno )
96 {
97 case ENOTDIR:
98 msg = String::compose( "'%1' is not a directory.", tmp );
99 break;
100 case ENOENT:
101 msg = String::compose( "Directory '%1' does not exist.", tmp );
102 break;
103 default:
104 msg = String::compose( "Errno %1 received when trying to open '%2'", errno, tmp );
105 break;
106 }
107
108 LOG( M_ERROR, "SetStatus", "Variable data_path not set: " + msg );
109 }
110 }
111
112 if ( updateValue< std::string >( dict, names::data_prefix, tmp ) )
113 {
114 if ( tmp.find( '/' ) == std::string::npos )
115 {
116 data_prefix_ = tmp;
117 }
118 else
119 {
120 LOG( M_ERROR, "SetStatus", "Data prefix must not contain path elements." );
121 }
122 }
123 }
124
125 void
initialize()126 IOManager::initialize()
127 {
128 DictionaryDatum dict( new Dictionary );
129 // The properties data_path and data_prefix can be set via environment variables
130 char* data_path = std::getenv( "NEST_DATA_PATH" );
131 if ( data_path )
132 {
133 ( *dict )[ names::data_path ] = std::string( data_path );
134 }
135 char* data_prefix = std::getenv( "NEST_DATA_PREFIX" );
136 if ( data_prefix )
137 {
138 ( *dict )[ names::data_prefix ] = std::string( data_prefix );
139 }
140
141 set_data_path_prefix_( dict );
142
143 overwrite_files_ = false;
144
145 for ( const auto& it : recording_backends_ )
146 {
147 it.second->initialize();
148 }
149 for ( const auto& it : stimulation_backends_ )
150 {
151 it.second->initialize();
152 }
153 }
154
155 void
finalize()156 IOManager::finalize()
157 {
158 for ( const auto& it : recording_backends_ )
159 {
160 it.second->finalize();
161 }
162 for ( const auto& it : stimulation_backends_ )
163 {
164 it.second->finalize();
165 }
166 }
167
change_num_threads(thread)168 void IOManager::change_num_threads( thread )
169 {
170 for ( const auto& it : recording_backends_ )
171 {
172 it.second->finalize();
173 it.second->initialize();
174 }
175 for ( const auto& it : stimulation_backends_ )
176 {
177 it.second->finalize();
178 it.second->initialize();
179 }
180 }
181
182 void
set_status(const DictionaryDatum & d)183 IOManager::set_status( const DictionaryDatum& d )
184 {
185 set_data_path_prefix_( d );
186
187 updateValue< bool >( d, names::overwrite_files, overwrite_files_ );
188
189 DictionaryDatum recording_backends;
190 if ( updateValue< DictionaryDatum >( d, names::recording_backends, recording_backends ) )
191 {
192 for ( const auto& it : recording_backends_ )
193 {
194 DictionaryDatum recording_backend_status;
195 if ( updateValue< DictionaryDatum >( recording_backends, it.first, recording_backend_status ) )
196 {
197 it.second->set_status( recording_backend_status );
198 }
199 }
200 }
201 }
202
203 void
get_status(DictionaryDatum & d)204 IOManager::get_status( DictionaryDatum& d )
205 {
206 ( *d )[ names::data_path ] = data_path_;
207 ( *d )[ names::data_prefix ] = data_prefix_;
208 ( *d )[ names::overwrite_files ] = overwrite_files_;
209
210 DictionaryDatum recording_backends( new Dictionary );
211 for ( const auto& it : recording_backends_ )
212 {
213 DictionaryDatum recording_backend_status( new Dictionary );
214 it.second->get_status( recording_backend_status );
215 ( *recording_backends )[ it.first ] = recording_backend_status;
216 }
217 ( *d )[ names::recording_backends ] = recording_backends;
218 }
219
220 void
pre_run_hook()221 IOManager::pre_run_hook()
222 {
223 for ( auto& it : recording_backends_ )
224 {
225 it.second->pre_run_hook();
226 }
227 for ( auto& it : stimulation_backends_ )
228 {
229 it.second->pre_run_hook();
230 }
231 }
232
233 void
post_run_hook()234 IOManager::post_run_hook()
235 {
236 for ( auto& it : recording_backends_ )
237 {
238 it.second->post_run_hook();
239 }
240 for ( auto& it : stimulation_backends_ )
241 {
242 it.second->post_run_hook();
243 }
244 }
245
246 void
post_step_hook()247 IOManager::post_step_hook()
248 {
249 for ( auto& it : recording_backends_ )
250 {
251 it.second->post_step_hook();
252 }
253 }
254
255 void
prepare()256 IOManager::prepare()
257 {
258 for ( auto& it : recording_backends_ )
259 {
260 it.second->prepare();
261 }
262 for ( auto& it : stimulation_backends_ )
263 {
264 it.second->prepare();
265 }
266 }
267
268 void
cleanup()269 IOManager::cleanup()
270 {
271 for ( auto& it : recording_backends_ )
272 {
273 it.second->cleanup();
274 }
275 for ( auto& it : stimulation_backends_ )
276 {
277 it.second->cleanup();
278 }
279 }
280
281 bool
is_valid_recording_backend(const Name & backend_name) const282 IOManager::is_valid_recording_backend( const Name& backend_name ) const
283 {
284 std::map< Name, RecordingBackend* >::const_iterator backend;
285 backend = recording_backends_.find( backend_name );
286 return backend != recording_backends_.end();
287 }
288
289 bool
is_valid_stimulation_backend(const Name & backend_name) const290 IOManager::is_valid_stimulation_backend( const Name& backend_name ) const
291 {
292 auto backend = stimulation_backends_.find( backend_name );
293 return backend != stimulation_backends_.end();
294 }
295
296 void
write(const Name & backend_name,const RecordingDevice & device,const Event & event,const std::vector<double> & double_values,const std::vector<long> & long_values)297 IOManager::write( const Name& backend_name,
298 const RecordingDevice& device,
299 const Event& event,
300 const std::vector< double >& double_values,
301 const std::vector< long >& long_values )
302 {
303 recording_backends_[ backend_name ]->write( device, event, double_values, long_values );
304 }
305
306 void
enroll_recorder(const Name & backend_name,const RecordingDevice & device,const DictionaryDatum & params)307 IOManager::enroll_recorder( const Name& backend_name, const RecordingDevice& device, const DictionaryDatum& params )
308 {
309 for ( auto& it : recording_backends_ )
310 {
311 if ( it.first == backend_name )
312 {
313 it.second->enroll( device, params );
314 }
315 else
316 {
317 it.second->disenroll( device );
318 }
319 }
320 }
321
322 void
enroll_stimulator(const Name & backend_name,StimulationDevice & device,const DictionaryDatum & params)323 nest::IOManager::enroll_stimulator( const Name& backend_name, StimulationDevice& device, const DictionaryDatum& params )
324 {
325
326 if ( not is_valid_stimulation_backend( backend_name ) and not backend_name.toString().empty() )
327 {
328 return;
329 }
330 if ( backend_name.toString().empty() )
331 {
332 for ( auto& it : stimulation_backends_ )
333 {
334 it.second->disenroll( device );
335 }
336 }
337 else
338 {
339 for ( auto& it : stimulation_backends_ )
340 {
341 if ( it.first == backend_name )
342 {
343 ( it.second )->enroll( device, params );
344 }
345 else
346 {
347 it.second->disenroll( device );
348 }
349 }
350 }
351 }
352
353 void
set_recording_value_names(const Name & backend_name,const RecordingDevice & device,const std::vector<Name> & double_value_names,const std::vector<Name> & long_value_names)354 IOManager::set_recording_value_names( const Name& backend_name,
355 const RecordingDevice& device,
356 const std::vector< Name >& double_value_names,
357 const std::vector< Name >& long_value_names )
358 {
359 recording_backends_[ backend_name ]->set_value_names( device, double_value_names, long_value_names );
360 }
361
362 void
check_recording_backend_device_status(const Name & backend_name,const DictionaryDatum & params)363 IOManager::check_recording_backend_device_status( const Name& backend_name, const DictionaryDatum& params )
364 {
365 recording_backends_[ backend_name ]->check_device_status( params );
366 }
367
368 void
get_recording_backend_device_defaults(const Name & backend_name,DictionaryDatum & params)369 IOManager::get_recording_backend_device_defaults( const Name& backend_name, DictionaryDatum& params )
370 {
371 recording_backends_[ backend_name ]->get_device_defaults( params );
372 }
373
374 void
get_recording_backend_device_status(const Name & backend_name,const RecordingDevice & device,DictionaryDatum & d)375 IOManager::get_recording_backend_device_status( const Name& backend_name,
376 const RecordingDevice& device,
377 DictionaryDatum& d )
378 {
379 recording_backends_[ backend_name ]->get_device_status( device, d );
380 }
381
382 void
register_recording_backends_()383 IOManager::register_recording_backends_()
384 {
385 recording_backends_.insert( std::make_pair( "ascii", new RecordingBackendASCII() ) );
386 recording_backends_.insert( std::make_pair( "memory", new RecordingBackendMemory() ) );
387 recording_backends_.insert( std::make_pair( "screen", new RecordingBackendScreen() ) );
388 #ifdef HAVE_MPI
389 recording_backends_.insert( std::make_pair( "mpi", new RecordingBackendMPI() ) );
390 #endif
391 #ifdef HAVE_SIONLIB
392 recording_backends_.insert( std::make_pair( "sionlib", new RecordingBackendSIONlib() ) );
393 #endif
394 }
395
396 void
register_stimulation_backends_()397 IOManager::register_stimulation_backends_()
398 {
399 #ifdef HAVE_MPI
400 stimulation_backends_.insert( std::make_pair( "mpi", new StimulationBackendMPI() ) );
401 #endif
402 }
403
404 } // namespace nest
405