From 91fd01199e1d7733b08681f78d0df4d7db99aa79 Mon Sep 17 00:00:00 2001 From: ruuskas Date: Tue, 25 Nov 2025 21:00:31 +0100 Subject: [PATCH 01/10] Add support for volumetric source spaces - select_vertices_in_sensor_range, restrict_forward_to_vertices, restrict_src_to_vertices, and restrict_forward_to_sensor_range now work with volumetric source spaces. - added a simple unittest to verify the above --- conpy/forward.py | 57 ++++++++++++++++++++++++++++--------------- tests/test_forward.py | 35 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/conpy/forward.py b/conpy/forward.py index 9cf8264..917e72e 100644 --- a/conpy/forward.py +++ b/conpy/forward.py @@ -84,6 +84,7 @@ def select_vertices_in_sensor_range( "You need to specify an Info object with " "information about the channels." ) + is_surf = src.kind == 'surface' # Load the head<->MRI transform if necessary if src[0]["coord_frame"] == FIFF.FIFFV_COORD_MRI: @@ -150,9 +151,13 @@ def select_vertices_in_sensor_range( return np.flatnonzero(src_sel) else: n_lh_verts = src[0]["nuse"] - lh_sel, rh_sel = src_sel[:n_lh_verts], src_sel[n_lh_verts:] + lh_sel = src_sel[:n_lh_verts] vert_lh = src[0]["vertno"][lh_sel] - vert_rh = src[1]["vertno"][rh_sel] + if is_surf: + rh_sel = src_sel[n_lh_verts:] + vert_rh = src[1]["vertno"][rh_sel] + else: + vert_rh = [] return [vert_lh, vert_rh] @@ -201,7 +206,10 @@ def restrict_forward_to_vertices( else: fwd_out = fwd - lh_vertno, rh_vertno = [src["vertno"] for src in fwd["src"]] + is_surf = fwd["src"].kind == 'surface' + lh_vertno = fwd["src"][0]["vertno"] + if is_surf: + rh_vertno = fwd["src"][1]["vertno"] if isinstance(vertno_or_idx[0], int): logger.info("Interpreting given vertno_or_idx as vertex indices.") @@ -212,9 +220,10 @@ def restrict_forward_to_vertices( n_vert_lh = len(lh_vertno) sel_lh_idx = vertno_or_idx[fwd_idx < n_vert_lh] - sel_rh_idx = vertno_or_idx[fwd_idx >= n_vert_lh] - n_vert_lh sel_lh_vertno = lh_vertno[sel_lh_idx] - sel_rh_vertno = rh_vertno[sel_rh_idx] + if is_surf: + sel_rh_idx = vertno_or_idx[fwd_idx >= n_vert_lh] - n_vert_lh + sel_rh_vertno = rh_vertno[sel_rh_idx] else: logger.info("Interpreting given vertno_or_idx as vertex numbers.") @@ -223,12 +232,14 @@ def restrict_forward_to_vertices( sel_lh_vertno, sel_rh_vertno = vertno_or_idx src_lh_idx = _find_indices_1d(lh_vertno, sel_lh_vertno, check_vertno) - src_rh_idx = _find_indices_1d(rh_vertno, sel_rh_vertno, check_vertno) - fwd_idx = np.hstack((src_lh_idx, src_rh_idx + len(lh_vertno))) + fwd_idx = src_lh_idx + if is_surf: + src_rh_idx = _find_indices_1d(rh_vertno, sel_rh_vertno, check_vertno) + fwd_idx = np.hstack((src_lh_idx, src_rh_idx + len(lh_vertno))) logger.info( "Restricting forward solution to %d out of %d vertices." - % (len(fwd_idx), len(lh_vertno) + len(rh_vertno)) + % (len(fwd_idx), len(lh_vertno) + len(rh_vertno) if is_surf else len(lh_vertno)) ) n_orient = fwd["sol"]["ncol"] // fwd["nsource"] @@ -260,7 +271,7 @@ def _reshape_select(X, dim3, sel): # Restrict the SourceSpaces inside the forward operator fwd_out["src"] = restrict_src_to_vertices( fwd_out["src"], - [sel_lh_vertno, sel_rh_vertno], + [sel_lh_vertno, sel_rh_vertno] if is_surf else [sel_lh_vertno, []], check_vertno=False, verbose=False, ) @@ -307,23 +318,28 @@ def restrict_src_to_vertices( else: src_out = src + is_surf = src.kind == "surface" + if vertno_or_idx: if isinstance(vertno_or_idx[0], int): logger.info("Interpreting given vertno_or_idx as vertex indices.") vertno_or_idx = np.asarray(vertno_or_idx) n_vert_lh = src[0]["nuse"] ind_lh = vertno_or_idx[vertno_or_idx < n_vert_lh] - ind_rh = vertno_or_idx[vertno_or_idx >= n_vert_lh] - n_vert_lh vert_no_lh = src[0]["vertno"][ind_lh] - vert_no_rh = src[1]["vertno"][ind_rh] + if is_surf: + ind_rh = vertno_or_idx[vertno_or_idx >= n_vert_lh] - n_vert_lh + vert_no_rh = src[1]["vertno"][ind_rh] else: logger.info("Interpreting given vertno_or_idx as vertex numbers.") - vert_no_lh, vert_no_rh = vertno_or_idx + vert_no_lh = vertno_or_idx[0] + if is_surf: + vert_no_rh = vertno_or_idx[1] if check_vertno: - if not ( - np.all(np.isin(vert_no_lh, src[0]["vertno"])) - and np.all(np.isin(vert_no_rh, src[1]["vertno"])) - ): + check_tmp = np.all(np.isin(vert_no_lh, src[0]["vertno"])) + if is_surf: + check_tmp = check_tmp and np.all(np.isin(vert_no_rh, src[1]["vertno"])) + if not check_tmp: raise ValueError( "One or more vertices were not present in SourceSpaces." ) @@ -332,16 +348,19 @@ def restrict_src_to_vertices( # Empty list vert_no_lh, vert_no_rh = [], [] + nuse = src[0]["nuse"] + src[1]["nuse"] if is_surf else src[0]["nuse"] + n_vertno = len(vert_no_lh) + len(vert_no_rh) if is_surf else len(vert_no_lh) logger.info( "Restricting source space to %d out of %d vertices." - % (len(vert_no_lh) + len(vert_no_rh), src[0]["nuse"] + src[1]["nuse"]) + % (n_vertno, nuse) ) - for hemi, verts in zip(src_out, (vert_no_lh, vert_no_rh)): + vertnos = (vert_no_lh, vert_no_rh) if is_surf else [vert_no_lh] + for hemi, verts in zip(src_out, vertnos): # Ensure vertices are in sequential order verts = np.sort(verts) - # Restrict the source space + # Restrict the source spaceççç hemi["vertno"] = verts hemi["nuse"] = len(verts) hemi["inuse"] = hemi["inuse"].copy() diff --git a/tests/test_forward.py b/tests/test_forward.py index 340bb3c..dc9cae3 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -33,6 +33,24 @@ def src(): ) +@pytest.fixture +def vol_src(): + """Make a volume source space.""" + path = mne.datasets.sample.data_path() + return mne.read_source_spaces( + op.join(path, "subjects", "sample", "bem", "volume-7mm-src.fif") + ) + + +@pytest.fixture +def vol_fwd(): + """Make a volume forward solution.""" + path = mne.datasets.sample.data_path() + return mne.read_forward_solution( + op.join(path, "MEG", "sample", "sample_audvis-meg-vol-7-fwd.fif") + ) + + def _trans(): path = mne.datasets.sample.data_path() return op.join(path, "MEG", "sample", "sample_audvis_raw-trans.fif") @@ -213,6 +231,23 @@ def test_select_vertices_in_sensor_range(fwd, src): assert_array_equal(verts2[1], np.array([2159])) +def test_select_vertices_in_sensor_range_volume(vol_fwd): + """Test selecting vertices in sensor range with volumetric source space.""" + fwd_r = restrict_forward_to_vertices(vol_fwd, ([1273, 1312], [])) + + verts = select_vertices_in_sensor_range(fwd_r, 0.08) + assert_array_equal(verts[0], np.array([1273])) + assert_array_equal(verts[1], np.array([])) + # Test indices + verts = select_vertices_in_sensor_range(fwd_r, 0.08, indices=True) + assert_array_equal(verts, np.array([0])) + + # Test restricting + fwd_rs = restrict_forward_to_sensor_range(fwd_r, 0.08) + assert_array_equal(fwd_rs["src"][0]["vertno"], np.array([1273])) + assert len(fwd_rs["src"]) == 1 # No second source space + + # FIXME: disabled until we can make a proper test # def test_radial_coord_system(): # """Test making a radial coordinate system.""" From 2d703d497ad2ac795a7d8ea27cd528890b244a0e Mon Sep 17 00:00:00 2001 From: ruuskas Date: Tue, 25 Nov 2025 21:16:26 +0100 Subject: [PATCH 02/10] lint too long line --- conpy/forward.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conpy/forward.py b/conpy/forward.py index 917e72e..ad8832f 100644 --- a/conpy/forward.py +++ b/conpy/forward.py @@ -338,7 +338,8 @@ def restrict_src_to_vertices( if check_vertno: check_tmp = np.all(np.isin(vert_no_lh, src[0]["vertno"])) if is_surf: - check_tmp = check_tmp and np.all(np.isin(vert_no_rh, src[1]["vertno"])) + check_tmp = check_tmp and np.all(np.isin(vert_no_rh, + src[1]["vertno"])) if not check_tmp: raise ValueError( "One or more vertices were not present in SourceSpaces." From 1d4affe6b56e9286f3e6f6335eb5c2ab07c01e7b Mon Sep 17 00:00:00 2001 From: Santeri Ruuskanen <66060772+ruuskas@users.noreply.github.com> Date: Sat, 29 Nov 2025 22:14:12 +0200 Subject: [PATCH 03/10] Update tests/test_forward.py Co-authored-by: Marijn van Vliet --- tests/test_forward.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_forward.py b/tests/test_forward.py index dc9cae3..662998c 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -35,7 +35,7 @@ def src(): @pytest.fixture def vol_src(): - """Make a volume source space.""" + """Load a volume source space.""" path = mne.datasets.sample.data_path() return mne.read_source_spaces( op.join(path, "subjects", "sample", "bem", "volume-7mm-src.fif") From a53111d26ba7c2caec698a0f2f72485cf5fb3955 Mon Sep 17 00:00:00 2001 From: Santeri Ruuskanen <66060772+ruuskas@users.noreply.github.com> Date: Sat, 29 Nov 2025 22:14:34 +0200 Subject: [PATCH 04/10] fix typo Co-authored-by: Marijn van Vliet --- conpy/forward.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conpy/forward.py b/conpy/forward.py index ad8832f..0180cda 100644 --- a/conpy/forward.py +++ b/conpy/forward.py @@ -361,7 +361,7 @@ def restrict_src_to_vertices( # Ensure vertices are in sequential order verts = np.sort(verts) - # Restrict the source spaceççç + # Restrict the source space hemi["vertno"] = verts hemi["nuse"] = len(verts) hemi["inuse"] = hemi["inuse"].copy() From ab7a0e45b6b60574e786fdcd0b24511e9c761329 Mon Sep 17 00:00:00 2001 From: Santeri Ruuskanen <66060772+ruuskas@users.noreply.github.com> Date: Sat, 29 Nov 2025 22:14:45 +0200 Subject: [PATCH 05/10] Update tests/test_forward.py Co-authored-by: Marijn van Vliet --- tests/test_forward.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_forward.py b/tests/test_forward.py index 662998c..cb5eac6 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -44,7 +44,7 @@ def vol_src(): @pytest.fixture def vol_fwd(): - """Make a volume forward solution.""" + """Load a volume forward solution.""" path = mne.datasets.sample.data_path() return mne.read_forward_solution( op.join(path, "MEG", "sample", "sample_audvis-meg-vol-7-fwd.fif") From a2d3638c2e992b493985bffe09942900afdaf761 Mon Sep 17 00:00:00 2001 From: Santeri Ruuskanen <66060772+ruuskas@users.noreply.github.com> Date: Sat, 29 Nov 2025 22:15:32 +0200 Subject: [PATCH 06/10] add assertion Co-authored-by: Marijn van Vliet --- tests/test_forward.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_forward.py b/tests/test_forward.py index cb5eac6..e648312 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -234,6 +234,7 @@ def test_select_vertices_in_sensor_range(fwd, src): def test_select_vertices_in_sensor_range_volume(vol_fwd): """Test selecting vertices in sensor range with volumetric source space.""" fwd_r = restrict_forward_to_vertices(vol_fwd, ([1273, 1312], [])) + assert_array_equal(fwd_r["src"][0]["vertno"], np.array([1273, 1312])) verts = select_vertices_in_sensor_range(fwd_r, 0.08) assert_array_equal(verts[0], np.array([1273])) From b659a0283c36c501451bd9041f9e64c4edb9ce11 Mon Sep 17 00:00:00 2001 From: ruuskas Date: Sat, 29 Nov 2025 22:16:42 +0200 Subject: [PATCH 07/10] make it less stupid --- conpy/forward.py | 92 ++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 53 deletions(-) diff --git a/conpy/forward.py b/conpy/forward.py index ad8832f..a7fc6d8 100644 --- a/conpy/forward.py +++ b/conpy/forward.py @@ -84,7 +84,7 @@ def select_vertices_in_sensor_range( "You need to specify an Info object with " "information about the channels." ) - is_surf = src.kind == 'surface' + n_src = len(src) # Load the head<->MRI transform if necessary if src[0]["coord_frame"] == FIFF.FIFFV_COORD_MRI: @@ -150,15 +150,11 @@ def select_vertices_in_sensor_range( if indices: return np.flatnonzero(src_sel) else: - n_lh_verts = src[0]["nuse"] - lh_sel = src_sel[:n_lh_verts] - vert_lh = src[0]["vertno"][lh_sel] - if is_surf: - rh_sel = src_sel[n_lh_verts:] - vert_rh = src[1]["vertno"][rh_sel] - else: - vert_rh = [] - return [vert_lh, vert_rh] + n_verts = [0] + [s["nuse"] for s in src] + n_verts = np.cumsum(n_verts) + sel = [src_sel[n_verts[i]:n_verts[i+1]] for i in range(n_src)] + verts = [src[i]["vertno"][sel[i]] for i in range(n_src)] + return verts @verbose @@ -206,11 +202,9 @@ def restrict_forward_to_vertices( else: fwd_out = fwd - is_surf = fwd["src"].kind == 'surface' - lh_vertno = fwd["src"][0]["vertno"] - if is_surf: - rh_vertno = fwd["src"][1]["vertno"] - + n_src = len(fwd["src"]) + hemi_vertno = [s["vertno"] for s in fwd["src"]] + n_hemi_vertno = [len(vertno) for vertno in hemi_vertno] if isinstance(vertno_or_idx[0], int): logger.info("Interpreting given vertno_or_idx as vertex indices.") vertno_or_idx = np.asarray(vertno_or_idx) @@ -218,28 +212,26 @@ def restrict_forward_to_vertices( # Make sure the vertices are in sequential order fwd_idx = np.sort(vertno_or_idx) - n_vert_lh = len(lh_vertno) - sel_lh_idx = vertno_or_idx[fwd_idx < n_vert_lh] - sel_lh_vertno = lh_vertno[sel_lh_idx] - if is_surf: - sel_rh_idx = vertno_or_idx[fwd_idx >= n_vert_lh] - n_vert_lh - sel_rh_vertno = rh_vertno[sel_rh_idx] + hemi_n_vert = [0] + [len(vertno) for vertno in hemi_vertno] + sel_hemi_idx = [ + vertno_or_idx[(fwd_idx > hemi_n_vert[i]) & (fwd_idx < hemi_n_vert[i+1])] + for i in range(n_src)] + sel_hemi_vertno = [hemi_vertno[sel] for sel in sel_hemi_idx] else: logger.info("Interpreting given vertno_or_idx as vertex numbers.") # Make sure vertno_or_idx is sorted vertno_or_idx = [np.sort(v) for v in vertno_or_idx] + sel_hemi_vertno = vertno_or_idx - sel_lh_vertno, sel_rh_vertno = vertno_or_idx - src_lh_idx = _find_indices_1d(lh_vertno, sel_lh_vertno, check_vertno) - fwd_idx = src_lh_idx - if is_surf: - src_rh_idx = _find_indices_1d(rh_vertno, sel_rh_vertno, check_vertno) - fwd_idx = np.hstack((src_lh_idx, src_rh_idx + len(lh_vertno))) + src_hemi_idx = [_find_indices_1d(vertno, sel, check_vertno) + sum( + n_hemi_vertno[:i]) for i, (vertno, sel) in enumerate(zip(hemi_vertno, + sel_hemi_vertno))] + fwd_idx = np.hstack(src_hemi_idx) logger.info( "Restricting forward solution to %d out of %d vertices." - % (len(fwd_idx), len(lh_vertno) + len(rh_vertno) if is_surf else len(lh_vertno)) + % (len(fwd_idx), sum(n_hemi_vertno)) ) n_orient = fwd["sol"]["ncol"] // fwd["nsource"] @@ -271,7 +263,7 @@ def _reshape_select(X, dim3, sel): # Restrict the SourceSpaces inside the forward operator fwd_out["src"] = restrict_src_to_vertices( fwd_out["src"], - [sel_lh_vertno, sel_rh_vertno] if is_surf else [sel_lh_vertno, []], + sel_hemi_vertno, check_vertno=False, verbose=False, ) @@ -318,46 +310,40 @@ def restrict_src_to_vertices( else: src_out = src - is_surf = src.kind == "surface" - + n_src = len(src) if vertno_or_idx: if isinstance(vertno_or_idx[0], int): logger.info("Interpreting given vertno_or_idx as vertex indices.") vertno_or_idx = np.asarray(vertno_or_idx) - n_vert_lh = src[0]["nuse"] - ind_lh = vertno_or_idx[vertno_or_idx < n_vert_lh] - vert_no_lh = src[0]["vertno"][ind_lh] - if is_surf: - ind_rh = vertno_or_idx[vertno_or_idx >= n_vert_lh] - n_vert_lh - vert_no_rh = src[1]["vertno"][ind_rh] + n_vert = [0] + [s["nuse"] for s in src] + ind = [ + vertno_or_idx[ + (vertno_or_idx >= n_vert[i]) & (vertno_or_idx < n_vert[i+1])] - + n_vert[i] for i in range(n_src) + ] + vertno = [s["vertno"][inds] for s, inds in zip(src, ind)] else: logger.info("Interpreting given vertno_or_idx as vertex numbers.") - vert_no_lh = vertno_or_idx[0] - if is_surf: - vert_no_rh = vertno_or_idx[1] + vertno = vertno_or_idx if check_vertno: - check_tmp = np.all(np.isin(vert_no_lh, src[0]["vertno"])) - if is_surf: - check_tmp = check_tmp and np.all(np.isin(vert_no_rh, - src[1]["vertno"])) - if not check_tmp: - raise ValueError( - "One or more vertices were not present in SourceSpaces." - ) + for s, verts in zip(src, vertno): + if not np.all(np.isin(verts, s["vertno"])): + raise ValueError( + "One or more vertices were not present in SourceSpaces." + ) else: # Empty list - vert_no_lh, vert_no_rh = [], [] + vertno = [[] for i in range(n_src)] - nuse = src[0]["nuse"] + src[1]["nuse"] if is_surf else src[0]["nuse"] - n_vertno = len(vert_no_lh) + len(vert_no_rh) if is_surf else len(vert_no_lh) + nuse = sum([s["nuse"] for s in src]) + n_vertno = sum([len(verts) for verts in vertno]) logger.info( "Restricting source space to %d out of %d vertices." % (n_vertno, nuse) ) - vertnos = (vert_no_lh, vert_no_rh) if is_surf else [vert_no_lh] - for hemi, verts in zip(src_out, vertnos): + for hemi, verts in zip(src_out, vertno): # Ensure vertices are in sequential order verts = np.sort(verts) From 61973d8f7521666213eabc454d6e47e4aa46e8f6 Mon Sep 17 00:00:00 2001 From: ruuskas Date: Sat, 29 Nov 2025 22:53:57 +0200 Subject: [PATCH 08/10] fix bugs --- conpy/forward.py | 11 +++++++---- tests/test_forward.py | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/conpy/forward.py b/conpy/forward.py index d98af10..f0c05c6 100644 --- a/conpy/forward.py +++ b/conpy/forward.py @@ -212,11 +212,13 @@ def restrict_forward_to_vertices( # Make sure the vertices are in sequential order fwd_idx = np.sort(vertno_or_idx) - hemi_n_vert = [0] + [len(vertno) for vertno in hemi_vertno] + hemi_n_vert = [0] + n_hemi_vertno sel_hemi_idx = [ - vertno_or_idx[(fwd_idx > hemi_n_vert[i]) & (fwd_idx < hemi_n_vert[i+1])] + vertno_or_idx[(fwd_idx >= hemi_n_vert[i]) + & (fwd_idx < np.cumsum(hemi_n_vert)[i+1])] - np.cumsum(hemi_n_vert)[i] for i in range(n_src)] - sel_hemi_vertno = [hemi_vertno[sel] for sel in sel_hemi_idx] + sel_hemi_vertno = [vertno[sel] for vertno, sel in zip(hemi_vertno, + sel_hemi_idx)] else: logger.info("Interpreting given vertno_or_idx as vertex numbers.") @@ -318,7 +320,8 @@ def restrict_src_to_vertices( n_vert = [0] + [s["nuse"] for s in src] ind = [ vertno_or_idx[ - (vertno_or_idx >= n_vert[i]) & (vertno_or_idx < n_vert[i+1])] - + (vertno_or_idx >= n_vert[i]) & + (vertno_or_idx < np.cumsum(n_vert)[i+1])] - n_vert[i] for i in range(n_src) ] vertno = [s["vertno"][inds] for s, inds in zip(src, ind)] diff --git a/tests/test_forward.py b/tests/test_forward.py index e648312..28ddf5c 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -233,12 +233,12 @@ def test_select_vertices_in_sensor_range(fwd, src): def test_select_vertices_in_sensor_range_volume(vol_fwd): """Test selecting vertices in sensor range with volumetric source space.""" - fwd_r = restrict_forward_to_vertices(vol_fwd, ([1273, 1312], [])) + fwd_r = restrict_forward_to_vertices(vol_fwd, ([[1273, 1312]])) assert_array_equal(fwd_r["src"][0]["vertno"], np.array([1273, 1312])) verts = select_vertices_in_sensor_range(fwd_r, 0.08) assert_array_equal(verts[0], np.array([1273])) - assert_array_equal(verts[1], np.array([])) + # Test indices verts = select_vertices_in_sensor_range(fwd_r, 0.08, indices=True) assert_array_equal(verts, np.array([0])) From 8d226c5ad3b74105b7fcfd5aae55862459e9c5cd Mon Sep 17 00:00:00 2001 From: ruuskas Date: Sat, 29 Nov 2025 23:01:17 +0200 Subject: [PATCH 09/10] now it should work even with n_src > 2 --- conpy/forward.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/conpy/forward.py b/conpy/forward.py index f0c05c6..cfc4781 100644 --- a/conpy/forward.py +++ b/conpy/forward.py @@ -150,8 +150,7 @@ def select_vertices_in_sensor_range( if indices: return np.flatnonzero(src_sel) else: - n_verts = [0] + [s["nuse"] for s in src] - n_verts = np.cumsum(n_verts) + n_verts = np.cumsum([0] + [s["nuse"] for s in src]) sel = [src_sel[n_verts[i]:n_verts[i+1]] for i in range(n_src)] verts = [src[i]["vertno"][sel[i]] for i in range(n_src)] return verts @@ -212,10 +211,10 @@ def restrict_forward_to_vertices( # Make sure the vertices are in sequential order fwd_idx = np.sort(vertno_or_idx) - hemi_n_vert = [0] + n_hemi_vertno + hemi_vert_idx = np.cumsum([0] + n_hemi_vertno) sel_hemi_idx = [ - vertno_or_idx[(fwd_idx >= hemi_n_vert[i]) - & (fwd_idx < np.cumsum(hemi_n_vert)[i+1])] - np.cumsum(hemi_n_vert)[i] + vertno_or_idx[(fwd_idx >= hemi_vert_idx[i]) + & (fwd_idx < hemi_vert_idx[i+1])] - hemi_vert_idx[i] for i in range(n_src)] sel_hemi_vertno = [vertno[sel] for vertno, sel in zip(hemi_vertno, sel_hemi_idx)] @@ -317,11 +316,11 @@ def restrict_src_to_vertices( if isinstance(vertno_or_idx[0], int): logger.info("Interpreting given vertno_or_idx as vertex indices.") vertno_or_idx = np.asarray(vertno_or_idx) - n_vert = [0] + [s["nuse"] for s in src] + n_vert = np.cumsum([0] + [s["nuse"] for s in src]) ind = [ vertno_or_idx[ (vertno_or_idx >= n_vert[i]) & - (vertno_or_idx < np.cumsum(n_vert)[i+1])] - + (vertno_or_idx < n_vert[i+1])] - n_vert[i] for i in range(n_src) ] vertno = [s["vertno"][inds] for s, inds in zip(src, ind)] From c7f97ba66bf6cf1cdbc6535d3a5727f64924b142 Mon Sep 17 00:00:00 2001 From: ruuskas Date: Sat, 29 Nov 2025 23:14:48 +0200 Subject: [PATCH 10/10] use consistent variable names --- conpy/forward.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/conpy/forward.py b/conpy/forward.py index cfc4781..71f2788 100644 --- a/conpy/forward.py +++ b/conpy/forward.py @@ -202,8 +202,8 @@ def restrict_forward_to_vertices( fwd_out = fwd n_src = len(fwd["src"]) - hemi_vertno = [s["vertno"] for s in fwd["src"]] - n_hemi_vertno = [len(vertno) for vertno in hemi_vertno] + vertno = [s["vertno"] for s in fwd["src"]] + n_vertno = [len(hemi_vertno) for hemi_vertno in vertno] if isinstance(vertno_or_idx[0], int): logger.info("Interpreting given vertno_or_idx as vertex indices.") vertno_or_idx = np.asarray(vertno_or_idx) @@ -211,28 +211,28 @@ def restrict_forward_to_vertices( # Make sure the vertices are in sequential order fwd_idx = np.sort(vertno_or_idx) - hemi_vert_idx = np.cumsum([0] + n_hemi_vertno) - sel_hemi_idx = [ - vertno_or_idx[(fwd_idx >= hemi_vert_idx[i]) - & (fwd_idx < hemi_vert_idx[i+1])] - hemi_vert_idx[i] + vert_idx = np.cumsum([0] + n_vertno) + sel_idx = [ + vertno_or_idx[(fwd_idx >= vert_idx[i]) + & (fwd_idx < vert_idx[i+1])] - vert_idx[i] for i in range(n_src)] - sel_hemi_vertno = [vertno[sel] for vertno, sel in zip(hemi_vertno, - sel_hemi_idx)] + sel_vertno = [hemi_vertno[sel] for hemi_vertno, sel in zip(vertno, sel_idx)] else: logger.info("Interpreting given vertno_or_idx as vertex numbers.") # Make sure vertno_or_idx is sorted vertno_or_idx = [np.sort(v) for v in vertno_or_idx] - sel_hemi_vertno = vertno_or_idx + sel_vertno = vertno_or_idx - src_hemi_idx = [_find_indices_1d(vertno, sel, check_vertno) + sum( - n_hemi_vertno[:i]) for i, (vertno, sel) in enumerate(zip(hemi_vertno, - sel_hemi_vertno))] - fwd_idx = np.hstack(src_hemi_idx) + src_idx = [ + _find_indices_1d(hemi_vertno, sel, check_vertno) + sum(n_vertno[:i]) + for i, (hemi_vertno, sel) in enumerate(zip(vertno, sel_vertno)) + ] + fwd_idx = np.hstack(src_idx) logger.info( "Restricting forward solution to %d out of %d vertices." - % (len(fwd_idx), sum(n_hemi_vertno)) + % (len(fwd_idx), sum(n_vertno)) ) n_orient = fwd["sol"]["ncol"] // fwd["nsource"] @@ -264,7 +264,7 @@ def _reshape_select(X, dim3, sel): # Restrict the SourceSpaces inside the forward operator fwd_out["src"] = restrict_src_to_vertices( fwd_out["src"], - sel_hemi_vertno, + sel_vertno, check_vertno=False, verbose=False, ) @@ -316,12 +316,11 @@ def restrict_src_to_vertices( if isinstance(vertno_or_idx[0], int): logger.info("Interpreting given vertno_or_idx as vertex indices.") vertno_or_idx = np.asarray(vertno_or_idx) - n_vert = np.cumsum([0] + [s["nuse"] for s in src]) + vert_idx = np.cumsum([0] + [s["nuse"] for s in src]) ind = [ vertno_or_idx[ - (vertno_or_idx >= n_vert[i]) & - (vertno_or_idx < n_vert[i+1])] - - n_vert[i] for i in range(n_src) + (vertno_or_idx >= vert_idx[i]) & (vertno_or_idx < vert_idx[i+1]) + ] - vert_idx[i] for i in range(n_src) ] vertno = [s["vertno"][inds] for s, inds in zip(src, ind)] else: