pyNIBS 0.2024.8__py3-none-any.whl → 0.2026.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pynibs/__init__.py +26 -14
- pynibs/coil/__init__.py +6 -0
- pynibs/{coil.py → coil/coil.py} +213 -543
- pynibs/coil/export.py +508 -0
- pynibs/congruence/__init__.py +4 -1
- pynibs/congruence/congruence.py +37 -45
- pynibs/congruence/ext_metrics.py +40 -11
- pynibs/congruence/stimulation_threshold.py +1 -2
- pynibs/expio/Mep.py +120 -370
- pynibs/expio/__init__.py +10 -0
- pynibs/expio/brainsight.py +34 -37
- pynibs/expio/cobot.py +25 -25
- pynibs/expio/exp.py +10 -7
- pynibs/expio/fit_funs.py +3 -0
- pynibs/expio/invesalius.py +70 -0
- pynibs/expio/localite.py +190 -91
- pynibs/expio/neurone.py +139 -0
- pynibs/expio/signal_ced.py +345 -2
- pynibs/expio/visor.py +16 -15
- pynibs/freesurfer.py +34 -33
- pynibs/hdf5_io/hdf5_io.py +149 -132
- pynibs/hdf5_io/xdmf.py +35 -31
- pynibs/mesh/__init__.py +1 -1
- pynibs/mesh/mesh_struct.py +77 -92
- pynibs/mesh/transformations.py +121 -21
- pynibs/mesh/utils.py +191 -99
- pynibs/models/_TMS.py +2 -1
- pynibs/muap.py +1 -2
- pynibs/neuron/__init__.py +10 -0
- pynibs/neuron/models/mep.py +566 -0
- pynibs/neuron/neuron_regression.py +98 -8
- pynibs/optimization/__init__.py +12 -2
- pynibs/optimization/{optimization.py → coil_opt.py} +157 -133
- pynibs/optimization/multichannel.py +1174 -24
- pynibs/optimization/workhorses.py +7 -8
- pynibs/regression/__init__.py +4 -2
- pynibs/regression/dual_node_detection.py +229 -219
- pynibs/regression/regression.py +92 -61
- pynibs/roi/__init__.py +4 -1
- pynibs/roi/roi_structs.py +19 -21
- pynibs/roi/{roi.py → roi_utils.py} +56 -33
- pynibs/subject.py +24 -14
- pynibs/util/__init__.py +20 -4
- pynibs/util/dosing.py +4 -5
- pynibs/util/quality_measures.py +39 -38
- pynibs/util/rotations.py +116 -9
- pynibs/util/{simnibs.py → simnibs_io.py} +29 -19
- pynibs/util/{util.py → utils.py} +20 -22
- pynibs/visualization/para.py +4 -4
- pynibs/visualization/render_3D.py +4 -4
- pynibs-0.2026.1.dist-info/METADATA +105 -0
- pynibs-0.2026.1.dist-info/RECORD +69 -0
- {pyNIBS-0.2024.8.dist-info → pynibs-0.2026.1.dist-info}/WHEEL +1 -1
- pyNIBS-0.2024.8.dist-info/METADATA +0 -723
- pyNIBS-0.2024.8.dist-info/RECORD +0 -107
- pynibs/data/configuration_exp0.yaml +0 -59
- pynibs/data/configuration_linear_MEP.yaml +0 -61
- pynibs/data/configuration_linear_RT.yaml +0 -61
- pynibs/data/configuration_sigmoid4.yaml +0 -68
- pynibs/data/network mapping configuration/configuration guide.md +0 -238
- pynibs/data/network mapping configuration/configuration_TEMPLATE.yaml +0 -42
- pynibs/data/network mapping configuration/configuration_for_testing.yaml +0 -43
- pynibs/data/network mapping configuration/configuration_modelTMS.yaml +0 -43
- pynibs/data/network mapping configuration/configuration_reg_isi_05.yaml +0 -43
- pynibs/data/network mapping configuration/output_documentation.md +0 -185
- pynibs/data/network mapping configuration/recommendations_for_accuracy_threshold.md +0 -77
- pynibs/data/neuron/models/L23_PC_cADpyr_biphasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L23_PC_cADpyr_monophasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L4_LBC_biphasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L4_LBC_monophasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L4_NBC_biphasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L4_NBC_monophasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L4_SBC_biphasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L4_SBC_monophasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L5_TTPC2_cADpyr_biphasic_v1.csv +0 -1281
- pynibs/data/neuron/models/L5_TTPC2_cADpyr_monophasic_v1.csv +0 -1281
- pynibs/tests/data/InstrumentMarker20200225163611937.xml +0 -19
- pynibs/tests/data/TriggerMarkers_Coil0_20200225163443682.xml +0 -14
- pynibs/tests/data/TriggerMarkers_Coil1_20200225170337572.xml +0 -6373
- pynibs/tests/data/Xdmf.dtd +0 -89
- pynibs/tests/data/brainsight_niiImage_nifticoord.txt +0 -145
- pynibs/tests/data/brainsight_niiImage_nifticoord_largefile.txt +0 -1434
- pynibs/tests/data/brainsight_niiImage_niifticoord_mixedtargets.txt +0 -47
- pynibs/tests/data/create_subject_testsub.py +0 -332
- pynibs/tests/data/data.hdf5 +0 -0
- pynibs/tests/data/geo.hdf5 +0 -0
- pynibs/tests/test_coil.py +0 -474
- pynibs/tests/test_elements2nodes.py +0 -100
- pynibs/tests/test_hdf5_io/test_xdmf.py +0 -61
- pynibs/tests/test_mesh_transformations.py +0 -123
- pynibs/tests/test_mesh_utils.py +0 -143
- pynibs/tests/test_nnav_imports.py +0 -101
- pynibs/tests/test_quality_measures.py +0 -117
- pynibs/tests/test_regressdata.py +0 -289
- pynibs/tests/test_roi.py +0 -17
- pynibs/tests/test_rotations.py +0 -86
- pynibs/tests/test_subject.py +0 -71
- pynibs/tests/test_util.py +0 -24
- /pynibs/{regression/score_types.py → neuron/models/m1_montbrio.py} +0 -0
- {pyNIBS-0.2024.8.dist-info → pynibs-0.2026.1.dist-info/licenses}/LICENSE +0 -0
- {pyNIBS-0.2024.8.dist-info → pynibs-0.2026.1.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import copy
|
|
3
|
+
import h5py
|
|
4
|
+
import pygpc
|
|
3
5
|
import pynibs
|
|
4
6
|
import numpy as np
|
|
5
7
|
import _pickle as pickle
|
|
@@ -206,7 +208,7 @@ def calc_e_threshold(layerid, theta, gradient=None, mep=None, neuronmodel="sensi
|
|
|
206
208
|
params[:, 2] = np.repeat(mep_norm, theta.shape[1])
|
|
207
209
|
|
|
208
210
|
idx = np.arange(params.shape[0])
|
|
209
|
-
idx_chunked = pynibs.compute_chunks(list(idx), multiprocessing.cpu_count())
|
|
211
|
+
idx_chunked = pynibs.util.utils.compute_chunks(list(idx), multiprocessing.cpu_count())
|
|
210
212
|
|
|
211
213
|
pool = multiprocessing.Pool(multiprocessing.cpu_count())
|
|
212
214
|
workhorse_partial = partial(workhorse_interp, interp=interp, params=params)
|
|
@@ -215,6 +217,7 @@ def calc_e_threshold(layerid, theta, gradient=None, mep=None, neuronmodel="sensi
|
|
|
215
217
|
pool.close()
|
|
216
218
|
pool.join()
|
|
217
219
|
|
|
220
|
+
|
|
218
221
|
else:
|
|
219
222
|
raise NotImplementedError
|
|
220
223
|
|
|
@@ -247,6 +250,7 @@ def calc_e_effective(e, layerid, theta, gradient=None, neuronmodel="sensitivity_
|
|
|
247
250
|
- "threshold_binary": assign e-field a binary value to predict MEPs
|
|
248
251
|
(False -> below threshold, True, above threshold).
|
|
249
252
|
- "IOcurve": subtract value read from precomputed neuron IO curve from electric field.
|
|
253
|
+
|
|
250
254
|
mep : np.ndarray of float [N_stim], optional
|
|
251
255
|
MEP data (required in case of "IOcurve" approach (neuronmodel)).
|
|
252
256
|
waveform : str, default: 'biphasic'
|
|
@@ -254,6 +258,7 @@ def calc_e_effective(e, layerid, theta, gradient=None, neuronmodel="sensitivity_
|
|
|
254
258
|
|
|
255
259
|
- "monophasic"
|
|
256
260
|
- "biphasic"
|
|
261
|
+
|
|
257
262
|
e_thresh_subject : float, optional
|
|
258
263
|
Subject specific stimulation threshold in V/m. Typically, between 60 ... 80 V/m.
|
|
259
264
|
This is not used for sensitivity_weighting and
|
|
@@ -263,14 +268,22 @@ def calc_e_effective(e, layerid, theta, gradient=None, neuronmodel="sensitivity_
|
|
|
263
268
|
e_eff : np.ndarray
|
|
264
269
|
Effective electric field (matrix) [N_stim x N_ele] the regression analysis can be performed with.
|
|
265
270
|
"""
|
|
271
|
+
e_thres = None
|
|
272
|
+
q = None
|
|
266
273
|
# determine sensitivity map
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
+
if neuronmodel in ["threshold_subtract", "threshold_binary", "sensitivity_weighting", "cosine", "IOcurve"]:
|
|
275
|
+
e_thres = calc_e_threshold(layerid=layerid,
|
|
276
|
+
theta=theta,
|
|
277
|
+
gradient=gradient,
|
|
278
|
+
neuronmodel=neuronmodel,
|
|
279
|
+
mep=mep,
|
|
280
|
+
waveform=waveform,
|
|
281
|
+
e_thresh_subject=e_thresh_subject)
|
|
282
|
+
elif neuronmodel == "neuron_coupling":
|
|
283
|
+
q = calc_q_coupling_model(e_mag=e,
|
|
284
|
+
theta=theta,
|
|
285
|
+
gradient=gradient,
|
|
286
|
+
waveform=waveform)
|
|
274
287
|
|
|
275
288
|
if neuronmodel == "threshold_subtract":
|
|
276
289
|
e_eff = e - e_thres
|
|
@@ -278,7 +291,84 @@ def calc_e_effective(e, layerid, theta, gradient=None, neuronmodel="sensitivity_
|
|
|
278
291
|
e_eff = e > e_thres
|
|
279
292
|
elif neuronmodel in ["sensitivity_weighting", "cosine"]:
|
|
280
293
|
e_eff = e / e_thres
|
|
294
|
+
elif neuronmodel == "neuron_coupling":
|
|
295
|
+
e_eff = q * e
|
|
281
296
|
else:
|
|
282
297
|
e_eff = np.zeros(e.shape)
|
|
283
298
|
|
|
284
299
|
return e_eff
|
|
300
|
+
|
|
301
|
+
def calc_q_coupling_model(e_mag, theta, gradient, waveform="monophasic"):
|
|
302
|
+
"""
|
|
303
|
+
Calculates the average dendritic current based of the neuron coupling model [1]. This current can the be
|
|
304
|
+
integrated over time, to yield a charge factor that is multiplied with the electric field to calculate
|
|
305
|
+
an effective electric field (e_eff).
|
|
306
|
+
|
|
307
|
+
[1] Miller, A., Knösche, T. R., & Weise, K. (2025). A coupling model of transcranial magnetic stimulation
|
|
308
|
+
activation of cortical cell populations. Brain Stimulation: Basic, Translational, and Clinical Research
|
|
309
|
+
in Neuromodulation, 18(1), 528-529.
|
|
310
|
+
|
|
311
|
+
Parameters
|
|
312
|
+
----------
|
|
313
|
+
e : np.ndarray
|
|
314
|
+
(N_stim, N_ele) Electric field (matrix).
|
|
315
|
+
theta : np.ndarray
|
|
316
|
+
(N_stim, N_ele) Theta angle (matrix) of electric field with respect to surface normal.
|
|
317
|
+
gradient : np.ndarray, optional
|
|
318
|
+
(N_stim, N_ele) Electric field gradient (matrix) between layer 1 and layer 6. Optional, the neuron mean field
|
|
319
|
+
model is more accurate when provided.
|
|
320
|
+
waveform : str, default: 'biphasic'
|
|
321
|
+
Waveform of TMS pulse:
|
|
322
|
+
|
|
323
|
+
- "monophasic"
|
|
324
|
+
- "biphasic"
|
|
325
|
+
|
|
326
|
+
Returns
|
|
327
|
+
-------
|
|
328
|
+
charges : np.ndarray
|
|
329
|
+
electric charges (matrix) [N_stim x N_ele] that can be used as scaling factors for the regression analysis.
|
|
330
|
+
"""
|
|
331
|
+
|
|
332
|
+
if waveform != 'biphasic':
|
|
333
|
+
raise NotImplementedError('only biphasic stimulation is implemented for the neuron-coupling model yet!')
|
|
334
|
+
|
|
335
|
+
# scaling factor for current (gpc was done in normalized current space)
|
|
336
|
+
i_scale = 5.148136e-9
|
|
337
|
+
t = np.linspace(0, 99.81, 500)
|
|
338
|
+
|
|
339
|
+
# read gpc session
|
|
340
|
+
fn_session = '/data/u_emueller_software/git/pynibs/pynibs/neuron/neuron_coupling_model.pkl'
|
|
341
|
+
session = pygpc.read_session(fname=fn_session)
|
|
342
|
+
|
|
343
|
+
with h5py.File(os.path.splitext(fn_session)[0] + ".hdf5", "r") as f:
|
|
344
|
+
coeffs = f["coeffs"][:]
|
|
345
|
+
|
|
346
|
+
# create grid object to transform from real to normalized coordinates [-1, 1]
|
|
347
|
+
#default values
|
|
348
|
+
# theta = 0 # angle of e-field [0, 180]°
|
|
349
|
+
# gradient = 0 # relative gradient of e-field [-20, 20] %/mm
|
|
350
|
+
# intensity = 250 # intensity of e-field [100, 400] V/m
|
|
351
|
+
fraction_nmda = 0.5 # fraction of nmda synapses [0.25, 0.75]
|
|
352
|
+
fraction_gaba_a = 0.95 # fraction of gaba_a synapses [0.9, 1.0]
|
|
353
|
+
fraction_ex = 0.6 # fraction of exc/ihn synapses [0.2, 0.8]
|
|
354
|
+
|
|
355
|
+
T_new = 30
|
|
356
|
+
dt_new = 0.01
|
|
357
|
+
t_new = np.arange(0, T_new, dt_new)
|
|
358
|
+
|
|
359
|
+
m, n = e_mag.shape
|
|
360
|
+
l = t_new.shape[0]
|
|
361
|
+
interp_current = np.zeros((m, n, l))
|
|
362
|
+
for i in range(n):
|
|
363
|
+
for j in range(m):
|
|
364
|
+
coords = np.array([[theta[i, j], gradient[i, j], e_mag[i, j], fraction_nmda, fraction_gaba_a, fraction_ex]])
|
|
365
|
+
grid = pygpc.RandomGrid(parameters_random=session.parameters_random, coords=coords)
|
|
366
|
+
|
|
367
|
+
# use gpc approximation to compute current
|
|
368
|
+
current = session.gpc[0].get_approximation(coeffs, grid.coords_norm) * i_scale
|
|
369
|
+
current = current.flatten()
|
|
370
|
+
t_new = np.arange(0, T_new, dt_new)
|
|
371
|
+
interp_current[i, j, :] = np.interp(t_new, t, current)
|
|
372
|
+
|
|
373
|
+
charges = interp_current.sum(axis=2) # integrate (sum) over time with assumption i(t=0) = 0
|
|
374
|
+
return charges
|
pynibs/optimization/__init__.py
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Routines to compute optimal sets of electric fields, either by optimizing
|
|
3
|
+
- single-channel TMS coil placements, or
|
|
4
|
+
- input currents for multichannel TMS coil arrays.
|
|
5
|
+
|
|
6
|
+
Used in [1]_
|
|
7
|
+
|
|
8
|
+
.. [1] Numssen, O., Martin, C. W., Worbs, T., Thielscher, A., Weise, K., & Knösche, T. R. (2025).
|
|
9
|
+
Optimizing and assessing multichannel TMS focality. Cold Spring Harbor Laboratory.
|
|
10
|
+
`10.1101/2025.09.19.677136 <https://doi.org/10.1101/2025.09.19.677136>`_
|
|
11
|
+
"""
|
|
2
12
|
from .opt_mep import *
|
|
3
|
-
from .
|
|
13
|
+
from .coil_opt import *
|
|
4
14
|
from .workhorses import *
|
|
5
15
|
from .multichannel import *
|