From 53f4f8c1c60f0821c83df4fd6c38c2a3bbe80c47 Mon Sep 17 00:00:00 2001 From: Edouard Date: Fri, 8 May 2026 20:23:57 -0400 Subject: [PATCH 01/16] WIP add headmodel computation --- toolbox/forward/bst_headmodeler.m | 9 +++- toolbox/forward/bst_seeg_uni.m | 70 +++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 toolbox/forward/bst_seeg_uni.m diff --git a/toolbox/forward/bst_headmodeler.m b/toolbox/forward/bst_headmodeler.m index 6af5e4dca..581fbdfc6 100644 --- a/toolbox/forward/bst_headmodeler.m +++ b/toolbox/forward/bst_headmodeler.m @@ -22,7 +22,7 @@ % .EEGMethod: Method used to compute the forward model for EEG sensors. % - 'eeg_3sphereberg' : EEG forward modeling with a set of 3 concentric spheres (Scalp, Skull, Brain/CSF) % - 'openmeeg' : OpenMEEG forward model -% .SEEGMethod: 'openmeeg' and 'duneuro' +% .SEEGMethod: 'uniform', 'openmeeg' and 'duneuro' % .ECOGMethod: 'openmeeg' and 'duneuro' % .NIRSMethod: 'import' % @@ -536,6 +536,13 @@ Gain(~isnan(Gain_dn)) = Gain_dn(~isnan(Gain_dn)); end +%% ===== COMPUTE: SEEG UNIFORM HEADMODELS ===== +if strcmp('uniform', OPTIONS.SEEGMethod) + + Gain(iSeeg, :) = bst_seeg_uni(OPTIONS.GridLoc, OPTIONS.Channel(iSeeg), sSurfInner, []); + strHistory = [strHistory, ' | ', 'Uniform medium (SEEG)', ' | ', sprintf('Cond: %1.3f', OPTIONS.Conductivity)]; +end + %% ===== COMPUTE: BRAINSTORM HEADMODELS ===== Param = []; diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m new file mode 100644 index 000000000..55310e0cc --- /dev/null +++ b/toolbox/forward/bst_seeg_uni.m @@ -0,0 +1,70 @@ +function G = bst_seeg_uni(GridLoc, sChannel, sInnerSkull, Options) +% BST_EEG_SPH: Calculate the electric potential, spherical head, arbitrary orientation +% +% USAGE: G = bst_eeg_sph(Rq, Channel, center, R, sigma); +% +% INPUT: +% - GridLoc : dipole location(in meters) [nDipoles x 3] +% - Channel : a Brainstorm channel structure [nSensors] +% - sInnerSkull : Inner skull surface +% - Options structure +% - Options.sigma : conductivity +% - Options.minDistance : in meter + + % Add default options + Options = struct_copy_fields(struct('sigma', 0.25, 'minDistance', 3/1000), Options, 1); + min_distance = Options.minDistance; + sigma0 = Options.sigma; + + + NbElectrodes = length(sChannel); + NbVertices = size(GridLoc, 1); + + % Find electrodes that are inside the inner skull + SEEG_Loc = zeros(NbElectrodes, 3); + for iEEG = 1:NbElectrodes + SEEG_Loc(iEEG, :) = sChannel(iEEG).Loc; + end + isSEEGInsideSkull = inpolyhd(SEEG_Loc, sInnerSkull.Vertices, sInnerSkull.Faces); + + % Compute the leadfield + G = zeros(NbElectrodes , 3*NbVertices); + for iContact = 1:NbElectrodes + + if ~isSEEGInsideSkull(iContact) + continue + end + + VectorSEEGtoCortex = SEEG_Loc(iContact, :) - GridLoc; + DistanceToCortex = vecnorm(VectorSEEGtoCortex, 2, 2)'; + + % Filter short distance + iShort = find(DistanceToCortex < min_distance); + if ~isempty(iShort) + fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); + + + VectorSEEGtoCortex(iShort, 1) = ( VectorSEEGtoCortex(iShort, 1) ./ DistanceToCortex(iShort)') * min_distance; + VectorSEEGtoCortex(iShort, 2) = ( VectorSEEGtoCortex(iShort, 2) ./ DistanceToCortex(iShort)') * min_distance; + VectorSEEGtoCortex(iShort, 3) = ( VectorSEEGtoCortex(iShort, 3) ./ DistanceToCortex(iShort)') * min_distance; + + DistanceToCortex(iShort) = min_distance; + end + + % Normalize the vector + VectorSEEGtoCortex(:, 1) = ( VectorSEEGtoCortex(:, 1) ./ DistanceToCortex'); + VectorSEEGtoCortex(:, 2) = ( VectorSEEGtoCortex(:, 2) ./ DistanceToCortex'); + VectorSEEGtoCortex(:, 3) = ( VectorSEEGtoCortex(:, 3) ./ DistanceToCortex'); + + + % Compute the leadfiels + for ind_vert = 1:NbVertices + G(iContact, 3*(ind_vert-1) + 1) = dot([1, 0, 0], VectorSEEGtoCortex(ind_vert, :)) / DistanceToCortex(ind_vert)^2 ; + G(iContact, 3*(ind_vert-1) + 2) = dot([0, 1, 0], VectorSEEGtoCortex(ind_vert, :)) / DistanceToCortex(ind_vert)^2 ; + G(iContact, 3*(ind_vert-1) + 3) = dot([0, 0, 1], VectorSEEGtoCortex(ind_vert, :)) / DistanceToCortex(ind_vert)^2 ; + end + + % Add normalization constant + G = G / (4 * pi * sigma0); + end +end \ No newline at end of file From 21a656e11e7424df4249e367c20b84646d50f2b7 Mon Sep 17 00:00:00 2001 From: Edouard Date: Fri, 8 May 2026 20:45:26 -0400 Subject: [PATCH 02/16] improve code. Compute for x,y,z --- toolbox/forward/bst_seeg_uni.m | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index 55310e0cc..776e7012b 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -28,6 +28,7 @@ isSEEGInsideSkull = inpolyhd(SEEG_Loc, sInnerSkull.Vertices, sInnerSkull.Faces); % Compute the leadfield + bst_progress('start', 'Computing head model', sprintf('Computing head model for %d contacts...', NbElectrodes), 0, NbElectrodes); G = zeros(NbElectrodes , 3*NbVertices); for iContact = 1:NbElectrodes @@ -59,12 +60,16 @@ % Compute the leadfiels for ind_vert = 1:NbVertices - G(iContact, 3*(ind_vert-1) + 1) = dot([1, 0, 0], VectorSEEGtoCortex(ind_vert, :)) / DistanceToCortex(ind_vert)^2 ; - G(iContact, 3*(ind_vert-1) + 2) = dot([0, 1, 0], VectorSEEGtoCortex(ind_vert, :)) / DistanceToCortex(ind_vert)^2 ; - G(iContact, 3*(ind_vert-1) + 3) = dot([0, 0, 1], VectorSEEGtoCortex(ind_vert, :)) / DistanceToCortex(ind_vert)^2 ; + G(iContact, 3*(ind_vert-1) + 1) = VectorSEEGtoCortex(ind_vert, 1) / DistanceToCortex(ind_vert)^2 ; + G(iContact, 3*(ind_vert-1) + 2) = VectorSEEGtoCortex(ind_vert, 2) / DistanceToCortex(ind_vert)^2 ; + G(iContact, 3*(ind_vert-1) + 3) = VectorSEEGtoCortex(ind_vert, 3) / DistanceToCortex(ind_vert)^2 ; end - % Add normalization constant - G = G / (4 * pi * sigma0); + bst_progress('inc', 1); end + + % Add normalization constant + G = G / (4 * pi * sigma0); + + bst_progress('stop'); end \ No newline at end of file From f89fc16c8283bdbecc9e944f3ec565540828d2ce Mon Sep 17 00:00:00 2001 From: Edouard Date: Fri, 8 May 2026 21:07:05 -0400 Subject: [PATCH 03/16] Add the option on the panel --- toolbox/forward/panel_headmodel.m | 1 + 1 file changed, 1 insertion(+) diff --git a/toolbox/forward/panel_headmodel.m b/toolbox/forward/panel_headmodel.m index 21575109f..d3eb991da 100644 --- a/toolbox/forward/panel_headmodel.m +++ b/toolbox/forward/panel_headmodel.m @@ -121,6 +121,7 @@ jCheckMethodSEEG.setSelected(1); % Combobox jComboMethodSEEG = gui_component('ComboBox', jPanelMethod, 'tab hfill', [], [], [], @UpdateComment, []); + jComboMethodSEEG.addItem(BstListItem('uniform', '', 'Uniform medium', [])); jComboMethodSEEG.addItem(BstListItem('openmeeg', '', 'OpenMEEG BEM', [])); jComboMethodSEEG.addItem(BstListItem('duneuro', '', 'DUNEuro FEM', [])); jComboMethodSEEG.setSelectedIndex(0); From 9a6d906706488193a4672f58ba5e2871556a1f52 Mon Sep 17 00:00:00 2001 From: Edouard Date: Fri, 8 May 2026 21:07:12 -0400 Subject: [PATCH 04/16] simplify code --- toolbox/forward/bst_seeg_uni.m | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index 776e7012b..de76382a0 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -16,15 +16,11 @@ min_distance = Options.minDistance; sigma0 = Options.sigma; - NbElectrodes = length(sChannel); NbVertices = size(GridLoc, 1); % Find electrodes that are inside the inner skull - SEEG_Loc = zeros(NbElectrodes, 3); - for iEEG = 1:NbElectrodes - SEEG_Loc(iEEG, :) = sChannel(iEEG).Loc; - end + SEEG_Loc = [sChannel.Loc]'; isSEEGInsideSkull = inpolyhd(SEEG_Loc, sInnerSkull.Vertices, sInnerSkull.Faces); % Compute the leadfield @@ -37,33 +33,28 @@ end VectorSEEGtoCortex = SEEG_Loc(iContact, :) - GridLoc; - DistanceToCortex = vecnorm(VectorSEEGtoCortex, 2, 2)'; + DistanceToCortex = vecnorm(VectorSEEGtoCortex, 2, 2); % Filter short distance iShort = find(DistanceToCortex < min_distance); if ~isempty(iShort) fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); - - VectorSEEGtoCortex(iShort, 1) = ( VectorSEEGtoCortex(iShort, 1) ./ DistanceToCortex(iShort)') * min_distance; - VectorSEEGtoCortex(iShort, 2) = ( VectorSEEGtoCortex(iShort, 2) ./ DistanceToCortex(iShort)') * min_distance; - VectorSEEGtoCortex(iShort, 3) = ( VectorSEEGtoCortex(iShort, 3) ./ DistanceToCortex(iShort)') * min_distance; + VectorSEEGtoCortex(iShort, 1) = ( VectorSEEGtoCortex(iShort, 1) ./ DistanceToCortex(iShort)) * min_distance; + VectorSEEGtoCortex(iShort, 2) = ( VectorSEEGtoCortex(iShort, 2) ./ DistanceToCortex(iShort)) * min_distance; + VectorSEEGtoCortex(iShort, 3) = ( VectorSEEGtoCortex(iShort, 3) ./ DistanceToCortex(iShort)) * min_distance; DistanceToCortex(iShort) = min_distance; end % Normalize the vector - VectorSEEGtoCortex(:, 1) = ( VectorSEEGtoCortex(:, 1) ./ DistanceToCortex'); - VectorSEEGtoCortex(:, 2) = ( VectorSEEGtoCortex(:, 2) ./ DistanceToCortex'); - VectorSEEGtoCortex(:, 3) = ( VectorSEEGtoCortex(:, 3) ./ DistanceToCortex'); - + VectorSEEGtoCortex = VectorSEEGtoCortex(:, 1) ./ repmat(DistanceToCortex, 1, 3); + + % Compute the leadfield + scaledVector = VectorSEEGtoCortex ./ repmat(DistanceToCortex.^2, 1, 3); - % Compute the leadfiels - for ind_vert = 1:NbVertices - G(iContact, 3*(ind_vert-1) + 1) = VectorSEEGtoCortex(ind_vert, 1) / DistanceToCortex(ind_vert)^2 ; - G(iContact, 3*(ind_vert-1) + 2) = VectorSEEGtoCortex(ind_vert, 2) / DistanceToCortex(ind_vert)^2 ; - G(iContact, 3*(ind_vert-1) + 3) = VectorSEEGtoCortex(ind_vert, 3) / DistanceToCortex(ind_vert)^2 ; - end + % Organize the matrix as x,y,z + G(iContact, :) = reshape(scaledVector', 1, []); bst_progress('inc', 1); end From 47eb805647f54a76e6edb6db97ac430a822cd34f Mon Sep 17 00:00:00 2001 From: Edouard Date: Fri, 8 May 2026 21:11:38 -0400 Subject: [PATCH 05/16] bug fix... --- toolbox/forward/bst_seeg_uni.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index de76382a0..0c30098cd 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -48,7 +48,7 @@ end % Normalize the vector - VectorSEEGtoCortex = VectorSEEGtoCortex(:, 1) ./ repmat(DistanceToCortex, 1, 3); + VectorSEEGtoCortex = VectorSEEGtoCortex ./ repmat(DistanceToCortex, 1, 3); % Compute the leadfield scaledVector = VectorSEEGtoCortex ./ repmat(DistanceToCortex.^2, 1, 3); From f3883de73c4e7d606227c38c3589846464b93d34 Mon Sep 17 00:00:00 2001 From: Edouard Date: Fri, 8 May 2026 21:43:04 -0400 Subject: [PATCH 06/16] fix vector name --- toolbox/forward/bst_seeg_uni.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index 0c30098cd..de50ec5bf 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -32,26 +32,26 @@ continue end - VectorSEEGtoCortex = SEEG_Loc(iContact, :) - GridLoc; - DistanceToCortex = vecnorm(VectorSEEGtoCortex, 2, 2); + VectorCortexToSEEG = SEEG_Loc(iContact, :) - GridLoc; + DistanceToCortex = vecnorm(VectorCortexToSEEG, 2, 2); % Filter short distance iShort = find(DistanceToCortex < min_distance); if ~isempty(iShort) fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); - VectorSEEGtoCortex(iShort, 1) = ( VectorSEEGtoCortex(iShort, 1) ./ DistanceToCortex(iShort)) * min_distance; - VectorSEEGtoCortex(iShort, 2) = ( VectorSEEGtoCortex(iShort, 2) ./ DistanceToCortex(iShort)) * min_distance; - VectorSEEGtoCortex(iShort, 3) = ( VectorSEEGtoCortex(iShort, 3) ./ DistanceToCortex(iShort)) * min_distance; + VectorCortexToSEEG(iShort, 1) = ( VectorCortexToSEEG(iShort, 1) ./ DistanceToCortex(iShort)) * min_distance; + VectorCortexToSEEG(iShort, 2) = ( VectorCortexToSEEG(iShort, 2) ./ DistanceToCortex(iShort)) * min_distance; + VectorCortexToSEEG(iShort, 3) = ( VectorCortexToSEEG(iShort, 3) ./ DistanceToCortex(iShort)) * min_distance; DistanceToCortex(iShort) = min_distance; end % Normalize the vector - VectorSEEGtoCortex = VectorSEEGtoCortex ./ repmat(DistanceToCortex, 1, 3); + VectorCortexToSEEG = VectorCortexToSEEG ./ repmat(DistanceToCortex, 1, 3); % Compute the leadfield - scaledVector = VectorSEEGtoCortex ./ repmat(DistanceToCortex.^2, 1, 3); + scaledVector = VectorCortexToSEEG ./ repmat(DistanceToCortex.^2, 1, 3); % Organize the matrix as x,y,z G(iContact, :) = reshape(scaledVector', 1, []); From 929286c362a45c1147a44d4b59f8b33b3e75d8e4 Mon Sep 17 00:00:00 2001 From: Edouard Date: Fri, 8 May 2026 23:09:10 -0400 Subject: [PATCH 07/16] Add documentation --- toolbox/forward/bst_seeg_uni.m | 43 ++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index de50ec5bf..0b760fbed 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -1,7 +1,7 @@ function G = bst_seeg_uni(GridLoc, sChannel, sInnerSkull, Options) -% BST_EEG_SPH: Calculate the electric potential, spherical head, arbitrary orientation +% bst_seeg_uni: Calculate the electric potential, spherical head, arbitrary orientation % -% USAGE: G = bst_eeg_sph(Rq, Channel, center, R, sigma); +% USAGE: G = bst_eeg_sph(GridLoc, sChannel, sInnerSkull, Options); % % INPUT: % - GridLoc : dipole location(in meters) [nDipoles x 3] @@ -10,6 +10,45 @@ % - Options structure % - Options.sigma : conductivity % - Options.minDistance : in meter +% OUTPUTS: +% - G : EEG forward model gain matrix [nSensors x (3*nDipoles)] +% +% DESCRIPTION: sEEG single layer forward model +% This function computes the voltage potential forward gain matrix for an array of +% sEEG electrodes inside the brain. The conductivity is assumed to be uniform and isotropoic +% inside the nedium (that is assumed to be infinite). +% +% For electrodes outside of the brain, the grain is set to 0. +% +% Ref: +% + Grova, C., Aiguabella, M., Zelmann, R., Lina, J.-M., Hall, J.A. and Kobayashi, E. (2016), +% Intracranial EEG potentials estimated from MEG sources: A new approach to correlate MEG and iEEG data in epilepsy. +% Hum. Brain Mapp., 37: 1661-1683. https://doi.org/10.1002/hbm.23127 +% +% + Næss, S., Halnes, G., Hagen, E., Hagler Jr, D. J., Dale, A. M., Einevoll, G. T., & Ness, T. V. (2021). +% Biophysically detailed forward modeling of the neural origin of EEG and MEG signals. NeuroImage, 225, 117467. +% + +% @============================================================================= +% This function is part of the Brainstorm software: +% https://neuroimage.usc.edu/brainstorm +% +% Copyright (c) University of Southern California & McGill University +% This software is distributed under the terms of the GNU General Public License +% as published by the Free Software Foundation. Further details on the GPLv3 +% license can be found at http://www.gnu.org/copyleft/gpl.html. +% +% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE +% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY +% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY +% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE. +% +% For more information type "brainstorm license" at command prompt. +% =============================================================================@ +% +% Authors: Edouard Delaire (2026) + % Add default options Options = struct_copy_fields(struct('sigma', 0.25, 'minDistance', 3/1000), Options, 1); From d1d9b605ae43b5e9a214965e5a7d74119f38300b Mon Sep 17 00:00:00 2001 From: Edouard Date: Sun, 10 May 2026 20:24:31 -0400 Subject: [PATCH 08/16] simplify code --- toolbox/forward/bst_seeg_uni.m | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index 0b760fbed..112c3356e 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -74,21 +74,16 @@ VectorCortexToSEEG = SEEG_Loc(iContact, :) - GridLoc; DistanceToCortex = vecnorm(VectorCortexToSEEG, 2, 2); + % Normalize the vector + VectorCortexToSEEG = VectorCortexToSEEG ./ repmat(DistanceToCortex, 1, 3); + % Filter short distance iShort = find(DistanceToCortex < min_distance); if ~isempty(iShort) - fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); - - VectorCortexToSEEG(iShort, 1) = ( VectorCortexToSEEG(iShort, 1) ./ DistanceToCortex(iShort)) * min_distance; - VectorCortexToSEEG(iShort, 2) = ( VectorCortexToSEEG(iShort, 2) ./ DistanceToCortex(iShort)) * min_distance; - VectorCortexToSEEG(iShort, 3) = ( VectorCortexToSEEG(iShort, 3) ./ DistanceToCortex(iShort)) * min_distance; - + fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); DistanceToCortex(iShort) = min_distance; end - % Normalize the vector - VectorCortexToSEEG = VectorCortexToSEEG ./ repmat(DistanceToCortex, 1, 3); - % Compute the leadfield scaledVector = VectorCortexToSEEG ./ repmat(DistanceToCortex.^2, 1, 3); From 069580f3ee1720389c74d2cde087eb3e8adb9f2b Mon Sep 17 00:00:00 2001 From: Edouard Date: Sun, 10 May 2026 20:41:02 -0400 Subject: [PATCH 09/16] Fix vector name When considereing volume model, the dipole is not always inside the cortex --- toolbox/forward/bst_seeg_uni.m | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index 112c3356e..3a8ee49a2 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -49,7 +49,6 @@ % % Authors: Edouard Delaire (2026) - % Add default options Options = struct_copy_fields(struct('sigma', 0.25, 'minDistance', 3/1000), Options, 1); min_distance = Options.minDistance; @@ -71,21 +70,21 @@ continue end - VectorCortexToSEEG = SEEG_Loc(iContact, :) - GridLoc; - DistanceToCortex = vecnorm(VectorCortexToSEEG, 2, 2); + VectorDipolesToSEEG = SEEG_Loc(iContact, :) - GridLoc; + DistanceToDipoles = vecnorm(VectorDipolesToSEEG, 2, 2); % Normalize the vector - VectorCortexToSEEG = VectorCortexToSEEG ./ repmat(DistanceToCortex, 1, 3); + VectorDipolesToSEEG = VectorDipolesToSEEG ./ repmat(DistanceToDipoles, 1, 3); % Filter short distance - iShort = find(DistanceToCortex < min_distance); + iShort = find(DistanceToDipoles < min_distance); if ~isempty(iShort) fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); - DistanceToCortex(iShort) = min_distance; + DistanceToDipoles(iShort) = min_distance; end % Compute the leadfield - scaledVector = VectorCortexToSEEG ./ repmat(DistanceToCortex.^2, 1, 3); + scaledVector = VectorDipolesToSEEG ./ repmat(DistanceToDipoles.^2, 1, 3); % Organize the matrix as x,y,z G(iContact, :) = reshape(scaledVector', 1, []); From 2b3458f9c532f3c2e0b7d0b952f1a834d0b93fd7 Mon Sep 17 00:00:00 2001 From: Edouard Date: Mon, 11 May 2026 19:29:10 -0400 Subject: [PATCH 10/16] wip -- add options --- toolbox/forward/bst_headmodeler.m | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/toolbox/forward/bst_headmodeler.m b/toolbox/forward/bst_headmodeler.m index 581fbdfc6..542a37e8e 100644 --- a/toolbox/forward/bst_headmodeler.m +++ b/toolbox/forward/bst_headmodeler.m @@ -539,7 +539,29 @@ %% ===== COMPUTE: SEEG UNIFORM HEADMODELS ===== if strcmp('uniform', OPTIONS.SEEGMethod) - Gain(iSeeg, :) = bst_seeg_uni(OPTIONS.GridLoc, OPTIONS.Channel(iSeeg), sSurfInner, []); + if ~isfield(OPTIONS, 'sigma') || ~isfield(OPTIONS, 'minDistance') + % Get options + prompt = {'Brain conductivity (S/m):','Minimum distance between SEEG and dipoles (mm):'}; + sOptions = inputdlg(prompt, 'SEEG head model options', [1 45; 1 45], {'0.25','3'}); + + if isempty(sOptions) + errMessage = 'Canceled by user.'; + OPTIONS = []; + return; + end + + try + OPTIONS.sigma = str2double(sOptions{1}); + catch + end + + try + OPTIONS.minDistance = str2double(sOptions{2}) / 1000; + catch + end + end + + Gain(iSeeg, :) = bst_seeg_uni(OPTIONS.GridLoc, OPTIONS.Channel(iSeeg), sSurfInner, OPTIONS); strHistory = [strHistory, ' | ', 'Uniform medium (SEEG)', ' | ', sprintf('Cond: %1.3f', OPTIONS.Conductivity)]; end From a4504613927e244b7b0069c2c286cd9e06864bb5 Mon Sep 17 00:00:00 2001 From: Edouard Date: Mon, 11 May 2026 20:16:07 -0400 Subject: [PATCH 11/16] use java_dialogs --- toolbox/forward/bst_headmodeler.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toolbox/forward/bst_headmodeler.m b/toolbox/forward/bst_headmodeler.m index 542a37e8e..98bb48d8d 100644 --- a/toolbox/forward/bst_headmodeler.m +++ b/toolbox/forward/bst_headmodeler.m @@ -540,9 +540,10 @@ if strcmp('uniform', OPTIONS.SEEGMethod) if ~isfield(OPTIONS, 'sigma') || ~isfield(OPTIONS, 'minDistance') + % Get options prompt = {'Brain conductivity (S/m):','Minimum distance between SEEG and dipoles (mm):'}; - sOptions = inputdlg(prompt, 'SEEG head model options', [1 45; 1 45], {'0.25','3'}); + sOptions = java_dialog('input', prompt, 'SEEG head model options', [], {'0.25','3'}); if isempty(sOptions) errMessage = 'Canceled by user.'; From 2be782b86e8da628b503f667f56800147f590a22 Mon Sep 17 00:00:00 2001 From: rcassani Date: Tue, 26 May 2026 13:45:57 -0400 Subject: [PATCH 12/16] Move interaction to `panel_headmodel.m` --- toolbox/forward/bst_headmodeler.m | 24 ---------------------- toolbox/forward/bst_seeg_uni.m | 10 ++++----- toolbox/forward/panel_headmodel.m | 34 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/toolbox/forward/bst_headmodeler.m b/toolbox/forward/bst_headmodeler.m index 98bb48d8d..03558fb61 100644 --- a/toolbox/forward/bst_headmodeler.m +++ b/toolbox/forward/bst_headmodeler.m @@ -538,30 +538,6 @@ %% ===== COMPUTE: SEEG UNIFORM HEADMODELS ===== if strcmp('uniform', OPTIONS.SEEGMethod) - - if ~isfield(OPTIONS, 'sigma') || ~isfield(OPTIONS, 'minDistance') - - % Get options - prompt = {'Brain conductivity (S/m):','Minimum distance between SEEG and dipoles (mm):'}; - sOptions = java_dialog('input', prompt, 'SEEG head model options', [], {'0.25','3'}); - - if isempty(sOptions) - errMessage = 'Canceled by user.'; - OPTIONS = []; - return; - end - - try - OPTIONS.sigma = str2double(sOptions{1}); - catch - end - - try - OPTIONS.minDistance = str2double(sOptions{2}) / 1000; - catch - end - end - Gain(iSeeg, :) = bst_seeg_uni(OPTIONS.GridLoc, OPTIONS.Channel(iSeeg), sSurfInner, OPTIONS); strHistory = [strHistory, ' | ', 'Uniform medium (SEEG)', ' | ', sprintf('Cond: %1.3f', OPTIONS.Conductivity)]; end diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index 3a8ee49a2..fe198fe99 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -8,8 +8,8 @@ % - Channel : a Brainstorm channel structure [nSensors] % - sInnerSkull : Inner skull surface % - Options structure -% - Options.sigma : conductivity -% - Options.minDistance : in meter +% - Options.Conductivity : Conductivity (S/m) +% - Options.MinSeegDipoleDist : Minimum distance between SEEG and dipoles % OUTPUTS: % - G : EEG forward model gain matrix [nSensors x (3*nDipoles)] % @@ -50,9 +50,9 @@ % Authors: Edouard Delaire (2026) % Add default options - Options = struct_copy_fields(struct('sigma', 0.25, 'minDistance', 3/1000), Options, 1); - min_distance = Options.minDistance; - sigma0 = Options.sigma; + Options = struct_copy_fields(struct('Conductivity', 0.25, 'MinSeegDipoleDist', 3/1000), Options, 1); + min_distance = Options.MinSeegDipoleDist; + sigma0 = Options.Conductivity; NbElectrodes = length(sChannel); NbVertices = size(GridLoc, 1); diff --git a/toolbox/forward/panel_headmodel.m b/toolbox/forward/panel_headmodel.m index d3eb991da..38c7c767d 100644 --- a/toolbox/forward/panel_headmodel.m +++ b/toolbox/forward/panel_headmodel.m @@ -438,6 +438,7 @@ function UpdateComment(varargin) sMethod.Comment = strrep(sMethod.Comment, 'os_meg', 'Overlapping spheres'); sMethod.Comment = strrep(sMethod.Comment, 'meg_sphere', 'Single sphere'); sMethod.Comment = strrep(sMethod.Comment, 'eeg_3sphereberg', '3-shell sphere'); + sMethod.Comment = strrep(sMethod.Comment, 'uniform', 'Uniform medium'); sMethod.Comment = strrep(sMethod.Comment, 'openmeeg', 'OpenMEEG BEM'); sMethod.Comment = strrep(sMethod.Comment, 'duneuro', 'DUNEuro FEM'); % Grid type @@ -447,6 +448,7 @@ function UpdateComment(varargin) sMethod.Comment = [sMethod.Comment ' (mixed)']; end end + isUniform = any(strcmpi(allMethods, 'uniform')); isOpenMEEG = any(strcmpi(allMethods, 'openmeeg')); isDuneuro = any(strcmpi(allMethods, 'duneuro')); % Get protocol description @@ -598,6 +600,38 @@ function UpdateComment(varargin) bst_error('Please import a cortex surface for this subject.', 'Head model', 0); return end + + % ===== UNIFORM ===== + if isUniform + % Interactive interface to set the OpenMEEG options + if OPTIONS.Interactive + OPTIONS.Conductivity = []; + OPTIONS.MinSeegDipoleDist = []; + % Get options + optionsStr = {'Brain conductivity (S/m):','Minimum distance between SEEG and dipoles (mm):'}; + res = java_dialog('input', optionsStr, 'SEEG head model options', [], {'0.25','3'}); + if isempty(res) + return + end + resDouble = str2double(res); + % Validate inputs + for iRes = 1 : length(resDouble) + if isnan(resDouble(iRes)) + errMessage = sprintf('Invalid input "%s" for option:\n%s', res{iRes}, optionsStr{iRes}); + return + end + end + OPTIONS.Conductivity = resDouble(1); + OPTIONS.MinSeegDipoleDist = resDouble(2)/1000; + end + % Check that inner skull exists + if ~isempty(sSubject.iInnerSkull) + OPTIONS.InnerSkullFile = file_fullpath(sSubject.Surface(sSubject.iInnerSkull(1)).FileName); + else + errMessage = 'No inner skull surface for this subject.'; + return + end + end % ===== OPENMEEG ===== if isOpenMEEG From 4636f0857dea46b834a385f8b792b65c9129f90c Mon Sep 17 00:00:00 2001 From: rcassani Date: Tue, 26 May 2026 13:52:58 -0400 Subject: [PATCH 13/16] Add all parameters to `History` --- toolbox/forward/bst_headmodeler.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/toolbox/forward/bst_headmodeler.m b/toolbox/forward/bst_headmodeler.m index 03558fb61..c5137ad70 100644 --- a/toolbox/forward/bst_headmodeler.m +++ b/toolbox/forward/bst_headmodeler.m @@ -539,10 +539,11 @@ %% ===== COMPUTE: SEEG UNIFORM HEADMODELS ===== if strcmp('uniform', OPTIONS.SEEGMethod) Gain(iSeeg, :) = bst_seeg_uni(OPTIONS.GridLoc, OPTIONS.Channel(iSeeg), sSurfInner, OPTIONS); - strHistory = [strHistory, ' | ', 'Uniform medium (SEEG)', ' | ', sprintf('Cond: %1.3f', OPTIONS.Conductivity)]; + strHistory = [strHistory, ' | ', 'Uniform medium (SEEG)', ... + ' | ', sprintf('Conductivity: %1.3f S/m', OPTIONS.Conductivity), ... + ' | ', sprintf('Min dist. betweem SEEG contact and dipoles: %1.3f mm', OPTIONS.MinSeegDipoleDist)]; end - %% ===== COMPUTE: BRAINSTORM HEADMODELS ===== Param = []; if (~isempty(OPTIONS.MEGMethod) && ~ismember(OPTIONS.MEGMethod, {'openmeeg', 'duneuro'})) || ... From 19047a083ddeb14acb2c0bbd8f732fe8dc6f23ac Mon Sep 17 00:00:00 2001 From: rcassani Date: Tue, 26 May 2026 13:53:41 -0400 Subject: [PATCH 14/16] Update help string `bst_seeg_uni` --- toolbox/forward/bst_seeg_uni.m | 48 ++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_uni.m index fe198fe99..f9301e99d 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_uni.m @@ -1,22 +1,22 @@ function G = bst_seeg_uni(GridLoc, sChannel, sInnerSkull, Options) -% bst_seeg_uni: Calculate the electric potential, spherical head, arbitrary orientation +% bst_seeg_uni: Calculate the electric potential for infinite homogeneous medium % -% USAGE: G = bst_eeg_sph(GridLoc, sChannel, sInnerSkull, Options); +% USAGE: G = bst_seeg_uni(GridLoc, sChannel, sInnerSkull, Options) % % INPUT: -% - GridLoc : dipole location(in meters) [nDipoles x 3] -% - Channel : a Brainstorm channel structure [nSensors] -% - sInnerSkull : Inner skull surface +% - GridLoc : Dipole locations (in meters) [nDipoles x 3] +% - sChannel : Channel structure [nSensors] +% - sInnerSkull : Inner skull surface structure % - Options structure % - Options.Conductivity : Conductivity (S/m) % - Options.MinSeegDipoleDist : Minimum distance between SEEG and dipoles % OUTPUTS: -% - G : EEG forward model gain matrix [nSensors x (3*nDipoles)] +% - G : SEEG forward model gain matrix [nSensors x (3*nDipoles)] % % DESCRIPTION: sEEG single layer forward model % This function computes the voltage potential forward gain matrix for an array of % sEEG electrodes inside the brain. The conductivity is assumed to be uniform and isotropoic -% inside the nedium (that is assumed to be infinite). +% inside the medium (that is assumed to be infinite). % % For electrodes outside of the brain, the grain is set to 0. % @@ -28,6 +28,21 @@ % + Næss, S., Halnes, G., Hagen, E., Hagler Jr, D. J., Dale, A. M., Einevoll, G. T., & Ness, T. V. (2021). % Biophysically detailed forward modeling of the neural origin of EEG and MEG signals. NeuroImage, 225, 117467. % +% dot(n_i, u_ij) +% V(E_j) = -------------------------- +% 4 * pi * sigma0 * (r_ij)^2 +% +% V(E_j) = Electric potential at sensor j +% n_i = Vector, current dipole for source i +% u_ij = Unit vector, oriented from source i to sensor j +% sigma0 = Conductivity of infinite homogeneous medium +% r_ij = Euclidean distance between source i and sensor j +% +% Written as matrix multiplication: V = G * N +% V = Electric potential at contacts [nSensors, nTime] +% G = Gain matrix [nSensors, nDipoles] +% N = Dipole activation currents [nDipoles, nTime] +% % @============================================================================= % This function is part of the Brainstorm software: @@ -47,7 +62,7 @@ % For more information type "brainstorm license" at command prompt. % =============================================================================@ % -% Authors: Edouard Delaire (2026) +% Authors: Edouard Delaire, 2026 % Add default options Options = struct_copy_fields(struct('Conductivity', 0.25, 'MinSeegDipoleDist', 3/1000), Options, 1); @@ -64,26 +79,25 @@ % Compute the leadfield bst_progress('start', 'Computing head model', sprintf('Computing head model for %d contacts...', NbElectrodes), 0, NbElectrodes); G = zeros(NbElectrodes , 3*NbVertices); - for iContact = 1:NbElectrodes - + for iContact = 1:NbElectrodes + % Ignore contacts outside of the inner skull if ~isSEEGInsideSkull(iContact) continue end - VectorDipolesToSEEG = SEEG_Loc(iContact, :) - GridLoc; - DistanceToDipoles = vecnorm(VectorDipolesToSEEG, 2, 2); - - % Normalize the vector + % Compute unit vectors from SEEG contact to source points (u_j) + VectorDipolesToSEEG = SEEG_Loc(iContact, :) - GridLoc; + DistanceToDipoles = sqrt(sum(VectorDipolesToSEEG.^2,2)); VectorDipolesToSEEG = VectorDipolesToSEEG ./ repmat(DistanceToDipoles, 1, 3); % Filter short distance - iShort = find(DistanceToDipoles < min_distance); + iShort = find(DistanceToDipoles < min_distance); if ~isempty(iShort) fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); - DistanceToDipoles(iShort) = min_distance; + DistanceToDipoles(iShort) = min_distance; end - % Compute the leadfield + % Compute the leadfield (u_j / (r_j)^2) scaledVector = VectorDipolesToSEEG ./ repmat(DistanceToDipoles.^2, 1, 3); % Organize the matrix as x,y,z From e9285289645879d0c02a2a29786459e2564b003f Mon Sep 17 00:00:00 2001 From: rcassani Date: Wed, 27 May 2026 11:44:59 -0400 Subject: [PATCH 15/16] Rename `uniform` to `homogeneous` --- toolbox/forward/bst_headmodeler.m | 17 +++++++++++------ .../{bst_seeg_uni.m => bst_seeg_homogeneous.m} | 6 +++--- toolbox/forward/panel_headmodel.m | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) rename toolbox/forward/{bst_seeg_uni.m => bst_seeg_homogeneous.m} (95%) diff --git a/toolbox/forward/bst_headmodeler.m b/toolbox/forward/bst_headmodeler.m index c5137ad70..9af1a6298 100644 --- a/toolbox/forward/bst_headmodeler.m +++ b/toolbox/forward/bst_headmodeler.m @@ -22,8 +22,13 @@ % .EEGMethod: Method used to compute the forward model for EEG sensors. % - 'eeg_3sphereberg' : EEG forward modeling with a set of 3 concentric spheres (Scalp, Skull, Brain/CSF) % - 'openmeeg' : OpenMEEG forward model -% .SEEGMethod: 'uniform', 'openmeeg' and 'duneuro' -% .ECOGMethod: 'openmeeg' and 'duneuro' +% .SEEGMethod: Method used to compute the forward model for SEEG sensors. +% - 'homogeneous' : Infinite homogeneous medium +% - 'openmeeg' : OpenMEEG forward model +% - 'duneuro' : DUNEuro forward model +% .ECOGMethod: Method used to compute the forward model for ECOG sensors. +% - 'openmeeg' : OpenMEEG forward model +% - 'duneuro' : DUNEuro forward model % .NIRSMethod: 'import' % % ======= METHODS OPTIONS ============================================= @@ -536,10 +541,10 @@ Gain(~isnan(Gain_dn)) = Gain_dn(~isnan(Gain_dn)); end -%% ===== COMPUTE: SEEG UNIFORM HEADMODELS ===== -if strcmp('uniform', OPTIONS.SEEGMethod) - Gain(iSeeg, :) = bst_seeg_uni(OPTIONS.GridLoc, OPTIONS.Channel(iSeeg), sSurfInner, OPTIONS); - strHistory = [strHistory, ' | ', 'Uniform medium (SEEG)', ... +%% ===== COMPUTE: SEEG INFINITE HOMOGENEOUS MEDIUM HEADMODEL ===== +if strcmp('homogeneous', OPTIONS.SEEGMethod) + Gain(iSeeg, :) = bst_seeg_homogeneous(OPTIONS.GridLoc, OPTIONS.Channel(iSeeg), sSurfInner, OPTIONS); + strHistory = [strHistory, ' | ', 'Homogeneous medium (SEEG)', ... ' | ', sprintf('Conductivity: %1.3f S/m', OPTIONS.Conductivity), ... ' | ', sprintf('Min dist. betweem SEEG contact and dipoles: %1.3f mm', OPTIONS.MinSeegDipoleDist)]; end diff --git a/toolbox/forward/bst_seeg_uni.m b/toolbox/forward/bst_seeg_homogeneous.m similarity index 95% rename from toolbox/forward/bst_seeg_uni.m rename to toolbox/forward/bst_seeg_homogeneous.m index f9301e99d..53aadb534 100644 --- a/toolbox/forward/bst_seeg_uni.m +++ b/toolbox/forward/bst_seeg_homogeneous.m @@ -1,7 +1,7 @@ -function G = bst_seeg_uni(GridLoc, sChannel, sInnerSkull, Options) -% bst_seeg_uni: Calculate the electric potential for infinite homogeneous medium +function G = bst_seeg_homogeneous(GridLoc, sChannel, sInnerSkull, Options) +% bst_seeg_homogeneous: Calculate the electric potential for infinite homogeneous medium % -% USAGE: G = bst_seeg_uni(GridLoc, sChannel, sInnerSkull, Options) +% USAGE: G = bst_seeg_homogeneous(GridLoc, sChannel, sInnerSkull, Options) % % INPUT: % - GridLoc : Dipole locations (in meters) [nDipoles x 3] diff --git a/toolbox/forward/panel_headmodel.m b/toolbox/forward/panel_headmodel.m index 38c7c767d..d70ad294c 100644 --- a/toolbox/forward/panel_headmodel.m +++ b/toolbox/forward/panel_headmodel.m @@ -121,7 +121,7 @@ jCheckMethodSEEG.setSelected(1); % Combobox jComboMethodSEEG = gui_component('ComboBox', jPanelMethod, 'tab hfill', [], [], [], @UpdateComment, []); - jComboMethodSEEG.addItem(BstListItem('uniform', '', 'Uniform medium', [])); + jComboMethodSEEG.addItem(BstListItem('homogeneous', '', 'Homogeneous medium', [])); jComboMethodSEEG.addItem(BstListItem('openmeeg', '', 'OpenMEEG BEM', [])); jComboMethodSEEG.addItem(BstListItem('duneuro', '', 'DUNEuro FEM', [])); jComboMethodSEEG.setSelectedIndex(0); @@ -438,7 +438,7 @@ function UpdateComment(varargin) sMethod.Comment = strrep(sMethod.Comment, 'os_meg', 'Overlapping spheres'); sMethod.Comment = strrep(sMethod.Comment, 'meg_sphere', 'Single sphere'); sMethod.Comment = strrep(sMethod.Comment, 'eeg_3sphereberg', '3-shell sphere'); - sMethod.Comment = strrep(sMethod.Comment, 'uniform', 'Uniform medium'); + sMethod.Comment = strrep(sMethod.Comment, 'homogeneous', 'Homogeneous medium'); sMethod.Comment = strrep(sMethod.Comment, 'openmeeg', 'OpenMEEG BEM'); sMethod.Comment = strrep(sMethod.Comment, 'duneuro', 'DUNEuro FEM'); % Grid type @@ -448,7 +448,7 @@ function UpdateComment(varargin) sMethod.Comment = [sMethod.Comment ' (mixed)']; end end - isUniform = any(strcmpi(allMethods, 'uniform')); + isHomogeneous = any(strcmpi(allMethods, 'homogeneous')); isOpenMEEG = any(strcmpi(allMethods, 'openmeeg')); isDuneuro = any(strcmpi(allMethods, 'duneuro')); % Get protocol description @@ -601,9 +601,9 @@ function UpdateComment(varargin) return end - % ===== UNIFORM ===== - if isUniform - % Interactive interface to set the OpenMEEG options + % ===== INFINITE HOMOGENEOUS MEDIUM ===== + if isHomogeneous + % Interactive interface to set the options if OPTIONS.Interactive OPTIONS.Conductivity = []; OPTIONS.MinSeegDipoleDist = []; From 489b56d7f7a27d524786e289e4eec968cf3d0b58 Mon Sep 17 00:00:00 2001 From: Raymundo Cassani Date: Wed, 27 May 2026 13:15:16 -0400 Subject: [PATCH 16/16] Add comment explaining dist replacement, remove msg --- toolbox/forward/bst_seeg_homogeneous.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/toolbox/forward/bst_seeg_homogeneous.m b/toolbox/forward/bst_seeg_homogeneous.m index 53aadb534..c56ecf56f 100644 --- a/toolbox/forward/bst_seeg_homogeneous.m +++ b/toolbox/forward/bst_seeg_homogeneous.m @@ -90,10 +90,10 @@ DistanceToDipoles = sqrt(sum(VectorDipolesToSEEG.^2,2)); VectorDipolesToSEEG = VectorDipolesToSEEG ./ repmat(DistanceToDipoles, 1, 3); - % Filter short distance + % Replace short distance (< 'min_distance') with 'min_distance' to prevent instabilities in the model by too close measurements iShort = find(DistanceToDipoles < min_distance); if ~isempty(iShort) - fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); + % fprintf(' %d vertex had distance to the cortex smaller than %.2f mm to electrodes %s \n', length(iShort), min_distance*1000, sChannel(iContact).Name); DistanceToDipoles(iShort) = min_distance; end @@ -110,4 +110,4 @@ G = G / (4 * pi * sigma0); bst_progress('stop'); -end \ No newline at end of file +end