pyNIBS 0.2024.8__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-0.2024.8.dist-info/LICENSE +623 -0
- pyNIBS-0.2024.8.dist-info/METADATA +723 -0
- pyNIBS-0.2024.8.dist-info/RECORD +107 -0
- pyNIBS-0.2024.8.dist-info/WHEEL +5 -0
- pyNIBS-0.2024.8.dist-info/top_level.txt +1 -0
- pynibs/__init__.py +34 -0
- pynibs/coil.py +1367 -0
- pynibs/congruence/__init__.py +15 -0
- pynibs/congruence/congruence.py +1108 -0
- pynibs/congruence/ext_metrics.py +257 -0
- pynibs/congruence/stimulation_threshold.py +318 -0
- pynibs/data/configuration_exp0.yaml +59 -0
- pynibs/data/configuration_linear_MEP.yaml +61 -0
- pynibs/data/configuration_linear_RT.yaml +61 -0
- pynibs/data/configuration_sigmoid4.yaml +68 -0
- pynibs/data/network mapping configuration/configuration guide.md +238 -0
- pynibs/data/network mapping configuration/configuration_TEMPLATE.yaml +42 -0
- pynibs/data/network mapping configuration/configuration_for_testing.yaml +43 -0
- pynibs/data/network mapping configuration/configuration_modelTMS.yaml +43 -0
- pynibs/data/network mapping configuration/configuration_reg_isi_05.yaml +43 -0
- pynibs/data/network mapping configuration/output_documentation.md +185 -0
- pynibs/data/network mapping configuration/recommendations_for_accuracy_threshold.md +77 -0
- pynibs/data/neuron/models/L23_PC_cADpyr_biphasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L23_PC_cADpyr_monophasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L4_LBC_biphasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L4_LBC_monophasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L4_NBC_biphasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L4_NBC_monophasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L4_SBC_biphasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L4_SBC_monophasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L5_TTPC2_cADpyr_biphasic_v1.csv +1281 -0
- pynibs/data/neuron/models/L5_TTPC2_cADpyr_monophasic_v1.csv +1281 -0
- pynibs/expio/Mep.py +1518 -0
- pynibs/expio/__init__.py +8 -0
- pynibs/expio/brainsight.py +979 -0
- pynibs/expio/brainvis.py +71 -0
- pynibs/expio/cobot.py +239 -0
- pynibs/expio/exp.py +1876 -0
- pynibs/expio/fit_funs.py +287 -0
- pynibs/expio/localite.py +1987 -0
- pynibs/expio/signal_ced.py +51 -0
- pynibs/expio/visor.py +624 -0
- pynibs/freesurfer.py +502 -0
- pynibs/hdf5_io/__init__.py +10 -0
- pynibs/hdf5_io/hdf5_io.py +1857 -0
- pynibs/hdf5_io/xdmf.py +1542 -0
- pynibs/mesh/__init__.py +3 -0
- pynibs/mesh/mesh_struct.py +1394 -0
- pynibs/mesh/transformations.py +866 -0
- pynibs/mesh/utils.py +1103 -0
- pynibs/models/_TMS.py +211 -0
- pynibs/models/__init__.py +0 -0
- pynibs/muap.py +392 -0
- pynibs/neuron/__init__.py +2 -0
- pynibs/neuron/neuron_regression.py +284 -0
- pynibs/neuron/util.py +58 -0
- pynibs/optimization/__init__.py +5 -0
- pynibs/optimization/multichannel.py +278 -0
- pynibs/optimization/opt_mep.py +152 -0
- pynibs/optimization/optimization.py +1445 -0
- pynibs/optimization/workhorses.py +698 -0
- pynibs/pckg/__init__.py +0 -0
- pynibs/pckg/biosig/biosig4c++-1.9.5.src_fixed.tar.gz +0 -0
- pynibs/pckg/libeep/__init__.py +0 -0
- pynibs/pckg/libeep/pyeep.so +0 -0
- pynibs/regression/__init__.py +11 -0
- pynibs/regression/dual_node_detection.py +2375 -0
- pynibs/regression/regression.py +2984 -0
- pynibs/regression/score_types.py +0 -0
- pynibs/roi/__init__.py +2 -0
- pynibs/roi/roi.py +895 -0
- pynibs/roi/roi_structs.py +1233 -0
- pynibs/subject.py +1009 -0
- pynibs/tensor_scaling.py +144 -0
- pynibs/tests/data/InstrumentMarker20200225163611937.xml +19 -0
- pynibs/tests/data/TriggerMarkers_Coil0_20200225163443682.xml +14 -0
- pynibs/tests/data/TriggerMarkers_Coil1_20200225170337572.xml +6373 -0
- pynibs/tests/data/Xdmf.dtd +89 -0
- pynibs/tests/data/brainsight_niiImage_nifticoord.txt +145 -0
- pynibs/tests/data/brainsight_niiImage_nifticoord_largefile.txt +1434 -0
- pynibs/tests/data/brainsight_niiImage_niifticoord_mixedtargets.txt +47 -0
- pynibs/tests/data/create_subject_testsub.py +332 -0
- pynibs/tests/data/data.hdf5 +0 -0
- pynibs/tests/data/geo.hdf5 +0 -0
- pynibs/tests/test_coil.py +474 -0
- pynibs/tests/test_elements2nodes.py +100 -0
- pynibs/tests/test_hdf5_io/test_xdmf.py +61 -0
- pynibs/tests/test_mesh_transformations.py +123 -0
- pynibs/tests/test_mesh_utils.py +143 -0
- pynibs/tests/test_nnav_imports.py +101 -0
- pynibs/tests/test_quality_measures.py +117 -0
- pynibs/tests/test_regressdata.py +289 -0
- pynibs/tests/test_roi.py +17 -0
- pynibs/tests/test_rotations.py +86 -0
- pynibs/tests/test_subject.py +71 -0
- pynibs/tests/test_util.py +24 -0
- pynibs/tms_pulse.py +34 -0
- pynibs/util/__init__.py +4 -0
- pynibs/util/dosing.py +233 -0
- pynibs/util/quality_measures.py +562 -0
- pynibs/util/rotations.py +340 -0
- pynibs/util/simnibs.py +763 -0
- pynibs/util/util.py +727 -0
- pynibs/visualization/__init__.py +2 -0
- pynibs/visualization/para.py +4372 -0
- pynibs/visualization/plot_2D.py +137 -0
- pynibs/visualization/render_3D.py +347 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import numpy as np
|
|
3
|
+
import os
|
|
4
|
+
import meshio
|
|
5
|
+
import tempfile
|
|
6
|
+
from pynibs import (point_data_to_cell_data_vtk,
|
|
7
|
+
cell_data_to_point_data_vtk,
|
|
8
|
+
cell_data_to_point_data,
|
|
9
|
+
data_nodes2elements)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestMeshFunctions(unittest.TestCase):
|
|
13
|
+
def setUp(self):
|
|
14
|
+
# Create a simple mesh for testing
|
|
15
|
+
self.points = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]])
|
|
16
|
+
self.con = np.array([[0, 1, 2]])
|
|
17
|
+
cells = [("triangle", self.con)]
|
|
18
|
+
|
|
19
|
+
self.cell_data = {"test": [np.array([[1]])]}
|
|
20
|
+
self.mesh_cell_data_1d = meshio.Mesh(self.points, cells, cell_data=self.cell_data)
|
|
21
|
+
|
|
22
|
+
self.cell_data = {"test": [np.array([[1, 2, 3]])]}
|
|
23
|
+
self.mesh_cell_data_3d = meshio.Mesh(self.points, cells, cell_data=self.cell_data)
|
|
24
|
+
|
|
25
|
+
cell_data = {"test": [np.array([[1, 2, 3]])],
|
|
26
|
+
"test2": [np.array([[100, 200, 300]])]}
|
|
27
|
+
self.mesh_cell_datas_3d = meshio.Mesh(self.points, cells, cell_data=cell_data)
|
|
28
|
+
|
|
29
|
+
# Create another mesh for testing with point data
|
|
30
|
+
self.point_data = {"test": np.array([[1, 2, 3],
|
|
31
|
+
[1, 2, 3],
|
|
32
|
+
[1, 2, 3]])}
|
|
33
|
+
self.mesh_point_data_3d = meshio.Mesh(self.points, cells, point_data=self.point_data)
|
|
34
|
+
|
|
35
|
+
point_data = {"test": np.array([1, 2, 3])}
|
|
36
|
+
self.mesh_point_data_1d = meshio.Mesh(self.points, cells, point_data=point_data)
|
|
37
|
+
|
|
38
|
+
point_data = {"test": np.array([1, 2, 3]),
|
|
39
|
+
"test2": np.array([100, 200, 300])}
|
|
40
|
+
self.mesh_point_datas_1d = meshio.Mesh(self.points, cells, point_data=point_data)
|
|
41
|
+
|
|
42
|
+
def test_point_to_cell_data(self):
|
|
43
|
+
# Test conversion from point data to cell data for both meshes
|
|
44
|
+
for mesh in [self.mesh_point_data_1d, self.mesh_point_data_3d]:
|
|
45
|
+
with tempfile.NamedTemporaryFile(suffix=".vtu") as temp_file:
|
|
46
|
+
cell_data = point_data_to_cell_data_vtk(mesh, fn=temp_file.name)
|
|
47
|
+
self.assertTrue("test" in cell_data)
|
|
48
|
+
self.assertEqual(cell_data["test"].shape[0], mesh.cells[0].data.shape[0])
|
|
49
|
+
self.assertTrue(os.path.exists(temp_file.name))
|
|
50
|
+
|
|
51
|
+
def test_cell_to_point_data(self):
|
|
52
|
+
# Test conversion from cell data to point data for both meshes
|
|
53
|
+
for mesh in [self.mesh_cell_data_1d, self.mesh_cell_data_3d]:
|
|
54
|
+
with tempfile.NamedTemporaryFile(suffix=".vtu") as temp_file:
|
|
55
|
+
point_data = cell_data_to_point_data_vtk(mesh, fn=temp_file.name)
|
|
56
|
+
self.assertTrue("test" in point_data)
|
|
57
|
+
self.assertEqual(point_data["test"].shape[0], mesh.points.shape[0])
|
|
58
|
+
self.assertTrue(os.path.exists(temp_file.name))
|
|
59
|
+
|
|
60
|
+
def test_point_to_cell_data_from_con(self):
|
|
61
|
+
# Test conversion from point data to cell data for both meshes
|
|
62
|
+
for mesh in [self.mesh_point_data_1d, self.mesh_point_data_3d]:
|
|
63
|
+
with tempfile.NamedTemporaryFile(suffix=".vtu") as temp_file:
|
|
64
|
+
cell_data = point_data_to_cell_data_vtk(nodes=self.points,
|
|
65
|
+
con=self.con,
|
|
66
|
+
point_data=self.point_data, fn=temp_file.name)
|
|
67
|
+
self.assertTrue("test" in cell_data)
|
|
68
|
+
self.assertEqual(cell_data["test"].shape[0], mesh.cells[0].data.shape[0])
|
|
69
|
+
self.assertTrue(os.path.exists(temp_file.name))
|
|
70
|
+
|
|
71
|
+
def test_cell_to_point_data_from_con(self):
|
|
72
|
+
# Test conversion from cell data to point data for both meshes
|
|
73
|
+
for mesh in [self.mesh_cell_data_1d, self.mesh_cell_data_3d]:
|
|
74
|
+
with tempfile.NamedTemporaryFile(suffix=".vtu") as temp_file:
|
|
75
|
+
point_data = cell_data_to_point_data_vtk(nodes=self.points,
|
|
76
|
+
con=self.con,
|
|
77
|
+
cell_data=self.cell_data,
|
|
78
|
+
fn=temp_file.name)
|
|
79
|
+
self.assertTrue("test" in point_data)
|
|
80
|
+
self.assertEqual(point_data["test"].shape[0], mesh.points.shape[0])
|
|
81
|
+
self.assertTrue(os.path.exists(temp_file.name))
|
|
82
|
+
|
|
83
|
+
def test_point_to_cell_multiple_data(self):
|
|
84
|
+
# Test conversion from point data to cell data for both meshes
|
|
85
|
+
mesh = self.mesh_point_datas_1d
|
|
86
|
+
with tempfile.NamedTemporaryFile(suffix=".vtu") as temp_file:
|
|
87
|
+
cell_data = point_data_to_cell_data_vtk(mesh, fn=temp_file.name)
|
|
88
|
+
self.assertTrue("test" in cell_data)
|
|
89
|
+
self.assertEqual(cell_data["test"].shape[0], mesh.cells[0].data.shape[0])
|
|
90
|
+
self.assertTrue("test2" in cell_data)
|
|
91
|
+
self.assertEqual(cell_data["test2"].shape[0], mesh.cells[0].data.shape[0])
|
|
92
|
+
self.assertTrue(os.path.exists(temp_file.name))
|
|
93
|
+
|
|
94
|
+
def test_cell_to_point_multiple_data(self):
|
|
95
|
+
# Test conversion from cell data to point data for both meshes
|
|
96
|
+
mesh = self.mesh_cell_datas_3d
|
|
97
|
+
with tempfile.NamedTemporaryFile(suffix=".vtu") as temp_file:
|
|
98
|
+
point_data = cell_data_to_point_data_vtk(mesh, fn=temp_file.name)
|
|
99
|
+
self.assertTrue("test" in point_data)
|
|
100
|
+
self.assertEqual(point_data["test"].shape[0], mesh.points.shape[0])
|
|
101
|
+
self.assertTrue("test2" in point_data)
|
|
102
|
+
self.assertEqual(point_data["test2"].shape[0], mesh.points.shape[0])
|
|
103
|
+
self.assertTrue(os.path.exists(temp_file.name))
|
|
104
|
+
|
|
105
|
+
def test_cell_data_to_point_data(self):
|
|
106
|
+
# Convert the cell data to point data
|
|
107
|
+
data_nodes = cell_data_to_point_data(self.con, self.cell_data['test'][0], self.points)
|
|
108
|
+
|
|
109
|
+
# Check the result
|
|
110
|
+
self.assertEqual(data_nodes.shape, self.points.shape)
|
|
111
|
+
self.assertTrue(np.all(data_nodes >= 1) and np.all(data_nodes <= 4))
|
|
112
|
+
|
|
113
|
+
def test_data_nodes2elements(self):
|
|
114
|
+
# Convert the node data to element data
|
|
115
|
+
data_tris = data_nodes2elements(self.point_data['test'], self.con)
|
|
116
|
+
|
|
117
|
+
# Check the result
|
|
118
|
+
self.assertEqual(data_tris.shape, self.con.shape)
|
|
119
|
+
self.assertTrue(np.all(data_tris >= 1) and np.all(data_tris <= 4))
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
if __name__ == "__main__":
|
|
123
|
+
unittest.main()
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pynibs
|
|
3
|
+
import unittest
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestFindNearest(unittest.TestCase):
|
|
8
|
+
monot_arr = np.array([0, 1, 2, 3, 5, 10])
|
|
9
|
+
nonmonot_arr = np.array([10, 0, 1, 2, 3, 5, 10])
|
|
10
|
+
value = 5
|
|
11
|
+
|
|
12
|
+
def test_01_find_nearest(self):
|
|
13
|
+
idx = pynibs.find_nearest(array=self.monot_arr, value=self.value)
|
|
14
|
+
assert idx == 4
|
|
15
|
+
|
|
16
|
+
def test_02_find_nearest_fail(self):
|
|
17
|
+
idx = pynibs.find_nearest(array=self.nonmonot_arr, value=self.value)
|
|
18
|
+
assert idx == -1
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestCalcSampleSphere(unittest.TestCase):
|
|
22
|
+
mesh_hdf5_fn = os.path.join(pynibs.__testdatadir__, 'geo.hdf5')
|
|
23
|
+
mesh = pynibs.load_mesh_hdf5(mesh_hdf5_fn)
|
|
24
|
+
|
|
25
|
+
def test_01_sample_sphere_even(self):
|
|
26
|
+
with self.assertRaises(AssertionError):
|
|
27
|
+
pynibs.sample_sphere(n_points=10, r=10)
|
|
28
|
+
|
|
29
|
+
def test_02_sample_sphere_odd(self):
|
|
30
|
+
points = pynibs.sample_sphere(n_points=11, r=10)
|
|
31
|
+
assert points.shape == (11, 3)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TestCalcTriSurface(unittest.TestCase):
|
|
35
|
+
mesh_hdf5_fn = os.path.join(pynibs.__testdatadir__, 'geo.hdf5')
|
|
36
|
+
mesh = pynibs.load_mesh_hdf5(mesh_hdf5_fn)
|
|
37
|
+
|
|
38
|
+
def test_01_calc_tri_volume(self):
|
|
39
|
+
tri_surf = pynibs.calc_tri_surface(points=self.mesh.points[self.mesh.triangles])
|
|
40
|
+
assert tri_surf.size == self.mesh.triangles.shape[0]
|
|
41
|
+
assert (tri_surf > 0).all()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TestCalcTetVolume(unittest.TestCase):
|
|
45
|
+
mesh_hdf5_fn = os.path.join(pynibs.__testdatadir__, 'geo.hdf5')
|
|
46
|
+
mesh = pynibs.load_mesh_hdf5(mesh_hdf5_fn)
|
|
47
|
+
|
|
48
|
+
def test_01_calc_tet_volume_abs(self):
|
|
49
|
+
tet_vol = pynibs.calc_tet_volume(points=self.mesh.points[self.mesh.tetrahedra])
|
|
50
|
+
assert tet_vol.size == self.mesh.tetrahedra.shape[0]
|
|
51
|
+
assert (tet_vol > 0).all()
|
|
52
|
+
|
|
53
|
+
def test_02_calc_tet_volume_no_abs(self):
|
|
54
|
+
tet_vol = pynibs.calc_tet_volume(points=self.mesh.points[self.mesh.tetrahedra],
|
|
55
|
+
abs=False)
|
|
56
|
+
assert tet_vol.size == self.mesh.tetrahedra.shape[0]
|
|
57
|
+
assert (tet_vol < 0).any()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class TestGetSphere(unittest.TestCase):
|
|
61
|
+
"""
|
|
62
|
+
Test pynibs.mesh.utils.* functions.
|
|
63
|
+
"""
|
|
64
|
+
mesh_hdf5_fn = os.path.join(pynibs.__testdatadir__, 'geo.hdf5')
|
|
65
|
+
target_empty = [10, 20, 30]
|
|
66
|
+
target_full_tris = [0., 45.2227265, 71.97155693]
|
|
67
|
+
target_full_tets = [9.51698047, 84.46553784, 0.]
|
|
68
|
+
radius = 3
|
|
69
|
+
|
|
70
|
+
def test_01_get_sphere_fails(self):
|
|
71
|
+
# no mesh and no mesh_fn
|
|
72
|
+
with self.assertRaises(AssertionError):
|
|
73
|
+
pynibs.get_sphere(mesh=None,
|
|
74
|
+
mesh_fn=None,
|
|
75
|
+
target=self.target_empty,
|
|
76
|
+
radius=self.radius)
|
|
77
|
+
|
|
78
|
+
# no target
|
|
79
|
+
with self.assertRaises(AssertionError):
|
|
80
|
+
pynibs.get_sphere(mesh=None, mesh_fn=self.mesh_hdf5_fn)
|
|
81
|
+
|
|
82
|
+
# wrong element type
|
|
83
|
+
with self.assertRaises(ValueError):
|
|
84
|
+
# no radius, return nearest element
|
|
85
|
+
pynibs.get_sphere(mesh=None,
|
|
86
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
87
|
+
target=self.target_empty,
|
|
88
|
+
elmtype='square')
|
|
89
|
+
|
|
90
|
+
def test_02_get_sphere_nearest_tri(self):
|
|
91
|
+
# no radius, return nearest element
|
|
92
|
+
nearest_elm = pynibs.get_sphere(mesh=None,
|
|
93
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
94
|
+
target=self.target_empty)
|
|
95
|
+
assert nearest_elm == 681
|
|
96
|
+
|
|
97
|
+
nearest_elm = pynibs.get_sphere(mesh=None,
|
|
98
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
99
|
+
target=self.target_empty,
|
|
100
|
+
elmtype='Triangle')
|
|
101
|
+
assert nearest_elm == 681
|
|
102
|
+
|
|
103
|
+
def test_02_get_sphere_nearest_tet(self):
|
|
104
|
+
# no radius, return nearest element
|
|
105
|
+
nearest_elm = pynibs.get_sphere(mesh=None,
|
|
106
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
107
|
+
target=self.target_empty,
|
|
108
|
+
elmtype='tets')
|
|
109
|
+
assert nearest_elm == 20232
|
|
110
|
+
|
|
111
|
+
nearest_elm = pynibs.get_sphere(mesh=None,
|
|
112
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
113
|
+
target=self.target_empty,
|
|
114
|
+
elmtype='Tetrahedron')
|
|
115
|
+
assert nearest_elm == 20232
|
|
116
|
+
|
|
117
|
+
# return sphere, but should be empty
|
|
118
|
+
sphere_empty = pynibs.get_sphere(mesh=None,
|
|
119
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
120
|
+
target=self.target_empty,
|
|
121
|
+
radius=5)
|
|
122
|
+
assert sphere_empty.size == 0
|
|
123
|
+
|
|
124
|
+
def test_02_get_sphere_tris(self):
|
|
125
|
+
# return tri sphere, should not be empty
|
|
126
|
+
sphere_full_tris = pynibs.get_sphere(mesh=None,
|
|
127
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
128
|
+
target=self.target_full_tris,
|
|
129
|
+
radius=10)
|
|
130
|
+
assert sphere_full_tris.size == 13
|
|
131
|
+
|
|
132
|
+
def test_03_get_sphere_tets(self):
|
|
133
|
+
# return tet sphere, should not be empty
|
|
134
|
+
sphere_full_tets = pynibs.get_sphere(mesh=None,
|
|
135
|
+
mesh_fn=self.mesh_hdf5_fn,
|
|
136
|
+
target=self.target_full_tets,
|
|
137
|
+
radius=10,
|
|
138
|
+
elmtype='tets')
|
|
139
|
+
assert sphere_full_tets.size == 50
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if __name__ == '__main__':
|
|
143
|
+
unittest.main()
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pynibs
|
|
4
|
+
|
|
5
|
+
class TestPyNIBSLocalite(unittest.TestCase):
|
|
6
|
+
def setUp(self):
|
|
7
|
+
# Set up any necessary paths to your .xml files here
|
|
8
|
+
self.valid_im_path = f"{pynibs.__testdatadir__}/InstrumentMarker20200225163611937.xml"
|
|
9
|
+
self.valid_tm_path = f"{pynibs.__testdatadir__}/TriggerMarkers_Coil1_20200225170337572.xml"
|
|
10
|
+
self.im_test = np.array([[[ 0.9013614 , 0.29839201, -0.3138959 , -71.18429093],
|
|
11
|
+
[ 0.38530408, -0.8834528 , 0.26659466, -79.95375675],
|
|
12
|
+
[ -0.19776044, -0.36123975, -0.91127244, 38.69342634],
|
|
13
|
+
[ 0. , 0. , 0. , 1. ]]])
|
|
14
|
+
self.self_tm_0 = np.array([[ 0.89563849, 0.37653939, -0.2367116 , -71.16214655],
|
|
15
|
+
[ 0.42635749, -0.87839562, 0.21592364, -75.74648256],
|
|
16
|
+
[ -0.12662378, -0.29431584, -0.94727356, 38.65814855],
|
|
17
|
+
[ 0. , 0. , 0. , 1. ]])
|
|
18
|
+
|
|
19
|
+
# def test_get_instrument_marker_valid(self):
|
|
20
|
+
# # Test get_instrument_marker with valid input
|
|
21
|
+
# final_arr, marker_description = pynibs.localite.get_instrument_marker(self.valid_im_path)
|
|
22
|
+
# # Assert expected result here
|
|
23
|
+
# assert np.isclose(final_arr, self.im_test).all()
|
|
24
|
+
# assert np.array(marker_description) == np.array(['test'])
|
|
25
|
+
#
|
|
26
|
+
# def test_get_instrument_marker_list(self):
|
|
27
|
+
# # Test get_instrument_marker with a list of valid paths
|
|
28
|
+
# final_arr, marker_description = pynibs.localite.get_instrument_marker([self.valid_im_path, self.valid_im_path])
|
|
29
|
+
# # Assert expected result here
|
|
30
|
+
# assert len(final_arr) == len(marker_description) == 2
|
|
31
|
+
# assert np.isclose(final_arr[0], self.im_test).all()
|
|
32
|
+
# assert np.isclose(final_arr[1], self.im_test).all()
|
|
33
|
+
# assert np.array(marker_description[0]) == np.array(['test'])
|
|
34
|
+
# assert np.array(marker_description[1]) == np.array(['test'])
|
|
35
|
+
|
|
36
|
+
def test_get_marker_valid(self):
|
|
37
|
+
# Test get_marker with valid parameters
|
|
38
|
+
final_arr, marker_description, times = pynibs.localite.get_marker(self.valid_im_path, 'InstrumentMarker')
|
|
39
|
+
# Assert expected result here
|
|
40
|
+
assert np.isclose(final_arr, self.im_test).all()
|
|
41
|
+
assert np.array(marker_description) == np.array(['test'])
|
|
42
|
+
assert times == []
|
|
43
|
+
|
|
44
|
+
def test_read_triggermarker_localite_valid(self):
|
|
45
|
+
# Test read_triggermarker_localite with valid input
|
|
46
|
+
m_nnav, didt, mso, descr, rec_time = pynibs.localite.read_triggermarker_localite(self.valid_tm_path)
|
|
47
|
+
|
|
48
|
+
assert m_nnav.shape == (4,4,400)
|
|
49
|
+
assert np.isclose(self.self_tm_0, m_nnav[:,:,0]).all()
|
|
50
|
+
|
|
51
|
+
assert len(didt) == 400
|
|
52
|
+
assert (didt[:2] == np.array([1,4])).all()
|
|
53
|
+
|
|
54
|
+
assert len(mso) == 400
|
|
55
|
+
assert (mso[:2] == np.array([3, 6])).all()
|
|
56
|
+
|
|
57
|
+
assert len(descr) == 400
|
|
58
|
+
|
|
59
|
+
assert len(rec_time) == 400
|
|
60
|
+
assert rec_time[:3] == ['475056', '475251', '475450']
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class TestReadTargetsBrainsight(unittest.TestCase):
|
|
64
|
+
def setUp(self):
|
|
65
|
+
# Prepare a valid test file
|
|
66
|
+
self.valid_file = f"{pynibs.__testdatadir__}/brainsight_niiImage_nifticoord.txt"
|
|
67
|
+
self.target0 = np.array([[-9.9700e-01, 5.3000e-02, 5.9000e-02, 1.5020e+01],
|
|
68
|
+
[-5.6000e-02, -9.9700e-01, -4.4000e-02, 5.3062e+01],
|
|
69
|
+
[ 5.6000e-02, -4.8000e-02, 9.9700e-01, 8.7219e+01],
|
|
70
|
+
[ 0.0000e+00, 0.0000e+00, 0.0000e+00, 1.0000e+00]])
|
|
71
|
+
|
|
72
|
+
self.sample0 = np.array([[ 7.1200e-01, 3.2100e-01, -6.2400e-01, -4.4198e+01],
|
|
73
|
+
[ 1.3000e-02, 8.8300e-01, 4.6900e-01, 7.5810e+01],
|
|
74
|
+
[ 7.0200e-01, -3.4200e-01, 6.2400e-01, 6.5742e+01],
|
|
75
|
+
[ 0.0000e+00, 0.0000e+00, 0.0000e+00, 1.0000e+00]])
|
|
76
|
+
|
|
77
|
+
def test_read_targets_brainsight(self):
|
|
78
|
+
# Test reading from a valid file
|
|
79
|
+
result = pynibs.brainsight.read_targets_brainsight(self.valid_file)
|
|
80
|
+
assert len(result) == 4
|
|
81
|
+
assert np.isclose(self.target0, result[:,:,0]).all()
|
|
82
|
+
self.assertEqual(result.shape, (4, 4, 7)) # Expecting one target with a 4x4 matrix
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_get_marker_targets(self):
|
|
86
|
+
# Test reading from a valid file
|
|
87
|
+
matsimnibs, description, timings = pynibs.brainsight.get_marker(self.valid_file, markertype='Targets')
|
|
88
|
+
assert matsimnibs.shape == (7,4,4)
|
|
89
|
+
assert np.isclose(self.target0, matsimnibs[0,:,:]).all()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_get_marker_samples(self):
|
|
93
|
+
# Test reading from a valid file
|
|
94
|
+
matsimnibs, description, timings = pynibs.brainsight.get_marker(self.valid_file, markertype='Samples')
|
|
95
|
+
assert matsimnibs.shape == (101,4,4)
|
|
96
|
+
assert matsimnibs.shape[0] == len(description) == len(timings)
|
|
97
|
+
assert np.isclose(self.sample0, matsimnibs[0,:,:]).all()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == '__main__':
|
|
101
|
+
unittest.main()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import gdist
|
|
2
|
+
import pynibs
|
|
3
|
+
import unittest
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestGeodesicDist(unittest.TestCase):
|
|
8
|
+
"""
|
|
9
|
+
Test pynibs.quality_measures.geodesic_dist()
|
|
10
|
+
"""
|
|
11
|
+
nodes1 = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])
|
|
12
|
+
tris1 = np.array([[0, 1, 2]])
|
|
13
|
+
nodes2 = np.array([[0, 0, 0], [1, 1, 1], [5, 2, 0], [5, 3, 5]])
|
|
14
|
+
tris2 = np.array([[0, 1, 2], [1, 2, 3]])
|
|
15
|
+
source_node = np.array([0])
|
|
16
|
+
source_tri = 1
|
|
17
|
+
source_is_node_node = True
|
|
18
|
+
source_is_node_tri = False
|
|
19
|
+
|
|
20
|
+
def test_geodesic_dist_node(self):
|
|
21
|
+
# Test case 1: source is a node
|
|
22
|
+
nodes_dist, tris_dist = pynibs.geodesic_dist(self.nodes1, self.tris1, self.source_node,
|
|
23
|
+
self.source_is_node_node)
|
|
24
|
+
|
|
25
|
+
assert isinstance(nodes_dist, np.ndarray)
|
|
26
|
+
assert isinstance(tris_dist, np.ndarray)
|
|
27
|
+
assert np.allclose(nodes_dist, [0, np.sqrt(3), 2 * np.sqrt(3)])
|
|
28
|
+
assert np.allclose(tris_dist, [np.sqrt(3)])
|
|
29
|
+
|
|
30
|
+
'''
|
|
31
|
+
# doesn't work yet:
|
|
32
|
+
def test_geodesic_dist_tri(self):
|
|
33
|
+
# Test case 2: source is a triangle
|
|
34
|
+
nodes_dist, tris_dist = pynibs.geodesic_dist(self.nodes2, self.tris2, self.source_tri, self.source_is_node_tri)
|
|
35
|
+
|
|
36
|
+
assert isinstance(nodes_dist, np.ndarray)
|
|
37
|
+
assert isinstance(tris_dist, np.ndarray)
|
|
38
|
+
assert np.allclose(nodes_dist, ?)
|
|
39
|
+
assert np.allclose(tris_dist, ?)
|
|
40
|
+
'''
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TestEuclideanDist(unittest.TestCase):
|
|
44
|
+
"""
|
|
45
|
+
Test pynibs.quality_measures.euclidean_dist()
|
|
46
|
+
"""
|
|
47
|
+
nodes = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]])
|
|
48
|
+
tris = np.array([[0, 1, 2], [1, 2, 3]])
|
|
49
|
+
source_node = np.array([0])
|
|
50
|
+
source_tri = np.array([0])
|
|
51
|
+
source_is_node_node = True
|
|
52
|
+
source_is_node_tri = False
|
|
53
|
+
|
|
54
|
+
def test_euclidean_dist_node(self):
|
|
55
|
+
# Test case 1: source is a node
|
|
56
|
+
nodes_dist, tris_dist = pynibs.euclidean_dist(self.nodes[:-1], self.tris[:-1], self.source_node,
|
|
57
|
+
self.source_is_node_node)
|
|
58
|
+
|
|
59
|
+
assert isinstance(nodes_dist, np.ndarray)
|
|
60
|
+
assert isinstance(tris_dist, np.ndarray)
|
|
61
|
+
assert np.allclose(nodes_dist, [0, np.sqrt(3), 2 * np.sqrt(3)])
|
|
62
|
+
assert np.allclose(tris_dist, [np.sqrt(3)])
|
|
63
|
+
|
|
64
|
+
'''
|
|
65
|
+
doesnt work yet:
|
|
66
|
+
def test_euclidean_dist_tri(self):
|
|
67
|
+
# Test case 2: source is a triangle
|
|
68
|
+
nodes_dist, tris_dist = pynibs.euclidean_dist(self.nodes, self.tris, self.source_tri, self.source_is_node_tri)
|
|
69
|
+
|
|
70
|
+
assert isinstance(nodes_dist, np.ndarray)
|
|
71
|
+
assert isinstance(tris_dist, np.ndarray)
|
|
72
|
+
assert np.allclose(nodes_dist, [0, np.sqrt(3), 2 * np.sqrt(3), 3 * np.sqrt(3)])
|
|
73
|
+
assert np.allclose(tris_dist, [0, np.sqrt(3)])
|
|
74
|
+
'''
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class TestIntersectionVecPlan(unittest.TestCase):
|
|
78
|
+
|
|
79
|
+
def test_direct_intersection(self):
|
|
80
|
+
ray_dir = np.array([0, 0, -1])
|
|
81
|
+
ray_origin = np.array([0, 0, 10])
|
|
82
|
+
plane_n = np.array([0, 0, 1])
|
|
83
|
+
plane_p = np.array([0, 0, 0])
|
|
84
|
+
expected_intersection = np.array([0, 0, 0])
|
|
85
|
+
intersec = pynibs.intersection_vec_plan(ray_dir, ray_origin, plane_n, plane_p)
|
|
86
|
+
np.testing.assert_array_almost_equal(intersec, expected_intersection)
|
|
87
|
+
|
|
88
|
+
def test_parallel_no_intersection(self):
|
|
89
|
+
ray_dir = np.array([0, 1, 0])
|
|
90
|
+
ray_origin = np.array([0, 0, 10])
|
|
91
|
+
plane_n = np.array([0, 0, 1])
|
|
92
|
+
plane_p = np.array([0, 0, 0])
|
|
93
|
+
intersec = pynibs.intersection_vec_plan(ray_dir, ray_origin, plane_n, plane_p)
|
|
94
|
+
assert (intersec == [np.inf, np.inf, np.inf]).all()
|
|
95
|
+
|
|
96
|
+
def test_origin_within_plane(self):
|
|
97
|
+
ray_dir = np.array([0, 0, 1])
|
|
98
|
+
ray_origin = np.array([0, 0, 0])
|
|
99
|
+
plane_n = np.array([0, 0, 1])
|
|
100
|
+
plane_p = np.array([0, 0, 0])
|
|
101
|
+
expected_intersection = np.array([0, 0, 0])
|
|
102
|
+
intersec = pynibs.intersection_vec_plan(ray_dir, ray_origin, plane_n, plane_p)
|
|
103
|
+
np.testing.assert_array_almost_equal(intersec, expected_intersection)
|
|
104
|
+
|
|
105
|
+
def test_edge_case_near_parallel(self):
|
|
106
|
+
ray_dir = np.array([0.001, 0.001, -1])
|
|
107
|
+
ray_origin = np.array([0, 0, 10])
|
|
108
|
+
plane_n = np.array([0, 0, 1])
|
|
109
|
+
plane_p = np.array([0, 0, 0])
|
|
110
|
+
# Expected intersection is approximate due to near parallel direction
|
|
111
|
+
expected_intersection = np.array([0.01, 0.01, 0])
|
|
112
|
+
intersec = pynibs.intersection_vec_plan(ray_dir, ray_origin, plane_n, plane_p)
|
|
113
|
+
np.testing.assert_array_almost_equal(intersec, expected_intersection, decimal=2)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == '__main__':
|
|
117
|
+
unittest.main()
|