1 /*
2 * stimulation_device.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
24 // Includes from nestkernel:
25 #include "stimulation_device.h"
26 #include "kernel_manager.h"
27
28
StimulationDevice()29 nest::StimulationDevice::StimulationDevice()
30 : DeviceNode()
31 , Device()
32 , first_syn_id_( invalid_synindex )
33 , backend_params_( new Dictionary )
34 {
35 }
36
StimulationDevice(StimulationDevice const & sd)37 nest::StimulationDevice::StimulationDevice( StimulationDevice const& sd )
38 : DeviceNode( sd )
39 , Device( sd )
40 , P_( sd.P_ )
41 , first_syn_id_( invalid_synindex ) // a new instance can't have any connections
42 , backend_params_( sd.backend_params_ )
43 {
44 }
45
46 bool
is_active(const Time & T) const47 nest::StimulationDevice::is_active( const Time& T ) const
48 {
49 long step = T.get_steps();
50 if ( get_type() == StimulationDevice::Type::CURRENT_GENERATOR
51 or get_type() == StimulationDevice::Type::DELAYED_RATE_CONNECTION_GENERATOR
52 or get_type() == StimulationDevice::Type::DOUBLE_DATA_GENERATOR )
53 {
54 step = step + 2;
55 }
56 return get_t_min_() < step and step <= get_t_max_();
57 }
58
59 void
enforce_single_syn_type(synindex syn_id)60 nest::StimulationDevice::enforce_single_syn_type( synindex syn_id )
61 {
62 if ( first_syn_id_ == invalid_synindex )
63 {
64 first_syn_id_ = syn_id;
65 }
66 if ( syn_id != first_syn_id_ )
67 {
68 throw IllegalConnection( "All outgoing connections from a device must use the same synapse type." );
69 }
70 }
71
72 void
calibrate()73 nest::StimulationDevice::calibrate()
74 {
75 Device::calibrate();
76 }
77
78 void
set_initialized_()79 nest::StimulationDevice::set_initialized_()
80 {
81 kernel().io_manager.enroll_stimulator( P_.stimulus_source_, *this, backend_params_ );
82 }
83
84 const std::string&
get_label() const85 nest::StimulationDevice::get_label() const
86 {
87 return P_.label_;
88 }
89
90
Parameters_()91 nest::StimulationDevice::Parameters_::Parameters_()
92 : label_()
93 , stimulus_source_( Name() )
94 {
95 }
96
97 void
get(DictionaryDatum & d) const98 nest::StimulationDevice::Parameters_::get( DictionaryDatum& d ) const
99 {
100 ( *d )[ names::label ] = label_;
101 ( *d )[ names::stimulus_source ] = LiteralDatum( stimulus_source_ );
102 }
103
104 void
set(const DictionaryDatum & d)105 nest::StimulationDevice::Parameters_::set( const DictionaryDatum& d )
106 {
107 updateValue< std::string >( d, names::label, label_ );
108
109 std::string stimulus_source;
110 if ( updateValue< std::string >( d, names::stimulus_source, stimulus_source ) )
111 {
112
113 if ( not kernel().io_manager.is_valid_stimulation_backend( stimulus_source ) )
114 {
115 std::string msg = String::compose( "Unknown input backend '%1'", stimulus_source );
116 throw BadProperty( msg );
117 }
118 stimulus_source_ = stimulus_source;
119 }
120 }
121
122 void
set_status(const DictionaryDatum & d)123 nest::StimulationDevice::set_status( const DictionaryDatum& d )
124 {
125
126 if ( kernel().simulation_manager.has_been_prepared() )
127 {
128 throw BadProperty( "Input parameters cannot be changed while inside a Prepare/Run/Cleanup context." );
129 }
130 Parameters_ ptmp = P_; // temporary copy in case of errors
131 ptmp.set( d ); // throws if BadProperty
132
133 Device::set_status( d );
134
135 if ( get_node_id() == 0 ) // this is a model prototype, not an actual instance
136 {
137 DictionaryDatum backend_params = DictionaryDatum( new Dictionary );
138
139 // copy all properties not previously accessed from d to backend_params
140 for ( auto& kv_pair : *d )
141 {
142 if ( not kv_pair.second.accessed() )
143 {
144 ( *backend_params )[ kv_pair.first ] = kv_pair.second;
145 }
146 }
147
148 // cache all properties accessed by the backend in private member
149 backend_params_->clear();
150 for ( auto& kv_pair : *backend_params )
151 {
152 if ( kv_pair.second.accessed() )
153 {
154 ( *backend_params_ )[ kv_pair.first ] = kv_pair.second;
155 d->lookup( kv_pair.first ).set_access_flag();
156 }
157 }
158 }
159 else
160 {
161 kernel().io_manager.enroll_stimulator( ptmp.stimulus_source_, *this, d );
162 }
163
164 // if we get here, temporaries contain consistent set of properties
165 P_ = ptmp;
166 }
167
168
169 void
get_status(DictionaryDatum & d) const170 nest::StimulationDevice::get_status( DictionaryDatum& d ) const
171 {
172 P_.get( d );
173
174 Device::get_status( d );
175
176 ( *d )[ names::element_type ] = LiteralDatum( names::stimulator );
177
178 if ( get_node_id() == 0 ) // this is a model prototype, not an actual instance
179 {
180 // overwrite with cached parameters
181 for ( auto& kv_pair : *backend_params_ )
182 {
183 ( *d )[ kv_pair.first ] = kv_pair.second;
184 }
185 }
186 }
187