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.
Files changed (107) hide show
  1. pyNIBS-0.2024.8.dist-info/LICENSE +623 -0
  2. pyNIBS-0.2024.8.dist-info/METADATA +723 -0
  3. pyNIBS-0.2024.8.dist-info/RECORD +107 -0
  4. pyNIBS-0.2024.8.dist-info/WHEEL +5 -0
  5. pyNIBS-0.2024.8.dist-info/top_level.txt +1 -0
  6. pynibs/__init__.py +34 -0
  7. pynibs/coil.py +1367 -0
  8. pynibs/congruence/__init__.py +15 -0
  9. pynibs/congruence/congruence.py +1108 -0
  10. pynibs/congruence/ext_metrics.py +257 -0
  11. pynibs/congruence/stimulation_threshold.py +318 -0
  12. pynibs/data/configuration_exp0.yaml +59 -0
  13. pynibs/data/configuration_linear_MEP.yaml +61 -0
  14. pynibs/data/configuration_linear_RT.yaml +61 -0
  15. pynibs/data/configuration_sigmoid4.yaml +68 -0
  16. pynibs/data/network mapping configuration/configuration guide.md +238 -0
  17. pynibs/data/network mapping configuration/configuration_TEMPLATE.yaml +42 -0
  18. pynibs/data/network mapping configuration/configuration_for_testing.yaml +43 -0
  19. pynibs/data/network mapping configuration/configuration_modelTMS.yaml +43 -0
  20. pynibs/data/network mapping configuration/configuration_reg_isi_05.yaml +43 -0
  21. pynibs/data/network mapping configuration/output_documentation.md +185 -0
  22. pynibs/data/network mapping configuration/recommendations_for_accuracy_threshold.md +77 -0
  23. pynibs/data/neuron/models/L23_PC_cADpyr_biphasic_v1.csv +1281 -0
  24. pynibs/data/neuron/models/L23_PC_cADpyr_monophasic_v1.csv +1281 -0
  25. pynibs/data/neuron/models/L4_LBC_biphasic_v1.csv +1281 -0
  26. pynibs/data/neuron/models/L4_LBC_monophasic_v1.csv +1281 -0
  27. pynibs/data/neuron/models/L4_NBC_biphasic_v1.csv +1281 -0
  28. pynibs/data/neuron/models/L4_NBC_monophasic_v1.csv +1281 -0
  29. pynibs/data/neuron/models/L4_SBC_biphasic_v1.csv +1281 -0
  30. pynibs/data/neuron/models/L4_SBC_monophasic_v1.csv +1281 -0
  31. pynibs/data/neuron/models/L5_TTPC2_cADpyr_biphasic_v1.csv +1281 -0
  32. pynibs/data/neuron/models/L5_TTPC2_cADpyr_monophasic_v1.csv +1281 -0
  33. pynibs/expio/Mep.py +1518 -0
  34. pynibs/expio/__init__.py +8 -0
  35. pynibs/expio/brainsight.py +979 -0
  36. pynibs/expio/brainvis.py +71 -0
  37. pynibs/expio/cobot.py +239 -0
  38. pynibs/expio/exp.py +1876 -0
  39. pynibs/expio/fit_funs.py +287 -0
  40. pynibs/expio/localite.py +1987 -0
  41. pynibs/expio/signal_ced.py +51 -0
  42. pynibs/expio/visor.py +624 -0
  43. pynibs/freesurfer.py +502 -0
  44. pynibs/hdf5_io/__init__.py +10 -0
  45. pynibs/hdf5_io/hdf5_io.py +1857 -0
  46. pynibs/hdf5_io/xdmf.py +1542 -0
  47. pynibs/mesh/__init__.py +3 -0
  48. pynibs/mesh/mesh_struct.py +1394 -0
  49. pynibs/mesh/transformations.py +866 -0
  50. pynibs/mesh/utils.py +1103 -0
  51. pynibs/models/_TMS.py +211 -0
  52. pynibs/models/__init__.py +0 -0
  53. pynibs/muap.py +392 -0
  54. pynibs/neuron/__init__.py +2 -0
  55. pynibs/neuron/neuron_regression.py +284 -0
  56. pynibs/neuron/util.py +58 -0
  57. pynibs/optimization/__init__.py +5 -0
  58. pynibs/optimization/multichannel.py +278 -0
  59. pynibs/optimization/opt_mep.py +152 -0
  60. pynibs/optimization/optimization.py +1445 -0
  61. pynibs/optimization/workhorses.py +698 -0
  62. pynibs/pckg/__init__.py +0 -0
  63. pynibs/pckg/biosig/biosig4c++-1.9.5.src_fixed.tar.gz +0 -0
  64. pynibs/pckg/libeep/__init__.py +0 -0
  65. pynibs/pckg/libeep/pyeep.so +0 -0
  66. pynibs/regression/__init__.py +11 -0
  67. pynibs/regression/dual_node_detection.py +2375 -0
  68. pynibs/regression/regression.py +2984 -0
  69. pynibs/regression/score_types.py +0 -0
  70. pynibs/roi/__init__.py +2 -0
  71. pynibs/roi/roi.py +895 -0
  72. pynibs/roi/roi_structs.py +1233 -0
  73. pynibs/subject.py +1009 -0
  74. pynibs/tensor_scaling.py +144 -0
  75. pynibs/tests/data/InstrumentMarker20200225163611937.xml +19 -0
  76. pynibs/tests/data/TriggerMarkers_Coil0_20200225163443682.xml +14 -0
  77. pynibs/tests/data/TriggerMarkers_Coil1_20200225170337572.xml +6373 -0
  78. pynibs/tests/data/Xdmf.dtd +89 -0
  79. pynibs/tests/data/brainsight_niiImage_nifticoord.txt +145 -0
  80. pynibs/tests/data/brainsight_niiImage_nifticoord_largefile.txt +1434 -0
  81. pynibs/tests/data/brainsight_niiImage_niifticoord_mixedtargets.txt +47 -0
  82. pynibs/tests/data/create_subject_testsub.py +332 -0
  83. pynibs/tests/data/data.hdf5 +0 -0
  84. pynibs/tests/data/geo.hdf5 +0 -0
  85. pynibs/tests/test_coil.py +474 -0
  86. pynibs/tests/test_elements2nodes.py +100 -0
  87. pynibs/tests/test_hdf5_io/test_xdmf.py +61 -0
  88. pynibs/tests/test_mesh_transformations.py +123 -0
  89. pynibs/tests/test_mesh_utils.py +143 -0
  90. pynibs/tests/test_nnav_imports.py +101 -0
  91. pynibs/tests/test_quality_measures.py +117 -0
  92. pynibs/tests/test_regressdata.py +289 -0
  93. pynibs/tests/test_roi.py +17 -0
  94. pynibs/tests/test_rotations.py +86 -0
  95. pynibs/tests/test_subject.py +71 -0
  96. pynibs/tests/test_util.py +24 -0
  97. pynibs/tms_pulse.py +34 -0
  98. pynibs/util/__init__.py +4 -0
  99. pynibs/util/dosing.py +233 -0
  100. pynibs/util/quality_measures.py +562 -0
  101. pynibs/util/rotations.py +340 -0
  102. pynibs/util/simnibs.py +763 -0
  103. pynibs/util/util.py +727 -0
  104. pynibs/visualization/__init__.py +2 -0
  105. pynibs/visualization/para.py +4372 -0
  106. pynibs/visualization/plot_2D.py +137 -0
  107. pynibs/visualization/render_3D.py +347 -0
@@ -0,0 +1,474 @@
1
+ import os
2
+ import h5py
3
+ import pynibs
4
+ import unittest
5
+ import tempfile
6
+ import numpy as np
7
+ from xml.sax import make_parser
8
+ from xml.sax.handler import ContentHandler
9
+ try:
10
+ import simnibs
11
+ except ImportError:
12
+ raise unittest.SkipTest("Cannot import SimNIBS - skipping test_coil.py")
13
+
14
+
15
+ def check_xml(xml_fn):
16
+ """Check well-formedness of xml"""
17
+ parser = make_parser()
18
+ parser.setContentHandler(ContentHandler())
19
+ parser.parse(xml_fn)
20
+
21
+
22
+ class TestCreateStimsiteFromTmslist(unittest.TestCase):
23
+ """
24
+ Test pynibs.coil.create_stimsite_from_tmslist()
25
+ """
26
+ folder = tempfile.TemporaryDirectory()
27
+ pos1 = np.array(([11, 12, 13, 14],
28
+ [21, 22, 23, 24],
29
+ [31, 32, 33, 34],
30
+ [41, 42, 43, 44]))
31
+ pos1 = pos1.transpose()
32
+ pos2 = np.array(([110, 120, 130, 140],
33
+ [210, 220, 230, 240],
34
+ [310, 320, 330, 340],
35
+ [410, 420, 430, 440]))
36
+ pos2 = pos2.transpose()
37
+
38
+ def test_create_stimsite_from_tmslist1_pos(self):
39
+ with tempfile.TemporaryDirectory() as folder:
40
+ pos1 = simnibs.sim_struct.POSITION()
41
+ pos1.matsimnibs = self.pos1
42
+ tmslist = simnibs.sim_struct.TMSLIST()
43
+ tmslist.add_position(pos1)
44
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
45
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=None, data=None, overwrite=False)
46
+ assert os.path.exists(fn_hdf)
47
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
48
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
49
+ with h5py.File(fn_hdf, 'r')as h:
50
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
51
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
52
+ if k != 'matsimnibs':
53
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
54
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
55
+
56
+ def test_create_stimsite_from_tmslist1_overwrite(self):
57
+ with tempfile.TemporaryDirectory() as folder:
58
+ pos1 = simnibs.sim_struct.POSITION()
59
+ pos1.matsimnibs = self.pos1
60
+ tmslist = simnibs.sim_struct.TMSLIST()
61
+ tmslist.add_position(pos1)
62
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
63
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=None, data=None, overwrite=False)
64
+ assert os.path.exists(fn_hdf)
65
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
66
+
67
+ # raise error if overwrite=False
68
+ with self.assertRaises(OSError):
69
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=None, data=None, overwrite=False)
70
+
71
+ # let's write a different file to make sure the correct one is written
72
+ pos2 = simnibs.sim_struct.POSITION()
73
+ pos2.matsimnibs = self.pos2
74
+ tmslist = simnibs.sim_struct.TMSLIST()
75
+ tmslist.add_position(pos2)
76
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=None, data=None, overwrite=True)
77
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
78
+ with h5py.File(fn_hdf, 'r')as h:
79
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
80
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
81
+ if k != 'matsimnibs':
82
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
83
+ assert (h[k][:] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
84
+
85
+ def test_create_stimsite_from_tmslist_2pos(self):
86
+ with tempfile.TemporaryDirectory() as folder:
87
+ pos1 = simnibs.sim_struct.POSITION()
88
+ pos1.matsimnibs = self.pos1
89
+ pos2 = simnibs.sim_struct.POSITION()
90
+ pos2.matsimnibs = self.pos2
91
+ tmslist = simnibs.sim_struct.TMSLIST()
92
+ tmslist.add_position(pos1)
93
+ tmslist.add_position(pos2)
94
+
95
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
96
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=None, data=None, overwrite=False)
97
+
98
+ assert os.path.exists(fn_hdf)
99
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
100
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
101
+ with h5py.File(fn_hdf, 'r')as h:
102
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
103
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
104
+ if k != 'matsimnibs':
105
+ assert h[k][:].shape == (2, 3), f"Wrong shape for {k}: {h[k][:].shape}"
106
+ assert (h[k][:][0, :] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
107
+ assert (h[k][:][1, :] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
108
+
109
+ def test_create_stimsite_from_tmslist1_datanames(self):
110
+ with tempfile.TemporaryDirectory() as folder:
111
+ pos1 = simnibs.sim_struct.POSITION()
112
+ pos1.matsimnibs = self.pos1
113
+ tmslist = simnibs.sim_struct.TMSLIST()
114
+ tmslist.add_position(pos1)
115
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
116
+ datanames = 'somedata'
117
+ data = np.array(1)
118
+ with self.assertRaises(AssertionError):
119
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=['1', '2'], data=data,
120
+ overwrite=False)
121
+ with self.assertRaises(ValueError):
122
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=None, data=data, overwrite=False)
123
+ with self.assertRaises(ValueError):
124
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=datanames, data=None, overwrite=False)
125
+
126
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=datanames, data=data, overwrite=False)
127
+ assert os.path.exists(fn_hdf)
128
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
129
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
130
+ with h5py.File(fn_hdf, 'r')as h:
131
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs', 'data']):
132
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
133
+ if k == 'data':
134
+ assert h[f"{k}/somedata"][:] == np.array([1])
135
+ elif k != 'matsimnibs':
136
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
137
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
138
+
139
+ datanames = ['somedata']
140
+ data = 1
141
+ with self.assertRaises(AssertionError):
142
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=datanames, data=data, overwrite=True)
143
+ data = np.array(1)
144
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=datanames, data=data, overwrite=True)
145
+ assert os.path.exists(fn_hdf)
146
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
147
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
148
+ with h5py.File(fn_hdf, 'r')as h:
149
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs', 'data']):
150
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
151
+ if k == 'data':
152
+ assert h[f"{k}/somedata"][:] == np.array([1])
153
+ elif k != 'matsimnibs':
154
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
155
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
156
+
157
+ def test_create_stimsite_from_tmslist_2pos_2datanames(self):
158
+ with tempfile.TemporaryDirectory() as folder:
159
+ pos1 = simnibs.sim_struct.POSITION()
160
+ pos1.matsimnibs = self.pos1
161
+ pos2 = simnibs.sim_struct.POSITION()
162
+ pos2.matsimnibs = self.pos2
163
+ tmslist = simnibs.sim_struct.TMSLIST()
164
+ tmslist.add_position(pos1)
165
+ tmslist.add_position(pos2)
166
+ datanames = ['somedata1', 'somedata2']
167
+ data = np.array(([1, 2], [3, 4])).transpose()
168
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
169
+ pynibs.create_stimsite_from_tmslist(fn_hdf, tmslist, datanames=datanames, data=data, overwrite=False)
170
+
171
+ assert os.path.exists(fn_hdf)
172
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
173
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
174
+ with h5py.File(fn_hdf, 'r')as h:
175
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs','data']):
176
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
177
+ if k == 'data':
178
+ h[k].keys()
179
+ assert (h[f"{k}/somedata1"][:] == np.array([1,2])).all()
180
+ assert (h[f"{k}/somedata2"][:] == np.array([3,4])).all()
181
+ elif k != 'matsimnibs':
182
+ assert h[k][:].shape == (2, 3), f"Wrong shape for {k}: {h[k][:].shape}"
183
+ assert (h[k][:][0, :] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
184
+ assert (h[k][:][1, :] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
185
+
186
+
187
+ class TestCreateStimsiteFromMatsimnibs(unittest.TestCase):
188
+ """
189
+ Test pynibs.coil.create_stimsite_from_matsimnibs()
190
+ """
191
+ folder = tempfile.TemporaryDirectory()
192
+ pos1 = np.array(([11, 12, 13, 14],
193
+ [21, 22, 23, 24],
194
+ [31, 32, 33, 34],
195
+ [41, 42, 43, 44]))
196
+ pos1 = pos1.transpose()
197
+ pos2 = np.array(([110, 120, 130, 140],
198
+ [210, 220, 230, 240],
199
+ [310, 320, 330, 340],
200
+ [410, 420, 430, 440]))
201
+ pos2 = pos2.transpose()
202
+
203
+ def test_create_stimsite_from_matsimnibs_1pos(self):
204
+ with tempfile.TemporaryDirectory() as folder:
205
+ pos1 = simnibs.sim_struct.POSITION()
206
+ pos1.matsimnibs = self.pos1
207
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
208
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=None, data=None, overwrite=False)
209
+ assert os.path.exists(fn_hdf)
210
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
211
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
212
+ with h5py.File(fn_hdf, 'r')as h:
213
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
214
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
215
+ if k != 'matsimnibs':
216
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
217
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
218
+
219
+ def test_create_stimsite_from_matsimnibs_overwrite(self):
220
+ with tempfile.TemporaryDirectory() as folder:
221
+
222
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
223
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=None, data=None, overwrite=False)
224
+ assert os.path.exists(fn_hdf)
225
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
226
+
227
+ # raise error if overwrite=False
228
+ with self.assertRaises(OSError):
229
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=None, data=None, overwrite=False)
230
+
231
+ # let's write a different file to make sure the correct one is written
232
+
233
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos2, datanames=None, data=None, overwrite=True)
234
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
235
+ with h5py.File(fn_hdf, 'r')as h:
236
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
237
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
238
+ if k != 'matsimnibs':
239
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
240
+ assert (h[k][:] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
241
+
242
+ def test_create_stimsite_from_matsimnibs_2pos(self):
243
+ with tempfile.TemporaryDirectory() as folder:
244
+
245
+ matsimnibs = np.dstack((self.pos1, self.pos2))
246
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
247
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, matsimnibs, datanames=None, data=None, overwrite=False)
248
+
249
+ assert os.path.exists(fn_hdf)
250
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
251
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
252
+ with h5py.File(fn_hdf, 'r')as h:
253
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
254
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
255
+ if k != 'matsimnibs':
256
+ assert h[k][:].shape == (2, 3), f"Wrong shape for {k}: {h[k][:].shape}"
257
+ assert (h[k][:][0, :] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
258
+ assert (h[k][:][1, :] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
259
+
260
+ def test_create_stimsite_from_matsimnibs_datanames(self):
261
+ with tempfile.TemporaryDirectory() as folder:
262
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
263
+ datanames = 'somedata'
264
+ data = np.array(1)
265
+ with self.assertRaises(AssertionError):
266
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=['1', '2'], data=data,
267
+ overwrite=False)
268
+ with self.assertRaises(ValueError):
269
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=None, data=data, overwrite=False)
270
+ with self.assertRaises(ValueError):
271
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=datanames, data=None, overwrite=False)
272
+
273
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=datanames, data=data, overwrite=False)
274
+ assert os.path.exists(fn_hdf)
275
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
276
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
277
+ with h5py.File(fn_hdf, 'r')as h:
278
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs', 'data']):
279
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
280
+ if k == 'data':
281
+ assert h[f"{k}/somedata"][:] == np.array([1])
282
+ elif k != 'matsimnibs':
283
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
284
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
285
+
286
+ datanames = ['somedata']
287
+ data = 1
288
+
289
+ with self.assertRaises(AssertionError):
290
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=datanames, data=data, overwrite=True)
291
+
292
+ data = np.array(1)
293
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, self.pos1, datanames=datanames, data=data, overwrite=True)
294
+
295
+ assert os.path.exists(fn_hdf)
296
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
297
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
298
+ with h5py.File(fn_hdf, 'r')as h:
299
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs', 'data']):
300
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
301
+ if k == 'data':
302
+ assert h[f"{k}/somedata"][:] == np.array([1])
303
+ elif k != 'matsimnibs':
304
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
305
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
306
+
307
+ def test_create_stimsite_from_matsimnibs_2pos_2datanames(self):
308
+ with tempfile.TemporaryDirectory() as folder:
309
+ matsimnibs = np.dstack((self.pos1, self.pos2))
310
+ datanames = ['somedata1', 'somedata2']
311
+ data = np.array(([1, 2], [3, 4])).transpose()
312
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
313
+ pynibs.create_stimsite_from_matsimnibs(fn_hdf, matsimnibs, datanames=datanames, data=data, overwrite=False)
314
+
315
+ assert os.path.exists(fn_hdf)
316
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
317
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
318
+ with h5py.File(fn_hdf, 'r')as h:
319
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs','data']):
320
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
321
+ if k == 'data':
322
+ h[k].keys()
323
+ assert (h[f"{k}/somedata1"][:] == np.array([1,2])).all()
324
+ assert (h[f"{k}/somedata2"][:] == np.array([3,4])).all()
325
+ elif k != 'matsimnibs':
326
+ assert h[k][:].shape == (2, 3), f"Wrong shape for {k}: {h[k][:].shape}"
327
+ assert (h[k][:][0, :] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
328
+ assert (h[k][:][1, :] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
329
+
330
+
331
+ class TestCreateStimsiteFromList(unittest.TestCase):
332
+ """
333
+ Test pynibs.coil.create_stimsite_from_list()
334
+ """
335
+ folder = tempfile.TemporaryDirectory()
336
+ pos1 = np.array(([11, 12, 13, 14],
337
+ [21, 22, 23, 24],
338
+ [31, 32, 33, 34],
339
+ [41, 42, 43, 44]))
340
+ pos1 = pos1.transpose()
341
+ pos2 = np.array(([110, 120, 130, 140],
342
+ [210, 220, 230, 240],
343
+ [310, 320, 330, 340],
344
+ [410, 420, 430, 440]))
345
+ pos2 = pos2.transpose()
346
+
347
+ def test_create_stimsite_from_list_1pos(self):
348
+ with tempfile.TemporaryDirectory() as folder:
349
+ pos1 = simnibs.sim_struct.POSITION()
350
+ pos1.matsimnibs = self.pos1
351
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
352
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=None, data=None, overwrite=False)
353
+ assert os.path.exists(fn_hdf)
354
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
355
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
356
+ with h5py.File(fn_hdf, 'r')as h:
357
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
358
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
359
+ if k != 'matsimnibs':
360
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
361
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
362
+
363
+ def test_create_stimsite_from_list_overwrite(self):
364
+ with tempfile.TemporaryDirectory() as folder:
365
+
366
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
367
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=None, data=None, overwrite=False)
368
+ assert os.path.exists(fn_hdf)
369
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
370
+
371
+ # raise error if overwrite=False
372
+ with self.assertRaises(OSError):
373
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=None, data=None, overwrite=False)
374
+
375
+ # let's write a different file to make sure the correct one is written
376
+
377
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos2], datanames=None, data=None, overwrite=True)
378
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
379
+ with h5py.File(fn_hdf, 'r')as h:
380
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
381
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
382
+ if k != 'matsimnibs':
383
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
384
+ assert (h[k][:] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
385
+
386
+ def test_create_stimsite_from_list_2pos(self):
387
+ with tempfile.TemporaryDirectory() as folder:
388
+
389
+ matsimnibs = [self.pos1, self.pos2]
390
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
391
+ pynibs.create_stimsite_from_list(fn_hdf, matsimnibs, datanames=None, data=None, overwrite=False)
392
+
393
+ assert os.path.exists(fn_hdf)
394
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
395
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
396
+ with h5py.File(fn_hdf, 'r')as h:
397
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs']):
398
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
399
+ if k != 'matsimnibs':
400
+ assert h[k][:].shape == (2, 3), f"Wrong shape for {k}: {h[k][:].shape}"
401
+ assert (h[k][:][0, :] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
402
+ assert (h[k][:][1, :] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
403
+
404
+ def test_create_stimsite_from_list_datanames(self):
405
+ with tempfile.TemporaryDirectory() as folder:
406
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
407
+ datanames = 'somedata'
408
+ data = np.array(1)
409
+ with self.assertRaises(AssertionError):
410
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=['1', '2'], data=data,
411
+ overwrite=False)
412
+ with self.assertRaises(ValueError):
413
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=None, data=data, overwrite=False)
414
+ with self.assertRaises(ValueError):
415
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=datanames, data=None, overwrite=False)
416
+
417
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=datanames, data=data, overwrite=False)
418
+ assert os.path.exists(fn_hdf)
419
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
420
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
421
+ with h5py.File(fn_hdf, 'r')as h:
422
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs', 'data']):
423
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
424
+ if k == 'data':
425
+ assert h[f"{k}/somedata"][:] == np.array([1])
426
+ elif k != 'matsimnibs':
427
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
428
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
429
+
430
+ datanames = ['somedata']
431
+ data = 1
432
+
433
+ with self.assertRaises(AssertionError):
434
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=datanames, data=data, overwrite=True)
435
+ data = np.array(1)
436
+ pynibs.create_stimsite_from_list(fn_hdf, [self.pos1], datanames=datanames, data=data, overwrite=True)
437
+ assert os.path.exists(fn_hdf)
438
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
439
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
440
+ with h5py.File(fn_hdf, 'r')as h:
441
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs', 'data']):
442
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
443
+ if k == 'data':
444
+ assert h[f"{k}/somedata"][:] == np.array([1])
445
+ elif k != 'matsimnibs':
446
+ assert h[k][:].shape == (1, 3), f"Wrong shape for {k}: {h[k][:].shape}"
447
+ assert (h[k][:] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
448
+
449
+ def test_create_stimsite_from_list_2pos_2datanames(self):
450
+ with tempfile.TemporaryDirectory() as folder:
451
+ matsimnibs = [self.pos1, self.pos2]
452
+ datanames = ['somedata1', 'somedata2']
453
+ data = np.array(([1, 2], [3, 4])).transpose()
454
+ fn_hdf = os.path.join(folder, "stimsite_from_list.hdf5")
455
+ pynibs.create_stimsite_from_list(fn_hdf, matsimnibs, datanames=datanames, data=data, overwrite=False)
456
+
457
+ assert os.path.exists(fn_hdf)
458
+ assert os.path.exists(fn_hdf.replace('.hdf5', '.xdmf'))
459
+ check_xml(fn_hdf.replace('.hdf5', '.xdmf'))
460
+ with h5py.File(fn_hdf, 'r')as h:
461
+ for idx, k in enumerate(['m0', 'm1', 'm2', 'centers', 'matsimnibs','data']):
462
+ assert k in h.keys(), f"{k} missing in {fn_hdf}"
463
+ if k == 'data':
464
+ h[k].keys()
465
+ assert (h[f"{k}/somedata1"][:] == np.array([1,2])).all()
466
+ assert (h[f"{k}/somedata2"][:] == np.array([3,4])).all()
467
+ elif k != 'matsimnibs':
468
+ assert h[k][:].shape == (2, 3), f"Wrong shape for {k}: {h[k][:].shape}"
469
+ assert (h[k][:][0, :] == self.pos1[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
470
+ assert (h[k][:][1, :] == self.pos2[:3, idx]).all(), f"Wrong values for {k}: {h[k][:]}"
471
+
472
+
473
+ if __name__ == '__main__':
474
+ unittest.main()
@@ -0,0 +1,100 @@
1
+ import warnings
2
+ import pynibs
3
+ import numpy as np
4
+ import unittest
5
+
6
+
7
+ class TestDataElements2Nodes(unittest.TestCase):
8
+ """
9
+ Test pynibs.data_elements2nodes()
10
+ """
11
+ np.random.seed(1)
12
+ n_elm_small = 100
13
+ n_elm_large = 100000
14
+ con_small_tri = np.random.choice(n_elm_small, n_elm_small * 3)
15
+ con_small_tri = np.reshape(con_small_tri, (n_elm_small, 3))
16
+ con_small_tet = np.random.choice(n_elm_small, n_elm_small * 4)
17
+ con_small_tet = np.reshape(con_small_tet, (n_elm_small, 4))
18
+
19
+ data_small = np.random.rand(n_elm_small) * 1000
20
+ data_small_zero = np.zeros(n_elm_small)
21
+ data_small_nan = data_small.copy()
22
+ data_small_nan[np.random.choice(n_elm_small,20,replace=False)] = np.nan
23
+ datas_small = [np.random.rand(n_elm_small), np.random.rand(n_elm_small), np.random.rand(n_elm_small)]
24
+
25
+ data_large = np.random.rand(n_elm_large) * 1000
26
+ con_large_tri = np.random.choice(n_elm_large, n_elm_large * 3)
27
+ con_large_tri = np.reshape(con_large_tri, (n_elm_large, 3))
28
+
29
+ ret_small_tri = np.array([[3.81717394e+03, -3.44380754e+03, -1.04068361e+02,
30
+ -3.03672180e+03, 1.69162931e-11, 3.28735690e+02,
31
+ -1.90366377e+03, -1.75718804e+03, -1.01526253e+03,
32
+ 1.04089987e+03, 2.77992727e+03, 1.09061487e+04,
33
+ 5.38944819e+03, -3.79793187e+02, 9.39673305e+02,
34
+ 1.98831328e+03, 1.58734484e+03, -1.13042037e+03,
35
+ -2.09536935e+03, 2.26513015e+03, 4.73078124e+03,
36
+ 3.39876074e+03, -7.55140605e+02, -2.97782279e+02,
37
+ -1.40251390e+03, 2.05253645e+03, -5.02309550e+02,
38
+ 2.96740726e+03, -3.00838583e+03, -5.50986205e+03,
39
+ 1.48806206e+03, 4.16278309e+03, 2.62938829e+03,
40
+ 1.93231842e+02, -4.61159330e+03, 2.59423044e+02,
41
+ -4.60235252e+03, -7.24318305e+03, 2.66801622e+03,
42
+ 5.76236046e+03, 2.97453723e+03, 3.08128171e+02,
43
+ 5.27098593e+02, 1.15281629e+03, -1.54514947e+03,
44
+ 3.34553994e+03, 3.41534538e+03, -1.55617593e+03,
45
+ -4.47155698e+03, 1.36873183e+02, 2.63697251e+03,
46
+ 1.90110815e-11, 1.91430775e+03, -2.15570486e+02,
47
+ 3.79785433e+03, 6.35365607e+03, -7.24051657e+02,
48
+ 5.20753754e+03, 3.19122804e-12, -5.82332417e+02,
49
+ 2.01945775e+03, -2.75572686e+03, -1.19368661e+03,
50
+ 1.65623497e+03, 1.09343732e+03, -6.13390936e+03,
51
+ 1.14957878e+03, 1.37436400e+03, -7.85602469e+02,
52
+ -2.49699644e+03, -6.00553990e+02, 3.23686455e+03,
53
+ 3.70927556e+03, 2.29986338e-13, 5.10659728e+02,
54
+ -1.22064351e+03, 5.40601193e+02, 1.08103027e+03,
55
+ -2.15922656e+03, -8.83769660e+02, -8.91707692e+02,
56
+ 4.99875852e+03, -2.02433759e+03, 9.20401644e+02,
57
+ 8.07942131e+01, 2.80601545e+03, 1.49195685e+03,
58
+ -2.74571524e+02, -1.13395172e+03, -1.41719240e+02,
59
+ -3.90122898e-14, -1.84344533e+02, -3.97735225e+03,
60
+ 1.93231842e+02, 4.02650694e+02, 0.00000000e+00,
61
+ -6.16506432e+02, 2.20263338e+03, 2.65351685e+03,
62
+ 1.54040912e+03]])
63
+
64
+ def test_e2n_single_data_tri(self):
65
+ ret = pynibs.data_elements2nodes(self.data_small, self.con_small_tri)
66
+ assert ret.shape == (1, self.n_elm_small)
67
+ assert np.all(np.isclose(ret, self.ret_small_tri))
68
+
69
+ def test_e2n_single_data_tri_zero(self):
70
+ ret = pynibs.data_elements2nodes(self.data_small_zero, self.con_small_tri, precise=True)
71
+
72
+ assert ret.shape == (1, self.n_elm_small)
73
+ assert np.nanmax(ret[0]) == 0
74
+ assert np.isnan(ret[0][4])
75
+
76
+ def test_e2n_single_data_tri_nan(self):
77
+ ret = pynibs.data_elements2nodes(self.data_small_nan, self.con_small_tri)
78
+ assert ret.shape == (1, self.n_elm_small)
79
+
80
+ def test_e2n_single_data_tet(self):
81
+ ret = pynibs.data_elements2nodes(self.data_small, self.con_small_tet)
82
+ assert ret.shape == (1, self.n_elm_small)
83
+
84
+ def test_e2n_mult_data(self):
85
+ ret = pynibs.data_elements2nodes(self.datas_small, self.con_small_tri)
86
+ assert len(ret) == 3
87
+ assert ret[0].shape == (self.n_elm_small,)
88
+
89
+ '''
90
+ def test_e2n_single_data_tri_large(self):
91
+ """
92
+ This tests for the OOM catch. Results are not checked, due to long compuation time.
93
+ """
94
+ warnings.filterwarnings("error", "Cannot allocate enough RAM")
95
+ with self.assertRaises(Exception):
96
+ pynibs.data_elements2nodes(self.data_large, self.con_large_tri)
97
+ '''
98
+
99
+ if __name__ == '__main__':
100
+ unittest.main()
@@ -0,0 +1,61 @@
1
+ import os
2
+ import shutil
3
+ import tempfile
4
+
5
+ import pynibs
6
+ import unittest
7
+ from xml.sax import make_parser
8
+ from xml.sax.handler import ContentHandler
9
+
10
+
11
+ def check_xml(xml_fn):
12
+ """Check well-formedness of xml"""
13
+ parser = make_parser()
14
+ parser.setContentHandler(ContentHandler())
15
+ parser.parse(xml_fn)
16
+
17
+
18
+ class TestWriteXdmf(unittest.TestCase):
19
+ """This tests pynibs.write_xdmf()"""
20
+
21
+ data_fn = os.path.join(pynibs.__testdatadir__, "data.hdf5")
22
+ geo_fn = os.path.join(pynibs.__testdatadir__, "geo.hdf5")
23
+ xml_scheme_fn = os.path.join(pynibs.__testdatadir__, "vtk-unstructured.xsd")
24
+ xdmf_geo_fn = os.path.join(pynibs.__testdatadir__, "geo.xdmf")
25
+ xdmf_data_fn = os.path.join(pynibs.__testdatadir__, "data.xdmf")
26
+
27
+ for fn in [xdmf_geo_fn, xdmf_data_fn]:
28
+ try:
29
+ os.remove(fn)
30
+ except OSError:
31
+ pass
32
+
33
+ def test_1_write_geo_only(self):
34
+ with tempfile.TemporaryDirectory() as tempdir:
35
+ geo_fn = shutil.copy(self.geo_fn, tempdir)
36
+ fn_xml = pynibs.write_xdmf(geo_fn)
37
+ check_xml(fn_xml)
38
+
39
+ def test_2_write_xdmf_exists(self):
40
+ with tempfile.TemporaryDirectory() as tempdir:
41
+ geo_fn = shutil.copy(self.geo_fn, tempdir)
42
+ pynibs.write_xdmf(geo_fn)
43
+ self.assertRaises(FileExistsError, pynibs.write_xdmf, geo_fn)
44
+
45
+ def test_3_write_xdmf_overwrite(self):
46
+ with tempfile.TemporaryDirectory() as tempdir:
47
+ geo_fn = shutil.copy(self.geo_fn, tempdir)
48
+ pynibs.write_xdmf(geo_fn)
49
+ pynibs.write_xdmf(geo_fn, overwrite_xdmf=True)
50
+
51
+ def test_4_write_datageo(self):
52
+ with tempfile.TemporaryDirectory() as tempdir:
53
+ geo_fn = shutil.copy(self.geo_fn, tempdir)
54
+ data_fn = shutil.copy(self.data_fn, tempdir)
55
+ pynibs.write_xdmf(geo_fn)
56
+ xdmf_data_fn = pynibs.write_xdmf(data_fn, geo_fn, overwrite_xdmf=True)
57
+ check_xml(xdmf_data_fn)
58
+
59
+
60
+ if __name__ == '__main__':
61
+ unittest.main()