Completed
Push — master ( a74470...c8bc69 )
by Andrei
58s
created

hhn_network.__alfa_function()   A

Complexity

Conditions 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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