• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NeuralEnsemble / elephant / 26578596908

28 May 2026 01:45PM UTC coverage: 45.709% (-42.7%) from 88.424%
26578596908

Pull #608

github

web-flow
Merge 1dbc34d87 into 354df0875
Pull Request #608: [ENH] Move to pyproject.toml

0 of 1 new or added line in 1 file covered. (0.0%)

3303 existing lines in 35 files now uncovered.

3526 of 7714 relevant lines covered (45.71%)

0.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.31
/elephant/current_source_density_src/utility_functions.py
1
# -*- coding: utf-8 -*-
2
"""
3
These are some useful functions used in CSD methods,
4
They include CSD source profiles to be used as ground truths,
5
placement of electrodes in 1D, 2D and 3D., etc
6
These scripts are based on Grzegorz Parka's,
7
Google Summer of Code 2014, INFC/pykCSD
8
This was written by :
9
Michal Czerwinski, Chaitanya Chintaluri
10
Laboratory of Neuroinformatics,
11
Nencki Institute of Experimental Biology, Warsaw.
12
"""
13
from __future__ import division
1✔
14

15
import numpy as np
1✔
16
from numpy import exp
1✔
17
import quantities as pq
1✔
18

19

20
def patch_quantities():
1✔
21
    """patch quantities with the SI unit Siemens if it does not exist"""
22
    for symbol, prefix, definition, u_symbol in zip(
1✔
23
        ['siemens', 'S', 'mS', 'uS', 'nS', 'pS'],
24
        ['', '', 'milli', 'micro', 'nano', 'pico'],
25
        [pq.A / pq.V, pq.A / pq.V, 'S', 'mS', 'uS', 'nS'],
26
        [None, None, None, None, u'µS', None]):
27
        if type(definition) is str:
1✔
28
            definition = lastdefinition / 1000
1✔
29
        if not hasattr(pq, symbol):
1✔
30
            setattr(pq, symbol, pq.UnitQuantity(
×
31
                prefix + 'siemens',
32
                definition,
33
                symbol=symbol,
34
                u_symbol=u_symbol))
35
        lastdefinition = definition
1✔
36
    return
1✔
37

38

39
def contains_duplicated_electrodes(elec_pos):
1✔
40
    """Checks for duplicate electrodes
41
    Parameters
42
    ----------
43
    elec_pos : np.array
44

45
    Returns
46
    -------
47
    has_duplicated_elec : Boolean
48
    """
UNCOV
49
    unique_elec_pos = set(map(tuple, elec_pos))
×
UNCOV
50
    has_duplicated_elec = len(unique_elec_pos) < len(elec_pos)
×
UNCOV
51
    return has_duplicated_elec
×
52

53

54
def distribute_srcs_1D(X, n_src, ext_x, R_init):
1✔
55
    """Distribute sources in 1D equally spaced
56
    Parameters
57
    ----------
58
    X : np.arrays
59
        points at which CSD will be estimated
60
    n_src : int
61
        number of sources to be included in the model
62
    ext_x : floats
63
        how much should the sources extend the area X
64
    R_init : float
65
        Same as R in 1D case
66
    Returns
67
    -------
68
    X_src : np.arrays
69
        positions of the sources
70
    R : float
71
        effective radius of the basis element
72
    """
UNCOV
73
    X_src = np.mgrid[(np.min(X) - ext_x):(np.max(X) + ext_x):
×
74
                     complex(0, n_src)]
UNCOV
75
    R = R_init
×
UNCOV
76
    return X_src, R
×
77

78

79
def distribute_srcs_2D(X, Y, n_src, ext_x, ext_y, R_init):
1✔
80
    """Distribute n_src's in the given area evenly
81
    Parameters
82
    ----------
83
    X, Y : np.arrays
84
        points at which CSD will be estimated
85
    n_src : int
86
        demanded number of sources to be included in the model
87
    ext_x, ext_y : floats
88
        how should the sources extend the area X, Y
89
    R_init : float
90
        demanded radius of the basis element
91
    Returns
92
    -------
93
    X_src, Y_src : np.arrays
94
        positions of the sources
95
    nx, ny : ints
96
        number of sources in directions x,y
97
        new n_src = nx * ny may not be equal to the demanded number of sources
98
    R : float
99
        effective radius of the basis element
100
    """
UNCOV
101
    Lx = np.max(X) - np.min(X)
×
UNCOV
102
    Ly = np.max(Y) - np.min(Y)
×
UNCOV
103
    Lx_n = Lx + (2 * ext_x)
×
UNCOV
104
    Ly_n = Ly + (2 * ext_y)
×
UNCOV
105
    [nx, ny, Lx_nn, Ly_nn, ds] = get_src_params_2D(Lx_n, Ly_n, n_src)
×
UNCOV
106
    ext_x_n = (Lx_nn - Lx) / 2
×
UNCOV
107
    ext_y_n = (Ly_nn - Ly) / 2
×
UNCOV
108
    X_src, Y_src = np.mgrid[(np.min(X) - ext_x_n):(np.max(X) + ext_x_n):
×
109
                            complex(0, nx),
110
                            (np.min(Y) - ext_y_n):(np.max(Y) + ext_y_n):
111
                            complex(0, ny)]
112
    # d = round(R_init / ds)
UNCOV
113
    R = R_init  # R = d * ds
×
UNCOV
114
    return X_src, Y_src, R
×
115

116

117
def get_src_params_2D(Lx, Ly, n_src):
1✔
118
    """Distribute n_src sources evenly in a rectangle of size Lx * Ly
119
    Parameters
120
    ----------
121
    Lx, Ly : floats
122
        lengths in the directions x, y of the area,
123
        the sources should be placed
124
    n_src : int
125
        demanded number of sources
126

127
    Returns
128
    -------
129
    nx, ny : ints
130
        number of sources in directions x, y
131
        new n_src = nx * ny may not be equal to the demanded number of sources
132
    Lx_n, Ly_n : floats
133
        updated lengths in the directions x, y
134
    ds : float
135
        spacing between the sources
136
    """
UNCOV
137
    coeff = [Ly, Lx - Ly, -Lx * n_src]
×
UNCOV
138
    rts = np.roots(coeff)
×
UNCOV
139
    r = [r for r in rts if type(r) is not complex and r > 0]
×
UNCOV
140
    nx = r[0]
×
UNCOV
141
    ny = n_src / nx
×
UNCOV
142
    ds = Lx / (nx - 1)
×
UNCOV
143
    nx = np.floor(nx) + 1
×
UNCOV
144
    ny = np.floor(ny) + 1
×
UNCOV
145
    Lx_n = (nx - 1) * ds
×
UNCOV
146
    Ly_n = (ny - 1) * ds
×
UNCOV
147
    return (nx, ny, Lx_n, Ly_n, ds)
×
148

149

150
def distribute_srcs_3D(X, Y, Z, n_src, ext_x, ext_y, ext_z, R_init):
1✔
151
    """Distribute n_src sources evenly in a rectangle of size Lx * Ly * Lz
152
    Parameters
153
    ----------
154
    X, Y, Z : np.arrays
155
        points at which CSD will be estimated
156
    n_src : int
157
        desired number of sources we want to include in the model
158
    ext_x, ext_y, ext_z : floats
159
        how should the sources extend over the area X,Y,Z
160
    R_init : float
161
        demanded radius of the basis element
162

163
    Returns
164
    -------
165
    X_src, Y_src, Z_src : np.arrays
166
        positions of the sources in 3D space
167
    nx, ny, nz : ints
168
        number of sources in directions x,y,z
169
        new n_src = nx * ny * nz may not be equal to the demanded number of
170
        sources
171

172
    R : float
173
        updated radius of the basis element
174
    """
UNCOV
175
    Lx = np.max(X) - np.min(X)
×
UNCOV
176
    Ly = np.max(Y) - np.min(Y)
×
UNCOV
177
    Lz = np.max(Z) - np.min(Z)
×
UNCOV
178
    Lx_n = Lx + 2 * ext_x
×
UNCOV
179
    Ly_n = Ly + 2 * ext_y
×
UNCOV
180
    Lz_n = Lz + 2 * ext_z
×
UNCOV
181
    (nx, ny, nz, Lx_nn, Ly_nn, Lz_nn, ds) = get_src_params_3D(Lx_n,
×
182
                                                              Ly_n,
183
                                                              Lz_n,
184
                                                              n_src)
UNCOV
185
    ext_x_n = (Lx_nn - Lx) / 2
×
UNCOV
186
    ext_y_n = (Ly_nn - Ly) / 2
×
UNCOV
187
    ext_z_n = (Lz_nn - Lz) / 2
×
UNCOV
188
    X_src, Y_src, Z_src = np.mgrid[(np.min(X) - ext_x_n):(np.max(X) + ext_x_n):
×
189
                                   complex(0, nx),
190
                                   (np.min(Y) - ext_y_n):(np.max(Y) + ext_y_n):
191
                                   complex(0, ny),
192
                                   (np.min(Z) - ext_z_n):(np.max(Z) + ext_z_n):
193
                                   complex(0, nz)]
194
    # d = np.round(R_init / ds)
UNCOV
195
    R = R_init
×
UNCOV
196
    return (X_src, Y_src, Z_src, R)
×
197

198

199
def get_src_params_3D(Lx, Ly, Lz, n_src):
1✔
200
    """Helps to evenly distribute n_src sources in a cuboid of size Lx * Ly * Lz
201
    Parameters
202
    ----------
203
    Lx, Ly, Lz : floats
204
        lengths in the directions x, y, z of the area,
205
        the sources should be placed
206
    n_src : int
207
        demanded number of sources to be included in the model
208
    Returns
209
    -------
210
    nx, ny, nz : ints
211
        number of sources in directions x, y, z
212
        new n_src = nx * ny * nz may not be equal to the demanded number of
213
        sources
214
    Lx_n, Ly_n, Lz_n : floats
215
        updated lengths in the directions x, y, z
216
    ds : float
217
        spacing between the sources (grid nodes)
218
    """
UNCOV
219
    V = Lx * Ly * Lz
×
UNCOV
220
    V_unit = V / n_src
×
UNCOV
221
    L_unit = V_unit**(1. / 3.)
×
UNCOV
222
    nx = np.ceil(Lx / L_unit)
×
UNCOV
223
    ny = np.ceil(Ly / L_unit)
×
UNCOV
224
    nz = np.ceil(Lz / L_unit)
×
UNCOV
225
    ds = Lx / (nx - 1)
×
UNCOV
226
    Lx_n = (nx - 1) * ds
×
UNCOV
227
    Ly_n = (ny - 1) * ds
×
UNCOV
228
    Lz_n = (nz - 1) * ds
×
UNCOV
229
    return (nx, ny, nz, Lx_n, Ly_n, Lz_n, ds)
×
230

231

232
def generate_electrodes(dim, xlims=[0.1, 0.9], ylims=[0.1, 0.9],
1✔
233
                        zlims=[0.1, 0.9], res=5):
234
    """Generates electrodes, helpful for FWD funtion.
235
        Parameters
236
        ----------
237
        dim : int
238
            Dimensionality of the electrodes, 1,2 or 3
239
        xlims : [start, end]
240
            Spatial limits of the electrodes
241
        ylims : [start, end]
242
            Spatial limits of the electrodes
243
        zlims : [start, end]
244
            Spatial limits of the electrodes
245
        res : int
246
            How many electrodes in each dimension
247
        Returns
248
        -------
249
        ele_x, ele_y, ele_z : flattened np.array of the electrode pos
250

251
    """
UNCOV
252
    if dim == 1:
×
UNCOV
253
        ele_x = np.mgrid[xlims[0]: xlims[1]: complex(0, res)]
×
UNCOV
254
        ele_x = ele_x.flatten()
×
UNCOV
255
        return ele_x
×
UNCOV
256
    elif dim == 2:
×
UNCOV
257
        ele_x, ele_y = np.mgrid[xlims[0]: xlims[1]: complex(0, res),
×
258
                                ylims[0]: ylims[1]: complex(0, res)]
UNCOV
259
        ele_x = ele_x.flatten()
×
UNCOV
260
        ele_y = ele_y.flatten()
×
UNCOV
261
        return ele_x, ele_y
×
UNCOV
262
    elif dim == 3:
×
UNCOV
263
        ele_x, ele_y, ele_z = np.mgrid[xlims[0]: xlims[1]: complex(0, res),
×
264
                                       ylims[0]: ylims[1]: complex(0, res),
265
                                       zlims[0]: zlims[1]: complex(0, res)]
UNCOV
266
        ele_x = ele_x.flatten()
×
UNCOV
267
        ele_y = ele_y.flatten()
×
UNCOV
268
        ele_z = ele_z.flatten()
×
UNCOV
269
        return ele_x, ele_y, ele_z
×
270

271

272
def gauss_1d_dipole(x):
1✔
273
    """1D Gaussian dipole source is placed between 0 and 1
274
       to be used to test the CSD
275

276
       Parameters
277
       ----------
278
       x : np.array
279
           Spatial pts. at which the true csd is evaluated
280

281
       Returns
282
       -------
283
       f : np.array
284
           The value of the csd at the requested points
285
    """
286
    src = 0.5*exp(-((x-0.7)**2)/(2.*0.3))*(2*np.pi*0.3)**-0.5
1✔
287
    snk = -0.5*exp(-((x-0.3)**2)/(2.*0.3))*(2*np.pi*0.3)**-0.5
1✔
288
    f = src+snk
1✔
289
    return f
1✔
290

291
def large_source_2D(x, y):
1✔
292
    """2D Gaussian large source profile - to use to test csd
293
       Parameters
294
       ----------
295
       x : np.array
296
           Spatial x pts. at which the true csd is evaluated
297
       y : np.array
298
           Spatial y pts. at which the true csd is evaluated
299
       Returns
300
       -------
301
       f : np.array
302
           The value of the csd at the requested points
303
    """
UNCOV
304
    zz = [0.4, -0.3, -0.1, 0.6]
×
UNCOV
305
    zs = [0.2, 0.3, 0.4, 0.2]
×
UNCOV
306
    f1 = 0.5965*exp( (-1*(x-0.1350)**2 - (y-0.8628)**2) /0.4464)* exp(-(-zz[0])**2 / zs[0]) /exp(-(zz[0])**2/zs[0])
×
UNCOV
307
    f2 = -0.9269*exp( (-2*(x-0.1848)**2 - (y-0.0897)**2) /0.2046)* exp(-(-zz[1])**2 / zs[1]) /exp(-(zz[1])**2/zs[1]);
×
UNCOV
308
    f3 = 0.5910*exp( (-3*(x-1.3189)**2 - (y-0.3522)**2) /0.2129)* exp(-(-zz[2])**2 / zs[2]) /exp(-(zz[2])**2/zs[2]);
×
UNCOV
309
    f4 = -0.1963*exp( (-4*(x-1.3386)**2 - (y-0.5297)**2) /0.2507)* exp(-(-zz[3])**2 / zs[3]) /exp(-(zz[3])**2/zs[3]);
×
UNCOV
310
    f = f1+f2+f3+f4
×
UNCOV
311
    return f
×
312

313
def small_source_2D(x, y):
1✔
314
    """2D Gaussian small source profile - to be used to test csd
315
       Parameters
316
       ----------
317
       x : np.array
318
           Spatial x pts. at which the true csd is evaluated
319
       y : np.array
320
           Spatial y pts. at which the true csd is evaluated
321
       Returns
322
       -------
323
       f : np.array
324
           The value of the csd at the requested points
325
    """
326
    def gauss2d(x,y,p):
×
327
        rcen_x = p[0] * np.cos(p[5]) - p[1] * np.sin(p[5])
×
328
        rcen_y = p[0] * np.sin(p[5]) + p[1] * np.cos(p[5])
×
329
        xp = x * np.cos(p[5]) - y * np.sin(p[5])
×
330
        yp = x * np.sin(p[5]) + y * np.cos(p[5])
×
331

332
        g = p[4]*exp(-(((rcen_x-xp)/p[2])**2+
×
333
                          ((rcen_y-yp)/p[3])**2)/2.)
334
        return g
×
335
    f1 = gauss2d(x,y,[0.3,0.7,0.038,0.058,0.5,0.])
×
336
    f2 = gauss2d(x,y,[0.3,0.6,0.038,0.058,-0.5,0.])
×
337
    f3 = gauss2d(x,y,[0.45,0.7,0.038,0.058,0.5,0.])
×
338
    f4 = gauss2d(x,y,[0.45,0.6,0.038,0.058,-0.5,0.])
×
339
    f = f1+f2+f3+f4
×
340
    return f
×
341

342
def gauss_3d_dipole(x, y, z):
1✔
343
    """3D Gaussian dipole profile - to be used to test csd.
344
       Parameters
345
       ----------
346
       x : np.array
347
           Spatial x pts. at which the true csd is evaluated
348
       y : np.array
349
           Spatial y pts. at which the true csd is evaluated
350
       z : np.array
351
           Spatial z pts. at which the true csd is evaluated
352
       Returns
353
       -------
354
       f : np.array
355
           The value of the csd at the requested points
356
    """
UNCOV
357
    x0, y0, z0 = 0.3, 0.7, 0.3
×
UNCOV
358
    x1, y1, z1 = 0.6, 0.5, 0.7
×
UNCOV
359
    sig_2 = 0.023
×
UNCOV
360
    A = (2*np.pi*sig_2)**-1
×
UNCOV
361
    f1 = A*exp( (-(x-x0)**2 -(y-y0)**2 -(z-z0)**2) / (2*sig_2) )
×
UNCOV
362
    f2 = -1*A*exp( (-(x-x1)**2 -(y-y1)**2 -(z-z1)**2) / (2*sig_2) )
×
UNCOV
363
    f = f1+f2
×
UNCOV
364
    return f
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc