1 /*
2 * model_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 "model_manager.h"
24
25 // C++ includes:
26 #include <algorithm>
27 #include <iostream>
28 #include <vector>
29
30 // Includes from libnestutil:
31 #include "compose.hpp"
32
33 // Includes from nestkernel:
34 #include "connector_model_impl.h"
35 #include "genericmodel_impl.h"
36 #include "kernel_manager.h"
37 #include "model_manager_impl.h"
38 #include "proxynode.h"
39 #include "vp_manager_impl.h"
40
41
42 namespace nest
43 {
44
ModelManager()45 ModelManager::ModelManager()
46 : pristine_models_()
47 , models_()
48 , pristine_prototypes_()
49 , prototypes_()
50 , modeldict_( new Dictionary )
51 , synapsedict_( new Dictionary )
52 , proxynode_model_( 0 )
53 , proxy_nodes_()
54 , dummy_spike_sources_()
55 , model_defaults_modified_( false )
56 {
57 }
58
~ModelManager()59 ModelManager::~ModelManager()
60 {
61 clear_models_();
62
63 clear_prototypes_();
64
65 // Now we can delete the clean model prototypes
66 std::vector< ConnectorModel* >::iterator i;
67 for ( i = pristine_prototypes_.begin(); i != pristine_prototypes_.end(); ++i )
68 {
69 if ( *i != 0 )
70 {
71 delete *i;
72 }
73 }
74
75 std::vector< std::pair< Model*, bool > >::iterator j;
76 for ( j = pristine_models_.begin(); j != pristine_models_.end(); ++j )
77 {
78 if ( ( *j ).first != 0 )
79 {
80 delete ( *j ).first;
81 }
82 }
83 }
84
85 void
initialize()86 ModelManager::initialize()
87 {
88 if ( proxynode_model_ == 0 )
89 {
90 proxynode_model_ = new GenericModel< proxynode >( "proxynode", "" );
91 proxynode_model_->set_type_id( 1 );
92 pristine_models_.push_back( std::pair< Model*, bool >( proxynode_model_, true ) );
93 }
94
95 // Re-create the model list from the clean prototypes
96 for ( index i = 0; i < pristine_models_.size(); ++i )
97 {
98 assert( pristine_models_[ i ].first != 0 );
99
100 // set the number of threads for the number of sli pools
101 pristine_models_[ i ].first->set_threads();
102 std::string name = pristine_models_[ i ].first->get_name();
103 models_.push_back( pristine_models_[ i ].first->clone( name ) );
104 if ( not pristine_models_[ i ].second )
105 {
106 modeldict_->insert( name, i );
107 }
108 }
109
110 // create proxy nodes, one for each thread and model and one dummy
111 // spike source for each thread.
112
113 proxy_nodes_.resize( kernel().vp_manager.get_num_threads() );
114 dummy_spike_sources_.resize( kernel().vp_manager.get_num_threads() );
115
116 #pragma omp parallel
117 {
118 const thread t = kernel().vp_manager.get_thread_id();
119 proxy_nodes_[ t ].clear();
120
121 for ( index i = 0; i < pristine_models_.size(); ++i )
122 {
123 const int model_id = pristine_models_[ i ].first->get_model_id();
124 proxy_nodes_[ t ].push_back( create_proxynode_( t, model_id ) );
125 }
126
127 const int model_id = get_model_id( "proxynode" );
128 dummy_spike_sources_[ t ] = create_proxynode_( t, model_id );
129 }
130
131 synapsedict_->clear();
132
133 // one list of prototypes per thread
134 std::vector< std::vector< ConnectorModel* > > tmp_proto( kernel().vp_manager.get_num_threads() );
135 prototypes_.swap( tmp_proto );
136
137 // (re-)append all synapse prototypes
138 for ( std::vector< ConnectorModel* >::iterator i = pristine_prototypes_.begin(); i != pristine_prototypes_.end();
139 ++i )
140 {
141 if ( *i != 0 )
142 {
143 std::string name = ( *i )->get_name();
144 for ( thread t = 0; t < static_cast< thread >( kernel().vp_manager.get_num_threads() ); ++t )
145 {
146 prototypes_[ t ].push_back( ( *i )->clone( name ) );
147 }
148 synapsedict_->insert( name, prototypes_[ 0 ].size() - 1 );
149 }
150 }
151 }
152
153 void
finalize()154 ModelManager::finalize()
155 {
156 clear_models_();
157 clear_prototypes_();
158 delete_secondary_events_prototypes();
159
160 // We free all Node memory
161 std::vector< std::pair< Model*, bool > >::iterator m;
162 for ( m = pristine_models_.begin(); m != pristine_models_.end(); ++m )
163 {
164 // delete all nodes, because cloning the model may have created instances.
165 ( *m ).first->clear();
166 }
167 }
168
169 void
set_status(const DictionaryDatum &)170 ModelManager::set_status( const DictionaryDatum& )
171 {
172 }
173
174 void
get_status(DictionaryDatum & dict)175 ModelManager::get_status( DictionaryDatum& dict )
176 {
177 // syn_ids start at 0, so the maximal number of syn models is MAX_SYN_ID + 1
178 def< int >( dict, names::max_num_syn_models, MAX_SYN_ID + 1 );
179 }
180
181 index
copy_model(Name old_name,Name new_name,DictionaryDatum params)182 ModelManager::copy_model( Name old_name, Name new_name, DictionaryDatum params )
183 {
184 if ( modeldict_->known( new_name ) or synapsedict_->known( new_name ) )
185 {
186 throw NewModelNameExists( new_name );
187 }
188
189 const Token oldnodemodel = modeldict_->lookup( old_name );
190 const Token oldsynmodel = synapsedict_->lookup( old_name );
191
192 index new_id;
193 if ( not oldnodemodel.empty() )
194 {
195 index old_id = static_cast< index >( oldnodemodel );
196 new_id = copy_node_model_( old_id, new_name );
197 set_node_defaults_( new_id, params );
198 }
199 else if ( not oldsynmodel.empty() )
200 {
201 index old_id = static_cast< index >( oldsynmodel );
202 new_id = copy_synapse_model_( old_id, new_name );
203 set_synapse_defaults_( new_id, params );
204 }
205 else
206 {
207 throw UnknownModelName( old_name );
208 }
209
210 return new_id;
211 }
212
213 index
register_node_model_(Model * model,bool private_model)214 ModelManager::register_node_model_( Model* model, bool private_model )
215 {
216 const index id = models_.size();
217 model->set_model_id( id );
218 model->set_type_id( id );
219
220 std::string name = model->get_name();
221
222 pristine_models_.push_back( std::pair< Model*, bool >( model, private_model ) );
223 models_.push_back( model->clone( name ) );
224
225 #pragma omp parallel
226 {
227 const thread t = kernel().vp_manager.get_thread_id();
228 const int model_id = model->get_model_id();
229 proxy_nodes_[ t ].push_back( create_proxynode_( t, model_id ) );
230 }
231
232 if ( not private_model )
233 {
234 modeldict_->insert( name, id );
235 }
236
237 return id;
238 }
239
240 index
copy_node_model_(index old_id,Name new_name)241 ModelManager::copy_node_model_( index old_id, Name new_name )
242 {
243 Model* old_model = get_model( old_id );
244 old_model->deprecation_warning( "CopyModel" );
245
246 Model* new_model = old_model->clone( new_name.toString() );
247 models_.push_back( new_model );
248
249 index new_id = models_.size() - 1;
250 modeldict_->insert( new_name, new_id );
251
252 #pragma omp parallel
253 {
254 const thread t = kernel().vp_manager.get_thread_id();
255 const int model_id = new_model->get_model_id();
256 proxy_nodes_[ t ].push_back( create_proxynode_( t, model_id ) );
257 }
258
259 return new_id;
260 }
261
262 index
copy_synapse_model_(index old_id,Name new_name)263 ModelManager::copy_synapse_model_( index old_id, Name new_name )
264 {
265 size_t new_id = prototypes_[ 0 ].size();
266
267 if ( new_id == invalid_synindex ) // we wrapped around (=63), maximal id of
268 // synapse_model = 62, see nest_types.h
269 {
270 const std::string msg =
271 "CopyModel cannot generate another synapse. Maximal synapse model count "
272 "of " + std::to_string( MAX_SYN_ID ) + " exceeded.";
273 LOG( M_ERROR, "ModelManager::copy_synapse_model_", msg );
274 throw KernelException( "Synapse model count exceeded" );
275 }
276 assert( new_id != invalid_synindex );
277
278 // if the copied synapse is a secondary connector model the synid of the copy
279 // has to be mapped to the corresponding secondary event type
280 if ( not get_synapse_prototype( old_id ).is_primary() )
281 {
282 ( get_synapse_prototype( old_id ).get_event() )->add_syn_id( new_id );
283 }
284
285 for ( thread t = 0; t < static_cast< thread >( kernel().vp_manager.get_num_threads() ); ++t )
286 {
287 prototypes_[ t ].push_back( get_synapse_prototype( old_id ).clone( new_name.toString() ) );
288 prototypes_[ t ][ new_id ]->set_syn_id( new_id );
289 }
290
291 synapsedict_->insert( new_name, new_id );
292
293 kernel().connection_manager.resize_connections();
294 return new_id;
295 }
296
297
298 void
set_model_defaults(Name name,DictionaryDatum params)299 ModelManager::set_model_defaults( Name name, DictionaryDatum params )
300 {
301 const Token nodemodel = modeldict_->lookup( name );
302 const Token synmodel = synapsedict_->lookup( name );
303
304 index id;
305 if ( not nodemodel.empty() )
306 {
307 id = static_cast< index >( nodemodel );
308 set_node_defaults_( id, params );
309 }
310 else if ( not synmodel.empty() )
311 {
312 id = static_cast< index >( synmodel );
313 set_synapse_defaults_( id, params );
314 }
315 else
316 {
317 throw UnknownModelName( name );
318 }
319
320 model_defaults_modified_ = true;
321 }
322
323
324 void
set_node_defaults_(index model_id,const DictionaryDatum & params)325 ModelManager::set_node_defaults_( index model_id, const DictionaryDatum& params )
326 {
327 params->clear_access_flags();
328
329 get_model( model_id )->set_status( params );
330
331 ALL_ENTRIES_ACCESSED( *params, "ModelManager::set_node_defaults_", "Unread dictionary entries: " );
332 }
333
334 void
set_synapse_defaults_(index model_id,const DictionaryDatum & params)335 ModelManager::set_synapse_defaults_( index model_id, const DictionaryDatum& params )
336 {
337 params->clear_access_flags();
338 assert_valid_syn_id( model_id );
339
340 std::vector< std::shared_ptr< WrappedThreadException > > exceptions_raised_( kernel().vp_manager.get_num_threads() );
341
342 // We have to run this in parallel to set the status on nodes that exist on each
343 // thread, such as volume_transmitter.
344 #pragma omp parallel
345 {
346 thread tid = kernel().vp_manager.get_thread_id();
347
348 try
349 {
350 prototypes_[ tid ][ model_id ]->set_status( params );
351 }
352 catch ( std::exception& err )
353 {
354 // We must create a new exception here, err's lifetime ends at
355 // the end of the catch block.
356 exceptions_raised_.at( tid ) = std::shared_ptr< WrappedThreadException >( new WrappedThreadException( err ) );
357 }
358 }
359
360 for ( thread tid = 0; tid < kernel().vp_manager.get_num_threads(); ++tid )
361 {
362 if ( exceptions_raised_.at( tid ).get() )
363 {
364 throw WrappedThreadException( *( exceptions_raised_.at( tid ) ) );
365 }
366 }
367
368 ALL_ENTRIES_ACCESSED( *params, "ModelManager::set_synapse_defaults_", "Unread dictionary entries: " );
369 }
370
371 // TODO: replace int with index and return value -1 with invalid_index, also
372 // change all pertaining code
373 int
get_model_id(const Name name) const374 ModelManager::get_model_id( const Name name ) const
375 {
376 const Name model_name( name );
377 for ( int i = 0; i < ( int ) models_.size(); ++i )
378 {
379 assert( models_[ i ] != NULL );
380 if ( model_name == models_[ i ]->get_name() )
381 {
382 return i;
383 }
384 }
385 return -1;
386 }
387
388
389 DictionaryDatum
get_connector_defaults(synindex syn_id) const390 ModelManager::get_connector_defaults( synindex syn_id ) const
391 {
392 assert_valid_syn_id( syn_id );
393
394 DictionaryDatum dict( new Dictionary() );
395
396 for ( thread t = 0; t < static_cast< thread >( kernel().vp_manager.get_num_threads() ); ++t )
397 {
398 // each call adds to num_connections
399 prototypes_[ t ][ syn_id ]->get_status( dict );
400 }
401
402 ( *dict )[ names::num_connections ] = kernel().connection_manager.get_num_connections( syn_id );
403
404 return dict;
405 }
406
407 bool
connector_requires_symmetric(const synindex syn_id) const408 ModelManager::connector_requires_symmetric( const synindex syn_id ) const
409 {
410 assert_valid_syn_id( syn_id );
411
412 return prototypes_[ 0 ][ syn_id ]->requires_symmetric();
413 }
414
415 bool
connector_requires_clopath_archiving(const synindex syn_id) const416 ModelManager::connector_requires_clopath_archiving( const synindex syn_id ) const
417 {
418 assert_valid_syn_id( syn_id );
419
420 return prototypes_[ 0 ][ syn_id ]->requires_clopath_archiving();
421 }
422
423 bool
connector_requires_urbanczik_archiving(const synindex syn_id) const424 ModelManager::connector_requires_urbanczik_archiving( const synindex syn_id ) const
425 {
426 assert_valid_syn_id( syn_id );
427
428 return prototypes_[ 0 ][ syn_id ]->requires_urbanczik_archiving();
429 }
430
431 void
clear_models_()432 ModelManager::clear_models_()
433 {
434 // We delete all models, which will also delete all nodes. The
435 // built-in models will be recovered from the pristine_models_ in
436 // init()
437 for ( std::vector< Model* >::iterator m = models_.begin(); m != models_.end(); ++m )
438 {
439 if ( *m != 0 )
440 {
441 delete *m;
442 }
443 }
444
445 models_.clear();
446 proxy_nodes_.clear();
447 dummy_spike_sources_.clear();
448
449 modeldict_->clear();
450
451 model_defaults_modified_ = false;
452 }
453
454 void
clear_prototypes_()455 ModelManager::clear_prototypes_()
456 {
457 for ( std::vector< std::vector< ConnectorModel* > >::iterator it = prototypes_.begin(); it != prototypes_.end();
458 ++it )
459 {
460 for ( std::vector< ConnectorModel* >::iterator pt = it->begin(); pt != it->end(); ++pt )
461 {
462 if ( *pt != 0 )
463 {
464 delete *pt;
465 }
466 }
467 it->clear();
468 }
469 prototypes_.clear();
470 }
471
472 void
calibrate(const TimeConverter & tc)473 ModelManager::calibrate( const TimeConverter& tc )
474 {
475 for ( auto&& model : models_ )
476 {
477 model->calibrate_time( tc );
478 }
479 for ( thread t = 0; t < static_cast< thread >( kernel().vp_manager.get_num_threads() ); ++t )
480 {
481 for ( std::vector< ConnectorModel* >::iterator pt = prototypes_[ t ].begin(); pt != prototypes_[ t ].end(); ++pt )
482 {
483 if ( *pt != 0 )
484 {
485 ( *pt )->calibrate( tc );
486 }
487 }
488 }
489 }
490
491 //!< Functor to compare Models by their name.
492 bool
compare_model_by_id_(const int a,const int b)493 ModelManager::compare_model_by_id_( const int a, const int b )
494 {
495 return kernel().model_manager.get_model( a )->get_name() < kernel().model_manager.get_model( b )->get_name();
496 }
497
498 void
memory_info() const499 ModelManager::memory_info() const
500 {
501
502 std::cout.setf( std::ios::left );
503 std::vector< index > idx( get_num_node_models() );
504
505 for ( index i = 0; i < get_num_node_models(); ++i )
506 {
507 idx[ i ] = i;
508 }
509
510 std::sort( idx.begin(), idx.end(), compare_model_by_id_ );
511
512 std::string sep( "--------------------------------------------------" );
513
514 std::cout << sep << std::endl;
515 std::cout << std::setw( 25 ) << "Name" << std::setw( 13 ) << "Capacity" << std::setw( 13 ) << "Available"
516 << std::endl;
517 std::cout << sep << std::endl;
518
519 for ( index i = 0; i < get_num_node_models(); ++i )
520 {
521 Model* mod = models_[ idx[ i ] ];
522 if ( mod->mem_capacity() != 0 )
523 {
524 std::cout << std::setw( 25 ) << mod->get_name() << std::setw( 13 )
525 << mod->mem_capacity() * mod->get_element_size() << std::setw( 13 )
526 << mod->mem_available() * mod->get_element_size() << std::endl;
527 }
528 }
529
530 std::cout << sep << std::endl;
531 std::cout.unsetf( std::ios::left );
532 }
533
534 void
create_secondary_events_prototypes()535 ModelManager::create_secondary_events_prototypes()
536 {
537 delete_secondary_events_prototypes();
538 secondary_events_prototypes_.resize( kernel().vp_manager.get_num_threads() );
539
540 for ( thread tid = 0; tid < static_cast< thread >( secondary_events_prototypes_.size() ); ++tid )
541 {
542 secondary_events_prototypes_[ tid ].clear();
543 for ( synindex syn_id = 0; syn_id < prototypes_[ tid ].size(); ++syn_id )
544 {
545 if ( not prototypes_[ tid ][ syn_id ]->is_primary() )
546 {
547 secondary_events_prototypes_[ tid ].insert(
548 std::pair< synindex, SecondaryEvent* >( syn_id, prototypes_[ tid ][ syn_id ]->create_event( 1 )[ 0 ] ) );
549 }
550 }
551 }
552 }
553
554 synindex
register_connection_model_(ConnectorModel * cf)555 ModelManager::register_connection_model_( ConnectorModel* cf )
556 {
557 if ( synapsedict_->known( cf->get_name() ) )
558 {
559 delete cf;
560 std::string msg = String::compose(
561 "A synapse type called '%1' already exists.\n"
562 "Please choose a different name!",
563 cf->get_name() );
564 throw NamingConflict( msg );
565 }
566
567 pristine_prototypes_.push_back( cf );
568
569 const synindex syn_id = prototypes_[ 0 ].size();
570 pristine_prototypes_[ syn_id ]->set_syn_id( syn_id );
571
572 for ( thread t = 0; t < static_cast< thread >( kernel().vp_manager.get_num_threads() ); ++t )
573 {
574 prototypes_[ t ].push_back( cf->clone( cf->get_name() ) );
575 prototypes_[ t ][ syn_id ]->set_syn_id( syn_id );
576 }
577
578 synapsedict_->insert( cf->get_name(), syn_id );
579
580 // Need to resize Connector vectors in case connection model is added after
581 // ConnectionManager is initialised.
582 kernel().connection_manager.resize_connections();
583
584 return syn_id;
585 }
586
587 Node*
create_proxynode_(thread t,int model_id)588 ModelManager::create_proxynode_( thread t, int model_id )
589 {
590 Node* proxy = proxynode_model_->allocate( t );
591 proxy->set_model_id( model_id );
592 return proxy;
593 }
594
595 } // namespace nest
596