Repository: mne-tools/mne-python

Issue:
ENH: crash or repair on manual STC smoothing if zeros remain in the morphed STC
... we should catch this case...

cc @Eric89GXL @mluessi @dgwakeman @agramfort 



Discussion:
Maybe a warning is better, because there are cases where this is not a bad thing: if your surface is too close to the BEM surfaces those points will be excluded from your source space. Thus zeros there are logical. 

> Thus zeros there are logical.

but this may propagate and it will distort results of analyses. E.g. it may help creating clusters that don't exist.

Another option would be a warning + repair-attempt. E.g. check after i iterations whetehr zereos are in. If not, return, else move on as if it was default.

What do you mean propogate?

@dgwakeman I mean that you'll have zeros in your final data. Nothing more. So when you use that with clustering you'll artifically disconnect vertices.

+1 for a big warning

True, although at least for the case of the BEM issues. These are typically fairly consistent across participants, so I would think the better way to deal with this is to detect if they are perfectly zero in whatever connectivity analysis you are using and remove them there (alternatively, if we can make them NANs it might be more appropriate.

+1 for warning

I feel we also should add the actual number of smoothing steps used somewhere to the stc object.

the pb is going to be to save this info to disk

@agramfort I feel I move more and more to h5py ... using the hidden functions we have heavily. The fiff format turns out to be quite limited for what you actually need for your work. We should think about these things carefully.... 

point taken

@agramfort I'm not saying all is bad. But we should try to stay compatibla and not to limit our needs by maintaining fiff compat. Difficult, I know. We have to deal with it however. Better we find an official solution than people forking around privately.


Resolving patch:
diff --git a/mne/source_estimate.py b/mne/source_estimate.py
--- a/mne/source_estimate.py
+++ b/mne/source_estimate.py
@@ -2007,6 +2007,10 @@ def _morph_buffer(data, idx_use, e, smooth, n_vertices, nearest, maps,
         data.data /= data_sum.repeat(np.diff(data.indptr))
     else:
         data[idx_use, :] /= data_sum[idx_use][:, None]
+    if len(idx_use) != len(data_sum):
+        warnings.warn('%s/%s vertices not included in smoothing, consider '
+                      'increasing the number of steps'
+                      % (len(idx_use), len(data_sum)))
 
     logger.info('    %d smooth iterations done.' % (k + 1))
     data_morphed = maps[nearest, :] * data


Test patch:
diff --git a/mne/tests/test_source_estimate.py b/mne/tests/test_source_estimate.py
--- a/mne/tests/test_source_estimate.py
+++ b/mne/tests/test_source_estimate.py
@@ -210,7 +210,9 @@ def test_stc_arithmetic():
         a -= 1
         a *= -1
         a /= 2
-        a **= 3
+        with warnings.catch_warnings(record=True):
+            warnings.simplefilter('always')
+            a **= 3
         out.append(a)
 
     assert_array_equal(out[0], out[1].data)
@@ -384,6 +386,13 @@ def test_morph_data():
     stc_to3 = morph_data(subject_from, subject_to, stc_from,
                          grade=vertices_to, smooth=12, buffer_size=3,
                          subjects_dir=subjects_dir)
+    # make sure we get a warning about # of steps
+    with warnings.catch_warnings(record=True) as w:
+        warnings.simplefilter('always')
+        morph_data(subject_from, subject_to, stc_from,
+                   grade=vertices_to, smooth=1, buffer_size=3,
+                   subjects_dir=subjects_dir)
+    assert_equal(len(w), 2)
 
     assert_array_almost_equal(stc_to.data, stc_to1.data, 5)
     assert_array_almost_equal(stc_to1.data, stc_to2.data)
@@ -394,6 +403,13 @@ def test_morph_data():
                                      smooth=12, subjects_dir=subjects_dir)
     stc_to3 = stc_from.morph_precomputed(subject_to, vertices_to, morph_mat)
     assert_array_almost_equal(stc_to1.data, stc_to3.data)
+    # steps warning
+    with warnings.catch_warnings(record=True) as w:
+        warnings.simplefilter('always')
+        compute_morph_matrix(subject_from, subject_to,
+                             stc_from.vertices, vertices_to,
+                             smooth=1, subjects_dir=subjects_dir)
+    assert_equal(len(w), 2)
 
     mean_from = stc_from.data.mean(axis=0)
     mean_to = stc_to1.data.mean(axis=0)