Skip to content

Commit 77195a2

Browse files
BUG: Fix bug with reading dig strings (mne-tools#13083)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent cf5ef5f commit 77195a2

File tree

6 files changed

+36
-31
lines changed

6 files changed

+36
-31
lines changed

doc/changes/devel/13083.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix bug with reading digitization points from digitization strings with newer MEGIN systems, by `Eric Larson`_.

mne/_fiff/_digitization.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ def _read_dig_fif(fid, meas_info, *, return_ch_names=False):
181181
if kind == FIFF.FIFF_DIG_POINT:
182182
tag = read_tag(fid, pos)
183183
dig.append(tag.data)
184+
elif kind == FIFF.FIFF_DIG_STRING:
185+
tag = read_tag(fid, pos)
186+
dig.extend(tag.data)
184187
elif kind == FIFF.FIFF_MNE_COORD_FRAME:
185188
tag = read_tag(fid, pos)
186189
coord_frame = _coord_frame_named.get(int(tag.data.item()))

mne/_fiff/meas_info.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
write_dig,
4747
)
4848
from .compensator import get_current_comp
49-
from .constants import FIFF, _ch_unit_mul_named, _coord_frame_named
49+
from .constants import FIFF, _ch_unit_mul_named
5050
from .ctf_comp import _read_ctf_comp, write_ctf_comp
5151
from .open import fiff_open
5252
from .pick import (
@@ -1970,7 +1970,7 @@ def _simplify_info(info, *, keep=()):
19701970

19711971

19721972
@verbose
1973-
def read_fiducials(fname, verbose=None):
1973+
def read_fiducials(fname, *, verbose=None):
19741974
"""Read fiducials from a fiff file.
19751975
19761976
Parameters
@@ -1990,26 +1990,8 @@ def read_fiducials(fname, verbose=None):
19901990
fname = _check_fname(fname=fname, overwrite="read", must_exist=True)
19911991
fid, tree, _ = fiff_open(fname)
19921992
with fid:
1993-
isotrak = dir_tree_find(tree, FIFF.FIFFB_ISOTRAK)
1994-
isotrak = isotrak[0]
1995-
pts = []
1996-
coord_frame = FIFF.FIFFV_COORD_HEAD
1997-
for k in range(isotrak["nent"]):
1998-
kind = isotrak["directory"][k].kind
1999-
pos = isotrak["directory"][k].pos
2000-
if kind == FIFF.FIFF_DIG_POINT:
2001-
tag = read_tag(fid, pos)
2002-
pts.append(DigPoint(tag.data))
2003-
elif kind == FIFF.FIFF_MNE_COORD_FRAME:
2004-
tag = read_tag(fid, pos)
2005-
coord_frame = tag.data[0]
2006-
coord_frame = _coord_frame_named.get(coord_frame, coord_frame)
2007-
2008-
# coord_frame is not stored in the tag
2009-
for pt in pts:
2010-
pt["coord_frame"] = coord_frame
2011-
2012-
return pts, coord_frame
1993+
pts = _read_dig_fif(fid, tree)
1994+
return pts, pts[0]["coord_frame"]
20131995

20141996

20151997
@verbose

mne/_fiff/open.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ def _show_tree(
348348
postpend += " ... list len=" + str(len(tag.data))
349349
elif issparse(tag.data):
350350
postpend += (
351-
f" ... sparse ({tag.data.getformat()}) shape="
351+
f" ... sparse ({tag.data.__class__.__name__}) shape="
352352
f"{tag.data.shape}"
353353
)
354354
else:

mne/_fiff/tag.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,19 +270,26 @@ def _read_id_struct(fid, tag, shape, rlims):
270270
)
271271

272272

273-
def _read_dig_point_struct(fid, tag, shape, rlims):
273+
def _read_dig_point_struct(fid, tag, shape, rlims, *, string=False):
274274
"""Read dig point struct tag."""
275275
kind = int(np.frombuffer(fid.read(4), dtype=">i4").item())
276276
kind = _dig_kind_named.get(kind, kind)
277277
ident = int(np.frombuffer(fid.read(4), dtype=">i4").item())
278278
if kind == FIFF.FIFFV_POINT_CARDINAL:
279279
ident = _dig_cardinal_named.get(ident, ident)
280-
return dict(
281-
kind=kind,
282-
ident=ident,
283-
r=np.frombuffer(fid.read(12), dtype=">f4"),
284-
coord_frame=FIFF.FIFFV_COORD_UNKNOWN,
285-
)
280+
n = 1 if not string else int(np.frombuffer(fid.read(4), dtype=">i4").item())
281+
out = [
282+
dict(
283+
kind=kind,
284+
ident=ident,
285+
r=np.frombuffer(fid.read(12), dtype=">f4"),
286+
coord_frame=FIFF.FIFFV_COORD_UNKNOWN,
287+
)
288+
for _ in range(n)
289+
]
290+
if not string:
291+
out = out[0]
292+
return out
286293

287294

288295
def _read_coord_trans_struct(fid, tag, shape, rlims):
@@ -378,18 +385,21 @@ def _read_julian(fid, tag, shape, rlims):
378385
FIFF.FIFFT_COMPLEX_DOUBLE: _read_complex_double,
379386
FIFF.FIFFT_ID_STRUCT: _read_id_struct,
380387
FIFF.FIFFT_DIG_POINT_STRUCT: _read_dig_point_struct,
388+
FIFF.FIFFT_DIG_STRING_STRUCT: partial(_read_dig_point_struct, string=True),
381389
FIFF.FIFFT_COORD_TRANS_STRUCT: _read_coord_trans_struct,
382390
FIFF.FIFFT_CH_INFO_STRUCT: _read_ch_info_struct,
383391
FIFF.FIFFT_OLD_PACK: _read_old_pack,
384392
FIFF.FIFFT_DIR_ENTRY_STRUCT: _read_dir_entry_struct,
385393
FIFF.FIFFT_JULIAN: _read_julian,
394+
FIFF.FIFFT_VOID: lambda fid, tag, shape, rlims: None,
386395
}
387396
_call_dict_names = {
388397
FIFF.FIFFT_STRING: "str",
389398
FIFF.FIFFT_COMPLEX_FLOAT: "c8",
390399
FIFF.FIFFT_COMPLEX_DOUBLE: "c16",
391400
FIFF.FIFFT_ID_STRUCT: "ids",
392401
FIFF.FIFFT_DIG_POINT_STRUCT: "dps",
402+
FIFF.FIFFT_DIG_STRING_STRUCT: "dss",
393403
FIFF.FIFFT_COORD_TRANS_STRUCT: "cts",
394404
FIFF.FIFFT_CH_INFO_STRUCT: "cis",
395405
FIFF.FIFFT_OLD_PACK: "op_",

mne/_fiff/tests/test_meas_info.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
write_cov,
3030
write_forward_solution,
3131
)
32-
from mne._fiff import meas_info
32+
from mne._fiff import meas_info, tag
3333
from mne._fiff._digitization import DigPoint, _make_dig_points
3434
from mne._fiff.constants import FIFF
3535
from mne._fiff.meas_info import (
@@ -1268,3 +1268,12 @@ def test_get_montage():
12681268
assert len(raw.info.get_montage().ch_names) == len(ch_names)
12691269
raw.info["bads"] = [ch_names[0]]
12701270
assert len(raw.info.get_montage().ch_names) == len(ch_names)
1271+
1272+
1273+
def test_tag_consistency():
1274+
"""Test that structures for tag reading are consistent."""
1275+
call_set = set(tag._call_dict)
1276+
call_names = set(tag._call_dict_names)
1277+
assert call_set == call_names, "Mismatch between _call_dict and _call_dict_names"
1278+
# TODO: This was inspired by FIFF_DIG_STRING gh-13083, we should ideally add a test
1279+
# that those dig points can actually be read in correctly at some point.

0 commit comments

Comments
 (0)