From 2cf62e02ea8edb898238efdca28ecd2dc5b2e0c5 Mon Sep 17 00:00:00 2001 From: ftadel Date: Tue, 9 Nov 2021 11:42:06 +0100 Subject: [PATCH] Ephys: DeriveLFP now available as a plugin and in the compiled distribution --- doc/updates.txt | 1 + toolbox/core/bst_plugin.m | 64 ++++++++++++++++--- toolbox/db/db_template.m | 1 + .../functions/process_convert_raw_to_lfp.m | 59 ++--------------- 4 files changed, 65 insertions(+), 60 deletions(-) diff --git a/doc/updates.txt b/doc/updates.txt index a73984fab..2c45d4e92 100644 --- a/doc/updates.txt +++ b/doc/updates.txt @@ -1,5 +1,6 @@ -------------------------------------------------------------- November 2021 +- Ephys: DeriveLFP now available as a plugin and in the compiled distribution - GUI: 3D MRI display: Moving slice by clicking on it - GUI: Automatic registration reports the distance headpoints/scalp -------------------------------------------------------------- diff --git a/toolbox/core/bst_plugin.m b/toolbox/core/bst_plugin.m index 310d80a1f..906a537fc 100644 --- a/toolbox/core/bst_plugin.m +++ b/toolbox/core/bst_plugin.m @@ -69,7 +69,8 @@ % - InstalledFcn : String to eval or function handle to call after installing the plugin % - UninstalledFcn : String to eval or function handle to call after uninstalling the plugin % - LoadedFcn : String to eval or function handle to call after loading the plugin -% - UnloadedFcn : String to eval or function handle to call after unloading the plugin +% - UnloadedFcn : String to eval or function handle to call after unloading the plugin +% - DeleteFiles : List of files to delete after installation % % Fields set when installing the plugin % ===================================== @@ -173,7 +174,7 @@ PlugDesc(end).CompiledStatus = 0; PlugDesc(end).UnloadPlugs = {'spm12', 'iso2mesh'}; PlugDesc(end).LoadFolders = {'lib/spm12', 'lib/iso2mesh', 'lib/cvx', 'lib/ncs2daprox', 'lib/NIFTI_20110921'}; - + % === FORWARD: OPENMEEG === PlugDesc(end+1) = GetStruct('openmeeg'); PlugDesc(end).Version = '2.4.1'; @@ -339,6 +340,19 @@ PlugDesc(end).LoadFolders = {'*'}; PlugDesc(end).InstalledFcn = 'd=pwd; cd(fileparts(which(''make''))); make; cd(d);'; + % === ELECTROPHYSIOLOGY: DERIVELFP === + PlugDesc(end+1) = GetStruct('derivelfp'); + PlugDesc(end).Version = '1.0'; + PlugDesc(end).Category = 'e-phys'; + PlugDesc(end).AutoUpdate = 0; + PlugDesc(end).URLzip = 'http://packlab.mcgill.ca/despikingtoolbox.zip'; + PlugDesc(end).URLinfo = 'https://journals.physiology.org/doi/full/10.1152/jn.00642.2010'; + PlugDesc(end).TestFile = 'despikeLFP.m'; + PlugDesc(end).ReadmeFile = 'readme.txt'; + PlugDesc(end).CompiledStatus = 2; + PlugDesc(end).LoadFolders = {'toolbox'}; + PlugDesc(end).DeleteFiles = {'ExampleDespiking.m', 'appendixpaper.pdf', 'downsample2x.m', 'examplelfpdespiking.mat', 'sta.m'}; + % === NIRSTORM === PlugDesc(end+1) = GetStruct('nirstorm'); PlugDesc(end).Version = 'github-master'; @@ -733,22 +747,35 @@ function Configure(PlugDesc) % Compiled: do not look for unreferenced plugins if isCompiled PlugList = []; - % Get folders in Brainstorm user folder + % Get a specific unlisted plugin elseif ~isempty(SelPlug) + % Get plugin name if ischar(SelPlug) - PlugList = dir(bst_fullfile(UserPluginsDir, SelPlug)); + PlugName = SelPlug; + else + PlugName = SelPlug.Name; + end + % If plugin is already referenced: skip + if ismember(PlugName, {PlugDesc.Name}) + PlugList = []; + % Else: Try to get target plugin as unreferenced else - PlugList = dir(bst_fullfile(UserPluginsDir, SelPlug.Name)); + PlugList = struct('name', SelPlug); end + % Get all folders in Brainstorm plugins folder else PlugList = dir(UserPluginsDir); end % Process folders containing a plugin.mat file for iDir = 1:length(PlugList) - % Process only folders containing a 'plugin.mat' file and not already referenced + % Process only folders PlugDir = bst_fullfile(UserPluginsDir, PlugList(iDir).name); + if ~isdir(PlugDir) || (PlugList(iDir).name(1) == '.') + continue; + end + % Process only folders containing a 'plugin.mat' file PlugMatFile = bst_fullfile(PlugDir, 'plugin.mat'); - if ~isdir(PlugDir) || (PlugList(iDir).name(1) == '.') || ~file_exist(PlugMatFile) || ismember(PlugList(iDir).name, {PlugDesc.Name}) + if ~file_exist(PlugMatFile) continue; end % If selecting only one plugin @@ -1169,7 +1196,8 @@ function Configure(PlugDesc) end end file_delete(pkgFile, 1, 3); - % Save plugin.mat + + % === SAVE PLUGIN.MAT === PlugDesc.Path = PlugPath; PlugMatFile = bst_fullfile(PlugDesc.Path, 'plugin.mat'); excludedFields = {'LoadedFcn', 'UnloadedFcn', 'InstalledFcn', 'UninstalledFcn', 'Path', 'isLoaded', 'isManaged'}; @@ -1200,6 +1228,26 @@ function Configure(PlugDesc) PlugDescSave = rmfield(PlugDesc, excludedFields); bst_save(PlugMatFile, PlugDescSave, 'v6'); + % === DELETE UNWANTED FILES === + if ~isempty(PlugDesc.DeleteFiles) && iscell(PlugDesc.DeleteFiles) + for iDel = 1:length(PlugDesc.DeleteFiles) + if ~isempty(PlugDesc.SubFolder) + fileDel = bst_fullfile(PlugDesc.Path, PlugDesc.SubFolder, PlugDesc.DeleteFiles{iDel}); + else + fileDel = bst_fullfile(PlugDesc.Path, PlugDesc.DeleteFiles{iDel}); + end + if file_exist(fileDel) + try + file_delete(fileDel, 1, 3); + catch + disp(['BST> Plugin ' PlugName ': Could not delete file: ' PlugDesc.DeleteFiles{iDel}]); + end + else + disp(['BST> Plugin ' PlugName ': Missing file: ' PlugDesc.DeleteFiles{iDel}]); + end + end + end + % === CALLBACK: POST-INSTALL === [isOk, errMsg] = ExecuteCallback(PlugDesc, 'InstalledFcn'); if ~isOk diff --git a/toolbox/db/db_template.m b/toolbox/db/db_template.m index f1a5a556b..2e8d373a3 100644 --- a/toolbox/db/db_template.m +++ b/toolbox/db/db_template.m @@ -1185,6 +1185,7 @@ 'UninstalledFcn',[], ... % String to eval or function handle to call after uninstalling the plugin 'LoadedFcn', [], ... % String to eval or function handle to call after loading the plugin 'UnloadedFcn', [], ... % String to eval or function handle to call after unloading the plugin + 'DeleteFiles', [], ... % Cell-array of files to delete after unzipping the plugin package (path relative to the plugin folder) ... % Set when installing or loading the plugin 'SubFolder', '', ... % If all the code is in a subfolder: detect this at installation time 'Path', [], ... % Set at runtime: Installation path for this plugin diff --git a/toolbox/process/functions/process_convert_raw_to_lfp.m b/toolbox/process/functions/process_convert_raw_to_lfp.m index 1274582ee..9ed5e3c46 100644 --- a/toolbox/process/functions/process_convert_raw_to_lfp.m +++ b/toolbox/process/functions/process_convert_raw_to_lfp.m @@ -23,6 +23,7 @@ % =============================================================================@ % % Authors: Konstantinos Nasiotis 2018 +% Francois Tadel, 2021 eval(macro_method); end @@ -100,25 +101,12 @@ end %% Check for dependencies - % If DespikeLFP is selected, check if it is already installed + % If DespikeLFP is selected: Install DeriveLFP plugin if sProcess.options.despikeLFP.Value - % Ensure we are including the DeriveLFP folder in the Matlab path - DeriveLFPDir = bst_fullfile(bst_get('BrainstormUserDir'), 'DeriveLFP'); - if exist(DeriveLFPDir, 'dir') - addpath(genpath(DeriveLFPDir)); - end - - % Install DeriveLFP if missing - if ~exist('despikeLFP.m', 'file') - rmpath(genpath(DeriveLFPDir)); - isOk = java_dialog('confirm', ... - ['The DeriveLFP toolbox is not installed on your computer.' 10 10 ... - 'Download and install the latest version?'], 'DeriveLFP'); - if ~isOk - bst_report('Error', sProcess, sInput, 'This process requires the DeriveLFP toolbox.'); - return; - end - downloadAndInstallDeriveLFP(); + [isInstalled, errMsg] = bst_plugin('Install', 'derivelfp'); + if ~isInstalled + bst_report('Error', sProcess, [], errMsg); + return; end end @@ -269,7 +257,7 @@ data = sMat.data'; end - % Aplly final filter + % Apply final filter data = bst_bandpass_hfilter(data, Fs, filterBounds(1), filterBounds(2), 0, 0); data = downsample(data, round(Fs/1000)); % The file now has a different sampling rate (fs/30) = 1000Hz. end @@ -364,36 +352,3 @@ end - -%% ===== DOWNLOAD AND INSTALL DeriveLFP ===== -function downloadAndInstallDeriveLFP() - DeriveLFPDir = bst_fullfile(bst_get('BrainstormUserDir'), 'DeriveLFP'); - DeriveLFPTmpDir = bst_fullfile(bst_get('BrainstormUserDir'), 'DeriveLFP_tmp'); - url = 'http://packlab.mcgill.ca/despikingtoolbox.zip'; - % If folders exists: delete - if isdir(DeriveLFPDir) - file_delete(DeriveLFPDir, 1, 3); - end - if isdir(DeriveLFPTmpDir) - file_delete(DeriveLFPTmpDir, 1, 3); - end - % Create folder - mkdir(DeriveLFPTmpDir); - % Download file - zipFile = bst_fullfile(DeriveLFPTmpDir, 'despikingtoolbox.zip'); - errMsg = gui_brainstorm('DownloadFile', url, zipFile, 'DeriveLFP download'); % This line downloads the file - if ~isempty(errMsg) - error(['Impossible to download DeriveLFP:' errMsg]); - end - % Unzip file - bst_progress('start', 'DeriveLFP', 'Installing DeriveLFP...'); - unzip(zipFile, DeriveLFPTmpDir); - newDeriveLFPDir = bst_fullfile(DeriveLFPTmpDir); - % Move directory to proper location - file_move(newDeriveLFPDir, DeriveLFPDir); - % Delete unnecessary files - file_delete(DeriveLFPTmpDir, 1, 3); - % Add to Matlab path - addpath(genpath(DeriveLFPDir)); -end -