pynibs.util package¶
Submodules¶
pynibs.util.dosing module¶
Functions used in our perspective on e-field based TMS dosing [1]
References
Numssen, O., Kuhnke, P., Weise, K., & Hartwigsen, G. (2024). Electric-field-based dosing for TMS. Imaging Neuroscience, 2, 1-12. DOI: 10.1162/imag_a_00106
- pynibs.util.dosing.get_intensity_e(e1, e2, target1, target2, radius1, radius2, headmesh, rmt=1, roi='midlayer_lh_rh', verbose=False)¶
Computes the stimulator intensity adjustment factor based on the electric field.
- Parameters:
e1 (str) – .hdf5 e field with midlayer.
e2 (str) – .hdf5 e field with midlayer.
target1 (np.ndarray (3,)) – Coordinates of cortical site of MT.
target2 (np.ndarray (3,)) – Coordinates of cortical target site.
radius1 (float) – Electric field of field1 is averaged over elements inside this radius around target1.
radius2 (float) – Electric field of field2 is averaged over elements inside this radius around target2.
headmesh (str) – .hdf5 headmesh.
rmt (float, default: 1) – Resting motor threshold to be corrected.
roi (str, default: 'midlayer_lh_rh') – Name of roi. Expected to sit in
mesh['/data/midlayer/roi_surface/'].verbose (bool, default: False) – Flag indicating verbosity.
- Returns:
rmt_e_corr – Adjusted stimulation intensity for target2.
- Return type:
- pynibs.util.dosing.get_intensity_e_old(mesh1, mesh2, target1, target2, radius1, radius2, rmt=1, verbose=False)¶
Computes the stimulator intensity adjustment factor based on the electric field. Something weird is going on here - check simnibs coordinates of midlayer before usage.
- Parameters:
mesh1 (str or simnibs.msh.mesh_io.Msh) – Midlayer mesh containing results of the optimal coil position of MT in the midlayer (e.g.: …/subject_overlays/00001.hd_fixed_TMS_1-0001_MagVenture_MCF_B65_REF_highres.ccd_scalar_central.msh)
mesh2 (str or simnibs.msh.mesh_io.Msh) – Midlayer mesh containing results of the optimal coil position of the target in the midlayer (e.g.: …/subject_overlays/00001.hd_fixed_TMS_1-0001_MagVenture_MCF_B65_REF_highres.ccd_scalar_central.msh)
target1 (np.ndarray) – (3,) Coordinates of cortical site of MT.
target2 (np.ndarray) – (3,) Coordinates of cortical target site.
radius1 (float) – Electric field in target 1 is averaged over elements inside this radius.
radius2 (float) – Electric field in target 2 is averaged over elements inside this radius.
rmt (float, default: 1) – Resting motor threshold, which will be corrected.
verbose (bool, default: False) – Flag indicating verbosity.
- Returns:
rmt_e_corr – Adjusted stimulation intensity for target2.
- Return type:
- pynibs.util.dosing.get_intensity_stokes(mesh, target1, target2, spat_grad=3, rmt=0, scalp_tag=1005, roi=None, verbose=False)¶
Computes the stimulator intensity adjustment factor according to Stokes et al. 2005 (doi:10.1152/jn.00067.2005). Adjustment is based on target-scalp distance differences: adj = (Dist2-Dist1)*spat_grad
- Parameters:
mesh (str or simnibs.msh.mesh_io.Msh) – Mesh of the head model.
target1 (np.ndarray) – (3,) Coordinates of cortical site of MT.
target2 (np.ndarray) – (3,) Coordinates of cortical target site.
spat_grad (float, default: 3) – Spatial gradient.
rmt (float, default: 0) – Resting motor threshold, which will be corrected.
scalp_tag (int, default: 1005) – Tag in the mesh where the scalp is to be set.
roi (np.ndarray, optional) – (3,N) Array of nodes to project targets onto.
verbose (bool, default: False) – Print verbosity information.
- Returns:
rmt_stokes – Adjusted stimulation intensity for target2.
- Return type:
pynibs.util.quality_measures module¶
Functions used in our publication on TMS quality metrics [1]
References
Numssen, O., Martin, S., Williams, K., Hartwigsen, G., & Knösche, T. (2024). Quantification of subject motion during TMS via pulsewise coil displacement. Brain Stimulation. DOI: 10.1016/j.brain.2024.07.003 #
- pynibs.util.quality_measures.c_map_comparison(c1, c2, t1, t2, nodes, tris)¶
Compares two c-maps in terms of NRMSD and calculates the geodesic distance between the hotspots.
- Parameters:
c1 (np.ndarray of float) – (n_ele) First c-map.
c2 (np.ndarray of float) – (n_ele) Second c-map (reference).
t1 (np.ndarray of float) –
Coordinates of the hotspot in the first c-map.
t2 (np.ndarray of float) – Coordinates of the hotspot in the second c-map.
nodes (np.ndarray of float) – (n_nodes, 3) Node coordinates
tris (np.ndarray of float) – (n_tris, 3) Connectivity of ROI elements
- Returns:
nrmsd (float) – Normalized root-mean-square deviation between the two c-maps in (%).
gdist (float) – Geodesic distance between the two hotspots in (mm).
- pynibs.util.quality_measures.calc_tms_motion_params(coil_positions, reference=None)¶
Computes motion parameters for a set of
coil_positions, i.e., coil shifts in [mm] in RAS coordinate system and rotations (pitch, roll, yaw) in [°]. Motion is computed w.r.t. the first (‘absolute’) and to the previous (‘relative’) stimulation.Position shifts are quantified with respect to the subject/nifti-specific RAS coordinate system. Rtrational changes are quantified with respect to the coil axes as follows:
pitch: rotation around left/right axis of coil
roll: rotation around coil handle axis
yaw: rotation around axis from center of coil towards head
Motion parameters for first coil position are set to 0.
- Parameters:
- Returns:
pos_diff_abs (np.ndarray) – (3, n_pulses) Absolute position differences (R, A, S).
euler_rots_abs (np.ndarray) – (3, n_pulses) Absolute rotation angles in euler angles (alpha, beta, gamma).
pos_diff_rel (np.ndarray) – (3, n_pulses) Relative position differences (R, A, S).
euler_rots_rel (np.ndarray) – (3, n_pulses) Relative rotation angles in euler angles (alpha, beta, gamma).
- pynibs.util.quality_measures.compute_pcd(delta_pos, delta_rot, skin_cortex_distance=20)¶
Computes _P_ulsewise _C_oil _D_isplacements (PCD) based on 3 position parameters (
delta_pos) and 3 rotation parmeters (delta_rot).The coil rotations (in euler angles) are transformed into a positional change projected on the cortex based on
skin_cortex_distanceas a proxy for the (local) change of the stimulation.delta_posanddelta_rotare expected to quantify motion w.r.t. the target coil position/rotation, for example the absolute deltas to the first stimulation.Axes definitions
delta_posanddelta_rotare supposed to follow this axes definition (SimNIBS):- delta_pos
X and Y: coil movement tangential to head surface
Z: coil movement perpendicular to head surface
- delta_rot
pitch: rotation around left/right axis of coil
roll: rotation around coil handle axis
yaw: rotation around axis from center of coil towards head
Examples
# get TriggerMarkers from a Localite session mats = pynibs.read_triggermarker_localite(tm_fn)[0] # calculate absolute and relative coil displacements delta_pos_abs, delta_rot_abs, delta_pos_rel, delta_rot_rel = pynibs.util.quality_measures.calc_tms_motion_params(mats) # compute PCD pcd, delta_pos, delta_rot = pynibs.util.quality_measures.compute_pcd(delta_pos_abs, delta_rot_abs) # plot movement axes = pynibs.util.quality_measures.plot_tms_motion_parameter(delta_pos_rel, delta_rot_rel, pcd) matplotlib.pyplot.show()
- Parameters:
delta_pos (np.ndarray) – (3, n_pulses) Absolute position differences (R, A, S).
delta_rot (np.ndarray) – (3, n_pulses) Absolute rotation angles in euler angles (alpha, beta, gamma).
skin_cortex_distance (int, default: 20) – Cortical depth of target to adjust coil rotations for.
- Returns:
pcd (np.ndarray) – Pulsewise coil displacements.
delta_pos (np.ndarray) – (n_pulses, ) sum(abs(delta_pos)) per pulse.
delta_rot (np.ndarray) – (n_pulses, ) sum(abs(delta_rot projected by skin_cortex_distance)) per pulse.
- pynibs.util.quality_measures.euclidean_dist(nodes, tris, source, source_is_node=True)¶
Returns Euclidean distance of all nodes to source node (triangle). This is just a wrapper for the gdist package.
Examples
with h5py.File(fn,'r') as f: tris = f['/mesh/elm/triangle_number_list'][:] nodes = f['/mesh/nodes/node_coord'][:] nodes_dist_euc, tris_dist_euc = euclidean_dist(nodes, tris, 3017) pynibs.write_data_hdf5(data_fn, data=[tris_dist_euc, nodes_dist_euc], data_names=["tris_dist_euc", "nodes_dist_euc", "]) pynibs.write_xdmf(data_fn,hdf5_geo_fn=fn)
- Parameters:
nodes (np.ndarray) – (n_nodes,3) The nodes, determined by their x-y-z-coordinates.
tris (np.ndarray) – (n_tris,3) Every triangle, determined by the node indices (vertices) that form it.
source (np.ndarray(int) or int) – Euclidean distances of all nodes (or triangles) to this one will be computed.
source_is_node (bool) – Whether source is a node idx or a triangle idx.
- Returns:
nodes_dist (np.ndarray) – (n_nodes,) Geodesic distance between source and all nodes in mm.
tris_dist (np.ndarray) – (n_tris,) Geodesic distance between source and all triangles in mm.
- pynibs.util.quality_measures.geodesic_dist(nodes, tris, source, source_is_node=True)¶
Returns geodesic distance in mm from all nodes to source node (or triangle). This is just a wrapper for the gdist package.
Examples
with h5py.File(fn,'r') as f: tris = f['/mesh/elm/triangle_number_list'][:] nodes = f['/mesh/nodes/node_coord'][:] nodes_dist_ged, tris_dist_ged = geodesic_dist(nodes, tris, 3017) pynibs.write_data_hdf5(data_fn, data=[tris_dist_ged, nodes_dist_ged], data_names=["tris_dist_ged", "nodes_dist_ged"]) pynibs.write_xdmf(data_fn,hdf5_geo_fn=fn)
- Parameters:
nodes (np.ndarray) – (n_nodes,3) The nodes, determined by their x-y-z-coordinates.
tris (np.ndarray) – (n_tris,3) Every triangle, determined by the node indices (vertices) that form it.
source (np.ndarray(int) or int) – Geodesic distances of all nodes (or triangles) to this one will be computed.
source_is_node (bool) – Whether source is a node idx or a triangle idx.
- Returns:
nodes_dist (np.ndarray) – (n_nodes,) Geodesic distance between source and all nodes in mm.
tris_dist (np.ndarray) – (n_tris,) Geodesic distance between source and all triangles in mm.
- pynibs.util.quality_measures.nrmsd(array, array_ref, error_norm='relative', x_axis=False)¶
Determine the normalized root-mean-square deviation between input data and reference data.
Notes
nrmsd = np.sqrt(1.0 / n_points * np.sum((data - data_ref) ** 2)) / (max(array_ref) - min(array_ref))
- Parameters:
array (np.ndarray) – input data [ (x), y0, y1, y2 … ].
array_ref (np.ndarray) – reference data [ (x_ref), y0_ref, y1_ref, y2_ref … ]. if array_ref is 1D, all sizes have to match.
error_norm (str, optional, default="relative") – Decide if error is determined “relative” or “absolute”.
x_axis (bool, default: False) – If True, the first column of array and array_ref is interpreted as the x-axis, where the data points are evaluated. If False, the data points are assumed to be at the same location.
- Returns:
normalized_rms – ([array.shape[1]]) Normalized root-mean-square deviation between the columns of array and array_ref.
- Return type:
np.ndarray of float
- pynibs.util.quality_measures.nrmse(array, array_ref, x_axis=False)¶
Determine the normalized root-mean-square deviation between input data and reference data.
nrmse = np.linalg.norm(array - array_ref) / np.linalg.norm(array_ref)
- Parameters:
array (np.ndarray) – input data [ (x), y0, y1, y2 … ].
array_ref (np.ndarray) – reference data [ (x_ref), y0_ref, y1_ref, y2_ref … ]. if array_ref is 1D, all sizes have to match.
x_axis (bool, default: False) – If True, the first column of array and array_ref is interpreted as the x-axis, where the data points are evaluated. If False, the data points are assumed to be at the same location.
- Returns:
nrmse – ([array.shape[1]]) Normalized root-mean-square deviation between the columns of array and array_ref.
- Return type:
np.ndarray of float
- pynibs.util.quality_measures.plot_tms_motion_parameter(pos_diff, euler_rots, pcd=None, fname=None)¶
Plots TMS coil motion parameters.
Pulsewise Coil Displacement (PCD) is a compound metric to quantify TMS coil movements. Data for a double (space) cTBS400 protocol is shown (with a break after 200 bursts).¶
- Parameters:
pos_diff (np.ndarray) – (3, n_pulses) Position differences (R, A, S).
euler_rots (np.ndarray) – (3, n_pulses) Rotation angles in euler angles (alpha, beta, gamma).
pcd (np.ndarray, optional) – (n_pulses,) pulsewise coil displacements.
fname (str, optional) – Filename to save plot.
- Returns:
axes – Figure axes.
- Return type:
matplotlib.pyplot.axes
pynibs.util.rotations module¶
Some helper functions to take care of geometric rotations
- pynibs.util.rotations.bases2rotmat(v1, v2)¶
Computes rotation matrix to rotate basis 1 (
v1) to another basis (v2).- Parameters:
v1 (np.ndarray) – (3, 3) original basis.
v2 (np.ndarray) – (3, 3) rotated basis.
- Returns:
rot_mat – (3, 3) rotation matrix to go from v1 to v2.
- Return type:
np.ndarray
- pynibs.util.rotations.euler_angles_to_rotation_matrix(theta)¶
Determines the rotation matrix from the three Euler angles theta = [Psi, Theta, Phi] (in rad), which rotate the coordinate system in the order z, y’, x’’.
- Parameters:
theta (np.ndarray) –
Euler angles in rad.
- Returns:
r –
Rotation matrix (z, y’, x’’).
- Return type:
np.ndarray
- pynibs.util.rotations.matsim2paraview(matsim)¶
Convert a matsimnibs matrix to a format that can be used in ParaView.
- Parameters:
matsim – (4, 4) matsimnibs matrix.
- pynibs.util.rotations.normalize_rot(rot)¶
Normalize rotation matrix.
- pynibs.util.rotations.points_to_triangles(points, triangles)¶
Compute the closest points on a triangle mesh to a set of points.
- Parameters:
points (np.ndarray) – (n, 3) Points to project.
triangles (np.ndarray) – (m, 3, 3) Triangle points.
- Returns:
(n, 3) Closest points on the triangle mesh.
- Return type:
np.ndarray
- pynibs.util.rotations.quat_rotation_angle(q)¶
Computes the rotation angle from the quaternion in rad.
- pynibs.util.rotations.quat_to_rot(q)¶
Computes the rotation matrix from quaternions.
- pynibs.util.rotations.quaternion_conjugate(q)¶
https://stackoverflow.com/questions/15425313/inverse-quaternion
- Parameters:
q (np.ndarray) – Input quaternion.
- Returns:
Conjugate of the input quaternion.
- Return type:
np.ndarray
- pynibs.util.rotations.quaternion_diff(q1, q2)¶
https://math.stackexchange.com/questions/2581668/ error-measure-between-two-rotations-when-one-matrix-might-not-be-a-valid-rotatio
- Parameters:
q1 (np.ndarray) – Quaternion 1.
q2 (np.ndarray) – Quaternion 2.
- Returns:
Difference between the two quaternions.
- Return type:
- pynibs.util.rotations.quaternion_inverse(q)¶
Compute the inverse of a quaternion.
The inverse of a quaternion is computed by taking the conjugate of the quaternion and dividing it by the norm of the quaternion. https://stackoverflow.com/questions/15425313/inverse-quaternion
- Parameters:
q (np.ndarray) – Input quaternion.
- Returns:
Inverse of the input quaternion.
- Return type:
np.ndarray
- pynibs.util.rotations.rot_to_quat(rot)¶
Computes the quaternions from rotation matrix (see e.g. https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/).
- pynibs.util.rotations.rotate_matsimnibs_euler(axis, angle, matsimnibs, metric='rad')¶
Rotates a matsimnibs matrix around
axisbyangle.- Parameters:
- Returns:
rotated_matsimnibs – (4, 4) Rotated system.
- Return type:
np.ndarray
- pynibs.util.rotations.rotation_matrix_to_euler_angles(r)¶
Calculates the euler angles theta = [Psi, Theta, Phi] (in rad) from the rotation matrix R which, rotate the coordinate system in the order z, y’, x’’ (https://www.learnopencv.com/rotation-matrix-to-euler-angles/).
- Parameters:
r (np.ndarray) – (3, 3) Rotation matrix (z, y’, x’’).
- Returns:
theta –
Euler angles in rad.
- Return type:
np.ndarray
- pynibs.util.rotations.rotmat_from_vecs(vec1, vec2)¶
Find the rotation matrix that aligns vec1 to vec2.
- Parameters:
1 (vec) – A 3D vector (‘source’).
2 (vec) – A 3D vector (‘destination’).
- Returns:
rot_mat (scipy.Rotation)
A transform matrix (3x3) which when applied to vec1, aligns it with vec2.
pynibs.util.simnibs_io module¶
pynibs.util.utils module¶
- pynibs.util.utils.add_center(var)¶
Adds center to argument list.
- pynibs.util.utils.bash(command)¶
Executes bash command and returns output message in stdout (uses os.popen).
- Parameters:
command (str) – Bash command.
- Returns:
output (str) – Output from stdout.
error (str) – Error message from stdout.
- pynibs.util.utils.bash_call(command)¶
Executes bash command and returns output message in stdout (uses subprocess.Popen).
- Parameters:
command (str) – bash command.
- pynibs.util.utils.calc_n_network_combs(n_e, n_c, n_i)¶
Determine number of combinations if all conditions may be replaced between N_i elements (mixed interaction).
- pynibs.util.utils.compute_chunks(seq, num)¶
Splits up a sequence _seq_ into _num_ chunks of similar size. If
len(seq) < num, (num-len(seq)) empty chunks are returned so thatlen(out) == num.
- pynibs.util.utils.cross_product(A, B)¶
Evaluates the cross product between the vector pairs in a and b using pure Python.
- pynibs.util.utils.cross_product_einsum2(a, b)¶
Evaluates the cross product between the vector pairs in a and b using the double Einstein sum.
- pynibs.util.utils.differential_evolution(fobj, bounds, mut=0.8, crossp=0.7, popsize=20, its=1000, **kwargs)¶
Differential evolution optimization algorithm.
- Parameters:
fobj (function object) – Function to optimize.
bounds (dict) – Dictionary containing the bounds of the free variables to optimize.
mut (float, default: 0.8) – Mutation factor.
crossp (float, default: 0.7) – Cross population factor.
popsize (int, default: 20) – Population size.
its (int, default: 1000) – Number of iterations.
kwargs (dict) – Arguments passed to fobj (constants etc…).
- Returns:
best (dict) – Dictionary containing the best values.
fitness (float) – Fitness value of the best solution.
- pynibs.util.utils.generalized_extreme_value_distribution(x, mu, sigma, k)¶
Generalized extreme value distribution.
- pynibs.util.utils.get_cartesian_product(array_list)¶
Generate a cartesian product of input arrays (all combinations).
cartesian_product = get_cartesian_product(array_list)- Parameters:
array_list (list of 1D ndarray of float) – Arrays to compute the cartesian product with.
- Returns:
cartesian_product – (M, len(arrays)) Array containing the cartesian products (all combinations of input vectors).
- Return type:
ndarray of float
Examples
import pygpc out = pygpc.get_cartesian_product(([1, 2, 3], [4, 5], [6, 7])) out
- pynibs.util.utils.intersection_vec_plan(ray_dir, ray_origin, plane_n, plane_p, eps=1e-06)¶
Computes intersection between vector (‘ray’) and plane.
- Parameters:
ray_dir (np.ndarray) – (3,) (Rotated) vector direction.
ray_origin (np.ndarray) – (3,) Any point on the ray.
plane_n (np.ndarray) – (3,) Plane normal.
plane_p (np.ndarray) – (3,) Any point on the plane.
eps (float, default=1e-6) – Resolution.
- Returns:
inters – (3,) Intersection location. (np.inf, np.inf, np.inf) if no intersection.
- Return type:
np.ndarray
- pynibs.util.utils.invert(trans)¶
Invert rotation matrix.
- pynibs.util.utils.likelihood_posterior(x, y, fun, bounds=None, verbose=True, normalized_params=False, **params)¶
Determines the likelihood of the data following the function “fun” assuming a two variability source of the data pairs (x, y) using the posterior distribution.
- Parameters:
x (ndarray of float) – (n_points) x data.
y (ndarray of float) – (n_points) y data
fun (function) – Function to fit the data to (e.g. sigmoid).
bounds (dict, optional) – Dictionary containing the bounds of “sigma_x” and “sigma_y” and the free parameters of fun.
verbose (bool, default: True) – Print function output after every calculation.
normalized_params (bool, default: False) – Are the parameters passed in normalized space between [0, 1]? If so, bounds are used to denormalize them before calculation.
**params (dict) – Free parameters to optimize. Contains “sigma_x”, “sigma_y”, and the free parameters of fun.
- Returns:
l – Negative likelihood.
- Return type:
- pynibs.util.utils.list2dict(l)¶
Transform list of dicts with same keys to dict of list
- pynibs.util.utils.load_muaps(fn_muaps, fs=1000000.0, fs_downsample=100000.0)¶
- pynibs.util.utils.mutual_coherence(array)¶
Calculate the mutual coherence of a matrix A. It can also be referred as the cosine of the smallest angle between two columns.
mutual_coherence = mutual_coherence(array)
- pynibs.util.utils.norm_percentile(data, percentile)¶
Normalizes data to a given percentile.
- Parameters:
data (np.ndarray) – (n_data, ) Dataset to normalize.
percentile (float) – Percentile of normalization value [0 … 100].
- Returns:
data_norm – (n_data, ) Normalized dataset.
- Return type:
np.ndarray
- pynibs.util.utils.rd(array, array_ref)¶
Determine the relative difference between input data and reference data.
- Parameters:
array (np.ndarray) – input data [ (x), y0, y1, y2 … ].
array_ref (np.ndarray) – reference data [ (x_ref), y0_ref, y1_ref, y2_ref … ] if array_ref is 1D, all sizes have to match.
- Returns:
rd – (array.shape[1]) Relative difference between the columns of array and array_ref.
- Return type:
ndarray of float
- pynibs.util.utils.recursive_len(item)¶
Determine len of list of lists (recursively).
- pynibs.util.utils.sigmoid_log_p(x, p)¶
- pynibs.util.utils.tal2mni(coords, direction='tal2mni', style='nonlinear')¶
Transform Talairach coordinates into (SPM) MNI space and vice versa.
This is taken from https://imaging.mrc-cbu.cam.ac.uk/imaging/MniTalairach and http://gibms.mc.ntu.edu.tw/bmlab/tools/data-analysis-codes/mni2tal-m/
- Parameters:
- Returns:
coords_trans – Transformed coordinates.
- Return type:
np.ndarray
