1 /* 2 * recording_backend.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 RECORDING_BACKEND_H 24 #define RECORDING_BACKEND_H 25 26 // C++ includes: 27 #include <vector> 28 29 // Includes from sli: 30 #include "dictdatum.h" 31 #include "name.h" 32 33 namespace nest 34 { 35 36 class RecordingDevice; 37 class Event; 38 39 /** 40 * Abstract base class for all NESTio recording backends 41 * 42 * This class provides the interface for the NESTio recording backends 43 * with which `RecordingDevice`s can be enrolled for recording and 44 * which they can use to write their data. 45 * 46 * Built-in recording backends are registered in the constructor of 47 * IOManager by inserting an instance of each of them into a std::map 48 * under the name of the backend. 49 * 50 * A user level call to Simulate internally executes the sequence 51 * Prepare → Run → Cleanup. During Prepare, the prepare() function of 52 * each backend is called by the IOManager. This gives the backend an 53 * opportunity to prepare data structures for the upcoming 54 * simulation cycle. 55 * 56 * The user level function Run drives the simulation main loop by 57 * uptating all nodes. At its beginning it calls pre_run_hook() on 58 * each recording backend via the IOManager. At the end of each run, 59 * it calls post_run_hook() respectively. 60 * 61 * During the simulation, recording devices call IOManager::write() in 62 * order to record data. These calls are forwarded to the backend, the 63 * device is enrolled with. Cleanup on the user level finally calls 64 * the cleanup() function of all backends. 65 * 66 * @ingroup NESTio 67 */ 68 69 class RecordingBackend 70 { 71 public: RecordingBackend()72 RecordingBackend() 73 { 74 } 75 ~RecordingBackend()76 virtual ~RecordingBackend() throw() 77 { 78 } 79 80 virtual void initialize() = 0; 81 virtual void finalize() = 0; 82 83 /** 84 * Enroll a `RecordingDevice` with the `RecordingBackend`. 85 * 86 * When this function is called by a `RecordingDevice` @p device, 87 * the `RecordingBackend` can set up per-device data structures and 88 * properties. Individual device instances can be identified using 89 * the `thread` and `node_id` of the @p device. 90 * 91 * This function is called from the set_initialized_() function of 92 * the @p device and their set_status() function. The companion 93 * function @p set_value_names() is called from Node::pre_run_hook() 94 * and makes the names of values to be recorded known. 95 * 96 * A backend needs to be able to cope with multiple calls to this 97 * function, as multiple calls to set_status() may occur on the @p 98 * device. For already enrolled devices this usually means that only 99 * the parameters in @p params have to be set, but no further 100 * actions are needed. 101 * 102 * Each recording backend must ensure that enrollment (including all 103 * settings made by the user) is persistent over multiple calls to 104 * Prepare, while the enrollment of all devices should end with a 105 * call to finalize(). 106 * 107 * A common implementation of this function will create an entry in 108 * a thread-local map, associating the device's node ID with the 109 * device-specific backend properties and an output facility of some 110 * kind. 111 * 112 * @param device the RecordingDevice to be enrolled 113 * @param params device-specific backend parameters 114 * 115 * @see set_value_names(), disenroll(), write(), 116 * 117 * @ingroup NESTio 118 */ 119 virtual void enroll( const RecordingDevice& device, const DictionaryDatum& params ) = 0; 120 121 /** 122 * Disenroll a `RecordingDevice` from the `RecordingBackend`. 123 * 124 * This function is considered to be the opposite of enroll() in the 125 * sense that it cancels the enrollment of a RecordingDevice from a 126 * RecordingBackend by deleting all device specific data. When 127 * setting a new recording backend for a recording device, this 128 * function is called for each backend the device is not enrolled 129 * with. 130 * 131 * @param device the RecordingDevice to be disenrolled 132 * 133 * @see enroll() 134 * 135 * @ingroup NESTio 136 */ 137 virtual void disenroll( const RecordingDevice& device ) = 0; 138 139 /** 140 * To make the names of recorded quantities known to the 141 * `RecordingBackend`, the vectors @p double_value_names and @p 142 * long_value_names can be set appropriately. If no values of a 143 * certain type (or none at all) will be recorded by @p device, the 144 * constants @ref NO_DOUBLE_VALUE_NAMES and @ref NO_LONG_VALUE_NAMES 145 * can be used. Please note that the lengths of the value names 146 * vectors *must* correspond to the length of the data vectors 147 * written during calls to `write()`, although this is not enforced 148 * by the API. 149 * 150 * @param device the device to set the value names for 151 * @param double_value_names the names for double values to be recorded 152 * @param long_value_names the names for long values to be recorded 153 * 154 * @see enroll(), disenroll(), write(), 155 * 156 * @ingroup NESTio 157 */ 158 virtual void set_value_names( const RecordingDevice& device, 159 const std::vector< Name >& double_value_names, 160 const std::vector< Name >& long_value_names ) = 0; 161 162 /** 163 * Prepare the backend at begin of the NEST Simulate function. 164 * 165 * This function is called by `KernelManager::prepare()` and allows the 166 * backend to open files or establish network connections or take similar 167 * action. 168 * 169 * @see cleanup() 170 * 171 * @ingroup NESTio 172 */ 173 virtual void prepare() = 0; 174 175 /** 176 * Clean up the backend at the end of a user level call to the NEST Simulate 177 * function. 178 * 179 * This function is called by `SimulationManager::cleanup()` and allows the 180 * backend to close open files or network connections or take similar action. 181 * 182 * @see prepare() 183 * 184 * @ingroup NESTio 185 */ 186 virtual void cleanup() = 0; 187 188 /** 189 * Initialize global backend-specific data structures. 190 * 191 * This function is called on each backend right at the very beginning of 192 * `SimulationManager::run()`. It can be used for initializations which have 193 * to be repeated at the beginning of every single call to run in a 194 * prepare-run-run-...-run-run-cleanup sequence. 195 * 196 * @see post_run_hook() 197 * 198 * @ingroup NESTio 199 */ 200 virtual void pre_run_hook() = 0; 201 202 /** 203 * Clean up the backend at the end of a Run. 204 * 205 * This is called right before `SimulationManager::run()` terminates. It 206 * allows the backend to flush open files, write remaining data to the 207 * screen, or perform similar operations that make sure that the user 208 * has access to all data from the previous simulation run. 209 * 210 * @see pre_run_hook() 211 * 212 * @ingroup NESTio 213 */ 214 virtual void post_run_hook() = 0; 215 216 /** 217 * Do work required at the end of each simulation step. 218 * 219 * This is called at the very end of each simulation step. It can for example 220 * be used to carry out writing to files in a synchronized way, all threads 221 * on all MPI processes performing it at the same time. 222 * 223 * @see pre_run_hook() 224 * 225 * @ingroup NESTio 226 */ 227 virtual void post_step_hook() = 0; 228 229 /** 230 * Write the data from the event to the backend specific channel together 231 * with the values given. 232 * 233 * This function needs to respect the time_in_steps property of the device 234 * and should return as quickly as possible if the `RecordingDevice` @p device 235 * is not enrolled with the backend. 236 * 237 * @param device the RecordingDevice, backend-specific channel to write to 238 * @param event the event 239 * @param double_values vector of double valued to be written 240 * @param long_values vector of long values to be written 241 * 242 * @ingroup NESTio 243 */ 244 virtual void write( const RecordingDevice& device, 245 const Event& event, 246 const std::vector< double >& double_values, 247 const std::vector< long >& long_values ) = 0; 248 249 /** 250 * Set the status of the recording backend using the key-value pairs 251 * contained in the params dictionary. 252 * 253 * @param params the status of the recording backend 254 * 255 * @see get_status() 256 * 257 * @ingroup NESTio 258 */ 259 virtual void set_status( const DictionaryDatum& params ) = 0; 260 261 /** 262 * Return the status of the recording backend by writing it to the given 263 * params dictionary. 264 * 265 * @param params the status of the recording backend 266 * 267 * @see set_status() 268 * 269 * @ingroup NESTio 270 */ 271 virtual void get_status( DictionaryDatum& params ) const = 0; 272 273 /** 274 * Check if the given per-device properties are valid and usable by 275 * the backend. 276 * 277 * This function is used to validate properties when SetDefaults is 278 * called on a recording device. If the properties are found to be 279 * valid, they will be cached in the recording device and set for 280 * individual instances by means of the call to enroll from the 281 * device's set_initialized_() function. In case the properties are 282 * invalid, this function is expected to throw BadProperty. 283 * 284 * @param params the parameter dictionary to validate 285 * 286 * @see get_device_defaults(), get_device_status() 287 * 288 * @ingroup NESTio 289 */ 290 virtual void check_device_status( const DictionaryDatum& params ) const = 0; 291 292 /** 293 * Return the per-device defaults by writing it to the given params 294 * dictionary. 295 * 296 * @param params the dictionary to add device-specific backend parameters to 297 * 298 * @see check_device_status(), get_device_status() 299 * 300 * @ingroup NESTio 301 */ 302 virtual void get_device_defaults( DictionaryDatum& params ) const = 0; 303 304 /** 305 * Return the per-device status of the given recording device by 306 * writing it to the given params dictionary. 307 * 308 * Please note that a corresponding setter function does not exist. 309 * Device-specific backend parameters are given in the call to 310 * enroll. 311 * 312 * @param device the recording device for which the status is returned 313 * @param params the dictionary to add device-specific backend parameters to 314 * 315 * @see enroll(), check_device_status(), get_device_defaults() 316 * 317 * @ingroup NESTio 318 */ 319 virtual void get_device_status( const RecordingDevice& device, DictionaryDatum& params ) const = 0; 320 321 static const std::vector< Name > NO_DOUBLE_VALUE_NAMES; 322 static const std::vector< Name > NO_LONG_VALUE_NAMES; 323 static const std::vector< double > NO_DOUBLE_VALUES; 324 static const std::vector< long > NO_LONG_VALUES; 325 }; 326 327 } // namespace 328 329 #endif // RECORDING_BACKEND_H 330