Completed
Push — 0.7.dev ( 11a2a3...92619e )
by Andrei
47s
created

hhn_network   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 383
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 383
rs 8.3396
wmc 44

10 Methods

Rating   Name   Duplication   Size   Complexity  
B __init__() 0 47 6
B simulate_static() 0 51 5
A simulate() 0 13 1
A __del__() 0 7 2
B _calculate_states() 0 52 4
F __update_peripheral_neurons() 0 37 10
A allocate_sync_ensembles() 0 11 1
F hnn_state() 0 85 9
A __alfa_function() 0 13 1
B __update_central_neurons() 0 24 5

How to fix   Complexity   

Complex Class

Complex classes like hhn_network often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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 verious ensembles.
173
    
174
    Example:
175
    @code
176
        # change period of time when high strength value of synaptic connection exists from CN2 to PN.
177
        params = hhn_parameters();
178
        params.deltah = 400;
179
        
180
        # create oscillatory network with stimulus
181
        net = hhn_network(6, [0, 0, 25, 25, 47, 47], params);
182
        
183
        # simulate network
184
        (t, dyn) = net.simulate(1200, 600);
185
        
186
        # draw network output during simulation
187
        draw_dynamics(t, dyn, x_title = "Time", y_title = "V", separate = True);
188
    @endcode
189
    
190
    """
191
    
192
    def __init__(self, num_osc, stimulus = None, parameters = None, type_conn = None, type_conn_represent = conn_represent.MATRIX, ccore = False):
193
        """!
194
        @brief Constructor of oscillatory network based on Hodgkin-Huxley neuron model.
195
        
196
        @param[in] num_osc (uint): Number of peripheral oscillators in the network.
197
        @param[in] stimulus (list): List of stimulus for oscillators, number of stimulus should be equal to number of peripheral oscillators.
198
        @param[in] parameters (hhn_parameters): Parameters of the network.
199
        @param[in] type_conn (conn_type): Type of connections between oscillators in the network (ignored for this type of network).
200
        @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list.
201
        @param[in] ccore (bool): If 'True' then CCORE is used (C/C++ implementation of the model).
202
        
203
        """
204
          
205
        super().__init__(num_osc, conn_type.NONE, type_conn_represent);
206
        
207
        if (stimulus is None):
208
            self._stimulus = [0.0] * num_osc;
209
        else:
210
            self._stimulus = stimulus;
211
        
212
        if (parameters is not None):
213
            self._params = parameters;
214
        else:
215
            self._params = hhn_parameters();
216
        
217
        self.__ccore_hhn_pointer = None;
218
        self.__ccore_hhn_dynamic_pointer = None;
219
        
220
        if (ccore is not False):
221
            self.__ccore_hhn_pointer = wrapper.hhn_create(num_osc, self._params);
222
        else:
223
            self._membrane_dynamic_pointer = None;        # final result is stored here.
224
            
225
            self._membrane_potential        = [0.0] * self._num_osc;
226
            self._active_cond_sodium        = [0.0] * self._num_osc;
227
            self._inactive_cond_sodium      = [0.0] * self._num_osc;
228
            self._active_cond_potassium     = [0.0] * self._num_osc;
229
            self._link_activation_time      = [0.0] * self._num_osc;
230
            self._link_pulse_counter        = [0.0] * self._num_osc;
231
            self._link_deactivation_time    = [0.0] * self._num_osc;
232
            self._link_weight3              = [0.0] * self._num_osc;
233
            self._pulse_generation_time     = [ [] for i in range(self._num_osc) ];
234
            self._pulse_generation          = [False] * self._num_osc;
235
            
236
            self._noise = [random.random() * 2.0 - 1.0 for i in range(self._num_osc)];
237
            
238
            self._central_element = [central_element(), central_element()];
239
240
241
    def __del__(self):
242
        """!
243
        @brief Destroy dynamically allocated oscillatory network instance in case of CCORE usage.
244
245
        """
246
        if self.__ccore_hhn_pointer:
247
            wrapper.hhn_destroy(self.__ccore_hhn_pointer)
248
249
250
    def simulate(self, steps, time, solution = solve_type.RK4):
251
        """!
252
        @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
253
        
254
        @param[in] steps (uint): Number steps of simulations during simulation.
255
        @param[in] time (double): Time of simulation.
256
        @param[in] solution (solve_type): Type of solver for differential equations.
257
        
258
        @return (list) Dynamic of oscillatory network.
259
        
260
        """
261
        
262
        return self.simulate_static(steps, time, solution);
263
    
264
    
265
    def simulate_static(self, steps, time, solution = solve_type.RK4):
266
        """!
267
        @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
268
        
269
        @param[in] steps (uint): Number steps of simulations during simulation.
270
        @param[in] time (double): Time of simulation.
271
        @param[in] solution (solve_type): Type of solver for differential equations.
272
        
273
        @return (list) Dynamic of oscillatory network.
274
        
275
        """
276
        
277
        # Check solver before simulation
278
        if (solution == solve_type.FAST):
279
            raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.");
280
        
281
        self._membrane_dynamic_pointer = None;
282
        
283
        if (self.__ccore_hhn_pointer is not None):
284
            self.__ccore_hhn_dynamic_pointer = wrapper.hhn_dynamic_create(True, False, False, False);
285
            wrapper.hhn_simulate(self.__ccore_hhn_pointer, steps, time, solution, self._stimulus, self.__ccore_hhn_dynamic_pointer);
286
            
287
            peripheral_membrane_potential = wrapper.hhn_dynamic_get_peripheral_evolution(self.__ccore_hhn_dynamic_pointer, 0);
288
            central_membrane_potential = wrapper.hhn_dynamic_get_central_evolution(self.__ccore_hhn_dynamic_pointer, 0);
289
            dynamic_time = wrapper.hhn_dynamic_get_time(self.__ccore_hhn_dynamic_pointer);
290
            
291
            self._membrane_dynamic_pointer = peripheral_membrane_potential;
292
293
            wrapper.hhn_dynamic_destroy(self.__ccore_hhn_dynamic_pointer);
294
            
295
            return (dynamic_time, peripheral_membrane_potential, central_membrane_potential);
296
        
297
        if (solution == solve_type.RKF45):
298
            raise NameError("Solver RKF45 is not support in python version.");
299
        
300
        dyn_peripheral, dyn_central, dyn_time = [], [], [];
301
        
302
        step = time / steps;
303
        int_step = step / 10.0;
304
        
305
        for t in numpy.arange(step, time + step, step):
306
            # update states of oscillators
307
            (memb_peripheral, memb_central) = self._calculate_states(solution, t, step, int_step);
308
            
309
            # update states of oscillators
310
            dyn_peripheral.append(memb_peripheral);
311
            dyn_central.append(memb_central);
312
            dyn_time.append(t);
313
        
314
        self._membrane_dynamic_pointer = dyn_peripheral;
315
        return (dyn_time, dyn_peripheral, dyn_central);
316
    
317
    
318
    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...
319
        """!
320
        @brief Caclculates new state of each oscillator in the network. Returns only excitatory state of oscillators.
321
        
322
        @param[in] solution (solve_type): Type solver of the differential equations.
323
        @param[in] t (double): Current time of simulation.
324
        @param[in] step (uint): Step of solution at the end of which states of oscillators should be calculated.
325
        @param[in] int_step (double): Differentiation step that is used for solving differential equation.
326
        
327
        @return (list) New states of membrance potentials for peripheral oscillators and for cental elements as a list where
328
                the last two values correspond to central element 1 and 2.
329
                 
330
        """
331
        
332
        next_membrane           = [0.0] * self._num_osc;
333
        next_active_sodium      = [0.0] * self._num_osc;
334
        next_inactive_sodium    = [0.0] * self._num_osc;
335
        next_active_potassium   = [0.0] * self._num_osc;
336
        
337
        # Update states of oscillators
338
        for index in range (0, self._num_osc, 1):
339
            result = odeint(self.hnn_state, 
340
                            [ self._membrane_potential[index], self._active_cond_sodium[index], self._inactive_cond_sodium[index], self._active_cond_potassium[index] ], 
341
                            numpy.arange(t - step, t, int_step), 
342
                            (index , ));
343
                            
344
            [ next_membrane[index], next_active_sodium[index], next_inactive_sodium[index], next_active_potassium[index] ] = result[len(result) - 1][0:4];        
345
        
346
        next_cn_membrane            = [0.0, 0.0];
347
        next_cn_active_sodium       = [0.0, 0.0];
348
        next_cn_inactive_sodium     = [0.0, 0.0];
349
        next_cn_active_potassium    = [0.0, 0.0];
350
        
351
        # Update states of central elements
352
        for index in range(0, len(self._central_element)):
353
            result = odeint(self.hnn_state, 
354
                            [ 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 ], 
355
                            numpy.arange(t - step, t, int_step), 
356
                            (self._num_osc + index , ));
357
                            
358
            [ 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];
359
        
360
        # Noise generation
361
        self._noise = [ 1.0 + 0.01 * (random.random() * 2.0 - 1.0) for i in range(self._num_osc)];
362
        
363
        # Updating states of PNs
364
        self.__update_peripheral_neurons(t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium);
365
        
366
        # Updation states of CN
367
        self.__update_central_neurons(t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium);
368
        
369
        return (next_membrane, next_cn_membrane);
370
    
371
    
372
    def __update_peripheral_neurons(self, t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium):
373
        """!
374
        @brief Update peripheral neurons in line with new values of current in channels.
375
        
376
        @param[in] t (doubles): Current time of simulation.
377
        @param[in] step (uint): Step (time duration) during simulation when states of oscillators should be calculated.
378
        @param[in] next_membrane (list): New values of membrane potentials for peripheral neurons.
379
        @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for peripheral neurons.
380
        @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for peripheral neurons.
381
        @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for peripheral neurons.
382
        
383
        """
384
        
385
        self._membrane_potential = next_membrane[:];
386
        self._active_cond_sodium = next_active_sodium[:];
387
        self._inactive_cond_sodium = next_inactive_sodium[:];
388
        self._active_cond_potassium = next_active_potassium[:];
389
        
390
        for index in range(0, self._num_osc):
391
            if (self._pulse_generation[index] is False):
392
                if (self._membrane_potential[index] >= 0.0):
393
                    self._pulse_generation[index] = True;
394
                    self._pulse_generation_time[index].append(t);
395
            elif (self._membrane_potential[index] < 0.0):
396
                self._pulse_generation[index] = False;
397
            
398
            # Update connection from CN2 to PN
399
            if (self._link_weight3[index] == 0.0):
400
                if (self._membrane_potential[index] > self._params.threshold):
401
                    self._link_pulse_counter[index] += step;
402
                
403
                    if (self._link_pulse_counter[index] >= 1 / self._params.eps):
404
                        self._link_weight3[index] = self._params.w3;
405
                        self._link_activation_time[index] = t;
406
            elif ( not ((self._link_activation_time[index] < t) and (t < self._link_activation_time[index] + self._params.deltah)) ):
407
                self._link_weight3[index] = 0.0;
408
                self._link_pulse_counter[index] = 0.0;
409
    
410
    
411
    def __update_central_neurons(self, t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium):
412
        """!
413
        @brief Update of central neurons in line with new values of current in channels.
414
        
415
        @param[in] t (doubles): Current time of simulation.
416
        @param[in] next_membrane (list): New values of membrane potentials for central neurons.
417
        @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for central neurons.
418
        @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for central neurons.
419
        @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for central neurons.
420
        
421
        """
422
        
423
        for index in range(0, len(self._central_element)):
424
            self._central_element[index].membrane_potential = next_cn_membrane[index];
425
            self._central_element[index].active_cond_sodium = next_cn_active_sodium[index];
426
            self._central_element[index].inactive_cond_sodium = next_cn_inactive_sodium[index];
427
            self._central_element[index].active_cond_potassium = next_cn_active_potassium[index];
428
            
429
            if (self._central_element[index].pulse_generation is False):
430
                if (self._central_element[index].membrane_potential >= 0.0):
431
                    self._central_element[index].pulse_generation = True;
432
                    self._central_element[index].pulse_generation_time.append(t);
433
            elif (self._central_element[index].membrane_potential < 0.0):
434
                self._central_element[index].pulse_generation = False;
435
    
436
    
437
    def hnn_state(self, inputs, t, argv):
438
        """!
439
        @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator.
440
        
441
        @param[in] inputs (list): States of oscillator for integration [v, m, h, n] (see description below).
442
        @param[in] t (double): Current time of simulation.
443
        @param[in] argv (tuple): Extra arguments that are not used for integration - index of oscillator.
444
        
445
        @return (list) new values of oscillator [v, m, h, n], where:
446
                v - membrane potantial of oscillator,
447
                m - activation conductance of the sodium channel,
448
                h - inactication conductance of the sodium channel,
449
                n - activation conductance of the potassium channel.
450
        
451
        """
452
        
453
        index = argv;
454
        
455
        v = inputs[0]; # membrane potential (v).
456
        m = inputs[1]; # activation conductance of the sodium channel (m).
457
        h = inputs[2]; # inactivaton conductance of the sodium channel (h).
458
        n = inputs[3]; # activation conductance of the potassium channel (n).
459
        
460
        # Calculate ion current
461
        # gNa * m[i]^3 * h * (v[i] - vNa) + gK * n[i]^4 * (v[i] - vK) + gL  (v[i] - vL)
462
        active_sodium_part = self._params.gNa * (m ** 3) * h * (v - self._params.vNa);
463
        inactive_sodium_part = self._params.gK * (n ** 4) * (v - self._params.vK);
464
        active_potassium_part = self._params.gL * (v - self._params.vL);
465
        
466
        Iion = active_sodium_part + inactive_sodium_part + active_potassium_part;
467
        
468
        Iext = 0.0;
469
        Isyn = 0.0;
470
        if (index < self._num_osc): 
471
            # PN - peripheral neuron - calculation of external current and synaptic current.
472
            Iext = self._stimulus[index] * self._noise[index];    # probably noise can be pre-defined for reducting compexity
473
            
474
            memory_impact1 = 0.0;
475
            for i in range(0, len(self._central_element[0].pulse_generation_time)):
476
                memory_impact1 += self.__alfa_function(t - self._central_element[0].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
477
            
478
            memory_impact2 = 0.0;
479
            for i in range(0, len(self._central_element[1].pulse_generation_time)):
480
                memory_impact2 += self.__alfa_function(t - self._central_element[1].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
481
    
482
            Isyn = self._params.w2 * (v - self._params.Vsyninh) * memory_impact1 + self._link_weight3[index] * (v - self._params.Vsyninh) * memory_impact2;
483
        else:
484
            # CN - central element.
485
            central_index = index - self._num_osc;
486
            if (central_index == 0):
487
                Iext = self._params.Icn1;   # CN1
488
                
489
                memory_impact = 0.0;
490
                for index_oscillator in range(0, self._num_osc):
491
                    for index_generation in range(0, len(self._pulse_generation_time[index_oscillator])):
492
                        memory_impact += self.__alfa_function(t - self._pulse_generation_time[index_oscillator][index_generation], self._params.alfa_excitatory, self._params.betta_excitatory);
493
                 
494
                Isyn = self._params.w1 * (v - self._params.Vsynexc) * memory_impact;
495
                
496
            elif (central_index == 1):
497
                Iext = self._params.Icn2;   # CN2
498
                Isyn = 0.0;
499
                
500
            else:
501
                assert 0;
502
        
503
        
504
        # Membrane potential
505
        dv = -Iion + Iext - Isyn;
506
        
507
        # Calculate variables
508
        potential = v - self._params.vRest;
509
        am = (2.5 - 0.1 * potential) / (math.exp(2.5 - 0.1 * potential) - 1.0);
510
        ah = 0.07 * math.exp(-potential / 20.0);
511
        an = (0.1 - 0.01 * potential) / (math.exp(1.0 - 0.1 * potential) - 1.0);
512
        
513
        bm = 4.0 * math.exp(-potential / 18.0);
514
        bh = 1.0 / (math.exp(3.0 - 0.1 * potential) + 1.0);
515
        bn = 0.125 * math.exp(-potential / 80.0);
516
        
517
        dm = am * (1.0 - m) - bm * m;
518
        dh = ah * (1.0 - h) - bh * h;
519
        dn = an * (1.0 - n) - bn * n;
520
        
521
        return [dv, dm, dh, dn];
522
        
523
        
524
    def allocate_sync_ensembles(self, tolerance = 0.1):
525
        """!
526
        @brief Allocates clusters in line with ensembles of synchronous oscillators where each. Synchronous ensemble corresponds to only one cluster.
527
        
528
        @param[in] tolerance (double): maximum error for allocation of synchronous ensemble oscillators.
529
        
530
        @return (list) Grours (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
531
        
532
        """
533
        
534
        return allocate_sync_ensembles(self._membrane_dynamic_pointer, tolerance, 20.0, None);
535
    
536
    
537
    def __alfa_function(self, time, alfa, betta):
538
        """!
539
        @brief Calculates value of alfa-function for difference between spike generation time and current simulation time.
540
        
541
        @param[in] time (double): Difference between last spike generation time and current time.
542
        @param[in] alfa (double): Alfa parameter for alfa-function.
543
        @param[in] betta (double): Betta parameter for alfa-function.
544
        
545
        @return (double) Value of alfa-function.
546
        
547
        """
548
        
549
        return alfa * time * math.exp(-betta * time);
550
    
551