diff --git a/mne/channels/montage.py b/mne/channels/montage.py index e28ded3f3d7..6a2a84241ea 100644 --- a/mne/channels/montage.py +++ b/mne/channels/montage.py @@ -1656,7 +1656,8 @@ def compute_native_head_t(montage, *, on_missing='warn', verbose=None): else: fid_keys = ('nasion', 'lpa', 'rpa') for key in fid_keys: - if fid_coords[key] is None: + this_coord = fid_coords[key] + if this_coord is None or np.any(np.isnan(this_coord)): msg = ( f'Fiducial point {key} not found, assuming identity ' f'{_verbose_frames[coord_frame]} to head transformation') diff --git a/mne/channels/tests/test_montage.py b/mne/channels/tests/test_montage.py index 88297cae040..5fe16a2294d 100644 --- a/mne/channels/tests/test_montage.py +++ b/mne/channels/tests/test_montage.py @@ -848,6 +848,52 @@ def test_set_dig_montage(): [6., 7., 8., 42., 42., 42.]]) +def test_set_dig_montage_with_nan_positions(): + """Test that fiducials are not NaN. + + Test that setting a montage with some NaN positions does not produce + NaN fiducials. + """ + def _ensure_fid_not_nan(info, ch_pos): + montage_kwargs = dict(ch_pos=dict(), coord_frame='head') + for ch_idx, ch in enumerate(info.ch_names): + montage_kwargs['ch_pos'][ch] = ch_pos[ch_idx] + + new_montage = make_dig_montage(**montage_kwargs) + info = info.copy() + info.set_montage(new_montage) + + recovered_montage = info.get_montage() + fid_coords, coord_frame = _get_fid_coords( + recovered_montage.dig, raise_error=False) + + for fid_coord in fid_coords.values(): + if fid_coord is not None: + assert not np.isnan(fid_coord).any() + + return fid_coords, coord_frame + + channels = list('ABCDEF') + info = create_info(channels, 1000, ch_types='seeg') + + # if all positions are NaN, the fiducials should not be NaN, but None + ch_pos = [info['chs'][ch_idx]['loc'][:3] + for ch_idx in range(len(channels))] + fid_coords, coord_frame = _ensure_fid_not_nan(info, ch_pos) + for fid_coord in fid_coords.values(): + assert fid_coord is None + assert coord_frame is None + + # if some positions are not NaN, the fiducials should be a non-NaN array + ch_pos[0] = np.array([1., 1.5, 1.]) + ch_pos[1] = np.array([2., 1.5, 1.5]) + ch_pos[2] = np.array([1.25, 1., 1.25]) + fid_coords, coord_frame = _ensure_fid_not_nan(info, ch_pos) + for fid_coord in fid_coords.values(): + assert isinstance(fid_coord, np.ndarray) + assert coord_frame == FIFF.FIFFV_COORD_HEAD + + @testing.requires_testing_data def test_fif_dig_montage(tmp_path): """Test FIF dig montage support.""" diff --git a/mne/io/_digitization.py b/mne/io/_digitization.py index a57e0eb78eb..c6baf9f507b 100644 --- a/mne/io/_digitization.py +++ b/mne/io/_digitization.py @@ -254,7 +254,8 @@ def _ensure_fiducials_head(dig): if radius is None: radius = [ np.linalg.norm(d['r']) for d in dig - if d['coord_frame'] == FIFF.FIFFV_COORD_HEAD] + if d['coord_frame'] == FIFF.FIFFV_COORD_HEAD + and not np.isnan(d['r']).any()] if not radius: return # can't complete, no head points radius = np.mean(radius)