Repository: mne-tools/mne-python

Issue:
DOC: Clarify 1-layer BEM+EEG error message
Hello, 

I am having issues calculating the forward solution. I get the error:  “Cannot use a homogeneous model in EEG calculations.”  What are some reasons for this error?


Discussion:
Related to this issue, has there been a solution to the following error: 

 Surface inner skull is not completely inside surface outer skull
>  I get the error: “Cannot use a homogeneous model in EEG calculations.” What are some reasons for this error?

This means you tried to use a 1-layer BEM instead of a 3-layer BEM when doing forward calculations with EEG channels.

> Surface inner skull is not completely inside surface outer skull

This means that your `inner_skull.surf` overlaps with `outer_skull.surf`. Usually this happens when using the watershed bem, and Freesurfer did a bad job of approximating the inner skull surface (which is created just by expanding the `brain.surf`) and/or the `outer_skull.surf` (which is created by shrinking the `outer_skin.surf`. You can visualize this stuff with `freeview`.

For further questions about how to get usable surfaces, the `mne_analysis` listserv is probably a better place so that more people with analysis knowledge and experiences can chime in and learn. GitHub issues are mostly for reporting bugs and/or enhancement requests. I'll leave this open and re-title so we remember to clarify the error message about 1- vs 3-layer BEM.

Resolving patch:
diff --git a/mne/forward/_make_forward.py b/mne/forward/_make_forward.py
--- a/mne/forward/_make_forward.py
+++ b/mne/forward/_make_forward.py
@@ -245,8 +245,9 @@ def _setup_bem(bem, bem_extra, neeg, mri_head_t, allow_none=False,
                 'BEM is in %s coordinates, should be in MRI'
                 % (_coord_frame_name(bem['surfs'][0]['coord_frame']),))
         if neeg > 0 and len(bem['surfs']) == 1:
-            raise RuntimeError('Cannot use a homogeneous model in EEG '
-                               'calculations')
+            raise RuntimeError('Cannot use a homogeneous (1-layer BEM) model '
+                               'for EEG forward calculations, consider '
+                               'using a 3-layer BEM instead')
         logger.info('Employing the head->MRI coordinate transform with the '
                     'BEM model.')
         # fwd_bem_set_head_mri_t: Set the coordinate transformation
diff --git a/mne/transforms.py b/mne/transforms.py
--- a/mne/transforms.py
+++ b/mne/transforms.py
@@ -412,6 +412,7 @@ def _ensure_trans(trans, fro='mri', to='head'):
         trans = [trans]
     # Ensure that we have exactly one match
     idx = list()
+    misses = list()
     for ti, this_trans in enumerate(trans):
         if not isinstance(this_trans, Transform):
             raise ValueError('%s None' % err_str)
@@ -419,8 +420,8 @@ def _ensure_trans(trans, fro='mri', to='head'):
                 this_trans['to']} == {from_const, to_const}:
             idx.append(ti)
         else:
-            misses = '%s->%s' % (_frame_to_str[this_trans['from']],
-                                 _frame_to_str[this_trans['to']])
+            misses += ['%s->%s' % (_frame_to_str[this_trans['from']],
+                                   _frame_to_str[this_trans['to']])]
     if len(idx) != 1:
         raise ValueError('%s %s' % (err_str, ', '.join(misses)))
     trans = trans[idx[0]]


Test patch:
diff --git a/mne/forward/tests/test_make_forward.py b/mne/forward/tests/test_make_forward.py
--- a/mne/forward/tests/test_make_forward.py
+++ b/mne/forward/tests/test_make_forward.py
@@ -163,9 +163,9 @@ def test_make_forward_solution_kit():
     # now let's use mne-python all the way
     raw_py = read_raw_kit(sqd_path, mrk_path, elp_path, hsp_path)
     # without ignore_ref=True, this should throw an error:
-    pytest.raises(NotImplementedError, make_forward_solution, raw_py.info,
-                  src=src, eeg=False, meg=True,
-                  bem=fname_bem_meg, trans=trans_path)
+    with pytest.raises(NotImplementedError, match='Cannot.*KIT reference'):
+        make_forward_solution(raw_py.info, src=src, eeg=False, meg=True,
+                              bem=fname_bem_meg, trans=trans_path)
 
     # check that asking for eeg channels (even if they don't exist) is handled
     meg_only_info = pick_info(raw_py.info, pick_types(raw_py.info, meg=True,
@@ -220,11 +220,15 @@ def test_make_forward_solution_kit():
 def test_make_forward_solution():
     """Test making M-EEG forward solution from python."""
     fwd_py = make_forward_solution(fname_raw, fname_trans, fname_src,
-                                   fname_bem, mindist=5.0, eeg=True, meg=True)
+                                   fname_bem, mindist=5.)
     assert (isinstance(fwd_py, Forward))
     fwd = read_forward_solution(fname_meeg)
     assert (isinstance(fwd, Forward))
     _compare_forwards(fwd, fwd_py, 366, 1494, meg_rtol=1e-3)
+    # Homogeneous model
+    with pytest.raises(RuntimeError, match='homogeneous.*1-layer.*EEG'):
+        make_forward_solution(fname_raw, fname_trans, fname_src,
+                              fname_bem_meg)
 
 
 @testing.requires_testing_data
@@ -280,6 +284,10 @@ def test_make_forward_solution_sphere():
     fwd_1 = make_forward_solution(fname_raw, fname_trans, src, sphere,
                                   meg=True, eeg=False)
     _compare_forwards(fwd, fwd_1, 306, 108, meg_rtol=1e-12, meg_atol=1e-12)
+    # Homogeneous model
+    sphere = make_sphere_model(head_radius=None)
+    with pytest.raises(RuntimeError, match='zero shells.*EEG'):
+        make_forward_solution(fname_raw, fname_trans, src, sphere)
 
 
 @pytest.mark.slowtest
@@ -322,13 +330,14 @@ def test_forward_mixed_source_space():
     fname_img = op.join(temp_dir, 'temp-image.mgz')
 
     # head coordinates and mri_resolution, but trans file
-    pytest.raises(ValueError, src_from_fwd.export_volume, fname_img,
-                  mri_resolution=True, trans=None)
+    with pytest.raises(ValueError, match='trans containing mri to head'):
+        src_from_fwd.export_volume(fname_img, mri_resolution=True, trans=None)
 
     # head coordinates and mri_resolution, but wrong trans file
     vox_mri_t = vol1[0]['vox_mri_t']
-    pytest.raises(ValueError, src_from_fwd.export_volume, fname_img,
-                  mri_resolution=True, trans=vox_mri_t)
+    with pytest.raises(ValueError, match='mri<->head, got mri_voxel->mri'):
+        src_from_fwd.export_volume(fname_img, mri_resolution=True,
+                                   trans=vox_mri_t)
 
 
 @pytest.mark.slowtest
@@ -413,8 +422,8 @@ def test_make_forward_dipole():
                          pos=[[0., 0., 1.0], [0., 0., 0.040]],
                          amplitude=[100e-9, 100e-9],
                          ori=[[1., 0., 0.], [1., 0., 0.]], gof=1)
-    pytest.raises(ValueError, make_forward_dipole, dip_outside, fname_bem,
-                  info, fname_trans)
+    with pytest.raises(ValueError, match='outside the inner skull'):
+        make_forward_dipole(dip_outside, fname_bem, info, fname_trans)
     # if we get this far, can safely assume the code works with BEMs too
     # -> use sphere again below for speed
 
diff --git a/mne/tests/test_bem.py b/mne/tests/test_bem.py
--- a/mne/tests/test_bem.py
+++ b/mne/tests/test_bem.py
@@ -97,8 +97,8 @@ def test_make_sphere_model():
     pytest.raises(ValueError, make_sphere_model, 'auto', 'auto', None)
     pytest.raises(ValueError, make_sphere_model, 'auto', 'auto', info,
                   relative_radii=(), sigmas=())
-    pytest.raises(ValueError, make_sphere_model, 'auto', 'auto', info,
-                  relative_radii=(1,))  # wrong number of radii
+    with pytest.raises(ValueError, match='relative_radii.*must match.*sigmas'):
+        make_sphere_model('auto', 'auto', info, relative_radii=(1,))
     # here we just make sure it works -- the functionality is actually
     # tested more extensively e.g. in the forward and dipole code
     with catch_logging() as log:
@@ -116,8 +116,8 @@ def test_make_sphere_model():
     bem = make_sphere_model('auto', None, info)
     assert 'no layers' in repr(bem)
     assert 'Sphere ' in repr(bem)
-    pytest.raises(ValueError, make_sphere_model, sigmas=(0.33,),
-                  relative_radii=(1.0,))
+    with pytest.raises(ValueError, match='at least 2 sigmas.*head_radius'):
+        make_sphere_model(sigmas=(0.33,), relative_radii=(1.0,))
 
 
 @testing.requires_testing_data