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