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