Completed
Push — master ( 0d6080...7e0de7 )
by Andrei
52s
created

central_element.__init__()   A

Complexity

Conditions 1

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
"""!
2
3
@brief Oscillatory Neural Network based on Hodgkin-Huxley Neuron Model
4
@details Based on article description:
5
         - D.Chik, R.Borisyuk, Y.Kazanovich. Selective attention model with spiking elements. 2009.
6
7
@authors Andrei Novikov ([email protected])
8
@date 2014-2018
9
@copyright GNU Public License
10
11
@cond GNU_PUBLIC_LICENSE
12
    PyClustering is free software: you can redistribute it and/or modify
13
    it under the terms of the GNU General Public License as published by
14
    the Free Software Foundation, either version 3 of the License, or
15
    (at your option) any later version.
16
    
17
    PyClustering is distributed in the hope that it will be useful,
18
    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
    GNU General Public License for more details.
21
    
22
    You should have received a copy of the GNU General Public License
23
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
@endcond
25
26
"""
27
28
from scipy.integrate import odeint;
0 ignored issues
show
Configuration introduced by
The import scipy.integrate could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
29
30
import pyclustering.core.hhn_wrapper as wrapper;
31
32
from pyclustering.nnet import *;
0 ignored issues
show
Unused Code introduced by
initial_type was imported with wildcard, but is not used.
Loading history...
Unused Code introduced by
IntEnum was imported with wildcard, but is not used.
Loading history...
33
34
from pyclustering.utils import allocate_sync_ensembles;
35
36
import numpy;
0 ignored issues
show
Configuration introduced by
The import numpy could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
37
import random;
38
39
class hhn_parameters:
40
    """!
41
    @brief Describes parameters of Hodgkin-Huxley Oscillatory Network.
42
    
43
    @see hhn_network
44
    
45
    """
46
    
47
    def __init__(self):
48
        """!
49
        @brief    Default constructor of parameters for Hodgkin-Huxley Oscillatory Network.
50
        @details  Constructor initializes parameters by default non-zero values that can be
51
                  used for simple simulation.
52
        """
53
        
54
        ## Intrinsic noise.
55
        self.nu      = random.random() * 2.0 - 1.0;
56
        
57
        ## Maximal conductivity for sodium current.
58
        self.gNa     = 120.0 * (1 + 0.02 * self.nu);
59
        
60
        ## Maximal conductivity for potassium current.
61
        self.gK      = 36.0 * (1 + 0.02 * self.nu);
62
        
63
        ## Maximal conductivity for leakage current.
64
        self.gL      = 0.3 * (1 + 0.02 * self.nu);
65
        
66
        
67
        ## Reverse potential of sodium current [mV].
68
        self.vNa     = 50.0;
69
        
70
        ## Reverse potential of potassium current [mV].
71
        self.vK      = -77.0;
72
        
73
        ## Reverse potantial of leakage current [mV].
74
        self.vL      = -54.4;
75
        
76
        ## Rest potential [mV].
77
        self.vRest   = -65.0;    
78
        
79
        
80
        ## External current [mV] for central element 1.
81
        self.Icn1    = 5.0;
82
        
83
        ## External current [mV] for central element 2.
84
        self.Icn2    = 30.0;
85
        
86
        
87
        ## Synaptic reversal potential [mV] for inhibitory effects.
88
        self.Vsyninh = -80.0;    
89
        
90
        ## Synaptic reversal potential [mV] for exciting effects.
91
        self.Vsynexc = 0.0;
92
        
93
        ## Alfa-parameter for alfa-function for inhibitory effect.
94
        self.alfa_inhibitory     = 6.0;
95
        
96
        ## Betta-parameter for alfa-function for inhibitory effect.
97
        self.betta_inhibitory    = 0.3;
98
        
99
        
100
        ## Alfa-parameter for alfa-function for excitatory effect.
101
        self.alfa_excitatory     = 40.0;
102
        
103
        ## Betta-parameter for alfa-function for excitatory effect.
104
        self.betta_excitatory    = 2.0;
105
        
106
        
107
        ## Strength of the synaptic connection from PN to CN1.
108
        self.w1 = 0.1;
109
        
110
        ## Strength of the synaptic connection from CN1 to PN.
111
        self.w2 = 9.0;
112
        
113
        ## Strength of the synaptic connection from CN2 to PN.
114
        self.w3 = 5.0;
115
        
116
        
117
        ## Period of time [ms] when high strength value of synaptic connection exists from CN2 to PN.
118
        self.deltah = 650.0;
119
        
120
        ## Threshold of the membrane potential that should exceeded by oscillator to be considered as an active.
121
        self.threshold = -10;
122
        
123
        ## Affects pulse counter.
124
        self.eps = 0.16;
125
126
127
class central_element:
128
    """!
129
    @brief Central element consist of two central neurons that are described by a little bit different dynamic than peripheral.
130
    
131
    @see hhn_network
132
    
133
    """
134
    
135
    def __init__(self):
136
        """!
137
        @brief Constructor of central element.
138
        
139
        """
140
        
141
        ## Membrane potential of cenral neuron (V).
142
        self.membrane_potential      = 0.0;
143
        
144
        ## Activation conductance of the sodium channel (m).
145
        self.active_cond_sodium      = 0.0;
146
        
147
        ## Inactivaton conductance of the sodium channel (h).
148
        self.inactive_cond_sodium    = 0.0;
149
        
150
        ## Activaton conductance of the sodium channel (h).
151
        self.active_cond_potassium   = 0.0;
152
        
153
        ## Spike generation of central neuron.
154
        self.pulse_generation = False;
155
        
156
        ## Timestamps of generated pulses.
157
        self.pulse_generation_time = [];
158
    
159
    def __repr__(self):
160
        """!
161
        @brief Returns string that represents central element.
162
        
163
        """
164
        return "%s, %s" % (self.membrane_potential, self.pulse_generation_time);
165
166
167
class hhn_network(network):
168
    """!
169
    @brief Oscillatory Neural Network with central element based on Hodgkin-Huxley neuron model. Interaction between oscillators is performed via
170
           central element (no connection between oscillators that are called as peripheral). Peripheral oscillators receive external stimulus.
171
           Central element consist of two oscillators: the first is used for synchronization some ensemble of oscillators and the second controls
172
           synchronization of the first cental oscillator with various ensembles.
173
    
174
    Usage example where oscillatory network with 6 oscillators is used for simulation. The first two oscillators
175
    has the same stimulus, as well as the third and fourth oscillators and the the last two. Thus three synchronous
176
    ensembles are expected after simulation.
177
    @code
178
        # change period of time when high strength value of synaptic connection exists from CN2 to PN.
179
        params = hhn_parameters();
180
        params.deltah = 400;
181
        
182
        # create oscillatory network with stimulus
183
        net = hhn_network(6, [0, 0, 25, 25, 47, 47], params);
184
        
185
        # simulate network
186
        (t, dyn) = net.simulate(1200, 600);
187
        
188
        # draw network output during simulation (membrane potential of peripheral and central neurons).
189
        amount_canvases = 6 + 2; # 6 peripheral oscillator + 2 central elements
190
        visualizer = dynamic_visualizer(amount_canvases, x_title="Time", y_title="V", y_labels=False);
191
        visualizer.append_dynamics(t, dyn_peripheral, 0, separate);
192
        visualizer.append_dynamics(t, dyn_central, amount_canvases - 2, True);
193
        visualizer.show();
194
    @endcode
195
196
    To increase performance CCORE can be used, for that purpose special flag should be specified when network is
197
    constructed:
198
    @code
199
        # create oscillatory network with stimulus using CCORE
200
        net = hhn_network(6, [0, 0, 25, 25, 47, 47], params, ccore=True);
201
    @endcode
202
203
    There is visualized results of simulation where three synchronous ensembles of oscillators can be observed. The
204
    first and the second forms the first ensemble, the third and the fourth forms the second ensemble and the last
205
    two oscillators forms the third ensemble.
206
    @image html hhn_three_ensembles.png
207
    
208
    """
209
    
210
    def __init__(self, num_osc, stimulus = None, parameters = None, type_conn = None, type_conn_represent = conn_represent.MATRIX, ccore = False):
211
        """!
212
        @brief Constructor of oscillatory network based on Hodgkin-Huxley neuron model.
213
        
214
        @param[in] num_osc (uint): Number of peripheral oscillators in the network.
215
        @param[in] stimulus (list): List of stimulus for oscillators, number of stimulus should be equal to number of peripheral oscillators.
216
        @param[in] parameters (hhn_parameters): Parameters of the network.
217
        @param[in] type_conn (conn_type): Type of connections between oscillators in the network (ignored for this type of network).
218
        @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list.
219
        @param[in] ccore (bool): If 'True' then CCORE is used (C/C++ implementation of the model).
220
        
221
        """
222
          
223
        super().__init__(num_osc, conn_type.NONE, type_conn_represent);
224
        
225
        if (stimulus is None):
226
            self._stimulus = [0.0] * num_osc;
227
        else:
228
            self._stimulus = stimulus;
229
        
230
        if (parameters is not None):
231
            self._params = parameters;
232
        else:
233
            self._params = hhn_parameters();
234
        
235
        self.__ccore_hhn_pointer = None;
236
        self.__ccore_hhn_dynamic_pointer = None;
237
        
238
        if (ccore is not False):
239
            self.__ccore_hhn_pointer = wrapper.hhn_create(num_osc, self._params);
240
        else:
241
            self._membrane_dynamic_pointer = None;        # final result is stored here.
242
            
243
            self._membrane_potential        = [0.0] * self._num_osc;
244
            self._active_cond_sodium        = [0.0] * self._num_osc;
245
            self._inactive_cond_sodium      = [0.0] * self._num_osc;
246
            self._active_cond_potassium     = [0.0] * self._num_osc;
247
            self._link_activation_time      = [0.0] * self._num_osc;
248
            self._link_pulse_counter        = [0.0] * self._num_osc;
249
            self._link_deactivation_time    = [0.0] * self._num_osc;
250
            self._link_weight3              = [0.0] * self._num_osc;
251
            self._pulse_generation_time     = [ [] for i in range(self._num_osc) ];
252
            self._pulse_generation          = [False] * self._num_osc;
253
            
254
            self._noise = [random.random() * 2.0 - 1.0 for i in range(self._num_osc)];
255
            
256
            self._central_element = [central_element(), central_element()];
257
258
259
    def __del__(self):
260
        """!
261
        @brief Destroy dynamically allocated oscillatory network instance in case of CCORE usage.
262
263
        """
264
        if self.__ccore_hhn_pointer:
265
            wrapper.hhn_destroy(self.__ccore_hhn_pointer)
266
267
268
    def simulate(self, steps, time, solution = solve_type.RK4):
269
        """!
270
        @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
271
        @details Output dynamic is sensible to amount of steps of simulation and solver of differential equation.
272
                  Python implementation uses 'odeint' from 'scipy', CCORE uses classical RK4 and RFK45 methods,
273
                  therefore in case of CCORE HHN (Hodgkin-Huxley network) amount of steps should be greater than in
274
                  case of Python HHN.
275
276
        @param[in] steps (uint): Number steps of simulations during simulation.
277
        @param[in] time (double): Time of simulation.
278
        @param[in] solution (solve_type): Type of solver for differential equations.
279
        
280
        @return (tuple) Dynamic of oscillatory network represented by (time, peripheral neurons dynamic, central elements
281
                dynamic), where types are (list, list, list).
282
        
283
        """
284
        
285
        return self.simulate_static(steps, time, solution);
286
    
287
    
288
    def simulate_static(self, steps, time, solution = solve_type.RK4):
289
        """!
290
        @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
291
        @details Output dynamic is sensible to amount of steps of simulation and solver of differential equation.
292
                  Python implementation uses 'odeint' from 'scipy', CCORE uses classical RK4 and RFK45 methods,
293
                  therefore in case of CCORE HHN (Hodgkin-Huxley network) amount of steps should be greater than in
294
                  case of Python HHN.
295
296
        @param[in] steps (uint): Number steps of simulations during simulation.
297
        @param[in] time (double): Time of simulation.
298
        @param[in] solution (solve_type): Type of solver for differential equations.
299
        
300
        @return (tuple) Dynamic of oscillatory network represented by (time, peripheral neurons dynamic, central elements
301
                dynamic), where types are (list, list, list).
302
        
303
        """
304
        
305
        # Check solver before simulation
306
        if (solution == solve_type.FAST):
307
            raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.");
308
        
309
        self._membrane_dynamic_pointer = None;
310
        
311
        if (self.__ccore_hhn_pointer is not None):
312
            self.__ccore_hhn_dynamic_pointer = wrapper.hhn_dynamic_create(True, False, False, False);
313
            wrapper.hhn_simulate(self.__ccore_hhn_pointer, steps, time, solution, self._stimulus, self.__ccore_hhn_dynamic_pointer);
314
            
315
            peripheral_membrane_potential = wrapper.hhn_dynamic_get_peripheral_evolution(self.__ccore_hhn_dynamic_pointer, 0);
316
            central_membrane_potential = wrapper.hhn_dynamic_get_central_evolution(self.__ccore_hhn_dynamic_pointer, 0);
317
            dynamic_time = wrapper.hhn_dynamic_get_time(self.__ccore_hhn_dynamic_pointer);
318
            
319
            self._membrane_dynamic_pointer = peripheral_membrane_potential;
320
321
            wrapper.hhn_dynamic_destroy(self.__ccore_hhn_dynamic_pointer);
322
            
323
            return (dynamic_time, peripheral_membrane_potential, central_membrane_potential);
324
        
325
        if (solution == solve_type.RKF45):
326
            raise NameError("Solver RKF45 is not support in python version.");
327
        
328
        dyn_peripheral = [ self._membrane_potential[:] ];
329
        dyn_central = [ [0.0, 0.0] ];
330
        dyn_time = [ 0.0 ];
331
        
332
        step = time / steps;
333
        int_step = step / 10.0;
334
        
335
        for t in numpy.arange(step, time + step, step):
336
            # update states of oscillators
337
            (memb_peripheral, memb_central) = self._calculate_states(solution, t, step, int_step);
338
            
339
            # update states of oscillators
340
            dyn_peripheral.append(memb_peripheral);
341
            dyn_central.append(memb_central);
342
            dyn_time.append(t);
343
        
344
        self._membrane_dynamic_pointer = dyn_peripheral;
345
        return (dyn_time, dyn_peripheral, dyn_central);
346
    
347
    
348
    def _calculate_states(self, solution, t, step, int_step):
0 ignored issues
show
Unused Code introduced by
The argument solution seems to be unused.
Loading history...
349
        """!
350
        @brief Caclculates new state of each oscillator in the network. Returns only excitatory state of oscillators.
351
        
352
        @param[in] solution (solve_type): Type solver of the differential equations.
353
        @param[in] t (double): Current time of simulation.
354
        @param[in] step (uint): Step of solution at the end of which states of oscillators should be calculated.
355
        @param[in] int_step (double): Differentiation step that is used for solving differential equation.
356
        
357
        @return (list) New states of membrance potentials for peripheral oscillators and for cental elements as a list where
358
                the last two values correspond to central element 1 and 2.
359
                 
360
        """
361
        
362
        next_membrane           = [0.0] * self._num_osc;
363
        next_active_sodium      = [0.0] * self._num_osc;
364
        next_inactive_sodium    = [0.0] * self._num_osc;
365
        next_active_potassium   = [0.0] * self._num_osc;
366
        
367
        # Update states of oscillators
368
        for index in range (0, self._num_osc, 1):
369
            result = odeint(self.hnn_state, 
370
                            [ self._membrane_potential[index], self._active_cond_sodium[index], self._inactive_cond_sodium[index], self._active_cond_potassium[index] ], 
371
                            numpy.arange(t - step, t, int_step), 
372
                            (index , ));
373
                            
374
            [ next_membrane[index], next_active_sodium[index], next_inactive_sodium[index], next_active_potassium[index] ] = result[len(result) - 1][0:4];        
375
        
376
        next_cn_membrane            = [0.0, 0.0];
377
        next_cn_active_sodium       = [0.0, 0.0];
378
        next_cn_inactive_sodium     = [0.0, 0.0];
379
        next_cn_active_potassium    = [0.0, 0.0];
380
        
381
        # Update states of central elements
382
        for index in range(0, len(self._central_element)):
383
            result = odeint(self.hnn_state, 
384
                            [ self._central_element[index].membrane_potential, self._central_element[index].active_cond_sodium, self._central_element[index].inactive_cond_sodium, self._central_element[index].active_cond_potassium ], 
385
                            numpy.arange(t - step, t, int_step), 
386
                            (self._num_osc + index , ));
387
                            
388
            [ next_cn_membrane[index], next_cn_active_sodium[index], next_cn_inactive_sodium[index], next_cn_active_potassium[index] ] = result[len(result) - 1][0:4];
389
        
390
        # Noise generation
391
        self._noise = [ 1.0 + 0.01 * (random.random() * 2.0 - 1.0) for i in range(self._num_osc)];
392
        
393
        # Updating states of PNs
394
        self.__update_peripheral_neurons(t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium);
395
        
396
        # Updation states of CN
397
        self.__update_central_neurons(t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium);
398
        
399
        return (next_membrane, next_cn_membrane);
400
    
401
    
402
    def __update_peripheral_neurons(self, t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium):
403
        """!
404
        @brief Update peripheral neurons in line with new values of current in channels.
405
        
406
        @param[in] t (doubles): Current time of simulation.
407
        @param[in] step (uint): Step (time duration) during simulation when states of oscillators should be calculated.
408
        @param[in] next_membrane (list): New values of membrane potentials for peripheral neurons.
409
        @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for peripheral neurons.
410
        @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for peripheral neurons.
411
        @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for peripheral neurons.
412
        
413
        """
414
        
415
        self._membrane_potential = next_membrane[:];
416
        self._active_cond_sodium = next_active_sodium[:];
417
        self._inactive_cond_sodium = next_inactive_sodium[:];
418
        self._active_cond_potassium = next_active_potassium[:];
419
        
420
        for index in range(0, self._num_osc):
421
            if (self._pulse_generation[index] is False):
422
                if (self._membrane_potential[index] >= 0.0):
423
                    self._pulse_generation[index] = True;
424
                    self._pulse_generation_time[index].append(t);
425
            elif (self._membrane_potential[index] < 0.0):
426
                self._pulse_generation[index] = False;
427
            
428
            # Update connection from CN2 to PN
429
            if (self._link_weight3[index] == 0.0):
430
                if (self._membrane_potential[index] > self._params.threshold):
431
                    self._link_pulse_counter[index] += step;
432
                
433
                    if (self._link_pulse_counter[index] >= 1 / self._params.eps):
434
                        self._link_weight3[index] = self._params.w3;
435
                        self._link_activation_time[index] = t;
436
            elif ( not ((self._link_activation_time[index] < t) and (t < self._link_activation_time[index] + self._params.deltah)) ):
437
                self._link_weight3[index] = 0.0;
438
                self._link_pulse_counter[index] = 0.0;
439
    
440
    
441
    def __update_central_neurons(self, t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium):
442
        """!
443
        @brief Update of central neurons in line with new values of current in channels.
444
        
445
        @param[in] t (doubles): Current time of simulation.
446
        @param[in] next_membrane (list): New values of membrane potentials for central neurons.
447
        @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for central neurons.
448
        @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for central neurons.
449
        @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for central neurons.
450
        
451
        """
452
        
453
        for index in range(0, len(self._central_element)):
454
            self._central_element[index].membrane_potential = next_cn_membrane[index];
455
            self._central_element[index].active_cond_sodium = next_cn_active_sodium[index];
456
            self._central_element[index].inactive_cond_sodium = next_cn_inactive_sodium[index];
457
            self._central_element[index].active_cond_potassium = next_cn_active_potassium[index];
458
            
459
            if (self._central_element[index].pulse_generation is False):
460
                if (self._central_element[index].membrane_potential >= 0.0):
461
                    self._central_element[index].pulse_generation = True;
462
                    self._central_element[index].pulse_generation_time.append(t);
463
            elif (self._central_element[index].membrane_potential < 0.0):
464
                self._central_element[index].pulse_generation = False;
465
    
466
    
467
    def hnn_state(self, inputs, t, argv):
468
        """!
469
        @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator.
470
        
471
        @param[in] inputs (list): States of oscillator for integration [v, m, h, n] (see description below).
472
        @param[in] t (double): Current time of simulation.
473
        @param[in] argv (tuple): Extra arguments that are not used for integration - index of oscillator.
474
        
475
        @return (list) new values of oscillator [v, m, h, n], where:
476
                v - membrane potantial of oscillator,
477
                m - activation conductance of the sodium channel,
478
                h - inactication conductance of the sodium channel,
479
                n - activation conductance of the potassium channel.
480
        
481
        """
482
        
483
        index = argv;
484
        
485
        v = inputs[0]; # membrane potential (v).
486
        m = inputs[1]; # activation conductance of the sodium channel (m).
487
        h = inputs[2]; # inactivaton conductance of the sodium channel (h).
488
        n = inputs[3]; # activation conductance of the potassium channel (n).
489
        
490
        # Calculate ion current
491
        # gNa * m[i]^3 * h * (v[i] - vNa) + gK * n[i]^4 * (v[i] - vK) + gL  (v[i] - vL)
492
        active_sodium_part = self._params.gNa * (m ** 3) * h * (v - self._params.vNa);
493
        inactive_sodium_part = self._params.gK * (n ** 4) * (v - self._params.vK);
494
        active_potassium_part = self._params.gL * (v - self._params.vL);
495
        
496
        Iion = active_sodium_part + inactive_sodium_part + active_potassium_part;
497
        
498
        Iext = 0.0;
499
        Isyn = 0.0;
500
        if (index < self._num_osc): 
501
            # PN - peripheral neuron - calculation of external current and synaptic current.
502
            Iext = self._stimulus[index] * self._noise[index];    # probably noise can be pre-defined for reducting compexity
503
            
504
            memory_impact1 = 0.0;
505
            for i in range(0, len(self._central_element[0].pulse_generation_time)):
506
                memory_impact1 += self.__alfa_function(t - self._central_element[0].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
507
            
508
            memory_impact2 = 0.0;
509
            for i in range(0, len(self._central_element[1].pulse_generation_time)):
510
                memory_impact2 += self.__alfa_function(t - self._central_element[1].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
511
    
512
            Isyn = self._params.w2 * (v - self._params.Vsyninh) * memory_impact1 + self._link_weight3[index] * (v - self._params.Vsyninh) * memory_impact2;
513
        else:
514
            # CN - central element.
515
            central_index = index - self._num_osc;
516
            if (central_index == 0):
517
                Iext = self._params.Icn1;   # CN1
518
                
519
                memory_impact = 0.0;
520
                for index_oscillator in range(0, self._num_osc):
521
                    for index_generation in range(0, len(self._pulse_generation_time[index_oscillator])):
522
                        memory_impact += self.__alfa_function(t - self._pulse_generation_time[index_oscillator][index_generation], self._params.alfa_excitatory, self._params.betta_excitatory);
523
                 
524
                Isyn = self._params.w1 * (v - self._params.Vsynexc) * memory_impact;
525
                
526
            elif (central_index == 1):
527
                Iext = self._params.Icn2;   # CN2
528
                Isyn = 0.0;
529
                
530
            else:
531
                assert 0;
532
        
533
        
534
        # Membrane potential
535
        dv = -Iion + Iext - Isyn;
536
        
537
        # Calculate variables
538
        potential = v - self._params.vRest;
539
        am = (2.5 - 0.1 * potential) / (math.exp(2.5 - 0.1 * potential) - 1.0);
540
        ah = 0.07 * math.exp(-potential / 20.0);
541
        an = (0.1 - 0.01 * potential) / (math.exp(1.0 - 0.1 * potential) - 1.0);
542
        
543
        bm = 4.0 * math.exp(-potential / 18.0);
544
        bh = 1.0 / (math.exp(3.0 - 0.1 * potential) + 1.0);
545
        bn = 0.125 * math.exp(-potential / 80.0);
546
        
547
        dm = am * (1.0 - m) - bm * m;
548
        dh = ah * (1.0 - h) - bh * h;
549
        dn = an * (1.0 - n) - bn * n;
550
        
551
        return [dv, dm, dh, dn];
552
        
553
        
554
    def allocate_sync_ensembles(self, tolerance = 0.1):
555
        """!
556
        @brief Allocates clusters in line with ensembles of synchronous oscillators where each. Synchronous ensemble corresponds to only one cluster.
557
        
558
        @param[in] tolerance (double): maximum error for allocation of synchronous ensemble oscillators.
559
        
560
        @return (list) Grours (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
561
        
562
        """
563
        
564
        return allocate_sync_ensembles(self._membrane_dynamic_pointer, tolerance, 20.0, None);
565
    
566
    
567
    def __alfa_function(self, time, alfa, betta):
568
        """!
569
        @brief Calculates value of alfa-function for difference between spike generation time and current simulation time.
570
        
571
        @param[in] time (double): Difference between last spike generation time and current time.
572
        @param[in] alfa (double): Alfa parameter for alfa-function.
573
        @param[in] betta (double): Betta parameter for alfa-function.
574
        
575
        @return (double) Value of alfa-function.
576
        
577
        """
578
        
579
        return alfa * time * math.exp(-betta * time);
580
    
581