diff --git a/GUI/OspreyGUI.m b/GUI/OspreyGUI.m index a885c939..f68a88b9 100644 --- a/GUI/OspreyGUI.m +++ b/GUI/OspreyGUI.m @@ -98,7 +98,15 @@ load(fullfile(gui.folder.ospFolder,'GUI','SPMpath.mat'),'SPMpath') gui.folder.spmversion = SPMpath; end - + + % Show warning if the version is different + if ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + opts.WindowStyle = 'replace'; + opts.Interpreter = 'tex'; + f = errordlg('The Osprey version of your MRS container is different from the Osprey version you are using. Please consider re-running the analysis to ensure full functionality. Osprey v.2 is not compatible with any earlier versions.','Version mismatch',opts); + end + + % Load selected colormap gui.colormap = MRSCont.colormap; @@ -111,6 +119,7 @@ %Setting up inital values for the gui control variables %Global controls gui.controls.Selected = 1; + gui.controls.Tab = 1; gui.controls.Number = 1; gui.controls.KeyPress = 0; %File selections for each sub function @@ -120,14 +129,21 @@ gui.quant.Selected.Model = 1; gui.quant.Selected.Quant = 1; gui.overview.Selected.Metab = 1; + gui.controls.act_Exp = 1; gui.controls.act_x = 1; gui.controls.act_y = 1; gui.controls.act_z = 1; + gui.controls.act_basis = 1; %Names for each selection gui.load.Names.Spec = {'metabolites'}; %Inital number of datasets if isfield(MRSCont, 'nDatasets') - gui.controls.nDatasets = MRSCont.nDatasets; + gui.controls.nDatasets = MRSCont.nDatasets(1); + if size(MRSCont.nDatasets,2) > 1 + gui.controls.nExperiments = MRSCont.nDatasets(2); + else + gui.controls.nExperiments = 1; + end else gui.controls.nDatasets = 0; end @@ -182,46 +198,27 @@ catch end end + + if gui.controls.nExperiments > 1 + gui.info.nXvoxels = gui.controls.nExperiments; + gui.info.nExperiments = gui.controls.nExperiments; + end if MRSCont.flags.didProcess %Get variables regarding the processing gui.process.Number = length(fieldnames(MRSCont.processed)); + gui.info.nYvoxels = MRSCont.processed.metab{1, 1}.subspecs; gui.process.Names = fieldnames(MRSCont.processed); end - if MRSCont.flags.didFit %Get variables regarding the fitting - if strcmp(MRSCont.opts.fit.style, 'Concatenated') - temp = fieldnames(MRSCont.fit.results); - if MRSCont.flags.isUnEdited - gui.fit.Names = fieldnames(MRSCont.fit.results); - end - if MRSCont.flags.isMEGA - gui.fit.Names = {'diff1','sum'}; - if length(temp) == 2 - gui.fit.Names{3} = temp{2}; - else if length(temp) == 3 - gui.fit.Names{3} = temp{2}; - gui.fit.Names{4} = temp{3}; - end - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - gui.fit.Names = {'diff1','diff2','sum'}; - if length(temp) == 2 - gui.fit.Names{4} = temp{2}; - else if length(temp) == 3 - gui.fit.Names{4} = temp{2}; - gui.fit.Names{5} = temp{3}; - end - end - end - gui.fit.Number = length(gui.fit.Names); + if MRSCont.flags.didFit %Get variables regarding the fitting + if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + gui.fit.Names = fieldnames(MRSCont.fit.results{1}); + gui.fit.Number = length(fieldnames(MRSCont.fit.results{1})); else - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - gui.fit.Names = fieldnames(MRSCont.fit.results{1}); - gui.fit.Number = length(fieldnames(MRSCont.fit.results{1})); - else - gui.fit.Names = fieldnames(MRSCont.fit.results); - gui.fit.Number = length(fieldnames(MRSCont.fit.results)); - end + gui.fit.Names = fieldnames(MRSCont.fit.results); + gui.fit.Number = length(fieldnames(MRSCont.fit.results)); + gui.controls.act_y = size(MRSCont.fit.results.metab.fitParams,3); + gui.info.nYvoxels = size(MRSCont.fit.results.metab.fitParams,3); + gui.info.nZvoxels = size(MRSCont.fit.results.metab.fitParams,1); end end @@ -230,10 +227,10 @@ gui.quant.Names.Model = fieldnames(MRSCont.quantify.tables); gui.quant.Number.Quants = length(fieldnames(MRSCont.quantify.tables.(gui.quant.Names.Model{1}))); gui.quant.Names.Quants = fieldnames(MRSCont.quantify.tables.(gui.quant.Names.Model{1})); - gui.quant.Number.Metabs = length(MRSCont.quantify.metabs); - gui.quant.Selected.Metab = find(strcmp(MRSCont.quantify.metabs, 'tNAA')); + gui.quant.Number.Metabs = length(MRSCont.quantify.names.(gui.quant.Names.Model{1})); + gui.quant.Selected.Metab = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{1}), 'tNAA')); gui.quant.Selected.Model = 1; - gui.quant.idx.GABA = find(strcmp(MRSCont.quantify.metabs, 'GABA')); + gui.quant.idx.GABA = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{1}), 'GABA')); elseif MRSCont.flags.didQuantify gui.quant.Number.Model = length(fieldnames(MRSCont.quantify.amplMets{1, 1})); gui.quant.Names.Model = fieldnames(MRSCont.quantify.amplMets{1, 1}); @@ -334,7 +331,8 @@ % Load button gui.layout.b_load = uicontrol('Parent', gui.layout.p2,'Style','PushButton','String','Load data','Enable','on','ForegroundColor', gui.colormap.Foreground); set(gui.layout.b_load,'Units','Normalized','Position',[0.1 0.75 0.8 0.08], 'FontSize', 16, 'FontName', gui.font, 'FontWeight', 'Bold','Tag','LoadButton'); - if (MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets >= length(MRSCont.raw))) + sz_raw = size(MRSCont.raw); + if (MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets(1) >= sz_raw(end))) gui.layout.b_load.Enable = 'off'; end set(gui.layout.b_load,'Callback',{@osp_onLoad,gui}, 'TooltipString', 'Call OspreyLoad'); @@ -342,9 +340,9 @@ % Process button gui.layout.b_proc = uicontrol('Parent', gui.layout.p2,'Style','PushButton','String','Process data','Enable','on','ForegroundColor', gui.colormap.Foreground); set(gui.layout.b_proc,'Units','Normalized','Position',[0.1 0.75 0.8 0.08], 'FontSize', 16, 'FontName', gui.font, 'FontWeight', 'Bold','Tag','ProcButton'); - if (MRSCont.flags.didProcess == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets >= length(MRSCont.processed.A))) + if (MRSCont.flags.didProcess == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets(1) >= length(MRSCont.processed.metab))) gui.layout.b_proc.Enable = 'off'; - else if ~(MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets >= length(MRSCont.raw))) + else if ~(MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets(1) >= sz_raw(end))) gui.layout.b_proc.Enable = 'off'; end end @@ -352,9 +350,9 @@ % Fit button gui.layout.b_fit = uicontrol('Parent', gui.layout.p2,'Style','PushButton','String','Model data','Enable','on','ForegroundColor', gui.colormap.Foreground); set(gui.layout.b_fit,'Units','Normalized','Position',[0.1 0.67 0.8 0.08], 'FontSize', 16, 'FontName', gui.font, 'FontWeight', 'Bold','Tag','FitButton'); - if (MRSCont.flags.didFit == 1 && isfield(MRSCont, 'fit') && (gui.controls.nDatasets >= length(MRSCont.fit.scale))) + if (MRSCont.flags.didFit == 1 && isfield(MRSCont, 'fit') && (gui.controls.nDatasets(1) >= length(MRSCont.fit.scale))) gui.layout.b_fit.Enable = 'off'; - else if ~(MRSCont.flags.didProcess == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets >= length(MRSCont.processed.A))) + else if ~(MRSCont.flags.didProcess == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets(1) >= sz_raw(end))) gui.layout.b_fit.Enable = 'off'; end end @@ -362,7 +360,7 @@ % Coregister button gui.layout.b_coreg = uicontrol('Parent', gui.layout.p2,'Style','PushButton','String','CoRegister','Enable','off','ForegroundColor', gui.colormap.Foreground); set(gui.layout.b_coreg,'Units','Normalized','Position',[0.1 0.59 0.8 0.08], 'FontSize', 16, 'FontName', gui.font, 'FontWeight', 'Bold','Tag','CoregButton'); - if MRSCont.flags.hasSPM == 1 && ~isempty(MRSCont.files_nii) && ~(MRSCont.flags.didCoreg == 1 && isfield(MRSCont, 'coreg') && (gui.controls.nDatasets >= length(MRSCont.coreg.vol_image))) && (MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets >= length(MRSCont.raw))) + if MRSCont.flags.hasSPM == 1 && ~isempty(MRSCont.files_nii) && ~(MRSCont.flags.didCoreg == 1 && isfield(MRSCont, 'coreg') && (gui.controls.nDatasets(1) >= length(MRSCont.coreg.vol_image))) && (MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets(1) >= length(MRSCont.raw))) if ~(isfield(MRSCont.flags,'addImages') && (MRSCont.flags.addImages == 0) && MRSCont.flags.moved) gui.layout.b_coreg.Enable = 'on'; end @@ -374,7 +372,7 @@ % Segment button gui.layout.b_segm = uicontrol('Parent', gui.layout.p2,'Style','PushButton','String','Segment','Enable','off','ForegroundColor', gui.colormap.Foreground); set(gui.layout.b_segm,'Units','Normalized','Position',[0.1 0.51 0.8 0.08], 'FontSize', 16, 'FontName', gui.font, 'FontWeight', 'Bold','Tag','SegButton'); - if MRSCont.flags.hasSPM == 1 && ~isempty(MRSCont.files_nii) && ~(MRSCont.flags.didSeg == 1 && isfield(MRSCont, 'seg') && (gui.controls.nDatasets >= length(MRSCont.seg.tissue.fGM(:,1)))) && (MRSCont.flags.didCoreg == 1 && isfield(MRSCont, 'coreg') && (gui.controls.nDatasets >= length(MRSCont.coreg.vol_image))) + if MRSCont.flags.hasSPM == 1 && ~isempty(MRSCont.files_nii) && ~(MRSCont.flags.didSeg == 1 && isfield(MRSCont, 'seg') && (gui.controls.nDatasets(1) >= length(MRSCont.seg.tissue.fGM(:,1)))) && (MRSCont.flags.didCoreg == 1 && isfield(MRSCont, 'coreg') && (gui.controls.nDatasets(1) >= length(MRSCont.coreg.vol_image))) if ~(isfield(MRSCont.flags,'addImages') && (MRSCont.flags.addImages == 0) && MRSCont.flags.moved) gui.layout.b_segm.Enable = 'on'; end @@ -388,7 +386,7 @@ set(gui.layout.b_quant,'Units','Normalized','Position',[0.1 0.43 0.8 0.08], 'FontSize', 16, 'FontName', gui.font, 'FontWeight', 'Bold','Tag','QuantifyButton'); if MRSCont.flags.didQuantify gui.layout.b_quant.Enable = 'off'; - else if ~(MRSCont.flags.didFit == 1 && isfield(MRSCont, 'fit') && (gui.controls.nDatasets >= length(MRSCont.fit.scale)) ) + else if ~(MRSCont.flags.didFit == 1 && isfield(MRSCont, 'fit') && (gui.controls.nDatasets(1) >= length(MRSCont.fit.scale)) ) gui.layout.b_quant.Enable = 'off'; end end @@ -437,7 +435,7 @@ end %% Create the display panel tab row - gui.layout.tabs = uix.TabPanel('Parent', gui.layout.mainLayout, 'Padding', 3, 'FontName', gui.font,'Visible','off',... + gui.layout.tabs = uix.TabPanel('Parent', gui.layout.mainLayout, 'Padding', 3, 'FontName', gui.font,'Visible','on',... 'FontSize', 16,'BackgroundColor',gui.colormap.Background,... 'ForegroundColor', gui.colormap.Foreground, 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground,... 'Tag','MainTabPanel'); @@ -468,7 +466,8 @@ % been completed: gui.controls.waitbar = waitbar(0,'Start','Name','Loading your MRS Container'); waitbar(0,gui.controls.waitbar,'Loading your raw spectra') - if (MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets >= length(MRSCont.raw))) % Was data loaded at all that can be looked at? + if (MRSCont.flags.didLoadData == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets(1) >= sz_raw(end))) % Was data loaded at all that can be looked at? + set(gui.layout.tabs, 'Visible','on'); osp_iniLoadWindow(gui); if MRSCont.flags.isMRSI gui.layout.LocPanel = uix.HBox('Parent', gui.layout.MRSILocPanel, 'BackgroundColor',gui.colormap.Background, 'Units', 'normalized','Tag','MRSILocPlot'); @@ -481,19 +480,19 @@ set(gui.controls.b_save_RawTab{gui.load.Selected},'Callback',{@osp_onPrint,gui}); end waitbar(gui.waitbar.step,gui.controls.waitbar,'Loading your processed spectra'); - if (MRSCont.flags.didProcess == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets >= length(MRSCont.processed.A))) % Has data been processed? + if (MRSCont.flags.didProcess == 1 && isfield(MRSCont, 'raw') && (gui.controls.nDatasets(1) >= length(MRSCont.processed.metab))) % Has data been processed? set(gui.layout.tabs, 'Visible','on'); osp_iniProcessWindow(gui); set(gui.controls.b_save_proTab{gui.load.Selected},'Callback',{@osp_onPrint,gui}); set(gui.layout.tabs, 'Visible','off'); end waitbar(gui.waitbar.step*2,gui.controls.waitbar,'Loading your fits'); - if (MRSCont.flags.didFit == 1 && isfield(MRSCont, 'fit') && (gui.controls.nDatasets >= length(MRSCont.fit.scale)) ) % Has data fitting been run? + if (MRSCont.flags.didFit == 1 && isfield(MRSCont, 'fit') && (gui.controls.nDatasets(1) >= length(MRSCont.fit.scale)) ) % Has data fitting been run? osp_iniFitWindow(gui); set(gui.controls.b_save_fitTab{gui.load.Selected},'Callback',{@osp_onPrint,gui}); end waitbar(gui.waitbar.step*3,gui.controls.waitbar,'Loading your image operations'); - if (MRSCont.flags.didCoreg == 1 && isfield(MRSCont, 'coreg') && (gui.controls.nDatasets >= length(MRSCont.coreg.vol_image))) % Have coreg/segment masks been created? + if (MRSCont.flags.didCoreg == 1 && isfield(MRSCont, 'coreg') && (gui.controls.nDatasets(1) >= length(MRSCont.coreg.vol_image))) % Have coreg/segment masks been created? osp_iniCoregWindow(gui); set(gui.controls.b_save_coregTab,'Callback',{@osp_onPrint,gui}); end @@ -502,7 +501,7 @@ osp_iniQuantifyWindow(gui); end waitbar(gui.waitbar.step*7,gui.controls.waitbar,'Loading your overview'); - if MRSCont.flags.didOverview && (isfield(MRSCont, 'fit') && (gui.controls.nDatasets >= length(MRSCont.fit.scale))) % Has data fitting been run? + if MRSCont.flags.didOverview && (isfield(MRSCont, 'fit') && (gui.controls.nDatasets(1) >= length(MRSCont.fit.scale))) % Has data fitting been run? osp_iniOverviewWindow(gui); set(gui.layout.overviewTab, 'SelectionChangedFcn',{@osp_OverviewTabChangedFcn,gui}); set(gui.controls.pop_specsOvPlot,'callback',{@osp_pop_specsOvPlot_Call,gui}); @@ -539,14 +538,7 @@ set(gui.layout.fitTab, 'SelectionChangedFcn',{@osp_FitTabChangeFcn,gui}); set(gui.layout.quantifyTab, 'SelectionChangedFcn',{@osp_QuantTabChangeFcn,gui}); set(gui.layout.ListBox,'Callback', {@osp_onListSelection,gui},'KeyPressFcn',{@osp_WindowKeyDown,gui}, 'KeyReleaseFcn', {@osp_WindowKeyUp,gui}); - - % Show warning if the version is different - if ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - opts.WindowStyle = 'replace'; - opts.Interpreter = 'tex'; - f = errordlg('The Osprey version of your MRS container is different from the Osprey version you are using. Please consider re-running the analysis to ensure full functionality.','Version mismatch',opts); - end - + end end end % End of class definition diff --git a/GUI/osp_FitTabChangeFcn.m b/GUI/osp_FitTabChangeFcn.m index d0753a66..6df07dce 100644 --- a/GUI/osp_FitTabChangeFcn.m +++ b/GUI/osp_FitTabChangeFcn.m @@ -25,8 +25,27 @@ function osp_FitTabChangeFcn(src,~,gui) % 2020-01-16: First version of the code. %%% 1. GET HANDLES %%% % User selected tab refreshs plot + MRSCont = getappdata(gui.figure,'MRSCont'); + gui.fit.Selected = src.Selection; - + gui.info.nXvoxels = 1; + gui.controls.act_x = 1; + gui.controls.b_left_y.Enable = 'off'; + gui.controls.b_left_z.Enable = 'off'; + gui.controls.b_right_y.Enable = 'off'; + gui.controls.b_right_z.Enable = 'off'; + gui.info.nYvoxels = size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,3); + gui.controls.act_y = 1; + gui.info.nZvoxels = size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,1); + gui.controls.act_z = 1; + if size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,3) > 1 + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + end + if size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,1) > 1 + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end %%% 2. UPDATE GUI %%% osp_updateFitWindow(gui); end \ No newline at end of file diff --git a/GUI/osp_OverviewTabChangedFcn.m b/GUI/osp_OverviewTabChangedFcn.m index e6bc3ffb..eabba9f0 100644 --- a/GUI/osp_OverviewTabChangedFcn.m +++ b/GUI/osp_OverviewTabChangedFcn.m @@ -30,6 +30,14 @@ function osp_OverviewTabChangedFcn(src,~,gui) osp_updateSpecsOvWindow(gui); set(gui.controls.pop_specsOvPlot, 'value',gui.process.Selected) case 2 + splt_string = strsplit(gui.controls.pop_specsOvPlot.String{gui.process.Selected}); + if length(splt_string) > 1 + if strcmp(splt_string{2},'ref') || strcmp(splt_string{2},'w') + gui.process.Selected = find(contains(gui.controls.pop_meanOvPlot.String,splt_string{2})); + else + gui.process.Selected = find(contains(gui.controls.pop_meanOvPlot.String,splt_string{3})); + end + end osp_updatemeanOvWindow(gui); set(gui.controls.pop_meanOvPlot, 'value',gui.process.Selected) case 3 diff --git a/GUI/osp_ProTabChangeFcn.m b/GUI/osp_ProTabChangeFcn.m index 63ce7c0f..6157b914 100644 --- a/GUI/osp_ProTabChangeFcn.m +++ b/GUI/osp_ProTabChangeFcn.m @@ -24,8 +24,23 @@ function osp_ProTabChangeFcn(src,~,gui) % HISTORY: % 2020-01-16: First version of the code. %%% 1. GET HANDLES %%% + MRSCont = getappdata(gui.figure,'MRSCont'); % User selected tab refreshs plot gui.process.Selected = src.Selection; + + if MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.extras > 0 + gui.info.nXvoxels = MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.sz(MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.extras); + else + gui.info.nXvoxels = 1; + end + gui.controls.act_x = 1; + if MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.subSpecs > 0 + gui.info.nYvoxels = MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.sz(MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.subSpecs); + else + gui.info.nYvoxels = MRSCont.nDatasets(2); + end + gui.controls.act_y = 1; + % Grid for Plot gui.layout.proPlot = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); gui.layout.proPre = gui.layout.proPlot.Children(1).Children(2).Children(2); diff --git a/GUI/osp_SelectionChangedFcn.m b/GUI/osp_SelectionChangedFcn.m index 31b31108..ef56e567 100644 --- a/GUI/osp_SelectionChangedFcn.m +++ b/GUI/osp_SelectionChangedFcn.m @@ -27,123 +27,149 @@ function osp_SelectionChangedFcn(src,~,gui) % Get MRSCont from hidden container in gui class MRSCont = getappdata(gui.figure,'MRSCont'); % User selected tab refreshs plot - OldValue = src.Selection; + OldValue = gui.controls.Tab; switch OldValue case 1 %Load tab - spec = gui.load.Selected; - if ~(spec == 2 || spec ==3) - gui.fit.Selected = 1; - else - if spec == 2 - gui.fit.Selected = 2; - else - gui.fit.Selected = 3; - end + tab = gui.layout.rawTab.TabTitles{gui.load.Selected}; + switch tab + case {'metabolites','MM'} + gui.process.Selected = gui.load.Selected; + gui.fit.Selected = gui.load.Selected; + case {'reference'} + gui.process.Selected = find(strcmp(gui.layout.proTab.TabTitles,'ref')); + gui.process.Selected = find(strcmp(gui.layout.fitTab.TabTitles,'ref')); + case {'water'} + gui.process.Selected = find(strcmp(gui.layout.proTab.TabTitles,'w')); + gui.process.Selected = find(strcmp(gui.layout.fitTab.TabTitles,'w')); + case {'MM reference'} + gui.process.Selected = find(strcmp(gui.layout.proTab.TabTitles,'mm_ref')); end case 2 %Process tab - spec = gui.process.Selected; - - if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - if ~(spec == 5 || spec == 6) - gui.load.Selected = 1; - gui.fit.Selected = 1; - else - if spec == 5 - gui.load.Selected = 2; - gui.fit.Selected = 4; - else - gui.load.Selected = 3; - gui.fit.Selected = 5; - end - end - elseif MRSCont.flags.isMEGA - if ~(spec == 3 || spec == 4) - gui.load.Selected = 1; - gui.fit.Selected = 1; - else - if spec == 3 - gui.load.Selected = 2; - gui.fit.Selected = 3; - else - gui.load.Selected = 3; - gui.fit.Selected = 4; - end - end - elseif MRSCont.flags.isUnEdited - gui.load.Selected = spec; - gui.fit.Selected = spec; + tab = gui.layout.proTab.TabTitles{gui.process.Selected}; + switch tab + case {'metab','mm'} + gui.load.Selected = gui.load.Selected; + gui.fit.Selected = gui.load.Selected; + case {'ref'} + gui.load.Selected = find(strcmp(gui.layout.rawTab.TabTitles,'reference')); + gui.process.Selected = find(strcmp(gui.layout.fitTab.TabTitles,'ref')); + case {'w'} + gui.load.Selected = find(strcmp(gui.layout.rawTab.TabTitles,'water')); + gui.process.Selected = find(strcmp(gui.layout.fitTab.TabTitles,'w')); + case {'mm_ref'} + gui.load.Selected = find(strcmp(gui.layout.rawTab.TabTitles,'MM reference')); end + - case 4 %Fit Tab - if (strcmp(gui.fit.Names{gui.fit.Selected},'off') || strcmp(gui.fit.Names{gui.fit.Selected},'diff1')||... - strcmp(gui.fit.Names{gui.fit.Selected},'diff2') || strcmp(gui.fit.Names{gui.fit.Selected},'sum')) - spec = 1; - else - if strcmp(gui.fit.Names{gui.fit.Selected},'w') - spec = 3; - else - spec = 2; - end - end - if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - if ~(spec == 2 || spec == 3) - gui.load.Selected = 1; - gui.process.Selected = 1; - else - if spec == 2 - gui.load.Selected = 2; - gui.process.Selected = 5; - else - gui.load.Selected = 3; - gui.process.Selected = 6; - end - end - elseif MRSCont.flags.isMEGA - if ~(spec == 2 || spec == 3) - gui.load.Selected = 1; - gui.process.Selected = 1; - else - if spec == 2 - gui.load.Selected = 2; - gui.process.Selected = 3; - else - gui.load.Selected = 3; - gui.process.Selected = 4; - end - end - elseif MRSCont.flags.isUnEdited - gui.load.Selected = spec; - gui.process.Selected = spec; + case 3 %Fit Tab + tab = gui.layout.fitTab.TabTitles{gui.fit.Selected}; + switch tab + case {'metab','mm'} + gui.load.Selected = gui.load.Selected; + gui.fit.Selected = gui.load.Selected; + case {'ref'} + gui.load.Selected = find(strcmp(gui.layout.rawTab.TabTitles,'reference')); + gui.process.Selected = find(strcmp(gui.layout.fitTab.TabTitles,'ref')); + case {'w'} + gui.load.Selected = find(strcmp(gui.layout.rawTab.TabTitles,'water')); + gui.process.Selected = find(strcmp(gui.layout.fitTab.TabTitles,'w')); end - case 5 %Quantify tab? + otherwise idx = 1; spec = 1; end + Exp = 1; + SubSpec = 1; + Basis = 1; + gui.controls.Tab = gui.layout.tabs.Selection; %%% 2. UPDATE GUI %%% switch gui.layout.tabs.Selection case 1 %Load tab - gui.layout.ListBox.Enable = 'on'; - set(gui.layout.rawTab, 'selection', gui.load.Selected); - osp_updateLoadWindow(gui); + gui.layout.ListBox.Enable = 'on'; + set(gui.layout.rawTab, 'Selection', gui.load.Selected); + gui.info.nXvoxels = MRSCont.nDatasets(2); + gui.controls.act_x = Exp; + osp_updateLoadWindow(gui); case 2 %Process tab - gui.layout.ListBox.Enable = 'on'; - gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); - set(gui.layout.proTab, 'selection', gui.process.Selected); - osp_updateProWindow(gui); + gui.layout.ListBox.Enable = 'on'; + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; + gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); + set(gui.layout.proTab, 'Selection', gui.process.Selected); + if MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.extras > 0 + gui.info.nXvoxels = MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.sz(MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.extras); + else + gui.info.nXvoxels = 1; + end + gui.controls.act_x = Exp; + if MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.subSpecs > 0 + gui.info.nYvoxels = MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.sz(MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.dims.subSpecs); + else + gui.info.nYvoxels = MRSCont.nDatasets(2); + end + gui.controls.act_y = SubSpec; + osp_updateProWindow(gui); case 3 %Fit tab - gui.layout.ListBox.Enable = 'on'; - set(gui.layout.fitTab, 'selection', gui.fit.Selected); - osp_updateFitWindow(gui); + gui.layout.ListBox.Enable = 'on'; + set(gui.layout.fitTab, 'Selection', gui.fit.Selected); + gui.info.nXvoxels = 1; + gui.controls.act_x = Exp; + gui.controls.b_left_y.Enable = 'off'; + gui.controls.b_left_z.Enable = 'off'; + gui.controls.b_right_y.Enable = 'off'; + gui.controls.b_right_z.Enable = 'off'; + gui.info.nYvoxels = size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,3); + gui.controls.act_y = 1; + gui.info.nZvoxels = size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,1); + gui.controls.act_z = 1; + if size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,3) > 1 + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + end + if size(MRSCont.fit.results.(gui.fit.Names{gui.fit.Selected}).fitParams,1) > 1 + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end + osp_updateFitWindow(gui); case 4 %Coreg Tab - gui.layout.ListBox.Enable = 'on'; - gui.InfoText.coreg = gui.layout.(gui.layout.proTabhandles{gui.load.Selected}).Children(2).Children; - osp_updateCoregWindow(gui); + gui.layout.ListBox.Enable = 'on'; + gui.InfoText.coreg = gui.layout.(gui.layout.proTabhandles{gui.load.Selected}).Children(2).Children; + osp_updateCoregWindow(gui); case 5 % Quantify tab - gui.layout.ListBox.Enable = 'on'; - osp_updateQuantifyWindow(gui); + gui.layout.ListBox.Enable = 'on'; + gui.controls.act_x = Exp; + gui.controls.b_left_y.Enable = 'off'; + gui.controls.b_left_z.Enable = 'off'; + gui.controls.b_right_y.Enable = 'off'; + gui.controls.b_right_z.Enable = 'off'; + gui.info.nYvoxels = size(MRSCont.fit.results.metab.fitParams,3); + gui.controls.act_y = 1; + gui.info.nZvoxels = size(MRSCont.fit.results.metab.fitParams,1); + gui.controls.act_z = 1; + if size(MRSCont.fit.results.metab.fitParams,3) > 1 + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + end + if size(MRSCont.fit.results.metab.fitParams,1) > 1 + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end + osp_updateQuantifyWindow(gui); case 6 %Overview tab - gui.layout.ListBox.Enable = 'off'; + gui.layout.ListBox.Enable = 'off'; + gui.controls.act_x = Exp; + gui.controls.b_left_x.Enable = 'off'; + gui.controls.b_left_z.Enable = 'off'; + gui.controls.b_right_x.Enable = 'off'; + gui.controls.b_right_z.Enable = 'off'; + gui.info.nXvoxels = 1; + gui.controls.act_x = 1; + gui.info.nZvoxels = size(MRSCont.fit.results.metab.fitParams,1); + gui.controls.act_z = 1; + if size(MRSCont.fit.results.metab.fitParams,1) > 1 + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end end end \ No newline at end of file diff --git a/GUI/osp_Toolbox_Check.m b/GUI/osp_Toolbox_Check.m index 1dca9b7c..3d74be19 100644 --- a/GUI/osp_Toolbox_Check.m +++ b/GUI/osp_Toolbox_Check.m @@ -32,7 +32,7 @@ % 2020-05-15: First version of the code. %% %%% 1. GET SPMPATH AND TOOLBOXES%%% -OspreyVersion = 'Osprey 1.2.0'; +OspreyVersion = 'Osprey 2.0.0'; fprintf(['Timestamp %s ' OspreyVersion ' ' Module '\n'], datestr(now,'mmmm dd, yyyy HH:MM:SS')); addons = matlab.addons.installedAddons; available = cellstr(table2cell(addons(:,1))); diff --git a/GUI/osp_check_distrOv_Call.m b/GUI/osp_check_distrOv_Call.m index 938a625d..0ea10d31 100644 --- a/GUI/osp_check_distrOv_Call.m +++ b/GUI/osp_check_distrOv_Call.m @@ -30,13 +30,14 @@ function osp_check_distrOv_Call(src,~,gui) metab = get(gui.controls.pop_distrOvMetab, 'Value'); Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; if ~strcmp(Selection,'Quality') - split_Selection = strsplit(Selection,'-'); - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') + split_Selection = strsplit(Selection,'-'); + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1}),split_Selection{2})); + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') set(gui.controls.pop_distrOvMetab, 'String', {'GABA'}); set(gui.controls.pop_distrOvMetab, 'Value', gui.quant.idx.GABA); set(gui.controls.pop_distrOvMetab, 'Enable', 'off'); else - set(gui.controls.pop_distrOvMetab, 'String', MRSCont.quantify.metabs.(split_Selection{1})); + set(gui.controls.pop_distrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){1,ind}); set(gui.controls.pop_distrOvMetab, 'Value', metab); set(gui.controls.pop_distrOvMetab, 'Enable', 'on'); end diff --git a/GUI/osp_iniFitWindow.m b/GUI/osp_iniFitWindow.m index 76cf9e3c..cd3b2bbd 100644 --- a/GUI/osp_iniFitWindow.m +++ b/GUI/osp_iniFitWindow.m @@ -48,7 +48,7 @@ function osp_iniFitWindow(gui) % Parameter shown in the info panel on top gui.upperBox.fit.box{t} = uix.HBox('Parent', gui.layout.(gui.layout.fitTabhandles{t}),'BackgroundColor',gui.colormap.Background,'Spacing',5); if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - gui.upperBox.fit.upperLeftButtons = uix.Panel('Parent', gui.upperBox.fit.box, ... + gui.upperBox.fit.upperLeftButtons = uix.Panel('Parent', gui.upperBox.fit.box{t}, ... 'Padding', 5, 'Title', ['Navigate voxel'],... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); @@ -98,6 +98,86 @@ function osp_iniFitWindow(gui) end set( gui.controls.navigate_RawTab, 'Widths', [-20 -30 -20 -30], 'Heights', [-33 -33 -33] ); end + + + gui.upperBox.fit.upperLeftButtons = uix.Panel('Parent', gui.upperBox.fit.box{t}, ... + 'Padding', 5, 'Title', ['Navigate model'],... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... + 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); + gui.controls.Buttonbox = uix.HBox('Parent',gui.upperBox.fit.upperLeftButtons, 'BackgroundColor',gui.colormap.Background); + gui.controls.navigate_RawTab = uix.Grid('Parent',gui.controls.Buttonbox,'BackgroundColor',gui.colormap.Background); + + gui.controls.text_x = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Exp:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_y = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Spec:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_z = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Basis:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_left_x = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + gui.controls.b_left_y = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + gui.controls.b_left_z = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + set(gui.controls.b_left_x,'Callback',{@osp_onLeftX,gui}); + set(gui.controls.b_left_y,'Callback',{@osp_onLeftY,gui}); + set(gui.controls.b_left_z,'Callback',{@osp_onLeftZ,gui}); + + + gui.controls.text_act_x = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_act_y = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_act_z = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + + gui.controls.b_right_x = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + gui.controls.b_right_y = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + gui.controls.b_right_z = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + set(gui.controls.b_right_x,'Callback',{@osp_onRightX,gui}); + set(gui.controls.b_right_y,'Callback',{@osp_onRightY,gui}); + set(gui.controls.b_right_z,'Callback',{@osp_onRightZ,gui}); + + gui.controls.b_left_x.Enable = 'off'; + gui.controls.b_left_y.Enable = 'off'; + gui.controls.b_left_z.Enable = 'off'; + gui.controls.b_right_x.Enable = 'off'; + gui.controls.b_right_y.Enable = 'off'; + gui.controls.b_right_z.Enable = 'off'; + + buttonString = [num2str(MRSCont.nDatasets(2) > 1) num2str(size(MRSCont.fit.results.(Selection).fitParams,3)>1) num2str(size(MRSCont.fit.results.(Selection).fitParams,1)>1)]; + switch buttonString + case '001' + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '010' + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + case '100' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + case '011' + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '101' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '110' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + case '111' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end + set( gui.controls.navigate_RawTab, 'Widths', [-20 -30 -20 -30], 'Heights', [-33 -33 -33]); + gui.upperBox.fit.Info{t} = uix.Panel('Parent', gui.upperBox.fit.box{t}, ... 'Padding', 5, 'Title', ['Actual file: ' MRSCont.files{gui.controls.Selected}],... 'FontName', gui.font,'HighlightColor', gui.colormap.Foreground,'BackgroundColor',... @@ -114,7 +194,7 @@ function osp_iniFitWindow(gui) if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) set(gui.upperBox.fit.box{t}, 'Width', [-0.12 -0.78 -0.1]); else - set(gui.upperBox.fit.box{t}, 'Width', [-0.9 -0.1]); + set(gui.upperBox.fit.box{t}, 'Width', [-0.15 -0.75 -0.1]); end % Creates layout for plotting and data control gui.Plot.fit{t} = uix.HBox('Parent', gui.layout.(gui.layout.fitTabhandles{t}), ... @@ -125,8 +205,8 @@ function osp_iniFitWindow(gui) else %Is concatenated and not water/reference gui.fit.Style = 'conc'; end - - + + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) switch MRSCont.opts.fit.method case 'LCModel' @@ -137,13 +217,13 @@ function osp_iniFitWindow(gui) CRLB = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.CRLB; end case 'Osprey' - RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ampl .* MRSCont.fit.scale{1,gui.controls.Selected}; + RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected,end}.ampl .* MRSCont.fit.scale{1,gui.controls.Selected}; end - ph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph0; - ph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph1; + ph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected,end}.ph0; + ph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected,end}.ph1; if ~strcmp(gui.fit.Names{t}, 'ref') && ~strcmp(gui.fit.Names{t}, 'w') - refShift = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refShift; - refFWHM = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refFWHM; + refShift = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected,end}.refShift; + refFWHM = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected,end}.refFWHM; end elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM switch MRSCont.opts.fit.method @@ -182,7 +262,7 @@ function osp_iniFitWindow(gui) refFWHM = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refFWHM; end end - + % For this visualization, we will have to make a few % distinctions upfront since the modeling algorithms (LCModel % vs. Osprey) do not always return the same kinds of data, or they @@ -210,14 +290,11 @@ function osp_iniFitWindow(gui) waterFitRangeString = ['Fitting range: ' num2str(MRSCont.opts.fit.rangeWater(1)) ' to ' num2str(MRSCont.opts.fit.rangeWater(2)) ' ppm']; % Where are the metabolite names stored? if strcmp(gui.fit.Style, 'ref') || strcmp(gui.fit.Style, 'w') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).water.(['np_sw_' num2str(round(MRSCont.processed.(gui.fit.Style){1}.sz(1))) '_' num2str(round(MRSCont.processed.(gui.fit.Style){1}.spectralwidth))]).name; + basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{1}.sz(1)) '_' num2str(MRSCont.processed.metab{1}.spectralwidth)]){1,1}.name; else if strcmp(gui.fit.Style, 'conc') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{1}.sz(1))) '_' num2str(round(MRSCont.processed.A{1}.spectralwidth))]).name; - else if strcmp(gui.fit.Style, 'off') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{1}.sz(1))) '_' num2str(round(MRSCont.processed.A{1}.spectralwidth))]).name; - else - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{1}.sz(1))) '_' num2str(round(MRSCont.processed.A{1}.spectralwidth))]).name; - end + basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{1}.sz(1)) '_' num2str(MRSCont.processed.metab{1}.spectralwidth)]){1,1}.name; + else + basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{1}.sz(1)) '_' num2str(MRSCont.processed.metab{1}.spectralwidth)]){1,end}.name; end end % Larger fonts for the results @@ -303,7 +380,7 @@ function osp_iniFitWindow(gui) end end - + set(gui.Results.fit{t}, 'Title', ['Raw Water Ratio']); gui.Results.FitText = uix.HBox('Parent', gui.Results.fit{t}, 'Padding', 5,'BackgroundColor',gui.colormap.Background); gui.Results.FitTextNames = uicontrol('Parent',gui.Results.FitText,'style','text',... @@ -536,7 +613,7 @@ function osp_iniFitWindow(gui) 'FontSize', 11, 'FontName', gui.font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); end - end + end end set(gui.Results.fit{t}, 'Title', ['Raw Amplitudes']); gui.Results.FitText = uix.HBox('Parent', gui.Results.fit{t}, 'Padding', 5,'BackgroundColor',gui.colormap.Background); @@ -590,7 +667,7 @@ function osp_iniFitWindow(gui) %osp_plotFit is used to visualize the fits (off,diff1,diff2,sum,ref,water) temp = figure( 'Visible', 'off' ); if ~((isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI)) - temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,1,gui.fit.Names{t}); + temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,[gui.controls.act_x gui.controls.act_y gui.controls.act_z],gui.fit.Names{t}); elseif MRSCont.flags.isPRIAM temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,gui.controls.act_x,Selection); %Create figure else diff --git a/GUI/osp_iniLoadWindow.m b/GUI/osp_iniLoadWindow.m index c01f70ae..2075cdd3 100644 --- a/GUI/osp_iniLoadWindow.m +++ b/GUI/osp_iniLoadWindow.m @@ -1,4 +1,4 @@ -function osp_iniLoadWindow(gui) +function osp_iniLoadWindow(gui) %% osp_iniLoadWindow % This function creates the initial load window in the gui. % @@ -6,7 +6,7 @@ function osp_iniLoadWindow(gui) % USAGE: % osp_iniLoadWindow(gui); % -% INPUT: gui = gui class containing all handles and the MRSCont +% INPUT: gui = gui class containing all handles and the MRSCont % % OUTPUT: Changes in gui parameters and MRSCont are written into the % gui class @@ -27,34 +27,53 @@ function osp_iniLoadWindow(gui) %%% 1. GET HANDLES %%% % This function creates the initial load window MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class - if MRSCont.flags.hasMM %Get variables regarding Subspectra %re_mm - gui.controls.Number = gui.controls.Number + 1;%re_mm - gui.load.Names.Spec{2} = 'MM';%re_mm - end %re_mm - if MRSCont.flags.hasRef %Get variables regarding Subspectra - gui.controls.Number = gui.controls.Number + 1; - if MRSCont.flags.hasMM%re_mm - gui.load.Names.Spec{3} = 'reference';%re_mm - else%re_mm - gui.load.Names.Spec{2} = 'reference'; - end%re_mm - if MRSCont.flags.hasWater - gui.controls.Number = gui.controls.Number + 1; - if MRSCont.flags.hasMM%re_mm - gui.load.Names.Spec{4} = 'water';%re_mm - else%re_mm - gui.load.Names.Spec{3} = 'water'; - end%re_mm - end - else if MRSCont.flags.hasWater - gui.controls.Number = gui.controls.Number + 1; - if MRSCont.flags.hasMM%re_mm - gui.load.Names.Spec{3} = 'water';%re_mm - else%re_mm + numberstring = [num2str(MRSCont.flags.hasMM) num2str(MRSCont.flags.hasRef) num2str(MRSCont.flags.hasMMRef) num2str(MRSCont.flags.hasWater)]; + switch numberstring + case '1000' + gui.controls.Number = gui.controls.Number + 1; + gui.load.Names.Spec{2} = 'MM'; + case '1100' + gui.controls.Number = gui.controls.Number + 2; + gui.load.Names.Spec{2} = 'MM'; + gui.load.Names.Spec{3} = 'reference'; + case '0100' + gui.controls.Number = gui.controls.Number + 1; + gui.load.Names.Spec{2} = 'reference'; + case '0101' + gui.controls.Number = gui.controls.Number + 2; + gui.load.Names.Spec{2} = 'reference'; + gui.load.Names.Spec{3} = 'water'; + case '0001' + gui.controls.Number = gui.controls.Number + 1; gui.load.Names.Spec{2} = 'water'; - end%re_mm - end + case '1010' + gui.controls.Number = gui.controls.Number + 2; + gui.load.Names.Spec{2} = 'MM'; + gui.load.Names.Spec{3} = 'MM reference'; + case '1110' + gui.controls.Number = gui.controls.Number + 3; + gui.load.Names.Spec{2} = 'MM'; + gui.load.Names.Spec{3} = 'reference'; + gui.load.Names.Spec{4} = 'MM reference'; + case '1011' + gui.controls.Number = gui.controls.Number + 3; + gui.load.Names.Spec{2} = 'MM'; + gui.load.Names.Spec{3} = ' MMreference'; + gui.load.Names.Spec{4} = 'water'; + case '1111' + gui.controls.Number = gui.controls.Number + 4; + gui.load.Names.Spec{2} = 'MM'; + gui.load.Names.Spec{3} = 'reference'; + gui.load.Names.Spec{4} = 'MM reference'; + gui.load.Names.Spec{5} = 'water'; + otherwise + gui.controls.Number = gui.controls.Number + 4; + gui.load.Names.Spec{2} = 'spectra 1'; + gui.load.Names.Spec{3} = 'spectra 2'; + gui.load.Names.Spec{4} = 'spectra 3'; + gui.load.Names.Spec{5} = 'spectra 4'; end + gui.layout.tabs.TabEnables{1} = 'on'; gui.layout.tabs.Selection = 1; gui.layout.EmptydataPlot = 0; @@ -68,47 +87,81 @@ function osp_iniLoadWindow(gui) gui.layout.rawTab.TabTitles = gui.load.Names.Spec; gui.layout.rawTab.TabEnables = {'on'}; end - if gui.controls.Number == 2 - if MRSCont.flags.hasRef + switch numberstring + case '1000' gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','refLoTab'); gui.layout.rawTab.TabTitles = gui.load.Names.Spec; gui.layout.rawTab.TabEnables = {'on', 'on'}; - gui.layout.rawTabhandles = {'metabLoTab', 'refLoTab'}; - end - if MRSCont.flags.hasWater - gui.layout.wLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','wLoTab'); - gui.layout.rawTab.TabTitles = gui.load.Names.Spec; - gui.layout.rawTab.TabEnables = {'on', 'on'}; - gui.layout.rawTabhandles = {'metabLoTab', 'wLoTab'}; - end - end - if gui.controls.Number == 3 - gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','refLoTab'); - gui.layout.wLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','wLoTab'); - gui.layout.rawTab.TabTitles = gui.load.Names.Spec; - gui.layout.rawTab.TabEnables = {'on', 'on','on'}; - gui.layout.rawTabhandles = {'metabLoTab', 'refLoTab', 'wLoTab'}; + gui.layout.rawTabhandles = {'metabLoTab', 'mmLoTab'}; + case '1100' + gui.layout.mmLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmLoTab');%re_mm + gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','refLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on','on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab', 'mmLoTab', 'refLoTab'};%re_mm + case '0100' + gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','refLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab','refLoTab'};%re_mm + case '0101' + gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmLoTab');%re_mm + gui.layout.wLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmrefLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on','on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab', 'refLoTab', 'wLoTab'};%re_mm + case '0001' + gui.layout.wLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','wLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab','wLoTab'};%re_mm + case '1010' + gui.layout.mmLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmLoTab');%re_mm + gui.layout.mmrefLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmrefLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on','on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab', 'mmLoTab', 'mmrefLoTab'};%re_mm + case '1110' + gui.layout.mmLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmLoTab');%re_mm + gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','refLoTab');%re_mm + gui.layout.mmrefLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmrefLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on','on','on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab', 'mmLoTab', 'refLoTab', 'mmrefLoTab'};%re_mm + case '1011' + gui.layout.mmLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmLoTab');%re_mm + gui.layout.mmrefLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmrefLoTab');%re_mm + gui.layout.wLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','wLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on','on','on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab', 'mmLoTab', 'mmrefLoTab', 'wLoTab'};%re_mm + case '1111' + gui.layout.mmLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmLoTab');%re_mm + gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','refLoTab');%re_mm + gui.layout.mmrefLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmrefLoTab');% + gui.layout.wLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','wLoTab');%re_mm + gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm + gui.layout.rawTab.TabEnables = {'on', 'on','on','on','on'};%re_mm + gui.layout.rawTabhandles = {'metabLoTab', 'mmLoTab', 'refLoTab', 'mmrefLoTab', 'wLoTab'};%re_mm end - if gui.controls.Number == 4 %re_mm - gui.layout.mmLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','mmLoTab');%re_mm - gui.layout.refLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','refLoTab');%re_mm - gui.layout.wLoTab = uix.VBox('Parent', gui.layout.rawTab, 'BackgroundColor',gui.colormap.Background,'Tag','wLoTab');%re_mm - gui.layout.rawTab.TabTitles = gui.load.Names.Spec;%re_mm - gui.layout.rawTab.TabEnables = {'on', 'on','on','on'};%re_mm - gui.layout.rawTabhandles = {'metabLoTab', 'mmLoTab', 'refLoTab', 'wLoTab'};%re_mm - end%re_mm %%% 3. FILLING INFO PANEL FOR THIS TAB %%% % All the information from the Raw data is read out here for t = gui.controls.Number : -1 : 1 % Loop over subspectra & tabs % Parameter shown in the info panel on top gui.upperBox.data.box{t} = uix.HBox('Parent', gui.layout.(gui.layout.rawTabhandles{t}),'BackgroundColor',gui.colormap.Background, 'Spacing',5); - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - gui.upperBox.data.box{t} = uix.Panel('Parent', gui.upperBox.data.box{t}, ... + if ((isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI)) && ~(MRSCont.nDatasets(2) > 1) + gui.upperBox.data.leftButtons{t} = uix.Panel('Parent', gui.upperBox.data.box{t}, ... 'Padding', 5, 'Title', ['Navigate voxel'],... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); - gui.controls.Buttonbox{t} = uix.HBox('Parent',gui.upperBox.data.box{t}, 'BackgroundColor',gui.colormap.Background); + gui.controls.Buttonbox{t} = uix.HBox('Parent',gui.upperBox.data.leftButtons{t}, 'BackgroundColor',gui.colormap.Background); gui.controls.navigate_RawTab{t} = uix.Grid('Parent',gui.controls.Buttonbox{t},'BackgroundColor',gui.colormap.Background); + if MRSCont.nDatasets(2) > 1 + gui.controls.text_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','Exp',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_left_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + set(gui.controls.b_left_Exp,'Callback',{@osp_onLeftExp,gui}); + end gui.controls.text_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','X:',... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); gui.controls.text_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','Y:',... @@ -130,6 +183,12 @@ function osp_iniLoadWindow(gui) if gui.info.nZvoxels <= 1 gui.controls.b_left_z.Enable = 'off'; end + if MRSCont.nDatasets(2) > 1 + gui.controls.text_act_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_right_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + set(gui.controls.b_right_Exp,'Callback',{@osp_onRightExp,gui}); + end gui.controls.text_act_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); gui.controls.text_act_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... @@ -141,7 +200,7 @@ function osp_iniLoadWindow(gui) gui.controls.b_right_z = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); set(gui.controls.b_right_x,'Callback',{@osp_onRightX,gui}); set(gui.controls.b_right_y,'Callback',{@osp_onRightY,gui}); - set(gui.controls.b_right_z,'Callback',{@osp_onRightZ,gui}); + set(gui.controls.b_right_z,'Callback',{@osp_onRightZ,gui}); if gui.info.nXvoxels <= 1 gui.controls.b_right_x.Enable = 'off'; end @@ -150,9 +209,79 @@ function osp_iniLoadWindow(gui) end if gui.info.nZvoxels <= 1 gui.controls.b_right_z.Enable = 'off'; - end + end set( gui.controls.navigate_RawTab{t}, 'Widths', [-20 -30 -20 -30], 'Heights', [-33 -33 -33] ); end + if MRSCont.nDatasets(2) > 1 + gui.upperBox.data.leftButtons{t} = uix.Panel('Parent', gui.upperBox.data.box{t}, ... + 'Padding', 5, 'Title', ['Navigate extra'],... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... + 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); + gui.controls.Buttonbox{t} = uix.HBox('Parent',gui.upperBox.data.leftButtons{t}, 'BackgroundColor',gui.colormap.Background); + gui.controls.navigate_RawTab{t} = uix.Grid('Parent',gui.controls.Buttonbox{t},'BackgroundColor',gui.colormap.Background); + if MRSCont.nDatasets(2) > 1 + gui.controls.text_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','Exp',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_left_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + set(gui.controls.b_left_Exp,'Callback',{@osp_onLeftExp,gui}); + end + if ((isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI)) + gui.controls.text_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','X:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','Y:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_z = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','Z:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_left_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + gui.controls.b_left_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + gui.controls.b_left_z = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + set(gui.controls.b_left_x,'Callback',{@osp_onLeftX,gui}); + set(gui.controls.b_left_y,'Callback',{@osp_onLeftY,gui}); + set(gui.controls.b_left_z,'Callback',{@osp_onLeftZ,gui}); + if gui.info.nXvoxels <= 1 + gui.controls.b_left_x.Enable = 'off'; + end + if gui.info.nYvoxels <= 1 + gui.controls.b_left_y.Enable = 'off'; + end + if gui.info.nZvoxels <= 1 + gui.controls.b_left_z.Enable = 'off'; + end + end + gui.controls.text_act_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_right_Exp = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + set(gui.controls.b_right_Exp,'Callback',{@osp_onRightExp,gui}); + if ((isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI)) + gui.controls.text_act_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_act_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_act_z = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_right_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + gui.controls.b_right_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + gui.controls.b_right_z = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + set(gui.controls.b_right_x,'Callback',{@osp_onRightX,gui}); + set(gui.controls.b_right_y,'Callback',{@osp_onRightY,gui}); + set(gui.controls.b_right_z,'Callback',{@osp_onRightZ,gui}); + if gui.info.nXvoxels <= 1 + gui.controls.b_right_x.Enable = 'off'; + end + if gui.info.nYvoxels <= 1 + gui.controls.b_right_y.Enable = 'off'; + end + if gui.info.nZvoxels <= 1 + gui.controls.b_right_z.Enable = 'off'; + end + end + if MRSCont.nDatasets(2) > 1 + set( gui.controls.navigate_RawTab{t}, 'Widths', [-20 -30 -20 -30], 'Heights', [-33] ); + else + set( gui.controls.navigate_RawTab{t}, 'Widths', [-20 -30 -20 -30], 'Heights', [-33 -33 -33] ); + end + end + gui.upperBox.data.Info{t} = uix.Panel('Parent', gui.upperBox.data.box{t}, ... 'Padding', 5, 'Title', ['Actual file: ' MRSCont.files{gui.controls.Selected}],... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... @@ -166,7 +295,7 @@ function osp_iniLoadWindow(gui) [img2] = imresize(img, 0.10); set(gui.controls.b_save_RawTab{t},'CData', img2, 'TooltipString', 'Create EPS figure from current file'); set(gui.controls.b_save_RawTab{t},'Callback',{@osp_onPrint,gui}); - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + if ((isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI)) || MRSCont.nDatasets(2) > 1 set(gui.upperBox.data.box{t}, 'Width', [-0.12 -0.78 -0.1]); else set(gui.upperBox.data.box{t}, 'Width', [-0.9 -0.1]); @@ -202,95 +331,113 @@ function osp_iniLoadWindow(gui) end end if ~isfield(MRSCont.flags,'isPRIAM') && ~isfield(MRSCont.flags,'isMRSI') && ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI - set(gui.InfoText.data, 'String', sprintf(StatText)); + if MRSCont.nDatasets(2) == 1 + set(gui.InfoText.data, 'String', sprintf(StatText)); + else + StatText = ['Exp. ' num2str(gui.controls.act_x) ': ' StatText]; + set(gui.InfoText.data{t}, 'String', sprintf(StatText)); + end else StatText = ['Voxel ' num2str(gui.controls.act_x) ': ' StatText]; set(gui.InfoText.data{t}, 'String', sprintf(StatText)); end - + %%% 4. VISUALIZATION PART OF THIS TAB %%% %osp_plotLoad is used to visualize the raw data. Number of subplots %depends on the number of subspectra of the seuqence temp = figure( 'Visible', 'off' ); - if t == 1 %Metabolite data/tab - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets'); - if MRSCont.flags.isUnEdited % One window for UnEdited - drawnow - set( temp.Children(1), 'Parent', gui.Plot.data{t} ); - end - if MRSCont.flags.isMEGA %Two windows for MEGA - set( temp.Children(2), 'Parent', gui.Plot.data{t} ); - set( temp.Children(1), 'Parent', gui.Plot.data{t} ); - set(gui.Plot.data{t},'Heights', [-0.49 -0.49]); - set(gui.Plot.data{t}.Children(2), 'Units', 'normalized') - set(gui.Plot.data{t}.Children(2), 'OuterPosition', [0,0.5,1,0.5]) - set(gui.Plot.data{t}.Children(1), 'Units', 'normalized') - set(gui.Plot.data{t}.Children(1), 'OuterPosition', [0,0,1,0.5]) - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Four windows for HERMES/HERCULES - gui.layout.multiACload = uix.VBox('Parent', gui.Plot.data{t}, 'Padding', 5, 'BackgroundColor',gui.colormap.Background); - gui.layout.multiAload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); - gui.layout.multiCload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); - gui.layout.multiBDload = uix.VBox('Parent', gui.Plot.data{t},'Padding', 5, 'BackgroundColor',gui.colormap.Background); - gui.layout.multiBload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); - gui.layout.multiDload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); - set( temp.Children(1), 'Parent', gui.layout.multiDload ); - set( temp.Children(1), 'Parent', gui.layout.multiCload ); - set( temp.Children(1), 'Parent', gui.layout.multiBload ); - set( temp.Children(1), 'Parent', gui.layout.multiAload ); - set(gui.Plot.data{t},'Width', [-0.49 -0.49]); - set(gui.layout.multiDload.Children(1), 'Units', 'normalized') - set(gui.layout.multiDload.Children(1), 'OuterPosition', [0,0,1,1]) - set(gui.layout.multiCload.Children(1), 'Units', 'normalized') - set(gui.layout.multiCload.Children(1), 'OuterPosition', [0,0,1,1]) - set(gui.layout.multiBload.Children(1), 'Units', 'normalized') - set(gui.layout.multiBload.Children(1), 'OuterPosition', [0,0,1,1]) - set(gui.layout.multiAload.Children(1), 'Units', 'normalized') - set(gui.layout.multiAload.Children(1), 'OuterPosition', [0,0,1,1]) - - end - else - if MRSCont.flags.hasMM %re_mm - if t == 2 %ref data/tab %re_mm - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm'); %re_mm - drawnow - set( temp.Children(1), 'Parent', gui.Plot.data{t} ); %re_mm - end %re_mm - if t == 3 %ref data/tab %re_mm - if MRSCont.flags.hasRef%re_mm - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref'); %re_mm - else%re_mm - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); %re_mm - end%re_mm - drawnow - set( temp.Children(1), 'Parent', gui.Plot.data{t} ); %re_mm - end %re_mm - if t == 4 %ref data/tab %re_mm - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); %re_mm - drawnow - set( temp.Children(1), 'Parent', gui.Plot.data{t} ); %re_mm - end %re_mm - else %re_mm - if t == 2 %ref data/tab - if MRSCont.flags.hasRef - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref'); - drawnow - set( temp.Children(1), 'Parent', gui.Plot.data{t} ); - elseif MRSCont.flags.hasWater - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); - drawnow - set( temp.Children(1), 'Parent', gui.Plot.data{t} ); - end - else %water data/tab has only one window all the time - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); - drawnow - set(temp.Children(1), 'Parent', gui.Plot.data{t} ); + switch gui.load.Names.Spec{t} + case 'metabolites' + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets'); + if MRSCont.flags.isUnEdited % One window for UnEdited + ViewAxes = gca(); + set( ViewAxes, 'Parent', gui.Plot.data{t} ); + end + if MRSCont.flags.isMEGA %Two windows for MEGA + set( temp.Children(2), 'Parent', gui.Plot.data{t} ); + set( temp.Children(1), 'Parent', gui.Plot.data{t} ); + set(gui.Plot.data{t},'Heights', [-0.49 -0.49]); + set(gui.Plot.data{t}.Children(2), 'Units', 'normalized') + set(gui.Plot.data{t}.Children(2), 'OuterPosition', [0,0.5,1,0.5]) + set(gui.Plot.data{t}.Children(1), 'Units', 'normalized') + set(gui.Plot.data{t}.Children(1), 'OuterPosition', [0,0,1,0.5]) + end + if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Four windows for HERMES/HERCULES + gui.layout.multiACload = uix.VBox('Parent', gui.Plot.data{t}, 'Padding', 5, 'BackgroundColor',gui.colormap.Background); + gui.layout.multiAload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiCload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiBDload = uix.VBox('Parent', gui.Plot.data{t},'Padding', 5, 'BackgroundColor',gui.colormap.Background); + gui.layout.multiBload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiDload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + set( temp.Children(1), 'Parent', gui.layout.multiDload ); + set( temp.Children(1), 'Parent', gui.layout.multiCload ); + set( temp.Children(1), 'Parent', gui.layout.multiBload ); + set( temp.Children(1), 'Parent', gui.layout.multiAload ); + set(gui.Plot.data{t},'Width', [-0.49 -0.49]); + set(gui.layout.multiDload.Children(1), 'Units', 'normalized') + set(gui.layout.multiDload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiCload.Children(1), 'Units', 'normalized') + set(gui.layout.multiCload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiBload.Children(1), 'Units', 'normalized') + set(gui.layout.multiBload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiAload.Children(1), 'Units', 'normalized') + set(gui.layout.multiAload.Children(1), 'OuterPosition', [0,0,1,1]) + end - end %re_mm + case 'MM' + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm'); + if MRSCont.flags.isUnEdited % One window for UnEdited + ViewAxes = gca(); + set( ViewAxes, 'Parent', gui.Plot.data{t} ); + end + if MRSCont.flags.isMEGA %Two windows for MEGA + set( temp.Children(2), 'Parent', gui.Plot.data{t} ); + set( temp.Children(1), 'Parent', gui.Plot.data{t} ); + set(gui.Plot.data{t},'Heights', [-0.49 -0.49]); + set(gui.Plot.data{t}.Children(2), 'Units', 'normalized') + set(gui.Plot.data{t}.Children(2), 'OuterPosition', [0,0.5,1,0.5]) + set(gui.Plot.data{t}.Children(1), 'Units', 'normalized') + set(gui.Plot.data{t}.Children(1), 'OuterPosition', [0,0,1,0.5]) + end + if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Four windows for HERMES/HERCULES + gui.layout.multiACload = uix.VBox('Parent', gui.Plot.data{t}, 'Padding', 5, 'BackgroundColor',gui.colormap.Background); + gui.layout.multiAload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiCload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiBDload = uix.VBox('Parent', gui.Plot.data{t},'Padding', 5, 'BackgroundColor',gui.colormap.Background); + gui.layout.multiBload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiDload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + set( temp.Children(1), 'Parent', gui.layout.multiDload ); + set( temp.Children(1), 'Parent', gui.layout.multiCload ); + set( temp.Children(1), 'Parent', gui.layout.multiBload ); + set( temp.Children(1), 'Parent', gui.layout.multiAload ); + set(gui.Plot.data{t},'Width', [-0.49 -0.49]); + set(gui.layout.multiDload.Children(1), 'Units', 'normalized') + set(gui.layout.multiDload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiCload.Children(1), 'Units', 'normalized') + set(gui.layout.multiCload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiBload.Children(1), 'Units', 'normalized') + set(gui.layout.multiBload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiAload.Children(1), 'Units', 'normalized') + set(gui.layout.multiAload.Children(1), 'OuterPosition', [0,0,1,1]) + + end + case 'reference' + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref'); %re_mm + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', gui.Plot.data{t} ); %re_mm + case 'MM reference' + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm_ref'); %re_mm + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', gui.Plot.data{t} ); %re_mm + case 'water' + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); %re_mm + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', gui.Plot.data{t} ); %re_mm end + % Get rid of the Load figure - close( temp ); + close( temp ); end h = findall(groot,'Type','figure'); for ff = 1 : length(h) @@ -299,4 +446,4 @@ function osp_iniLoadWindow(gui) end end setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class -end \ No newline at end of file +end diff --git a/GUI/osp_iniOverviewWindow.m b/GUI/osp_iniOverviewWindow.m index 41c787be..86658338 100644 --- a/GUI/osp_iniOverviewWindow.m +++ b/GUI/osp_iniOverviewWindow.m @@ -41,7 +41,7 @@ function osp_iniOverviewWindow(gui) gui.layout.overviewTab.TabWidth = 115; gui.layout.overviewTab.Selection = 1; - + gui.layout.overviewTabhandels = {'specsOvTab','meanOvTab','quantOvTab','distrOvTab','corrOvTab','diceOvTab'}; % Check version of Osprey - since we have changed the layout of the Overview struct with the implementation of DualVoxel if isfield(MRSCont.overview.Osprey, 'sort_data') sort_data = 'sort_data'; @@ -56,17 +56,32 @@ function osp_iniOverviewWindow(gui) 'BackgroundColor',gui.colormap.Background,'Padding', 5); %Creates popup menu for the processed Subspectra (A,B,C,D,mm,ref,water) .... re_mm - tempFitNames = gui.layout.fitTab.TabTitles; - if ~isempty(tempFitNames) - for i = 1 : gui.fit.Number - tempFitNames{i} = strcat('Fit: ',tempFitNames{i}); + SubNames = fieldnames(MRSCont.overview.SubSpecNamesStruct); + k=1; + if ~isempty(SubNames) + for i = 1 : gui.process.Number + for j = 1 :size(MRSCont.overview.SubSpecNamesStruct.(SubNames{i}),2) + tempSubNames{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + k=k+1; + end end - if MRSCont.flags.hasMM - tempFitNames{gui.fit.Number+1} = 'MM_clean'; + end + + FitNames = fieldnames(MRSCont.overview.FitSpecNamesStruct); + k=1; + if ~isempty(FitNames) + for i = 1 : gui.fit.Number + for j = 1 :size(MRSCont.overview.FitSpecNamesStruct.(FitNames{i}),2) + tempFitNames{k} = ['Model ', FitNames{i}, ' ', MRSCont.overview.FitSpecNamesStruct.(FitNames{i}){1,j}]; + k=k+1; + end end end gui.upperBox.specsOv.box = uix.HBox('Parent', gui.Plot.specsOv,'BackgroundColor',gui.colormap.Background, 'Spacing',5); + + gui = upper_navigate_box(gui, 'specsOv','metab',1); + gui.controls.specsOvPlot = uix.Panel('Parent', gui.upperBox.specsOv.box,'Title', 'Individual spectra or fit', ... 'Padding', 5,'HighlightColor', gui.colormap.Foreground,'BackgroundColor',gui.colormap.Background,... 'ForegroundColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); @@ -74,7 +89,7 @@ function osp_iniOverviewWindow(gui) 'Padding', 5, 'Spacing', 10,'BackgroundColor',gui.colormap.Background); gui.controls.pop_specsOvPlot = uicontrol('Parent',gui.controls.specsOv,'style','popupmenu',... 'Units', 'Normalized', 'Position', [0 0 1 1],'FontName', gui.font, ... - 'String',[gui.layout.proTab.TabTitles;tempFitNames], 'Value', 1); + 'String',[tempSubNames';tempFitNames'], 'Value', 1); gui.controls.check_specsOvPlot = uicontrol('Parent',gui.controls.specsOv,'Style','checkbox','BackgroundColor',gui.colormap.Background,'String','Grand Mean', ... 'Value',gui.controls.GM,'Position',[0 0 1 1],'FontName', gui.font); gui.upperBox.specsOv.upperButtons = uix.Panel('Parent', gui.upperBox.specsOv.box, ... @@ -86,13 +101,13 @@ function osp_iniOverviewWindow(gui) [img2] = imresize(img, 0.05); set(gui.controls.b_save_specOvTab,'CData', img2, 'TooltipString', 'Create EPS figure from current file'); set(gui.controls.b_save_specOvTab,'Callback',{@osp_onPrint,gui}); - set(gui.upperBox.specsOv.box, 'Width', [-0.9 -0.1]) + set(gui.upperBox.specsOv.box, 'Width', [-0.16 -0.74 -0.1]) set(gui.controls.specsOv, 'Width', [-0.85 -0.15]) %op_plotspec is used to visualize the processed data gui.layout.shiftind = 0.2; for g = 1 : gui.overview.Number.Groups %Loop over groups. Difterenc colors and shifts for different groups - temp = osp_plotOverviewSpec(MRSCont, gui.process.Names{gui.process.Selected}, g, gui.layout.shiftind); + temp = osp_plotOverviewSpec(MRSCont, tempSubNames{1}, g, gui.layout.shiftind); if g == 1 ViewAxes=get(temp,'Children'); drawnow @@ -119,14 +134,35 @@ function osp_iniOverviewWindow(gui) else %Water data? set(gui.Plot.specsOv.Children(2), 'XLim', [0 2*4.68]) end - set(gui.Plot.specsOv,'Heights', [-0.07 -0.93]); + set(gui.Plot.specsOv,'Heights', [-0.1 -0.9]); %%% 3. MEAN SPECS %%% gui.layout.overviewTab.Selection = 2; gui.Plot.meanOv = uix.VBox('Parent', gui.layout.meanOvTab,'BackgroundColor',gui.colormap.Background,'Padding', 5); + + SubNames = fieldnames(MRSCont.overview.SubSpecNamesStruct); + k=1; + if ~isempty(SubNames) + for i = 1 : gui.process.Number + for j = 1 :size(MRSCont.overview.SubSpecNamesStruct.(SubNames{i}),2) + if ~isempty(find(strcmp(FitNames,SubNames{i}))) + if (~isempty(find(strcmp(MRSCont.overview.FitSpecNamesStruct.(SubNames{i}),MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j})))) + tempSubNamesFit{k} = ['Model ' , SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + else + tempSubNamesFit{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + end + else + tempSubNamesFit{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + end + k=k+1; + end + end + end + %Creates popup menu for the processed Subspectra and fits (A,B,C,D,ref,water) gui.upperBox.meanOv.box = uix.HBox('Parent', gui.Plot.meanOv,'BackgroundColor',gui.colormap.Background, 'Spacing',5); + gui = upper_navigate_box(gui, 'meanOv','metab',1); gui.controls.meanOvPlot = uix.Panel('Parent', gui.upperBox.meanOv.box,'Title', 'Actual spectrum', ... 'Padding', 5,'HighlightColor', gui.colormap.Foreground,'BackgroundColor',gui.colormap.Background,... 'ForegroundColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); @@ -134,7 +170,7 @@ function osp_iniOverviewWindow(gui) 'Padding', 5, 'Spacing', 10,'BackgroundColor',gui.colormap.Background); gui.controls.pop_meanOvPlot = uicontrol('Parent',gui.controls.meanOv,'style','popupmenu',... 'Units', 'Normalized', 'Position', [0 0 1 1],'FontName', gui.font, ... - 'String',gui.layout.proTab.TabTitles, 'Value', 1); + 'String',tempSubNamesFit, 'Value', 1); gui.controls.check_meanOvPlot = uicontrol('Parent',gui.controls.meanOv,'Style','checkbox','BackgroundColor',gui.colormap.Background,'String','Grand Mean', ... 'Value',gui.controls.GM,'Position',[0 0 1 1],'FontName', gui.font); gui.upperBox.meanOv.upperButtons = uix.Panel('Parent', gui.upperBox.meanOv.box, ... @@ -146,7 +182,7 @@ function osp_iniOverviewWindow(gui) [img2] = imresize(img, 0.05); set(gui.controls.b_save_meanOvTab,'CData', img2, 'TooltipString', 'Create EPS figure from current file'); set(gui.controls.b_save_meanOvTab,'Callback',{@osp_onPrint,gui}); - set(gui.upperBox.meanOv.box, 'Width', [-0.9 -0.1]) + set(gui.upperBox.meanOv.box, 'Width', [-0.16 -0.74 -0.1]) set(gui.controls.meanOv, 'Width', [-0.85 -0.15]) %op_plotspec is used for a dummy plot which is update later gui.layout.shift = 0.5; @@ -168,6 +204,9 @@ function osp_iniOverviewWindow(gui) set(gcf,'Color','w'); title(['Overview ' gui.layout.proTab.TabTitles{gui.load.Selected}],'Color', MRSCont.colormap.Foreground); ax=get(temp,'Parent'); + if iscell(ax) + ax = ax{1}; + end figpl = get(ax,'Parent'); ViewAxes = gca(); drawnow @@ -179,7 +218,7 @@ function osp_iniOverviewWindow(gui) set(gui.Plot.meanOv.Children(2), 'XLim', [0 2*4.68]) end osp_updatemeanOvWindow(gui); %Update the plot with the mean and SD - set(gui.Plot.meanOv,'Heights', [-0.07 -0.93]); + set(gui.Plot.meanOv,'Heights', [-0.1 -0.9]); %%% 4. QUANTIFICATION TABLE %%% if isfield(gui.quant, 'Number') @@ -187,42 +226,31 @@ function osp_iniOverviewWindow(gui) gui.layout.overviewTab.Selection = 3; gui.Plot.quantOv = uix.VBox('Parent', gui.layout.quantOvTab,'BackgroundColor',gui.colormap.Background,'Padding', 5); - %Creates Popup menu to change between quantifications (tCr, waterScaled etc.) - tempFitNames = cell(1); - if strcmp(MRSCont.opts.fit.style,'Concatenated') - tempFitNames{1} = 'conc'; - if MRSCont.flags.hasRef - tempFitNames{2} = 'ref'; - end - if MRSCont.flags.hasWater - if MRSCont.flags.hasRef - tempFitNames{3} = 'w'; - else - tempFitNames{2} = 'w'; - end - end - else - tempFitNames = gui.layout.fitTab.TabTitles; - end - - popMenuNames_Count = 0; - if strcmp(MRSCont.opts.fit.style,'Concatenated') - fitNumber = length(tempFitNames); - else - fitNumber = gui.fit.Number; - end - for i = 0 : fitNumber-1 - if ~strcmp(tempFitNames{i+1},'ref') && ~strcmp(tempFitNames{i+1},'w') && ~strcmp(tempFitNames{i+1},'mm') - gui.quant.Number.Quants = length(fieldnames(MRSCont.quantify.tables.(tempFitNames{i+1}))); - gui.quant.Names.Quants = fieldnames(MRSCont.quantify.tables.(tempFitNames{i+1})); - for j = 1 : gui.quant.Number.Quants - popMenuNames_Count = popMenuNames_Count + 1; - gui.quant.popMenuNames{popMenuNames_Count} = [strcat(tempFitNames{i+1}, '-') ,gui.quant.Names.Quants{j}]; + %Creates Popup menu to change between quantifications (tCr, waterScaled etc.) + FitNames = fieldnames(MRSCont.overview.FitSpecNamesStruct); + l=1; + if ~isempty(FitNames) + for i = 1 : gui.fit.Number + for k = 1 :size(MRSCont.overview.FitSpecNamesStruct.(FitNames{i}),2) + if isfield(MRSCont.quantify.tables,FitNames{i}) + for j = 1 : length(fieldnames(MRSCont.quantify.tables.(FitNames{i}))) + QuantNames = fieldnames(MRSCont.quantify.tables.(FitNames{i})); + if ~strcmp(FitNames{i},'ref') && ~strcmp(FitNames{i},'w') && ~strcmp(FitNames{i},'mm') + tempFitNames{l} = [FitNames{i}, '-', MRSCont.overview.FitSpecNamesStruct.(FitNames{i}){1,k}, '-', QuantNames{j}]; + l=l+1; + end + end + end end end end - gui.quant.popMenuNames{popMenuNames_Count+1} = 'Quality'; - gui.controls.quantOvPlot = uix.Panel('Parent', gui.Plot.quantOv,'Title', 'Actual Quantification', ... + + + tempFitNames{end+1} = 'Quality'; + gui.quant.popMenuNames = tempFitNames; + gui.upperBox.quantOv.box = uix.HBox('Parent', gui.Plot.quantOv,'BackgroundColor',gui.colormap.Background, 'Spacing',5); + gui = upper_navigate_box(gui, 'quantOv','metab',1); + gui.controls.quantOvPlot = uix.Panel('Parent', gui.upperBox.quantOv.box,'Title', 'Actual Quantification', ... 'Padding', 5,'HighlightColor', gui.colormap.Foreground,'BackgroundColor',gui.colormap.Background,... 'ForegroundColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); gui.controls.pop_quantOvPlot = uicontrol('Parent',gui.controls.quantOvPlot,'style','popupmenu',... @@ -235,14 +263,14 @@ function osp_iniOverviewWindow(gui) 'Title', ['Results: ' (gui.quant.Names.Model{gui.quant.Selected.Model}) '-' (gui.quant.Names.Quants{gui.quant.Selected.Quant})],... 'FontName', gui.font,'HighlightColor', gui.colormap.Foreground,'BackgroundColor',gui.colormap.Background,... 'ForegroundColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); - QuantTextOv = cell(MRSCont.nDatasets+1,length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}))); - QuantTextOv(1,:) = MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}); - QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{gui.quant.Selected.Quant}).Voxel_1(:,:)); + QuantTextOv = cell(MRSCont.nDatasets(1)+1,length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){1,1})); + QuantTextOv(1,:) = MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){1,1}; + QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{gui.quant.Selected.Quant}).Voxel_1{1,1}(:,:)); temp=uimulticollist ( 'units', 'normalized', 'position', [0 0 1 1], 'string', QuantTextOv,... 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); set(temp,'BackgroundColor',gui.colormap.Background) set(temp, 'Parent', gui.Results.quantOv ); - set(gui.Plot.quantOv,'Heights', [-0.07 -0.93]); + set(gui.Plot.quantOv,'Heights', [-0.10 -0.9]); else gui.Results.quantOv1 = uix.Panel('Parent', gui.Plot.quantOv, 'Padding', 5, ... 'Title', ['Results Voxel 1: ' (gui.quant.Names.Model{gui.quant.Selected.Model}) '-' (gui.quant.Names.Quants{gui.quant.Selected.Quant})],... @@ -268,15 +296,17 @@ function osp_iniOverviewWindow(gui) set(temp,'BackgroundColor',gui.colormap.Background) set(temp, 'Parent', gui.Results.quantOv2 ); - set(gui.Plot.quantOv,'Heights', [-0.07 -0.46 -0.46]); + set(gui.Plot.quantOv,'Heights', [-0.10 -0.45 -0.45]); end - + set(gui.upperBox.quantOv.box, 'Width', [-0.16 -0.84]) %%% 5. RAINCLOUD PLOTS %%% gui.layout.overviewTab.Selection = 4; gui.Plot.distrOv = uix.VBox('Parent', gui.layout.distrOvTab, 'BackgroundColor',gui.colormap.Background,'Padding', 5); %Creates popup menus for differnt quantifications and metabolites gui.upperBox.distrOv.box = uix.HBox('Parent', gui.Plot.distrOv,'BackgroundColor',gui.colormap.Background, 'Spacing',5); + gui = upper_navigate_box(gui, 'distrOv','metab',1); + if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) gui.upperBox.distrOv.upperLeftButtons = uix.Panel('Parent', gui.upperBox.distrOv.box, ... 'Padding', 5, 'Title', ['Navigate voxel'],... @@ -338,7 +368,7 @@ function osp_iniOverviewWindow(gui) 'String',gui.quant.popMenuNames, 'Value', 1); gui.controls.pop_distrOvMetab = uicontrol('Parent',gui.controls.distrOv,'style','popupmenu',... 'Units', 'Normalized', 'Position', [0 0 1 1],'FontName', gui.font, ... - 'String',MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}), 'Value', 1); + 'String',MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){1,1}, 'Value', 1); gui.controls.check_distrOv = uicontrol('Parent',gui.controls.distrOv,'Style','checkbox','BackgroundColor',gui.colormap.Background,'String','Grand Mean', ... 'Value',gui.controls.GM,'Position',[0 0 1 1],'FontName', gui.font); gui.upperBox.distrOv.upperButtons = uix.Panel('Parent', gui.upperBox.distrOv.box, ... @@ -350,15 +380,13 @@ function osp_iniOverviewWindow(gui) [img2] = imresize(img, 0.05); set(gui.controls.b_save_distrOvTab,'CData', img2, 'TooltipString', 'Create EPS figure from current file'); set(gui.controls.b_save_distrOvTab,'Callback',{@osp_onPrint,gui}); - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - set(gui.upperBox.distrOv.box, 'Width', [-0.12 -0.78 -0.1]) - else - set(gui.upperBox.distrOv.box, 'Width', [-0.9 -0.1]) - end + + set(gui.upperBox.distrOv.box, 'Width', [-0.16 -0.74 -0.1]) + %osp_plotQuantifyTable to create distribution overview as raincloud plot temp = figure( 'Visible', 'off' ); - [temp] = osp_plotRaincloud(MRSCont,gui.quant.Names.Model{gui.quant.Selected.Model}, gui.quant.Names.Quants{gui.quant.Selected.Quant},MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.overview.Selected.Metab},'Raincloud plot'); + [temp] = osp_plotRaincloud(MRSCont,MRSCont.overview.FitSpecNamesStruct.metab{gui.quant.Selected.Model}, gui.quant.Names.Quants{gui.quant.Selected.Quant},MRSCont.quantify.names.metab{gui.quant.Selected.Model}{gui.overview.Selected.Metab},'Raincloud plot',0,1); ViewAxes = gca(); set(ViewAxes, 'Parent', gui.Plot.distrOv); close( temp ); @@ -374,6 +402,8 @@ function osp_iniOverviewWindow(gui) % Creates popup menu for differnt quantification, metabolite and % correaltion measure gui.upperBox.corrOv.box = uix.HBox('Parent', gui.Plot.corrOv,'BackgroundColor',gui.colormap.Background, 'Spacing',5); + gui = upper_navigate_box(gui, 'corrOv','metab',1); + if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) gui.upperBox.corrOv.upperLeftButtons = uix.Panel('Parent', gui.upperBox.corrOv.box, ... 'Padding', 5, 'Title', ['Navigate voxel'],... @@ -434,7 +464,7 @@ function osp_iniOverviewWindow(gui) 'String',gui.quant.popMenuNames, 'Value', 1); gui.controls.pop_corrOvMetab = uicontrol('Parent',gui.controls.corrOv,'style','popupmenu',... 'Units', 'Normalized', 'Position', [0 0 1 1],'FontName', gui.font, ... - 'String',MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}), 'Value', 1); + 'String',MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){1,1}, 'Value', 1); gui.controls.pop_corrOvCorr = uicontrol('Parent',gui.controls.corrOv,'style','popupmenu',... 'Units', 'Normalized', 'Position', [0 0 1 1],'FontName', gui.font, ... 'String',gui.overview.Names.QM, 'Value', 1); @@ -456,19 +486,17 @@ function osp_iniOverviewWindow(gui) [img2] = imresize(img, 0.05); set(gui.controls.b_save_corrOvTab,'CData', img2, 'TooltipString', 'Create EPS figure from current file'); set(gui.controls.b_save_corrOvTab,'Callback',{@osp_onPrint,gui}); - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - set(gui.upperBox.corrOv.box, 'Width', [-0.12 -0.78 -0.1]) - else - set(gui.upperBox.corrOv.box, 'Width', [-0.9 -0.1]) - end + + set(gui.upperBox.corrOv.box, 'Width', [-0.16 -0.74 -0.1]) + %%%%%%%%%%%%%%%%%%VISUALIZATION PART OF THIS TAB%%%%%%%%%%%%%%%%%%%%%%%% %osp_plotQuantifyTable is used to create a correlation plot temp = figure( 'Visible', 'off' ); if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - [temp] = osp_plotScatter(MRSCont, gui.quant.Names.Model{gui.quant.Selected.Model}, gui.quant.Names.Quants{gui.quant.Selected.Quant},MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.overview.Selected.Metab},MRSCont.QM.SNR.A',gui.overview.Names.QM{gui.overview.Selected.Corr}); + [temp] = osp_plotScatter(MRSCont, MRSCont.overview.FitSpecNamesStruct.(FitNames{1}){1,1}, gui.quant.Names.Quants{gui.quant.Selected.Quant},MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){1,1}{gui.overview.Selected.Metab},MRSCont.QM.SNR.metab(1,:,1)',gui.overview.Names.QM{gui.overview.Selected.Corr}); elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - [temp] = osp_plotScatter(MRSCont, gui.quant.Names.Model{gui.quant.Selected.Model}, gui.quant.Names.Quants{gui.quant.Selected.Quant},MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.overview.Selected.Metab},MRSCont.QM{1,gui.controls.act_x}.SNR.A',gui.overview.Names.QM{gui.overview.Selected.Corr},1); + [temp] = osp_plotScatter(MRSCont, MRSCont.overview.FitSpecNamesStruct.(FitNames{1}){1,1}, gui.quant.Names.Quants{gui.quant.Selected.Quant},MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.overview.Selected.Metab},MRSCont.QM{1,gui.controls.act_x}.SNR.A(1,:,1)',gui.overview.Names.QM{gui.overview.Selected.Corr},1); end ViewAxes = gca(); set(ViewAxes, 'Parent', gui.Plot.corrOv); @@ -482,6 +510,6 @@ function osp_iniOverviewWindow(gui) if ~(strcmp(h(ff).Tag, 'Osprey') || strcmp(h(ff).Tag, 'TMWWaitbar')) close(h(ff)) end - end + end setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class end diff --git a/GUI/osp_iniProcessWindow.m b/GUI/osp_iniProcessWindow.m index 3950e72e..9b7fd958 100644 --- a/GUI/osp_iniProcessWindow.m +++ b/GUI/osp_iniProcessWindow.m @@ -32,195 +32,49 @@ function osp_iniProcessWindow(gui) gui.layout.EmptyProPlot = 0; %%% 2. CREATING SUB TABS FOR THIS TAB %%% % In this case one tab fo each subspec (A,B,C,D,ref,water) - gui.layout.AProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); + gui.layout.metabProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); gui.layout.proTab.TabWidth = 90; - gui.layout.proTabhandles = {'AProTab'}; + gui.layout.proTabhandles = {'metabProTab'}; % Set up tabs with regard to the sequence type - if MRSCont.flags.isUnEdited %Is UnEdited? - if (MRSCont.flags.hasRef && MRSCont.flags.hasWater && MRSCont.flags.hasMM ) %Has all%re_mm - gui.layout.mmProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5);%re_mm - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5);%re_mm - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5);%re_mm - gui.layout.proTab.TabTitles = {'A', 'MM','ref','w'};%re_mm - gui.layout.proTab.TabEnables = {'on', 'on','on','on'};%re_mm - gui.layout.proTabhandles = {'AProTab','mmProTab', 'refProTab', 'wProTab'}; % Create 4 Tabs %re_mm - gui.process.SNR = {'tNAA','MM09','water','water'};%re_mm - elseif (~MRSCont.flags.hasRef && MRSCont.flags.hasWater && MRSCont.flags.hasMM ) %Has all%re_mm - gui.layout.mmProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5);%re_mm - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5);%re_mm - gui.layout.proTab.TabTitles = {'A', 'MM','w'};%re_mm - gui.layout.proTab.TabEnables = {'on', 'on','on'};%re_mm - gui.layout.proTabhandles = {'AProTab','mmProTab', 'wProTab'}; % Create 4 Tabs %re_mm - gui.process.SNR = {'tNAA','MM09','water'};%re_mm - elseif (MRSCont.flags.hasRef && ~MRSCont.flags.hasWater && MRSCont.flags.hasMM ) %Has all%re_mm - gui.layout.mmProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5);%re_mm - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5);%re_mm - gui.layout.proTab.TabTitles = {'A', 'MM','w'};%re_mm - gui.layout.proTab.TabEnables = {'on', 'on','on'};%re_mm - gui.layout.proTabhandles = {'AProTab','mmProTab', 'refProTab'}; % Create 4 Tabs %re_mm - gui.process.SNR = {'tNAA','MM09','water'};%re_mm - elseif (MRSCont.flags.hasRef && MRSCont.flags.hasWater && ~MRSCont.flags.hasMM) %Has water and reference (This should actually not happen with UnEdited data...) - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','ref','w'}; - gui.layout.proTab.TabEnables = {'on','on','on'}; - gui.layout.proTabhandles = {'AProTab', 'refProTab', 'wProTab'}; % Create 3 Tabs - gui.process.SNR = {'tNAA','water','water'}; - elseif (~MRSCont.flags.hasRef && ~MRSCont.flags.hasWater && ~MRSCont.flags.hasMM) %Only metabolite data - gui.layout.proTab.TabTitles = {'A'}; - gui.layout.proTab.TabEnables = {'on'}; - gui.layout.proTabhandles = {'AProTab'}; % Create 1 Tab - gui.process.SNR = {'tNAA'}; - else - if MRSCont.flags.hasRef %Has only reference? - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','ref'}; - gui.layout.proTab.TabEnables = {'on', 'on'}; - gui.layout.proTabhandles = {'AProTab', 'refProTab'}; % Create 2 Tabs - gui.process.SNR = {'tNAA','water'}; - end - if MRSCont.flags.hasWater %Has only water? - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','w'}; - gui.layout.proTab.TabEnables = {'on', 'on'}; - gui.layout.proTabhandles = {'AProTab', 'wProTab'}; %Create 2 Tabs - gui.process.SNR = {'tNAA','water'}; - end - end + + TabTitles = {'metab'}; + gui.process.metab.SNR = MRSCont.processed.metab{1,1}.QC_names; + gui.process.metab.name = MRSCont.processed.metab{1,1}.names; + if MRSCont.flags.hasMM + TabTitles = horzcat(TabTitles, 'mm'); + gui.process.mm.SNR = MRSCont.processed.mm{1,1}.QC_names; + gui.process.mm.name = MRSCont.processed.mm{1,1}.names; end - if MRSCont.flags.isMEGA %Is MEGA? - if (MRSCont.flags.hasRef && MRSCont.flags.hasWater) %Has water and reference? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','diff1','sum','ref','w'}; - gui.layout.proTab.TabEnables = {'on', 'on','on', 'on', 'on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab', 'diff1ProTab','sumProTab', 'refProTab', 'wProTab'}; %Create 6 tabs - gui.process.SNR = {'tNAA','tCr',MRSCont.processed.diff1{1,gui.process.Selected}.target,'tNAA','water','water'}; - if iscell(gui.process.SNR{3}) - gui.process.SNR{3} = gui.process.SNR{3}{1}; - end - elseif (~MRSCont.flags.hasRef && ~MRSCont.flags.hasWater) %Only metabolites? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','diff1','sum'}; - gui.layout.proTab.TabEnables = {'on', 'on','on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab', 'diff1ProTab','sumProTab',}; %Create 4 tabs - gui.process.SNR = {'tNAA','tCr',MRSCont.processed.diff1{1,gui.process.Selected}.target,'water'}; - if iscell(gui.process.SNR{3}) - gui.process.SNR{3} = gui.process.SNR{3}{1}; - end - else - if MRSCont.flags.hasRef %Has only reference? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','diff1','sum','ref'}; - gui.layout.proTab.TabEnables = {'on', 'on','on', 'on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab', 'diff1ProTab','sumProTab', 'refProTab'}; %Create 5 tabs - gui.process.SNR = {'tNAA','tCr',MRSCont.processed.diff1{1,gui.process.Selected}.target,'tNAA','water'}; - if iscell(gui.process.SNR{3}) - gui.process.SNR{3} = gui.process.SNR{3}{1}; - end - end - if MRSCont.flags.hasWater %Has only water? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','diff1','sum','w'}; - gui.layout.proTab.TabEnables = {'on', 'on','on', 'on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab', 'diff1ProTab','sumProTab', 'wProTab'}; %Create 5 tabs - gui.process.SNR = {'tNAA','tCr',MRSCont.processed.diff1{1,gui.process.Selected}.target,'tNAA','water'}; - if iscell(gui.process.SNR{3}) - gui.process.SNR{3} = gui.process.SNR{3}{1}; - end - end - end + if MRSCont.flags.hasRef + TabTitles = horzcat(TabTitles, 'ref'); + gui.process.ref.SNR = MRSCont.processed.ref{1,1}.QC_names; + gui.process.ref.name = MRSCont.processed.ref{1,1}.names; end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Is HERMES\HERCULES? - if (MRSCont.flags.hasRef && MRSCont.flags.hasWater) %Has water and reference? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.CProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.DProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff2ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','C','D','diff1', 'diff2','sum','ref','w'}; - gui.layout.proTab.TabEnables = {'on', 'on','on', 'on', 'on', 'on', 'on', 'on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab','CProTab','DProTab', 'diff1ProTab', 'diff2ProTab', 'sumProTab', 'refProTab', 'wProTab'}; %Create 9 tabs - try - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target{1},MRSCont.processed.diff2{1,gui.process.Selected}.target{1},'tNAA','water','water'}; - catch - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target,MRSCont.processed.diff2{1,gui.process.Selected}.target,'tNAA','water','water'}; - end - elseif (~MRSCont.flags.hasRef && ~MRSCont.flags.hasWater) %Only metabs? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.CProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.DProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff2ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','C','D','diff1', 'diff2','sum'}; - gui.layout.proTab.TabEnables = {'on', 'on','on', 'on', 'on', 'on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab','CProTab','DProTab', 'diff1ProTab', 'diff2ProTab', 'sumProTab'}; %Create 7 tabs - try - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target{1},MRSCont.processed.diff2{1,gui.process.Selected}.target{1},'tNAA'}; - catch - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target,MRSCont.processed.diff2{1,gui.process.Selected}.target,'tNAA'}; - end - else - if MRSCont.flags.hasRef %Has only reference? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.CProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.DProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff2ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.refProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','C','D','diff1', 'diff2','sum','ref'}; - gui.layout.proTab.TabEnables = {'on', 'on','on','on', 'on', 'on', 'on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab','CProTab','DProTab','diff1ProTab', 'diff2ProTab', 'sumProTab','refProTab'}; %Create 8 tabs - try - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target{1},MRSCont.processed.diff2{1,gui.process.Selected}.target{1},'tNAA','water'}; - catch - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target,MRSCont.processed.diff2{1,gui.process.Selected}.target,'tNAA','water'}; - end - end - if MRSCont.flags.hasWater %Has only water? - gui.layout.BProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.CProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.DProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff1ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.diff2ProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.sumProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.wProTab = uix.VBox('Parent', gui.layout.proTab, 'Padding', 5,'BackgroundColor',gui.colormap.Background,'Spacing',5); - gui.layout.proTab.TabTitles = {'A','B','C','D','diff1', 'diff2','sum','w'}; - gui.layout.proTab.TabEnables = {'on', 'on','on','on', 'on', 'on', 'on', 'on'}; - gui.layout.proTabhandles = {'AProTab','BProTab','CProTab','DProTab','diff1ProTab', 'diff2ProTab', 'sumProTab','wProTab'}; %Create 8 tabs - try - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target{1},MRSCont.processed.diff2{1,gui.process.Selected}.target{1},'tNAA','water'}; - catch - gui.process.SNR = {'tNAA','tCr','tNAA', 'tCr', MRSCont.processed.diff1{1,gui.process.Selected}.target,MRSCont.processed.diff2{1,gui.process.Selected}.target,'tNAA','water'}; - end - end - end + if MRSCont.flags.hasMMRef + TabTitles = horzcat(TabTitles, 'mm_ref'); + gui.process.mm_ref.SNR = MRSCont.processed.mm_ref{1,1}.QC_names; + gui.process.mm_ref.name = MRSCont.processed.mm_ref{1,1}.names; end - + if MRSCont.flags.hasWater + TabTitles = horzcat(TabTitles, 'w'); + gui.process.w.SNR = MRSCont.processed.w{1,1}.QC_names; + gui.process.w.name = MRSCont.processed.w{1,1}.names; + end + for t = 2 : length(TabTitles) + gui.layout.(strcat(TabTitles{t},'ProTab')) = uix.VBox('Parent', gui.layout.proTab,'BackgroundColor',gui.colormap.Background,'Spacing',5); + end + gui.layout.proTabhandles = strcat(TabTitles,'ProTab'); + gui.process.TabTitles = TabTitles; + gui.layout.proTab.TabTitles = TabTitles; %%% 3. FILLING INFO PANEL FOR THIS TAB %%% % All the information from the Raw data is read out here for t = length(gui.layout.proTabhandles) : -1 : 1 %Loop over subspecs/tabs - ind=find(ismember(gui.layout.proTabhandles,[gui.process.Names{t} 'ProTab'])); - gui.layout.proTab.Selection = ind; - gui.upperBox.pro.box{ind} = uix.HBox('Parent', gui.layout.(gui.layout.proTabhandles{ind}),'BackgroundColor',gui.colormap.Background,'Spacing',5); - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - gui.upperBox.data.upperLeftButtons = uix.Panel('Parent', gui.upperBox.pro.box{ind}, ... +% ind=find(ismember(gui.layout.proTabhandles,[gui.process.TabTitles{t} 'ProTab'])); + gui.layout.proTab.Selection = t; + gui.layout.proTab.TabEnables{t} = 'on'; + gui.upperBox.pro.box{t} = uix.HBox('Parent', gui.layout.(gui.layout.proTabhandles{t}),'BackgroundColor',gui.colormap.Background,'Spacing',5); + if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + gui.upperBox.data.upperLeftButtons = uix.Panel('Parent', gui.upperBox.pro.box{t}, ... 'Padding', 5, 'Title', ['Navigate voxel'],... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); @@ -271,104 +125,121 @@ function osp_iniProcessWindow(gui) end set( gui.controls.navigate_RawTab, 'Widths', [-20 -30 -20 -30], 'Heights', [-33 -33 -33] ); end - gui.upperBox.pro.Info{ind} = uix.Panel('Parent', gui.upperBox.pro.box{ind}, ... + + + + gui.upperBox.pro.upperLeftButtons{t} = uix.Panel('Parent', gui.upperBox.pro.box{t}, ... + 'Padding', 5, 'Title', ['Navigate data'],... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... + 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); + gui.controls.Buttonbox{t} = uix.HBox('Parent',gui.upperBox.pro.upperLeftButtons{t}, 'BackgroundColor',gui.colormap.Background); + gui.controls.navigate_RawTab{t} = uix.Grid('Parent',gui.controls.Buttonbox{t},'BackgroundColor',gui.colormap.Background); + + gui.controls.text_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','Exp:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','Spec:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_left_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + gui.controls.b_left_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + set(gui.controls.b_left_x,'Callback',{@osp_onLeftX,gui}); + set(gui.controls.b_left_y,'Callback',{@osp_onLeftY,gui}); + + + gui.controls.text_act_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_act_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + + gui.controls.b_right_x = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + gui.controls.b_right_y = uicontrol(gui.controls.navigate_RawTab{t},'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + set(gui.controls.b_right_x,'Callback',{@osp_onRightX,gui}); + set(gui.controls.b_right_y,'Callback',{@osp_onRightY,gui}); + + gui.controls.b_left_x.Enable = 'off'; + gui.controls.b_left_y.Enable = 'off'; + gui.controls.b_right_x.Enable = 'off'; + gui.controls.b_right_y.Enable = 'off'; + + buttonString = [num2str(MRSCont.processed.(TabTitles{t}){1}.dims.extras > 1) num2str(MRSCont.processed.(TabTitles{t}){1}.subspecs>1)]; + switch buttonString + case '01' + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + case '10' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + case '11' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + end + set( gui.controls.navigate_RawTab{t}, 'Widths', [-20 -30 -20 -30], 'Heights', [-50 -50]); + + + gui.upperBox.pro.Info{t} = uix.Panel('Parent', gui.upperBox.pro.box{t}, ... 'Padding', 5, 'Title', ['Actual file: ' MRSCont.files{gui.controls.Selected}],... 'HighlightColor', gui.colormap.Foreground,'FontName', gui.font, 'BackgroundColor',... gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); - gui.upperBox.pro.upperButtons = uix.Panel('Parent', gui.upperBox.pro.box{ind}, ... + gui.upperBox.pro.upperButtons = uix.Panel('Parent', gui.upperBox.pro.box{t}, ... 'Padding', 5, 'Title', ['Save'],... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); - gui.controls.b_save_proTab{ind} = uicontrol('Parent',gui.upperBox.pro.upperButtons,'Style','PushButton'); + gui.controls.b_save_proTab{t} = uicontrol('Parent',gui.upperBox.pro.upperButtons,'Style','PushButton'); [img, ~, ~] = imread('Printer.png', 'BackgroundColor', gui.colormap.Background); [img2] = imresize(img, 0.1); - set(gui.controls.b_save_proTab{ind},'CData', img2, 'TooltipString', 'Create EPS figure from current file'); - set(gui.controls.b_save_proTab{ind},'Callback',{@osp_onPrint,gui}); - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - set(gui.upperBox.pro.box{ind}, 'Width', [-0.12 -0.78 -0.1]); - else - set(gui.upperBox.pro.box{ind}, 'Width', [-0.9 -0.1]); - end + set(gui.controls.b_save_proTab{t},'CData', img2, 'TooltipString', 'Create EPS figure from current file'); + set(gui.controls.b_save_proTab{t},'Callback',{@osp_onPrint,gui}); + set(gui.upperBox.pro.box{t}, 'Width', [-0.16 -0.74 -0.1]); + % Creates layout for plotting and data control - gui.Plot.pro{ind} = uix.HBox('Parent', gui.layout.(gui.layout.proTabhandles{ind}), ... + gui.Plot.pro{t} = uix.HBox('Parent', gui.layout.(gui.layout.proTabhandles{t}), ... 'Padding', 5,'BackgroundColor', gui.colormap.Background); - set(gui.layout.(gui.layout.proTabhandles{ind}), 'Heights', [-0.1 -0.9]); + set(gui.layout.(gui.layout.proTabhandles{t}), 'Heights', [-0.1 -0.9]); % Get parameter from file to fill the info panel + Exp = 1; if ~(isfield(MRSCont.flags,'isPRIAM')|| isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - if (strcmp(gui.process.Names{t},'A') || strcmp(gui.process.Names{t},'B') || strcmp(gui.process.Names{t},'C') || strcmp(gui.process.Names{t},'D') || strcmp(gui.process.Names{t},'diff1') || strcmp(gui.process.Names{t},'diff2') || strcmp(gui.process.Names{t},'sum')) - StatText = ['Metabolite Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(gui.process.Names{t})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.(gui.process.Names{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.(gui.process.Names{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq/1e6) ' Hz']; - else if strcmp(gui.process.Names{t},'ref') - StatText = ['Reference Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... + if strcmp(gui.process.TabTitles{t},'metab') + StatText = ['SNR(' gui.process.(gui.process.TabTitles{t}).SNR{1} '): ' num2str(MRSCont.QM.SNR.(gui.process.TabTitles{t})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.(gui.process.TabTitles{t}).SNR{1} '): '... + num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{t})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{t})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.TabTitles{t}){gui.controls.Selected}.txfrq(Exp)*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(gui.process.TabTitles{t})(Exp,gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.A(gui.controls.Selected)*MRSCont.processed.(gui.process.TabTitles{t}){gui.controls.Selected}.txfrq(Exp)/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.A(gui.controls.Selected)*MRSCont.processed.(gui.process.TabTitles{t}){gui.controls.Selected}.txfrq(Exp)/1e6) ' Hz']; + else + StatText = ['SNR(' gui.process.(gui.process.TabTitles{t}).SNR{1} '): ' num2str(MRSCont.QM.SNR.(gui.process.TabTitles{t})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.(gui.process.TabTitles{t}).SNR{1} '): '... + num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{t})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{t})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.TabTitles{t}){gui.controls.Selected}.txfrq(Exp)*1e6))... ' Hz / ppm']; - else - if ~strcmp(gui.process.Names{t},'mm') %re - StatText = ['Water Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)) '/' (num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else - StatText = ['MM Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)) '/' (num2str(MRSCont.QM.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - end %re - end end elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - if (strcmp(gui.process.Names{t},'A') || strcmp(gui.process.Names{t},'B') || strcmp(gui.process.Names{t},'C') || strcmp(gui.process.Names{t},'D') || strcmp(gui.process.Names{t},'diff1') || strcmp(gui.process.Names{t},'diff2') || strcmp(gui.process.Names{t},'sum')) - StatText = ['Voxel ' num2str(gui.controls.act_x) ': Metabolite Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{1,gui.controls.act_x}.freqShift.(gui.process.Names{t})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.pre.AvgDeltaCr.(gui.process.Names{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.post.AvgDeltaCr.(gui.process.Names{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq/1e6) ' Hz']; - else if strcmp(gui.process.Names{t},'ref') - StatText = ['Voxel ' num2str(gui.controls.act_x) ': Reference Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... + if (contains(gui.process.TabTitles{t},{'A','B','C','D','diff1','diff2','sum'})) + StatText = ['Voxel ' num2str(gui.controls.act_x) ': SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.TabTitles{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... + num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{1,gui.controls.act_x}.freqShift.(gui.process.TabTitles{t})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.pre.AvgDeltaCr.(gui.process.TabTitles{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.post.AvgDeltaCr.(gui.process.TabTitles{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq/1e6) ' Hz']; + else + StatText = ['Voxel ' num2str(gui.controls.act_x) ':SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.TabTitles{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... + num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq*1e6))... ' Hz / ppm']; - else - if ~strcmp(gui.process.Names{t},'mm') %re - StatText = ['Voxel ' num2str(gui.controls.act_x) ': Water Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) '/' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else - StatText = ['Voxel ' num2str(gui.controls.act_x) ': MM Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) '/' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - end %re - end end else - if (strcmp(gui.process.Names{t},'A') || strcmp(gui.process.Names{t},'B') || strcmp(gui.process.Names{t},'C') || strcmp(gui.process.Names{t},'D') || strcmp(gui.process.Names{t},'diff1') || strcmp(gui.process.Names{t},'diff2') || strcmp(gui.process.Names{t},'sum')) - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': Metabolite Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.freqShift.(gui.process.Names{t})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.pre.AvgDeltaCr.(gui.process.Names{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.post.AvgDeltaCr.(gui.process.Names{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq/1e6) ' Hz']; - else if strcmp(gui.process.Names{t},'ref') - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': Reference Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... + if (contains(gui.process.TabTitles{t},{'A','B','C','D','diff1','diff2','sum'})) + StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.TabTitles{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... + num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.freqShift.(gui.process.TabTitles{t})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.pre.AvgDeltaCr.(gui.process.TabTitles{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.post.AvgDeltaCr.(gui.process.TabTitles{t})(gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq/1e6) ' Hz']; + else + StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.TabTitles{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... + num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{t}){gui.controls.Selected}.txfrq*1e6))... ' Hz / ppm']; - else - if ~strcmp(gui.process.Names{t},'mm') %re - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': Water Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) '/' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': MM Data -> SNR(' gui.process.SNR{t} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.Names{t})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{t} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)) '/' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.Names{t})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{t}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - end %re - end end end - gui.InfoText.pro{ind} = uicontrol('Parent',gui.upperBox.pro.Info{ind},'style','text',... + gui.InfoText.pro{t} = uicontrol('Parent',gui.upperBox.pro.Info{t},'style','text',... 'FontSize', 12, 'FontName', gui.font,... 'HorizontalAlignment', 'left', 'String', sprintf(StatText),... 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); %%% 4. VISUALIZATION PART OF THIS TAB %%% %osp_plotProcess is used to visualize the processed spectra - temp = osp_plotProcess(MRSCont, gui.controls.Selected,gui.process.Names{t}); % Create figure + temp = osp_plotProcess(MRSCont, gui.controls.Selected,gui.process.TabTitles{t},1,Exp); % Create figure %Subplots are distributed here gui.layout.proSpecs = uix.VBox('Parent', gui.Plot.pro{t}, 'Padding', 5, 'BackgroundColor',gui.colormap.Background); gui.layout.proPre = uix.VBox('Parent', gui.layout.proSpecs,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); diff --git a/GUI/osp_iniQuantifyWindow.m b/GUI/osp_iniQuantifyWindow.m index 5394f1dd..09d2db43 100644 --- a/GUI/osp_iniQuantifyWindow.m +++ b/GUI/osp_iniQuantifyWindow.m @@ -45,10 +45,87 @@ function osp_iniQuantifyWindow(gui) %%% 3. FILLING INFO PANEL FOR THIS TAB %%% if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) for t = 1 : gui.quant.Number.Model %Loop over fits - gui.upperBox.quant.Info = uix.Panel('Parent', gui.layout.(gui.layout.quantifyTabhandles{t}), 'Padding', 5, ... + gui.upperBox.quant.box{t} = uix.HBox('Parent', gui.layout.(gui.layout.quantifyTabhandles{t}),'BackgroundColor',gui.colormap.Background,'Spacing',5); + gui.upperBox.quant.upperLeftButtons = uix.Panel('Parent', gui.upperBox.quant.box{t}, ... + 'Padding', 5, 'Title', ['Navigate results'],... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... + 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); + gui.controls.Buttonbox = uix.HBox('Parent',gui.upperBox.quant.upperLeftButtons, 'BackgroundColor',gui.colormap.Background); + gui.controls.navigate_RawTab = uix.Grid('Parent',gui.controls.Buttonbox,'BackgroundColor',gui.colormap.Background); + gui.controls.text_x = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Exp:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_y = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Spec:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_z = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Basis:',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_left_x = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + gui.controls.b_left_y = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + gui.controls.b_left_z = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + set(gui.controls.b_left_x,'Callback',{@osp_onLeftX,gui}); + set(gui.controls.b_left_y,'Callback',{@osp_onLeftY,gui}); + set(gui.controls.b_left_z,'Callback',{@osp_onLeftZ,gui}); + + gui.controls.text_act_x = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_act_y = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.text_act_z = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_right_x = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + gui.controls.b_right_y = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + gui.controls.b_right_z = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + set(gui.controls.b_right_x,'Callback',{@osp_onRightX,gui}); + set(gui.controls.b_right_y,'Callback',{@osp_onRightY,gui}); + set(gui.controls.b_right_z,'Callback',{@osp_onRightZ,gui}); + + gui.controls.b_left_x.Enable = 'off'; + gui.controls.b_left_y.Enable = 'off'; + gui.controls.b_left_z.Enable = 'off'; + gui.controls.b_right_x.Enable = 'off'; + gui.controls.b_right_y.Enable = 'off'; + gui.controls.b_right_z.Enable = 'off'; + + buttonString = [num2str(MRSCont.nDatasets(2) > 1) num2str(size(MRSCont.fit.results.metab.fitParams,3)>1) num2str(size(MRSCont.fit.results.metab.fitParams,1)>1)]; + switch buttonString + case '001' + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '010' + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + case '100' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + case '011' + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '101' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '110' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + case '111' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end + set( gui.controls.navigate_RawTab, 'Widths', [-20 -30 -20 -30], 'Heights', [-33 -33 -33] ); + + gui.upperBox.quant.Info = uix.Panel('Parent', gui.upperBox.quant.box{t}, 'Padding', 5, ... 'Title', ['Actual file: ' MRSCont.files{gui.controls.Selected}],... 'FontName', gui.font,'HighlightColor', gui.colormap.Foreground,'BackgroundColor',gui.colormap.Background,... 'ForegroundColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); + set(gui.upperBox.quant.box{t}, 'Width', [-0.15 -0.85]); % Creates layout for plotting and data control gui.Plot.quant = uix.HBox('Parent', gui.layout.(gui.layout.quantifyTabhandles{t}),'BackgroundColor',gui.colormap.Background); set(gui.layout.(gui.layout.quantifyTabhandles{t}), 'Heights', [-0.1 -0.9]); @@ -62,26 +139,26 @@ function osp_iniQuantifyWindow(gui) % In this case a table is created based on a uicontol slider gui.quant.Number.Quants = length(fieldnames(MRSCont.quantify.tables.(gui.quant.Names.Model{t}))); gui.quant.Names.Quants = fieldnames(MRSCont.quantify.tables.(gui.quant.Names.Model{t})); - QuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{t}))+1,gui.quant.Number.Quants); + QuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{t}){gui.controls.act_z,gui.controls.act_y})+1,gui.quant.Number.Quants); QuantText{1,1} = 'Metabolite'; - QuantText(2:end,1) = MRSCont.quantify.metabs.(gui.quant.Names.Model{t})'; + QuantText(2:end,1) = MRSCont.quantify.names.(gui.quant.Names.Model{t}){gui.controls.act_z,gui.controls.act_y}'; for q = 1 : gui.quant.Number.Quants % Collect all results QuantText(1,q+1) = gui.quant.Names.Quants(q); if (strcmp(gui.quant.Names.Quants(q),'AlphaCorrWaterScaled') || strcmp(gui.quant.Names.Quants(q),'AlphaCorrWaterScaledGroupNormed')) && isfield(MRSCont.quantify.tables.(gui.quant.Names.Model{t}),'AlphaCorrWaterScaled') - idx_GABA = find(strcmp(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABA')); + idx_GABA = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_y},'GABA')); if strcmp(MRSCont.opts.fit.coMM3, 'none') - tempQuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); - tempQuantText(idx_GABA) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1(gui.controls.Selected,:))'; + tempQuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y}),1); + tempQuantText(idx_GABA) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1{gui.controls.act_z,gui.controls.act_y}(gui.controls.Selected,:))'; else - tempQuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); - tempQuants = MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1(gui.controls.Selected,:); + tempQuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_y}),1); + tempQuants = MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1{gui.controls.act_z,gui.controls.act_y}(gui.controls.Selected,:); tempQuantText(idx_GABA) = table2cell(tempQuants(1,1)); - idx_GABAp = find(strcmp(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABAplus')); + idx_GABAp = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y},'GABAplus')); tempQuantText(idx_GABAp) = table2cell(tempQuants(1,2)); end QuantText(2:end,q+1) = tempQuantText; else - QuantText(2:end,q+1) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{t}).(gui.quant.Names.Quants{q}).Voxel_1(gui.controls.Selected,:))'; + QuantText(2:end,q+1) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{t}).(gui.quant.Names.Quants{q}).Voxel_1{gui.controls.act_z,gui.controls.act_y}(gui.controls.Selected,:))'; end end temp=uimulticollist ( 'units', 'normalized', 'position', [0 0 1 1], 'string', QuantText,... diff --git a/GUI/osp_onLeftBasis.m b/GUI/osp_onLeftBasis.m new file mode 100644 index 00000000..cde2eb54 --- /dev/null +++ b/GUI/osp_onLeftBasis.m @@ -0,0 +1,73 @@ +function osp_onLeftBasis( ~, ~ ,gui) +%% osp_onLeftX +% Callback function on process click on left x voxel direction button. +% +% +% USAGE: +% osp_onLeftX( ~, ~ ,gui); +% +% INPUT: gui = gui class containing all handles and the MRSCont +% +% OUTPUT: Changes in gui parameters and MRSCont are written into the +% gui class +% +% +% AUTHORS: +% Dr. Helge Zoellner (Johns Hopkins University, 2020-01-16) +% hzoelln2@jhmi.edu +% +% CREDITS: +% This code is based on numerous functions from the FID-A toolbox by +% Dr. Jamie Near (McGill University) +% https://github.com/CIC-methods/FID-A +% Simpson et al., Magn Reson Med 77:23-33 (2017) +% +% HISTORY: +% 2021-01-21: First version of the code. +%%% 1. INITIALIZE %%% + MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + selectedTab = get(gui.layout.tabs, 'Selection'); + + % User wants to process the data +%%% 2. UPDATEWINDOW %%% + + if gui.controls.act_basis > 1 + gui.controls.act_basis = gui.controls.act_basis - 1; + + setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class + set(gui.controls.text_act_basis,'String',num2str(gui.controls.act_basis)); + switch selectedTab %Which tab? + case 1 %Load tab? + osp_updateLoadWindow(gui); + case 2 %Process tab? + gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + % Grid for Plot and Data control sliders + gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); + osp_updateProWindow(gui); + case 3 %Fit tab? + osp_updateFitWindow(gui); + case 4 %Coreg tab? + osp_updateCoregWindow(gui); + case 5 %Quantify tab? + osp_updateQuantifyWindow(gui); + case 6 %Overview tab? + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + switch selectedOvTab % Wihich overview tab? + case 1 %Iindiv spec + osp_updateSpecsOvWindow(gui); + + case 2 %Mean spec + osp_updatemeanOvWindow(gui); + + case 3 %Quant table + osp_updatequantOvWindow(gui); + case 4 %Raincloud + osp_updatedistrOvWindow(gui); + case 5 %Correlation + osp_updatecorrOvWindow(gui); + + end + + end + end +end % osp_onLeftX \ No newline at end of file diff --git a/GUI/osp_onLeftExp.m b/GUI/osp_onLeftExp.m new file mode 100644 index 00000000..b22873c7 --- /dev/null +++ b/GUI/osp_onLeftExp.m @@ -0,0 +1,72 @@ +function osp_onLeftExp( ~, ~ ,gui) +%% osp_onLeftX +% Callback function on process click on left x voxel direction button. +% +% +% USAGE: +% osp_onLeftX( ~, ~ ,gui); +% +% INPUT: gui = gui class containing all handles and the MRSCont +% +% OUTPUT: Changes in gui parameters and MRSCont are written into the +% gui class +% +% +% AUTHORS: +% Dr. Helge Zoellner (Johns Hopkins University, 2020-01-16) +% hzoelln2@jhmi.edu +% +% CREDITS: +% This code is based on numerous functions from the FID-A toolbox by +% Dr. Jamie Near (McGill University) +% https://github.com/CIC-methods/FID-A +% Simpson et al., Magn Reson Med 77:23-33 (2017) +% +% HISTORY: +% 2021-01-21: First version of the code. +%%% 1. INITIALIZE %%% + MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + selectedTab = get(gui.layout.tabs, 'Selection'); + + % User wants to process the data +%%% 2. UPDATEWINDOW %%% + + if gui.controls.act_Exp > 1 + gui.controls.act_Exp = gui.controls.act_Exp - 1; + + setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class + switch selectedTab %Which tab? + case 1 %Load tab? + osp_updateLoadWindow(gui); + case 2 %Process tab? +% gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); + % Grid for Plot and Data control sliders + gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); + osp_updateProWindow(gui); + case 3 %Fit tab? + osp_updateFitWindow(gui); + case 4 %Coreg tab? + osp_updateCoregWindow(gui); + case 5 %Quantify tab? + osp_updateQuantifyWindow(gui); + case 6 %Overview tab? + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + switch selectedOvTab % Wihich overview tab? + case 1 %Iindiv spec + osp_updateSpecsOvWindow(gui); + + case 2 %Mean spec + osp_updatemeanOvWindow(gui); + + case 3 %Quant table + osp_updatequantOvWindow(gui); + case 4 %Raincloud + osp_updatedistrOvWindow(gui); + case 5 %Correlation + osp_updatecorrOvWindow(gui); + + end + + end + end +end % osp_onLeftX \ No newline at end of file diff --git a/GUI/osp_onLeftX.m b/GUI/osp_onLeftX.m index dc69a116..b11a2b9c 100644 --- a/GUI/osp_onLeftX.m +++ b/GUI/osp_onLeftX.m @@ -40,7 +40,7 @@ function osp_onLeftX( ~, ~ ,gui) case 1 %Load tab? osp_updateLoadWindow(gui); case 2 %Process tab? - gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; % Grid for Plot and Data control sliders gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); osp_updateProWindow(gui); diff --git a/GUI/osp_onLeftY.m b/GUI/osp_onLeftY.m index b436efb9..aa23ab29 100644 --- a/GUI/osp_onLeftY.m +++ b/GUI/osp_onLeftY.m @@ -40,7 +40,7 @@ function osp_onLeftY( ~, ~ ,gui) case 1 %Load tab? osp_updateLoadWindow(gui); case 2 %Process tab? - gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; % Grid for Plot and Data control sliders gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); osp_updateProWindow(gui); diff --git a/GUI/osp_onLeftZ.m b/GUI/osp_onLeftZ.m index 4701b35a..4319ca09 100644 --- a/GUI/osp_onLeftZ.m +++ b/GUI/osp_onLeftZ.m @@ -40,7 +40,7 @@ function osp_onLeftZ( ~, ~ ,gui) case 1 %Load tab? osp_updateLoadWindow(gui); case 2 %Process tab? - gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; % Grid for Plot and Data control sliders gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); osp_updateProWindow(gui); diff --git a/GUI/osp_onListSelection.m b/GUI/osp_onListSelection.m index ce853bfd..9e761a3b 100644 --- a/GUI/osp_onListSelection.m +++ b/GUI/osp_onListSelection.m @@ -32,6 +32,9 @@ function osp_onListSelection( src, ~,gui) case 1 osp_updateLoadWindow(gui); case 2 + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; + % Grid for Plot and Data control sliders + gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); osp_updateProWindow(gui); case 3 osp_updateFitWindow(gui); diff --git a/GUI/osp_onPrint.m b/GUI/osp_onPrint.m index 96c90dab..3ee796c9 100644 --- a/GUI/osp_onPrint.m +++ b/GUI/osp_onPrint.m @@ -6,7 +6,7 @@ function osp_onPrint( ~, ~ ,gui) % USAGE: % osp_onPrint( ~, ~ ,gui); % -% INPUT: gui = gui class containing all handles and the MRSCont +% INPUT: gui = gui class containing all handles and the MRSCont % % OUTPUT: Changes in gui parameters and MRSCont are written into the % gui class @@ -37,16 +37,16 @@ function osp_onPrint( ~, ~ ,gui) 'ToolBar', 'none', 'HandleVisibility', 'off', 'Renderer', 'painters', 'Color', gui.colormap.Background); Title = MRSCont.ver.Osp; - + Frame = uix.Panel('Parent',out, 'Padding', 1, 'Title', Title,... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... 'HighlightColor', gui.colormap.Background, 'ShadowColor', gui.colormap.Background); - input_figure = uix.VBox('Parent', Frame, 'BackgroundColor',gui.colormap.Background, 'Spacing', 5); + input_figure = uix.VBox('Parent', Frame, 'BackgroundColor',gui.colormap.Background, 'Spacing', 5); box = uix.HBox('Parent', input_figure,'BackgroundColor',gui.colormap.Background, 'Spacing',6); Info = uix.Panel('Parent',box, 'Padding', 5, 'Title', MRSCont.files{gui.controls.Selected},... 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); - LogoFig = figure('Visible','off'); + LogoFig = figure('Visible','off'); [I, map] = imread('osprey.gif','gif'); axes(LogoFig, 'Position', [0, 0.85, 0.15, 0.15*11.63/14.22]); imshow(I, map); @@ -70,41 +70,57 @@ function osp_onPrint( ~, ~ ,gui) 'FontSize', 12, 'FontName', gui.font,'ForegroundColor', gui.colormap.Foreground,... 'HorizontalAlignment', 'left', 'String', '', 'BackgroundColor',gui.colormap.Background); % Get parameter from file to fill the info panel - if gui.load.Selected == 1 %Is metabolite data? - StatText = ['Metabolite Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw{1,gui.controls.Selected}.spectralwidth) ' Hz'... - '\nraw subspecs: ' num2str(MRSCont.raw{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw{1,gui.controls.Selected}.averages)... + switch gui.load.Names.Spec{gui.load.Selected} + case 'metabolites' + StatText = ['Metabolite Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw{1,gui.controls.Selected}.tr) '\naverages: ' num2str(MRSCont.raw{1,gui.controls.Selected}.averages)... '; Sz: ' num2str(MRSCont.raw{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; - else if gui.load.Selected == 2 %Is water or ref data? - StatText = ['Reference Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.spectralwidth) ' Hz'... + case 'MM' + StatText = ['MM Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.spectralwidth) ' Hz'... %re_mm + '\nraw subspecs: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.averages)... + '; Sz: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... %re_mm + num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; %re_mm + case 'reference' + StatText = ['Reference Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.spectralwidth) ' Hz'... %re_mm '\nraw subspecs: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.averages)... - '; Sz: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... - num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; - else + '; Sz: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... %re_mm + num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; %re_mm + case 'MM reference' + StatText = ['MM reference Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.spectralwidth) ' Hz'... + '\nraw subspecs: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.averages)... + '; Sz: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... + num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; + case 'water' StatText = ['Water Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.spectralwidth) ' Hz'... '\nraw subspecs: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.averages)... '; Sz: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; end - end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) set(InfoText, 'String',sprintf(StatText)) elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM StatText = [StatText '; Voxel ' num2str(gui.controls.act_x)]; set(InfoText, 'String',sprintf(StatText)) - end + end %%% 4. VISUALIZATION PART OF THIS TAB %%% %osp_plotLoad is used to visualize the raw data. Number of subplots %depends on the number of subspectra of the seuqence - if gui.load.Selected == 1 %Metabolite data/tab + Exp = gui.controls.act_x; + switch gui.load.Names.Spec{gui.load.Selected} + case 'metabolites' + if Exp > max(MRSCont.opts.MultipleSpectra.metab) + Exp = 1; + gui.controls.act_Exp = 1; + end if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets'); VoxelIndex = 1; elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets',gui.controls.act_x); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets',gui.controls.act_x); VoxelIndex = gui.controls.act_x; end - outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyLoad_mets.pdf']; + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_mets.pdf']; if MRSCont.flags.isUnEdited % One window for UnEdited ViewAxes = gca(); set( ViewAxes, 'Parent', Plot ); @@ -140,29 +156,109 @@ function osp_onPrint( ~, ~ ,gui) set(multiAload.Children(1), 'OuterPosition', [0,0,1,1]) end - else if gui.load.Selected == 2 %ref data/tab - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref'); - VoxelIndex = 1; - elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',gui.controls.act_x); - VoxelIndex = gui.controls.act_x; + case 'MM' + if Exp > max(MRSCont.opts.MultipleSpectra.mm) + Exp = 1; + gui.controls.act_Exp = 1; end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',Exp); + VoxelIndex = 1; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',Exp,gui.controls.act_x); + VoxelIndex = gui.controls.act_x; + else + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + end + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_MM.pdf']; + if MRSCont.flags.isUnEdited % One window for UnEdited ViewAxes = gca(); set( ViewAxes, 'Parent', Plot ); - outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyLoad_ref.pdf']; - else %water data/tab has only one window all the time - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); + end + if MRSCont.flags.isMEGA %Two windows for MEGA + set( temp.Children(2), 'Parent', Plot ); + set( temp.Children(1), 'Parent', Plot ); + set(Plot,'Heights', [-0.49 -0.49]); + set(Plot.Children(2), 'Units', 'normalized') + set(Plot.Children(2), 'OuterPosition', [0,0.5,1,0.5]) + set(Plot.Children(1), 'Units', 'normalized') + set(Plot.Children(1), 'OuterPosition', [0,0,1,0.5]) + end + if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Four windows for HERMES/HERCULES + gui.layout.multiACload = uix.VBox('Parent', Plot, 'Padding', 5, 'BackgroundColor',gui.colormap.Background); + gui.layout.multiAload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiCload = uix.VBox('Parent', gui.layout.multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiBDload = uix.VBox('Parent', Plot,'Padding', 5, 'BackgroundColor',gui.colormap.Background); + gui.layout.multiBload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + gui.layout.multiDload = uix.VBox('Parent', gui.layout.multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',gui.colormap.Background); + set( temp.Children(1), 'Parent', gui.layout.multiDload ); + set( temp.Children(1), 'Parent', gui.layout.multiCload ); + set( temp.Children(1), 'Parent', gui.layout.multiBload ); + set( temp.Children(1), 'Parent', gui.layout.multiAload ); + set(Plot,'Width', [-0.49 -0.49]); + set(gui.layout.multiDload.Children(1), 'Units', 'normalized') + set(gui.layout.multiDload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiCload.Children(1), 'Units', 'normalized') + set(gui.layout.multiCload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiBload.Children(1), 'Units', 'normalized') + set(gui.layout.multiBload.Children(1), 'OuterPosition', [0,0,1,1]) + set(gui.layout.multiAload.Children(1), 'Units', 'normalized') + set(gui.layout.multiAload.Children(1), 'OuterPosition', [0,0,1,1]) + + end + case 'reference' + if Exp > max(MRSCont.opts.MultipleSpectra.ref) + Exp = 1; + gui.controls.act_Exp = 1; + end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',Exp); VoxelIndex = 1; elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',gui.controls.act_x); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',Exp,gui.controls.act_x); VoxelIndex = gui.controls.act_x; - end - ViewAxes = gca(); - set(ViewAxes, 'Parent', Plot ); - outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyLoad_w.pdf']; + else + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + end + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', Plot ); + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_ref.pdf']; + + case 'MM reference' + if Exp > max(MRSCont.opts.MultipleSpectra.mm_ref) + Exp = 1; + gui.controls.act_Exp = 1; end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm_ref',Exp); + VoxelIndex = 1; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm_ref',Exp,gui.controls.act_x); + VoxelIndex = gui.controls.act_x; + else + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm_ref',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + end + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', Plot ); + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_mm_ref.pdf']; + + case 'water' + if Exp > max(MRSCont.opts.MultipleSpectra.w) + Exp = 1; + gui.controls.act_Exp = 1; + end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',Exp); + VoxelIndex = 1; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',Exp,gui.controls.act_x); + VoxelIndex = gui.controls.act_x; + else + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + end + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', Plot ); + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_w.pdf']; end set(input_figure, 'Heights', [-0.1 -0.9]); % Get rid of the Load figure @@ -171,27 +267,24 @@ function osp_onPrint( ~, ~ ,gui) case 2 %Process Tab outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyProcess'); [~,filename,~] = fileparts(MRSCont.files{gui.controls.Selected}); - Selection = gui.process.Names{gui.process.Selected}; - + Selection = gui.process.TabTitles{gui.process.Selected}; + Exp = gui.controls.act_x; + SubSpec = gui.controls.act_y; Plot = uix.HBox('Parent', input_figure, ... 'Padding', 5,'BackgroundColor', gui.colormap.Background); set(input_figure, 'Heights', [-0.11 -0.89]); + % Get parameter from file to fill the info panel if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - if (strcmp(gui.process.Names{gui.process.Selected},'A') || strcmp(gui.process.Names{gui.process.Selected},'B') || strcmp(gui.process.Names{gui.process.Selected},'C') || strcmp(gui.process.Names{gui.process.Selected},'D') || strcmp(gui.process.Names{gui.process.Selected},'diff1') || strcmp(gui.process.Names{gui.process.Selected},'diff2') || strcmp(gui.process.Names{gui.process.Selected},'sum') ) - StatText = ['Metabolite Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq/1e6) ' Hz']; - else if (strcmp(gui.process.Names{gui.process.Selected},'ref') || strcmp(gui.process.Names{gui.process.Selected},'mm')) - StatText = ['Reference Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... + if strcmp(gui.process.TabTitles{gui.process.Selected},'metab') + StatText = ['SNR(' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{SubSpec} '): ' num2str(MRSCont.QM.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)) '; FWHM (' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{SubSpec} '): '... + num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)/MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.A(gui.controls.Selected)*MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.A(gui.controls.Selected)*MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6) ' Hz']; + else + StatText = ['SNR(' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{1} '): ' num2str(MRSCont.QM.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{1} '): '... + num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)*1e6))... ' Hz / ppm']; - else - StatText = ['Water Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '/' (num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - end end elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM if (strcmp(gui.process.Names{gui.process.Selected},'A') || strcmp(gui.process.Names{gui.process.Selected},'B') || strcmp(gui.process.Names{gui.process.Selected},'C') || strcmp(gui.process.Names{gui.process.Selected},'D') || strcmp(gui.process.Names{gui.process.Selected},'diff1') || strcmp(gui.process.Names{gui.process.Selected},'diff2') || strcmp(gui.process.Names{gui.process.Selected},'sum') ) @@ -208,9 +301,9 @@ function osp_onPrint( ~, ~ ,gui) num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '/' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... ' Hz / ppm']; end - end + end end - + if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM StatText = ['Voxel ' num2str(gui.controls.act_x) ': ' StatText]; end @@ -221,10 +314,10 @@ function osp_onPrint( ~, ~ ,gui) %%% 4. VISUALIZATION PART OF THIS TAB %%% %osp_plotProcess is used to visualize the processed spectra if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotProcess(MRSCont, gui.controls.Selected,gui.process.Names{gui.process.Selected}); % Create figure + temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection,SubSpec,Exp); % Create figure VoxelIndex = 1; elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotProcess(MRSCont, gui.controls.Selected,gui.process.Names{gui.process.Selected},gui.controls.act_x); %Create figure + temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection,SubSpec,Exp,gui.controls.act_x); %Create figure VoxelIndex = gui.controls.act_x; end %Subplots are distributed here @@ -250,18 +343,21 @@ function osp_onPrint( ~, ~ ,gui) set(proDrift.Children(1), 'OuterPosition', [0,0,1,1]) set(proAlgn.Children(1), 'Units', 'normalized') set(proAlgn.Children(1), 'OuterPosition', [0,0,1,1]) - - outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyProcess_' Selection '.pdf']; + + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyProcess_' Selection '_' MRSCont.processed.(Selection){gui.controls.Selected}.names{SubSpec} '.pdf']; case 3 %Fit outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyFit'); % For this visualization, we will have to make a few % distinctions upfront since the modeling algorithms (LCModel % vs. Osprey) do not always return the same kinds of data, or they % return them in different formats. + + basis = gui.controls.act_z; + subspectrum = gui.controls.act_y; switch MRSCont.opts.fit.method case 'LCModel' % Number of metabolites and lipid/MM basis functions - basisNames = MRSCont.fit.results.off.fitParams{gui.controls.Selected}.name; + basisNames = MRSCont.fit.results.(gui.fit.Style).fitParams{gui.controls.Selected}.name; nLip = sum(~cellfun(@isempty, strfind(basisNames, 'Lip'))); nMM = sum(~cellfun(@isempty, strfind(basisNames, 'MM'))); nMMLip = nLip + nMM; @@ -270,35 +366,40 @@ function osp_onPrint( ~, ~ ,gui) % No info panel string for the water fit range waterFitRangeString = ''; % Where are the metabolite names stored? - basisSetNames = MRSCont.fit.results.(gui.fit.Style).fitParams{gui.controls.Selected}.name; + basisSetNames = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.name; + subSpecName = 'A'; % Smaller fonts for the results resultsFontSize = 6; case 'Osprey' - % Number of metabolites and lipid/MM basis functions - nMets = MRSCont.fit.basisSet.nMets; - nMMLip = MRSCont.fit.basisSet.nMM; + % Additional info panel string for the water fit range waterFitRangeString = ['Fitting range: ' num2str(MRSCont.opts.fit.rangeWater(1)) ' to ' num2str(MRSCont.opts.fit.rangeWater(2)) ' ppm']; % Where are the metabolite names stored? if strcmp(gui.fit.Style, 'ref') || strcmp(gui.fit.Style, 'w') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).water.(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{1}.spectralwidth))]).name; - else if strcmp(gui.fit.Style, 'conc') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{1}.spectralwidth))]).name; - else if strcmp(gui.fit.Style, 'off') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{1}.spectralwidth))]).name; - else - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{1}.spectralwidth))]).name; + basisSet = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{gui.controls.Selected}.sz(1)) '_' num2str(MRSCont.processed.metab{gui.controls.Selected}.spectralwidth)]){1}; + basisSetNames = basisSet.name; + subSpecName = gui.fit.Style; + else if strcmp(gui.fit.Style, 'conc') + basisSet = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{gui.controls.Selected}.sz(1)) '_' num2str(MRSCont.processed.metab{gui.controls.Selected}.spectralwidth)]){basis,1}; + basisSetNames = basisSet.name; + subSpecName = basisSet.names{1}; + else + basisSet = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{gui.controls.Selected}.sz(1)) '_' num2str(MRSCont.processed.metab{gui.controls.Selected}.spectralwidth)]){basis,1,subspectrum}; + basisSetNames = basisSet.name; + subSpecName = basisSet.names{1}; end end - end - % Larger fonts for the results - resultsFontSize = 11; + % Number of metabolites and lipid/MM basis functions + nMets = MRSCont.fit.basisSet.nMets; + nMMLip = MRSCont.fit.basisSet.nMM; + % Larger fonts for the results + resultsFontSize = 11; end [~,filename,~] = fileparts(MRSCont.files{gui.controls.Selected}); Selection = gui.fit.Names{gui.fit.Selected}; Plot = uix.HBox('Parent', input_figure, 'Padding', 5,'BackgroundColor',gui.colormap.Background); set(input_figure, 'Heights', [-0.12 -0.88]); - if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') || strcmp(gui.fit.Names{gui.fit.Selected}, 'w') %Is not concateneted or is reference/water fit + if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') || strcmp(gui.fit.Names{gui.fit.Selected}, 'w') %Is not concateneted or is reference/water fit gui.fit.Style = gui.fit.Names{gui.fit.Selected}; switch MRSCont.opts.fit.method case 'LCModel' @@ -309,27 +410,27 @@ function osp_onPrint( ~, ~ ,gui) CRLB = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.CRLB; end case 'Osprey' - RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; + RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; end else %Is concatenated and not water/reference gui.fit.Style = 'conc'; end if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + ph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ph0; + ph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ph1; if ~strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') && ~strcmp(gui.fit.Names{gui.fit.Selected}, 'w') - refShift = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refShift; - refFWHM = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refFWHM; - ph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph0; - ph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph1; + refShift = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.refShift; + refFWHM = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.refFWHM; switch MRSCont.opts.fit.method case 'Osprey' iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; - end + end end - RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; + RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM if ~strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') && ~strcmp(gui.fit.Names{gui.fit.Selected}, 'w') refShift = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refShift; @@ -339,11 +440,11 @@ function osp_onPrint( ~, ~ ,gui) switch MRSCont.opts.fit.method case 'Osprey' iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; - end + end end RawAmpl = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; else @@ -355,22 +456,22 @@ function osp_onPrint( ~, ~ ,gui) switch MRSCont.opts.fit.method case 'Osprey' iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; - end + end end - RawAmpl = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; + RawAmpl = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; end % Get parameter from file to fill the info panel if ~strcmp (Selection, 'ref') && ~strcmp (Selection, 'w') %Metabolite data if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) switch MRSCont.opts.fit.method case 'Osprey' - iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; end @@ -382,9 +483,9 @@ function osp_onPrint( ~, ~ ,gui) elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM switch MRSCont.opts.fit.method case 'Osprey' - iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; end @@ -396,9 +497,9 @@ function osp_onPrint( ~, ~ ,gui) else switch MRSCont.opts.fit.method case 'Osprey' - iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; end @@ -425,7 +526,7 @@ function osp_onPrint( ~, ~ ,gui) Results = uix.Panel('Parent', Plot,... 'Title', ['Raw Amplitudes'],'FontName', gui.font,'HighlightColor', gui.colormap.Foreground,... 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) if ~(MRSCont.flags.hasRef || MRSCont.flags.hasWater) %Raw amplitudes are reported as no water/reference fitting was performed if ~(strcmp(gui.fit.Style, 'ref') || strcmp(gui.fit.Style, 'w')) %Metabolite fit NameText = ['']; @@ -603,12 +704,12 @@ function osp_onPrint( ~, ~ ,gui) end end end - + %%% 5. VISUALIZATION PART OF THIS TAB %%% %osp_plotFit is used to visualize the fits (off,diff1,diff2,sum,ref,water) temp = figure( 'Visible', 'off' ); if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,1,Selection); + temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,[gui.controls.act_x gui.controls.act_y gui.controls.act_z],Selection); VoxelIndex = 1; elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,gui.controls.act_x,Selection); @@ -624,11 +725,11 @@ function osp_onPrint( ~, ~ ,gui) set(Plot,'Widths', [-0.16 -0.84]); set(Plot.Children(2), 'Units', 'normalized'); set(Plot.Children(2), 'OuterPosition', [0.17,0.02,0.75,0.98]) - outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyFit_' gui.fit.Style '_' Selection '.pdf']; + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyFit_' gui.fit.Style '_' subSpecName '_basis_' num2str(gui.controls.act_z) '.pdf']; case 4 %Coreg/Seg outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyCoregSeg'); [~,filename,~] = fileparts(MRSCont.files{gui.controls.Selected}); - + % Creates layout for plotting and data control Plot = uix.HBox('Parent', input_figure,'BackgroundColor',gui.colormap.Background); set(input_figure, 'Heights', [-0.1 -0.9]); @@ -653,7 +754,7 @@ function osp_onPrint( ~, ~ ,gui) temp = osp_plotCoreg(MRSCont, gui.controls.Selected); else temp = osp_plotCoreg(MRSCont, gui.controls.Selected,gui.controls.act_x); - end + end ViewAxes = gca(); set(ViewAxes, 'Parent', Results ); colormap(Results.Children,'gray') @@ -663,7 +764,7 @@ function osp_onPrint( ~, ~ ,gui) temp = osp_plotSegment(MRSCont, gui.controls.Selected); else temp = osp_plotSegment(MRSCont, gui.controls.Selected,gui.controls.act_x); - end + end ViewAxes = gca(); set(ViewAxes, 'Parent', Results ); colormap(Results.Children(1),'gray'); @@ -673,13 +774,13 @@ function osp_onPrint( ~, ~ ,gui) temp = osp_plotCoreg(MRSCont, gui.controls.Selected); else temp = osp_plotCoreg(MRSCont, gui.controls.Selected,gui.controls.act_x); - end + end ViewAxes = gca(); set(ViewAxes, 'Parent', Results ); colormap(Results.Children,'gray'); close( temp ); - end - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) VoxelIndex = 1; else VoxelIndex = gui.controls.act_x; @@ -705,11 +806,11 @@ function osp_onPrint( ~, ~ ,gui) Selection = gui.controls.pop_specsOvPlot.String(gui.process.Selected); outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyOverview','Individual'); if gui.controls.GM == 0 - outputFile = [Selection{1} '.pdf']; + outputFile = [Selection{1} '.pdf']; for g = 1 : gui.overview.Number.Groups %Loop over groups - temp = osp_plotOverviewSpec(MRSCont, Selection{1},g, gui.layout.shiftind); + temp = osp_plotOverviewSpec(MRSCont, Selection{1},g, gui.layout.shiftind,'Frequency (ppm)','','',gui.controls.act_z); if g == 1 - fig_hold = temp; + fig_hold = temp; else ax=get(temp,'Children'); copyobj(ax.Children, fig_hold.Children(1)); @@ -719,10 +820,10 @@ function osp_onPrint( ~, ~ ,gui) end else - outputFile = [Selection{1} 'Grand_mean.pdf']; - fig_hold = osp_plotOverviewSpec(MRSCont, Selection{1},'GMean', gui.layout.shiftind); + outputFile = [Selection{1} ' basis_' num2str(gui.controls.act_z) ' Grand_mean.pdf']; + fig_hold = osp_plotOverviewSpec(MRSCont, Selection{1},'GMean', gui.layout.shiftind,'Frequency (ppm)','','',gui.controls.act_z); set(fig_hold.Children, 'Parent', Plot ); - end + end close(fig_hold); case 2 %MeanOverview Selection = gui.controls.pop_meanOvPlot.String(gui.process.Selected); @@ -739,95 +840,102 @@ function osp_onPrint( ~, ~ ,gui) lines=get(ax,'Children'); copyobj(lines, fig_hold.Children(1)); close(temp); - end + end else fig_hold = osp_plotMeanSpec(MRSCont, Selection{1},g); end end - else + else if ~(isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM) - outputFile = [Selection{1} 'Grand_mean.pdf']; - fig_hold = osp_plotMeanSpec(MRSCont, Selection{1},'GMean', 1); + outputFile = [Selection{1} ' basis_' num2str(gui.controls.act_z) ' Grand_mean.pdf']; + fig_hold = osp_plotMeanSpec(MRSCont, Selection{1},'GMean', 1,0,'Frequency (ppm)','','',gui.controls.act_z); else - outputFile = [Selection{1} 'Grand_mean_Dual_Voxel.pdf']; - fig_hold = osp_plotMeanSpec(MRSCont, Selection{1},1, 0.01,10); + outputFile = [Selection{1} ' basis_' num2str(gui.controls.act_z) 'Grand_mean_Dual_Voxel.pdf']; + fig_hold = osp_plotMeanSpec(MRSCont, Selection{1},1, 0.01,10,'Frequency (ppm)','','',gui.controls.act_z); end end set(fig_hold.Children, 'Parent', Plot ); + set(out.Children.Children(1).Children(1).Children,'Children',flipud(out.Children.Children(1).Children(1).Children.Children)); close(fig_hold); - + case 4 %Raincloud plot outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyOverview', 'Raincloud'); Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; - if ~strcmp(Selection,'Quality') + if ~strcmp(Selection,'Quality') split_Selection = strsplit(Selection,'-'); - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') metab = 'GABA'; else - metab = MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Metab}; + metab = MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}{gui.overview.Selected.Metab}; end if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) if ~gui.controls.GM - fig_hold = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot',0,gui.controls.act_x); + fig_hold = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',0,gui.controls.act_x,gui.controls.act_z); else - fig_hold = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot',1,gui.controls.act_x); + fig_hold = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',1,gui.controls.act_x,gui.controls.act_z); end VoxelIndex = gui.controls.act_x; else if ~gui.controls.GM - fig_hold = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot'); + fig_hold = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',0,1,gui.controls.act_z); else - fig_hold = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot',1); - end + fig_hold = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',1,1,gui.controls.act_z); + end VoxelIndex = 1; end + split_Selection{4}=['basis ' num2str(gui.controls.act_z)]; else quality = {'SNR','FWHM','freqShift'}; if ~gui.controls.GM - fig_hold = osp_plotRaincloud(MRSCont,'Quality','Quality',quality{gui.overview.Selected.Metab},'Raincloud plot'); + fig_hold = osp_plotRaincloud(MRSCont,'Quality','Quality',quality{gui.overview.Selected.Metab},'Raincloud plot'); else - fig_hold = osp_plotRaincloud(MRSCont,'Quality','Quality',quality{gui.overview.Selected.Metab},'Raincloud plot',1); + fig_hold = osp_plotRaincloud(MRSCont,'Quality','Quality',quality{gui.overview.Selected.Metab},'Raincloud plot',1); end - split_Selection{2}=quality{gui.overview.Selected.Metab}; - split_Selection{1}='Quality'; - metab = 'Spectral'; - end + split_Selection{2}='Quality'; + split_Selection{1}='Spectral'; + split_Selection{3}=quality{gui.overview.Selected.Metab}; + split_Selection{4}=''; + metab = ''; + VoxelIndex = 1; + end delete( fig_hold.Children(1)); set( fig_hold.Children, 'Parent', Plot ); set(out.Children.Children(1).Children(1).Children,'Children',flipud(out.Children.Children(1).Children(1).Children.Children)); close(fig_hold); if ~gui.controls.GM - outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '.pdf']; + outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '_' split_Selection{3} '_' split_Selection{4} '.pdf']; else - outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} 'Grand_mean.pdf']; + outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '_' split_Selection{3} '_' split_Selection{4} '_Grand_mean.pdf']; end case 5 %Correlation plot outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyOverview', 'Correlation'); Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; split_Selection = strsplit(Selection,'-'); + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); MRSCont.flags.isGUI =0; - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') metab = 'GABA'; else - metab = MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Metab}; - end + metab = MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}{gui.overview.Selected.Metab}; + end if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) VoxelIndex = 1; if gui.overview.Selected.CorrChoice == 1 switch gui.overview.Selected.Corr case 1 - fig_hold = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.QM.SNR.A',gui.overview.Names.QM{gui.overview.Selected.Corr}); - outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '_' gui.overview.Names.QM{gui.overview.Selected.Corr} '.pdf']; + fig_hold = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.QM.SNR.metab(1,:,ind)',gui.overview.Names.QM{gui.overview.Selected.Corr},1,gui.controls.act_z); + outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{2} '_' split_Selection{3} '_basis' num2str(gui.controls.act_z) '_' gui.overview.Names.QM{gui.overview.Selected.Corr} '.pdf']; case 2 - fig_hold = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.QM.FWHM.A',gui.overview.Names.QM{gui.overview.Selected.Corr}); - outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '_' gui.overview.Names.QM{gui.overview.Selected.Corr} '.pdf']; + fig_hold = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.QM.FWHM.metab(1,:,ind)',gui.overview.Names.QM{gui.overview.Selected.Corr},1,gui.controls.act_z); + outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{3} '_' split_Selection{3} '_basis' num2str(gui.controls.act_z) '_' gui.overview.Names.QM{gui.overview.Selected.Corr} '.pdf']; end else if gui.overview.Selected.CorrChoice == 2 - fig_hold = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Metab},metab,metab); - outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '_' MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Metab} '.pdf']; - else - fig_hold = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,gui.overview.CorrMeas{gui.overview.Selected.Corr},gui.overview.Names.Corr{gui.overview.Selected.Corr}); - outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '_' gui.overview.Names.Corr{gui.overview.Selected.Corr} '.pdf']; + fig_hold = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.quantify.names.(split_Selection{1}){1,ind}{gui.overview.Selected.Corr},MRSCont.quantify.names.(split_Selection{1}){1,ind}{gui.overview.Selected.Corr},1,gui.controls.act_z); + outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{2} '_' split_Selection{3} '_basis' num2str(gui.controls.act_z) '_' MRSCont.quantify.names.(split_Selection{1}){1,ind}{gui.overview.Selected.Metab} '.pdf']; + else + fig_hold = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,gui.overview.CorrMeas{gui.overview.Selected.Corr},gui.overview.Names.Corr{gui.overview.Selected.Corr},1,gui.controls.act_z); + outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{2} '_' split_Selection{3} '_basis' num2str(gui.controls.act_z) '_' gui.overview.Names.Corr{gui.overview.Selected.Corr} '.pdf']; end end else @@ -848,7 +956,7 @@ function osp_onPrint( ~, ~ ,gui) fig_hold = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,gui.overview.CorrMeas{gui.overview.Selected.Corr},gui.overview.Names.Corr{gui.overview.Selected.Corr},gui.controls.act_x); outputFile = ['Voxel_' num2str(VoxelIndex) '_' metab '_' split_Selection{1} '_' split_Selection{2} '_' gui.overview.Names.Corr{gui.overview.Selected.Corr} '.pdf']; end - end + end end delete( fig_hold.Children(1)); delete( fig_hold.Children(1)); @@ -857,10 +965,10 @@ function osp_onPrint( ~, ~ ,gui) close(fig_hold); MRSCont.flags.isGUI =1; end - - end + + end set(out,'Renderer','painters','Menu','none','Toolbar','none'); - setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class + setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class %% Clean up and save % Save the figure to the output folder @@ -873,4 +981,4 @@ function osp_onPrint( ~, ~ ,gui) saveas(out,fullfile(outputFolder,outputFile),'pdf'); close(out); -end \ No newline at end of file +end diff --git a/GUI/osp_onRightBasis.m b/GUI/osp_onRightBasis.m new file mode 100644 index 00000000..d8e75f33 --- /dev/null +++ b/GUI/osp_onRightBasis.m @@ -0,0 +1,74 @@ +function osp_onRightBasis( ~, ~ ,gui) +%% osp_onRightX +% Callback function on process click on left x voxel direction button. +% +% +% USAGE: +% osp_onRightX( ~, ~ ,gui); +% +% INPUT: gui = gui class containing all handles and the MRSCont +% +% OUTPUT: Changes in gui parameters and MRSCont are written into the +% gui class +% +% +% AUTHORS: +% Dr. Helge Zoellner (Johns Hopkins University, 2020-01-16) +% hzoelln2@jhmi.edu +% +% CREDITS: +% This code is based on numerous functions from the FID-A toolbox by +% Dr. Jamie Near (McGill University) +% https://github.com/CIC-methods/FID-A +% Simpson et al., Magn Reson Med 77:23-33 (2017) +% +% HISTORY: +% 2021-01-21: First version of the code. +%%% 1. INITIALIZE %%% + MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + selectedTab = get(gui.layout.tabs, 'Selection'); + + % User wants to process the data +%%% 2. UPDATEWINDOW %%% + if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') || strcmp(gui.fit.Names{gui.fit.Selected}, 'w') %Is not concateneted or is reference/water fit + gui.fit.Style = gui.fit.Names{gui.fit.Selected}; + else %Is concatenated and not water/reference + gui.fit.Style = 'conc'; + end + + if gui.controls.act_basis < length(MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{1}.sz(1)) '_' num2str(MRSCont.processed.metab{1}.spectralwidth)])) + gui.controls.act_basis = gui.controls.act_basis + 1; + + setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class + set(gui.controls.text_act_basis,'String',num2str(gui.controls.act_basis)); + switch selectedTab %Which tab? + case 1 %Load tab? + osp_updateLoadWindow(gui); + case 2 %Process tab? + gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + % Grid for Plot and Data control sliders + gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); + osp_updateProWindow(gui); + case 3 %Fit tab? + osp_updateFitWindow(gui); + case 4 %Coreg tab? + osp_updateCoregWindow(gui); + case 5 %Quantify tab? + osp_updateQuantifyWindow(gui); + case 6 %Overview tab? + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + switch selectedOvTab % Wihich overview tab? + case 1 %Iindiv spec + osp_updateSpecsOvWindow(gui); + case 2 %Mean spec + osp_updatemeanOvWindow(gui); + case 3 %Quant table + osp_updatequantOvWindow(gui); + case 4 %Raincloud + osp_updatedistrOvWindow(gui); + case 5 %Correlation + osp_updatecorrOvWindow(gui); + end + end + end +end % osp_onRightX \ No newline at end of file diff --git a/GUI/osp_onRightExp.m b/GUI/osp_onRightExp.m new file mode 100644 index 00000000..106d8340 --- /dev/null +++ b/GUI/osp_onRightExp.m @@ -0,0 +1,68 @@ +function osp_onRightExp( ~, ~ ,gui) +%% osp_onRightX +% Callback function on process click on left x voxel direction button. +% +% +% USAGE: +% osp_onRightX( ~, ~ ,gui); +% +% INPUT: gui = gui class containing all handles and the MRSCont +% +% OUTPUT: Changes in gui parameters and MRSCont are written into the +% gui class +% +% +% AUTHORS: +% Dr. Helge Zoellner (Johns Hopkins University, 2020-01-16) +% hzoelln2@jhmi.edu +% +% CREDITS: +% This code is based on numerous functions from the FID-A toolbox by +% Dr. Jamie Near (McGill University) +% https://github.com/CIC-methods/FID-A +% Simpson et al., Magn Reson Med 77:23-33 (2017) +% +% HISTORY: +% 2021-01-21: First version of the code. +%%% 1. INITIALIZE %%% + MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + selectedTab = get(gui.layout.tabs, 'Selection'); + + % User wants to process the data +%%% 2. UPDATEWINDOW %%% + + if gui.controls.act_Exp < gui.info.nExperiments + gui.controls.act_Exp = gui.controls.act_Exp + 1; + + setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class + switch selectedTab %Which tab? + case 1 %Load tab? + osp_updateLoadWindow(gui); + case 2 %Process tab? +% gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); + % Grid for Plot and Data control sliders + gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); + osp_updateProWindow(gui); + case 3 %Fit tab? + osp_updateFitWindow(gui); + case 4 %Coreg tab? + osp_updateCoregWindow(gui); + case 5 %Quantify tab? + osp_updateQuantifyWindow(gui); + case 6 %Overview tab? + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + switch selectedOvTab % Wihich overview tab? + case 1 %Iindiv spec + osp_updateSpecsOvWindow(gui); + case 2 %Mean spec + osp_updatemeanOvWindow(gui); + case 3 %Quant table + osp_updatequantOvWindow(gui); + case 4 %Raincloud + osp_updatedistrOvWindow(gui); + case 5 %Correlation + osp_updatecorrOvWindow(gui); + end + end + end +end % osp_onRightX \ No newline at end of file diff --git a/GUI/osp_onRightX.m b/GUI/osp_onRightX.m index b9f5a78b..32fe226d 100644 --- a/GUI/osp_onRightX.m +++ b/GUI/osp_onRightX.m @@ -40,7 +40,7 @@ function osp_onRightX( ~, ~ ,gui) case 1 %Load tab? osp_updateLoadWindow(gui); case 2 %Process tab? - gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; % Grid for Plot and Data control sliders gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); osp_updateProWindow(gui); diff --git a/GUI/osp_onRightY.m b/GUI/osp_onRightY.m index 44e59330..45f5a9c6 100644 --- a/GUI/osp_onRightY.m +++ b/GUI/osp_onRightY.m @@ -40,7 +40,7 @@ function osp_onRightY( ~, ~ ,gui) case 1 %Load tab? osp_updateLoadWindow(gui); case 2 %Process tab? - gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; % Grid for Plot and Data control sliders gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); osp_updateProWindow(gui); diff --git a/GUI/osp_onRightZ.m b/GUI/osp_onRightZ.m index 76c08cf4..cdf4d480 100644 --- a/GUI/osp_onRightZ.m +++ b/GUI/osp_onRightZ.m @@ -40,7 +40,7 @@ function osp_onRightZ( ~, ~ ,gui) case 1 %Load tab? osp_updateLoadWindow(gui); case 2 %Process tab? - gui.InfoText.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children; + gui.InfoText.pro = gui.upperBox.pro.Info{gui.process.Selected}.Children; % Grid for Plot and Data control sliders gui.Plot.pro = gui.layout.(gui.layout.proTabhandles{gui.process.Selected}); osp_updateProWindow(gui); diff --git a/GUI/osp_pop_corrOvQuant_Call.m b/GUI/osp_pop_corrOvQuant_Call.m index 09bd7868..a433b0bf 100644 --- a/GUI/osp_pop_corrOvQuant_Call.m +++ b/GUI/osp_pop_corrOvQuant_Call.m @@ -28,16 +28,32 @@ function osp_pop_corrOvQuant_Call(src,~,gui) src.Value=idx; gui.quant.Selected.Quant = idx; Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(4),'String',gui.controls.act_x) split_Selection = strsplit(Selection,'-'); - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') - set(gui.controls.pop_corrOvMetab, 'String', {'GABA'}); - set(gui.controls.pop_corrOvMetab, 'Value', gui.quant.idx.GABA); - set(gui.controls.pop_corrOvMetab, 'Enable', 'off'); - set(gui.overview.Selected, 'Metab',1) - else - set(gui.controls.pop_corrOvMetab, 'String', MRSCont.quantify.metabs.(split_Selection{1})); - set(gui.controls.pop_corrOvMetab, 'Value', gui.overview.Selected.Metab); - set(gui.controls.pop_corrOvMetab, 'Enable', 'on'); + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') + set(gui.controls.pop_corrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + set(gui.controls.pop_corrOvMetab, 'String', {'GABA'}); + set(gui.controls.pop_corrOvMetab, 'Value', gui.quant.idx.GABA); + set(gui.controls.pop_corrOvMetab, 'Enable', 'on'); + else + metab_idx_old = get(gui.controls.pop_corrOvMetab, 'Value'); + name_list=get(gui.controls.pop_corrOvMetab, 'String'); + name_old = name_list{metab_idx_old}; + name_list_new=MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}; + metab_idx_new = find(strcmp(name_list_new,name_old)); + if ~isempty(metab_idx_new) + set(gui.controls.pop_corrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + else + metab_idx_new = 1; + set(gui.controls.pop_corrOvMetab, 'Value', 1); + set(gui.controls.pop_corrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + gui.overview.Selected.Metab = 1; + end + set(gui.controls.pop_corrOvMetab, 'Value', metab_idx_new); + set(gui.controls.pop_corrOvMetab, 'Enable', 'on'); end setappdata(gui.figure,'MRSCont',MRSCont); %Write MRSCont into hidden container in gui class osp_updatecorrOvWindow(gui); diff --git a/GUI/osp_pop_distrOvQuant_Call.m b/GUI/osp_pop_distrOvQuant_Call.m index 12d7dc7f..07b2e9f0 100644 --- a/GUI/osp_pop_distrOvQuant_Call.m +++ b/GUI/osp_pop_distrOvQuant_Call.m @@ -27,18 +27,37 @@ function osp_pop_distrOvQuant_Call(src,~,gui) idx=(src.Value); src.Value=idx; gui.quant.Selected.Quant = idx; - metab = get(gui.controls.pop_distrOvMetab, 'Value'); Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(4),'String',gui.controls.act_x) + if ~strcmp(Selection,'Quality') - split_Selection = strsplit(Selection,'-'); - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') + split_Selection = strsplit(Selection,'-'); + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') + set(gui.controls.pop_distrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); set(gui.controls.pop_distrOvMetab, 'String', {'GABA'}); set(gui.controls.pop_distrOvMetab, 'Value', gui.quant.idx.GABA); - set(gui.controls.pop_distrOvMetab, 'Enable', 'off'); + set(gui.controls.pop_distrOvMetab, 'Enable', 'on'); else - set(gui.controls.pop_distrOvMetab, 'String', MRSCont.quantify.metabs.(split_Selection{1})); - set(gui.controls.pop_distrOvMetab, 'Value', metab); + metab_idx_old = get(gui.controls.pop_distrOvMetab, 'Value'); + name_list=get(gui.controls.pop_distrOvMetab, 'String'); + name_old = name_list{metab_idx_old}; + name_list_new=MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}; + metab_idx_new = find(strcmp(name_list_new,name_old)); + if ~isempty(metab_idx_new) + set(gui.controls.pop_distrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + else + metab_idx_new = 1; + set(gui.controls.pop_distrOvMetab, 'Value', 1); + set(gui.controls.pop_distrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + gui.overview.Selected.Metab = 1; + end + set(gui.controls.pop_distrOvMetab, 'Value', metab_idx_new); set(gui.controls.pop_distrOvMetab, 'Enable', 'on'); + + end else gui.overview.Selected.Metab = 1; diff --git a/GUI/osp_pop_whichcorrOvCorr_Call.m b/GUI/osp_pop_whichcorrOvCorr_Call.m index 44260b2f..e81ef8a2 100644 --- a/GUI/osp_pop_whichcorrOvCorr_Call.m +++ b/GUI/osp_pop_whichcorrOvCorr_Call.m @@ -30,13 +30,32 @@ function osp_pop_whichcorrOvCorr_Call(src,~,gui) gui.overview.Selected.Corr = 1; Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; split_Selection = strsplit(Selection,'-'); + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(4),'String',gui.controls.act_x) + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); if idx == 1 set(gui.controls.pop_corrOvCorr, 'String', gui.overview.Names.QM); set(gui.controls.pop_corrOvCorr, 'Value', gui.overview.Selected.Corr); else if idx == 2 - set(gui.controls.pop_corrOvCorr, 'String', MRSCont.quantify.metabs.(split_Selection{1})); - set(gui.controls.pop_corrOvCorr, 'Value', gui.overview.Selected.Corr); + metab_idx_old = get(gui.controls.pop_corrOvCorr, 'Value'); + name_list=get(gui.controls.pop_corrOvCorr, 'String'); + name_old = name_list{metab_idx_old}; + name_list_new=MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}; + metab_idx_new = find(strcmp(name_list_new,name_old)); + if ~isempty(metab_idx_new) + set(gui.controls.pop_corrOvCorr, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + set(gui.controls.pop_corrOvCorr, 'Value', gui.overview.Selected.Corr); + else + metab_idx_new = 1; + set(gui.controls.pop_corrOvCorr, 'Value', 1); + set(gui.controls.pop_corrOvCorr, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + gui.overview.Selected.Corr = 1; + end + set(gui.controls.pop_corrOvCorr, 'Value', metab_idx_new); + + else set(gui.controls.pop_corrOvCorr, 'String', gui.overview.Names.Corr); set(gui.controls.pop_corrOvCorr, 'Value', gui.overview.Selected.Corr); diff --git a/GUI/osp_updateFitWindow.m b/GUI/osp_updateFitWindow.m index e65bea80..c3fcdf42 100644 --- a/GUI/osp_updateFitWindow.m +++ b/GUI/osp_updateFitWindow.m @@ -6,8 +6,8 @@ function osp_updateFitWindow(gui) % USAGE: % osp_updateFitWindow(gui); % -% INPUT: -% gui = gui class containing all handles and the MRSCont +% INPUT: +% gui = gui class containing all handles and the MRSCont % % % AUTHORS: @@ -25,11 +25,10 @@ function osp_updateFitWindow(gui) %%% 1. INITIALIZE %%% MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class Selection = gui.fit.Names{gui.fit.Selected}; - if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - set(gui.layout.(gui.layout.fitTabhandles{gui.fit.Selected}).Children(2).Children(3).Children(1).Children.Children(4),'String',gui.controls.act_z) - set(gui.layout.(gui.layout.fitTabhandles{gui.fit.Selected}).Children(2).Children(3).Children(1).Children.Children(5),'String',gui.controls.act_y) - set(gui.layout.(gui.layout.fitTabhandles{gui.fit.Selected}).Children(2).Children(3).Children(1).Children.Children(6),'String',gui.controls.act_x) - end + + set(gui.layout.(gui.layout.fitTabhandles{gui.fit.Selected}).Children(2).Children(3).Children(1).Children.Children(4),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.fitTabhandles{gui.fit.Selected}).Children(2).Children(3).Children(1).Children.Children(5),'String',gui.controls.act_y) + set(gui.layout.(gui.layout.fitTabhandles{gui.fit.Selected}).Children(2).Children(3).Children(1).Children.Children(6),'String',gui.controls.act_x) switch MRSCont.opts.fit.method case 'LCModel' gui.Results.FitTextCRLB = gui.Results.fit{gui.fit.Selected}.Children.Children(1); @@ -39,23 +38,26 @@ function osp_updateFitWindow(gui) gui.Results.FitTextAmpl = gui.Results.fit{gui.fit.Selected}.Children.Children(1); gui.Results.FitTextNames = gui.Results.fit{gui.fit.Selected}.Children.Children(2); end - + gui.layout.EmptyFitPlot = 0; - - + + %%% 2. FILLING INFO PANEL FOR THIS TAB %%% % All the information from the Raw data is read out here - if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') || strcmp(gui.fit.Names{gui.fit.Selected}, 'w') %Is not concateneted or is reference/water fit + if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') || strcmp(gui.fit.Names{gui.fit.Selected}, 'w') %Is not concateneted or is reference/water fit gui.fit.Style = gui.fit.Names{gui.fit.Selected}; else %Is concatenated and not water/reference gui.fit.Style = 'conc'; end - + + + basis = gui.controls.act_z; + subspectrum = gui.controls.act_y; % For this visualization, we will have to make a few % distinctions upfront since the modeling algorithms (LCModel % vs. Osprey) do not always return the same kinds of data, or they % return them in different formats. - + switch MRSCont.opts.fit.method case 'LCModel' % Number of metabolites and lipid/MM basis functions @@ -72,27 +74,27 @@ function osp_updateFitWindow(gui) % Smaller fonts for the results resultsFontSize = 9; case 'Osprey' - % Number of metabolites and lipid/MM basis functions - nMets = MRSCont.fit.basisSet.nMets; - nMMLip = MRSCont.fit.basisSet.nMM; - % Additional info panel string for the water fit range + % Additional info panel string for the water fit range waterFitRangeString = ['Fitting range: ' num2str(MRSCont.opts.fit.rangeWater(1)) ' to ' num2str(MRSCont.opts.fit.rangeWater(2)) ' ppm']; % Where are the metabolite names stored? if strcmp(gui.fit.Style, 'ref') || strcmp(gui.fit.Style, 'w') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).water.(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.spectralwidth))]).name; + basisSet = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{gui.controls.Selected}.sz(1)) '_' num2str(MRSCont.processed.metab{gui.controls.Selected}.spectralwidth)]){1}; + basisSetNames = basisSet.name; else if strcmp(gui.fit.Style, 'conc') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.spectralwidth))]).name; - else if strcmp(gui.fit.Style, 'off') - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.spectralwidth))]).name; - else - basisSetNames = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.sz(1))) '_' num2str(round(MRSCont.processed.A{gui.controls.Selected}.spectralwidth))]).name; - end + basisSet = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{gui.controls.Selected}.sz(1)) '_' num2str(MRSCont.processed.metab{gui.controls.Selected}.spectralwidth)]){basis,1}; + basisSetNames = basisSet.name; + else + basisSet = MRSCont.fit.resBasisSet.(gui.fit.Style).(['np_sw_' num2str(MRSCont.processed.metab{gui.controls.Selected}.sz(1)) '_' num2str(MRSCont.processed.metab{gui.controls.Selected}.spectralwidth)]){basis,1,subspectrum}; + basisSetNames = basisSet.name; end end + % Number of metabolites and lipid/MM basis functions + nMets = basisSet.nMets; + nMMLip = basisSet.nMM; % Larger fonts for the results resultsFontSize = 11; end - + if ~((isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI)) switch MRSCont.opts.fit.method case 'LCModel' @@ -103,18 +105,18 @@ function osp_updateFitWindow(gui) CRLB = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.CRLB; end case 'Osprey' - RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ampl .* MRSCont.fit.scale{1,gui.controls.Selected}; + RawAmpl = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ampl .* MRSCont.fit.scale{1,gui.controls.Selected}; end - ph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph0; - ph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph1; + ph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ph0; + ph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ph1; if ~strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') && ~strcmp(gui.fit.Names{gui.fit.Selected}, 'w') - refShift = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refShift; - refFWHM = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refFWHM; + refShift = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.refShift; + refFWHM = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.refFWHM; switch MRSCont.opts.fit.method case 'Osprey' - iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph0 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; end @@ -129,18 +131,18 @@ function osp_updateFitWindow(gui) CRLB = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{gui.controls.Selected}.CRLB; end case 'Osprey' - RawAmpl = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; + RawAmpl = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{basis,gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; end - ph0 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph0; - ph1 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph1; + ph0 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{basis,gui.controls.Selected}.ph0; + ph1 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{basis,gui.controls.Selected}.ph1; if ~strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') && ~strcmp(gui.fit.Names{gui.fit.Selected}, 'w') - refShift = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refShift; - refFWHM = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refFWHM; + refShift = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{basis,gui.controls.Selected}.refShift; + refFWHM = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{basis,gui.controls.Selected}.refFWHM; switch MRSCont.opts.fit.method case 'Osprey' - iniph0 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph0 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{basis,gui.controls.Selected}.prelimParams.ph0; + iniph1 = MRSCont.fit.results{1,gui.controls.act_x}.(gui.fit.Style).fitParams{basis,gui.controls.Selected}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; end @@ -155,24 +157,24 @@ function osp_updateFitWindow(gui) CRLB = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{gui.controls.Selected}.CRLB; end case 'Osprey' - RawAmpl = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{gui.controls.Selected}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; + RawAmpl = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ampl .* MRSCont.fit.scale{gui.controls.Selected}; end - ph0 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph0; - ph1 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.ph1; + ph0 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ph0; + ph1 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.ph1; if ~strcmp(gui.fit.Names{gui.fit.Selected}, 'ref') && ~strcmp(gui.fit.Names{gui.fit.Selected}, 'w') - refShift = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refShift; - refFWHM = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.refFWHM; + refShift = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.refShift; + refFWHM = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.refFWHM; switch MRSCont.opts.fit.method case 'Osprey' - iniph0 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph0; - iniph1 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{1,gui.controls.Selected}.prelimParams.ph1; - case 'LCModel' + iniph0 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results{gui.controls.act_x,gui.controls.act_y}.(gui.fit.Style).fitParams{basis,gui.controls.Selected,subspectrum}.prelimParams.ph1; + case 'LCModel' iniph0 = nan; iniph1 = nan; end end end - + if ~strcmp (Selection, 'ref') && ~strcmp (Selection, 'w') %Metabolite data? StatText = ['Metabolite Data -> Sequence: ' gui.load.Names.Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' Selection,... '\nFitting range: ' num2str(MRSCont.opts.fit.range(1)) ' to ' num2str(MRSCont.opts.fit.range(2)) ' ppm; Baseline knot spacing: ' num2str(MRSCont.opts.fit.bLineKnotSpace) ' ppm; ph0: ' num2str(ph0,'%1.2f') 'deg; ph1: ' num2str(ph1,'%1.2f') 'deg; refShift: ' num2str(refShift,'%1.2f') ' Hz; refFWHM: ' num2str(refFWHM,'%1.2f')... @@ -287,7 +289,7 @@ function osp_updateFitWindow(gui) set(gui.Results.FitTextNames, 'String',sprintf(NameText)); set(gui.Results.FitTextAmpl, 'String',sprintf(RawAmplText)); end - end + end else if ~(MRSCont.flags.hasRef || MRSCont.flags.hasWater) %Raw amplitudes are reported as no water/reference fitting was performed if ~(strcmp(gui.fit.Style, 'ref') || strcmp(gui.fit.Style, 'w')) %Metabolite fit? @@ -331,12 +333,12 @@ function osp_updateFitWindow(gui) set(gui.Results.FitTextNames, 'String',sprintf(NameText)); set(gui.Results.FitTextAmpl, 'String',sprintf(RawAmplText)); end - end + end end %%%3. VISUALIZATION PART OF THIS TAB %%% temp = figure( 'Visible', 'off' ); - if ~isfield(MRSCont.flags,'isPRIAM') && ~isfield(MRSCont.flags,'isMRSI') && ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI - temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,1,Selection); %Create figure + if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI + temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,[gui.controls.act_x gui.controls.act_y gui.controls.act_z],Selection); %Create figure elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM temp = osp_plotFit(MRSCont, gui.controls.Selected,gui.fit.Style,gui.controls.act_x,Selection); %Create figure else @@ -353,10 +355,10 @@ function osp_updateFitWindow(gui) set(gui.Plot.fit{gui.fit.Selected}.Children(2), 'OuterPosition', [0.17,0.02,0.75,0.98]) % Get rid of the Load figure close(temp); - + % If it is Multivoxel data we have to update the Voxel Position % window - if MRSCont.flags.isMRSI + if MRSCont.flags.isMRSI temp = osp_plotRawMRSIpos(MRSCont, 1, [gui.controls.act_y gui.controls.act_x]); ViewAxes = gca(); drawnow @@ -366,4 +368,4 @@ function osp_updateFitWindow(gui) set(gui.upperBox.fit.Info{gui.fit.Selected},'Title', ['Actual file: ' MRSCont.files{gui.controls.Selected}] ); set(gui.controls.b_save_fitTab{gui.fit.Selected},'Callback',{@osp_onPrint,gui}); setappdata(gui.figure,'MRSCont',MRSCont); % Get MRSCont from hidden container in gui class -end \ No newline at end of file +end diff --git a/GUI/osp_updateLoadWindow.m b/GUI/osp_updateLoadWindow.m index a2b2c75d..683b0aed 100644 --- a/GUI/osp_updateLoadWindow.m +++ b/GUI/osp_updateLoadWindow.m @@ -23,7 +23,7 @@ function osp_updateLoadWindow(gui) % HISTORY: % 2020-01-16: First version of the code. %%% 1. INITIALIZE %%% - MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) set(gui.layout.(gui.layout.rawTabhandles{gui.load.Selected}).Children(2).Children(3).Children(1).Children.Children(4),'String',gui.controls.act_z) set(gui.layout.(gui.layout.rawTabhandles{gui.load.Selected}).Children(2).Children(3).Children(1).Children.Children(5),'String',gui.controls.act_y) @@ -33,46 +33,33 @@ function osp_updateLoadWindow(gui) gui.layout.EmptyPlot.data = 0; %%% 2. FILLING INFO PANEL FOR THIS TAB %%% % All the information from the Raw data is read out here - if gui.load.Selected == 1 %Is metabolite data? + switch gui.load.Names.Spec{gui.load.Selected} + case 'metabolites' StatText = ['Metabolite Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw{1,gui.controls.Selected}.tr) '\naverages: ' num2str(MRSCont.raw{1,gui.controls.Selected}.averages)... '; Sz: ' num2str(MRSCont.raw{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... num2str(MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; - else - if MRSCont.flags.hasMM %re_mm - if gui.load.Selected == 2 %re_mm + case 'MM' StatText = ['MM Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.spectralwidth) ' Hz'... %re_mm '\nraw subspecs: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.averages)... '; Sz: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... %re_mm num2str(MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_mm{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; %re_mm - end %re_mm - if gui.load.Selected == 3 %Is water or ref data? %re_mm + case 'reference' StatText = ['Reference Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.spectralwidth) ' Hz'... %re_mm '\nraw subspecs: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.averages)... '; Sz: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... %re_mm num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; %re_mm - end %re_mm - else %re_mm - if gui.load.Selected == 2 %Is water or ref data? - if MRSCont.flags.hasRef - StatText = ['Reference Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.spectralwidth) ' Hz'... - '\nraw subspecs: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.averages)... - '; Sz: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... - num2str(MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; - elseif MRSCont.flags.hasWater - StatText = ['Water Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.spectralwidth) ' Hz'... - '\nraw subspecs: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.averages)... - '; Sz: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... - num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; - end - else + case 'MM reference' + StatText = ['MM reference Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.spectralwidth) ' Hz'... + '\nraw subspecs: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.averages)... + '; Sz: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... + num2str(MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_mm_ref{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; + case 'water' StatText = ['Water Data -> Sequence: ' gui.load.Names.Seq '; B0: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.Bo) '; TE / TR: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.te) ' / ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.spectralwidth) ' Hz'... '\nraw subspecs: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.rawAverages) '; averages: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.averages)... '; Sz: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.sz) '; dimensions: ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1})) ' x ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2})) ' x ' num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})) ' mm = '... num2str(MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{1}) * MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{2}) * MRSCont.raw_w{1,gui.controls.Selected}.geometry.size.(gui.load.Names.Geom{3})/1000) ' ml']; - end - end %re_mm - end + if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI set(gui.InfoText.data{gui.load.Selected}, 'String',sprintf(StatText)) elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM @@ -86,13 +73,19 @@ function osp_updateLoadWindow(gui) %%% 3. VISUALIZATION PART OF THIS TAB %%% temp = figure( 'Visible', 'off' ); - if gui.load.Selected == 1 %Is Metabolite data/tab? + Exp = gui.controls.act_Exp; + switch gui.load.Names.Spec{gui.load.Selected} + case 'metabolites' + if Exp > max(MRSCont.opts.MultipleSpectra.metab) + Exp = 1; + gui.controls.act_Exp = 1; + end if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets'); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets',Exp); elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets',gui.controls.act_x); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets',Exp,gui.controls.act_x); else - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets',[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mets',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); end if MRSCont.flags.isUnEdited %Is UnEdited? ViewAxes = gca(); @@ -135,93 +128,119 @@ function osp_updateLoadWindow(gui) set( gui.layout.multiAload.Children, 'YLim', temp.Children(4).YLim); set( temp.Children(4).Children, 'Parent', gui.layout.multiAload.Children ); % Update pre alignment plot end - else - if MRSCont.flags.hasMM %re_mm - if gui.load.Selected == 2 %ref data/tab %re_mm - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm'); + set(gui.upperBox.data.Info{gui.load.Selected},'Title', ['Actual file: ' MRSCont.files{Exp,gui.controls.Selected}] ); + case 'MM' + if Exp > max(MRSCont.opts.MultipleSpectra.mm) + Exp = 1; + gui.controls.act_Exp = 1; + end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',Exp); elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',gui.controls.act_x); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',Exp,gui.controls.act_x); else - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); - end - ViewAxes = gca(); - delete(gui.Plot.data{gui.load.Selected}.Children(1).Children(1).Children) - set( gui.Plot.data{gui.load.Selected}.Children(1).Children(1), 'XLim',ViewAxes.XLim) - set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children(1).Children(1)); - set( gui.Plot.data{gui.load.Selected}.Children(1).Children(1).Title, 'String',ViewAxes.Title.String) - end %re_mm - if gui.load.Selected == 3 %ref data/tab %re_mm - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref'); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + end + if MRSCont.flags.isUnEdited %Is UnEdited? + ViewAxes = gca(); + delete(gui.Plot.data{gui.load.Selected}.Children(1).Children) + set(gui.Plot.data{gui.load.Selected}.Children, 'XLim', ViewAxes.XLim) + set(gui.Plot.data{gui.load.Selected}.Children, 'YLim', ViewAxes.YLim) + set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children); + set(gui.Plot.data{gui.load.Selected}.Children.Title, 'String', ViewAxes.Title.String) + end + if MRSCont.flags.isMEGA %Is MEGA? + delete(gui.Plot.data{gui.load.Selected}.Children(1).Children) + delete(gui.Plot.data{gui.load.Selected}.Children(2).Children) + set(gui.Plot.data{gui.load.Selected}.Children(2), 'XLim', temp.Children(2).XLim) + set(gui.Plot.data{gui.load.Selected}.Children(1), 'XLim', temp.Children(1).XLim) + set(gui.Plot.data{gui.load.Selected}.Children(2), 'YLim', temp.Children(2).YLim) + set(gui.Plot.data{gui.load.Selected}.Children(1), 'YLim', temp.Children(1).YLim) + set(temp.Children(2).Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children(2)); + set(temp.Children(1).Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children(1)); + set(gui.Plot.data{gui.load.Selected}.Children(2).Title, 'String', temp.Children(2).Title.String) + end + if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) % Is HERMES/HERCULES + try + delete(gui.layout.multiAload.Children.Children) + delete(gui.layout.multiBload.Children.Children) + delete(gui.layout.multiCload.Children.Children) + delete(gui.layout.multiDload.Children.Children) + catch + end + %Fill window with new content + set( gui.layout.multiDload.Children, 'XLim', temp.Children(1).XLim); + set( gui.layout.multiDload.Children, 'YLim', temp.Children(1).YLim); + set( temp.Children(1).Children, 'Parent', gui.layout.multiDload.Children ); % Update drift plot + set( gui.layout.multiCload.Children, 'XLim', temp.Children(2).XLim); + set( gui.layout.multiCload.Children, 'YLim', temp.Children(2).YLim); + set( temp.Children(2).Children, 'Parent', gui.layout.multiCload.Children ); % Update aligned and averaged plot + set( gui.layout.multiBload.Children, 'XLim', temp.Children(3).XLim); + set( gui.layout.multiBload.Children, 'YLim', temp.Children(3).YLim); + set( temp.Children(3).Children, 'Parent', gui.layout.multiBload.Children ); % Update post alignment plot + set( gui.layout.multiAload.Children, 'XLim', temp.Children(4).XLim); + set( gui.layout.multiAload.Children, 'YLim', temp.Children(4).YLim); + set( temp.Children(4).Children, 'Parent', gui.layout.multiAload.Children ); % Update pre alignment plot + end + set(gui.upperBox.data.Info{gui.load.Selected},'Title', ['Actual file: ' MRSCont.files_mm{Exp,gui.controls.Selected}] ); + case 'reference' + if Exp > max(MRSCont.opts.MultipleSpectra.ref) + Exp = 1; + gui.controls.act_Exp = 1; + end + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',Exp); elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',gui.controls.act_x); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',Exp,gui.controls.act_x); else - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); - end + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + end ViewAxes = gca(); delete(gui.Plot.data{gui.load.Selected}.Children.Children) set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children); set(gui.Plot.data{gui.load.Selected}.Children.Title, 'String', ViewAxes.Title.String); set(gui.Plot.data{gui.load.Selected}.Children, 'XLim',ViewAxes.XLim); - end %re_mm - if gui.load.Selected == 4 %ref data/tab %re_mm - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); - elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',gui.controls.act_x); - else - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); - end - ViewAxes = gca(); - delete(gui.Plot.data{gui.load.Selected}.Children(1).Children) - set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children(1)); - set( gui.Plot.data{gui.load.Selected}.Children(1).Title, 'String',ViewAxes.Title.String) - set( gui.Plot.data{gui.load.Selected}.Children(1), 'XLim',ViewAxes.XLim) + set(gui.upperBox.data.Info{gui.load.Selected},'Title', ['Actual file: ' MRSCont.files_ref{Exp,gui.controls.Selected}] ); + case 'MM reference' + if Exp > max(MRSCont.opts.MultipleSpectra.mm_ref) + Exp = 1; + gui.controls.act_Exp = 1; end - else %re_mm - if gui.load.Selected == 2 %Is Ref data/tab? - if MRSCont.flags.hasRef - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref'); - elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'ref',gui.controls.act_x); - end - ViewAxes = gca(); - delete(gui.Plot.data{gui.load.Selected}.Children(1).Children) - set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children(1)); - set(gui.Plot.data{gui.load.Selected}.Children(1).Title, 'String', ViewAxes.Title.String) - set(gui.Plot.data{gui.load.Selected}.Children(1), 'XLim',ViewAxes.XLim) - elseif MRSCont.flags.hasWater - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm_ref',Exp); elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',gui.controls.act_x); - else - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); - end - ViewAxes = gca(); - delete(gui.Plot.data{gui.load.Selected}.Children(1).Children) - set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children(1)); - set( gui.Plot.data{gui.load.Selected}.Children(1).Children(1).Title, 'String',ViewAxes.Title.String) - set( gui.Plot.data{gui.load.Selected}.Children(1).Children(1), 'XLim',ViewAxes.XLim) + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm_ref',Exp,gui.controls.act_x); + else + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'mm_ref',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + end + ViewAxes = gca(); + delete(gui.Plot.data{gui.load.Selected}.Children.Children) + set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children); + set(gui.Plot.data{gui.load.Selected}.Children.Title, 'String', ViewAxes.Title.String); + set(gui.Plot.data{gui.load.Selected}.Children, 'XLim',ViewAxes.XLim); + set(gui.upperBox.data.Info{gui.load.Selected},'Title', ['Actual file: ' MRSCont.files_mm_ref{Exp,gui.controls.Selected}] ); + case 'water' + if Exp > max(MRSCont.opts.MultipleSpectra.w) + Exp = 1; + gui.controls.act_Exp = 1; end - else %Is water data/tab? if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w'); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',Exp); elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',gui.controls.act_x); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',Exp,gui.controls.act_x); else - temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); + temp = osp_plotLoad(MRSCont, gui.controls.Selected,'w',Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); end ViewAxes = gca(); delete(gui.Plot.data{gui.load.Selected}.Children(1).Children) set(ViewAxes.Children, 'Parent', gui.Plot.data{gui.load.Selected}.Children(1)); set( gui.Plot.data{gui.load.Selected}.Children(1).Title, 'String',ViewAxes.Title.String) - set( gui.Plot.data{gui.load.Selected}.Children(1), 'XLim',ViewAxes.XLim) - end - end + set( gui.Plot.data{gui.load.Selected}.Children(1), 'XLim',ViewAxes.XLim) + set(gui.upperBox.data.Info{gui.load.Selected},'Title', ['Actual file: ' MRSCont.files_w{Exp,gui.controls.Selected}] ); end + + + % Get rid of the Load figure close( temp ); h = findall(groot,'Type','figure'); @@ -239,8 +258,10 @@ function osp_updateLoadWindow(gui) drawnow set( gui.layout.LocPanel.Children,'ColorData', ViewAxes.ColorData ); close(temp) - end - set(gui.upperBox.data.Info{gui.load.Selected},'Title', ['Actual file: ' MRSCont.files{gui.controls.Selected}] ); + end set(gui.controls.b_save_RawTab{gui.load.Selected},'Callback',{@osp_onPrint,gui}); + if MRSCont.nDatasets(2) > 1 + set(gui.layout.(gui.layout.rawTabhandles{gui.load.Selected}).Children(2).Children(3).Children(1).Children.Children(2),'String',gui.controls.act_Exp) + end setappdata(gui.figure,'MRSCont',MRSCont); % Write MRSCont into hidden container in gui class end diff --git a/GUI/osp_updateProWindow.m b/GUI/osp_updateProWindow.m index 9faa7a80..01331176 100644 --- a/GUI/osp_updateProWindow.m +++ b/GUI/osp_updateProWindow.m @@ -28,87 +28,70 @@ function osp_updateProWindow(gui) set(gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children(3).Children(1).Children.Children(4),'String',gui.controls.act_z); set(gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children(3).Children(1).Children.Children(5),'String',gui.controls.act_y); set(gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children(3).Children(1).Children.Children(6),'String',gui.controls.act_x); + else + set(gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children(3).Children(1).Children.Children(3),'String',gui.controls.act_y); + set(gui.layout.(gui.layout.proTabhandles{gui.process.Selected}).Children(2).Children(3).Children(1).Children.Children(4),'String',gui.controls.act_x); end gui.layout.EmptyProPlot = 0; - Selection = gui.process.Names{gui.process.Selected}; + Selection = gui.process.TabTitles{gui.process.Selected}; + Exp = gui.controls.act_x; + SubSpec = gui.controls.act_y; + + if (MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.dims.extras == 0) || (Exp > MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.sz(MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.dims.extras)) + Exp = 1; + gui.controls.act_x = 1; + end + if (MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.dims.subSpecs == 0) || (SubSpec > MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.sz(MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.dims.subSpecs)) + SubSpec = 1; + gui.controls.act_x = 1; + end + %%% 2. FILLING INFO PANEL FOR THIS TAB %%% % All the information from the Raw data is read out here - if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - - if ~strcmp (Selection, 'ref') && ~strcmp (Selection, 'w') && ~strcmp (Selection, 'mm') %Metabolite data? - StatText = ['Metabolite Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq/1e6) ' Hz']; - else if strcmp (Selection, 'ref') %Reference data? - StatText = ['Reference Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else if ~strcmp (Selection, 'mm') % re_mm - StatText = ['Water Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '/' (num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else - StatText = ['MM Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '/' (num2str(MRSCont.QM.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - end - end - end - elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - if ~strcmp (Selection, 'ref') && ~strcmp (Selection, 'w') && ~strcmp (Selection, 'mm') %Metabolite data? - StatText = ['Voxel ' num2str(gui.controls.act_x) ': Metabolite Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{1,gui.controls.act_x}.freqShift.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.pre.AvgDeltaCr.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.post.AvgDeltaCr.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)*MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq/1e6) ' Hz']; - else if strcmp (Selection, 'ref') %Reference data? - StatText = ['Voxel ' num2str(gui.controls.act_x) ': Reference Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else if ~strcmp (Selection, 'mm') % re_mm - StatText = ['Voxel ' num2str(gui.controls.act_x) ': Water Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '/' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else - StatText = ['Voxel ' num2str(gui.controls.act_x) ': MM Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)) '/' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.Names{gui.process.Selected})(gui.controls.Selected)/MRSCont.processed.(gui.process.Names{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - end + if ~(isfield(MRSCont.flags,'isPRIAM')|| isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + if strcmp(gui.process.TabTitles{gui.process.Selected},'metab') + StatText = ['SNR(' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{SubSpec} '): ' num2str(MRSCont.QM.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)) '; FWHM (' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{1} '): '... + num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)/MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected,SubSpec)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.A(gui.controls.Selected)*MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.A(gui.controls.Selected)*MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6) ' Hz']; + else + StatText = ['SNR(' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{1} '): ' num2str(MRSCont.QM.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.(gui.process.TabTitles{gui.process.Selected}).SNR{1} '): '... + num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.TabTitles{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)*1e6))... + ' Hz / ppm']; end - end - else - if (strcmp(Selection,'A') || strcmp(Selection,'B') || strcmp(Selection,'C') || strcmp(Selection,'D') || strcmp(Selection,'diff1') || strcmp(Selection,'diff2') || strcmp(Selection,'sum')) - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': Metabolite Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(Selection)(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)/MRSCont.processed.(Selection){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.freqShift.(Selection)(gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.pre.AvgDeltaCr.(Selection)(gui.controls.Selected)*MRSCont.processed.(Selection){gui.controls.Selected}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.post.AvgDeltaCr.(Selection)(gui.controls.Selected)*MRSCont.processed.(Selection){gui.controls.Selected}.txfrq/1e6) ' Hz']; - else if strcmp(Selection,'ref') - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': Reference Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(Selection)(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)/MRSCont.processed.(Selection){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + if (contains(gui.process.TabTitles{gui.process.Selected},{'A','B','C','D','diff1','diff2','sum'})) + StatText = ['Voxel ' num2str(gui.controls.act_x) ': SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... + num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{1,gui.controls.act_x}.freqShift.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.pre.AvgDeltaCr.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{1,gui.controls.act_x}.drift.post.AvgDeltaCr.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6) ' Hz']; else - if ~strcmp(Selection,'mm') %re - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': Water Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(Selection)(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)) '/' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)/MRSCont.processed.(Selection){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - else - StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': MM Data -> SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(Selection)(gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... - num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)) '/' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(Selection)(gui.controls.Selected)/MRSCont.processed.(Selection){gui.controls.Selected}.txfrq*1e6))... - ' Hz / ppm']; - end %re + StatText = ['Voxel ' num2str(gui.controls.act_x) ':SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{1,gui.controls.act_x}.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... + num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{1,gui.controls.act_x}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... + ' Hz / ppm']; end - end - end + else + if (contains(gui.process.TabTitles{gui.process.Selected},{'A','B','C','D','diff1','diff2','sum'})) + StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... + num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.freqShift.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.pre.AvgDeltaCr.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.drift.post.AvgDeltaCr.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)*MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq(Exp)/1e6) ' Hz']; + else + StatText = ['Voxel ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y) ': SNR(' gui.process.SNR{gui.process.Selected} '): ' num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.SNR.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) '; FWHM (' gui.process.SNR{gui.process.Selected} '): '... + num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)) ' / ' (num2str(MRSCont.QM{gui.controls.act_x,gui.controls.act_y}.FWHM.(gui.process.TabTitles{gui.process.Selected})(Exp,gui.controls.Selected)/MRSCont.processed.(gui.process.StructFields{gui.process.Selected}){gui.controls.Selected}.txfrq*1e6))... + ' Hz / ppm']; + end + end - set(gui.InfoText.pro{gui.process.Selected}, 'String',sprintf(StatText)); + set(gui.InfoText.pro, 'String',sprintf(StatText)); %%% 3. VISUALIZATION PART OF THIS TAB %%% if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection); %Create figure + temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection,SubSpec,Exp); %Create figure elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection,gui.controls.act_x); %Create figure + temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection,SubSpec,Exp,gui.controls.act_x); %Create figure else - temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); %Create figure + temp = osp_plotProcess(MRSCont, gui.controls.Selected,Selection,SubSpec,Exp,[gui.controls.act_x gui.controls.act_y gui.controls.act_z]); %Create figure end %Delete old content delete(gui.layout.proDrift.Children.Children) diff --git a/GUI/osp_updateQuantifyWindow.m b/GUI/osp_updateQuantifyWindow.m index ac65153f..35273d0a 100644 --- a/GUI/osp_updateQuantifyWindow.m +++ b/GUI/osp_updateQuantifyWindow.m @@ -25,12 +25,17 @@ function osp_updateQuantifyWindow(gui) %%% 1. INITIALIZE %%% MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class gui.layout.EmptyQuantPlot = 0; + basisSet = MRSCont.fit.resBasisSet.metab.(['np_sw_' num2str(MRSCont.processed.metab{gui.controls.Selected}.sz(1)) '_' num2str(MRSCont.processed.metab{gui.controls.Selected}.spectralwidth)]){gui.controls.act_z,1,gui.controls.act_y}; + subSpecName = basisSet.names{1}; if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - gui.upperBox.quant.Info = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2); + gui.upperBox.quant.Info = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(1); + set(gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(2).Children.Children.Children(4),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(2).Children.Children.Children(5),'String',gui.controls.act_y) + set(gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(2).Children.Children.Children(6),'String',gui.controls.act_x) gui.Plot.quant = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(1); - gui.InfoText.quant = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children; + gui.InfoText.quant = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(1).Children; StatText = ['Sequence: ' gui.load.Names.Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style ... - '\nSelected subspecs: ' gui.quant.Names.Model{gui.quant.Selected.Model} ]; + '\nSelected metabolite subspectrum: ' subSpecName '\nMM model ' num2str(gui.controls.act_z) ]; elseif (MRSCont.flags.isPRIAM && isfield(MRSCont.flags,'isPRIAM')) gui.upperBox.quant.Info = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(1); set(gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(2).Children.Children.Children(4),'String',gui.controls.act_z) @@ -39,7 +44,7 @@ function osp_updateQuantifyWindow(gui) gui.Plot.quant = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(1); gui.InfoText.quant = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(1).Children; StatText = ['Voxel ' num2str(gui.controls.act_x) ': Sequence: ' gui.load.Names.Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style ... - '\nSelected subspecs: ' gui.quant.Names.Model{gui.quant.Selected.Model} ]; + '\nSelected metabolite subspectrum: ' gui.quant.Names.Model{gui.quant.Selected.Model} ]; else gui.upperBox.quant.Info = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(1); set(gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(2).Children.Children.Children(4),'String',gui.controls.act_z) @@ -50,9 +55,10 @@ function osp_updateQuantifyWindow(gui) gui.Plot.quantMRSImap = gui.Plot.quantHBox.Children(1).Children(2); gui.InfoText.quant = gui.layout.(gui.layout.quantifyTabhandles{gui.quant.Selected.Model}).Children(2).Children(1).Children; StatText = ['Metabolite maps and fits of ' gui.load.Names.Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style ... - '\nSelected subspecs: ' gui.quant.Names.Model{gui.quant.Selected.Model} 'Selected voxel for fit display ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y)]; + '\nSelected metabolite subspectrum: ' gui.quant.Names.Model{gui.quant.Selected.Model} 'Selected voxel for fit display ' num2str(gui.controls.act_x) ' ' num2str(gui.controls.act_y)]; end + %%% 2. FILLING INFO PANEL FOR THIS TAB %%% % All the information from the Raw data is read out here set(gui.InfoText.quant, 'String',sprintf(StatText)) @@ -60,28 +66,28 @@ function osp_updateQuantifyWindow(gui) if ~(isfield(MRSCont.flags,'isMRSI')&& MRSCont.flags.isMRSI) gui.quant.Number.Quants = length(fieldnames(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}))); gui.quant.Names.Quants = fieldnames(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model})); - QuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}))+1,gui.quant.Number.Quants); + QuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y})+1,gui.quant.Number.Quants); QuantText{1,1} = 'Metabolite'; - QuantText(2:end,1) = MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model})'; + QuantText(2:end,1) = MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y}'; end if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) for q = 1 : gui.quant.Number.Quants %Collect all results QuantText(1,q+1) = gui.quant.Names.Quants(q); if strcmp(gui.quant.Names.Quants(q),'AlphaCorrWaterScaled') || strcmp(gui.quant.Names.Quants(q),'AlphaCorrWaterScaledGroupNormed') - idx_GABA = find(strcmp(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABA')); + idx_GABA = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y},'GABA')); if strcmp(MRSCont.opts.fit.coMM3, 'none') - tempQuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); - tempQuantText(idx_GABA) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1(gui.controls.Selected,:))'; + tempQuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y}),1); + tempQuantText(idx_GABA) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1{gui.controls.act_z,gui.controls.act_y}(gui.controls.Selected,:))'; else - tempQuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); - tempQuants = MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1(gui.controls.Selected,:); + tempQuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y}),1); + tempQuants = MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1{gui.controls.act_z,gui.controls.act_y}(gui.controls.Selected,:); tempQuantText(idx_GABA) = table2cell(tempQuants(1,1)); - idx_GABAp = find(strcmp(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABAplus')); + idx_GABAp = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}){gui.controls.act_z,gui.controls.act_y},'GABAplus')); tempQuantText(idx_GABAp) = table2cell(tempQuants(1,2)); end QuantText(2:end,q+1) = tempQuantText; else - QuantText(2:end,q+1) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1(gui.controls.Selected,:))'; + QuantText(2:end,q+1) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).Voxel_1{gui.controls.act_z,gui.controls.act_y}(gui.controls.Selected,:))'; end end temp=uimulticollist ( 'units', 'normalized', 'position', [0 0 1 1], 'string', QuantText,... @@ -94,15 +100,15 @@ function osp_updateQuantifyWindow(gui) for q = 1 : gui.quant.Number.Quants %Collect all results QuantText(1,q+1) = gui.quant.Names.Quants(q); if strcmp(gui.quant.Names.Quants(q),'AlphaCorrWaterScaled') || strcmp(gui.quant.Names.Quants(q),'AlphaCorrWaterScaledGroupNormed') - idx_GABA = find(strcmp(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABA')); + idx_GABA = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABA')); if strcmp(MRSCont.opts.fit.coMM3, 'none') - tempQuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); + tempQuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); tempQuantText(idx_GABA) = table2cell(MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).(['Voxel_' num2str(gui.controls.act_x)])(gui.controls.Selected,:))'; else - tempQuantText = cell(length(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); + tempQuantText = cell(length(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model})),1); tempQuants = MRSCont.quantify.tables.(gui.quant.Names.Model{gui.quant.Selected.Model}).(gui.quant.Names.Quants{q}).(['Voxel_' num2str(gui.controls.act_x)])(gui.controls.Selected,:); tempQuantText(idx_GABA) = table2cell(tempQuants(1,1)); - idx_GABAp = find(strcmp(MRSCont.quantify.metabs.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABAplus')); + idx_GABAp = find(strcmp(MRSCont.quantify.names.(gui.quant.Names.Model{gui.quant.Selected.Model}),'GABAplus')); tempQuantText(idx_GABAp) = table2cell(tempQuants(1,2)); end QuantText(2:end,q+1) = tempQuantText; diff --git a/GUI/osp_updateSpecsOvWindow.m b/GUI/osp_updateSpecsOvWindow.m index b0009289..1e28aef2 100644 --- a/GUI/osp_updateSpecsOvWindow.m +++ b/GUI/osp_updateSpecsOvWindow.m @@ -24,25 +24,37 @@ function osp_updateSpecsOvWindow(gui) % 2020-01-16: First version of the code. %%% 1. INITIALIZE %%% MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(4),'String',gui.controls.act_x) delete(gui.Plot.specsOv.Children(2).Children) + %%% 2. VISUALIZATION PART OF THIS TAB %%% Selection = gui.controls.pop_specsOvPlot.String(gui.process.Selected); if gui.controls.GM == 0 for g = 1 : gui.overview.Number.Groups %Loop over groups - temp = osp_plotOverviewSpec(MRSCont, Selection{1},g, gui.layout.shiftind); + temp = osp_plotOverviewSpec(MRSCont, Selection{1},g, gui.layout.shiftind,'Frequency (ppm)','','',gui.controls.act_z); ax=get(temp,'Children'); copyobj(ax.Children, gui.Plot.specsOv.Children(2)); end else - temp = osp_plotOverviewSpec(MRSCont, Selection{1},'GMean', gui.layout.shiftind); + temp = osp_plotOverviewSpec(MRSCont, Selection{1},'GMean', gui.layout.shiftind,'Frequency (ppm)','','',gui.controls.act_z); ax=get(temp,'Children'); copyobj(ax.Children, gui.Plot.specsOv.Children(2)); end - switch Selection{1} - case {'A','B','C','D','diff1','diff2','sum','MM','MM_clean'} + + which_spec_split = split(Selection); + if length(which_spec_split) == 3 + spec = which_spec_split{2}; + else + spec = which_spec_split{1}; + end + + switch spec + case {'metab','mm'} set(gui.Plot.specsOv.Children(2), 'XLim', [0.2 4.5]) set(gui.Plot.specsOv.Children(2).Title, 'String', ['Overview ' Selection]) - case {'ref','w','Fit:ref','Fit:w'} + case {'ref','w','mm_ref'} set(gui.Plot.specsOv.Children(2), 'XLim', [0 2*4.68]) set(gui.Plot.specsOv.Children(2).Title, 'String', ['Overview ' Selection]) otherwise diff --git a/GUI/osp_updatecorrOvWindow.m b/GUI/osp_updatecorrOvWindow.m index 637cba72..8097c998 100644 --- a/GUI/osp_updatecorrOvWindow.m +++ b/GUI/osp_updatecorrOvWindow.m @@ -27,44 +27,49 @@ function osp_updatecorrOvWindow(gui) delete(gui.Plot.corrOv.Children(3).Children) Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; split_Selection = strsplit(Selection,'-'); + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); + selectedOvTab = get(gui.layout.overviewTab,'Selection'); if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - set(gui.controls.corrOvPanel,'Title',['Actual Quantification and Metabolite in Voxel ' num2str(gui.controls.act_x)]); - set(gui.layout.corrOvTab.Children.Children(1).Children(3).Children.Children.Children(4),'String',gui.controls.act_z) - set(gui.layout.corrOvTab.Children.Children(1).Children(3).Children.Children.Children(5),'String',gui.controls.act_y) - set(gui.layout.corrOvTab.Children.Children(1).Children(3).Children.Children.Children(6),'String',gui.controls.act_x) + set(gui.controls.distrOvPanel,'Title',['Actual Quantification and Metabolite in Voxel ' num2str(gui.controls.act_x)]); + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children.Children(1).Children(3).Children.Children.Children(4),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children.Children(1).Children(3).Children.Children.Children(5),'String',gui.controls.act_y) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children.Children(1).Children(3).Children.Children.Children(6),'String',gui.controls.act_x) + else + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(4),'String',gui.controls.act_x) end %%% 2. VISUALIZATION PART OF THIS TAB %%% - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') metab = 'GABA'; else - metab = MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Metab}; + metab = MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}{gui.overview.Selected.Metab}; end - if ~(isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) if gui.overview.Selected.CorrChoice == 1 switch gui.overview.Selected.Corr case 1 - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.QM.SNR.A',gui.overview.Names.QM{gui.overview.Selected.Corr}); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.QM.SNR.metab(1,:,ind)',gui.overview.Names.QM{gui.overview.Selected.Corr},1,gui.controls.act_z); case 2 - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.QM.FWHM.A',gui.overview.Names.QM{gui.overview.Selected.Corr}); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.QM.FWHM.metab(1,:,ind)',gui.overview.Names.QM{gui.overview.Selected.Corr},1,gui.controls.act_z); end else if gui.overview.Selected.CorrChoice == 2 - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Corr},MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Corr}); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.quantify.names.(split_Selection{1}){1,ind}{gui.overview.Selected.Corr},MRSCont.quantify.names.(split_Selection{1}){1,ind}{gui.overview.Selected.Corr},1,gui.controls.act_z); else - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,gui.overview.CorrMeas{gui.overview.Selected.Corr},gui.overview.Names.Corr{gui.overview.Selected.Corr}); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,gui.overview.CorrMeas{gui.overview.Selected.Corr},gui.overview.Names.Corr{gui.overview.Selected.Corr},1,gui.controls.act_z); end end else if gui.overview.Selected.CorrChoice == 1 switch gui.overview.Selected.Corr case 1 - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.QM.SNR.A',gui.overview.Names.QM{gui.overview.Selected.Corr},gui.controls.act_x); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.QM.SNR.metab(1,:,ind)',gui.overview.Names.QM{gui.overview.Selected.Corr},gui.controls.act_x,gui.controls.act_z); case 2 - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.QM.FWHM.A',gui.overview.Names.QM{gui.overview.Selected.Corr},gui.controls.act_x); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.QM.FWHM.metab(1,:,ind)',gui.overview.Names.QM{gui.overview.Selected.Corr},gui.controls.act_x,gui.controls.act_z); end else if gui.overview.Selected.CorrChoice == 2 - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Corr},MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Corr},gui.controls.act_x); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,MRSCont.quantify.names.(split_Selection{1}){1,ind}{gui.overview.Selected.Corr},MRSCont.quantify.names.(split_Selection{1}){1,ind}{gui.overview.Selected.Corr},gui.controls.act_x,gui.controls.act_z); else - temp = osp_plotScatter(MRSCont,split_Selection{1},split_Selection{2},metab,gui.overview.CorrMeas{gui.overview.Selected.Corr},gui.overview.Names.Corr{gui.overview.Selected.Corr},gui.controls.act_x); + temp = osp_plotScatter(MRSCont,split_Selection{2},split_Selection{3},metab,gui.overview.CorrMeas{gui.overview.Selected.Corr},gui.overview.Names.Corr{gui.overview.Selected.Corr},gui.controls.act_x,gui.controls.act_z); end end end @@ -84,7 +89,7 @@ function osp_updatecorrOvWindow(gui) set(gui.Plot.corrOv.Children(3).Title, 'String', ['Voxel ' num2str(gui.controls.act_x) ' ' metab ' vs FHWM (ppm)']) %Update title end else if gui.overview.Selected.CorrChoice == 2 - set(gui.Plot.corrOv.Children(3).Title, 'String', ['Voxel ' num2str(gui.controls.act_x) ' ' MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Corr} ' vs ' metab]) %Update title + set(gui.Plot.corrOv.Children(3).Title, 'String', ['Voxel ' num2str(gui.controls.act_x) ' ' MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}{gui.overview.Selected.Corr} ' vs ' metab]) %Update title else set(gui.Plot.corrOv.Children(3).Title, 'String', ['Voxel ' num2str(gui.controls.act_x) ' ' gui.overview.Names.Corr{gui.overview.Selected.Corr} ' vs ' metab]) %Update title end diff --git a/GUI/osp_updatedistrOvWindow.m b/GUI/osp_updatedistrOvWindow.m index 7a593f08..bbb4726c 100644 --- a/GUI/osp_updatedistrOvWindow.m +++ b/GUI/osp_updatedistrOvWindow.m @@ -26,33 +26,40 @@ function osp_updatedistrOvWindow(gui) MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class delete(gui.Plot.distrOv.Children(3).Children) Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; + selectedOvTab = get(gui.layout.overviewTab,'Selection'); if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) set(gui.controls.distrOvPanel,'Title',['Actual Quantification and Metabolite in Voxel ' num2str(gui.controls.act_x)]); - set(gui.layout.distrOvTab.Children.Children(1).Children(3).Children.Children.Children(4),'String',gui.controls.act_z) - set(gui.layout.distrOvTab.Children.Children(1).Children(3).Children.Children.Children(5),'String',gui.controls.act_y) - set(gui.layout.distrOvTab.Children.Children(1).Children(3).Children.Children.Children(6),'String',gui.controls.act_x) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children.Children(1).Children(3).Children.Children.Children(4),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children.Children(1).Children(3).Children.Children.Children(5),'String',gui.controls.act_y) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children.Children(1).Children(3).Children.Children.Children(6),'String',gui.controls.act_x) + else + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(4),'String',gui.controls.act_x) end %%% 2. VISUALIZATION PART OF THIS TAB %%% if ~strcmp(Selection,'Quality') split_Selection = strsplit(Selection,'-'); - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') metab = 'GABA'; else - metab = MRSCont.quantify.metabs.(split_Selection{1}){gui.overview.Selected.Metab}; + metab = MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}{gui.overview.Selected.Metab}; end if (isfield(MRSCont.flags, 'isPRIAM') || isfield(MRSCont.flags, 'isMRSI')) && (MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) if ~gui.controls.GM - [temp] = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot',0,gui.controls.act_x); + [temp] = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',0,gui.controls.act_x,gui.controls.act_z); else - [temp] = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot',1,gui.controls.act_x); + [temp] = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',1,gui.controls.act_x,gui.controls.act_z); end else if ~gui.controls.GM - [temp] = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot'); + [temp] = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',0,1,gui.controls.act_z); else - [temp] = osp_plotRaincloud(MRSCont,split_Selection{1},split_Selection{2},metab,'Raincloud plot',1); + [temp] = osp_plotRaincloud(MRSCont,split_Selection{2},split_Selection{3},metab,'Raincloud plot',1,1,gui.controls.act_z); end end + set(gui.controls.pop_distrOvMetab, 'String', MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}); + split_Selection{4}=['basis ' num2str(gui.controls.act_z)]; else quality = {'SNR','FWHM','freqShift'}; if ~gui.controls.GM @@ -60,10 +67,14 @@ function osp_updatedistrOvWindow(gui) else [temp] = osp_plotRaincloud(MRSCont,'Quality','Quality',quality{gui.overview.Selected.Metab},'Raincloud plot',1); end - split_Selection{1}=quality{gui.overview.Selected.Metab}; + split_Selection{2}='Quality'; + split_Selection{1}='Spectral'; + split_Selection{3}=quality{gui.overview.Selected.Metab}; + split_Selection{4}=''; metab = ''; + set(gui.controls.pop_distrOvMetab, 'String', quality); end - + set( temp.Children(2).Children, 'Parent', gui.Plot.distrOv.Children(3) ); set( gui.Plot.distrOv.Children(3), 'XLabel', temp.Children(2).XLabel); set( gui.Plot.distrOv.Children(3), 'YLim', temp.Children(2).YLim); @@ -74,6 +85,6 @@ function osp_updatedistrOvWindow(gui) else gui.Plot.distrOv.Children(3).Legend.Location = 'North'; % Update legend end - set(gui.Plot.distrOv.Children(3).Title, 'String', ['Raincloud plot voxel ' num2str(gui.controls.act_x) ' : ' split_Selection{1} ' ' metab]) %Update title + set(gui.Plot.distrOv.Children(3).Title, 'String', ['Raincloud plot voxel ' num2str(gui.controls.act_x) ' : ' split_Selection{1} ' ' split_Selection{2} ' ' split_Selection{3} ' ' split_Selection{4} ' ' metab]) %Update title setappdata(gui.figure,'MRSCont',MRSCont); %Write MRSCont into hidden container in gui class end diff --git a/GUI/osp_updatemeanOvWindow.m b/GUI/osp_updatemeanOvWindow.m index c89701a8..ed679e9e 100644 --- a/GUI/osp_updatemeanOvWindow.m +++ b/GUI/osp_updatemeanOvWindow.m @@ -23,7 +23,10 @@ function osp_updatemeanOvWindow(gui) % HISTORY: % 2020-01-16: First version of the code. %%% 1. INITIALIZE %%% - MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(1).Children(3).Children(1).Children(1).Children(4),'String',gui.controls.act_x) delete(gui.Plot.meanOv.Children(2).Children) %%% 2. VISUALIZATION PART OF THIS TAB %%% Selection = gui.controls.pop_meanOvPlot.String(gui.process.Selected); @@ -44,14 +47,22 @@ function osp_updatemeanOvWindow(gui) end else if ~(isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM) - temp = osp_plotMeanSpec(MRSCont, Selection{1},'GMean', 1); + temp = osp_plotMeanSpec(MRSCont, Selection{1},'GMean', 1,0,'Frequency (ppm)','','',gui.controls.act_z); else - temp = osp_plotMeanSpec(MRSCont, Selection{1},1, 0.01,10); + temp = osp_plotMeanSpec(MRSCont, Selection{1},1, 0.01,10,'Frequency (ppm)','','',gui.controls.act_z); end ViewAxes = gca(); set(ViewAxes.Children,'Parent',gui.Plot.meanOv.Children(2)) end - if (strcmp(Selection{1},'A') || strcmp(Selection{1},'B') || strcmp(Selection{1},'C') || strcmp(Selection{1},'D') || strcmp(Selection{1},'diff1') || strcmp(Selection{1},'diff2') || strcmp(Selection{1},'sum')) + + which_spec_split = split(Selection{1}); + if length(which_spec_split) == 3 + spec = which_spec_split{2}; + else + spec = which_spec_split{1}; + end + + if (strcmp(spec,'metab') || strcmp(spec,'mm')) set(gui.Plot.meanOv.Children(2), 'XLim', ViewAxes.XLim) set(gui.Plot.meanOv.Children(2), 'XMinorTick', 'On') set(gui.Plot.meanOv.Children(2).Title, 'String', ViewAxes.Title.String) diff --git a/GUI/osp_updatequantOvWindow.m b/GUI/osp_updatequantOvWindow.m index 31d02faf..07172dda 100644 --- a/GUI/osp_updatequantOvWindow.m +++ b/GUI/osp_updatequantOvWindow.m @@ -25,32 +25,37 @@ function osp_updatequantOvWindow(gui) %%% 1. INITIALIZE %%% MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class Selection = gui.quant.popMenuNames{gui.quant.Selected.Quant}; + selectedOvTab = get(gui.layout.overviewTab,'Selection'); + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(2).Children(2).Children(1).Children(1).Children(3),'String',gui.controls.act_z) + set(gui.layout.(gui.layout.overviewTabhandels{selectedOvTab}).Children(1).Children(2).Children(2).Children(1).Children(1).Children(4),'String',gui.controls.act_x) + if ~strcmp(Selection,'Quality') split_Selection = strsplit(Selection,'-'); + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(split_Selection{1})(1,:),split_Selection{2})); %This function updates the quantification table overview tab - if strcmp(split_Selection{2},'AlphaCorrWaterScaled') || strcmp(split_Selection{2},'AlphaCorrWaterScaledGroupNormed') + if strcmp(split_Selection{3},'AlphaCorrWaterScaled') || strcmp(split_Selection{3},'AlphaCorrWaterScaledGroupNormed') if isfield(MRSCont,'exclude') && ~isempty(MRSCont.exclude) exclude = length(MRSCont.exclude); else exclude = 0; end if ~strcmp(MRSCont.opts.fit.coMM3, 'none') - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,2); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,2); QuantTextOv(1,:) = {'GABA','GABA+'}; else - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,1); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,1); QuantTextOv(1,:) = {'GABA'}; end - QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(split_Selection{1}).(split_Selection{2}).Voxel_1(:,:)); + QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(split_Selection{1}).(split_Selection{3}).Voxel_1{gui.controls.act_z,ind}(:,:)); else if isfield(MRSCont,'exclude') && ~isempty(MRSCont.exclude) exclude = length(MRSCont.exclude); else exclude = 0; end - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,length(MRSCont.quantify.metabs.(split_Selection{1}))); - QuantTextOv(1,:) = MRSCont.quantify.metabs.(split_Selection{1}); - QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(split_Selection{1}).(split_Selection{2}).Voxel_1(:,:)); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,length(MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind})); + QuantTextOv(1,:) = MRSCont.quantify.names.(split_Selection{1}){gui.controls.act_z,ind}; + QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(split_Selection{1}).(split_Selection{3}).Voxel_1{gui.controls.act_z,ind}(:,:)); end else if isfield(MRSCont,'exclude') && ~isempty(MRSCont.exclude) @@ -58,7 +63,7 @@ function osp_updatequantOvWindow(gui) else exclude = 0; end - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,length(MRSCont.QM.tables.Properties.VariableNames)); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,length(MRSCont.QM.tables.Properties.VariableNames)); QuantTextOv(1,:) = MRSCont.QM.tables.Properties.VariableNames; QuantTextOv(2:end,:) = table2cell(MRSCont.QM.tables(:,:)); end @@ -93,10 +98,10 @@ function osp_updatequantOvWindow(gui) exclude = 0; end if ~strcmp(MRSCont.opts.fit.coMM3, 'none') - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,2); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,2); QuantTextOv(1,:) = {'GABA','GABA+'}; else - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,1); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,1); QuantTextOv(1,:) = {'GABA'}; end QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(split_Selection{1}).(split_Selection{2}).Voxel_2(:,:)); @@ -106,7 +111,7 @@ function osp_updatequantOvWindow(gui) else exclude = 0; end - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,length(MRSCont.quantify.metabs.(split_Selection{1}))); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,length(MRSCont.quantify.metabs.(split_Selection{1}))); QuantTextOv(1,:) = MRSCont.quantify.metabs.(split_Selection{1}); QuantTextOv(2:end,:) = table2cell(MRSCont.quantify.tables.(split_Selection{1}).(split_Selection{2}).Voxel_2(:,:)); end @@ -116,7 +121,7 @@ function osp_updatequantOvWindow(gui) else exclude = 0; end - QuantTextOv = cell(MRSCont.nDatasets+1-exclude,length(MRSCont.QM.tables.Properties.VariableNames)); + QuantTextOv = cell(MRSCont.nDatasets(1)+1-exclude,length(MRSCont.QM.tables.Properties.VariableNames)); QuantTextOv(1,:) = MRSCont.QM.tables.Properties.VariableNames; QuantTextOv(2:end,:) = table2cell(MRSCont.QM.tables(:,:)); end diff --git a/GUI/upper_navigate_box.m b/GUI/upper_navigate_box.m new file mode 100644 index 00000000..86fdb79a --- /dev/null +++ b/GUI/upper_navigate_box.m @@ -0,0 +1,116 @@ +function gui = upper_navigate_box(gui, name,Selection,Overview) + MRSCont = getappdata(gui.figure,'MRSCont'); % Get MRSCont from hidden container in gui class + + gui.upperBox.(name).upperLeftButtons = uix.Panel('Parent', gui.upperBox.(name).box, ... + 'Padding', 5, 'Title', ['Navigate model'],... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground,... + 'HighlightColor', gui.colormap.Foreground, 'ShadowColor', gui.colormap.Foreground); + gui.controls.Buttonbox = uix.HBox('Parent',gui.upperBox.(name).upperLeftButtons, 'BackgroundColor',gui.colormap.Background); + gui.controls.navigate_RawTab = uix.Grid('Parent',gui.controls.Buttonbox,'BackgroundColor',gui.colormap.Background); + + gui.controls.text_x = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Exp',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + if ~Overview + gui.controls.text_y = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Spec',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + end + gui.controls.text_z = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','Basis',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + gui.controls.b_left_x = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + if ~Overview + gui.controls.b_left_y = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + end + gui.controls.b_left_z = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','<'); + set(gui.controls.b_left_x,'Callback',{@osp_onLeftX,gui}); + if ~Overview + set(gui.controls.b_left_y,'Callback',{@osp_onLeftY,gui}); + end + set(gui.controls.b_left_z,'Callback',{@osp_onLeftZ,gui}); + + + gui.controls.text_act_x = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + if ~Overview + gui.controls.text_act_y = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + end + gui.controls.text_act_z = uicontrol(gui.controls.navigate_RawTab,'Style','text','String','1',... + 'FontName', gui.font, 'BackgroundColor',gui.colormap.Background,'ForegroundColor', gui.colormap.Foreground); + + gui.controls.b_right_x = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + if ~Overview + gui.controls.b_right_y = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + end + gui.controls.b_right_z = uicontrol(gui.controls.navigate_RawTab,'Style','PushButton', 'BackgroundColor',gui.colormap.Background,'String','>'); + set(gui.controls.b_right_x,'Callback',{@osp_onRightX,gui}); + if ~Overview + set(gui.controls.b_right_y,'Callback',{@osp_onRightY,gui}); + end + set(gui.controls.b_right_z,'Callback',{@osp_onRightZ,gui}); + + gui.controls.b_left_x.Enable = 'off'; + if ~Overview + gui.controls.b_left_y.Enable = 'off'; + end + gui.controls.b_left_z.Enable = 'off'; + gui.controls.b_right_x.Enable = 'off'; + if ~Overview + gui.controls.b_right_y.Enable = 'off'; + end + gui.controls.b_right_z.Enable = 'off'; + + if ~Overview + buttonString = [num2str(MRSCont.nDatasets(2) > 1) num2str(size(MRSCont.fit.results.(Selection).fitParams,3)>1) num2str(size(MRSCont.fit.results.(Selection).fitParams,1)>1)]; + switch buttonString + case '001' + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '010' + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + case '100' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + case '011' + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '101' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '110' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + case '111' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_left_y.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_right_y.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end + set( gui.controls.navigate_RawTab, 'Widths', [-20 -30 -20 -30], 'Heights', [-33 -33 -33]); + else + buttonString = [num2str(MRSCont.nDatasets(2) > 1) num2str(size(MRSCont.fit.results.(Selection).fitParams,1)>1)]; + switch buttonString + case '01' + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + case '10' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + case '11' + gui.controls.b_left_x.Enable = 'on'; + gui.controls.b_right_x.Enable = 'on'; + gui.controls.b_left_z.Enable = 'on'; + gui.controls.b_right_z.Enable = 'on'; + end + set( gui.controls.navigate_RawTab, 'Widths', [-20 -30 -20 -30], 'Heights', [-50 -50]); + end + +end \ No newline at end of file diff --git a/ci/Osprey_Plot_GUI_test.m b/ci/Osprey_Plot_GUI_test.m index c687dc40..15034736 100644 --- a/ci/Osprey_Plot_GUI_test.m +++ b/ci/Osprey_Plot_GUI_test.m @@ -42,110 +42,128 @@ function testOspreyGUI(~) delete( gui.figure ); %Test loading and plots - osp_plotModule(MRSCont, 'OspreyLoad', 1, 'mets'); + osp_plotModule(MRSCont, 'OspreyLoad', 1, [1 1], 'metabolites'); if MRSCont.flags.hasRef - osp_plotModule(MRSCont, 'OspreyLoad', 1, 'ref'); + osp_plotModule(MRSCont, 'OspreyLoad',1, [1 1], 'ref'); end if MRSCont.flags.hasWater - osp_plotModule(MRSCont, 'OspreyLoad', 1, 'w'); + osp_plotModule(MRSCont, 'OspreyLoad', 1, [1 1], 'w'); end if MRSCont.flags.hasMM - osp_plotModule(MRSCont, 'OspreyLoad', 1, 'mm'); + osp_plotModule(MRSCont, 'OspreyLoad', 1, [1 1], 'MM'); end %Test process and plots Names = fieldnames(MRSCont.processed); - for ss = 1 : length(Names) - osp_plotModule(MRSCont, 'OspreyProcess', 1, Names{ss}); + for mm = 1 : length(Names) + for ss = 1 : length(MRSCont.processed.(Names{mm}){1}.names) + if (~contains(MRSCont.processed.(Names{mm}){1}.names{ss},'spline')) && (~contains(MRSCont.processed.(Names{mm}){1}.names{ss},'clean')) + osp_plotModule(MRSCont, 'OspreyProcess', 1,[1 ss], Names{mm}); + end + end end %Test fit and plots - if strcmp(MRSCont.opts.fit.style, 'Concatenated') - temp = fieldnames(MRSCont.fit.results); - if MRSCont.flags.isUnEdited - Names = fieldnames(MRSCont.fit.results); - end - if MRSCont.flags.isMEGA - Names = {'diff1','sum'}; - if length(temp) == 2 - Names{3} = temp{2}; - else if length(temp) == 3 - Names{3} = temp{2}; - Names{4} = temp{3}; - end - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - Names = {'diff1','diff2','sum'}; - if length(temp) == 2 - Names{4} = temp{2}; - else if length(temp) == 3 - Names{4} = temp{2}; - Names{5} = temp{3}; + Names = {'metab'}; + if MRSCont.flags.hasMM + Names{end+1} = 'mm'; + end + if MRSCont.flags.hasRef + Names{end+1} = 'ref'; + end + if MRSCont.flags.hasWater + Names{end+1} = 'w'; + end + + for mm = 1 : length(Names) + if isfield(MRSCont.fit.results,Names{mm}) + for bb = 1 : size(MRSCont.fit.results.(Names{mm}).fitParams,1) + for ss = 1 : size(MRSCont.fit.results.(Names{mm}).fitParams,3) + osp_plotModule(MRSCont, 'OspreyFit', 1,[bb ss], Names{mm}); end end end - else - Names = fieldnames(MRSCont.fit.results); - end - for ss = 1 : length(Names) - osp_plotModule(MRSCont, 'OspreyFit', 1, Names{ss}); - end + end osp_plotModule(MRSCont, 'OspreyCoreg', 1); + SubNames = fieldnames(MRSCont.overview.SubSpecNamesStruct); + k=1; + if ~isempty(SubNames) + for i = 1 : length(SubNames) + for j = 1 :size(MRSCont.overview.SubSpecNamesStruct.(SubNames{i}),2) + tempSubNames{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + k=k+1; + end + end + end - - Names = fieldnames(MRSCont.processed); + FitNames = fieldnames(MRSCont.overview.FitSpecNamesStruct); + k=1; + if ~isempty(FitNames) + for i = 1 : length(FitNames) + for j = 1 :size(MRSCont.overview.FitSpecNamesStruct.(FitNames{i}),2) + tempFitNames{k} = ['Model ', FitNames{i}, ' ', MRSCont.overview.FitSpecNamesStruct.(FitNames{i}){1,j}]; + k=k+1; + end + end + end + Names = [tempSubNames';tempFitNames']; for ss = 1 : length(Names) - osp_plotModule(MRSCont, 'OspreySpecOverview', 1, Names{ss}); - osp_plotModule(MRSCont, 'OspreyMeanOverview', 1, Names{ss}); + osp_plotModule(MRSCont, 'OspreySpecOverview', 1,1, Names{ss}); end - + + SubNames = fieldnames(MRSCont.overview.SubSpecNamesStruct); + k=1; + if ~isempty(SubNames) + for i = 1 : length(SubNames) + for j = 1 :size(MRSCont.overview.SubSpecNamesStruct.(SubNames{i}),2) + if ~isempty(find(strcmp(FitNames,SubNames{i}))) + if (~isempty(find(strcmp(MRSCont.overview.FitSpecNamesStruct.(SubNames{i}),MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j})))) + Names{k} = ['Model ' , SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + else + Names{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + end + else + Names{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + end + k=k+1; + end + end + end + for ss = 1 : length(Names) + osp_plotModule(MRSCont, 'OspreyMeanOverview', 1,1, Names{ss}); + end + if MRSCont.flags.isUnEdited - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'tNAA'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'tCho'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'Ins'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'Glx'); - - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tNAA', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tCho', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Ins', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Glx', 'SNR'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'tNAA'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'tCho'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'Ins'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'Glx'); + + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tNAA', 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tCho', 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Ins', 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Glx', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tNAA', 'FWHM'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tCho', 'FWHM'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Ins', 'FWHM'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Glx', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tNAA', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tCho', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Ins', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Glx', 'FWHM'); end if MRSCont.flags.isMEGA - if ~strcmp(MRSCont.opts.fit.style, 'Concatenated') - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - else - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - end + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); end if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - if ~strcmp(MRSCont.opts.fit.style, 'Concatenated') - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{2}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{2}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{2}, 'FWHM'); - else - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{2}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{2}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{2}, 'FWHM'); - end - end + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{2}); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{2}, 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{2}, 'FWHM'); + end end \ No newline at end of file diff --git a/coreg/OspreyCoreg.m b/coreg/OspreyCoreg.m index 5ed3f41e..6f750352 100755 --- a/coreg/OspreyCoreg.m +++ b/coreg/OspreyCoreg.m @@ -53,8 +53,8 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyCoreg',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +for kk = 1:MRSCont.nDatasets(1) + [~] = printLog('OspreyCoreg',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); if ~(MRSCont.flags.didCoreg == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'coreg') && (kk > length(MRSCont.coreg.vol_image))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) % Get the input file name @@ -168,7 +168,7 @@ end end time = toc(refCoregTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.Coreg = time; %% Clean up and save % Set exit flags and version diff --git a/exampledata/ima/jobIMA.m b/exampledata/ima/jobIMA.m index 0761a024..dbdb6423 100644 --- a/exampledata/ima/jobIMA.m +++ b/exampledata/ima/jobIMA.m @@ -98,10 +98,27 @@ % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array % Save LCModel-exportable files for each spectrum? opts.saveLCM = 1; % OPTIONS: - 0 (no, default) @@ -164,7 +181,11 @@ % - {'fixedGauss'} % - {'none'} -opts.fit.FWHMcoMM3 = 14; +opts.fit.FWHMcoMM3 = 14; + +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/exampledata/nifti-mrs/jobNIfTIMRS.m b/exampledata/nifti-mrs/jobNIfTIMRS.m index 832a49d1..eaed2c77 100644 --- a/exampledata/nifti-mrs/jobNIfTIMRS.m +++ b/exampledata/nifti-mrs/jobNIfTIMRS.m @@ -98,10 +98,27 @@ % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array % Save LCModel-exportable files for each spectrum? opts.saveLCM = 1; % OPTIONS: - 0 (no, default) @@ -153,6 +170,9 @@ opts.fit.fitMM = 1; % OPTIONS: - 0 (no) % - 1 (yes, default) +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/exampledata/nifti-mrs/sub-02/ses-01/mrs/sub-02_ses-01_SVS-ref.nii.gz b/exampledata/nifti-mrs/sub-02/ses-01/mrs/sub-02_ses-01_SVS-ref.nii.gz new file mode 100644 index 00000000..749a1dd1 Binary files /dev/null and b/exampledata/nifti-mrs/sub-02/ses-01/mrs/sub-02_ses-01_SVS-ref.nii.gz differ diff --git a/exampledata/nifti-mrs/sub-02/ses-01/mrs/sub-02_ses-01_SVS.nii.gz b/exampledata/nifti-mrs/sub-02/ses-01/mrs/sub-02_ses-01_SVS.nii.gz new file mode 100644 index 00000000..f0630634 Binary files /dev/null and b/exampledata/nifti-mrs/sub-02/ses-01/mrs/sub-02_ses-01_SVS.nii.gz differ diff --git a/exampledata/p/jobP.m b/exampledata/p/jobP.m index 4e5723ad..64790e60 100644 --- a/exampledata/p/jobP.m +++ b/exampledata/p/jobP.m @@ -97,11 +97,27 @@ % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' - +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array % Save LCModel-exportable files for each spectrum? opts.saveLCM = 1; % OPTIONS: - 0 (no, default) % - 1 (yes) @@ -153,6 +169,9 @@ opts.fit.fitMM = 1; % OPTIONS: - 0 (no) % - 1 (yes, default) +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/exampledata/rda/jobRDA.m b/exampledata/rda/jobRDA.m index f5d6bd23..eecc4e63 100644 --- a/exampledata/rda/jobRDA.m +++ b/exampledata/rda/jobRDA.m @@ -98,10 +98,27 @@ % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array % Save processed spectra in vendor-specific format (SDAT/SPAR, RDA, P)? opts.saveVendor = 0; % OPTIONS: - 0 (no, default) @@ -154,6 +171,9 @@ opts.fit.fitMM = 1; % OPTIONS: - 0 (no) % - 1 (yes, default) +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/exampledata/sdat/MEGA/jobSDAT_MEGA.m b/exampledata/sdat/MEGA/jobSDAT_MEGA.m index 5ff47b19..3b75458e 100644 --- a/exampledata/sdat/MEGA/jobSDAT_MEGA.m +++ b/exampledata/sdat/MEGA/jobSDAT_MEGA.m @@ -4,7 +4,7 @@ % A valid Osprey job contains four distinct classes of items: % 1. basic information on the MRS sequence used % 2. several settings for data handling and modeling -% 3. a list of MRS (and, optionally, structural imaging) data files +% 3. a list of MRS (and, optionally, structural imaging) data files % to be loaded % 4. an output folder to store the results and exported files % @@ -29,7 +29,7 @@ % Defined in cell array "files_w" % - Structural image data used for co-registration and tissue class % segmentation (usually a T1 MPRAGE). These files need to be -% provided in the NIfTI format (*.nii) or, for GE data, as a +% provided in the NIfTI format (*.nii) or, for GE data, as a % folder containing DICOM Files (*.dcm). % (OPTIONAL) % Defined in cell array "files_nii" @@ -57,7 +57,7 @@ % AUTHOR: % Dr. Georg Oeltzschner (Johns Hopkins University, 2019-07-15) % goeltzs1@jhmi.edu -% +% % HISTORY: % 2019-07-15: First version of the code. @@ -71,7 +71,7 @@ % - 'MEGA' % - 'HERMES' % - 'HERCULES' - + % Specify editing targets editTarget = {'GABA'}; % OPTIONS: - {'none'} (default if 'unedited') % - {'GABA'}, {'GSH'}, {'Lac'}, {'PE322'}, {'PE398'} (for 'MEGA') @@ -79,9 +79,9 @@ % Specify data scenario dataScenario = 'invivo'; % OPTIONS: - 'invivo' (default) - % - 'phantom' - % - 'PRIAM' - % - 'MRSI' + % - 'phantom' + % - 'PRIAM' + % - 'MRSI' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -90,37 +90,54 @@ %%% 2. SPECIFY DATA HANDLING AND MODELING OPTIONS %%% % Which spectral registration method should be used? Robust spectral % registration is default, a frequency restricted spectral registration -% method is also availaible and is linked to the fit range. +% method is also availaible and is linked to the fit range. opts.SpecReg = 'RobSpecReg'; % OPTIONS: - 'RobSpecReg' (default) Spectral aligment with Water/Lipid removal, using simialrity meric, and weighted averaging % - 'ProbSpecReg' Probabilistic spectral aligment to median target and weighted averaging % - 'RestrSpecReg' Frequency restricted (fit range) spectral aligment, using simialrity meric, and weighted averaging % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' - +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array + % Save LCModel-exportable files for each spectrum? opts.saveLCM = 0; % OPTIONS: - 0 (no, default) % - 1 (yes) % Save jMRUI-exportable files for each spectrum? opts.savejMRUI = 0; % OPTIONS: - 0 (no, default) % - 1 (yes) - + % Save processed spectra in vendor-specific format (SDAT/SPAR, RDA, P)? opts.saveVendor = 0; % OPTIONS: - 0 (no, default) % - 1 (yes) - + % Save processed spectra in NIfTI-MRS format? opts.saveNII = 0; % OPTIONS: - 0 (no, default) % - 1 (yes) - + % Save PDF output for all Osprey modules and subjects? opts.savePDF = 0; % OPTIONS: - 0 (no, default) - % - 1 (yes) - + % - 1 (yes) + % Choose the fitting algorithm opts.fit.method = 'Osprey'; % OPTIONS: - 'Osprey' (default) @@ -134,8 +151,8 @@ % except for Ala, bHB, bHG, Cit, EtOH, Glc, Gly, Phenyl, Ser, and Tyros. opts.fit.includeMetabs = {'default'}; % OPTIONS: - {'default'} % - {'full'} - % - {custom} - + % - {custom} + % Choose the fitting style for difference-edited datasets (MEGA, HERMES, HERCULES) % (only available for the Osprey fitting method) opts.fit.style = 'Separate'; % OPTIONS: - 'Concatenated' (default) - will fit DIFF and SUM simultaneously) @@ -144,24 +161,30 @@ % Determine fitting range (in ppm) for the metabolite and water spectra opts.fit.range = [0.5 4]; % [ppm] Default: [0.2 4.2] opts.fit.rangeWater = [2.0 7.4]; % [ppm] Default: [2.0 7.4] +opts.fit.GAP.A = []; +opts.fit.GAP.diff1 = []; % Determine the baseline knot spacing (in ppm) for the metabolite spectra -opts.fit.bLineKnotSpace = 0.4; % [ppm] Default: 0.4. +opts.fit.bLineKnotSpace = 0.55; % [ppm] Default: 0.4. -% Add macromolecule and lipid basis functions to the fit? +% Add macromolecule and lipid basis functions to the fit? opts.fit.fitMM = 1; % OPTIONS: - 0 (no) % - 1 (yes, default) -% How do you want to model the co-edited macromolecules at 3 ppm for GABA-edited MRS? -opts.fit.coMM3 = '3to2MM'; % OPTIONS: - {'3to2MM'} (default) +% How do you want to model the co-edited macromolecules at 3 ppm for GABA-edited MRS? +opts.fit.coMM3 = 'freeGauss'; % OPTIONS: - {'3to2MM'} (default) % - {'3to2MMsoft'} - % - {'1to1GABA'} - % - {'1to1GABAsoft'} - % - {'freeGauss'} + % - {'1to1GABA'} + % - {'1to1GABAsoft'} + % - {'freeGauss'} % - {'fixedGauss'} - % - {'none'} + % - {'none'} -opts.fit.FWHMcoMM3 = 14; +opts.fit.FWHMcoMM3 = 14; + +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -179,7 +202,7 @@ % up the jobFile for your own data you can set a direct path to your data % folder e.g., data_folder = /Volumes/MyProject/data/' -data_folder = fileparts(which('exampledata/sdat/MEGA/jobSDAT_MEGA.m')); +data_folder = fileparts(which('exampledata/sdat/MEGA/jobSDAT_MEGA.m')); % The following lines perform an automated set-up of the jobFile which % takes advatage of the BIDS foramt. If you are not using BIDS (highly @@ -199,19 +222,19 @@ sess = sess([sess.isdir]); sess = sess(contains({sess.name},'ses')); for ll = 1:length(sess) - + % Specify metabolite data % (MANDATORY) dir_metabolite = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_megapress' filesep '*.SDAT']); files(counter) = {[dir_metabolite(end).folder filesep dir_metabolite(end).name]}; - + % Specify water reference data for eddy-current correction (same sequence as metabolite data!) % (OPTIONAL) % Leave empty for GE P-files (.7) - these include water reference data by % default. dir_ref = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_megapress-ref' filesep '*.SDAT']); files_ref(counter) = {[dir_ref(end).folder filesep dir_ref(end).name]}; - + % Specify water data for quantification (e.g. short-TE water scan) % (OPTIONAL) dir_w = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_press-ref' filesep '*.SDAT']); @@ -219,13 +242,13 @@ % Specify metabolite-nulled data for quantification % (OPTIONAL) - files_mm = {}; - + files_mm = {}; + % Specify T1-weighted structural imaging data % (OPTIONAL) % Link to single NIfTI (*.nii) files for Siemens and Philips data % Link to DICOM (*.dcm) folders for GE data - files_nii(counter) = {[sess(ll).folder filesep sess(ll).name filesep 'anat' filesep subs(kk).name filesep sess(ll).name '_T1w.nii.gz']}; + files_nii(counter) = {[sess(ll).folder filesep sess(ll).name filesep 'anat' filesep subs(kk).name filesep sess(ll).name '_T1w.nii.gz']}; counter = counter + 1; end end @@ -254,13 +277,13 @@ % Specify metabolite-nulled data for quantification % (OPTIONAL) -% files_mm = {}; +% files_mm = {}; % Specify T1-weighted structural imaging data % (OPTIONAL) % Link to single NIfTI (*.nii.gz or #.nii) files for GE, Siemens and Philips data % files_nii = {'/Volumes/MyProject/data/sub-01/anat/T1w.nii.gz',... -% '/Volumes/MyProject/data/sub-02/anat/T1w.nii.gz'}; +% '/Volumes/MyProject/data/sub-02/anat/T1w.nii.gz'}; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -280,4 +303,4 @@ % Specify output folder (you can always use the direct path) % (MANDATORY) -outputFolder = fullfile(data_folder, 'derivatives'); \ No newline at end of file +outputFolder = fullfile(data_folder, 'derivatives'); diff --git a/exampledata/sdat/MEGA/jobSDAT_MEGA_Multidataset.m b/exampledata/sdat/MEGA/jobSDAT_MEGA_Multidataset.m new file mode 100644 index 00000000..cb3bf87f --- /dev/null +++ b/exampledata/sdat/MEGA/jobSDAT_MEGA_Multidataset.m @@ -0,0 +1,315 @@ +%% jobSDAT.m +% This function describes an Osprey job defined in a MATLAB script. +% +% A valid Osprey job contains four distinct classes of items: +% 1. basic information on the MRS sequence used +% 2. several settings for data handling and modeling +% 3. a list of MRS (and, optionally, structural imaging) data files +% to be loaded +% 4. an output folder to store the results and exported files +% +% The list of MRS and structural imaging files is provided in the form of +% cell arrays. They can simply be provided explicitly, or from a more +% complex script that automatically determines file names from a given +% folder structure. +% +% Osprey distinguishes between four sets of data: +% - metabolite (water-suppressed) data +% (MANDATORY) +% Defined in cell array "files" +% - water reference data acquired with the SAME sequence as the +% metabolite data, just without water suppression RF pulses. This +% data is used to determine complex coil combination +% coefficients, and perform eddy current correction. +% (OPTIONAL) +% Defined in cell array "files_ref" +% - additional water data used for water-scaled quantification, +% usually from short-TE acquisitions due to reduced T2-weighting +% (OPTIONAL) +% Defined in cell array "files_w" +% - Structural image data used for co-registration and tissue class +% segmentation (usually a T1 MPRAGE). These files need to be +% provided in the NIfTI format (*.nii) or, for GE data, as a +% folder containing DICOM Files (*.dcm). +% (OPTIONAL) +% Defined in cell array "files_nii" +% +% Files in the formats +% - .7 (GE) +% - .SDAT, .DATA/.LIST, .RAW/.SIN/.LAB (Philips) +% - .DAT (Siemens) +% usually contain all of the acquired data in a single file per scan. GE +% systems store water reference data in the same .7 file, so there is no +% need to specify it separately under files_ref. +% +% Files in the formats +% - .DCM (any) +% - .IMA, .RDA (Siemens) +% may contain separate files for each average. Instead of providing +% individual file names, please specify folders. Metabolite data, water +% reference data, and water data need to be located in separate folders. +% +% In the example script at hand the MATLAB functions strrep and which are +% used to generate a relative path, which allows you to run the examples +% on your machine directly. To set up your own Osprey job supply the +% specific locations as described above. +% +% AUTHOR: +% Dr. Georg Oeltzschner (Johns Hopkins University, 2019-07-15) +% goeltzs1@jhmi.edu +% +% HISTORY: +% 2019-07-15: First version of the code. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% 1. SPECIFY SEQUENCE INFORMATION %%% + +% Specify sequence type +seqType = 'MEGA'; % OPTIONS: - 'unedited' (default) + % - 'MEGA' + % - 'HERMES' + % - 'HERCULES' + +% Specify editing targets +editTarget = {'GABA'}; % OPTIONS: - {'none'} (default if 'unedited') + % - {'GABA'}, {'GSH'}, {'Lac'}, {'PE322'}, {'PE398'} (for 'MEGA') + % - {'GABA', 'GSH'}, {'GABA', 'Lac'}, {'NAA', 'NAAG'} (for 'HERMES'and 'HERCULES') + + % Specify data scenario +dataScenario = 'invivo'; % OPTIONS: - 'invivo' (default) + % - 'phantom' + % - 'PRIAM' + % - 'MRSI' +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% 2. SPECIFY DATA HANDLING AND MODELING OPTIONS %%% +% Which spectral registration method should be used? Robust spectral +% registration is default, a frequency restricted spectral registration +% method is also availaible and is linked to the fit range. +opts.SpecReg = 'RobSpecReg'; % OPTIONS: - 'RobSpecReg' (default) Spectral aligment with Water/Lipid removal, using simialrity meric, and weighted averaging + % - 'ProbSpecReg' Probabilistic spectral aligment to median target and weighted averaging + % - 'RestrSpecReg' Frequency restricted (fit range) spectral aligment, using simialrity meric, and weighted averaging + % - 'none' + +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array + +% Save LCModel-exportable files for each spectrum? +opts.saveLCM = 0; % OPTIONS: - 0 (no, default) + % - 1 (yes) +% Save jMRUI-exportable files for each spectrum? +opts.savejMRUI = 0; % OPTIONS: - 0 (no, default) + % - 1 (yes) + +% Save processed spectra in vendor-specific format (SDAT/SPAR, RDA, P)? +opts.saveVendor = 0; % OPTIONS: - 0 (no, default) + % - 1 (yes) + +% Save processed spectra in NIfTI-MRS format? +opts.saveNII = 0; % OPTIONS: - 0 (no, default) + % - 1 (yes) + +% Save PDF output for all Osprey modules and subjects? +opts.savePDF = 0; % OPTIONS: - 0 (no, default) + % - 1 (yes) + +% Choose the fitting algorithm +opts.fit.method = 'Osprey'; % OPTIONS: - 'Osprey' (default) + +% Select the metabolites to be included in the basis set as a cell array, +% with entries separates by commas. +% With default Osprey basis sets, you can select the following metabolites: +% Ala, Asc, Asp, bHB, bHG, Cit, Cr, CrCH2, EtOH, GABA, GPC, GSH, Glc, Gln, +% Glu, Gly, H2O, Ins, Lac, NAA, NAAG, PCh, PCr, PE, Phenyl, Scyllo, Ser, +% Tau, Tyros, MM09, MM12, MM14, MM17, MM20, Lip09, Lip13, Lip20. +% If you enter 'default', the basis set will include all of the above +% except for Ala, bHB, bHG, Cit, EtOH, Glc, Gly, Phenyl, Ser, and Tyros. +opts.fit.includeMetabs = {'default'}; % OPTIONS: - {'default'} + % - {'full'} + % - {custom} + +% Choose the fitting style for difference-edited datasets (MEGA, HERMES, HERCULES) +% (only available for the Osprey fitting method) +opts.fit.style = 'Separate'; % OPTIONS: - 'Concatenated' (default) - will fit DIFF and SUM simultaneously) + % - 'Separate' - will fit DIFF and OFF separately + +% Determine fitting range (in ppm) for the metabolite and water spectra +opts.fit.range = [0.5 4]; % [ppm] Default: [0.2 4.2] +opts.fit.rangeWater = [2.0 7.4]; % [ppm] Default: [2.0 7.4] +opts.fit.GAP.A = []; +opts.fit.GAP.diff1 = []; + +% Determine the baseline knot spacing (in ppm) for the metabolite spectra +opts.fit.bLineKnotSpace = 0.55; % [ppm] Default: 0.4. + +% Add macromolecule and lipid basis functions to the fit? +opts.fit.fitMM = 1; % OPTIONS: - 0 (no) + % - 1 (yes, default) + +% How do you want to model the co-edited macromolecules at 3 ppm for GABA-edited MRS? +opts.fit.coMM3 = 'freeGauss'; % OPTIONS: - {'3to2MM'} (default) + % - {'3to2MMsoft'} + % - {'1to1GABA'} + % - {'1to1GABAsoft'} + % - {'freeGauss'} + % - {'fixedGauss'} + % - {'none'} + +opts.fit.FWHMcoMM3 = 14; + +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% 3. SPECIFY MRS DATA AND STRUCTURAL IMAGING FILES %% +% When using single-average Siemens RDA or DICOM files, specify their +% folders instead of single files! + +% Clear existing files +clear files files_ref files_w files_nii files_mm + +% Data folder in BIDS format +% The filparts(which()) comment is needed to find the data on your machine. If you set +% up the jobFile for your own data you can set a direct path to your data +% folder e.g., data_folder = /Volumes/MyProject/data/' + +data_folder = fileparts(which('exampledata/sdat/MEGA/jobSDAT_MEGA.m')); + +% The following lines perform an automated set-up of the jobFile which +% takes advatage of the BIDS foramt. If you are not using BIDS (highly +% recommended) you can look at the definitions below the loop to see how to +% set up direct path links to your data. + +subs = dir(data_folder); +subs(1:2) = []; +subs = subs([subs.isdir]); +subs = subs(contains({subs.name},'sub')); +counter = 1; + +for kk = 1:length(subs) + % Loop over sessions + sess = dir([subs(kk).folder filesep subs(kk).name]); + sess(1:2) = []; + sess = sess([sess.isdir]); + sess = sess(contains({sess.name},'ses')); + for ll = 1:length(sess) + + % Specify metabolite data + % (MANDATORY) + % This is a multiple scans per subject example where we duplicate + % the scan entries from the example data. These can then be + % averaged using the osp_AverageAllDatasetsAlongExtra function + dir_metabolite = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_megapress' filesep '*.SDAT']); + files(counter) = {{[dir_metabolite(end).folder filesep dir_metabolite(end).name], [dir_metabolite(end).folder filesep dir_metabolite(end).name]}}; + + % Specify water reference data for eddy-current correction (same sequence as metabolite data!) + % (OPTIONAL) + % Leave empty for GE P-files (.7) - these include water reference data by + % default. + dir_ref = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_megapress-ref' filesep '*.SDAT']); + files_ref(counter) = {{[dir_ref(end).folder filesep dir_ref(end).name], [dir_ref(end).folder filesep dir_ref(end).name]}}; + + % Specify water data for quantification (e.g. short-TE water scan) + % (OPTIONAL) + dir_w = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_press-ref' filesep '*.SDAT']); + files_w(counter) = {[dir_w(end).folder filesep dir_w(end).name]}; + + % Specify metabolite-nulled data for quantification + % (OPTIONAL) + files_mm = {}; + + % Specify T1-weighted structural imaging data + % (OPTIONAL) + % Link to single NIfTI (*.nii) files for Siemens and Philips data + % Link to DICOM (*.dcm) folders for GE data + files_nii(counter) = {[sess(ll).folder filesep sess(ll).name filesep 'anat' filesep subs(kk).name filesep sess(ll).name '_T1w.nii.gz']}; + counter = counter + 1; + end +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Definitions without using BIDS + +% You can always supply direct path to each of the files within +% the cell array. For example: + +% Specify metabolite data +% (MANDATORY) +% files = {{'/Volumes/MyProject/data/sub-01/mrs/MEGAPRESS_act.SDAT',... +% '/Volumes/MyProject/data/sub-02/mrs/MEGAPRESS_act.SDAT'},... +% {'/Volumes/MyProject/data/sub-01/mrs/MEGAPRESS_act.SDAT',... +% '/Volumes/MyProject/data/sub-02/mrs/MEGAPRESS_act.SDAT'}}; + +% Specify water reference data for eddy-current correction (same sequence as metabolite data!) +% (OPTIONAL) +% Leave empty for GE P-files (.7) - these include water reference data by +% default. +% files_ref = {{'/Volumes/MyProject/data/sub-01/mrs/MEGAPRESS_ref.SDAT',... +% '/Volumes/MyProject/data/sub-02/mrs/MEGAPRESS_ref.SDAT'},... +% {'/Volumes/MyProject/data/sub-01/mrs/MEGAPRESS_ref.SDAT',... +% '/Volumes/MyProject/data/sub-02/mrs/MEGAPRESS_ref.SDAT'}}; + +% Specify water data for quantification (e.g. short-TE water scan) +% (OPTIONAL) +% files_w = {{'/Volumes/MyProject/data/sub-01/mrs/PRESS_ref.SDAT',... +% '/Volumes/MyProject/data/sub-02/mrs/PRESS_ref.SDAT'},... +% {'/Volumes/MyProject/data/sub-01/mrs/PRESS_ref.SDAT',... +% '/Volumes/MyProject/data/sub-02/mrs/PRESS_ref.SDAT'}}; + +% Specify metabolite-nulled data for quantification +% (OPTIONAL) +% files_mm = {}; + +% Specify T1-weighted structural imaging data +% (OPTIONAL) +% Link to single NIfTI (*.nii.gz or #.nii) files for GE, Siemens and Philips data +% files_nii = {'/Volumes/MyProject/data/sub-01/anat/T1w.nii.gz',... +% '/Volumes/MyProject/data/sub-02/anat/T1w.nii.gz'}; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% 4. SPECIFY STAT FILE %%% +% Supply location of a csv file, which contains possible correlation +% measures and group variables. Each column must start with the name of the +% measure. For the grouping variable use 'group' and numbers between 1 and +% the number of included groups. If no group is supplied the data will be +% treated as one group. (You can always use the direct path) + +file_stat = fullfile(data_folder, 'stat.csv'); +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% 5. SPECIFY OUTPUT FOLDER %% +% The Osprey data container will be saved as a *.mat file in the output +% folder that you specify below. In addition, any exported files (for use +% with jMRUI, TARQUIN, or LCModel) will be saved in sub-folders. + +% Specify output folder (you can always use the direct path) +% (MANDATORY) +outputFolder = fullfile(data_folder, 'derivatives_Multidatasets'); diff --git a/exampledata/sdat/UnEdited/jobSDAT.m b/exampledata/sdat/UnEdited/jobSDAT.m index 12dc6df4..83183d31 100644 --- a/exampledata/sdat/UnEdited/jobSDAT.m +++ b/exampledata/sdat/UnEdited/jobSDAT.m @@ -4,7 +4,7 @@ % A valid Osprey job contains four distinct classes of items: % 1. basic information on the MRS sequence used % 2. several settings for data handling and modeling -% 3. a list of MRS (and, optionally, structural imaging) data files +% 3. a list of MRS (and, optionally, structural imaging) data files % to be loaded % 4. an output folder to store the results and exported files % @@ -29,7 +29,7 @@ % Defined in cell array "files_w" % - Structural image data used for co-registration and tissue class % segmentation (usually a T1 MPRAGE). These files need to be -% provided in the NIfTI format (*.nii) or, for GE data, as a +% provided in the NIfTI format (*.nii) or, for GE data, as a % folder containing DICOM Files (*.dcm). % (OPTIONAL) % Defined in cell array "files_nii" @@ -57,7 +57,7 @@ % AUTHOR: % Dr. Georg Oeltzschner (Johns Hopkins University, 2019-07-15) % goeltzs1@jhmi.edu -% +% % HISTORY: % 2019-07-15: First version of the code. @@ -80,9 +80,9 @@ % Specify data scenario dataScenario = 'invivo'; % OPTIONS: - 'invivo' (default) - % - 'phantom' - % - 'PRIAM' - % - 'MRSI' + % - 'phantom' + % - 'PRIAM' + % - 'MRSI' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -91,17 +91,33 @@ %%% 2. SPECIFY DATA HANDLING AND MODELING OPTIONS %%% % Which spectral registration method should be used? Robust spectral % registration is default, a frequency restricted spectral registration -% method is also availaible and is linked to the fit range. +% method is also availaible and is linked to the fit range. opts.SpecReg = 'RobSpecReg'; % OPTIONS: - 'RobSpecReg' (default) Spectral aligment with Water/Lipid removal, using simialrity meric, and weighted averaging % - 'ProbSpecReg' Probabilistic spectral aligment to median target and weighted averaging % - 'RestrSpecReg' Frequency restricted (fit range) spectral aligment, using simialrity meric, and weighted averaging % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array + % Save LCModel-exportable files for each spectrum? opts.saveLCM = 1; % OPTIONS: - 0 (no, default) @@ -109,7 +125,7 @@ % Save jMRUI-exportable files for each spectrum? opts.savejMRUI = 1; % OPTIONS: - 0 (no, default) % - 1 (yes) - + % Save processed spectra in vendor-specific format (SDAT/SPAR, RDA, P)? opts.saveVendor = 1; % OPTIONS: - 0 (no, default) % - 1 (yes) @@ -117,11 +133,11 @@ % Save processed spectra in NIfTI-MRS format? opts.saveNII = 0; % OPTIONS: - 0 (no, default) % - 1 (yes) - + % Save PDF output for all Osprey modules and subjects? opts.savePDF = 0; % OPTIONS: - 0 (no, default) - % - 1 (yes) - + % - 1 (yes) + % Select the metabolites to be included in the basis set as a cell array, % with entries separates by commas. % With default Osprey basis sets, you can select the following metabolites: @@ -131,8 +147,8 @@ % If you enter 'default', the basis set will include all of the above % except for Ala, bHB, bHG, Cit, EtOH, Glc, Gly, Phenyl, Ser, and Tyros. opts.fit.includeMetabs = {'default'}; % OPTIONS: - {'default'} - % - {custom} - + % - {custom} + % Choose the fitting algorithm opts.fit.method = 'Osprey'; % OPTIONS: - 'Osprey' (default) % - 'LCModel' @@ -149,10 +165,13 @@ % Determine the baseline knot spacing (in ppm) for the metabolite spectra opts.fit.bLineKnotSpace = 0.4; % [ppm] Default: 0.4. -% Add macromolecule and lipid basis functions to the fit? +% Add macromolecule and lipid basis functions to the fit? opts.fit.fitMM = 1; % OPTIONS: - 0 (no) % - 1 (yes, default) - + +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -170,7 +189,7 @@ % up the jobFile for your own data you can set a direct path to your data % folder e.g., data_folder = /Volumes/MyProject/data/' -data_folder = fileparts(which('exampledata/sdat/UnEdited/jobSDAT.m')); +data_folder = fileparts(which('exampledata/sdat/UnEdited/jobSDAT.m')); % The following lines perform an automated set-up of the jobFile which % takes advatage of the BIDS foramt. If you are not using BIDS (highly @@ -190,32 +209,32 @@ sess = sess([sess.isdir]); sess = sess(contains({sess.name},'ses')); for ll = 1:length(sess) - + % Specify metabolite data % (MANDATORY) dir_metabolite = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_press' filesep '*.SDAT']); files(counter) = {[dir_metabolite(end).folder filesep dir_metabolite(end).name]}; - + % Specify water reference data for eddy-current correction (same sequence as metabolite data!) % (OPTIONAL) % Leave empty for GE P-files (.7) - these include water reference data by % default. dir_ref = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_press-ref' filesep '*.SDAT']); files_ref(counter) = {[dir_ref(end).folder filesep dir_ref(end).name]}; - + % Specify water data for quantification (e.g. short-TE water scan) % (OPTIONAL) files_w = {}; % Specify metabolite-nulled data for quantification % (OPTIONAL) - files_mm = {}; - + files_mm = {}; + % Specify T1-weighted structural imaging data % (OPTIONAL) % Link to single NIfTI (*.nii) files for Siemens and Philips data % Link to DICOM (*.dcm) folders for GE data - files_nii(counter) = {[sess(ll).folder filesep sess(ll).name filesep 'anat' filesep subs(kk).name filesep sess(ll).name '_T1w.nii.gz']}; + files_nii(counter) = {[sess(ll).folder filesep sess(ll).name filesep 'anat' filesep subs(kk).name filesep sess(ll).name '_T1w.nii.gz']}; counter = counter + 1; end end @@ -244,13 +263,13 @@ % Specify metabolite-nulled data for quantification % (OPTIONAL) -% files_mm = {}; +% files_mm = {}; % Specify T1-weighted structural imaging data % (OPTIONAL) % Link to single NIfTI (*.nii.gz or #.nii) files for GE, Siemens and Philips data % files_nii = {'/Volumes/MyProject/data/sub-01/anat/T1w.nii.gz',... -% '/Volumes/MyProject/data/sub-02/anat/T1w.nii.gz'}; +% '/Volumes/MyProject/data/sub-02/anat/T1w.nii.gz'}; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -274,4 +293,4 @@ % (MANDATORY) outputFolder = fullfile(data_folder, 'derivatives'); -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/exampledata/sdat/UnEdited/jobSDAT_LCModel.m b/exampledata/sdat/UnEdited/jobSDAT_LCModel.m index 7825055f..54fc575f 100644 --- a/exampledata/sdat/UnEdited/jobSDAT_LCModel.m +++ b/exampledata/sdat/UnEdited/jobSDAT_LCModel.m @@ -4,7 +4,7 @@ % A valid Osprey job contains four distinct classes of items: % 1. basic information on the MRS sequence used % 2. several settings for data handling and modeling -% 3. a list of MRS (and, optionally, structural imaging) data files +% 3. a list of MRS (and, optionally, structural imaging) data files % to be loaded % 4. an output folder to store the results and exported files % @@ -29,7 +29,7 @@ % Defined in cell array "files_w" % - Structural image data used for co-registration and tissue class % segmentation (usually a T1 MPRAGE). These files need to be -% provided in the NIfTI format (*.nii) or, for GE data, as a +% provided in the NIfTI format (*.nii) or, for GE data, as a % folder containing DICOM Files (*.dcm). % (OPTIONAL) % Defined in cell array "files_nii" @@ -57,7 +57,7 @@ % AUTHOR: % Dr. Georg Oeltzschner (Johns Hopkins University, 2019-07-15) % goeltzs1@jhmi.edu -% +% % HISTORY: % 2019-07-15: First version of the code. @@ -80,10 +80,10 @@ % Specify data scenario dataScenario = 'invivo'; % OPTIONS: - 'invivo' (default) - % - 'phantom' - % - 'PRIAM' + % - 'phantom' + % - 'PRIAM' % - 'MRSI' - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -92,17 +92,34 @@ %%% 2. SPECIFY DATA HANDLING AND MODELING OPTIONS %%% % Which spectral registration method should be used? Robust spectral % registration is default, a frequency restricted spectral registration -% method is also availaible and is linked to the fit range. +% method is also availaible and is linked to the fit range. opts.SpecReg = 'RobSpecReg'; % OPTIONS: - 'RobSpecReg' (default) Spectral aligment with Water/Lipid removal, using simialrity meric, and weighted averaging % - 'ProbSpecReg' Probabilistic spectral aligment to median target and weighted averaging % - 'RestrSpecReg' Frequency restricted (fit range) spectral aligment, using simialrity meric, and weighted averaging % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array % Save LCModel-exportable files for each spectrum? opts.saveLCM = 1; % OPTIONS: - 0 (no, default) @@ -110,19 +127,19 @@ % Save jMRUI-exportable files for each spectrum? opts.savejMRUI = 0; % OPTIONS: - 0 (no, default) % - 1 (yes) - + % Save processed spectra in vendor-specific format (SDAT/SPAR, RDA, P)? opts.saveVendor = 1; % OPTIONS: - 0 (no, default) % - 1 (yes) - + % Save processed spectra in NIfTI-MRS format? opts.saveNII = 0; % OPTIONS: - 0 (no, default) % - 1 (yes) % Save PDF output for all Osprey modules and subjects? opts.savePDF = 0; % OPTIONS: - 0 (no, default) - % - 1 (yes) - + % - 1 (yes) + % Select the metabolites to be included in the basis set as a cell array, % with entries separates by commas. % With default Osprey basis sets, you can select the following metabolites: @@ -132,29 +149,29 @@ % If you enter 'default', the basis set will include all of the above % except for Ala, bHB, bHG, Cit, EtOH, Glc, Gly, Phenyl, Ser, and Tyros. opts.fit.includeMetabs = {'default'}; % OPTIONS: - {'default'} - % - {custom} - + % - {custom} + % Choose the fitting algorithm opts.fit.method = 'LCModel'; % OPTIONS: - 'Osprey' (default) % - 'LCModel' - + % Determine fitting range (in ppm) for the metabolite spectra opts.fit.range = [0.5 4]; % [ppm] Default: [0.5 4] - - + + %%% ----- OSPREY FITTING OPTIONS ----- % Choose the fitting style for difference-edited datasets (MEGA, HERMES, HERCULES) % (only available for the Osprey fitting method) opts.fit.style = 'Separate'; % OPTIONS: - 'Separate' (default) - will fit DIFF and OFF separately % - 'Concatenated' - will fit DIFF and SUM simultaneously) - + % Determine fitting range (in ppm) for water spectra opts.fit.rangeWater = [2.0 7.4]; % [ppm] Default: [2.0 7.4] % Determine the baseline knot spacing (in ppm) for the metabolite spectra opts.fit.bLineKnotSpace = 0.4; % [ppm] Default: 0.4. -% Add macromolecule and lipid basis functions to the fit? +% Add macromolecule and lipid basis functions to the fit? opts.fit.fitMM = 1; % OPTIONS: - 0 (no) % - 1 (yes, default) @@ -165,7 +182,7 @@ opts.fit.basisSetFile = which('3T_PRESS_Philips_35ms_noMM.BASIS'); -% Specify LCModel-type control file (.CONTROL) +% Specify LCModel-type control file (.CONTROL) % This is optional: If you leave this field blank, Osprey will create a % minimum control file for you. % opts.fit.controlFile = ''; @@ -187,7 +204,7 @@ % up the jobFile for your own data you can set a direct path to your data % folder e.g., data_folder = /Volumes/MyProject/data/' -data_folder = fileparts(which('exampledata/sdat/UnEdited/jobSDAT_LCModel.m')); +data_folder = fileparts(which('exampledata/sdat/UnEdited/jobSDAT_LCModel.m')); % The following lines perform an automated set-up of the jobFile which % takes advatage of the BIDS foramt. If you are not using BIDS (highly @@ -207,32 +224,32 @@ sess = sess([sess.isdir]); sess = sess(contains({sess.name},'ses')); for ll = 1:length(sess) - + % Specify metabolite data % (MANDATORY) dir_metabolite = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_press' filesep '*.SDAT']); files(counter) = {[dir_metabolite(end).folder filesep dir_metabolite(end).name]}; - + % Specify water reference data for eddy-current correction (same sequence as metabolite data!) % (OPTIONAL) % Leave empty for GE P-files (.7) - these include water reference data by % default. dir_ref = dir([sess(ll).folder filesep sess(ll).name filesep 'mrs' filesep subs(kk).name '_' sess(ll).name '_press-ref' filesep '*.SDAT']); files_ref(counter) = {[dir_ref(end).folder filesep dir_ref(end).name]}; - + % Specify water data for quantification (e.g. short-TE water scan) % (OPTIONAL) files_w = {}; % Specify metabolite-nulled data for quantification % (OPTIONAL) - files_mm = {}; - + files_mm = {}; + % Specify T1-weighted structural imaging data % (OPTIONAL) % Link to single NIfTI (*.nii) files for Siemens and Philips data % Link to DICOM (*.dcm) folders for GE data - files_nii(counter) = {[sess(ll).folder filesep sess(ll).name filesep 'anat' filesep subs(kk).name filesep sess(ll).name '_T1w.nii.gz']}; + files_nii(counter) = {[sess(ll).folder filesep sess(ll).name filesep 'anat' filesep subs(kk).name filesep sess(ll).name '_T1w.nii.gz']}; counter = counter + 1; end end @@ -261,13 +278,13 @@ % Specify metabolite-nulled data for quantification % (OPTIONAL) -% files_mm = {}; +% files_mm = {}; % Specify T1-weighted structural imaging data % (OPTIONAL) % Link to single NIfTI (*.nii.gz or #.nii) files for GE, Siemens and Philips data % files_nii = {'/Volumes/MyProject/data/sub-01/anat/T1w.nii.gz',... -% '/Volumes/MyProject/data/sub-02/anat/T1w.nii.gz'}; +% '/Volumes/MyProject/data/sub-02/anat/T1w.nii.gz'}; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -287,6 +304,6 @@ % Specify output folder (you can always use the direct path) % (MANDATORY) -outputFolder = fullfile(data_folder, 'derivatives'); +outputFolder = fullfile(data_folder, 'derivativesLCM'); -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/exampledata/twix/jobTwix.m b/exampledata/twix/jobTwix.m index 5bdb3824..5b26a7b5 100644 --- a/exampledata/twix/jobTwix.m +++ b/exampledata/twix/jobTwix.m @@ -97,10 +97,27 @@ % - 'none' % Which algorithm do you want to align the sub spectra? L2 norm -% optimazation is the default. This is only used for edited MRS! -opts.SubSpecAlignment = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) Minimizes the target peak in the difference spectrum (depends on sequence and editing target) - % - 'L1Norm' Minimizes the sum(abs(difference spectrum)) between 1.95 and 4 ppm - % - 'none' +% optimization is the default. This is only used for edited MRS! +% Which algorithm do you want to align the sub spectra? L2 norm +% optimization is the default. This is only used for edited MRS! +%Perform correction on the metabolite data (raw) or metabolite +%-nulled data (mm). +opts.SubSpecAlignment.mets = 'L2Norm'; % OPTIONS: - 'L2Norm' (default) + % - 'L1Norm' + % - 'none' + +%Perform eddy-current correction on the metabolite data (raw) or metabolite +%-nulled data (mm). This can either be done similar for all data sets by +%supplying a single value or specified for each dataset individually by supplying +% multiple entries (number has to match the number of datasets) e.g. to perform ECC +% for the second dataset only: +% opts.ECC.raw = [0 1]; +% opts.ECC.mm = [0 1]; + + +opts.ECC.raw = 1; % OPTIONS: - '1' (default) +opts.ECC.mm = 1; % - '0' (no) + % - [] array % Save processed spectra in vendor-specific format (SDAT/SPAR, RDA, P)? opts.saveVendor = 0; % OPTIONS: - 0 (no, default) @@ -159,6 +176,9 @@ opts.fit.fitMM = 1; % OPTIONS: - 0 (no) % - 1 (yes, default) +% Optional: In case the automatic basisset picker is not working you can manually +% select the path to the basis set in the osprey/fit/basis, i.e.: +% opts.fit.basisSetFile = 'osprey/fit/basis/3T/philips/mega/press/gaba68/basis_philips_megapress_gaba68.mat'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/fit/OspreyFit.m b/fit/OspreyFit.m index 5717a0cd..bf86d84b 100644 --- a/fit/OspreyFit.m +++ b/fit/OspreyFit.m @@ -83,7 +83,7 @@ refFitTime = tic; % Loop over all the datasets here for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyFitRef',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + [~] = printLog('OspreyFitRef',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.ref.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) [MRSCont] = osp_fitWater(MRSCont, kk, 'ref'); end @@ -103,7 +103,7 @@ waterFitTime = tic; % Loop over all the datasets here for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyFitWater',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + [~] = printLog('OspreyFitWater',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.w.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) [MRSCont] = osp_fitWater(MRSCont, kk, 'w'); end @@ -115,7 +115,7 @@ end MRSCont.runtime.Fit = MRSCont.runtime.Fit + MRSCont.runtime.FitMet; - + else MRSCont.runtime.Fit = MRSCont.runtime.FitMet; end @@ -128,10 +128,32 @@ MRSCont.fit.resBasisSet = MRSCont.fit.resBasisSet{2,2}; end +%% Delete redundant resBasiset entries +if strcmpi(MRSCont.opts.fit.method, 'Osprey') + if ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + FitNames = fieldnames(MRSCont.fit.resBasisSet); + NoFit = length(fieldnames(MRSCont.fit.resBasisSet)); + for sf = 1 : NoFit + if iscell(MRSCont.fit.resBasisSet.(FitNames{sf})) + MRSCont.fit.resBasisSet.(FitNames{sf}) = MRSCont.fit.resBasisSet.(FitNames{sf})(:,MRSCont.info.metab.unique_ndatapoint_spectralwidth_ind,:); + for combs = 1 : length(MRSCont.info.metab.unique_ndatapoint_spectralwidth_ind) + resBasisSetNew.(FitNames{sf}).([MRSCont.info.metab.unique_ndatapoint_spectralwidth{combs}]) = MRSCont.fit.resBasisSet.(FitNames{sf})(:,combs,:); + end + else + MRSCont.fit.resBasisSet.(FitNames{sf}).water = MRSCont.fit.resBasisSet.(FitNames{sf}).water(MRSCont.info.(FitNames{sf}).unique_ndatapoint_spectralwidth_ind); + for combs = 1 : length(MRSCont.info.(FitNames{sf}).unique_ndatapoint_spectralwidth_ind) + resBasisSetNew.(FitNames{sf}).water.([MRSCont.info.(FitNames{sf}).unique_ndatapoint_spectralwidth{combs}]) = MRSCont.fit.resBasisSet.(FitNames{sf}).water{combs}; + end + end + end + MRSCont.fit.resBasisSet = resBasisSetNew; + end +end + %% Store and print some QM parameters if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI [MRSCont] = osp_fit_Quality(MRSCont); - + L = length(MRSCont.QM.tables.Properties.VariableNames); % Store data quality measures in csv file if MRSCont.flags.isUnEdited @@ -169,28 +191,28 @@ fprintf(msg); error(msg); end - + % Loop over field names to populate descriptive fields of table for JSON export for JJ = L:length(MRSCont.QM.tables.Properties.VariableNames) switch MRSCont.QM.tables.Properties.VariableNames{JJ} case 'relResA' MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'relResA'} = 'relResA';%CWDJ?? - MRSCont.QM.tables.Properties.VariableDescriptions{'relResA'} = ''; + MRSCont.QM.tables.Properties.VariableDescriptions{'relResA'} = 'Fit quality number for spectrum A relative amplitude of the residual compared to the standard deveiation of the noise'; MRSCont.QM.tables.Properties.VariableUnits{'relResA'} = 'arbitrary'; case 'relRessum' MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'relRessum'} = 'relRessum'; - MRSCont.QM.tables.Properties.VariableDescriptions{'relRessum'} = ''; + MRSCont.QM.tables.Properties.VariableDescriptions{'relRessum'} = 'Fit quality number for sum spectrum relative amplitude of the residual compared to the standard deveiation of the noise'; MRSCont.QM.tables.Properties.VariableUnits{'relRessum'} = 'arbitrary'; case 'relResdiff1' MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'relResdiff1'} = 'relResdiff1'; - MRSCont.QM.tables.Properties.VariableDescriptions{'relResdiff1'} = ''; + MRSCont.QM.tables.Properties.VariableDescriptions{'relResdiff1'} = 'Fit quality number for diff1 spectrum relative amplitude of the residual compared to the standard deveiation of the noise'; MRSCont.QM.tables.Properties.VariableUnits{'relResdiff1'} = 'arbitrary'; case 'relResdiff2' MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'relResdiff2'} = 'relResdiff2'; - MRSCont.QM.tables.Properties.VariableDescriptions{'relResdiff2'} = ''; + MRSCont.QM.tables.Properties.VariableDescriptions{'relResdiff2'} = 'Fit quality number for diff2 spectrum relative amplitude of the residual compared to the standard deveiation of the noise'; MRSCont.QM.tables.Properties.VariableUnits{'relResdiff2'} = 'arbitrary'; end - end + end %Output as .tsv osp_WriteBIDsTable(MRSCont.QM.tables, [outputFolder filesep 'QM_processed_spectra']) @@ -201,28 +223,6 @@ MRSCont.flags.didFit = 1; diary off -%Delete redundant resBasiset entries -if strcmpi(MRSCont.opts.fit.method, 'Osprey') - if ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) - FitNames = fieldnames(MRSCont.fit.results); - NoFit = length(fieldnames(MRSCont.fit.results)); - for sf = 1 : NoFit - if iscell(MRSCont.fit.resBasisSet.(FitNames{sf})) - MRSCont.fit.resBasisSet.(FitNames{sf}) = MRSCont.fit.resBasisSet.(FitNames{sf})(MRSCont.info.A.unique_ndatapoint_spectralwidth_ind); - for combs = 1 : length(MRSCont.info.A.unique_ndatapoint_spectralwidth_ind) - resBasisSetNew.(FitNames{sf}).([MRSCont.info.A.unique_ndatapoint_spectralwidth{combs}]) = MRSCont.fit.resBasisSet.(FitNames{sf}){combs}; - end - else - MRSCont.fit.resBasisSet.(FitNames{sf}).water = MRSCont.fit.resBasisSet.(FitNames{sf}).water(MRSCont.info.(FitNames{sf}).unique_ndatapoint_spectralwidth_ind); - for combs = 1 : length(MRSCont.info.(FitNames{sf}).unique_ndatapoint_spectralwidth_ind) - resBasisSetNew.(FitNames{sf}).water.([MRSCont.info.(FitNames{sf}).unique_ndatapoint_spectralwidth{combs}]) = MRSCont.fit.resBasisSet.(FitNames{sf}).water{combs}; - end - end - end - MRSCont.fit.resBasisSet = resBasisSetNew; - end -end - % Save the output structure to the output folder % Determine output folder outputFolder = MRSCont.outputFolder; diff --git a/fit/osp_fitHERCULES.m b/fit/osp_fitHERCULES.m index 536ca234..942e28ad 100644 --- a/fit/osp_fitHERCULES.m +++ b/fit/osp_fitHERCULES.m @@ -33,8 +33,7 @@ progressText = ''; end for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyFit',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); %%% 1. DETERMINE THE FITTING STYLE %%% % Extract fit options fitOpts = MRSCont.opts.fit; @@ -46,49 +45,51 @@ % For the separate (classic) HERMES fit, model the two DIFF % spectra and the SUM spectrum separately. if strcmp(fitStyle, 'Separate') - if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.sum.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - + if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.sum.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + %%% 2a. FIT SUM-SPECTRUM % Apply scaling factor to the data - dataToFit = MRSCont.processed.sum{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'sum'); basisSetSum = MRSCont.fit.basisSet; basisSetSum.fids = basisSetSum.fids(:,:,7); basisSetSum.specs = basisSetSum.specs(:,:,7); dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); - + + fitOpts.GAP = MRSCont.opts.fit.GAP.sum; % Call the fit function [fitParamsSum, resBasisSetSum] = fit_runFit(dataToFit, basisSetSum, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.sum{kk} = resBasisSetSum; - MRSCont.fit.results.sum.fitParams{kk} = fitParamsSum; + MRSCont.fit.resBasisSet.metab{1,kk,1} = resBasisSetSum; + MRSCont.fit.results.metab.fitParams{1,kk,1} = fitParamsSum; %%% 2b. FIT DIFF1-SPECTRUM % Apply scaling factor to the data - dataToFit = MRSCont.processed.diff1{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'diff1'); basisSetDiff1 = MRSCont.fit.basisSet; basisSetDiff1.fids = basisSetDiff1.fids(:,:,5); basisSetDiff1.specs = basisSetDiff1.specs(:,:,5); dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); dataToFit.refShift = fitParamsSum.refShift; - dataToFit.refFWHM = fitParamsSum.refFWHM; - - + dataToFit.refFWHM = fitParamsSum.refFWHM; + if isfield(fitOpts, 'coMM3') && ~strcmp(fitOpts.coMM3, 'none') [basisSetDiff1] = osp_addDiffMMPeaks(basisSetDiff1,basisSetSum,fitOpts); end + + fitOpts.GAP = MRSCont.opts.fit.GAP.diff1; % Call the fit function [fitParamsDiff1, resBasisSetDiff1] = fit_runFit(dataToFit, basisSetDiff1, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.diff1{kk} = resBasisSetDiff1; - MRSCont.fit.results.diff1.fitParams{kk} = fitParamsDiff1; + MRSCont.fit.resBasisSet.metab{1,kk,2} = resBasisSetDiff1; + MRSCont.fit.results.metab.fitParams{1,kk,2} = fitParamsDiff1; %%% 2c. FIT DIFF2-SPECTRUM % Apply scaling factor to the data - dataToFit = MRSCont.processed.diff2{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'diff2'); basisSetDiff2 = MRSCont.fit.basisSet; basisSetDiff2.fids = basisSetDiff2.fids(:,:,6); basisSetDiff2.specs = basisSetDiff2.specs(:,:,6); @@ -97,12 +98,13 @@ dataToFit.refFWHM = fitParamsSum.refFWHM; fitOpts.Diff2 = 1; + fitOpts.GAP = MRSCont.opts.fit.GAP.diff2; % Call the fit function [fitParamsDiff2, resBasisSetDiff2] = fit_runFit(dataToFit, basisSetDiff2, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.diff2{kk} = resBasisSetDiff2; - MRSCont.fit.results.diff2.fitParams{kk} = fitParamsDiff2; + MRSCont.fit.resBasisSet.metab{1,kk,3} = resBasisSetDiff2; + MRSCont.fit.results.metab.fitParams{1,kk,3} = fitParamsDiff2; end end @@ -111,29 +113,14 @@ % For the concatenated MEGA fit, model the DIFF1 and SUM spectra % together. if strcmp(fitStyle, 'Concatenated') - if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.conc.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.conc.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) %%% 3a. FIT CONCATENATED SPECTRUM % Apply scaling factor to the data - dataToFit = {MRSCont.processed.diff1{kk}, MRSCont.processed.diff2{kk}, MRSCont.processed.sum{kk}}; + dataToFit = {op_takesubspec(MRSCont.processed.metab{kk},7), op_takesubspec(MRSCont.processed.metab{kk},5), op_takesubspec(MRSCont.processed.metab{kk},6)}; basisSetConc = MRSCont.fit.basisSet; basisSetConc.fids = basisSetConc.fids(:,:,5:7); basisSetConc.specs = basisSetConc.specs(:,:,5:7); - - basisSetSum = MRSCont.fit.basisSet; - basisSetSum.fids = basisSetSum.fids(:,:,7); - basisSetSum.specs = basisSetSum.specs(:,:,7); - - basisSetDiff1 = MRSCont.fit.basisSet; - basisSetDiff1.fids = basisSetDiff1.fids(:,:,5); - basisSetDiff1.specs = basisSetDiff1.specs(:,:,5); - if isfield(fitOpts, 'coMM3') && ~strcmp(fitOpts.coMM3, 'none') - [basisSetDiff1] = osp_addDiffMMPeaks(basisSetDiff1,basisSetSum,fitOpts); - end - - basisSetConc.fids(:,:,1) = basisSetDiff1.fids(:,:); - basisSetConc.specs(:,:,1) = basisSetDiff1.specs(:,:); - for rr = 1:length(dataToFit) dataToFit{rr} = op_ampScale(dataToFit{rr}, 1/MRSCont.fit.scale{kk}); end @@ -147,8 +134,8 @@ end end end - time = toc(metFitTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.FitMet = time; + end \ No newline at end of file diff --git a/fit/osp_fitHERMES.m b/fit/osp_fitHERMES.m index 97659a91..9f022ef9 100644 --- a/fit/osp_fitHERMES.m +++ b/fit/osp_fitHERMES.m @@ -33,7 +33,7 @@ progressText = ''; end for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyFit',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); %%% 1. DETERMINE THE FITTING STYLE %%% % Extract fit options fitOpts = MRSCont.opts.fit; @@ -49,23 +49,24 @@ %%% 2a. FIT SUM-SPECTRUM % Apply scaling factor to the data - dataToFit = MRSCont.processed.sum{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'sum'); basisSetSum = MRSCont.fit.basisSet; basisSetSum.fids = basisSetSum.fids(:,:,7); basisSetSum.specs = basisSetSum.specs(:,:,7); dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); + fitOpts.GAP = MRSCont.opts.fit.GAP.sum; % Call the fit function [fitParamsSum, resBasisSetSum] = fit_runFit(dataToFit, basisSetSum, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.sum{kk} = resBasisSetSum; - MRSCont.fit.results.sum.fitParams{kk} = fitParamsSum; + MRSCont.fit.resBasisSet.metab{1,kk,1} = resBasisSetSum; + MRSCont.fit.results.metab.fitParams{1,kk,1} = fitParamsSum; %%% 2b. FIT DIFF1-SPECTRUM % Apply scaling factor to the data - dataToFit = MRSCont.processed.diff1{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'diff1'); basisSetDiff1 = MRSCont.fit.basisSet; basisSetDiff1.fids = basisSetDiff1.fids(:,:,5); basisSetDiff1.specs = basisSetDiff1.specs(:,:,5); @@ -77,17 +78,18 @@ [basisSetDiff1] = osp_addDiffMMPeaks(basisSetDiff1,basisSetSum,fitOpts); end + fitOpts.GAP = MRSCont.opts.fit.GAP.diff1; % Call the fit function [fitParamsDiff1, resBasisSetDiff1] = fit_runFit(dataToFit, basisSetDiff1, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.diff1{kk} = resBasisSetDiff1; - MRSCont.fit.results.diff1.fitParams{kk} = fitParamsDiff1; + MRSCont.fit.resBasisSet.metab{1,kk,2} = resBasisSetDiff1; + MRSCont.fit.results.metab.fitParams{1,kk,2} = fitParamsDiff1; %%% 2c. FIT DIFF2-SPECTRUM % Apply scaling factor to the data - dataToFit = MRSCont.processed.diff2{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'diff2'); basisSetDiff2 = MRSCont.fit.basisSet; basisSetDiff2.fids = basisSetDiff2.fids(:,:,6); basisSetDiff2.specs = basisSetDiff2.specs(:,:,6); @@ -96,12 +98,13 @@ dataToFit.refFWHM = fitParamsSum.refFWHM; fitOpts.Diff2 = 1; + fitOpts.GAP = MRSCont.opts.fit.GAP.diff2; % Call the fit function [fitParamsDiff2, resBasisSetDiff2] = fit_runFit(dataToFit, basisSetDiff2, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.diff2{kk} = resBasisSetDiff2; - MRSCont.fit.results.diff2.fitParams{kk} = fitParamsDiff2; + MRSCont.fit.resBasisSet.metab{1,kk,3} = resBasisSetDiff2; + MRSCont.fit.results.metab.fitParams{1,kk,3} = fitParamsDiff2; end end @@ -114,7 +117,7 @@ %%% 3a. FIT CONCATENATED SPECTRUM % Apply scaling factor to the data - dataToFit = {MRSCont.processed.diff1{kk}, MRSCont.processed.diff2{kk}, MRSCont.processed.sum{kk}}; + dataToFit = {op_takesubspec(MRSCont.processed.metab{kk},7), op_takesubspec(MRSCont.processed.metab{kk},5), op_takesubspec(MRSCont.processed.metab{kk},6)}; basisSetConc = MRSCont.fit.basisSet; basisSetConc.fids = basisSetConc.fids(:,:,5:7); basisSetConc.specs = basisSetConc.specs(:,:,5:7); @@ -132,7 +135,7 @@ end end time = toc(metFitTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.FitMet = time; end \ No newline at end of file diff --git a/fit/osp_fitInitialise.m b/fit/osp_fitInitialise.m index d50bbaf5..bb30ef42 100644 --- a/fit/osp_fitInitialise.m +++ b/fit/osp_fitInitialise.m @@ -136,9 +136,6 @@ metabList = fit_createMetabList(MRSCont.opts.fit.includeMetabs); % Collect MMfit flag from the options determined in the job file fitMM = MRSCont.opts.fit.fitMM; - if fitMM == 1 && metabList.MMexp == 1 - fitMM = 2; - end % Create the modified basis set basisSet = fit_selectMetabs(basisSet, metabList, fitMM); else @@ -147,9 +144,6 @@ metabList = fit_createMetabList(MRSCont.opts.fit.includeMetabs); % Collect MMfit flag from the options determined in the job file fitMM = MRSCont.opts.fit.fitMM; - if fitMM == 1 && metabList.MMexp == 1 - fitMM = 2; - end % Create the modified basis set basisSet = fit_selectMetabs(basisSet, metabList, fitMM); end @@ -157,7 +151,12 @@ % Determine the scaling factor between data and basis set for each dataset for kk = 1:MRSCont.nDatasets if ~MRSCont.flags.isMRSI && ~MRSCont.flags.isPRIAM - MRSCont.fit.scale{kk} = max(real(MRSCont.processed.A{kk}.specs)) / max(max(max(real(basisSet.specs)))); + if ~MRSCont.flags.isUnEdited + dataToScale = op_takesubspec(MRSCont.processed.metab{kk},1); + else + dataToScale = MRSCont.processed.metab{kk}; + end + MRSCont.fit.scale{kk} = max(real(dataToScale.specs)) / max(max(max(real(basisSet.specs)))); else MRSCont.fit.scale{kk} = max(max(max(real(MRSCont.processed.A{kk}.specs)))) / max(max(max(real(basisSet.specs)))); end diff --git a/fit/osp_fitMEGA.m b/fit/osp_fitMEGA.m index f188fcac..af6bb0fe 100644 --- a/fit/osp_fitMEGA.m +++ b/fit/osp_fitMEGA.m @@ -32,9 +32,30 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyFit',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - + +if MRSCont.flags.hasMM == 1 + basisSet_mm = load(MRSCont.opts.fit.basisSetFile); + basisSet_mm = basisSet_mm.BASIS; + basisSet_mm = fit_sortBasisSet(basisSet_mm); + metabList_mm = fit_createMetabListMM('unedited'); + basisSet_mm = fit_selectMetabs(basisSet_mm, metabList_mm, 1); + basisSet_mm.fids = basisSet_mm.fids(:,:,1); + basisSet_mm.specs = basisSet_mm.specs(:,:,1); + basisSet_mm_A = basisSet_mm; + + basisSet_mm = load(MRSCont.opts.fit.basisSetFile); + basisSet_mm = basisSet_mm.BASIS; + basisSet_mm = fit_sortBasisSet(basisSet_mm); + metabList_mm = fit_createMetabListMM('MEGA'); + basisSet_mm = fit_selectMetabs(basisSet_mm, metabList_mm, 1); + basisSet_mm.fids = basisSet_mm.fids(:,:,3); + basisSet_mm.specs = basisSet_mm.specs(:,:,3); + basisSet_mm_diff1 = basisSet_mm; +end + +for kk = 1:MRSCont.nDatasets(1) + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + %%% 1. DETERMINE THE FITTING STYLE %%% % Extract fit options fitOpts = MRSCont.opts.fit; @@ -45,78 +66,184 @@ % For the separate (classic) MEGA fit, model the EDIT-OFF and DIFF % spectra separately. if strcmp(fitStyle, 'Separate') - if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.off.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.off.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) %%% 2a. FIT OFF-SPECTRUM % Apply scaling factor to the data - dataToFit = MRSCont.processed.A{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'A'); basisSetOff = MRSCont.fit.basisSet; basisSetOff.fids = basisSetOff.fids(:,:,1); basisSetOff.specs = basisSetOff.specs(:,:,1); dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); + fitOpts.GAP = MRSCont.opts.fit.GAP.A; + % Call the fit function [fitParamsOff, resBasisSetOff] = fit_runFit(dataToFit, basisSetOff, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.off{kk} = resBasisSetOff; - MRSCont.fit.results.off.fitParams{kk} = fitParamsOff; + MRSCont.fit.resBasisSet.metab{1,kk,1} = resBasisSetOff; + MRSCont.fit.results.metab.fitParams{1,kk,1} = fitParamsOff; %%% 2b. FIT DIFF1-SPECTRUM % Apply scaling factor to the data fitOpts = MRSCont.opts.fit; - dataToFit = MRSCont.processed.diff1{kk}; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'diff1'); basisSetDiff1 = MRSCont.fit.basisSet; basisSetDiff1.fids = basisSetDiff1.fids(:,:,3); basisSetDiff1.specs = basisSetDiff1.specs(:,:,3); dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); dataToFit.refShift = fitParamsOff.refShift; dataToFit.refFWHM = fitParamsOff.refFWHM; - + if ~strcmp(fitOpts.coMM3, 'none') [basisSetDiff1] = osp_addDiffMMPeaks(basisSetDiff1,basisSetOff,fitOpts); end + fitOpts.GAP = MRSCont.opts.fit.GAP.diff1; % Call the fit function [fitParamsDiff1, resBasisSetDiff1] = fit_runFit(dataToFit, basisSetDiff1, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.resBasisSet.diff1{kk} = resBasisSetDiff1; - MRSCont.fit.results.diff1.fitParams{kk} = fitParamsDiff1; - - %Modeling MM spectra after the main spectrum - if MRSCont.flags.hasMM == 1 - dataToFit_mm = MRSCont.processed.diff1_mm{kk}; + MRSCont.fit.resBasisSet.metab{1,kk,2} = resBasisSetDiff1; + MRSCont.fit.results.metab.fitParams{1,kk,2} = fitParamsDiff1; + + %Modeling MM spectra after the main spectrum + if MRSCont.flags.hasMM == 1 + dataToFit_mm = op_takesubspec(MRSCont.processed.mm{kk},'A'); dataToFit_mm = op_ampScale(dataToFit_mm, 1/MRSCont.fit.scale{kk}); + [refShift_mm, ~] = fit_OspreyReferencingMM(dataToFit_mm); + [dataToFit_mm] = op_freqshift(dataToFit_mm,-refShift_mm); %add some info from the metabolite fit dataToFit_mm.lineShape = fitParamsOff.lineShape; dataToFit_mm.refFWHM = fitParamsOff.refFWHM; + dataToFit_mm.refShift = 0; + % Extract fit options + fitOpts_mm = MRSCont.opts.fit; + fitModel_mm = fitOpts.method; + fitOpts_mm.sequence = 'unedited'; + + % Call the fit function + [fitParams_mm, resBasisSet_mm] = fit_runFitMM(dataToFit_mm, basisSet_mm_A, fitModel_mm, fitOpts_mm); + % Save back the basis set and fit parameters to MRSCont + MRSCont.fit.basisSet_mm = basisSet_mm_A; + MRSCont.fit.resBasisSet.mm{1,kk,1} = resBasisSet_mm; + MRSCont.fit.results.mm.fitParams{1,kk,1} = fitParams_mm; + + % Create full spectralwidth clean MM spectrum + disp('Create clean metabolite-nulled off spectrum...'); + [mm_clean] = fit_OspreyCleanMM(dataToFit_mm, resBasisSet_mm, fitOpts_mm,MRSCont.fit.scale{kk},fitParams_mm); + mm_clean.names = {'A_clean'}; + mm_clean.flags.isUnEdited = 1; + mm_clean.flags.isMEGA = 0; +% [mm_clean,~] = op_autophase(mm_clean,0.8,1); + [refShift_mm, ~] = fit_OspreyReferencingMM(mm_clean); + [mm_clean] = op_freqshift(mm_clean,-refShift_mm); + mm_clean = op_ampScale(mm_clean, MRSCont.fit.scale{kk}); + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},mm_clean); + dataToFit_mm = op_takesubspec(MRSCont.processed.mm{kk},'A'); + [dataToFit_mm] = op_freqshift(dataToFit_mm,-refShift_mm); + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},dataToFit_mm); + + + % Create full spectralwidth clean MM spectrum spline model + disp('Create clean metabolite-nulled off spline model...'); + %Fit them with a spline? + dataToFit_mm_clean = op_takesubspec(MRSCont.processed.mm{kk},'A_clean'); + fitOpts_mm_clean = MRSCont.opts.fit; + fitOpts_mm_clean.range=[dataToFit_mm_clean.ppm(1) dataToFit_mm_clean.ppm(end)]; + [~,mm_clean_spline] = fit_Osprey_SplineOnly(dataToFit_mm_clean, 0.1, fitOpts_mm_clean.range); + mm_clean_spline.names = {'A_spline'}; + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},mm_clean_spline); + +% % Gaussian fit with(out) baseline +% disp('Fit clean metabolite-nulled spectrum...'); +% fitOpts_mm.Params2 = fitParams_mm; +% dataToFit_mm_clean = op_ampScale(dataToFit_mm_clean, 1/MRSCont.fit.scale{kk}); +% [fitParams_mm_Gauss, resBasisSet_mm_Gauss] = fit_runFitMM(dataToFit_mm_clean, basisSetMM, 'OspreyMMGaussian', fitOpts_mm); +% MRSCont.fit.basisSet_mm_Gauss = basisSetMM; +% MRSCont.fit.resBasisSet.diff1_mm_Gauss{kk} = resBasisSet_mm_Gauss; +% MRSCont.fit.results.diff1_mm.fitParams{kk}.fitParams_mm_Gauss = fitParams_mm_Gauss; + +% % Fit off with individual MM model + disp('Fit off with metabolite-nulled spline model...'); + fitOpts.mm_clean_spline = mm_clean_spline; + fitOpts.prelimParams = fitParamsOff.prelimParams; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'A'); + dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); + % Call the fit function + [fitParamsOffExpMM, resBasisSetOffExpMM] = fit_runFit(dataToFit, basisSetOff, fitModel, fitOpts); + MRSCont.fit.resBasisSet.metab{2,kk,1} = resBasisSetOffExpMM; + MRSCont.fit.results.metab.fitParams{2,kk,1} = fitParamsOffExpMM; + + %Clean diff1 mm spectrum + dataToFit_mm = op_takesubspec(MRSCont.processed.mm{kk},'diff1'); + dataToFit_mm = op_ampScale(dataToFit_mm, 1/MRSCont.fit.scale{kk}); + [refShift_mm, ~] = fit_OspreyReferencingMM(dataToFit_mm); + [dataToFit_mm] = op_freqshift(dataToFit_mm,-refShift_mm); + %add some info from the metabolite fit + dataToFit_mm.lineShape = fitParamsDiff1.lineShape; + dataToFit_mm.refFWHM = fitParamsDiff1.refFWHM; + dataToFit_mm.refShift = 0; % Extract fit options fitOpts_mm = MRSCont.opts.fit; fitModel_mm = fitOpts.method; fitOpts_mm.sequence = 'MEGA'; - %Specify a reduced basis set for MM modeling - %basisSet_mm = MRSCont.fit.basisSet; - %Reduce the size of the basis set - - %Adjust basis set - % Clear existing basis set - MRSCont.fit.basisSet_mm = []; - basisSet_mm = basisSetDiff1; - % Generate the list of basis functions that are supposed to be included in - % the basis set - % To do: Interface with interactive user input - metabList_mm = fit_createMetabListMM('MEGA'); - % Create the modified basis set - basisSet_mm = fit_selectMetabs(basisSet_mm, metabList_mm, 0); + % Call the fit function - [fitParams_mm, resBasisSet_mm] = fit_runFitMM(dataToFit_mm, basisSet_mm, fitModel_mm, fitOpts_mm); + [fitParams_mm, resBasisSet_mm] = fit_runFitMM(dataToFit_mm, basisSet_mm_diff1, fitModel_mm, fitOpts_mm); % Save back the basis set and fit parameters to MRSCont - MRSCont.fit.basisSet_mm = basisSet_mm; - MRSCont.fit.resBasisSet.diff1_mm{kk} = resBasisSet_mm; - MRSCont.fit.results.diff1_mm.fitParams{kk} = fitParams_mm; - end - + MRSCont.fit.basisSet_mm = basisSet_mm_diff1; + MRSCont.fit.resBasisSet.mm{1,kk,2} = resBasisSet_mm; + MRSCont.fit.results.mm.fitParams{1,kk,2} = fitParams_mm; + + % Create full spectralwidth clean MM spectrum + disp('Create clean metabolite-nulled diff1 spectrum...'); + [mm_clean] = fit_OspreyCleanMM(dataToFit_mm, resBasisSet_mm, fitOpts_mm,MRSCont.fit.scale{kk},fitParams_mm); + mm_clean.names = {'diff1_clean'}; +% [mm_clean,~] = op_autophase(mm_clean,0.8,1); + [refShift_mm, ~] = fit_OspreyReferencingMM(mm_clean); + [mm_clean] = op_freqshift(mm_clean,-refShift_mm); + mm_clean = op_ampScale(mm_clean, MRSCont.fit.scale{kk}); + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},mm_clean); + dataToFit_mm = op_takesubspec(MRSCont.processed.mm{kk},'diff1'); + [dataToFit_mm] = op_freqshift(dataToFit_mm,-refShift_mm); + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},dataToFit_mm); + + + % Create full spectralwidth clean MM spectrum spline model + disp('Create clean metabolite-nulled diff1 spline model...'); + %Fit them with a spline? + dataToFit_mm_clean = op_takesubspec(MRSCont.processed.mm{kk},'diff1_clean'); + fitOpts_mm_clean = MRSCont.opts.fit; + fitOpts_mm_clean.range=[dataToFit_mm_clean.ppm(1) dataToFit_mm_clean.ppm(end)]; + [~,mm_clean_spline] = fit_Osprey_SplineOnly(dataToFit_mm_clean, 0.1, fitOpts_mm_clean.range); + mm_clean_spline.names = {'diff1_spline'}; + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},mm_clean_spline); + +% % Gaussian fit with(out) baseline +% disp('Fit clean metabolite-nulled spectrum...'); +% fitOpts_mm.Params2 = fitParams_mm; +% dataToFit_mm_clean = op_ampScale(dataToFit_mm_clean, 1/MRSCont.fit.scale{kk}); +% [fitParams_mm_Gauss, resBasisSet_mm_Gauss] = fit_runFitMM(dataToFit_mm_clean, basisSetMM, 'OspreyMMGaussian', fitOpts_mm); +% MRSCont.fit.basisSet_mm_Gauss = basisSetMM; +% MRSCont.fit.resBasisSet.diff1_mm_Gauss{kk} = resBasisSet_mm_Gauss; +% MRSCont.fit.results.diff1_mm.fitParams{kk}.fitParams_mm_Gauss = fitParams_mm_Gauss; + +% % Fit diff1 with individual MM model + disp('Fit diff1 with metabolite-nulled spline model...'); + fitOpts.mm_clean_spline = mm_clean_spline; + fitOpts.prelimParams = fitParamsDiff1.prelimParams; + fitOpts.coMM3 = 'none'; + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'diff1'); + dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); + % Call the fit function + [fitParamsDiff1ExpMM, resBasisSetDiff1ExpMM] = fit_runFit(dataToFit, basisSetDiff1, fitModel, fitOpts); + MRSCont.fit.resBasisSet.metab{2,kk,2} = resBasisSetDiff1ExpMM; + MRSCont.fit.results.metab.fitParams{2,kk,2} = fitParamsDiff1ExpMM; + + end + end end @@ -125,11 +252,11 @@ % For the concatenated MEGA fit, model the DIFF1 and SUM spectra % together. if strcmp(fitStyle, 'Concatenated') - if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.conc.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.conc.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) %%% 3a. FIT CONCATENATED SPECTRUM % Select the difference and sum spectrum to put into the % concatenated fit - dataToFit = {MRSCont.processed.diff1{kk} MRSCont.processed.sum{kk}}; + dataToFit = {op_takesubspec(MRSCont.processed.metab{kk},3) op_takesubspec(MRSCont.processed.metab{kk},4)}; basisSetConc = MRSCont.fit.basisSet; % Create the basis set with difference and sum basis functions basisSetConc.fids(:,:,1) = basisSetConc.fids(:,:,3); @@ -138,7 +265,7 @@ basisSetConc.specs(:,:,2) = basisSetConc.specs(:,:,4); basisSetConc.fids(:,:,3:4) = []; basisSetConc.specs(:,:,3:4) = []; - + if ~strcmp(fitOpts.coMM3, 'none') basisSetDiff1 = MRSCont.fit.basisSet; basisSetDiff1.fids = basisSetDiff1.fids(:,:,3); @@ -147,7 +274,7 @@ basisSetConc.fids(:,:,1) = basisSetDiff1.fids(:,:); basisSetConc.specs(:,:,1) = basisSetDiff1.specs(:,:); end - + % Apply scaling factor to the data for rr = 1:length(dataToFit) dataToFit{rr} = op_ampScale(dataToFit{rr}, 1/MRSCont.fit.scale{kk}); @@ -159,10 +286,85 @@ MRSCont.fit.resBasisSet.conc{kk} = resBasisSetConc; MRSCont.fit.results.conc.fitParams{kk} = fitParamsConc; end - end + end end +%Fit again with mean MM basis function +if MRSCont.opts.fit.MeanMM + if MRSCont.flags.hasMM == 1 + + fids = zeros(mm_clean_spline.sz(1),MRSCont.nDatasets(1)); + for kk = 1:MRSCont.nDatasets(1) + fids(:,kk) = MRSCont.processed.mm{kk}.fids(:,6); + end + mean_fids = mean(fids,2); + mm_clean_spline.fids = mean_fids; + mm_clean_spline.specs = fftshift(fft(mean_fids,[],1),1); + fitOpts.mm_clean_spline = mm_clean_spline; + MRSCont.opts.fit.mm_clean_spline= mm_clean_spline; + end + + for kk = 1:MRSCont.nDatasets(1) + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + % Fit diff1 with individual MM model + disp('Fit off with mean metabolite-nulled spline model...'); + % Call the fit function + fitOpts.prelimParams = MRSCont.fit.results.metab.fitParams{1,kk,1}.prelimParams; + fitOpts.GAP = MRSCont.opts.fit.GAP.A; + + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'A'); + dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); + dataToFit.refShift = MRSCont.fit.results.metab.fitParams{1,kk,1}.refShift; + dataToFit.refFWHM = MRSCont.fit.results.metab.fitParams{1,kk,1}.refFWHM; + + [fitParamsOffExpMM, resBasisSetOffExpMM] = fit_runFit(dataToFit, basisSetOff, fitModel, fitOpts); + MRSCont.fit.resBasisSet.metab{3,kk,1} = resBasisSetOffExpMM; + MRSCont.fit.results.metab.fitParams{3,kk,1} = fitParamsOffExpMM; + + end + + if MRSCont.flags.hasMM == 1 + + fids = zeros(mm_clean_spline.sz(1),MRSCont.nDatasets(1)); + for kk = 1:MRSCont.nDatasets(1) + fids(:,kk) = MRSCont.processed.mm{kk}.fids(:,7); + end + mean_fids = mean(fids,2); + mm_clean_spline.fids = mean_fids; + mm_clean_spline.specs = fftshift(fft(mean_fids,[],1),1); + fitOpts.mm_clean_spline = mm_clean_spline; + MRSCont.opts.fit.mm_clean_spline= mm_clean_spline; + else + load('/Volumes/Samsung/working/editedMM/mm_clean_spline.mat') % This is just for now :D + [refShift_mm, ~] = fit_OspreyReferencingMM(mm_clean_spline); + [mm_clean_spline] = op_freqshift(mm_clean_spline,-refShift_mm); + MRSCont.opts.fit.mm_clean_spline= mm_clean_spline; + fitOpts.mm_clean_spline = mm_clean_spline; + end + + fitOpts.coMM3 = 'none'; + for kk = 1:MRSCont.nDatasets(1) + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + % Fit diff1 with individual MM model + disp('Fit diff1 with mean metabolite-nulled spline model...'); + % Call the fit function + fitOpts.prelimParams = MRSCont.fit.results.metab.fitParams{1,kk,2}.prelimParams; + fitOpts.GAP = MRSCont.opts.fit.GAP.diff1; + + dataToFit = op_takesubspec(MRSCont.processed.metab{kk},'diff1'); + dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); + dataToFit.refShift = MRSCont.fit.results.metab.fitParams{1,kk,2}.refShift; + dataToFit.refFWHM = MRSCont.fit.results.metab.fitParams{1,kk,2}.refFWHM; + + [fitParamsDiff1ExpMM, resBasisSetDiff1ExpMM] = fit_runFit(dataToFit, basisSetDiff1, fitModel, fitOpts); + MRSCont.fit.resBasisSet.metab{3,kk,2} = resBasisSetDiff1ExpMM; + MRSCont.fit.results.metab.fitParams{3,kk,2} = fitParamsDiff1ExpMM; + + end +end + + time = toc(metFitTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,MRSCont.nDatasets,1,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.FitMet = time; -end \ No newline at end of file +end diff --git a/fit/osp_fitUnEdited.m b/fit/osp_fitUnEdited.m index 233c08c0..4e273deb 100644 --- a/fit/osp_fitUnEdited.m +++ b/fit/osp_fitUnEdited.m @@ -33,16 +33,24 @@ else progressText = ''; end +if MRSCont.flags.hasMM == 1 + basisSet_mm = load(MRSCont.opts.fit.basisSetFile); + basisSet_mm = basisSet_mm.BASIS; + basisSet_mm = fit_sortBasisSet(basisSet_mm); + metabList_mm = fit_createMetabListMM('unedited'); + basisSet_mm = fit_selectMetabs(basisSet_mm, metabList_mm, 1); +end + for kk = 1:MRSCont.nDatasets % ----- Osprey fit pipeline ----- if strcmpi(MRSCont.opts.fit.method, 'Osprey') - [~] = printLog('OspreyFit', kk, MRSCont.nDatasets, progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI); + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); if ~(MRSCont.flags.didFit == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'fit') && (kk > length(MRSCont.fit.results.off.fitParams))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) % Apply scaling factor to the data - dataToFit = MRSCont.processed.A{kk}; + dataToFit = MRSCont.processed.metab{kk}; dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); % Extract fit options fitOpts = MRSCont.opts.fit; @@ -51,7 +59,7 @@ % If MRSI data load priors if MRSCont.flags.isMRSI if isfield(MRSCont.fit, 'results') - fitParamsOff = MRSCont.fit.results.off.fitParams{kk}; + fitParamsOff = MRSCont.fit.results.metab.fitParams{kk}; % dataToFit.refShift = fitParamsOff.refShift; % dataToFit.refFWHM = fitParamsOff.refFWHM; fitOpts.MRSIpriors = fitParamsOff; @@ -60,12 +68,13 @@ % Call the fit function basisSet = MRSCont.fit.basisSet; + fitOpts.GAP = MRSCont.opts.fit.GAP.A; [fitParams, resBasisSet] = fit_runFit(dataToFit, basisSet, fitModel, fitOpts); % Save back the basis set and fit parameters to MRSCont MRSCont.fit.basisSet = basisSet; - MRSCont.fit.resBasisSet.off{kk} = resBasisSet; - MRSCont.fit.results.off.fitParams{kk} = fitParams; + MRSCont.fit.resBasisSet.metab{1,kk,1} = resBasisSet; + MRSCont.fit.results.metab.fitParams{1,kk,1} = fitParams; %Modeling MM spectra after the main spectrum re_mm if MRSCont.flags.hasMM == 1 %re_mm dataToFit_mm = MRSCont.processed.mm{kk}; @@ -73,6 +82,7 @@ %add some info from the metabolite fit dataToFit_mm.lineShape = fitParams.lineShape; dataToFit_mm.refFWHM = fitParams.refFWHM; + dataToFit_mm.refShift = 0; % Extract fit options fitOpts_mm = MRSCont.opts.fit; fitModel_mm = fitOpts.method; @@ -95,20 +105,58 @@ fitMM = MRSCont.opts.fit.fitMM; % Create the modified basis set basisSet_mm = fit_selectMetabs(basisSet_mm, metabList_mm, fitMM); + % Call the fit function [fitParams_mm, resBasisSet_mm] = fit_runFitMM(dataToFit_mm, basisSet_mm, fitModel_mm, fitOpts_mm); % Save back the basis set and fit parameters to MRSCont MRSCont.fit.basisSet_mm = basisSet_mm; - MRSCont.fit.resBasisSet.mm{kk} = resBasisSet_mm; - MRSCont.fit.results.mm.fitParams{kk} = fitParams_mm; - MRSCont.fit.basisSet_mm; - end % re_mm + MRSCont.fit.resBasisSet.mm{1,kk,1} = resBasisSet_mm; + MRSCont.fit.results.mm.fitParams{1,kk,1} = fitParams_mm; + + % Create full spectralwidth clean MM spectrum + disp('Create clean metabolite-nulled spectrum...'); + [mm_clean] = fit_OspreyCleanMM(dataToFit_mm, resBasisSet_mm, fitOpts_mm,MRSCont.fit.scale{kk},fitParams_mm); + mm_clean.names = {'A_clean'}; + mm_clean = op_ampScale(mm_clean, MRSCont.fit.scale{kk}); + + + % Create full spectralwidth clean MM spectrum spline model + disp('Create clean metabolite-nulled spline model...'); + %Fit them with a spline? + fitOpts_mm_clean = MRSCont.opts.fit; + fitOpts_mm_clean.range=[mm_clean.ppm(1) mm_clean.ppm(end)]; + [~,mm_clean_spline] = fit_Osprey_SplineOnly(mm_clean, 0.1, fitOpts_mm_clean.range); + mm_clean_spline.names = {'A_spline'}; + temp = op_zeropad(mm_clean, 16); + [refShift_mm, ~] = osp_XReferencing(temp,[0.91],[1],[0 4.2],1);% determine frequency shift + [mm_clean] = op_freqshift(mm_clean,-refShift_mm); + [mm_clean_spline] = op_freqshift(mm_clean_spline,-refShift_mm); + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},mm_clean); + MRSCont.processed.mm{kk} = op_mergesubspec(MRSCont.processed.mm{kk},mm_clean_spline); + +% % Gaussian fit with(out) baseline +% disp('Fit clean metabolite-nulled spectrum...'); +% fitOpts_mm.Params2 = fitParams_mm; +% dataToFit_mm_clean = op_ampScale(dataToFit_mm_clean, 1/MRSCont.fit.scale{kk}); +% [fitParams_mm_Gauss, resBasisSet_mm_Gauss] = fit_runFitMM(dataToFit_mm_clean, basisSetMM, 'OspreyMMGaussian', fitOpts_mm); +% MRSCont.fit.basisSet_mm_Gauss = basisSetMM; +% MRSCont.fit.resBasisSet.diff1_mm_Gauss{kk} = resBasisSet_mm_Gauss; +% MRSCont.fit.results.diff1_mm.fitParams{kk}.fitParams_mm_Gauss = fitParams_mm_Gauss; + +% % Fit diff1 with individual MM model + disp('Fit metabolite data with metabolite-nulled spline model...'); + fitOpts.mm_clean_spline = mm_clean_spline; + fitOpts.prelimParams = fitParams.prelimParams; + % Call the fit function + [fitParamsAExpMM, resBasisSetAExpMM] = fit_runFit(dataToFit, basisSet, fitModel, fitOpts); + MRSCont.fit.resBasisSet.metab{2,kk,1} = resBasisSetAExpMM; + MRSCont.fit.results.metab.fitParams{2,kk,1} = fitParamsAExpMM; + end end % ----- LCModel wrapper fit pipeline ----- elseif strcmpi(MRSCont.opts.fit.method, 'LCModel') - [~] = printLog('OspreyFit', kk, MRSCont.nDatasets, progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI,1); - + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Put the scale to be 1 for now. Might have to adjust. MRSCont.fit.scale{kk} = 1; @@ -145,14 +193,50 @@ callLCModel(MRSCont, MRSCont.opts.fit.lcmodel.controlfileA{kk},[pathLCModelBinary filesep bin]); % Save the parameters and information about the basis set - MRSCont.fit.results.off.fitParams{kk} = readLCMFitParams(MRSCont, 'A', kk); + + MRSCont.fit.results.metab.fitParams{kk} = readLCMFitParams(MRSCont, 'A', kk); end end +%Fit again with mean MM basis function +if MRSCont.opts.fit.MeanMM + if MRSCont.flags.hasMM == 1 + + fids = zeros(mm_clean_spline.sz(1),MRSCont.nDatasets(1)); + for kk = 1:MRSCont.nDatasets(1) + fids(:,kk) = MRSCont.processed.mm{kk}.fids(:,3); + end + mean_fids = mean(fids,2); + mm_clean_spline.fids = mean_fids; + mm_clean_spline.specs = fftshift(fft(mean_fids,[],1),1); + fitOpts.mm_clean_spline = mm_clean_spline; + MRSCont.opts.fit.mm_clean_spline= mm_clean_spline; + end + + for kk = 1:MRSCont.nDatasets(1) + [~] = printLog('OspreyFit',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + % Fit diff1 with individual MM model + disp('Fit metabolite data with mean metabolite-nulled spline model...'); + % Call the fit function + fitOpts.prelimParams = MRSCont.fit.results.metab.fitParams{1,kk}.prelimParams; + fitOpts.GAP = MRSCont.opts.fit.GAP.A; + + dataToFit = MRSCont.processed.metab{kk}; + dataToFit = op_ampScale(dataToFit, 1/MRSCont.fit.scale{kk}); + dataToFit.refShift = MRSCont.fit.results.metab.fitParams{1,kk,1}.refShift; + dataToFit.refFWHM = MRSCont.fit.results.metab.fitParams{1,kk,1}.refFWHM; + + [fitParamsAExpMM, resBasisSetAExpMM] = fit_runFit(dataToFit, basisSet, fitModel, fitOpts); + MRSCont.fit.resBasisSet.metab{3,kk,1} = resBasisSetAExpMM; + MRSCont.fit.results.metab.fitParams{3,kk,1} = fitParamsAExpMM; + + end +end + time = toc(metFitTime); -[~] = printLog('done', time, MRSCont.nDatasets, progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI); +[~] = printLog('done',time,MRSCont.nDatasets,1,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.FitMet = time; end diff --git a/fit/osp_fitWater.m b/fit/osp_fitWater.m index 85d585b8..8afa421b 100644 --- a/fit/osp_fitWater.m +++ b/fit/osp_fitWater.m @@ -84,7 +84,7 @@ % Call the fit function [fitParamsWater, resBasisSetWater] = fit_runFitWater(dataToFit, basisSet, fitModel, fitOpts); % Save back the fit parameters to MRSCont - MRSCont.fit.resBasisSet{x}.(str).water{kk} = resBasisSetWater; + MRSCont.fit.resBasisSet{x}.(str){kk} = resBasisSetWater; MRSCont.fit.results{x}.(str).fitParams{kk} = fitParamsWater; end elseif MRSCont.flags.isMRSI == 1 @@ -133,10 +133,10 @@ % Save back the fit parameters to MRSCont % 2D MRSI data if ZVox <=1 - MRSCont.fit.resBasisSet{x,y}.(str).water{kk} = resBasisSetWater; + MRSCont.fit.resBasisSet{x,y}.(str){kk} = resBasisSetWater; MRSCont.fit.results{x,y}.(str).fitParams{kk} = fitParamsWater; else % 3D MRSI data - MRSCont.fit.resBasisSet{x,y,z}.(str).water{kk} = resBasisSetWater; + MRSCont.fit.resBasisSet{x,y,z}.(str){kk} = resBasisSetWater; MRSCont.fit.results{x,y,z}.(str).fitParams{kk} = fitParamsWater; end @@ -161,7 +161,7 @@ % Call the fit function [fitParamsWater, resBasisSetWater] = fit_runFitWater(dataToFit, basisSet, fitModel, fitOpts); % Write - MRSCont.fit.resBasisSet.(str).water{kk} = resBasisSetWater; + MRSCont.fit.resBasisSet.(str){kk} = resBasisSetWater; MRSCont.fit.results.(str).fitParams{kk} = fitParamsWater; end diff --git a/fit/osp_fit_Quality.m b/fit/osp_fit_Quality.m index 36702638..90461566 100644 --- a/fit/osp_fit_Quality.m +++ b/fit/osp_fit_Quality.m @@ -34,144 +34,114 @@ %%% 2. INITIALIZE VARIABLES %%% %Getting the names of the SubSpectra and Fits -FitNames = fieldnames(MRSCont.fit.results); -NoFit = length(fieldnames(MRSCont.fit.results)); -dataPlotNames = FitNames; -tempFitNames = FitNames; -shift = 0; - -%Getting the final model names (needed for concatenated fits) -for sf = 1 : NoFit - switch MRSCont.opts.fit.method - case {'Osprey', 'LCModel'} - switch FitNames{sf} - case 'off' - dataPlotNames{sf} = 'A'; - case 'conc' - if MRSCont.flags.isMEGA - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - shift = 1; - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'diff2'; - dataPlotNames{sf+2} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - tempFitNames{sf+2} = 'conc'; - shift = 2; - end - otherwise - dataPlotNames{sf + shift} = FitNames{sf}; - tempFitNames{sf + shift} = FitNames{sf}; - end - case 'OspreyNoLS' - switch FitNames{sf} - case 'off' - dataPlotNames{sf} = 'A'; - case 'conc' - if MRSCont.flags.isMEGA - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - shift = 1; - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'diff2'; - dataPlotNames{sf+2} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - tempFitNames{sf+2} = 'conc'; - shift = 2; +OrderNames = {'metab'}; +OrderNamesFit = {'metab'}; +if MRSCont.flags.hasMM + OrderNames = horzcat(OrderNames, 'mm'); + OrderNamesFit = horzcat(OrderNamesFit, 'mm'); +end + +if MRSCont.flags.hasRef + OrderNames = horzcat(OrderNames, 'ref'); + if ~strcmp(MRSCont.opts.fit.method,'LCModel') + OrderNamesFit = horzcat(OrderNamesFit, 'ref'); + end +end + +if MRSCont.flags.hasMMRef + OrderNames = horzcat(OrderNames, 'mm_ref'); +end + +if MRSCont.flags.hasWater + OrderNames = horzcat(OrderNames, 'w'); + OrderNamesFit = horzcat(OrderNamesFit, 'w'); +end + +S = orderfields(MRSCont.fit.results,OrderNamesFit); +FitSpecNames = fieldnames(S)'; +NoFitSpecNames = length(FitSpecNames); +if ~strcmp(MRSCont.opts.fit.method,'LCModel') + for sf = 1 : NoFitSpecNames + for sn = 1 : size(MRSCont.fit.results.(FitSpecNames{sf}).fitParams,3) + for sb = 1 : size(MRSCont.fit.results.(FitSpecNames{sf}).fitParams,1) + if ~(strcmp(FitSpecNames{sf},'ref') ||strcmp(FitSpecNames{sf},'w')) + if ~isempty(MRSCont.fit.results.(FitSpecNames{sf}).fitParams{sb,1,sn}) + FitSpecNamesStruct.(FitSpecNames{sf}){sb,sn} = MRSCont.fit.resBasisSet.(FitSpecNames{sf}).(MRSCont.info.(FitSpecNames{sf}).unique_ndatapoint_spectralwidth{1}){1,1,sn}.names{1}; end - otherwise - dataPlotNames{sf + shift} = FitNames{sf}; - tempFitNames{sf + shift} = FitNames{sf}; + else + FitSpecNamesStruct.(FitSpecNames{sf}){1} = MRSCont.fit.resBasisSet.(FitSpecNames{sf}).(MRSCont.info.(FitSpecNames{sf}).unique_ndatapoint_spectralwidth{1}){1,1,1}.names{1}; + end end + end end +else + FitSpecNamesStruct.(FitSpecNames{1}){1} = 'A'; end -FitNames = tempFitNames; -NoFit = length(FitNames); - -% Apply the same steps to the fits -for sf = 1 : NoFit %Loop over all fits - for kk = 1 : MRSCont.nDatasets %Loop over all datasets - switch MRSCont.opts.fit.method %Which model was used - - case 'Osprey' - if ~(strcmp((FitNames{sf}), 'ref') || strcmp((FitNames{sf}), 'w')) % Not the water model - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}){kk}; - dataToPlot = MRSCont.processed.(dataPlotNames{sf}){kk}; - % Get the fit parameters - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - % Pack up into structs to feed into the reconstruction functions - inputData.dataToFit = dataToPlot; - inputData.basisSet = basisSet; - inputSettings.scale = MRSCont.fit.scale{kk}; - inputSettings.fitRangePPM = fitRangePPM; - inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; - inputSettings.fitStyle = MRSCont.opts.fit.style; - inputSettings.flags.isMEGA = MRSCont.flags.isMEGA; - inputSettings.flags.isHERMES = MRSCont.flags.isHERMES; - inputSettings.flags.isHERCULES = MRSCont.flags.isHERCULES; - inputSettings.flags.isPRIAM = MRSCont.flags.isPRIAM; - inputSettings.concatenated.Subspec = dataPlotNames{sf}; - if strcmp(inputSettings.fitStyle,'Concatenated') - [ModelOutput] = fit_OspreyParamsToConcModel(inputData, inputSettings, fitParams); - else - [ModelOutput] = fit_OspreyParamsToModel(inputData, inputSettings, fitParams); - end - end - - case 'OspreyNoLS' - if ~(strcmp((FitNames{sf}), 'ref') || strcmp((FitNames{sf}), 'w')) % Not the water model - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}){kk}; - dataToPlot = MRSCont.processed.(dataPlotNames{sf}){kk}; - % Get the fit parameters - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - % Pack up into structs to feed into the reconstruction functions - inputData.dataToFit = dataToPlot; - inputData.basisSet = basisSet; - inputSettings.scale = MRSCont.fit.scale{kk}; - inputSettings.fitRangePPM = fitRangePPM; - inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; - inputSettings.fitStyle = MRSCont.opts.fit.style; - inputSettings.flags.isMEGA = MRSCont.flags.isMEGA; - inputSettings.flags.isHERMES = MRSCont.flags.isHERMES; - inputSettings.flags.isHERCULES = MRSCont.flags.isHERCULES; - inputSettings.flags.isPRIAM = MRSCont.flags.isPRIAM; - inputSettings.concatenated.Subspec = dataPlotNames{sf}; - if strcmp(inputSettings.fitStyle,'Concatenated') - [ModelOutput] = fit_OspreyParamsToConcModel(inputData, inputSettings, fitParams); - else - [ModelOutput] = fit_OspreyNoLSParamsToModel(inputData, inputSettings, fitParams); - end + + +for ss = 1 :NoFitSpecNames %Loop over fitted spectra + +for sf = 1 : size(FitSpecNamesStruct.(FitSpecNames{ss}),2) %Loop over all fits + bf = 1; + if ~isempty(FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}) + for kk = 1 : MRSCont.nDatasets(1) %Loop over all datasets + switch MRSCont.opts.fit.method %Which model was used + case 'Osprey' + if ~strcmp(FitSpecNames{ss}, 'ref') && ~strcmp(FitSpecNames{ss}, 'w') && ~strcmp(FitSpecNames{ss}, 'mm') % metabolite only + fitRangePPM = MRSCont.opts.fit.range; + + dataToPlot = op_takesubspec(MRSCont.processed.(FitSpecNames{ss}){kk},find(strcmp(MRSCont.processed.(FitSpecNames{ss}){kk}.names,FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}))); + basisSet = MRSCont.fit.resBasisSet.(FitSpecNames{ss}).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){bf,sf}; + fitParams = MRSCont.fit.results.(FitSpecNames{ss}).fitParams{bf,kk,sf}; + % Pack up into structs to feed into the reconstruction functions + inputData.dataToFit = dataToPlot; + inputData.basisSet = basisSet; + inputSettings.scale = MRSCont.fit.scale{kk}; + + inputSettings.fitRangePPM = fitRangePPM; + inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; + inputSettings.fitStyle = MRSCont.opts.fit.style; + inputSettings.flags.isMEGA = MRSCont.flags.isMEGA; + inputSettings.flags.isHERMES = MRSCont.flags.isHERMES; + inputSettings.flags.isHERCULES = MRSCont.flags.isHERCULES; + inputSettings.flags.isPRIAM = MRSCont.flags.isPRIAM; + inputSettings.concatenated.Subspec = FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}; + if isfield(MRSCont.opts.fit,'GAP') + inputSettings.GAP = MRSCont.opts.fit.GAP.(FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}); + else + inputSettings.GAP = []; + end + if strcmp(inputSettings.fitStyle,'Concatenated') + [ModelOutput] = fit_OspreyParamsToConcModel(inputData, inputSettings, fitParams); + else + [ModelOutput] = fit_OspreyParamsToModel(inputData, inputSettings, fitParams); + end + + end + case 'LCModel' + dataToPlot = MRSCont.processed.(FitSpecNames{ss}){kk}; + fitParams = MRSCont.fit.results.(FitSpecNames{ss}).fitParams{bf,kk,sf}; + + % Get the LCModel plots we previously extracted from .coord + % etc. + [ModelOutput] = fit_LCModelParamsToModel(fitParams); + end - case 'LCModel' - dataToPlot = MRSCont.processed.(dataPlotNames{sf}){kk}; - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - [ModelOutput] = fit_LCModelParamsToModel(fitParams); - + %NOW FIND THE STANDARD DEVIATION OF THE NOISE: + noisewindow=dataToPlot.specs(dataToPlot.ppm>-2 & dataToPlot.ppm<0)./MRSCont.fit.scale{kk}; + ppmwindow2=dataToPlot.ppm(dataToPlot.ppm>-2 & dataToPlot.ppm<0)'; + + P=polyfit(ppmwindow2,noisewindow,2); + noise=noisewindow-polyval(P,ppmwindow2); + + MRSCont.QM.relAmpl.(FitSpecNamesStruct.(FitSpecNames{ss}){1,sf})(kk) = sum(ModelOutput.residual.^2)/(std(real(noise))^2 * length(ModelOutput.residual)); + + end end +end +end - %NOW FIND THE STANDARD DEVIATION OF THE NOISE: - noisewindow=dataToPlot.specs(dataToPlot.ppm>-2 & dataToPlot.ppm<0)./MRSCont.fit.scale{kk}; - ppmwindow2=dataToPlot.ppm(dataToPlot.ppm>-2 & dataToPlot.ppm<0)'; - - P=polyfit(ppmwindow2,noisewindow,2); - noise=noisewindow-polyval(P,ppmwindow2); - - MRSCont.QM.relAmpl.(dataPlotNames{sf})(kk) = sum(ModelOutput.residual.^2)/(std(real(noise))^2 * length(ModelOutput.residual)); - end -end diff --git a/fit/osp_writelcm_control.m b/fit/osp_writelcm_control.m index a6172c80..65e1ed3e 100644 --- a/fit/osp_writelcm_control.m +++ b/fit/osp_writelcm_control.m @@ -68,6 +68,9 @@ end name_raw = MRSCont.opts.fit.lcmodel.(subspec){kk}; +% Retrieve data +dataToExport = op_takesubspec(MRSCont.processed.metab{kk},find(strcmp(MRSCont.processed.metab{kk}.names,which))); + % Retrieve the filenames of the LCModel .RAW files that were created at the % end of OspreyProcess using osp_saveLCM. if isfield(MRSCont.opts.fit.lcmodel, 'outfileRef') @@ -95,9 +98,9 @@ end % Add the necessary parameters -LCMparam = osp_editControlParameters(LCMparam, 'hzpppm', sprintf('%2.6e', MRSCont.processed.(which){kk}.txfrq/1e6)); -LCMparam = osp_editControlParameters(LCMparam, 'deltat', sprintf('%2.6e', MRSCont.processed.(which){kk}.dwelltime)); -LCMparam = osp_editControlParameters(LCMparam, 'nunfil', sprintf('%i', MRSCont.processed.(which){kk}.sz(1))); +LCMparam = osp_editControlParameters(LCMparam, 'hzpppm', sprintf('%2.6e', dataToExport.txfrq/1e6)); +LCMparam = osp_editControlParameters(LCMparam, 'deltat', sprintf('%2.6e', dataToExport.dwelltime)); +LCMparam = osp_editControlParameters(LCMparam, 'nunfil', sprintf('%i', dataToExport.sz(1))); if isfield(LCMparam, 'chcomb') LCMparam = osp_editControlParameters(LCMparam, 'ncombi', sprintf('%i', length(LCMparam.chcomb))); end diff --git a/graphics/osprey.gif b/graphics/osprey.gif index 7dd54fdb..fc9bac6e 100644 Binary files a/graphics/osprey.gif and b/graphics/osprey.gif differ diff --git a/graphics/osprey.png b/graphics/osprey.png index b5953284..29f99fa3 100644 Binary files a/graphics/osprey.png and b/graphics/osprey.png differ diff --git a/job/OspreyJob.m b/job/OspreyJob.m index 47847478..3f9e6aa3 100755 --- a/job/OspreyJob.m +++ b/job/OspreyJob.m @@ -83,6 +83,9 @@ if isfield(jobStruct, 'files_mm') %re_mm Adding functionality for MM files_mm = {jobStruct.files_mm}; %re_mm end %re_mm + if isfield(jobStruct, 'files_mm_ref') + files_mm_ref = {jobStruct.files_mm_ref}; + end if isfield(jobStruct, 'files_ref') files_ref = {jobStruct.files_ref}; end @@ -224,7 +227,14 @@ end if ~isfield(MRSCont.opts, 'SubSpecAlignment') - MRSCont.opts.SubSpecAlignment = 'L2Norm'; + MRSCont.opts.SubSpecAlignment.mets = 'L2Norm'; + MRSCont.opts.SubSpecAlignment.mm = 'none'; +else if ~isfield(MRSCont.opts.SubSpecAlignment, 'mets') + SubSpecAlignment = MRSCont.opts.SubSpecAlignment; + MRSCont.opts = rmfield(MRSCont.opts,'SubSpecAlignment'); + MRSCont.opts.SubSpecAlignment.mets = SubSpecAlignment; + MRSCont.opts.SubSpecAlignment.mm = 'none'; + end end @@ -236,13 +246,27 @@ MRSCont.opts.editTarget = {'none'}; MRSCont.opts.fit.style = opts.fit.style; if strcmp(opts.fit.style, 'Concatenated') - fprintf('Fitting style was changed to Separate, because this is unedited data. Please indicate otherwise in the csv-file or the GUI \n'); + fprintf('Fitting style was changed to Separate, because this is unedited data.\n'); MRSCont.opts.fit.style = 'Separate'; - end + end + if ~isfield(MRSCont.opts.fit, 'GAP') + MRSCont.opts.fit.GAP.A = []; + MRSCont.opts.fit.GAP.mm = []; + MRSCont.opts.fit.GAP.ref = []; + MRSCont.opts.fit.GAP.ref_mm = []; + MRSCont.opts.fit.GAP.w = []; + end + if ~isfield(MRSCont.opts.fit, 'MeanMM') + MRSCont.opts.fit.MeanMM = 0; + end case 'MEGA' MRSCont.flags.isMEGA = 1; MRSCont.opts.editTarget = editTarget; MRSCont.opts.fit.style = opts.fit.style; + if strcmp(opts.fit.style, 'Concatenated') + fprintf('Fitting style was changed to Separate, because concatenated modeling is still under development.\n'); + MRSCont.opts.fit.style = 'Separate'; + end if isfield(opts.fit, 'coMM3') MRSCont.opts.fit.coMM3 = opts.fit.coMM3; MRSCont.opts.fit.FWHMcoMM3 = opts.fit.FWHMcoMM3; @@ -250,19 +274,79 @@ MRSCont.opts.fit.coMM3 = 'none'; MRSCont.opts.fit.FWHMcoMM3 = 14; end + if ~isfield(MRSCont.opts.fit, 'GAP') + MRSCont.opts.fit.GAP.A = []; + MRSCont.opts.fit.GAP.diff1 = []; + MRSCont.opts.fit.GAP.A_mm = []; + MRSCont.opts.fit.GAP.diff1_mm = []; + MRSCont.opts.fit.GAP.ref = []; + MRSCont.opts.fit.GAP.ref_mm = []; + MRSCont.opts.fit.GAP.w = []; + else if ~isfield(MRSCont.opts.fit.GAP, 'A') + MRSCont.opts.fit.GAP.A = []; + end + if ~isfield(MRSCont.opts.fit.GAP, 'diff1') + MRSCont.opts.fit.GAP.diff1 = []; + end + end + if ~isfield(MRSCont.opts.fit, 'MeanMM') + MRSCont.opts.fit.MeanMM = 0; + end case 'HERMES' MRSCont.flags.isHERMES = 1; MRSCont.opts.editTarget = editTarget; MRSCont.opts.fit.style = opts.fit.style; + if strcmp(opts.fit.style, 'Concatenated') + fprintf('Fitting style was changed to Separate, because concatenated modeling is still under development.\n'); + MRSCont.opts.fit.style = 'Separate'; + end + if ~isfield(MRSCont.opts.fit, 'GAP') + MRSCont.opts.fit.GAP.sum = []; + MRSCont.opts.fit.GAP.diff1 = []; + MRSCont.opts.fit.GAP.diff2 = []; + else if ~isfield(MRSCont.opts.fit.GAP, 'sum') + MRSCont.opts.fit.GAP.sum = []; + end + if ~isfield(MRSCont.opts.fit.GAP, 'diff1') + MRSCont.opts.fit.GAP.diff1 = []; + end + if ~isfield(MRSCont.opts.fit.GAP, 'diff2') + MRSCont.opts.fit.GAP.diff2 = []; + end + end + if ~isfield(MRSCont.opts.fit, 'MeanMM') + MRSCont.opts.fit.MeanMM = 0; + end case 'HERCULES' MRSCont.flags.isHERCULES = 1; MRSCont.opts.editTarget = editTarget; MRSCont.opts.fit.style = opts.fit.style; + if strcmp(opts.fit.style, 'Concatenated') + fprintf('Fitting style was changed to Separate, because concatenated modeling is still under development.\n'); + MRSCont.opts.fit.style = 'Separate'; + end + if ~isfield(MRSCont.opts.fit, 'GAP') + MRSCont.opts.fit.GAP.sum = []; + MRSCont.opts.fit.GAP.diff1 = []; + MRSCont.opts.fit.GAP.diff2 = []; + else if ~isfield(MRSCont.opts.fit.GAP, 'sum') + MRSCont.opts.fit.GAP.sum = []; + end + if ~isfield(MRSCont.opts.fit.GAP, 'diff1') + MRSCont.opts.fit.GAP.diff1 = []; + end + if ~isfield(MRSCont.opts.fit.GAP, 'diff2') + MRSCont.opts.fit.GAP.diff2 = []; + end + end + if ~isfield(MRSCont.opts.fit, 'MeanMM') + MRSCont.opts.fit.MeanMM = 0; + end otherwise error('Invalid job file! seqType must be ''unedited'', ''MEGA'', ''HERMES'', or ''HERCULES''.'); end -% AUtomatically chekc whehther LCModel is used and turn on RAW export +% AUtomatically check whehther LCModel is used and turn on RAW export if strcmp(opts.fit.method, 'LCModel') MRSCont.opts.saveLCM = 1; end @@ -349,6 +433,11 @@ else MRSCont.files_mm = {}; end %re_mm +if exist('files_mm_ref','var') + MRSCont.files_mm_ref = files_mm_ref; +else + MRSCont.files_mm_ref = {}; +end if exist('files_ref','var') MRSCont.files_ref = files_ref; else @@ -376,7 +465,7 @@ end % Check that each array has an identical number of entries -fieldNames = {'files', 'files_ref', 'files_w','files_mm', 'files_nii', 'files_sense'}; +fieldNames = {'files', 'files_ref', 'files_w','files_mm','files_mm_ref', 'files_nii', 'files_sense'}; ctr = 0; for kk = 1:length(fieldNames) if isfield(MRSCont, fieldNames{kk}) @@ -413,7 +502,7 @@ %%% 7. SET FLAGS AND VERSION %%% MRSCont.flags.didJob = 1; MRSCont.loadedJob = jobFile; -MRSCont.ver.Osp = 'Osprey 1.2.0'; +MRSCont.ver.Osp = 'Osprey 2.0.0'; %%% 8. CHECK IF OUTPUT STRUCTURE ALREADY EXISTS IN OUTPUT FOLDER %%% @@ -552,7 +641,13 @@ if isfield(MRSCont,'files_w') MRSCont.files_w = MRSContNew.files_w; end - if isfield(MRSCont,'files_ref') + if isfield(MRSCont,'files_mm') + MRSCont.files_mm = MRSContNew.files_mm; + end + if isfield(MRSCont,'files_mm_ref') + MRSCont.files_mm_ref = MRSContNew.files_mm_ref; + end + if isfield(MRSCont,'files_nii') MRSCont.files_nii = MRSContNew.files_nii; end if isfield(MRSCont,'files_sense') diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey.m index 92d827c9..ae458779 100644 --- a/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey.m +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey.m @@ -47,6 +47,25 @@ % Resample basis set to match data resolution and frequency range resBasisSet = fit_resampleBasis(dataToFit, basisSet); +resBasisSet.names = dataToFit.names; + +% Add individual MM spline in case MM spectra were measured +if isfield(fitOpts,'mm_clean_spline') +mm_clean_spline = op_zeropad(fitOpts.mm_clean_spline, 2); +resBasisSet.nMM = 1; +ind = find(strcmp(resBasisSet.name,'MM09')); +factor = (max(real(resBasisSet.specs(:,ind)))/max(real(mm_clean_spline.specs))); +resBasisSet.fids = resBasisSet.fids(:,1:resBasisSet.nMets); +resBasisSet.specs = resBasisSet.specs(:,1:resBasisSet.nMets); +resBasisSet.name = resBasisSet.name(1:resBasisSet.nMets); +resBasisSet.fids(:,resBasisSet.nMets+1) = mm_clean_spline.fids*factor; +resBasisSet.specs(:,resBasisSet.nMets+1) = mm_clean_spline.specs*factor; +resBasisSet.name{end+1} = 'MMExp'; +resBasisSet.sz = size(resBasisSet.fids); +% figure(1), plot(resBasisSet.ppm, real(resBasisSet.specs(:,19)), resBasisSet.ppm,real(mm_clean_spline.specs)) +end + + %%% 1. EXTRACT OPTIONS AND PREPARE FIT %%% % Extract ppm fit range @@ -99,13 +118,18 @@ % (Worth exploring in future versions by passing the starting values for % the phase corrections as arguments.) if ~isfield(fitOpts, 'MRSIpriors') - fprintf('\nRunning preliminary analysis with reduced basis set...'); - if ~isempty(progressText) - String = get(progressText,'String'); - set(progressText,'String' ,sprintf([String(1,:) '\nRunning preliminary analysis with reduced basis set...\n'])); - drawnow + if ~isfield(fitOpts,'mm_clean_spline') + fprintf('\nRunning preliminary analysis with reduced basis set...'); + if ~isempty(progressText) + String = get(progressText,'String'); + set(progressText,'String' ,sprintf([String(1,:) '\nRunning preliminary analysis with reduced basis set...\n'])); + drawnow + end + [fitParamsStep1] = fit_Osprey_PrelimReduced(dataToFitRef, resBasisSet, fitRangePPM); + else + fprintf('\nTake priors from earlier analysis...'); + fitParamsStep1 = fitOpts.prelimParams; end - [fitParamsStep1] = fit_Osprey_PrelimReduced(dataToFitRef, resBasisSet, fitRangePPM); else fprintf('\nTake priors from center voxel...'); if ~isempty(progressText) @@ -134,24 +158,28 @@ drawnow end -if isfield(fitOpts,'coMM3') && isfield(dataToFit,'refShift') && ~isfield(fitOpts,'Diff2') - switch fitOpts.coMM3 - case '3to2MMsoft' - [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,0.66,'MM'); - case '1to1GABAsoft' - [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,1,'GABA'); - case '3to2GABAsoft' % 3:2 GABA and co-edited MM3 model - [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,0.66,'GABA'); - case '2to3GABAsoft' % 2:3 GABA and co-edited MM3 model - [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,1.5,'GABA'); - case 'freeGauss' % Gauss with free frequency and linewidth - [fitParamsStep2] = fit_OspreyPrelimStep2freeGauss(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM); - resBasisSet = fitParamsStep2.resBasisSetUpdated; - otherwise - [fitParamsStep2] = fit_OspreyPrelimStep2(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM); - end +if ~isfield(fitOpts,'mm_clean_spline') && ~isfield(fitOpts,'GaussLBMM') + if isfield(fitOpts,'coMM3') && isfield(dataToFit,'refShift') && ~isfield(fitOpts,'Diff2') + switch fitOpts.coMM3 + case '3to2MMsoft' + [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,0.66,'MM'); + case '1to1GABAsoft' + [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,1,'GABA'); + case '3to2GABAsoft' % 3:2 GABA and co-edited MM3 model + [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,0.66,'GABA'); + case '2to3GABAsoft' % 2:3 GABA and co-edited MM3 model + [fitParamsStep2] = fit_OspreyPrelimStep2coMM3(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,1.5,'GABA'); + case 'freeGauss' % Gauss with free frequency and linewidth + [fitParamsStep2] = fit_OspreyPrelimStep2freeGauss(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM); + resBasisSet = fitParamsStep2.resBasisSetUpdated; + otherwise + [fitParamsStep2] = fit_OspreyPrelimStep2(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,fitOpts.GAP); + end + else + [fitParamsStep2] = fit_OspreyPrelimStep2(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,fitOpts.GAP); + end else - [fitParamsStep2] = fit_OspreyPrelimStep2(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM); + [fitParamsStep2] = fit_OspreyPrelimStep2MMExp(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,fitOpts.GAP); end % [J,~,CRLB] = fit_Osprey_CRLB(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM,fitParamsStep2,refShift); diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyCleanMM.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyCleanMM.m new file mode 100644 index 00000000..a45cfac0 --- /dev/null +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyCleanMM.m @@ -0,0 +1,113 @@ +% fit_OspreyMM2.m +% Georg Oeltzschner, Johns Hopkins University 2019. +% +% USAGE: +% [fitParams] = fit_Osprey(dataToFit, resBasisSet, fitOpts); +% +% DESCRIPTION: +% THIS RETURNS A CLEANED MM SPECTRUM - need to fix up comments and maybe +% change name to somethign useful + +function [out] = fit_OspreyCleanMM(dataToFit, basisSet, fitOpts,scale,fitParams) + + +%%% 0. PREPARE DATA AND BASIS SET %%% +dataToFit = op_zeropad(dataToFit, 2); + +% switch fitOpts.sequence +% case 'unedited' +% %Invert the NAA, Cr and CrCH2 peaks +% basisSet.specs(:,1)=-basisSet.specs(:,1); +% basisSet.specs(:,2)=-basisSet.specs(:,2); +% basisSet.specs(:,4)=-basisSet.specs(:,4); +% case 'MEGA' +% %Invert the NAA/NAAG peak +% basisSet.specs(:,1)=-basisSet.specs(:,1); +% basisSet.specs(:,2)=-basisSet.specs(:,2); +% end + +basisSet = fit_resampleBasis(dataToFit, basisSet); + +out=dataToFit; + + +%%% 1. EXTRACT OPTIONS AND PREPARE FIT %%% + +% ... fit parameters +nMets = basisSet.nMets; +nMM = basisSet.nMM; +nBasisFcts = nMets + nMM; % number of basis functions +lineShape = fitParams.lineShape; +ph0 = fitParams.ph0 * pi/180; % zero-order phase correction [convert from deg to rad] +ph1 = fitParams.ph1 * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] +gaussLB = fitParams.gaussLB; % Gaussian damping [Hz] +lorentzLB = fitParams.lorentzLB; % Lorentzian damping [Hz] for each basis function +freqShift = fitParams.freqShift; % Frequency shift [Hz] for each basis function +ampl = fitParams.ampl; % Amplitudes for metabolite/MM/lipid basis functions +refShift = fitParams.refShift; % Reference shift applied to the data during first step of fitting + +% Normalize +lineShape = lineShape/sum(lineShape); + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Run the time-domain operations on the metabolite basis functions +% (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) +t = basisSet.t; +%ph0=-ph0; +for ii=1:nBasisFcts + basisSet.fids(:,ii) = basisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + basisSet.fids(:,ii) = basisSet.fids(:,ii) * exp(1i*ph0); +end +basisSet.specs = fftshift(fft(basisSet.fids,[],1),1); + +% Run the frequency-domain operations on the basis functions +% (first order phase correction) +% Cut out the frequency range of the basis set +%basisSet = op_freqrange(basisSet,fitRangePPM(1),fitRangePPM(end),length(splineArray(:,1,1))); +% Create a ppm vector around a pivot point (water) +ppm_ax = basisSet.ppm; +pivotPoint = 4.68; +multiplier = ppm_ax - pivotPoint; +%ph1=-ph1; +% Apply the linear phase correction +for ii=1:nBasisFcts + basisSet.specs(:,ii) = basisSet.specs(:,ii) .* exp(1i*ph1*multiplier); +end +basisSet.fids = ifft(fftshift(basisSet.specs,1),[],1); + + +%%% 3. APPLY THE LINEAR PARAMETERS %%% +% Convolve the lineshape with the metabolite basis functions only +% (NOT the macromolecules or lipids or baseline splines). +A = basisSet.specs; +for kk = 1:basisSet.nMets + A(:,kk) = conv(A(:,kk), lineShape, 'same'); +end + +% Calculate the final metabolite residual + +MetabFit = A(:,1:basisSet.nMets) * ampl(1:basisSet.nMets); +% MetabFit = MetabFit *scale; + + +% Calculate the residual +% Cut out the frequency range of the spectrum to be fit +% Apply initial referencing shift +dataToFit = op_freqshift(dataToFit, -refShift); +%dataToFit.fids = dataToFit.fids * exp(-1i*ph0); +dataToFit.specs = fftshift(fft(dataToFit.fids,[],1),1); +% dataToFit = op_ampScale(dataToFit, scale); +%dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end),length(splineArray(:,1,1))); +%dataToFit.specs = dataToFit.specs .* exp(-1i*ph1*multiplier); +%dataToFit.fids = ifft(fftshift(dataToFit.specs,1),[],1); +out.specs=dataToFit.specs-MetabFit; +out.fids = ifft(fftshift(out.specs,1),[],1); + +out = op_truncate(out,2); +end + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyMM.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyMM.m index 9c6171ce..9a57d299 100644 --- a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyMM.m +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyMM.m @@ -38,7 +38,7 @@ dataToFit = op_zeropad(dataToFit, 2); % Resample basis set to match data resolution and frequency range resBasisSet = fit_resampleBasis(dataToFit, basisSet); - +resBasisSet.names = dataToFit.names; %%% 1. EXTRACT OPTIONS AND PREPARE FIT %%% % Extract ppm fit range @@ -50,19 +50,19 @@ %%% 2. INITIAL REFERENCING %%% % Determine initial coarse frequency shift from cross-correlation with % landmark delta functions for NAA, Cr, Cho. -% if ~isfield(dataToFit,'refShift') %NO referenceing so far +if ~isfield(dataToFit,'refShift') %NO referenceing so far disp('Running initial referencing...'); [refShift, ~] = fit_OspreyReferencingMM(dataToFit); refFWHM = dataToFit.refFWHM; % Apply initial referencing shift dataToFitRef = op_freqshift(dataToFit, -refShift); -% else %Referencing was performed on another Subspec -% disp('Initial was performed on another Subspec...'); -% refShift = dataToFit.refShift; -% refFWHM = dataToFit.refFWHM; -% % Apply initial referencing shift -% dataToFitRef = op_freqshift(dataToFit, -refShift); -% end +else %Referencing was performed on another Subspec + disp('Initial was performed on another Subspec...'); + refShift = dataToFit.refShift; + refFWHM = dataToFit.refFWHM; + % Apply initial referencing shift + dataToFitRef = op_freqshift(dataToFit, -refShift); +end %%% 3. PRELIMINARY ANALYSIS STEP 1 %%% % In step 1 of the preliminary analysis, a reduced basis set (Cr, Glu, Ins, @@ -92,23 +92,6 @@ disp('Running final preliminary analysis step with full basis set...'); [fitParamsStep2] = fit_OspreyPrelimStep2MM(dataToFitRef, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM); -RFWHM = 2.5; % choose slightly larger than the LCM default -convolutionRange = RFWHM * refFWHM/2; -PPMINC = abs(dataToFit.ppm(1) - dataToFit.ppm(2)); -% Calculate number of points -N_s = round(convolutionRange/PPMINC); -if mod(N_s,2) == 0 - N_s = N_s - 1; % make odd number -end -if N_s < 0 - N_s = - N_s; % make odd number -end - -lineShape = zeros(N_s,1); -lineShape(ceil(N_s/2)) = 1; - -% Normalize -lineShape = lineShape/sum(lineShape); %%% 5. CREATE OUTPUT %%% diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyMMGaussians.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyMMGaussians.m new file mode 100644 index 00000000..c519e44b --- /dev/null +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyMMGaussians.m @@ -0,0 +1,66 @@ +% fit_OspreyMM.m +% Georg Oeltzschner, Johns Hopkins University 2019. +% +% USAGE: +% [fitParams] = fit_Osprey(dataToFit, resBasisSet, fitOpts); +% +% DESCRIPTION: +% This is the function describing the Osprey fitting model, which is +% performed with the resampled basis set resBasisSet on the data contained +% in the FID-A data structure dataToFit, using the fit options in the +% structure fitOpts. +% +% This model is attempting to emulate the rather elusive original LCModel +% algorithm (Provencher, Magn Reson Med 30:672-679 (1993)). +% +% OUTPUTS: +% fitParams = Structure containing all necessary fit parameters +% - ampl: amplitudes for metabolite/MM/lipids +% - beta_j: amplitudes for baseline spline functions +% - lineshape: coefficients for lineshape convolution +% - ph0: zero-order phase correction +% - ph1: first-order phase correction +% - gaussLB: Gaussian dampening (common to all basis +% functions) +% - lorentzLB: Lorentzian dampening (individual to each +% basis function) +% - freqShift: frequency shift (individual to each basis +% function) +% +% INPUTS: +% dataToFit = FID-A data structure +% basisSet = FID-A basis set container +% fitOpts = Structure containing fit options + +function [fitParams, resBasisSet] = fit_OspreyMMGaussians(dataToFit, basisSet, fitOpts) + +%%% 0. PREPARE DATA AND BASIS SET %%% +dataToFit = op_zeropad(dataToFit, 2); +% Resample basis set to match data resolution and frequency range +resBasisSet = fit_resampleBasis(dataToFit, basisSet); + + +%%% 1. EXTRACT OPTIONS AND PREPARE FIT %%% +% Extract ppm fit range +fitRangePPM = fitOpts.range; + +dataToFitRef = op_freqshift(dataToFit, -fitOpts.Params2.refShift); +%%% 4. FINAL PRELIMINARY ANALYSIS STEP 2 %%% +% In the final step of the preliminary analysis, the full basis set is used +% with the full LCModel (except for baseline regularization) to obtain +% the final optimal starting values. +disp('Running final preliminary analysis step with full basis set...'); +[fitParamsStep4] = fit_OspreyPrelimStep2MMGaussians(dataToFitRef, resBasisSet, fitRangePPM, fitOpts.Params2); + + + +%%% 5. CREATE OUTPUT %%% +% Return fit parameters +fitParams = fitParamsStep4; +end + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyParamsToModel.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyParamsToModel.m index c5fbb4ab..1aa44375 100644 --- a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyParamsToModel.m +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyParamsToModel.m @@ -56,6 +56,9 @@ ph0 = fitParams.ph0 * pi/180; % zero-order phase correction [convert from deg to rad] ph1 = fitParams.ph1 * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] gaussLB = fitParams.gaussLB; % Gaussian damping [Hz] +if isfield(fitParams,'gaussLBMM') + gaussLBMM = fitParams.gaussLBMM; % Gaussian damping [Hz] +end lorentzLB = fitParams.lorentzLB; % Lorentzian damping [Hz] for each basis function freqShift = fitParams.freqShift; % Frequency shift [Hz] for each basis function ampl = fitParams.ampl; % Amplitudes for metabolite/MM/lipid basis functions @@ -75,9 +78,21 @@ % Run the time-domain operations on the metabolite basis functions % (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) t = basisSet.t; -for ii=1:nBasisFcts - basisSet.fids(:,ii) = basisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; -% basisSet.fids(:,ii) = basisSet.fids(:,ii) * exp(1i*ph0); +if ~isfield(fitParams,'gaussLBMM') + for ii=1:nBasisFcts + basisSet.fids(:,ii) = basisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + % basisSet.fids(:,ii) = basisSet.fids(:,ii) * exp(1i*ph0); + end +else + for ii=1:basisSet.nMets + basisSet.fids(:,ii) = basisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + % basisSet.fids(:,ii) = basisSet.fids(:,ii) * exp(1i*ph0); + end + for ii=basisSet.nMets+1:nBasisFcts + basisSet.fids(:,ii) = basisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLBMM.*t.*t)'; + % basisSet.fids(:,ii) = basisSet.fids(:,ii) * exp(1i*ph0); + end + end basisSet.specs = fftshift(fft(basisSet.fids,[],1),1); @@ -143,5 +158,15 @@ ModelOutput.indivMets(:,kk) = ampl(kk) * A(:,kk); end +if ~isempty(inputSettings.GAP) + GAP = inputSettings.GAP; +% ModelOutput.data(ppm_ax>GAP(1) & ppm_axGAP(1) & ppm_axGAP(1) & ppm_axGAP(1) & ppm_axGAP(1) & ppm_axGAP(2))); +% fit = AB*ampl; +% fit = vertcat(fit(ppm_axGAP(2))); + F = vertcat(F(ppm_axGAP(2))); +end %%% 5. CALCULATE ANALYTIC JACOBIAN % j = sqrt(-1); % i % @@ -631,6 +640,7 @@ splineArray = inputData.splineArray; % ... settings: fitRangePPM = inputSettings.fitRangePPM; +GAP = inputSettings.GAP; % ... fit parameters nMets = resBasisSet.nMets; nMM = resBasisSet.nMM; @@ -699,6 +709,11 @@ data = real(dataToFit.specs); b = data; +if ~isempty(GAP) + b = vertcat(b(ppm_axGAP(2))); + AB = vertcat(AB(ppm_axGAP(2),:)); +end + % The function we want to minimize is the sum of squares of the residual fcn = @(x) norm( AB*x - b)^2; AtA = AB'*AB; Ab = AB'*b; diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MM.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MM.m index 63ce9331..81c08eb7 100644 --- a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MM.m +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MM.m @@ -601,16 +601,18 @@ fitParamsFinal.beta_j = ampl(size(A,2)+1:end); % Plot (comment out if not debugging) -% figure(99) +% figure % plot(data); hold; % plot(AB*ampl); % plot(B*ampl(size(A,2)+1:end)); plot(data - (AB*ampl) + 1.1*max(data)); +% plot(data - (A*ampl(1:size(A,2)))+ 1.6*max(data)); % for rr = 1:(nMets+nMM) -% plot(ampl(rr)*A(:,rr)); +% plot(ampl(rr)*A(:,rr)- 1.1*max(data)); % end % title('Preliminary Analysis with full basis set (unregularized)'); % hold; + end diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MMExp.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MMExp.m new file mode 100644 index 00000000..dda27ad0 --- /dev/null +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MMExp.m @@ -0,0 +1,799 @@ +function [fitParamsStep2] = fit_OspreyPrelimStep2MMExp(dataToFit, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM,GAP) +%% [fitParamsStep2] = fit_OspreyPrelimStep2(dataToFit, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM) +% Performs the second step of the LCModel preliminary analysis +% according to the LCModel algorithm. The algorithm is described in: +% S.W. Provencher, "Estimation of metabolite concentrations from +% localized in vivo NMR spectra", Magn Reson Med 30(6):672-679 (1993) +% +% During the second step, the input spectrum is fit using the full basis +% set allowing individual frequency shifts and Lorentzian dampening +% for each metabolite basis function. Additionally, a lineshape +% convolution is applied to account for deviations from the ideal +% Voigtian lineshape (= Gaussian/Lorentzian convolution). + +% In addition, pre-defined macromolecule and lipid basis functions are +% added, as well as an unregularized baseline. MM/lipids and the baseline +% are phased with the same phasing parameters as the metabolites, but the +% lineshape convolution is not applied to them. +% +% Input: +% dataToFit = FID-A data structure +% basisSet = FID-A basis set container +% minKnotSpacing = Scalar: minimum baseline knot spacing +% (this is the DKNTMN parameter in LCModel) +% fitRangePPM = 2-element vector: fit range [ppm] +% (this is the range over which the difference +% between spectrum and model is minimized) +% fitParamsStep1 = Fit parameters from the first preliminary +% analysis +% refFWHM = Preliminary linewidth estimate (in ppm) that is +% used to determine the width of the lineshape +% function that the basis functions are +% subsequently convolved with +% Output: +% fitParamsStep2 = Fit parameters: +% - amplitudes of basis functions +% - zero-order phase [deg] +% - first-order phase [deg/ppm] +% - Gaussian LB [Hz] +% - Lorentzian LB [Hz] +% - global frequency shift [Hz] +% +% Author: +% Dr. Georg Oeltzschner (Johns Hopkins University, 2020-01-14) +% goeltzs1@jhmi.edu +% +% History: +% 2020-01-14: First version of the code. +% + +%%% 1. SET UP EXPECTATION VALUES AND SPLINE BASIS FUNCTIONS %%% +% Generate the expectation values and standard deviation values for the +% delta (1/T2) Lorentzian linebroadening and the frequency shift parameter +% in LCModel. +% See LCModel manual, Section 11.14 (p. 149) +[EXT2, SDT2, SDSH] = fit_setExpectValues(dataToFit, resBasisSet); + +% Create an array of normalized cubic baseline spline basis functions. +[splineArray] = fit_makeSplineBasis(dataToFit, fitRangePPM, minKnotSpacingPPM); +nSplines = size(splineArray,2); + + +%%% 2. SET AND GET STARTING VALUES %%% +% Set the starting values for the non-linear parameters to be passed on +% to the Levenberg-Marquardt NLLS solving algorithm. Note that the +% amplitude parameters do not need to be initialized, as the +% non-negative linear Lawson-Hanson solver does not require starting +% values to be provided. +nBasisFcts = resBasisSet.nMets + resBasisSet.nMM; % number of basis functions +ph0 = fitParamsStep1.ph0; % zero-order phase correction [deg] +ph1 = fitParamsStep1.ph1; % first-order phase correction [deg/ppm] +gaussLB = fitParamsStep1.gaussLB; % Gaussian dampening [Hz] +gaussLBMM = 0.04 * dataToFit.txfrq*1e-6; % Common Gaussian dampening [Hz] +lorentzLB = EXT2'; % Lorentzian dampening [Hz] for each basis function +freqShift = fitParamsStep1.freqShift * zeros(nBasisFcts,1); % Frequency shift [Hz] for each basis function +ampl = zeros(nBasisFcts+nSplines,1); % Amplitude parameters for basis functions and baseline + +% Create the lineshape starting values +% Set up the convolution (see LCModel manual Sec 11.12, p. 148) +RFWHM = 2.5; % choose slightly larger than the LCM default +convolutionRange = RFWHM * refFWHM/2; +PPMINC = abs(dataToFit.ppm(1) - dataToFit.ppm(2)); +% Calculate number of points +N_s = round(convolutionRange/PPMINC); +%%% OPTION A - CREATE INITIAL GUESS FROM CR SINGLET %%% +% % Apply the linebroadening parameters to the Cr singlet in order to obtain +% % an initial lineshape model +% % Find the creatine basis function +% idx_Cr = find(strcmp(resBasisSet.name,'Cr')); +% if isempty(idx_Cr) +% error('No basis function with nametag ''Cr'' found! Abort!'); +% end +% t = resBasisSet.t; +% CrFID = resBasisSet.fids(:,idx_Cr,1) .* exp(-gaussLB^2.*t.*t)' .* exp(-lorentzLB(idx_Cr).*t)'; +% CrSPEC = fftshift(fft(CrFID,[],1),1); +% % Cut out N_s points around the maximum +% [~, maxCr_idx] = max(abs(real(CrSPEC))); +% if mod(N_s,2) == 0 +% lineShape = real(CrSPEC(maxCr_idx-N_s/2:maxCr_idx+N_s/2)); +% else +% lineShape = real(CrSPEC(maxCr_idx-floor(N_s/2):maxCr_idx+ceil(N_s/2))); +% end +%%% OPTION B - CREATE INITIAL GUESS AS DELTA FUNCTION %%% +% Initialize as delta function +if mod(N_s,2) == 0 + N_s = N_s - 1; % make odd number +end +if N_s == 0 + N_s=1; +end + +if N_s < 0 + N_s=-N_s; +end + +lineShape = zeros(N_s,1); +lineShape(ceil(N_s/2)) = 1; + +% Normalize +lineShape = lineShape/sum(lineShape); + +% Concatenate all initial guesses together into one large x0 vector. +x0 = [ph0; ph1; gaussLB; gaussLBMM; lorentzLB; freqShift; ampl; lineShape]; + + +%%% 3. CLL NON-LINEAR SOLVER %%% +% Run the non-linear solver to optimize the non-linear parameters. At each +% iteration of the non-linear least squares solver, the linear parameters +% are calculated separately (similar to the VARiable PROjection algorithm). +% +% We're using a Levenberg-Marquardt implementation for the non-linear +% problem that allows us to impose hard box constraints on the non-linear +% parameters, keeping them within reasonable limits. +% (c) Alexander Drentler +% https://www.mathworks.com/matlabcentral/fileexchange/53449-levenberg-marquardt-toolbox + +% Initial regularization parameter close to zero +regParameter = 2e-2; +% Pack everything up into structs to pass it on to the solver. +% ... data: +inputData.dataToFit = dataToFit; +inputData.resBasisSet = resBasisSet; +inputData.splineArray = splineArray; +% Get an estimate for the standard deviation of the noise +% This is to calculate a Q factor, but need to normalize this noise value +% here - leave alone for now +if max(dataToFit.ppm > 10) + noiseRange = (dataToFit.ppm > 9); +else + noiseRange = (dataToFit.ppm < -2); +end +dataNoise = real(dataToFit.specs(noiseRange,1)); +dataNoise = detrend(dataNoise); +stdNoise = std(dataNoise); +inputData.stdNoise = stdNoise; +% ... settings: +inputSettings.fitRangePPM = fitRangePPM; +inputSettings.regParameter = regParameter; +inputSettings.EXT2 = EXT2'; +inputSettings.SDT2 = SDT2'; +inputSettings.SDSH = SDSH'; +inputSettings.GAP = GAP; + +% Set the hard box constraints for the parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +lb_ph0 = -45; +ub_ph0 = +45; % Zero order phase shift [deg] +lb_ph1 = -20; +ub_ph1 = +20; % First order phase shift [deg/ppm] +lb_gaussLB = 0; +ub_gaussLB = sqrt(5000); % Gaussian dampening [Hz] +lb_gaussLBMM = 0; +ub_gaussLBMM = sqrt(5000); % Gaussian dampening [Hz] +lb_lorentzLB_mets = zeros(nMets, 1); +ub_lorentzLB_mets = 10.0 * ones(nMets, 1); % Lorentzian dampening [Hz] - Metabolites +lb_lorentzLB_MM = zeros(nMM, 1); +ub_lorentzLB_MM = 100 * ones(nMM, 1); % Lorentzian dampening [Hz] - MM/Lipids +lb_freqShift_mets = -4.0 * ones(nMets,1); +ub_freqShift_mets = +4.0 * ones(nMets,1); % Frequency shift [Hz] - Metabolites +lb_freqShift_MM = -4 * ones(nMM,1); +ub_freqShift_MM = +4 * ones(nMM,1); % Frequency shift [Hz] - MM/Lipids +lb_ampl = -Inf * ones(nMets+nMM+size(splineArray,2),1); +ub_ampl = +Inf * ones(nMets+nMM+size(splineArray,2),1); % Amplitude for metabolite and spline basis functions +lb_lineShape = -Inf * ones(size(lineShape)); +ub_lineShape = +Inf * ones(size(lineShape)); % Lineshape coefficients + +% Concatenate together into LB/UB vectors +lb = [lb_ph0; lb_ph1; lb_gaussLB; lb_gaussLBMM; lb_lorentzLB_mets; lb_lorentzLB_MM; lb_freqShift_mets; lb_freqShift_MM; lb_ampl; lb_lineShape]; +ub = [ub_ph0; ub_ph1; ub_gaussLB; ub_gaussLBMM; ub_lorentzLB_mets; ub_lorentzLB_MM; ub_freqShift_mets; ub_freqShift_MM; ub_ampl; ub_lineShape]; + + +% Set up and run the non-linear solver. +opts.Display = 'off'; +opts.TolFun = 1e-6; +opts.TolX = 1e-6; +opts.MaxIter = 400; +% opts.Jacobian = 'on'; +% opts.Broyden_updates=2; +[x,Res,~,~,~,~,~,J] = LevenbergMarquardt(@(x) fit_Osprey_PrelimStep2_Model(x, inputData, inputSettings), x0, lb, ub, opts); + + +%%% 4. PERFORM FINAL COMPUTATION OF LINEAR PARAMETERS %%% +% After the non-linear optimization is finished, we need to perform the +% final evaluation of the linear parameters (i.e. the amplitudes and +% baseline parameters). +[fitParamsFinal] = fit_Osprey_PrelimStep2_finalLinear(x, inputData, inputSettings); +fitParamsFinal.Res = Res; +fitParamsFinal.J = J; + +%%% 5. CREATE OUTPUT %%% +% Return the fit parameters from the final linear computation to be used in +% the next LCModel analysis step (i.e. the fit with the full basis set): +fitParamsStep2 = fitParamsFinal; + + +end + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%% MODEL FUNCTION %%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% LCModel preliminary analysis step 2 model +function [F,J] = fit_Osprey_PrelimStep2_Model(x, inputData, inputSettings) +% This function receives the current set of non-linear parameters during +% every iteration of the non-linear least-squares optimization. The +% parameters are applied to the basis set. +% +% Then, a limited-memory Broyden-Fletcher-Goldfarb-Shanno solver allowing +% for boxed constraints is applied to determine the optimal amplitudes of +% the linear parameters to the current set of non-linear parameters. +% +% The linear parameters are usually the amplitudes for the basis +% functions and cubic baseline splines. +% +% This function returns the difference between the input data and +% the current optimized model. This difference is used by the NLLS +% solver. +% +% USAGE: +% F = fit_LCModel_PrelimStep2_Model(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% F = Difference between data and model. This is the +% objective to be least-squares-optimized by the +% non-linear solver. + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +resBasisSet = inputData.resBasisSet; +splineArray = inputData.splineArray; +stdNoise = inputData.stdNoise; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +regParameter = inputSettings.regParameter; +EXT2 = inputSettings.EXT2; +SDT2 = inputSettings.SDT2; +SDSH = inputSettings.SDSH; +GAP = inputSettings.GAP; +% ... fit parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +nBasisFcts = nMets + nMM; % number of basis functions +nSplines = size(splineArray,2); % number of spline basis functions +ph0 = x(1) * pi/180; % zero-order phase correction [convert from deg to rad] +ph1 = x(2) * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] +gaussLB = x(3); % Gaussian dampening [Hz^2] +gaussLBMM = x(4); % Gaussian dampening [Hz^2] +lorentzLB = x(5:nBasisFcts+4); % Lorentzian dampening [Hz] for each basis function +freqShift = x(nBasisFcts+5:2*nBasisFcts+4); % Frequency shift [Hz] for each basis function +ampl = x(2*nBasisFcts+5:3*nBasisFcts+4+nSplines); % Amplitudes +lineShape = x(3*nBasisFcts+5+nSplines:end); % Lineshape coefficients +% Normalize the lineshape +lineShape = lineShape/sum(lineShape); + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Run the time-domain operations on the metabolite basis functions +% (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) +t = resBasisSet.t; +for ii=1:resBasisSet.nMets + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +for ii=resBasisSet.nMets+1:nBasisFcts + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLBMM.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +resBasisSet.specs = fftshift(fft(resBasisSet.fids,[],1),1); + +% Run the frequency-domain operations on the basis functions +% (first order phase correction) +% Cut out the frequency range of the basis set +resBasisSet = op_freqrange(resBasisSet,fitRangePPM(1),fitRangePPM(end),length(splineArray(:,1,1))); +% Create a ppm vector around a pivot point (water) +ppm_ax = resBasisSet.ppm; +pivotPoint = 4.68; +multiplier = ppm_ax - pivotPoint; +% Apply the linear phase correction +for ii=1:nBasisFcts + resBasisSet.specs(:,ii) = resBasisSet.specs(:,ii) .* exp(1i*ph1*multiplier); +end +resBasisSet.fids = ifft(fftshift(resBasisSet.specs,1),[],1); + +% Apply phasing to the spline basis functions +B = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +B = B * exp(1i*ph0); +B = B .* exp(1i*ph1*multiplier); +B = [real(B)]; + + +%%% 3. SET UP THE LINEAR SOLVER %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) + +% Convolve the lineshape with the metabolite basis functions only +% (NOT the macromolecules or lipids or baseline splines). +A = real(resBasisSet.specs); +for kk = 1:resBasisSet.nMets + A(:,kk) = conv(A(:,kk), lineShape, 'same'); +end + +% Concatenate the metabolite/MM/lipid basis functions and the baseline basis +% functions +AB = [A B]; +% Cut out the data over the fit range, and use real part only +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end),length(splineArray(:,1,1))); +data = real(dataToFit.specs); +b = data; + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( AB*x - b)^2; +AtA = AB'*AB; Ab = AB'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [zeros(nMets+nMM,1); -inf*ones(nSplines,1)]; +u = [inf*ones(nMets+nMM,1); inf*ones(nSplines,1)]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. ADD SOFT CONSTRAINTS ON AMPLITUDES %%% +% To impose soft constraints on the amplitudes, we can augment the problem +% with additional rows in the equation system. This is done in the function +% fit_createSoftConstrOsprey. +% (see Wilson et al., MRM 2011) +[augmA, augmb] = fit_createSoftConstrOsprey(resBasisSet, AB, b, ampl); +A_augB = [AB; augmA]; +b_aug = [b; augmb]; + +% Now, run the L-BFGS-B algorithm again with the augmented equation system +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A_augB*x - b_aug)^2; +AtA = A_augB'*A_augB; A_augb = A_augB'*b_aug; +grad = @(x) 2*( AtA*x - A_augb ); +% Prepare the function wrapper +fun = @(x)fminunc_wrapper(x, fcn, grad); +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb( fun, l, u, opts ); + + +%%% 4. CREATE OBJECTIVE FUNCTION +% The objective function to be minimized by the non-linear least squares +% solver is the fit residual. +% +% The LCModel algorithm wants to minimize not only the sum of squares +% between the data and the model, but imposes regularization on several +% parameters. +% Therefore, we have to reconstruct the fit spectrum from the parameters we +% derived, and then calculate the sum of squares ourselves, in addition to +% the penalty terms. +% For the last step of the preliminary analysis, this is done without any +% regularization at all. + +% Calculate the sum of squares +SOS = sum((data - AB*ampl).^2); + +% Calculate the baseline regularization penalty term +% Extract the baseline coefficients +beta_j = ampl(size(A,2)+1:end); +% Create the analytical regularizor matrix specified in Eq (3.13) in the +% original publication of the CONTIN algorithm behind LCModel: +% Provencher, Comp Phys Comm 27:213-227 (1982) +% First, create a banded Toeplitz matrix +n = length(beta_j); +e = ones(n,1); +K = spdiags([1*e 0*e -9*e 16*e -9*e 0*e 1*e], -3:3, n, n); +K = full(K); +% Then, correct the first two and last two lines according to the above +% paper +K(1, 1:4) = [8 -6 0 1]; +K(2, 1:5) = [-6 14 -6 0 1]; +K(end-1, end-4:end) = [1 0 -6 14 -6]; +K(end, end-3:end) = [1 0 -6 8]; +% Bring in the factor of 1/6 +K = 1/6 .* K; +% Additionally, bring in the geometric factor delta, which is the knot +% spacing, ie delta = range/(number of segments). +% !!! THIS ISN'T CLEARLY UNDERSTOOD YET !!! +normalizationFactor = 1/(size(splineArray,1)/(size(splineArray,2)-1))^3; +% Final regularization penalty +regB = norm(regParameter*sqrtm(full(K))*beta_j*1/(mean(beta_j)))^2; + +% Calculate the penalty term for the Lorentzian linebroadening and +% frequency shifts +penaltyLBFS = sum((lorentzLB - EXT2).^2./(SDT2).^2 + (freqShift.^2)./(SDSH.^2)); + +% Return the loss function +% F = 1/sqrt(stdNoise) * SOS + regB + penaltyLBFS; +% This would be the classic LCModel function to be minimized +% For the preliminary step, just return the functional without any regularization +F = (data - AB*ampl); + + +if ~isempty(GAP) +% data = vertcat(data(ppm_axGAP(2))); +% fit = AB*ampl; +% fit = vertcat(fit(ppm_axGAP(2))); + F = vertcat(F(ppm_axGAP(2))); +end +%%% 5. CALCULATE ANALYTIC JACOBIAN +% j = sqrt(-1); % i +% +% % Model function +% % Y(f) = exp(i(ph0+ph1(f))) * (sum(betaj * B) + sum(amp conv(M, lineshape)) +% % with M = fft(basisSet.fids .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)') +% % The derivatives are 'easier' in the time-domain, so we will stick with +% % the FIDS for the calculations +% +% % dimensions and number of matrix entries +% [npoints,~] = size(resBasisSet.fids); %number of points and number of basis functions +% t = resBasisSet.t; +% +% % % Apply phasing to the spline basis functions +% Acomp = resBasisSet.specs; +% for kk = 1:resBasisSet.nMets +% Acomp(:,kk) = conv(Acomp(:,kk), lineShape, 'same'); +% end +% +% Bcomp = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +% Bcomp = Bcomp * exp(1i*ph0); +% Bcomp = Bcomp .* exp(1i*ph1*multiplier); +% +% ABcomp = [Acomp Bcomp]; +% completeFit = ABcomp*ampl; +% +% +% %Computation of the Jacobian +% % The size is MxN with M (number of estimated parameters) and N (number of +% % points). +% %Store the indices of the different partial derivatives +% ph0Col = 1; +% ph1Col = 2; +% gaussLBCol = 3 * ones(1,nMets + nMM); +% lorentzLBCol = gaussLBCol(end) + 1 : (gaussLBCol(1) + nMets + nMM); +% freqShiftCol = lorentzLBCol(end) + 1 : (lorentzLBCol(end) + nMets + nMM); +% AmplCol = freqShiftCol(end) + 1 : (freqShiftCol(end) + nMets + nMM); +% SplineAmplCol = AmplCol(end) + 1 : (AmplCol(end) + size(splineArray,2)); +% lineshapeCol = SplineAmplCol(end)+1 : SplineAmplCol(end) + length(lineShape); +% +% nparams = 3 + length(lorentzLBCol) + length(freqShiftCol) + length(AmplCol) + length(SplineAmplCol) + length(lineshapeCol); +% +% J = zeros(npoints,nparams); +% Jfd = zeros(npoints,nparams); +% +% +% %derivative wrt ph0 +% % for ii = 1:nMets +% % col = ph0Col(ii); +% % J(:,col) = J(:,col)+j*basisSet.fids(:,ii)*ampl(ii); +% % Jfd(:,col) = fftshift(fft(J(:,col),[],1),1); +% % Jfd(:,col) = conv(Jfd(:,col), lineShape, 'same') + B * beta_j; +% % end +% Jfd(:,1) = j * completeFit; +% +% %derivative wrt ph1 +% % for ii = 1:nBasisFcts +% % col = ph1Col(ii); +% % J(:,col) = J(:,col)+j*basisSet.fids(:,ii)*ampl(ii); +% % Jfd(:,col) = fftshift(fft(J(:,col),[],1),1); +% % Jfd(:,col) = conv(Jfd(:,col), lineShape, 'same') + B * beta_j; +% % end +% Jfd(:,2) = j * completeFit .* multiplier; +% +% %derivative wrt gaussLB +% for ii = 1:nBasisFcts +% if ii <= nMets % Sum up derivarives of all metabolite functions first +% col = gaussLBCol(ii); +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*(t.^2)'; +% Jfd(:,col) = Jfd(:,col) + conv(fftshift(fft(-resBasisSet.fids(:,ii).*(t.^2)',[],1),1), lineShape, 'same')*ampl(ii); +% else % No convolution is applied to the MM functions +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*(t.^2)'; +% Jfd(:,col) = Jfd(:,col) + fftshift(fft(-resBasisSet.fids(:,ii).*(t.^2)',[],1),1)*ampl(ii); +% end +% end +% +% +% %derivative wrt lorentzLB +% for ii = 1:nBasisFcts +% if ii <= nMets % Sum up derivarives of all metabolite functions first +% col = lorentzLBCol(ii); +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + conv(fftshift(fft(J(:,col),[],1),1), lineShape, 'same')*ampl(ii); +% else % No convolution is applied to the MM functions +% col = lorentzLBCol(ii); +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + fftshift(fft(J(:,col),[],1),1)*ampl(ii); +% end +% end +% +% %derivative wrt freqShift +% for ii=1:nBasisFcts +% if ii <= nMets % Sum up derivarives of all metabolite functions first +% col = freqShiftCol(ii); +% J(:,col) = J(:,col)-j*resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + conv(fftshift(fft(J(:,col),[],1),1), lineShape, 'same')*ampl(ii); +% else % No convolution is applied to the MM functions +% col = freqShiftCol(ii); +% J(:,col) = J(:,col)-j*resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + fftshift(fft(J(:,col),[],1),1)*ampl(ii); +% end +% end +% +% % derivative wrt basis set amplitudes +% for ii=1:nBasisFcts +% if ii <= nMets +% col = AmplCol(ii); +% J(:,col) = resBasisSet.fids(:,ii); +% Jfd(:,col) = conv(fftshift(fft(J(:,col),[],1),1), lineShape, 'same'); +% else +% col = AmplCol(ii); +% J(:,col) = resBasisSet.fids(:,ii); +% Jfd(:,col) = fftshift(fft(J(:,col),[],1),1); +% end +% end +% +% +% % derivative wrt spline amplitudes +% for ii=1:length(SplineAmplCol) +% col = SplineAmplCol(ii); +% Jfd(:,col) = Jfd(:,col)+Bcomp(:,ii); +% end +% +% +% %derivative wrt lineshape +% % We will do a discrete convolution of S'*M by using the Toeplitz matrix +% % form of the partial derivative of the lineshape vector S and M beeing +% % the metabolite basis functions. This is allowed as convolutions are +% % commutative and (M*S)' = M'*S = M*S' -> (M*S)' = S'*M. +% +% %We need to create S' as a Toeplitz matrix. The derivatives will +% %essantially be ones on the diagonal (first lineshape coeff) or the upper off +% %diagonal (all other lineshape coeff). +% +% nLineShape = length(lineShape); +% nPoints = length(resBasisSet.fids(:,1)); +% +% %Set up the first rows of each partial derivative +% Toep1row = zeros(nLineShape,nPoints); +% for ii = 1 : nLineShape +% Toep1row(ii,ii) = 1; +% end +% +% %We will set it up as a 3D vector with the partial derivatives in the third dimensions and the +% %Toeplitz matrix spanning the first two dimensions. +% ToepLineShape = zeros(nPoints,nPoints,nLineShape); +% for ii = 1 : nLineShape +% if ii <= 1 +% ToepLineShape(:,:,ii) = toeplitz(Toep1row(ii,:)); +% else +% ToepLineShape(:,:,ii) = tril(toeplitz(Toep1row(ii,:))); % extract lower triangle of the Toeplitz matrix +% end +% end +% +% for ii=1:nLineShape % Loop over the lineshape derivatives +% col = lineshapeCol(ii); +% for kk = 1 : nMets % Convolute all basis functions to create the full model function +% J(:,col) = J(:,col)+resBasisSet.fids(:,kk); +% Jfd(:,col) = Jfd(:,col) + ampl(kk)*(ToepLineShape(:,:,ii) * fftshift(fft(resBasisSet.fids(:,kk),[],1),1)); +% end +% +% end +% +% J = real(Jfd); + +end + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%% FINAL LINEAR ITERATION %%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [fitParamsFinal] = fit_Osprey_PrelimStep2_finalLinear(x, inputData, inputSettings) +% This function is applied after the final iteration of the non-linear +% solver has returned the final set of non-linear parameters. +% +% At this point, the linear solver has to be run one last time to +% estimate the final set of linear parameters. +% +% The function returns all model parameters. +% +% USAGE: +% fitParamsFinal = fit_finalLinearSolver(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% fitParamsFinal = Set of final fit parameters + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +resBasisSet = inputData.resBasisSet; +splineArray = inputData.splineArray; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +GAP = inputSettings.GAP; +% ... fit parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +nBasisFcts = nMets + nMM; % number of basis functions +nSplines = size(splineArray,2); +ph0 = x(1) * pi/180; % zero-order phase correction [convert from deg to rad] +ph1 = x(2) * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] +gaussLB = x(3); % Gaussian dampening [Hz^2] +gaussLBMM = x(4); % Gaussian dampening [Hz^2] +lorentzLB = x(5:nBasisFcts+4); % Lorentzian dampening [Hz] for each basis function +freqShift = x(nBasisFcts+5:2*nBasisFcts+4); % Frequency shift [Hz] for each basis function +ampl = x(2*nBasisFcts+5:3*nBasisFcts+4+nSplines); % Amplitudes +lineShape = x(3*nBasisFcts+5+nSplines:end); % Lineshape coefficients +% Normalize +lineShape = lineShape/sum(lineShape); + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Run the time-domain operations on the metabolite basis functions +% (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) +t = resBasisSet.t; +for ii=1:resBasisSet.nMets + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +for ii=resBasisSet.nMets:nBasisFcts + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLBMM.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +resBasisSet.specs = fftshift(fft(resBasisSet.fids,[],1),1); + +% Run the frequency-domain operations on the basis functions +% (first order phase correction) +% Cut out the frequency range of the basis set +resBasisSet = op_freqrange(resBasisSet,fitRangePPM(1),fitRangePPM(end),length(splineArray(:,1,1))); +ppm_ax = resBasisSet.ppm; +pivotPoint = 4.68; +multiplier = ppm_ax - pivotPoint; +for ii=1:nBasisFcts + resBasisSet.specs(:,ii) = resBasisSet.specs(:,ii) .* exp(1i*ph1*multiplier); +end +resBasisSet.fids = ifft(fftshift(resBasisSet.specs,1),[],1); + +% Apply phasing to the spline basis functions +B = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +B = B * exp(1i*ph0); +B = B .* exp(1i*ph1*multiplier); +B = [real(B)]; + + +%%% 3. SET UP AND CALL SOLVER FOR LINEAR PARAMETERS %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) + +% Set up the equation system to be solved +% Convolve the lineshape with the metabolite basis functions only +% (NOT the macromolecules or lipids or baseline splines). +A = real(resBasisSet.specs); +for kk = 1:resBasisSet.nMets + A(:,kk) = conv(A(:,kk), lineShape, 'same'); +end + +% Concatenate the metabolite/MM/lipid basis functions and the baseline basis +% functions +AB = [A B]; +% Cut out the data over the fit range, and use real part only +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end),length(splineArray(:,1,1))); +data = real(dataToFit.specs); +b = data; + +if ~isempty(GAP) + b = vertcat(b(ppm_axGAP(2))); + AB = vertcat(AB(ppm_axGAP(2),:)); +end + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( AB*x - b)^2; +AtA = AB'*AB; Ab = AB'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [zeros(nMets+nMM,1); -inf*ones(nSplines,1)]; +u = [inf*ones(nMets+nMM,1); inf*ones(nSplines,1)]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. ADD SOFT CONSTRAINTS ON AMPLITUDES %%% +% To impose soft constraints on the amplitudes, we can augment the problem +% with additional rows in the equation system. This is done in the function +% fit_createSoftConstrOsprey. +% (see Wilson et al., MRM 2011) +[augmA, augmb] = fit_createSoftConstrOsprey(resBasisSet, AB, b, ampl); +A_augB = [AB; augmA]; +b_aug = [b; augmb]; + +% Now, run the L-BFGS-B algorithm again with the augmented equation system +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A_augB*x - b_aug)^2; +AtA = A_augB'*A_augB; A_augb = A_augB'*b_aug; +grad = @(x) 2*( AtA*x - A_augb ); +% Prepare the function wrapper +fun = @(x)fminunc_wrapper(x, fcn, grad); +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb( fun, l, u, opts ); + + +%%% 5. CREATE OUTPUT %%% +% Return the final fit parameters +fitParamsFinal.ampl = ampl(1:size(A,2)); +fitParamsFinal.ph0 = x(1); +fitParamsFinal.ph1 = x(2); +fitParamsFinal.gaussLB = x(3); +fitParamsFinal.gaussLBMM = x(4); +fitParamsFinal.lorentzLB = x(5:nBasisFcts+4); +fitParamsFinal.freqShift = x(nBasisFcts+5:2*nBasisFcts+4); +fitParamsFinal.lineShape = x(3*nBasisFcts+5+size(splineArray,2):end); +fitParamsFinal.beta_j = ampl(size(A,2)+1:end); + +% % Plot (comment out if not debugging) +% figure(99) +% plot(data); hold; +% plot(AB*ampl); +% plot(B*ampl(size(A,2)+1:end)); plot(data - (AB*ampl) + 1.1*max(data)); +% for rr = 1:(nMets+nMM) +% plot(ampl(rr)*A(:,rr)); +% end +% title('Preliminary Analysis with full basis set (unregularized)'); +% hold; + + +end + diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MMGaussians.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MMGaussians.m new file mode 100644 index 00000000..25d83aa2 --- /dev/null +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep2MMGaussians.m @@ -0,0 +1,450 @@ +function [fitParamsStep2] = fit_OspreyPrelimStep2MMGaussians(dataToFit, resBasisSet, fitRangePPM, fitParamsStep1) +%% [fitParamsStep2] = fit_OspreyPrelimStep2MM(dataToFit, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM) +% Performs the second step of the LCModel preliminary analysis +% according to the LCModel algorithm. The algorithm is described in: +% S.W. Provencher, "Estimation of metabolite concentrations from +% localized in vivo NMR spectra", Magn Reson Med 30(6):672-679 (1993) +% +% During the second step, the input spectrum is fit using the full basis +% set allowing individual frequency shifts and Lorentzian dampening +% for each metabolite basis function. Additionally, a lineshape +% convolution is applied to account for deviations from the ideal +% Voigtian lineshape (= Gaussian/Lorentzian convolution). + +% In addition, pre-defined macromolecule and lipid basis functions are +% added, as well as an unregularized baseline. MM/lipids and the baseline +% are phased with the same phasing parameters as the metabolites, but the +% lineshape convolution is not applied to them. +% +% Input: +% dataToFit = FID-A data structure +% basisSet = FID-A basis set container +% minKnotSpacing = Scalar: minimum baseline knot spacing +% (this is the DKNTMN parameter in LCModel) +% fitRangePPM = 2-element vector: fit range [ppm] +% (this is the range over which the difference +% between spectrum and model is minimized) +% fitParamsStep1 = Fit parameters from the first preliminary +% analysis +% refFWHM = Preliminary linewidth estimate (in ppm) that is +% used to determine the width of the lineshape +% function that the basis functions are +% subsequently convolved with +% Output: +% fitParamsStep2 = Fit parameters: +% - amplitudes of basis functions +% - zero-order phase [deg] +% - first-order phase [deg/ppm] +% - Gaussian LB [Hz] +% - Lorentzian LB [Hz] +% - global frequency shift [Hz] +% +% Author: +% Dr. Georg Oeltzschner (Johns Hopkins University, 2020-01-14) +% goeltzs1@jhmi.edu +% +% History: +% 2020-01-14: First version of the code. +% + +%%% 2. SET AND GET STARTING VALUES %%% +% Set the starting values for the non-linear parameters to be passed on +% to the Levenberg-Marquardt NLLS solving algorithm. Note that the +% amplitude parameters do not need to be initialized, as the +% non-negative linear Lawson-Hanson solver does not require starting +% values to be provided. +nBasisFcts = resBasisSet.nMets + resBasisSet.nMM; % number of basis functions +ph0 = fitParamsStep1.ph0; % zero-order phase correction [deg] +ph1 = fitParamsStep1.ph1; % first-order phase correction [deg/ppm] +gaussLB = 0; % Gaussian dampening [Hz] +lorentzLB = ones(nBasisFcts,1); % Lorentzian dampening [Hz] for each basis function +freqShift = ones(nBasisFcts,1); % Frequency shift [Hz] for each basis function +ampl = zeros(nBasisFcts,1); % Amplitude parameters for basis functions and baseline + +% Concatenate all initial guesses together into one large x0 vector. +x0 = [ph0; ph1; gaussLB; lorentzLB; freqShift; ampl]; + + +%%% 3. CLL NON-LINEAR SOLVER %%% +% Run the non-linear solver to optimize the non-linear parameters. At each +% iteration of the non-linear least squares solver, the linear parameters +% are calculated separately (similar to the VARiable PROjection algorithm). +% +% We're using a Levenberg-Marquardt implementation for the non-linear +% problem that allows us to impose hard box constraints on the non-linear +% parameters, keeping them within reasonable limits. +% (c) Alexander Drentler +% https://www.mathworks.com/matlabcentral/fileexchange/53449-levenberg-marquardt-toolbox + +% Initial regularization parameter close to zero +regParameter = 2e-2; +% Pack everything up into structs to pass it on to the solver. +% ... data: +inputData.dataToFit = dataToFit; +inputData.resBasisSet = resBasisSet; +% Get an estimate for the standard deviation of the noise +% This is to calculate a Q factor, but need to normalize this noise value +% here - leave alone for now +if max(dataToFit.ppm > 10) + noiseRange = (dataToFit.ppm > 9); +else + noiseRange = (dataToFit.ppm < -2); +end +dataNoise = real(dataToFit.specs(noiseRange,1)); +dataNoise = detrend(dataNoise); +stdNoise = std(dataNoise); +inputData.stdNoise = stdNoise; +% ... settings: +inputSettings.fitRangePPM = fitRangePPM; +inputSettings.regParameter = regParameter; + + +% Set the hard box constraints for the parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +lb_ph0 = -7.5; +ub_ph0 = +7.5; % Zero order phase shift [deg] +lb_ph1 = -2.5; +ub_ph1 = +2.5; % First order phase shift [deg/ppm] +lb_gaussLB = 0; +ub_gaussLB = sqrt(5000); % Gaussian dampening [Hz] +lb_lorentzLB_MM = zeros(nMM, 1); +ub_lorentzLB_MM = 100 * ones(nMM, 1); % Lorentzian dampening [Hz] - MM/Lipids +lb_freqShift_MM = -6.5 * ones(nMM,1); +ub_freqShift_MM = +6.5 * ones(nMM,1); % Frequency shift [Hz] - MM/Lipids +lb_ampl = -Inf * ones(nMets+nMM,1); +ub_ampl = +Inf * ones(nMets+nMM,1); % Amplitude for metabolite and spline basis functions + +% Concatenate together into LB/UB vectors +lb = [lb_ph0; lb_ph1; lb_gaussLB; lb_lorentzLB_MM; lb_freqShift_MM; lb_ampl;]; +ub = [ub_ph0; ub_ph1; ub_gaussLB; ub_lorentzLB_MM; ub_freqShift_MM; ub_ampl;]; + + +% Set up and run the non-linear solver. +opts.Display = 'off'; +opts.TolFun = 1e-6; +opts.TolX = 1e-6; +opts.MaxIter = 400; +[x,~,~,~,~,~,~,~] = LevenbergMarquardt(@(x) fit_Osprey_PrelimStep2_ModelMM(x, inputData, inputSettings), x0, lb, ub, opts); + + +%%% 4. PERFORM FINAL COMPUTATION OF LINEAR PARAMETERS %%% +% After the non-linear optimization is finished, we need to perform the +% final evaluation of the linear parameters (i.e. the amplitudes and +% baseline parameters). +[fitParamsFinal] = fit_Osprey_PrelimStep2_finalLinearMM(x, inputData, inputSettings); + + +%%% 5. CREATE OUTPUT %%% +% Return the fit parameters from the final linear computation to be used in +% the next LCModel analysis step (i.e. the fit with the full basis set): +fitParamsStep2 = fitParamsFinal; + + +end + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%% MODEL FUNCTION %%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% LCModel preliminary analysis step 2 model +function F = fit_Osprey_PrelimStep2_ModelMM(x, inputData, inputSettings) +% This function receives the current set of non-linear parameters during +% every iteration of the non-linear least-squares optimization. The +% parameters are applied to the basis set. +% +% Then, a limited-memory Broyden-Fletcher-Goldfarb-Shanno solver allowing +% for boxed constraints is applied to determine the optimal amplitudes of +% the linear parameters to the current set of non-linear parameters. +% +% The linear parameters are usually the amplitudes for the basis +% functions and cubic baseline splines. +% +% This function returns the difference between the input data and +% the current optimized model. This difference is used by the NLLS +% solver. +% +% USAGE: +% F = fit_LCModel_PrelimStep2_Model(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% F = Difference between data and model. This is the +% objective to be least-squares-optimized by the +% non-linear solver. + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +resBasisSet = inputData.resBasisSet; +stdNoise = inputData.stdNoise; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +regParameter = inputSettings.regParameter; + +% ... fit parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +nBasisFcts = nMets + nMM; % number of basis functions +ph0 = x(1) * pi/180; % zero-order phase correction [convert from deg to rad] +ph1 = x(2) * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] +gaussLB = x(3); % Gaussian dampening [Hz^2] +lorentzLB = x(4:nBasisFcts+3); % Lorentzian dampening [Hz] for each basis function +freqShift = x(nBasisFcts+4:2*nBasisFcts+3); % Frequency shift [Hz] for each basis function +ampl = x(2*nBasisFcts+4:3*nBasisFcts+3); % Amplitudes + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Run the time-domain operations on the metabolite basis functions +% (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) +t = resBasisSet.t; +for ii=1:nBasisFcts + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +resBasisSet.specs = fftshift(fft(resBasisSet.fids,[],1),1); + +% Run the frequency-domain operations on the basis functions +% (first order phase correction) +% Cut out the frequency range of the basis set +resBasisSet = op_freqrange(resBasisSet,fitRangePPM(1),fitRangePPM(end)); +% Create a ppm vector around a pivot point (water) +ppm_ax = resBasisSet.ppm; +pivotPoint = 4.68; +multiplier = ppm_ax - pivotPoint; +% Apply the linear phase correction +for ii=1:nBasisFcts + resBasisSet.specs(:,ii) = resBasisSet.specs(:,ii) .* exp(1i*ph1*multiplier); +end +resBasisSet.fids = ifft(fftshift(resBasisSet.specs,1),[],1); + +%%% 3. SET UP THE LINEAR SOLVER %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) +A = real(resBasisSet.specs); +% Concatenate the metabolite/MM/lipid basis functions and the baseline basis +% functions +AB = [A]; +% Cut out the data over the fit range, and use real part only +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end)); +data = real(dataToFit.specs); +b = data; + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( AB*x - b)^2; +AtA = AB'*AB; Ab = AB'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [zeros(nMets+nMM,1);]; +u = [inf*ones(nMets+nMM,1);]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. ADD SOFT CONSTRAINTS ON AMPLITUDES %%% +A_augB = [AB]; +b_aug = [b]; + +% Now, run the L-BFGS-B algorithm again with the augmented equation system +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A_augB*x - b_aug)^2; +AtA = A_augB'*A_augB; A_augb = A_augB'*b_aug; +grad = @(x) 2*( AtA*x - A_augb ); +% Prepare the function wrapper +fun = @(x)fminunc_wrapper(x, fcn, grad); +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb( fun, l, u, opts ); + + +%%% 4. CREATE OBJECTIVE FUNCTION +% The objective function to be minimized by the non-linear least squares +% solver is the fit residual. +% + +% Return the loss function +% F = 1/sqrt(stdNoise) * SOS + regB + penaltyLBFS; +% This would be the classic LCModel function to be minimized +% For the preliminary step, just return the functional without any regularization +F = (data - AB*ampl); + + +end + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%% FINAL LINEAR ITERATION %%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [fitParamsFinal] = fit_Osprey_PrelimStep2_finalLinearMM(x, inputData, inputSettings) +% This function is applied after the final iteration of the non-linear +% solver has returned the final set of non-linear parameters. +% +% At this point, the linear solver has to be run one last time to +% estimate the final set of linear parameters. +% +% The function returns all model parameters. +% +% USAGE: +% fitParamsFinal = fit_finalLinearSolver(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% fitParamsFinal = Set of final fit parameters + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +resBasisSet = inputData.resBasisSet; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +% ... fit parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +nBasisFcts = nMets + nMM; % number of basis functions +ph0 = x(1) * pi/180; % zero-order phase correction [convert from deg to rad] +ph1 = x(2) * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] +gaussLB = x(3); % Gaussian dampening [Hz^2] +lorentzLB = x(4:nBasisFcts+3); % Lorentzian dampening [Hz] for each basis function +freqShift = x(nBasisFcts+4:2*nBasisFcts+3); % Frequency shift [Hz] for each basis function +ampl = x(2*nBasisFcts+4:3*nBasisFcts+3); + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Run the time-domain operations on the metabolite basis functions +% (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) +t = resBasisSet.t; +for ii=1:nBasisFcts + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +resBasisSet.specs = fftshift(fft(resBasisSet.fids,[],1),1); + +% Run the frequency-domain operations on the basis functions +% (first order phase correction) +% Cut out the frequency range of the basis set +resBasisSet = op_freqrange(resBasisSet,fitRangePPM(1),fitRangePPM(end)); +ppm_ax = resBasisSet.ppm; +pivotPoint = 4.68; +multiplier = ppm_ax - pivotPoint; +for ii=1:nBasisFcts + resBasisSet.specs(:,ii) = resBasisSet.specs(:,ii) .* exp(1i*ph1*multiplier); +end +resBasisSet.fids = ifft(fftshift(resBasisSet.specs,1),[],1); + + + +%%% 3. SET UP AND CALL SOLVER FOR LINEAR PARAMETERS %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) +A = real(resBasisSet.specs); +% Concatenate the metabolite/MM/lipid basis functions and the baseline basis +% functions +AB = [A]; +% Cut out the data over the fit range, and use real part only +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end)); +data = real(dataToFit.specs); +b = data; + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( AB*x - b)^2; +AtA = AB'*AB; Ab = AB'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [zeros(nMets+nMM,1);]; +u = [inf*ones(nMets+nMM,1);]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. ADD SOFT CONSTRAINTS ON AMPLITUDES %%% +% To impose soft constraints on the amplitudes, we can augment the problem +% with additional rows in the equation system. This is done in the function +% fit_createSoftConstrOsprey. +% (see Wilson et al., MRM 2011) +A_augB = [AB]; +b_aug = [b]; + +% Now, run the L-BFGS-B algorithm again with the augmented equation system +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A_augB*x - b_aug)^2; +AtA = A_augB'*A_augB; A_augb = A_augB'*b_aug; +grad = @(x) 2*( AtA*x - A_augb ); +% Prepare the function wrapper +fun = @(x)fminunc_wrapper(x, fcn, grad); +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb( fun, l, u, opts ); + + +%%% 5. CREATE OUTPUT %%% +% Return the final fit parameters +fitParamsFinal.ampl = ampl(1:size(A,2)); +fitParamsFinal.ph0 = x(1); +fitParamsFinal.ph1 = x(2); +fitParamsFinal.gaussLB = x(3); +fitParamsFinal.lorentzLB = x(4:nBasisFcts+3); +fitParamsFinal.freqShift = x(nBasisFcts+4:2*nBasisFcts+3); + +% Plot (comment out if not debugging) +% figure(99) +% plot(data); hold; +% plot(AB*ampl); +% plot(data - (AB*ampl) + 1.1*max(data)); +% for rr = 1:(nMets+nMM) +% plot(ampl(rr)*A(:,rr)); +% end +% title('Preliminary Analysis with full basis set (unregularized)'); +% hold; + + +end + diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep3.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep3.m new file mode 100644 index 00000000..631fedfe --- /dev/null +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyPrelimStep3.m @@ -0,0 +1,768 @@ +function [fitParamsStep3] = fit_OspreyPrelimStep3(dataToFit, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep2,GAP) +%% [fitParamsStep2] = fit_OspreyPrelimStep3(dataToFit, resBasisSet, minKnotSpacingPPM, fitRangePPM, fitParamsStep1, refFWHM) +% Performs the second step of the LCModel preliminary analysis +% according to the LCModel algorithm. The algorithm is described in: +% S.W. Provencher, "Estimation of metabolite concentrations from +% localized in vivo NMR spectra", Magn Reson Med 30(6):672-679 (1993) +% +% During the second step, the input spectrum is fit using the full basis +% set allowing individual frequency shifts and Lorentzian dampening +% for each metabolite basis function. Additionally, a lineshape +% convolution is applied to account for deviations from the ideal +% Voigtian lineshape (= Gaussian/Lorentzian convolution). + +% In addition, pre-defined macromolecule and lipid basis functions are +% added, as well as an unregularized baseline. MM/lipids and the baseline +% are phased with the same phasing parameters as the metabolites, but the +% lineshape convolution is not applied to them. +% +% Input: +% dataToFit = FID-A data structure +% basisSet = FID-A basis set container +% minKnotSpacing = Scalar: minimum baseline knot spacing +% (this is the DKNTMN parameter in LCModel) +% fitRangePPM = 2-element vector: fit range [ppm] +% (this is the range over which the difference +% between spectrum and model is minimized) +% fitParamsStep1 = Fit parameters from the first preliminary +% analysis +% refFWHM = Preliminary linewidth estimate (in ppm) that is +% used to determine the width of the lineshape +% function that the basis functions are +% subsequently convolved with +% Output: +% fitParamsStep2 = Fit parameters: +% - amplitudes of basis functions +% - zero-order phase [deg] +% - first-order phase [deg/ppm] +% - Gaussian LB [Hz] +% - Lorentzian LB [Hz] +% - global frequency shift [Hz] +% +% Author: +% Dr. Georg Oeltzschner (Johns Hopkins University, 2020-01-14) +% goeltzs1@jhmi.edu +% +% History: +% 2020-01-14: First version of the code. +% + +%%% 1. SET UP EXPECTATION VALUES AND SPLINE BASIS FUNCTIONS %%% +% Generate the expectation values and standard deviation values for the +% delta (1/T2) Lorentzian linebroadening and the frequency shift parameter +% in LCModel. +% See LCModel manual, Section 11.14 (p. 149) +[EXT2, SDT2, SDSH] = fit_setExpectValues(dataToFit, resBasisSet); + +% Create an array of normalized cubic baseline spline basis functions. +[splineArray] = fit_makeSplineBasis(dataToFit, fitRangePPM, minKnotSpacingPPM); +nSplines = size(splineArray,2); +D = diff(eye(nSplines), 2); + + +%%% 2. SET AND GET STARTING VALUES %%% +% Set the starting values for the non-linear parameters to be passed on +% to the Levenberg-Marquardt NLLS solving algorithm. Note that the +% amplitude parameters do not need to be initialized, as the +% non-negative linear Lawson-Hanson solver does not require starting +% values to be provided. +inputSettings.ph0 = fitParamsStep2.ph0; % zero-order phase correction [deg] +inputSettings.ph1 = fitParamsStep2.ph1; % first-order phase correction [deg/ppm] +inputSettings.gaussLB = fitParamsStep2.gaussLB; % Gaussian dampening [Hz] +inputSettings.freqShift = fitParamsStep2.freqShift(1:end-1); % Lorentzian dampening [Hz] for each basis function +gaussLBMM = fitParamsStep2.gaussLBMM; % Common Gaussian dampening [Hz] +inputSettings.lorentzLB = fitParamsStep2.lorentzLB(1:end-1); % Lorentzian dampening [Hz] for each basis function +lorentzLB_MM = fitParamsStep2.lorentzLB(end) * ones(resBasisSet.nMM,1); +freqShift_MM = zeros(resBasisSet.nMM,1); % Frequency shift [Hz] for each basis function +inputSettings.ampl = fitParamsStep2.ampl(1 : end-1); % Amplitude parameters for basis functions and baseline +ampl = zeros(resBasisSet.nMM+nSplines,1); % Frequency shift [Hz] for each basis function +lineShape = fitParamsStep2.lineShape; % Amplitude parameters for basis functions and baseline + + +% Normalize +inputSettings.lineShape = lineShape/sum(lineShape); + +% Concatenate all initial guesses together into one large x0 vector. +x0 = [gaussLBMM; lorentzLB_MM; freqShift_MM; ampl]; + + +%%% 3. CLL NON-LINEAR SOLVER %%% +% Run the non-linear solver to optimize the non-linear parameters. At each +% iteration of the non-linear least squares solver, the linear parameters +% are calculated separately (similar to the VARiable PROjection algorithm). +% +% We're using a Levenberg-Marquardt implementation for the non-linear +% problem that allows us to impose hard box constraints on the non-linear +% parameters, keeping them within reasonable limits. +% (c) Alexander Drentler +% https://www.mathworks.com/matlabcentral/fileexchange/53449-levenberg-marquardt-toolbox + +% Initial regularization parameter close to zero +regParameter = 2e-2; +% Pack everything up into structs to pass it on to the solver. +% ... data: +inputData.dataToFit = dataToFit; +inputData.resBasisSet = resBasisSet; +inputData.splineArray = splineArray; +% Get an estimate for the standard deviation of the noise +% This is to calculate a Q factor, but need to normalize this noise value +% here - leave alone for now +if max(dataToFit.ppm > 10) + noiseRange = (dataToFit.ppm > 9); +else + noiseRange = (dataToFit.ppm < -2); +end +dataNoise = real(dataToFit.specs(noiseRange,1)); +dataNoise = detrend(dataNoise); +stdNoise = std(dataNoise); +inputData.stdNoise = stdNoise; +% ... settings: +inputSettings.fitRangePPM = fitRangePPM; +inputSettings.regParameter = regParameter; +inputSettings.EXT2 = EXT2'; +inputSettings.SDT2 = SDT2'; +inputSettings.SDSH = SDSH'; +inputSettings.GAP = GAP; + + +% Set the hard box constraints for the parameters +nMM = resBasisSet.nMM; +lb_gaussLBMM = 0; +ub_gaussLBMM = sqrt(5000); % Gaussian dampening [Hz] +lb_lorentzLB_MM = zeros(nMM, 1); +ub_lorentzLB_MM = 100 * ones(nMM, 1); % Lorentzian dampening [Hz] - MM/Lipids +lb_freqShift_MM = -4 * ones(nMM,1); +ub_freqShift_MM = +4 * ones(nMM,1); % Frequency shift [Hz] - MM/Lipids +lb_ampl = -Inf * ones(nMM+size(splineArray,2),1); +ub_ampl = +Inf * ones(nMM+size(splineArray,2),1); % Amplitude for metabolite and spline basis functions + + +% Concatenate together into LB/UB vectors +lb = [lb_gaussLBMM; lb_lorentzLB_MM; lb_freqShift_MM; lb_ampl]; +ub = [ub_gaussLBMM; ub_lorentzLB_MM; ub_freqShift_MM; ub_ampl]; + + +% Set up and run the non-linear solver. +opts.Display = 'off'; +opts.TolFun = 1e-6; +opts.TolX = 1e-6; +opts.MaxIter = 400; +% opts.Jacobian = 'on'; +% opts.Broyden_updates=2; +[x,Res,~,~,~,~,~,J] = LevenbergMarquardt(@(x) fit_Osprey_PrelimStep3_Model(x, inputData, inputSettings), x0, lb, ub, opts); + + +%%% 4. PERFORM FINAL COMPUTATION OF LINEAR PARAMETERS %%% +% After the non-linear optimization is finished, we need to perform the +% final evaluation of the linear parameters (i.e. the amplitudes and +% baseline parameters). +[fitParamsFinal] = fit_Osprey_PrelimStep3_finalLinear(x, inputData, inputSettings); +fitParamsFinal.Res = Res; +fitParamsFinal.J = J; + +%%% 5. CREATE OUTPUT %%% +% Return the fit parameters from the final linear computation to be used in +% the next LCModel analysis step (i.e. the fit with the full basis set): +fitParamsStep3 = fitParamsFinal; + + +end + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%% MODEL FUNCTION %%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% LCModel preliminary analysis step 2 model +function [F,J] = fit_Osprey_PrelimStep3_Model(x, inputData, inputSettings) +% This function receives the current set of non-linear parameters during +% every iteration of the non-linear least-squares optimization. The +% parameters are applied to the basis set. +% +% Then, a limited-memory Broyden-Fletcher-Goldfarb-Shanno solver allowing +% for boxed constraints is applied to determine the optimal amplitudes of +% the linear parameters to the current set of non-linear parameters. +% +% The linear parameters are usually the amplitudes for the basis +% functions and cubic baseline splines. +% +% This function returns the difference between the input data and +% the current optimized model. This difference is used by the NLLS +% solver. +% +% USAGE: +% F = fit_LCModel_PrelimStep2_Model(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% F = Difference between data and model. This is the +% objective to be least-squares-optimized by the +% non-linear solver. + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +resBasisSet = inputData.resBasisSet; +splineArray = inputData.splineArray; +stdNoise = inputData.stdNoise; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +regParameter = inputSettings.regParameter; +EXT2 = inputSettings.EXT2; +SDT2 = inputSettings.SDT2; +SDSH = inputSettings.SDSH; +GAP = inputSettings.GAP; +% ... fit parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +nBasisFcts = nMets + nMM; % number of basis functions +nSplines = size(splineArray,2); % number of spline basis functions +ph0 = inputSettings.ph0 * pi/180; % zero-order phase correction [convert from deg to rad] +ph1 = inputSettings.ph1 * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] +gaussLB = inputSettings.gaussLB; % Gaussian dampening [Hz^2] +lorentzLB = inputSettings.lorentzLB; +freqShift = inputSettings.freqShift; +gaussLBMM = x(1); % Gaussian dampening [Hz^2] +lorentzLBMM = x(2:nMM+1); % Lorentzian dampening [Hz] for each basis function +freqShiftMM = x(nMM+2:2*nMM+1); % Frequency shift [Hz] for each basis function +ampl = x(2*nMM+2:3*nMM+1+nSplines); % Amplitudes +% Normalize the lineshape +lineShape = inputSettings.lineShape; + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Run the time-domain operations on the metabolite basis functions +% (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) +t = resBasisSet.t; +for ii=1:resBasisSet.nMets + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +for ii=1:resBasisSet.nMM + resBasisSet.fids(:,resBasisSet.nMets+ii) = resBasisSet.fids(:,resBasisSet.nMets+ii) .* exp(-1i*freqShiftMM(ii).*t)' .* exp(-lorentzLBMM(ii).*t)' .* exp(-gaussLBMM.*t.*t)'; + resBasisSet.fids(:,resBasisSet.nMets+ii) = resBasisSet.fids(:,resBasisSet.nMets+ii) * exp(1i*ph0); +end +resBasisSet.specs = fftshift(fft(resBasisSet.fids,[],1),1); + +% Run the frequency-domain operations on the basis functions +% (first order phase correction) +% Cut out the frequency range of the basis set +resBasisSet = op_freqrange(resBasisSet,fitRangePPM(1),fitRangePPM(end),length(splineArray(:,1,1))); +% Create a ppm vector around a pivot point (water) +ppm_ax = resBasisSet.ppm; +pivotPoint = 4.68; +multiplier = ppm_ax - pivotPoint; +% Apply the linear phase correction +for ii=1:nBasisFcts + resBasisSet.specs(:,ii) = resBasisSet.specs(:,ii) .* exp(1i*ph1*multiplier); +end +resBasisSet.fids = ifft(fftshift(resBasisSet.specs,1),[],1); + +% Apply phasing to the spline basis functions +B = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +B = B * exp(1i*ph0); +B = B .* exp(1i*ph1*multiplier); +B = [real(B)]; + + +%%% 3. SET UP THE LINEAR SOLVER %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) + +% Convolve the lineshape with the metabolite basis functions only +% (NOT the macromolecules or lipids or baseline splines). +A = real(resBasisSet.specs(:,1:resBasisSet.nMets)); +for kk = 1:resBasisSet.nMets + A(:,kk) = conv(A(:,kk), lineShape, 'same'); +end +A_us = A; +A = A * inputSettings.ampl; + +MM = real(resBasisSet.specs(:,resBasisSet.nMets+1:end)); +% Concatenate the metabolite/MM/lipid basis functions and the baseline basis +% functions +AB = [MM B]; +% Cut out the data over the fit range, and use real part only +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end),length(splineArray(:,1,1))); +data = real(dataToFit.specs); +b = data; + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A + AB*x - b)^2; +AtA = AB'*AB; Ab = AB'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [zeros(nMM,1); -inf*ones(nSplines,1)]; +u = [inf*ones(nMM,1); inf*ones(nSplines,1)]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. ADD SOFT CONSTRAINTS ON AMPLITUDES %%% +% To impose soft constraints on the amplitudes, we can augment the problem +% with additional rows in the equation system. This is done in the function +% fit_createSoftConstrOsprey. +% (see Wilson et al., MRM 2011) +[augmA, augmb] = fit_createSoftConstrOsprey(resBasisSet, AB, b, ampl); +A_augB = [AB; augmA]; +b_aug = [b; augmb]; +A = [A; zeros(length(augmb),1)]; + +% Now, run the L-BFGS-B algorithm again with the augmented equation system +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A + A_augB*x - b_aug)^2; +AtA = A_augB'*A_augB; A_augb = A_augB'*b_aug; +grad = @(x) 2*( AtA*x - A_augb ); +% Prepare the function wrapper +fun = @(x)fminunc_wrapper(x, fcn, grad); +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb( fun, l, u, opts ); + +ampl = vertcat(inputSettings.ampl,ampl); +%%% 4. CREATE OBJECTIVE FUNCTION +% The objective function to be minimized by the non-linear least squares +% solver is the fit residual. +% +% The LCModel algorithm wants to minimize not only the sum of squares +% between the data and the model, but imposes regularization on several +% parameters. +% Therefore, we have to reconstruct the fit spectrum from the parameters we +% derived, and then calculate the sum of squares ourselves, in addition to +% the penalty terms. +% For the last step of the preliminary analysis, this is done without any +% regularization at all. + +% Calculate the sum of squares +% SOS = sum((data - AB*ampl).^2); + +% Calculate the baseline regularization penalty term +% Extract the baseline coefficients +beta_j = ampl(size(A,2)+1:end); +% Create the analytical regularizor matrix specified in Eq (3.13) in the +% original publication of the CONTIN algorithm behind LCModel: +% Provencher, Comp Phys Comm 27:213-227 (1982) +% First, create a banded Toeplitz matrix +n = length(beta_j); +e = ones(n,1); +K = spdiags([1*e 0*e -9*e 16*e -9*e 0*e 1*e], -3:3, n, n); +K = full(K); +% Then, correct the first two and last two lines according to the above +% paper +K(1, 1:4) = [8 -6 0 1]; +K(2, 1:5) = [-6 14 -6 0 1]; +K(end-1, end-4:end) = [1 0 -6 14 -6]; +K(end, end-3:end) = [1 0 -6 8]; +% Bring in the factor of 1/6 +K = 1/6 .* K; +% Additionally, bring in the geometric factor delta, which is the knot +% spacing, ie delta = range/(number of segments). +% !!! THIS ISN'T CLEARLY UNDERSTOOD YET !!! +% normalizationFactor = 1/(size(splineArray,1)/(size(splineArray,2)-1))^3; +% Final regularization penalty +% regB = norm(regParameter*sqrtm(full(K))*beta_j*1/(mean(beta_j)))^2; + +% Calculate the penalty term for the Lorentzian linebroadening and +% frequency shifts +% penaltyLBFS = sum((lorentzLB - EXT2).^2./(SDT2).^2 + (freqShift.^2)./(SDSH.^2)); + +% Return the loss function +% F = 1/sqrt(stdNoise) * SOS + regB + penaltyLBFS; +% This would be the classic LCModel function to be minimized +% For the preliminary step, just return the functional without any regularization + +regBAmpl = sum((beta_j.^2))/sqrt(stdNoise); + +F = (data - [A_us AB]*ampl) + regBAmpl; + + +if ~isempty(GAP) +% data = vertcat(data(ppm_axGAP(2))); +% fit = AB*ampl; +% fit = vertcat(fit(ppm_axGAP(2))); + F = vertcat(F(ppm_axGAP(2))); +end +%%% 5. CALCULATE ANALYTIC JACOBIAN +% j = sqrt(-1); % i +% +% % Model function +% % Y(f) = exp(i(ph0+ph1(f))) * (sum(betaj * B) + sum(amp conv(M, lineshape)) +% % with M = fft(basisSet.fids .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)') +% % The derivatives are 'easier' in the time-domain, so we will stick with +% % the FIDS for the calculations +% +% % dimensions and number of matrix entries +% [npoints,~] = size(resBasisSet.fids); %number of points and number of basis functions +% t = resBasisSet.t; +% +% % % Apply phasing to the spline basis functions +% Acomp = resBasisSet.specs; +% for kk = 1:resBasisSet.nMets +% Acomp(:,kk) = conv(Acomp(:,kk), lineShape, 'same'); +% end +% +% Bcomp = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +% Bcomp = Bcomp * exp(1i*ph0); +% Bcomp = Bcomp .* exp(1i*ph1*multiplier); +% +% ABcomp = [Acomp Bcomp]; +% completeFit = ABcomp*ampl; +% +% +% %Computation of the Jacobian +% % The size is MxN with M (number of estimated parameters) and N (number of +% % points). +% %Store the indices of the different partial derivatives +% ph0Col = 1; +% ph1Col = 2; +% gaussLBCol = 3 * ones(1,nMets + nMM); +% lorentzLBCol = gaussLBCol(end) + 1 : (gaussLBCol(1) + nMets + nMM); +% freqShiftCol = lorentzLBCol(end) + 1 : (lorentzLBCol(end) + nMets + nMM); +% AmplCol = freqShiftCol(end) + 1 : (freqShiftCol(end) + nMets + nMM); +% SplineAmplCol = AmplCol(end) + 1 : (AmplCol(end) + size(splineArray,2)); +% lineshapeCol = SplineAmplCol(end)+1 : SplineAmplCol(end) + length(lineShape); +% +% nparams = 3 + length(lorentzLBCol) + length(freqShiftCol) + length(AmplCol) + length(SplineAmplCol) + length(lineshapeCol); +% +% J = zeros(npoints,nparams); +% Jfd = zeros(npoints,nparams); +% +% +% %derivative wrt ph0 +% % for ii = 1:nMets +% % col = ph0Col(ii); +% % J(:,col) = J(:,col)+j*basisSet.fids(:,ii)*ampl(ii); +% % Jfd(:,col) = fftshift(fft(J(:,col),[],1),1); +% % Jfd(:,col) = conv(Jfd(:,col), lineShape, 'same') + B * beta_j; +% % end +% Jfd(:,1) = j * completeFit; +% +% %derivative wrt ph1 +% % for ii = 1:nBasisFcts +% % col = ph1Col(ii); +% % J(:,col) = J(:,col)+j*basisSet.fids(:,ii)*ampl(ii); +% % Jfd(:,col) = fftshift(fft(J(:,col),[],1),1); +% % Jfd(:,col) = conv(Jfd(:,col), lineShape, 'same') + B * beta_j; +% % end +% Jfd(:,2) = j * completeFit .* multiplier; +% +% %derivative wrt gaussLB +% for ii = 1:nBasisFcts +% if ii <= nMets % Sum up derivarives of all metabolite functions first +% col = gaussLBCol(ii); +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*(t.^2)'; +% Jfd(:,col) = Jfd(:,col) + conv(fftshift(fft(-resBasisSet.fids(:,ii).*(t.^2)',[],1),1), lineShape, 'same')*ampl(ii); +% else % No convolution is applied to the MM functions +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*(t.^2)'; +% Jfd(:,col) = Jfd(:,col) + fftshift(fft(-resBasisSet.fids(:,ii).*(t.^2)',[],1),1)*ampl(ii); +% end +% end +% +% +% %derivative wrt lorentzLB +% for ii = 1:nBasisFcts +% if ii <= nMets % Sum up derivarives of all metabolite functions first +% col = lorentzLBCol(ii); +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + conv(fftshift(fft(J(:,col),[],1),1), lineShape, 'same')*ampl(ii); +% else % No convolution is applied to the MM functions +% col = lorentzLBCol(ii); +% J(:,col) = J(:,col)-resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + fftshift(fft(J(:,col),[],1),1)*ampl(ii); +% end +% end +% +% %derivative wrt freqShift +% for ii=1:nBasisFcts +% if ii <= nMets % Sum up derivarives of all metabolite functions first +% col = freqShiftCol(ii); +% J(:,col) = J(:,col)-j*resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + conv(fftshift(fft(J(:,col),[],1),1), lineShape, 'same')*ampl(ii); +% else % No convolution is applied to the MM functions +% col = freqShiftCol(ii); +% J(:,col) = J(:,col)-j*resBasisSet.fids(:,ii).*t'; +% Jfd(:,col) = Jfd(:,col) + fftshift(fft(J(:,col),[],1),1)*ampl(ii); +% end +% end +% +% % derivative wrt basis set amplitudes +% for ii=1:nBasisFcts +% if ii <= nMets +% col = AmplCol(ii); +% J(:,col) = resBasisSet.fids(:,ii); +% Jfd(:,col) = conv(fftshift(fft(J(:,col),[],1),1), lineShape, 'same'); +% else +% col = AmplCol(ii); +% J(:,col) = resBasisSet.fids(:,ii); +% Jfd(:,col) = fftshift(fft(J(:,col),[],1),1); +% end +% end +% +% +% % derivative wrt spline amplitudes +% for ii=1:length(SplineAmplCol) +% col = SplineAmplCol(ii); +% Jfd(:,col) = Jfd(:,col)+Bcomp(:,ii); +% end +% +% +% %derivative wrt lineshape +% % We will do a discrete convolution of S'*M by using the Toeplitz matrix +% % form of the partial derivative of the lineshape vector S and M beeing +% % the metabolite basis functions. This is allowed as convolutions are +% % commutative and (M*S)' = M'*S = M*S' -> (M*S)' = S'*M. +% +% %We need to create S' as a Toeplitz matrix. The derivatives will +% %essantially be ones on the diagonal (first lineshape coeff) or the upper off +% %diagonal (all other lineshape coeff). +% +% nLineShape = length(lineShape); +% nPoints = length(resBasisSet.fids(:,1)); +% +% %Set up the first rows of each partial derivative +% Toep1row = zeros(nLineShape,nPoints); +% for ii = 1 : nLineShape +% Toep1row(ii,ii) = 1; +% end +% +% %We will set it up as a 3D vector with the partial derivatives in the third dimensions and the +% %Toeplitz matrix spanning the first two dimensions. +% ToepLineShape = zeros(nPoints,nPoints,nLineShape); +% for ii = 1 : nLineShape +% if ii <= 1 +% ToepLineShape(:,:,ii) = toeplitz(Toep1row(ii,:)); +% else +% ToepLineShape(:,:,ii) = tril(toeplitz(Toep1row(ii,:))); % extract lower triangle of the Toeplitz matrix +% end +% end +% +% for ii=1:nLineShape % Loop over the lineshape derivatives +% col = lineshapeCol(ii); +% for kk = 1 : nMets % Convolute all basis functions to create the full model function +% J(:,col) = J(:,col)+resBasisSet.fids(:,kk); +% Jfd(:,col) = Jfd(:,col) + ampl(kk)*(ToepLineShape(:,:,ii) * fftshift(fft(resBasisSet.fids(:,kk),[],1),1)); +% end +% +% end +% +% J = real(Jfd); + +end + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%% FINAL LINEAR ITERATION %%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [fitParamsFinal] = fit_Osprey_PrelimStep3_finalLinear(x, inputData, inputSettings) +% This function is applied after the final iteration of the non-linear +% solver has returned the final set of non-linear parameters. +% +% At this point, the linear solver has to be run one last time to +% estimate the final set of linear parameters. +% +% The function returns all model parameters. +% +% USAGE: +% fitParamsFinal = fit_finalLinearSolver(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% fitParamsFinal = Set of final fit parameters + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +resBasisSet = inputData.resBasisSet; +splineArray = inputData.splineArray; +stdNoise = inputData.stdNoise; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +regParameter = inputSettings.regParameter; +EXT2 = inputSettings.EXT2; +SDT2 = inputSettings.SDT2; +SDSH = inputSettings.SDSH; +GAP = inputSettings.GAP; +% ... fit parameters +nMets = resBasisSet.nMets; +nMM = resBasisSet.nMM; +nBasisFcts = nMets + nMM; % number of basis functions +nSplines = size(splineArray,2); % number of spline basis functions +ph0 = inputSettings.ph0 * pi/180; % zero-order phase correction [convert from deg to rad] +ph1 = inputSettings.ph1 * pi/180; % first-order phase correction [convert from deg/ppm to rad/ppm] +gaussLB = inputSettings.gaussLB; % Gaussian dampening [Hz^2] +lorentzLB = inputSettings.lorentzLB; +freqShift = inputSettings.freqShift; +gaussLBMM = x(1); % Gaussian dampening [Hz^2] +lorentzLBMM = x(2:nMM+1); % Lorentzian dampening [Hz] for each basis function +freqShiftMM = x(nMM+2:2*nMM+1); % Frequency shift [Hz] for each basis function +ampl = x(2*nMM+2:3*nMM+1+nSplines); % Amplitudes +% Normalize the lineshape +lineShape = inputSettings.lineShape; + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Run the time-domain operations on the metabolite basis functions +% (frequency shift, Lorentzian dampening, Gaussian dampening, zero phase shift) +t = resBasisSet.t; +for ii=1:resBasisSet.nMets + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) .* exp(-1i*freqShift(ii).*t)' .* exp(-lorentzLB(ii).*t)' .* exp(-gaussLB.*t.*t)'; + resBasisSet.fids(:,ii) = resBasisSet.fids(:,ii) * exp(1i*ph0); +end +for ii=1:resBasisSet.nMM + resBasisSet.fids(:,resBasisSet.nMets+ii) = resBasisSet.fids(:,resBasisSet.nMets+ii) .* exp(-1i*freqShiftMM(ii).*t)' .* exp(-lorentzLBMM(ii).*t)' .* exp(-gaussLBMM.*t.*t)'; + resBasisSet.fids(:,resBasisSet.nMets+ii) = resBasisSet.fids(:,resBasisSet.nMets+ii) * exp(1i*ph0); +end +resBasisSet.specs = fftshift(fft(resBasisSet.fids,[],1),1); + +% Run the frequency-domain operations on the basis functions +% (first order phase correction) +% Cut out the frequency range of the basis set +resBasisSet = op_freqrange(resBasisSet,fitRangePPM(1),fitRangePPM(end),length(splineArray(:,1,1))); +% Create a ppm vector around a pivot point (water) +ppm_ax = resBasisSet.ppm; +pivotPoint = 4.68; +multiplier = ppm_ax - pivotPoint; +% Apply the linear phase correction +for ii=1:nBasisFcts + resBasisSet.specs(:,ii) = resBasisSet.specs(:,ii) .* exp(1i*ph1*multiplier); +end +resBasisSet.fids = ifft(fftshift(resBasisSet.specs,1),[],1); + +% Apply phasing to the spline basis functions +B = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +B = B * exp(1i*ph0); +B = B .* exp(1i*ph1*multiplier); +B = [real(B)]; + + +%%% 3. SET UP THE LINEAR SOLVER %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) + +% Convolve the lineshape with the metabolite basis functions only +% (NOT the macromolecules or lipids or baseline splines). +A = real(resBasisSet.specs(:,1:resBasisSet.nMets)); +for kk = 1:resBasisSet.nMets + A(:,kk) = conv(A(:,kk), lineShape, 'same'); +end +A_us = A; +A = A * inputSettings.ampl; + +MM = real(resBasisSet.specs(:,resBasisSet.nMets+1:end)); +% Concatenate the metabolite/MM/lipid basis functions and the baseline basis +% functions +AB = [MM B]; +% Cut out the data over the fit range, and use real part only +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end),length(splineArray(:,1,1))); +data = real(dataToFit.specs); +b = data; + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A + AB*x - b)^2; +AtA = AB'*AB; Ab = AB'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [zeros(nMM,1); -inf*ones(nSplines,1)]; +u = [inf*ones(nMM,1); inf*ones(nSplines,1)]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. ADD SOFT CONSTRAINTS ON AMPLITUDES %%% +% To impose soft constraints on the amplitudes, we can augment the problem +% with additional rows in the equation system. This is done in the function +% fit_createSoftConstrOsprey. +% (see Wilson et al., MRM 2011) +[augmA, augmb] = fit_createSoftConstrOsprey(resBasisSet, AB, b, ampl); +A_augB = [AB; augmA]; +b_aug = [b; augmb]; +A = [A; zeros(length(augmb),1)]; + +% Now, run the L-BFGS-B algorithm again with the augmented equation system +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( A + A_augB*x - b_aug)^2; +AtA = A_augB'*A_augB; A_augb = A_augB'*b_aug; +grad = @(x) 2*( AtA*x - A_augb ); +% Prepare the function wrapper +fun = @(x)fminunc_wrapper(x, fcn, grad); +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb( fun, l, u, opts ); + +ampl = vertcat(inputSettings.ampl,ampl); + + +%%% 5. CREATE OUTPUT %%% +% Return the final fit parameters +fitParamsFinal.ampl = ampl(1:nBasisFcts); +fitParamsFinal.ph0 = inputSettings.ph0; +fitParamsFinal.ph1 = inputSettings.ph1; +fitParamsFinal.gaussLB = inputSettings.gaussLB; +fitParamsFinal.gaussLBMM = x(1); +fitParamsFinal.lorentzLB = [inputSettings.lorentzLB; x(2:nMM+1)]; +fitParamsFinal.freqShift = [inputSettings.freqShift; x(nMM+1:2*nMM+1)]; +fitParamsFinal.lineShape = inputSettings.lineShape; +fitParamsFinal.beta_j = ampl(nBasisFcts+1:end); + +% % Plot (comment out if not debugging) +% figure(99) +% plot(data); hold; +% plot(AB*ampl); +% plot(B*ampl(size(A,2)+1:end)); plot(data - (AB*ampl) + 1.1*max(data)); +% for rr = 1:(nMets+nMM) +% plot(ampl(rr)*A(:,rr)); +% end +% title('Preliminary Analysis with full basis set (unregularized)'); +% hold; + + +end + diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyReferencingMM.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyReferencingMM.m index b379b394..0b1e5ce6 100644 --- a/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyReferencingMM.m +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_OspreyReferencingMM.m @@ -28,9 +28,11 @@ % History: % 2018-10-12: First version of the code. % - % Calculate power spectrum to estimate reference shift and FWHM dataToFit=op_freqrange(dataToFit,0.5,4.2); +if dataToFit.flags.isMEGA && dataToFit.dims.subSpecs~=0 + dataToFit = op_takesubspec(dataToFit,3); % Get diff1 spectrum +end spec = dataToFit.specs; ppm = dataToFit.ppm; realspec = real(spec); @@ -38,13 +40,21 @@ y = zeros(size(x)); % Set up delta functions -[a,b] = min((abs(x-0.9))); -[c,d] = min((abs(x-3.03))); -[e,f] = min((abs(x-3.9))); -y(b) = 1; -y(d) = -1; -y(f) = 1; +if dataToFit.flags.isUnEdited + [a,b] = min((abs(x-0.9))); + [c,d] = min((abs(x-2.01))); + [e,f] = min((abs(x-3.9))); + y(b) = 1; + y(d) = -1; + y(f) = 1; +end +if dataToFit.flags.isMEGA + [a,b] = min((abs(x-0.915))); +% [e,f] = min((abs(x-3.9))); + y(b) = 1; +% y(f) = 1; +end % Plot cross-correlation function, normalize it to its maximum r = xcorr(realspec,y)'; r2 = xcorr(real(spec),y)'; diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey_PrelimReducedMM.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey_PrelimReducedMM.m index fd1e515e..84c0e37c 100644 --- a/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey_PrelimReducedMM.m +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey_PrelimReducedMM.m @@ -52,9 +52,10 @@ %%% 1. CREATE REDUCED BASIS SET %%% % For now, the reduced basis set includes only NAA, Cr, and -CrCH2 % Glu, analogous to LCModel. -metabList.Cr = 1; +% metabList.Cr = 1; metabList.NAA = 1; -metabList.CrCH2 = 1; +% metabList.NAA_Ace = 1; +% metabList.CrCH2 = 1; fitMM = 0; reducedBasisSet = fit_selectMetabs(basisSet, metabList, fitMM); nMets = length(reducedBasisSet.name); diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey_SplineOnly.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey_SplineOnly.m new file mode 100644 index 00000000..ba779c3d --- /dev/null +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_Osprey_SplineOnly.m @@ -0,0 +1,318 @@ +function [fitParamsStep3,out] = fit_Osprey_SplineOnly(dataToFit, minKnotSpacingPPM, fitRangePPM) +%% [fitParamsStep1] = fit_Osprey_PrelimReduced(dataToFit, minKnotSpacingPPM, fitRangePPM) +% Performs the first step of the LCModel preliminary analysis +% analogous to the LCModel algorithm. The algorithm is described in: +% S.W. Provencher, "Estimation of metabolite concentrations from +% localized in vivo NMR spectra", Magn Reson Med 30(6):672-679 (1993) +% +% During the first step, the input spectrum is fit using a reduced basis +% set (Cr, Glu, Ins, GPC, NAA) and simplified model, using a common +% frequency shift and common Gaussian and Lorentzian linebroadening +% for all basis functions of the reduced basis set. +% +% In addition, there is an unregularized baseline contribution. It seems +% like this initial baseline has a fixed number of splines (18?), but I +% need to investigate this further. For now, set the minKnotSpacingPPM +% parameter (= DKNTMN in LCModel) to 0.16. +% +% Input: +% dataToFit = FID-A data structure +% basisSet = FID-A basis set container +% minKnotSpacing = Scalar: minimum baseline knot spacing +% (this is the DKNTMN parameter in LCModel) +% fitRangePPM = 2-element vector: fit range [ppm] +% (this is the range over which the difference +% between spectrum and model is minimized) +% Output: +% fitParamsStep1 = Fit parameters: +% - amplitudes of basis functions +% - zero-order phase [deg] +% - first-order phase [deg/ppm] +% - Gaussian LB [Hz] +% - Lorentzian LB [Hz] +% - global frequency shift [Hz] +% +% Author: +% Dr. Georg Oeltzschner (Johns Hopkins University, 2020-01-14) +% goeltzs1@jhmi.edu +% +% History: +% 2020-01-14: First version of the code. +% + + +%%% 0. SET EXPECTATION VALUES FOR LORENTZIAN LINEBROADENING AND FREQ SHIFTS +% See LCModel manual, Section 11.14 (p. 149) +exT2 = 2.0; % [Hz] - expectation value for Lorentzian linebroadening +SDT2 = 0.4; % [Hz] - standard deviation for Lorentzian linebroadening +SDSH = 0.004; % [Hz] - standard deviation for frequency shifts +scalingT2 = sqrt(dataToFit.txfrq*1e-6 / 85.15); % scaling factor to account for T2 decrease with field strength + + +%%% 1. CREATE REDUCED BASIS SET %%% +% Create the spline basis functions for the given resolution, fit range, +% and knot spacing parameter. +[splineArray] = fit_makeSplineBasis(dataToFit, fitRangePPM, minKnotSpacingPPM); +nSplines = size(splineArray,2); + + +%%% 2. SET AND GET STARTING VALUES %%% +% Amplitudes for each spline basis +% function: +ampl = [zeros(nSplines,1)]; + +% Concatenate together into one large starting value vector. +x0 = [ampl]; + + +%%% 3. CALL NON-LINEAR SOLVER %%% +% Run the non-linear solver to optimize the non-linear parameters. At each +% iteration of the non-linear least squares solver, the linear parameters +% are calculated separately (similar to the VARiable PROjection algorithm). +% +% We're using a Levenberg-Marquardt implementation for the non-linear +% problem that allows us to impose hard box constraints on the non-linear +% parameters, keeping them within reasonable limits. +% (c) Alexander Drentler +% https://www.mathworks.com/matlabcentral/fileexchange/53449-levenberg-marquardt-toolbox + +% Pack everything up into structs to pass it on to the solver. +% ... data: +inputData.dataToFit = dataToFit; +inputData.splineArray = splineArray; +% ... settings: +inputSettings.fitRangePPM = fitRangePPM; + +% Set the hard box constraints for the parameters +lb_beta_j = -Inf*ones(nSplines,1); +ub_beta_j = +Inf*ones(nSplines,1); % Baseline spline amplitudes + +% Concatenate together into LB/UB vectors +lb = [lb_beta_j]; +ub = [ub_beta_j]; + +% Set up and run the non-linear solver. +opts.Display = 'off'; +opts.TolFun = 1e-6; +opts.TolX = 1e-6; +opts.MaxIter = 400; +[x] = LevenbergMarquardt(@(x) fit_Osprey_PrelimReduced_Model(x, inputData, inputSettings),x0,lb,ub,opts); + + +%%% 4. PERFORM FINAL COMPUTATION OF LINEAR PARAMETERS %%% +% After the non-linear optimization is finished, we need to perform the +% final evaluation of the linear parameters (i.e. the amplitudes and +% baseline parameters). +[fitParamsFinal] = fit_Osprey_PrelimReduced_finalLinear(x, inputData, inputSettings); + + +%%% 5. CREATE OUTPUT %%% +out = dataToFit; +out.specs = complex(fitParamsFinal.spline(1:size(fitParamsFinal.spline,1)/2),fitParamsFinal.spline(size(fitParamsFinal.spline,1)/2+1:end)); +out.fids = ifft(fftshift(out.specs,1),[],1); +% Return the fit parameters from the final linear computation to be used in +% the next LCModel analysis step (i.e. the fit with the full basis set): +fitParamsStep3 = fitParamsFinal; +%dummy=fitParamsStep1.ampl; +%fitParamsStep1.ampl=zeros([]) +end + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%% MODEL FUNCTION %%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function F = fit_Osprey_PrelimReduced_Model(x, inputData, inputSettings) +% This function receives the current set of non-linear parameters during +% every iteration of the non-linear least-squares optimization. The +% parameters are applied to the basis set. +% +% Then, a limited-memory Broyden-Fletcher-Goldfarb-Shanno solver allowing +% for boxed constraints is applied to determine the optimal amplitudes of +% the linear parameters to the current set of non-linear parameters. +% +% The linear parameters are usually the amplitudes for the basis +% functions and cubic baseline splines. +% +% This function returns the difference between the input data and +% the current optimized model. This difference is used by the NLLS +% solver. +% +% USAGE: +% F = fit_LCModel_PrelimReduced_Model(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% F = Difference between data and model. This is the +% objective to be least-squares-optimized by the +% non-linear solver. + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +splineArray = inputData.splineArray; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +% ... fit parameters +nSplines = size(splineArray,2); % number of spline basis functions +ampl = x(1:end); % Amplitudes for each basis function + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% + +% Apply phasing to the spline basis functions +B = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +B = [real(B); imag(B)]; + + +%%% 3. SET UP AND CALL SOLVER FOR LINEAR PARAMETERS %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) + +% Set up the equation system to be solved +% Concatenate the metabolite/MM/lipid basis functions and the baseline basis +% functions +% Cut out the data over the fit range, and turn complex into real problem +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end),size(splineArray,1)); +data = [real(dataToFit.specs); imag(dataToFit.specs)]; +b = data; + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( B*x - b)^2; +AtA = B'*B; Ab = B'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [-inf*ones(nSplines,1)]; +u = [inf*ones(nSplines,1)]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. CREATE OBJECTIVE FUNCTION +% The objective function to be minimized by the non-linear least squares +% solver is the fit residual: +F = data - (B*ampl); + + +end + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%% FINAL LINEAR ITERATION %%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [fitParamsFinal] = fit_Osprey_PrelimReduced_finalLinear(x, inputData, inputSettings) +% This function is applied after the final iteration of the non-linear +% solver has returned the final set of non-linear parameters. +% +% At this point, the linear solver has to be run one last time to +% estimate the final set of linear parameters. +% +% The function returns all model parameters. +% +% USAGE: +% fitParamsFinal = fit_LCModel_PrelimReduced_finalLinear(x, inputData, inputSettings) +% +% INPUTS: +% x = Vector providing the last set of parameters coming +% out of the non-linear solver +% inputData = Struct containing all necessary data to prepare the +% final linear solving step (data, basis set...). +% inputSettings = Struct containing all necessary settings. +% +% OUTPUTS: +% fitParamsFinal = Set of final fit parameters + + +%%% 1. UNPACK THE INPUT %%% +% ... data: +dataToFit = inputData.dataToFit; +splineArray = inputData.splineArray; +% ... settings: +fitRangePPM = inputSettings.fitRangePPM; +% ... fit parameters +nSplines = size(splineArray,2); % number of spline basis functions +ampl = x(1:end); % Amplitudes for each basis function + + +%%% 2. APPLY THE NON-LINEAR PARAMETERS %%% +% Apply phasing to the spline basis functions +B = [splineArray(:,:,1) + 1i*splineArray(:,:,2)]; +B = [real(B); imag(B)]; + + +%%% 3. SET UP AND CALL SOLVER FOR LINEAR PARAMETERS %%% +% To calculate the linearly occurring amplitude parameters for the +% metabolite/MM/lipid basis functions and the baseline basis functions, we +% call the linear L-BFGS-B algorithm. +% (c) Stephen Becker +% (https://www.mathworks.com/matlabcentral/fileexchange/35104-lbfgsb-l-bfgs-b-mex-wrapper) + +% Cut out the data over the fit range, and turn complex into real problem +dataToFit = op_freqrange(dataToFit, fitRangePPM(1), fitRangePPM(end),size(splineArray,1)); +data = [real(dataToFit.specs); imag(dataToFit.specs)]; +b = data; + +% The function we want to minimize is the sum of squares of the residual +fcn = @(x) norm( B*x - b)^2; +AtA = B'*B; Ab = B'*b; +grad = @(x) 2*( AtA*x - Ab ); + +% Define bounds. The lower bounds for the metabolite/MM/lipid basis +% functions are zero. All other parameters are supposed to be unbound. +l = [-inf*ones(nSplines,1)]; +u = [inf*ones(nSplines,1)]; + +% Prepare the function wrapper +fun = @(x)fminunc_wrapper( x, fcn, grad); +% Request very high accuracy: +opts = struct( 'factr', 1e4, 'pgtol', 1e-8, 'm', 10); +opts.printEvery = 0; + +% Run the algorithm: +% Feed initial guess from the input parameters +opts.x0 = ampl; +[ampl, ~, ~] = lbfgsb(fun, l, u, opts ); + + +%%% 4. CREATE OUTPUT %%% +% Return the final fit parameters +fitParamsFinal.beta_j = ampl(1:end); +fitParamsFinal.spline = B*ampl; + +% % Plot (comment out if not debugging) +% figure(99) +% plot(data); hold; +% plot(B*ampl(size(A,2)+1:end)); plot(data - (B*ampl) + 1.1*max(data)); +% title('Preliminary Analysis with reduced basis set'); +% hold; + + +end + diff --git a/libraries/FID-A/fitTools/fitModels/Osprey/fit_createSoftConstrOsprey.m b/libraries/FID-A/fitTools/fitModels/Osprey/fit_createSoftConstrOsprey.m index 3acb5185..5ef90edd 100644 --- a/libraries/FID-A/fitTools/fitModels/Osprey/fit_createSoftConstrOsprey.m +++ b/libraries/FID-A/fitTools/fitModels/Osprey/fit_createSoftConstrOsprey.m @@ -40,10 +40,18 @@ % Set up vector of soft constraints. All of the below vectors require % identical length. -constr1.met = {'Lip13', 'Lip13', 'MM09', 'MM09', 'MM09', 'MM09', 'NAA', 'MM09', 'MM09', 'MM09'}; -constr1.wght = [1 1 1 1 1 1 1 1 1 1]; -constr2.met = {'Lip09', 'Lip20', 'MM20', 'MM12', 'MM14', 'MM17', 'NAAG', 'MM37', 'MM38', 'MM40'}; -constr2.wght = [0.267 0.15 1.5 0.3 0.75 0.375 0.15 0.89 0.1 1.39 ]; +% constr1.met = {'Lip13', 'Lip13', 'MM09', 'MM09', 'MM09', 'MM09', 'NAA', 'MM09', 'MM09', 'MM09', 'MM09'}; +% constr1.wght = [1 1 1 1 1 1 1 1 1 1 1]; +% constr2.met = {'Lip09', 'Lip20', 'MM20', 'MM12', 'MM14', 'MM17', 'NAAG', 'MM37', 'MM38', 'MM40', 'MM42'}; +% constr2.wght = [0.267 0.15 1.5 0.3 0.75 0.375 0.15 0.89 0.1 1.39 0.3]; +% constr1.met = {'MM09', 'MM09', 'MM09', 'MM09', 'MM09', 'MM09' 'MM09', 'MM09', 'MM09', 'MM09'}; +% constr1.wght = [1 1 1 1 1 1 1 1 1 1]; +% constr2.met = {'MM12', 'MM14', 'MM17', 'MM20', 'MM22', 'MM27', 'MM30', 'MM32', 'MM37', 'MM42'}; +% constr2.wght = [1 1 1 1 1 1 1 1 1 1]; +constr1.met = {'MM09', 'MM09', 'MM09', 'MM09', 'MM09', 'MM09', 'NAA', 'MM09', 'MM09', 'MM09', 'MM09'}; +constr1.wght = [1 1 1 1 1 1 1 1 1 1 1]; +constr2.met = {'MM12', 'MM14', 'MM17', 'MM20', 'MM22', 'MM27', 'NAAG', 'MM30', 'MM32', 'MM37', 'MM42'}; +constr2.wght = [1 1 1 1 1 1 0.15 1 1 1 1]; len1 = length(constr1.met); len2 = length(constr1.wght); len3 = length(constr2.met); diff --git a/libraries/FID-A/fitTools/fit_createMetabList.m b/libraries/FID-A/fitTools/fit_createMetabList.m index b47dd8ef..ed33c5d9 100644 --- a/libraries/FID-A/fitTools/fit_createMetabList.m +++ b/libraries/FID-A/fitTools/fit_createMetabList.m @@ -22,8 +22,8 @@ % Define the set of available metabolites all_mets = {'Ala','Asc','Asp','bHB','bHG','Cit','Cr','CrCH2','EA','EtOH','GABA','GPC','GSH','Glc','Gln' ... ,'Glu','Gly','HCar','H2O','Ins','Lac','NAA','NAAG','PCh','PCr','PE','Phenyl' ... - ,'Scyllo','Ser','Tau','Tyros','MM09','MM12','MM14','MM17','MM20' ... - ,'Lip09','Lip13','Lip20','MM37','MM38','MM40','MM42','MMexp'}; + ,'Scyllo','Ser','Tau','Tyros','NAA_Ace','NAA_Asp','MM09','MM12','MM14','MM17','MM20','MM22', 'MM27','MM30','MM32' ... + ,'Lip09','Lip13','Lip20','MM37','MM38','MM40','MM42','MMexp','MM_PRESS_PCC','MM_PRESS_CSO'}; for rr = 1:length(all_mets) metabList.(all_mets{rr}) = 0; end diff --git a/libraries/FID-A/fitTools/fit_createMetabListMM.m b/libraries/FID-A/fitTools/fit_createMetabListMM.m index 0118c5f0..3a78c04f 100644 --- a/libraries/FID-A/fitTools/fit_createMetabListMM.m +++ b/libraries/FID-A/fitTools/fit_createMetabListMM.m @@ -3,11 +3,11 @@ % % USAGE: % metabList = fit_createMetabList; -% +% % DESCRIPTION: -% Creates a list of metabolite basis functions that are to be included in +% Creates a list of metabolite basis functions that are to be included in % a fit. -% +% % OUTPUTS: % metabList = structure including flags (1 = included, 0 = excluded) for % each metabolite included in the FID-A spin system definition, @@ -18,7 +18,7 @@ % NONE function metabList = fit_createMetabListMM(sequence) -switch sequence +switch sequence case 'unedited' % Select metabolites to include in basis set metabList.Ala = 0; @@ -50,6 +50,8 @@ metabList.Ser = 0; metabList.Tau = 0; metabList.Tyros = 0; + metabList.NAA_Ace = 0; + metabList.NAA_Asp = 0; % Select MM/lipid basis functions to include metabList.MM09 = 1; @@ -73,7 +75,7 @@ metabList.EtOH = 0; metabList.GABA = 0; metabList.GPC = 0; - metabList.GSH = 0; + metabList.GSH = 1; metabList.Glc = 0; metabList.Gln = 0; metabList.Glu = 0; @@ -82,7 +84,7 @@ metabList.Ins = 0; metabList.Lac = 0; metabList.NAA = 1; - metabList.NAAG = 0; + metabList.NAAG = 1; metabList.PCh = 0; metabList.PCr = 0; metabList.PE = 0; @@ -91,6 +93,8 @@ metabList.Ser = 0; metabList.Tau = 0; metabList.Tyros = 0; + metabList.NAA_Ace = 0; + metabList.NAA_Asp = 0; % Select MM/lipid basis functions to include metabList.MM09 = 0; @@ -103,4 +107,4 @@ metabList.Lip20 = 0; end -end \ No newline at end of file +end diff --git a/libraries/FID-A/fitTools/fit_makeMMBasis.m b/libraries/FID-A/fitTools/fit_makeMMBasis.m new file mode 100644 index 00000000..116a4b81 --- /dev/null +++ b/libraries/FID-A/fitTools/fit_makeMMBasis.m @@ -0,0 +1,187 @@ +% fit_makeMMBasis.m +% Georg Oeltzschner, Johns Hopkins University 2019. +% +% USAGE: +% [BASIS] = fit_makeBasis(folder, addMMFlag, sequence, editTarget) +% +% DESCRIPTION: +% Generates a basis set in FID-A structure. The code will search all *.mat +% files in the input folder for FID-A structures with simulated spectra. It +% also performs sanity checks on the simulation parameters, and returns +% warnings if parameters are not identical for all parameters. +% +% INPUTS: +% folder = folder containing *.mat files representing FID-A structures +% addMMFlag = Flag to decide whether MM and lipid basis functions should be +% added to the basis set. +% OPTIONS: 1 = Add MM+lip (Default) +% 0 = Don't add MM+lip +% sequence = sequence type +% OPTIONS: 'unedited' (default) +% 'MEGA' +% 'HERMES' +% 'HERCULES' +% editTarget= Target molecule of edited data. +% OPTIONS: 'GABA' +% 'GSH' +% ' + +% +% OUTPUTS: +% BASIS = Simulated basis set in FID-A structure format. + +function [BASIS] = fit_makeMMBasis(inBASIS) + + BASIS = inBASIS; + + BASIS.fids = BASIS.fids .* BASIS.scale; + BASIS.specs = BASIS.specs .* BASIS.scale; + + + n = BASIS.n; + sw = BASIS.spectralwidth; + Bo = BASIS.Bo; + centerFreq = BASIS.centerFreq; + % The amplitude and FWHM values are determined as for the LCModel and + % TARQUIN algorithms (see Wilson et al., MRM 2011). + hzppm = Bo*42.577; + + % To scale the amplitudes correctly, we first need to determine the + % area of the 3.027 ppm CH3 signal of creatine + [CrArea] = detCrArea(BASIS); + oneProtonArea = CrArea/3; + + % Next, we determine the area of a Gaussian singlet with nominal area 1 + testGaussian = op_gaussianPeak(n,sw,Bo,centerFreq,0.1*hzppm,0,1); + testGaussian = op_dccorr(testGaussian,'p'); + gaussianArea = sum(real(testGaussian.specs)); + + % Now we know the scaling factor to generate MM/lipid signals with the + % correct relative scaling with respect to the CH3 signal + MM09 = op_gaussianPeak(n,sw,Bo,centerFreq,0.1*hzppm,0.91,3*oneProtonArea/gaussianArea); + MMBase.MM09 = op_dccorr(MM09,'p'); + MM12 = op_gaussianPeak(n,sw,Bo,centerFreq,0.15*hzppm,1.21,2*oneProtonArea/gaussianArea); + MMBase.MM12 = op_dccorr(MM12,'p'); + MM15 = op_gaussianPeak(n,sw,Bo,centerFreq,0.15*hzppm,1.51,2*oneProtonArea/gaussianArea); + MMBase.MM15 = op_dccorr(MM15,'p'); + MMBase.MM15.fids = -MMBase.MM15.fids; + MMBase.MM15.specs = -MMBase.MM15.specs; + MM18 = op_gaussianPeak(n,sw,Bo,centerFreq,0.1*hzppm,1.8,2*oneProtonArea/gaussianArea); + MMBase.MM18 = op_dccorr(MM18,'p'); + MM20 = op_gaussianPeak(n,sw,Bo,centerFreq,0.1*hzppm,2.08,3*oneProtonArea/gaussianArea); + MMBase.MM20 = op_dccorr(MM20,'p'); + MMBase.MM20.fids = -MMBase.MM20.fids; + MMBase.MM20.specs = -MMBase.MM20.specs; + MM23 = op_gaussianPeak(n,sw,Bo,centerFreq,0.2*hzppm,2.3,0.33*oneProtonArea/gaussianArea); + MMBase.MM23 = op_dccorr(MM23,'p'); + MMBase.MM23.fids = MMBase.MM23.fids; + MMBase.MM23.specs = MMBase.MM23.specs; + MM3co = op_gaussianPeak(n,sw,Bo,centerFreq,14,3,2*oneProtonArea/gaussianArea); + MM3co = op_dccorr(MM3co,'p'); + MMBase.MM3co = op_dccorr(MM3co,'p'); + +% MM20a = op_gaussianPeak(n,sw,Bo,centerFreq,0.15*hzppm,2.08,1.33*oneProtonArea/gaussianArea); +% MM20b = op_gaussianPeak(n,sw,Bo,centerFreq,0.2*hzppm,2.25,0.33*oneProtonArea/gaussianArea); +% MM20c = op_gaussianPeak(n,sw,Bo,centerFreq,0.15*hzppm,1.95,0.33*oneProtonArea/gaussianArea); +% MM20d = op_gaussianPeak(n,sw,Bo,centerFreq,0.2*hzppm,3.0,0.4*oneProtonArea/gaussianArea); +% MM20 = op_addScans(MM20a,MM20b); MM20 = op_addScans(MM20,MM20c); MM20 = op_addScans(MM20,MM20d); +% MMBase.MM20 = op_dccorr(MM20,'p'); + + MMLips = {'MM09','MM12','MM15','MM18','MM20','MM23','MM3co'}; + + % Now copy over the names, fids, and specs into the basis set structure + BASIS = rmfield(BASIS,'fids'); + BASIS = rmfield(BASIS,'specs'); + BASIS = rmfield(BASIS,'name'); + BASIS.fids(:,1) = MMBase.(MMLips{1}).fids; + BASIS.specs(:,1) = MMBase.(MMLips{1}).specs; + BASIS.name{1} = MMLips{1}; + for rr = 2:length(MMLips) + BASIS.name{rr} = MMLips{rr}; + BASIS.fids(:,rr) = MMBase.(MMLips{rr}).fids; + BASIS.specs(:,rr) = MMBase.(MMLips{rr}).specs; + end + + +% Copy over the FID, specs, dims, and the metabolite names +BASIS.flags.addedMM = 1; +BASIS.nMM = length(MMLips); +BASIS.nMets = 0; +BASIS.sz = size(BASIS.fids); + +BASIS.fids = BASIS.fids ./ BASIS.scale; +BASIS.specs = BASIS.specs ./ BASIS.scale; + + +end + + +% detCrArea.m +% Georg Oeltzschner, Johns Hopkins University 2020 +% +% USAGE: +% [CrArea] = detCrArea(buffer); +% +% DESCRIPTION: +% Finds the creatine spectrum in the temporary basis set buffer, then fits +% a Lorentzian to the 3.027 ppm CH3 creatine singlet to determine its area. +% Subsequently, macromolecule and lipid basis functions are scaled +% accordingly. +% +% INPUTS: +% in = a temporary buffer containing simulated basis functions +% +% OUTPUTS: +% CrArea = Estimated area under the 3.027 ppm CH3 Cr singlet. + + +function [CrArea] = detCrArea(in); + +% Find the creatine basis function +idx_Cr = find(strcmp(in.name,'Cr')); +if isempty(idx_Cr) + error('No basis function with nametag ''Cr'' found! Abort!'); +end + +%[~, idx_3027] = min(abs(buffer.ppm(:,1)-3.027)); + +% Determine the window where we are going to look for the peak. +ppm = in.ppm(1,:); +ppmmin = 3.027 - 0.4; +ppmmax = 3.027 + 0.4; +refWindow = in.specs(ppm>ppmmin & ppmppmmin & ppm= 0.4*abs(maxRef)); +FWHM1 = abs(ppmWindow(gtHalfMax(1)) - ppmWindow(gtHalfMax(end))); +FWHM1 = FWHM1*(42.577*in.Bo(1)); %Assumes proton. + +% Determine an initial estimate for the center frequency of the Cr peak +crFreq = ppmWindow(maxRef_index); + +% Set up the fit +parsGuess=zeros(1,5); +parsGuess(1) = maxRef; % amplitude +parsGuess(2) = (5*in.Bo/3)/(42.577*in.Bo); %FWHM. Assumes Proton. LW = 5/3 Hz/T. % FWHM. Assumes Proton. +parsGuess(3) = crFreq; % center frequency +parsGuess(4) = 0; % baseline offset +parsGuess(5) = 0; % phase + +% Run first guess +yGuess = op_lorentz(parsGuess, ppmWindow); +parsFit = nlinfit(ppmWindow, real(refWindow'), @op_lorentz, parsGuess); +yFit = op_lorentz(parsFit, ppmWindow); + +% figure; +% plot(ppmWindow,refWindow,'.',ppmWindow,yGuess,':',ppmWindow,yFit); +% legend('data','guess','fit'); + +CrArea = sum(yFit); + +end \ No newline at end of file diff --git a/libraries/FID-A/fitTools/fit_runFitMM.m b/libraries/FID-A/fitTools/fit_runFitMM.m index 2f83e8ff..1a6dc85c 100644 --- a/libraries/FID-A/fitTools/fit_runFitMM.m +++ b/libraries/FID-A/fitTools/fit_runFitMM.m @@ -3,7 +3,7 @@ % % USAGE: % [fitParams, resBasisSet] = fit_runFit(dataToFit, basisSet, fitModel, fitOpts); -% +% % DESCRIPTION: % This function performs spectral fitting of the data in dataToFit, using % the basis set in basisSet, using a set of options defined in fitOpts. @@ -14,7 +14,7 @@ % The function 'fitModel' describes the actual fitting process that is % being performed. The workflow is designed to encourage development and % easy testing/implementation of new quantitative models. -% +% % OUTPUTS: % fitParams = Structure containing all necessary fit parameters % (model-dependent) @@ -32,21 +32,36 @@ if nargin<4 fitOpts = fit_defaultFitOpts(fitModel); end -switch fitOpts.sequence - case 'unedited' - %Invert the NAA, Cr and CrCH2 peaks - basisSet.specs(:,1)=-basisSet.specs(:,1); - basisSet.specs(:,2)=-basisSet.specs(:,2); - basisSet.specs(:,4)=-basisSet.specs(:,4); - case 'MEGA' - %Invert the NAA peaks - basisSet.specs(:,1)=-basisSet.specs(:,1); + +if ~strcmp(fitModel,'OspreyMMGaussian') + switch fitOpts.sequence + case 'unedited' + %Invert the NAA, Cr and CrCH2 peaks + basisSet.specs(:,1)=-basisSet.specs(:,1); + basisSet.specs(:,2)=-basisSet.specs(:,2); + basisSet.specs(:,4)=-basisSet.specs(:,4); + case 'MEGA' + %Invert the NAA/NAAG peak +% basisSet.specs(:,2)=-basisSet.specs(:,2); +% basisSet.specs(:,3)=-basisSet.specs(:,3); +% basisSet.specs(:,4)=-basisSet.specs(:,4); + basisSet.specs(:,1)=-basisSet.specs(:,1); + basisSet.specs(:,2)=-basisSet.specs(:,2); + basisSet.specs(:,3)=-basisSet.specs(:,3); +% basisSet.specs(:,4)=-basisSet.specs(:,4); +% basisSet.specs(:,5)=-basisSet.specs(:,5); +% basisSet.specs(:,6)=-basisSet.specs(:,6); +% basisSet.specs(:,7)=-basisSet.specs(:,7); + + end end %%% 1. SELECT THE MODEL %%% switch fitModel case 'Osprey' [fitParams, resBasisSet] = fit_OspreyMM(dataToFit, basisSet, fitOpts); + case 'OspreyMMGaussian' + [fitParams, resBasisSet] = fit_OspreyMMGaussians(dataToFit, basisSet, fitOpts); end @@ -67,7 +82,7 @@ % Determine fitting range (in ppm) for the metabolite and water spectra fitOpts.range = [0.2 4.2]; % [ppm] Default: [0.2 4.2] fitOpts.rangeWater = [2.0 7.4]; % [ppm] Default: [2.0 7.4] - + % Determine the baseline knot spacing (in ppm) for the metabolite spectra fitOpts.bLineKnotSpace = 0.4; % [ppm] Default: 0.4. end diff --git a/libraries/FID-A/fitTools/fit_runFitWater.m b/libraries/FID-A/fitTools/fit_runFitWater.m index 08a05529..20d2a596 100644 --- a/libraries/FID-A/fitTools/fit_runFitWater.m +++ b/libraries/FID-A/fitTools/fit_runFitWater.m @@ -36,6 +36,7 @@ %%% 1. PREPARE DATA AND BASIS SETS %%% % Resample basis set to match data resolution and frequency range resBasisSet = fit_resampleBasis(dataToFit, basisSet); +resBasisSet.names = dataToFit.names; %%% 2. SELECT THE MODEL %%% diff --git a/libraries/FID-A/fitTools/fit_selectMetabs.m b/libraries/FID-A/fitTools/fit_selectMetabs.m index 9cd809c7..a5f008e4 100644 --- a/libraries/FID-A/fitTools/fit_selectMetabs.m +++ b/libraries/FID-A/fitTools/fit_selectMetabs.m @@ -38,9 +38,9 @@ fitMM = 1; end % Save all available metabolite names in a cell -all_mets = {'Ala','Asc','Asp','bHB','bHG','Cit','Cr','CrCH2','EA','EtOH','GABA','GPC','GSH','Glc','Gln' ... +all_mets = {'Ala','Asc','Asp','bHB','bHG','Cit','Cr','CrCH2','EA','EtOH','fCho','GABA','GPC','GSH','Glc','Gln' ... ,'Glu','Gly','HCar','H2O','Ins','Lac','NAA','NAAG','PCh','PCr','PE','Phenyl' ... - ,'Scyllo','Ser','Tau','Tyros'}; + ,'Scyllo','Ser','Tau','Tyros','NAA_Ace','NAA_Asp'}; % Duplicate the input basis set basisSetOut = basisSetIn; @@ -63,24 +63,31 @@ % If the flag for including MM/lipid basis functions is set in osp_FitInitialise, % include them now -switch fitMM - case 2 - all_MMs = {'MMexp'}; - otherwise - all_MMs = {'MM09','MM12','MM14','MM17','MM20','Lip09','Lip13','Lip20'}; -end + +all_MMs = {'MM09','MM12','MM14','MM17','MM20','MM22', 'MM27','MM30','MM32','Lip09','Lip13','Lip20','MM37','MM38','MM40','MM42','MMexp','MM_PRESS_PCC','MM_PRESS_CSO'}; + % Check which of these are available in the basis set MMsInBasisSet = basisSetIn.name; [MMsToKeep,~,~] = intersect(MMsInBasisSet, all_MMs, 'stable'); -if fitMM ==1 - idx_toKeepMM = ones(length(MMsToKeep),1); -else if fitMM == 2 - idx_toKeepMM = zeros(12,1); - idx_toKeepMM(end) = 1; - else - idx_toKeepMM = zeros(length(MMsToKeep),1); +idx_toKeepMM = zeros(length(MMsToKeep),1); +if fitMM + for kk = 1:length(MMsToKeep) + if ~isfield(metabList, MMsToKeep{kk}) || ~metabList.(MMsToKeep{kk}) + idx_toKeepMM(kk) = 0; + else + idx_toKeepMM(kk) = 1; + end end end +% if fitMM ==1 +% idx_toKeepMM = ones(length(MMsToKeep),1); +% else if fitMM == 2 +% idx_toKeepMM = zeros(8,1); +% idx_toKeepMM(end) = 1; +% else +% idx_toKeepMM = zeros(length(MMsToKeep),1); +% end +% end idx_toKeep = [idx_toKeep; idx_toKeepMM]; basisSetOut.nMM = sum(idx_toKeepMM); diff --git a/libraries/FID-A/fitTools/fit_sortBasisSet.m b/libraries/FID-A/fitTools/fit_sortBasisSet.m index fd0c5a0a..269d5cc2 100644 --- a/libraries/FID-A/fitTools/fit_sortBasisSet.m +++ b/libraries/FID-A/fitTools/fit_sortBasisSet.m @@ -18,9 +18,9 @@ function basisSetOut = fit_sortBasisSet(basisSetIn) % Save all available metabolite names in a cell -all_mets = {'Ala','Asc','Asp','bHB','bHG','Cit','Cr','CrCH2','EA','EtOH','GABA','GPC','GSH','Glc','Gln' ... +all_mets = {'Ala','Asc','Asp','bHB','bHG','Cit','Cr','CrCH2','EA','EtOH','fCho','GABA','GPC','GSH','Glc','Gln' ... ,'Glu','Gly','H2O','Ins','Lac','NAA','NAAG','PCh','PCr','PE','Phenyl' ... - ,'Scyllo','Ser','Tau','Tyros'}; + ,'Scyllo','Ser','Tau','Tyros','NAA_Ace','NAA_Asp'}; % Duplicate the input basis set basisSetOut = basisSetIn; @@ -38,7 +38,7 @@ end basisSetOut.nMets = actBasisFnct-1; -all_MMs = {'MM09','MM12','MM14','MM17','MM20','Lip09','Lip13','Lip20'}; +all_MMs = {'MM09','MM12','MM14','MM17','MM20','MM22', 'MM27','MM30','MM32','Lip09','Lip13','Lip20','MM37','MM38','MM40','MM42','MMexp','MM_PRESS_PCC','MM_PRESS_CSO'}; for kk = 1 : length(all_MMs) name = all_MMs{kk}; idx = find(strcmp(basisSetIn.name,name)); diff --git a/libraries/FID-A/inputOutput/io_loadspec_GE.m b/libraries/FID-A/inputOutput/io_loadspec_GE.m index 1b6b44ae..4f27b11f 100755 --- a/libraries/FID-A/inputOutput/io_loadspec_GE.m +++ b/libraries/FID-A/inputOutput/io_loadspec_GE.m @@ -268,7 +268,13 @@ else out_w.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end - +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; %DONE diff --git a/libraries/FID-A/inputOutput/io_loadspec_bruk.m b/libraries/FID-A/inputOutput/io_loadspec_bruk.m index 6047d13a..7b201c03 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_bruk.m +++ b/libraries/FID-A/inputOutput/io_loadspec_bruk.m @@ -351,6 +351,13 @@ else out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; if isRef @@ -395,4 +402,12 @@ else ref.flags.isISIS=(ref.sz(ref.dims.subSpecs)==4); end + % Sequence flags + ref.flags.isUnEdited = 0; + ref.flags.isMEGA = 0; + ref.flags.isHERMES = 0; + ref.flags.isHERCULES = 0; + ref.flags.isPRIAM = 0; + ref.flags.isMRSI = 0; + end diff --git a/libraries/FID-A/inputOutput/io_loadspec_data.m b/libraries/FID-A/inputOutput/io_loadspec_data.m index 8bd1ed6d..92f03fc1 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_data.m +++ b/libraries/FID-A/inputOutput/io_loadspec_data.m @@ -462,7 +462,13 @@ else out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end - +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; %FOR WATER UNSUPPRESSED DATA %FILLING IN DATA STRUCTURE @@ -510,6 +516,13 @@ else out_w.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end + % Sequence flags + out_w.flags.isUnEdited = 0; + out_w.flags.isMEGA = 0; + out_w.flags.isHERMES = 0; + out_w.flags.isHERCULES = 0; + out_w.flags.isPRIAM = 0; + out_w.flags.isMRSI = 0; end % No water in list file diff --git a/libraries/FID-A/inputOutput/io_loadspec_dicom.m b/libraries/FID-A/inputOutput/io_loadspec_dicom.m index 7f22f40a..81ac9e3f 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_dicom.m +++ b/libraries/FID-A/inputOutput/io_loadspec_dicom.m @@ -315,7 +315,25 @@ else out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end - +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; +if strcmp(seq,'PRESS') || strcmp(seq,'STEAM') || strcmp(seq,'SLASER') + out.flags.isUnEdited = 1; +end +if contains(seq,'MEGA') + out.flags.isMEGA = 1; +end +if strcmp(seq,'HERMES') + out.flags.isHERMES = 1; +end +if strcmp(seq,'HERCULES') + out.flags.isHERCULES = 1; +end %DONE diff --git a/libraries/FID-A/inputOutput/io_loadspec_lcmraw.m b/libraries/FID-A/inputOutput/io_loadspec_lcmraw.m index 5009a298..02d52dad 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_lcmraw.m +++ b/libraries/FID-A/inputOutput/io_loadspec_lcmraw.m @@ -195,6 +195,13 @@ else out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end + % Sequence flags + out.flags.isUnEdited = 0; + out.flags.isMEGA = 0; + out.flags.isHERMES = 0; + out.flags.isHERCULES = 0; + out.flags.isPRIAM = 0; + out.flags.isMRSI = 0; diff --git a/libraries/FID-A/inputOutput/io_loadspec_niimrs.m b/libraries/FID-A/inputOutput/io_loadspec_niimrs.m index 9af7bb49..01184d52 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_niimrs.m +++ b/libraries/FID-A/inputOutput/io_loadspec_niimrs.m @@ -401,6 +401,8 @@ out.nii_mrs.hdr_ext = hdr_ext; if isfield(hdr_ext, 'SequenceName') out.seq = hdr_ext.SequenceName; +else + out.seq = 'nii_spec'; end % Geometry @@ -435,6 +437,13 @@ else out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; end diff --git a/libraries/FID-A/inputOutput/io_loadspec_rda.m b/libraries/FID-A/inputOutput/io_loadspec_rda.m index 858acc84..b13f4065 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_rda.m +++ b/libraries/FID-A/inputOutput/io_loadspec_rda.m @@ -46,18 +46,18 @@ tline = fgets(fid); while (isempty(strfind(tline , head_end_text))) - + tline = fgets(fid); - + if ( isempty(strfind (tline , head_start_text)) + isempty(strfind (tline , head_end_text )) == 2) - - + + % Store this data in the appropriate format - + occurence_of_colon = findstr(':',tline); variable = tline(1:occurence_of_colon-1) ; value = tline(occurence_of_colon+1 : length(tline)) ; - + switch variable case { 'PatientID' , 'PatientName' , 'StudyDescription' , 'PatientBirthDate' , 'StudyDate' , 'StudyTime' , 'PatientAge' , 'SeriesDate' , ... 'SeriesTime' , 'SeriesDescription' , 'ProtocolName' , 'PatientPosition' , 'ModelName' , 'StationName' , 'InstitutionName' , ... @@ -72,10 +72,10 @@ case 1 rda.sex = 'Male'; case 2 - + rda.sex = 'Female'; end - + case { 'SeriesNumber' , 'InstanceNumber' , 'AcquisitionNumber' , 'NumOfPhaseEncodingSteps' , 'NumberOfRows' , 'NumberOfColumns' , 'VectorSize' } %Integers eval(['rda.' , variable , ' = str2num(value); ']); @@ -111,16 +111,16 @@ rda.ColumnVector(2) = str2num(value); case {'ColumnVector[2]' } rda.ColumnVector(3) = str2num(value); - + otherwise % We don't know what this variable is. Report this just to keep things clear %disp(['Unrecognised variable ' , variable ]); end - + else % Don't bother storing this bit of the output end - + end % Get the header of the first file to make some decisions. @@ -172,12 +172,12 @@ complex_data = fread(fid , rda.CSIMatrix_Size(1) * rda.CSIMatrix_Size(1) *rda.CSIMatrix_Size(1) *rda.VectorSize * 2 , 'double'); %fread(fid , 1, 'double'); %This was a check to confirm that we had read all the data (it passed!) fclose(fid); - + % Now convert this data into something meaningful - + %Reshape so that we can get the real and imaginary separated hmm = reshape(complex_data, 2 , rda.VectorSize , rda.CSIMatrix_Size(1) , rda.CSIMatrix_Size(2) , rda.CSIMatrix_Size(3) ); - + %Combine the real and imaginary into the complex matrix fids(kk,:) = complex(hmm(1,:,:,:,:),hmm(2,:,:,:,:)); end @@ -308,4 +308,11 @@ out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; end diff --git a/libraries/FID-A/inputOutput/io_loadspec_sdat.m b/libraries/FID-A/inputOutput/io_loadspec_sdat.m index f3b3a2cd..7841e5a2 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_sdat.m +++ b/libraries/FID-A/inputOutput/io_loadspec_sdat.m @@ -171,5 +171,11 @@ else out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end - +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; %DONE diff --git a/libraries/FID-A/inputOutput/io_loadspec_twix.m b/libraries/FID-A/inputOutput/io_loadspec_twix.m index 9eeec5c9..3199029e 100644 --- a/libraries/FID-A/inputOutput/io_loadspec_twix.m +++ b/libraries/FID-A/inputOutput/io_loadspec_twix.m @@ -570,6 +570,24 @@ out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end - +% Sequence flags +out.flags.isUnEdited = 0; +out.flags.isMEGA = 0; +out.flags.isHERMES = 0; +out.flags.isHERCULES = 0; +out.flags.isPRIAM = 0; +out.flags.isMRSI = 0; +if strcmp(seq,'PRESS') || strcmp(seq,'STEAM') || strcmp(seq,'SLASER') + out.flags.isUnEdited = 1; +end +if contains(seq,'MEGA') + out.flags.isMEGA = 1; +end +if strcmp(seq,'HERMES') + out.flags.isHERMES = 1; +end +if strcmp(seq,'HERCULES') + out.flags.isHERCULES = 1; +end %DONE diff --git a/libraries/FID-A/processingTools/op_SignalFilter.m b/libraries/FID-A/processingTools/op_SignalFilter.m new file mode 100644 index 00000000..5b2610a4 --- /dev/null +++ b/libraries/FID-A/processingTools/op_SignalFilter.m @@ -0,0 +1,198 @@ +%%% BELOW ARE THE SIGNAL FILTERING FUNCTIONS + +function out = op_SignalFilter(spec, r_flag, q_flag, in) +% Based on: Cobas, J.C., Bernstein, M.A., Martín-Pastor, M., Tahoces, P.G., +% 2006. A new general-purpose fully automatic baseline-correction procedure +% for 1D and 2D NMR data. J. Magn. Reson. 183, 145-51. + +showPlots = 1; + +[z.real, z.imag] = BaselineModeling(spec, r_flag, q_flag, in); + +if showPlots == 1 + + freq = in.ppm; + + H = figure(77); + d.w = 0.5; + d.h = 0.65; + d.l = (1-d.w)/2; + d.b = (1-d.h)/2; + set(H,'Color', 'w', 'Units', 'Normalized', 'OuterPosition', [d.l d.b d.w d.h]); + + subplot(2,2,1); cla; + plot(freq, real(spec), 'k'); + set(gca, 'XDir', 'reverse', 'XLim', [0 6], 'Box', 'off'); + hold on; + plot(freq, z.real, 'r'); + set(gca, 'XDir', 'reverse', 'XLim', [0 6], 'Box', 'off'); + + subplot(2,2,2); cla; + plot(freq, imag(spec), 'k'); + set(gca, 'XDir', 'reverse', 'XLim', [0 6], 'Box', 'off'); + hold on; + plot(freq, z.imag, 'r'); + set(gca, 'XDir', 'reverse', 'XLim', [0 6], 'Box', 'off'); + + subplot(2,2,3); cla; + plot(freq, real(spec) - z.real, 'k'); + set(gca, 'XDir', 'reverse', 'XLim', [0 6], 'Box', 'off'); + + subplot(2,2,4); cla; + plot(freq, imag(spec) - z.imag, 'k'); + set(gca, 'XDir', 'reverse', 'XLim', [0 6], 'Box', 'off'); + + drawnow; + %pause(0.5); + +end + +% out = ifft(fftshift(complex(real(spec) - z.real, imag(spec) - z.imag),in.dims.t),[],in.dims.t); +fids = ifft(fftshift(complex(z.real,z.imag),in.dims.t),[],in.dims.t); + +out = in; + +out.fids = fids; +out.specs = complex(z.real,z.imag); + +[out2] = op_iterativeFatFilter(out,[1.1 1.85],150,1500,1); +end + + +function [z_real, z_imag] = BaselineModeling(spec, r_flag, q_flag, in) +% Based on: +% Golotvin & Williams, 2000. Improved baseline recognition +% and modeling of FT NMR spectra. J. Magn. Reson. 146, 122-125 +% Cobas et al., 2006. A new general-purpose fully automatic +% baseline-correction procedure for 1D and 2D NMR data. J. Magn. Reson. +% 183, 145-151 + +% Power spectrum of first-derivative of signal calculated by CWT +Wy = abs(cwt2(real(spec), 10)).^2; + +freq = in.ppm; +noiseLim = freq <= 12 & freq >= 10; + +sigma = std(Wy(noiseLim)); + +w = 1:5; +k = 3; +baseline = zeros(length(Wy),1); +signal = zeros(length(Wy),1); + +while 1 + if w(end) > length(Wy) + break + end + h = max(Wy(w)) - min(Wy(w)); + if h < k*sigma + baseline(w) = Wy(w); + else + signal(w) = Wy(w); + end + w = w + 1; +end + +% Include lipids in baseline estimate and water, as appropriate +if r_flag + lipidLim = freq <= 1.8 & freq >= -2; + baseline(lipidLim) = Wy(lipidLim); +end +if q_flag + waterLim = freq <= 5.5 & freq >= 4.25; + baseline(waterLim) = Wy(waterLim); +end + +z_real = real(spec); +z_real(baseline == 0) = 0; +if r_flag + lipids = whittaker(z_real(lipidLim), 2, 20); +end +if q_flag + water = whittaker(z_real(waterLim), 2, 0.2); +end +z_real = whittaker(z_real, 2, 1e3); +if r_flag + z_real(lipidLim) = lipids; +end +if q_flag + z_real(waterLim) = water; +end + +z_imag = -imag(hilbert(z_real)); + +end + + +function Wy = cwt2(y, a) + +precis = 10; +coef = sqrt(2)^precis; +pas = 1/2^precis; + +lo = [sqrt(2)*0.5 sqrt(2)*0.5]; +hi = lo .* [1 -1]; +long = length(lo); +nbpts = (long-1)/pas+2; + +psi = coef*upcoef2(lo,hi,precis); +psi = [0 psi 0]; +xVal = linspace(0,(nbpts-1)*pas,nbpts); + +step = xVal(2) - xVal(1); +valWAV = cumsum(psi)*step; +xVal = xVal - xVal(1); +xMaxVal = xVal(end); + +y = y(:)'; +j = 1+floor((0:a*xMaxVal)/(a*step)); +if length(j) == 1 + j = [1 1]; +end +f = fliplr(valWAV(j)); + +Wy = -sqrt(a) * keepVec(diff(conv2(y,f,'full')),length(y)); + + function out = upcoef2(lo,hi,a) + out = hi; + for k = 2:a + out = conv2(dyadup2(out),lo,'full'); + end + function out = dyadup2(in) + z = zeros(1,length(in)); + out = [in; z]; + out(end) = []; + out = out(:)'; + end + end + + function out = keepVec(in,len) + out = in; + ok = len >= 0 && len < length(in); + if ~ok + return + end + d = (length(in)-len)/2; + first = 1+floor(d); + last = length(in)-ceil(d); + out = in(first:last); + end + +end + +function z = whittaker(y, d, lambda) +% Code taken from: Eilers, 2003. A perfect smoother. Anal. Chem. 75, +% 3631-3636 + +y = y(:); + +m = length(y); +E = speye(m); +D = diff(E,d); + +w = double(y ~= 0); +W = spdiags(w,0,m,m); +C = chol(W + lambda*(D'*D)); +z = C\(C'\(w.*y)); + +end \ No newline at end of file diff --git a/libraries/FID-A/processingTools/op_ampScale.m b/libraries/FID-A/processingTools/op_ampScale.m index 0c49c3c3..576684d2 100644 --- a/libraries/FID-A/processingTools/op_ampScale.m +++ b/libraries/FID-A/processingTools/op_ampScale.m @@ -16,7 +16,23 @@ function out=op_ampScale(in,A); - +sz_A = length(A); out=in; -out.specs=in.specs*A; -out.fids=in.fids*A; +if sz_A == 1 + out.specs=in.specs*A; + out.fids=in.fids*A; +else + + if in.dims.averages==0 + for ss = 1 : out.sz(end) + out.specs(:,ss)=in.specs(:,ss)*A(ss); + out.fids(:,ss)=in.fids(:,ss)*A(ss); + end + else + for ss = 1 : out.sz(end) + out.specs(:,:,ss)=in.specs(:,:,ss)*A(ss); + out.fids(:,:,ss)=in.fids(:,:,ss)*A(ss); + end + end +end + diff --git a/libraries/FID-A/processingTools/op_average_extra.m b/libraries/FID-A/processingTools/op_average_extra.m new file mode 100644 index 00000000..fd4d25ff --- /dev/null +++ b/libraries/FID-A/processingTools/op_average_extra.m @@ -0,0 +1,101 @@ +% op_averaging.m +% Jamie Near, McGill University 2014. +% +% USAGE: +% out=op_average_extra(in,which); +% +% DESCRIPTION: +% Combine the averages in a scan by adding the averages together and then +% dividing by the number of averages. +% +% INPUTS: +% in = input data in matlab structure format. +% +% OUTPUTS: +% out = Output following averaging. + +function out=op_average_extra(in,to_average); +if nargin < 2 + to_average = 1; +end +if in.dims.extras==0 || in.extras<2 + %DO NOTHING + warning('Just one extra spectrum found. Returning input without modification!'); + out=in; +else + if to_average == 1 + %add the spectrum along the averages dimension; + fids=sum(in.fids,in.dims.extras); + fids=squeeze(fids); + fids=fids/in.sz(in.dims.extras); %divide by number of averages; + + %re-calculate Specs using fft + specs=fftshift(fft(fids,[],in.dims.t),in.dims.t); + + %change the dims variables. + if in.dims.t>in.dims.extras + dims.t=in.dims.t-1; + else + dims.t=in.dims.t; + end + if in.dims.coils>in.dims.extras + dims.coils=in.dims.coils-1; + else + dims.coils=in.dims.coils; + end + if in.dims.averages>in.dims.extras + dims.averages=in.dims.averages-1; + else + dims.averages=in.dims.averages; + end + if in.dims.subSpecs>in.dims.extras + dims.subSpecs=in.dims.subSpecs-1; + else + dims.subSpecs=in.dims.subSpecs; + end + dims.extras = 0; + + else + + end + + + + %re-calculate the sz variable + sz=size(fids); + + + %FILLING IN DATA STRUCTURE + out=in; + out.fids=fids; + out.specs=specs; + out.sz=sz; + out.dims=dims; + out.averages=1; + + %Change all the remaining entries + if to_average == 1 + out.spectralwidth = mean(out.spectralwidth); + out.dwelltime = mean(out.dwelltime); + out.txfrq = mean(out.txfrq); + out.seq = out.seq(1); + out.te = mean(out.te); + out.tr = mean(out.tr); + out.pointsToLeftshift = mean(out.pointsToLeftshift); + out.centerFreq = mean(out.centerFreq); + out.names = out.names(1,:); + out.extra_names = {'Average across all extra entries'}; + out.extras = 0; + else + + end + + %FILLING IN THE FLAGS + out.flags=in.flags; + out.flags.writtentostruct=1; + out.flags.averaged=1; + +end + + + diff --git a/libraries/FID-A/processingTools/op_get_Multispectra_SNR.m b/libraries/FID-A/processingTools/op_get_Multispectra_SNR.m index 9a6ff32b..465ceed0 100644 --- a/libraries/FID-A/processingTools/op_get_Multispectra_SNR.m +++ b/libraries/FID-A/processingTools/op_get_Multispectra_SNR.m @@ -13,8 +13,8 @@ % OUTPUTS: % SNR = Estimated SNR of the input spectrum. -function [SNR]=op_get_Multispectra_SNR(in,MM); - +function [out,SNR]=op_get_Multispectra_SNR(in,MM); +out = in; if nargin < 2 MM = 0; end @@ -25,25 +25,31 @@ if ~MM if in.flags.isUnEdited SNRRange = {[1.8,2.2]}; + QC_names = {'tNAA'}; end if in.flags.isMEGA SNRRange = {[1.8,2.2],[2.8,3.2],[2.8,3.2],[2.8,3.2]}; + QC_names = {'tNAA','tCr',in.target,'tCr'}; end if in.flags.isHERMES || in.flags.isHERCULES SNRRange = {[1.8,2.2],[2.8,3.2],[2.8,3.2],[1.8,2.2],[2.8,3.2],[2.8,3.2],[2.8,3.2]}; + QC_names = {'tNAA','tCr','tCr','tNAA',in.target{1},in.target{2},'tCr'}; end else if in.flags.isUnEdited SNRRange = {[0.7,1.1]}; + QC_names = {'MM09'}; end if in.flags.isMEGA SNRRange = {[0.7,1.1],[0.7,1.1],[0.7,1.1],[0.7,1.1]}; + QC_names = {'MM09','MM09','MM09','MM09'}; end if in.flags.isHERMES || in.flags.isHERCULES SNRRange = {[0.7,1.1],[0.7,1.1],[0.7,1.1],[0.7,1.1],[0.7,1.1],[0.7,1.1],[0.7,1.1]}; + QC_names = {'MM09','MM09','MM09','MM09','MM09','MM09','MM09'}; end end - +out.QC_names = QC_names; SNR = cell(in.subspecs,1); for ss = 1 : in.subspecs if in.subspecs == 1 diff --git a/libraries/FID-A/processingTools/op_iterativeWaterFilter.m b/libraries/FID-A/processingTools/op_iterativeWaterFilter.m index d3852cd6..09e057e7 100644 --- a/libraries/FID-A/processingTools/op_iterativeWaterFilter.m +++ b/libraries/FID-A/processingTools/op_iterativeWaterFilter.m @@ -49,32 +49,51 @@ end end -% Make the first attempt with the initial guess for the number of -% components to be removed -[out_temp,~,~] = op_removeWater(in,wlim,Kinit,M,plot_bool); % Remove the residual water +out_temp = cell(in.subspecs,1); +for ss = 1 : in.subspecs + if in.subspecs == 1 + out_temp{ss} = in; + else + out_temp{ss} = op_takesubspec(in,ss); + end + % Make the first attempt with the initial guess for the number of + % components to be removed + [out_temp{ss},~,~] = op_removeWater(out_temp{ss},wlim,Kinit,M,plot_bool); % Remove the residual water -% If the resulting FID is empty... -if isnan(real(out_temp.fids)) - % ... increase the number of components to 1.5 times the initial guess - K_rr = 1.5*Kinit; - % Run again - while (isnan(real(out_temp.fids(1))) && (K_rr > 0)) - [out_temp,~,~] = op_removeWater(in,wlim,K_rr,M,plot_bool); % Remove the residual water - % If the resulting FID is still empty, decrease the number of - % components and try again until it is not empty. - K_rr = K_rr-1; + % If the resulting FID is empty... + if isnan(real(out_temp{ss}.fids)) + % ... increase the number of components to 1.5 times the initial guess + K_rr = 1.5*Kinit; + % Run again + while (isnan(real(out_temp{ss}.fids(1))) && (K_rr > 0)) + if in.subspecs == 1 + out_temp{ss} = in; + else + out_temp{ss} = op_takesubspec(in,ss); + end + [out_temp{ss},~,~] = op_removeWater(out_temp{ss},wlim,K_rr,M,plot_bool); % Remove the residual water + % If the resulting FID is still empty, decrease the number of + % components and try again until it is not empty. + K_rr = K_rr-1; + end end -end -if isnan(real(out_temp.fids)) - out_temp.fids = in.fids; - out_temp.specs = in.specs; + if isnan(real(out_temp{ss}.fids)) + out_temp{ss}.fids = out_temp{ss}.fids; + out_temp{ss}.specs = out_temp{ss}.specs; + end + out_temp{ss} = op_fddccorr(out_temp{ss},100); % Correct back to baseline end - - % Use the first non-empty FID to return -out = out_temp; -out = op_fddccorr(out,100); % Correct back to baseline +out = out_temp{1}; +watersupp = out_temp{1}.watersupp; +out = rmfield(out,'watersupp'); +out.watersupp{1} = watersupp; +for ss = 2 : in.subspecs + out = op_mergesubspec(out,out_temp{ss}); + out.watersupp{ss} = out_temp{ss}.watersupp; +end + diff --git a/libraries/FID-A/processingTools/op_mergeextra.m b/libraries/FID-A/processingTools/op_mergeextra.m index 8117a092..22e18c93 100644 --- a/libraries/FID-A/processingTools/op_mergeextra.m +++ b/libraries/FID-A/processingTools/op_mergeextra.m @@ -22,7 +22,7 @@ if isfield(in1, 'extra_names') names = in1.extra_names; else - names = cell(); + names = {}; end if ~ischar(varargin{end}) error('You have to at indicate an extra name as last argument') @@ -90,22 +90,25 @@ in1.tr(end+1) = in2.tr; in1.centerFreq(end+1) = in2.centerFreq; in1.pointsToLeftshift(end+1) = in2.pointsToLeftshift; - in1.specReg{end+1} = in2.specReg; + if isfield(in1,'specReg') + in1.specReg{end+1} = in2.specReg; + end if size(in1.names,2) > size(in2.names,2) in2.names = cat(2,in2.names,cell(1,size(in1.names,2)-size(in2.names,2))); else if size(in2.names,2) > size(in1.names,2) in1.names{size(in1.names,1),size(in2.names,2)} = []; end end - if size(in1.watersupp,2) > size(in2.watersupp,2) - in2.watersupp = cat(2,in2.watersupp,cell(1,size(in1.watersupp,2)-size(in2.watersupp,2))); - else if size(in2.watersupp,2) > size(in1.watersupp,2) - in1.watersupp{size(in1.watersupp,1),size(in2.watersupp,2)} = []; - end + if isfield(in1,'watersupp') + if size(in1.watersupp,2) > size(in2.watersupp,2) + in2.watersupp = cat(2,in2.watersupp,cell(1,size(in1.watersupp,2)-size(in2.watersupp,2))); + else if size(in2.watersupp,2) > size(in1.watersupp,2) + in1.watersupp{size(in1.watersupp,1),size(in2.watersupp,2)} = []; + end + end + in1.watersupp = cat(1,in1.watersupp,in2.watersupp); end in1.names = cat(1,in1.names,in2.names); - in1.watersupp = cat(1,in1.watersupp,in2.watersupp); - end sz=size(in1.fids); in1.seq = seq_names; diff --git a/libraries/FID-A/processingTools/op_phaseCrCho.m b/libraries/FID-A/processingTools/op_phaseCrCho.m index d108ff7b..5fd5c233 100644 --- a/libraries/FID-A/processingTools/op_phaseCrCho.m +++ b/libraries/FID-A/processingTools/op_phaseCrCho.m @@ -37,15 +37,32 @@ error('ERROR: Can not operate on data with extras dimension! ABORTING!!'); end if in.dims.subSpecs>0 - error('ERROR: Can not operate on data with multiple subspectra! ABORTING!!'); + temp = cell(in.subspecs,1); + phShift = zeros(in.subspecs,1); + temp{1} = op_takesubspec(in_avg,1); + % Fit the Cr-Cho doublet to the input spectrum + parsFit = op_creChoFit(temp{1}, suppressPlot); + % Extract phase adjustment + phShift = ones(in.subspecs,1) * parsFit(4); + % Apply negative phase of the fit to the data + for ss = 1 : in.subspecs + temp{ss} = op_takesubspec(in_avg,ss); + temp{ss} = op_addphase(temp{ss}, -phShift(ss)*180/pi, 0, temp{ss}.centerFreq, suppressPlot); + end + out = temp{1}; + for ss = 2 : in.subspecs + out = op_mergesubspec(out,temp{ss}); + end + +else + % Fit the Cr-Cho doublet to the input spectrum + parsFit = op_creChoFit(in_avg, suppressPlot); + % Extract phase adjustment + phShift = parsFit(4); + % Apply negative phase of the fit to the data + out = op_addphase(in, -parsFit(4)*180/pi, 0, in.centerFreq, suppressPlot); + end -% Fit the Cr-Cho doublet to the input spectrum -parsFit = op_creChoFit(in_avg, suppressPlot); -% Extract phase adjustment -phShift = parsFit(4); -% Apply negative phase of the fit to the data -out = op_addphase(in, -parsFit(4)*180/pi, 0, in.centerFreq, suppressPlot); - end diff --git a/libraries/FID-A/processingTools/op_plotspec.m b/libraries/FID-A/processingTools/op_plotspec.m index 61188ca6..78462a9a 100755 --- a/libraries/FID-A/processingTools/op_plotspec.m +++ b/libraries/FID-A/processingTools/op_plotspec.m @@ -279,9 +279,9 @@ box off; xlabel(xlab,'FontSize',20); ylabel(ylab,'FontSize',20); -Fig1Ax1 = get(out, 'Children'); -Fig1Ax1Line1 = get(Fig1Ax1, 'Children'); -set(Fig1Ax1Line1, 'LineWidth', 1); +% Fig1Ax1 = get(out, 'Children'); +% Fig1Ax1Line1 = get(Fig1Ax1, 'Children'); +% set(Fig1Ax1Line1, 'LineWidth', 1); diff --git a/libraries/FID-A/processingTools/op_preref.m b/libraries/FID-A/processingTools/op_preref.m index e52257d1..821a3725 100644 --- a/libraries/FID-A/processingTools/op_preref.m +++ b/libraries/FID-A/processingTools/op_preref.m @@ -152,7 +152,7 @@ specs = temp_proc.specs(:,av:av+(round(temp_proc.averages*0.1)-1)); temp_spec.fids = mean(fids,2); % store average fid temp_spec.specs = mean(specs,2); % store average spectra - [refShift, ~] = osp_CrChoReferencing(temp_spec); % determine frequency shift + [refShift, ~] = osp_XReferencing(temp_spec,[3.03 3.22],[1 1],[0 4.2],1);% determine frequency shift refShift_ind_ini(av : av+round(temp_proc.averages*0.1)-1) = refShift; %save initial frequency guess end if mod(temp_proc.averages,round(temp_proc.averages*0.1)) > 0 % remaining averages if data isn't a multiple of 10. @@ -160,7 +160,7 @@ specs = temp_proc.specs(:,end-(mod(temp_proc.averages,round(temp_proc.averages*0.1))-1):end); temp_spec.fids = mean(fids,2); % store average fid temp_spec.specs = mean(specs,2); % store average spectra - [refShift, ~] = osp_CrChoReferencing(temp_spec); % determine frequency shift + [refShift, ~] = osp_XReferencing(temp_spec,[3.03 3.22],[1 1],[0 4.2],1);% determine frequency shift refShift_ind_ini(end-(mod(temp_proc.averages,round(temp_proc.averages*0.1))-1) : temp_proc.averages) = refShift; %save initial frequency guess end diff --git a/libraries/FID-A/processingTools/op_takeextra.m b/libraries/FID-A/processingTools/op_takeextra.m new file mode 100644 index 00000000..48f38c17 --- /dev/null +++ b/libraries/FID-A/processingTools/op_takeextra.m @@ -0,0 +1,99 @@ +% op_takeextra.m +% Jamie Near, McGill University 2014. +% +% USAGE: +% out=op_takesubspec(in,index); +% +% DESCRIPTION: +% Extract the subspectra with indices corresponding to the 'index' input +% array. +% +% INPUTS: +% in = input data in matlab structure format. +% index = vector indicating the indices of the subspectra you would like +% to extract. +% +% OUTPUTS: +% out = Output dataset consisting of subspectra indices extracted from +% the input. + +function out=op_takeextra(in,index); + +if in.dims.extras>0 +in.fids = squeeze(in.fids); + if in.dims.extras==1 + %SHOULD NEVER HAPPEN (Time dimension should always be dim=1) + error('ERROR: dims.extras==1. This should never happen! Aborting!'); + elseif in.dims.extras==2 + fids=in.fids(:,index,:,:,:); + elseif in.dims.extras==3; + fids=in.fids(:,:,index,:,:,:); + elseif in.dims.extras==4; + fids=in.fids(:,:,:,index,:,:,:); + elseif in.dims.extras==5 + fids=in.fids(:,:,:,:,index,:,:,:); + end + + %re-calculate Specs using fft + specs=fftshift(fft(fids,[],in.dims.t),in.dims.t); + + %change the dims variables + if in.dims.t>in.dims.extras + dims.t=in.dims.t-1; + else + dims.t=in.dims.t; + end + if in.dims.coils>in.dims.extras + dims.coils=in.dims.coils-1; + else + dims.coils=in.dims.coils; + end + if in.dims.averages>in.dims.extras + dims.averages=in.dims.averages-1; + else + dims.averages=in.dims.averages; + end + if in.dims.extras>in.dims.extras + dims.subSpecs=in.dims.subSpecs-1; + else + dims.subSpecs=in.dims.subSpecs; + end + dims.extras=0; + + %re-calculate the sz variable + sz=size(fids); + + + %FILLING IN DATA STRUCTURE + out=in; + out.fids=fids; + out.specs=specs; + out.sz=sz; + out.dims=dims; + if ~out.flags.averaged + try + out.averages = out.sz(out.dims.averages); + catch + out.averages = out.sz(2); + end + end + out.extras=1; + if isfield(out, 'extra_names') + out.extra_names = out.extra_names(index); + end + out.names = out.names(index,:); + out.spectralwidth = out.spectralwidth(index); + out.dwelltime = out.dwelltime(index); + out.txfrq = out.txfrq(index); + out.seq = out.seq{index}; + out.te = out.te(index); + out.tr = out.tr(index); + out.pointsToLeftshift = out.pointsToLeftshift(index); + out.centerFreq = out.centerFreq(index); + %FILLING IN THE FLAGS + out.flags=in.flags; + out.flags.writtentostruct=1; + out.flags.isISIS=0; +else + out = in; +end diff --git a/libraries/FID-A/processingTools/op_takesubspec.m b/libraries/FID-A/processingTools/op_takesubspec.m index a97fd847..b3dfcc9b 100644 --- a/libraries/FID-A/processingTools/op_takesubspec.m +++ b/libraries/FID-A/processingTools/op_takesubspec.m @@ -19,13 +19,24 @@ function out=op_takesubspec(in,index); +if ~isnumeric(index) + index = find(strcmp(in.names,index)); + if isempty(index) + index = 1; + end +end + if in.flags.subtracted error('ERROR: Subspectra have already been combined! Aborting!'); end % in.fids = squeeze(in.fids); if in.dims.subSpecs==0 %Can't take subspec because there are none: - error('ERROR: There are no subspectra in this dataset! Aborting!'); + if index > 1 + error('ERROR: There are no subspectra in this dataset! Aborting!'); + else + fids = in.fids; + end elseif in.dims.subSpecs==1 %SHOULD NEVER HAPPEN (Time dimension should always be dim=1) error('ERROR: dims.subSpecs==1. This should never happen! Aborting!'); @@ -43,22 +54,22 @@ specs=fftshift(fft(fids,[],in.dims.t),in.dims.t); %change the dims variables -if in.dims.t>in.dims.subSpecs +if in.dims.t>in.dims.subSpecs && in.dims.subSpecs ~=0 dims.t=in.dims.t-1; else dims.t=in.dims.t; end -if in.dims.coils>in.dims.subSpecs +if in.dims.coils>in.dims.subSpecs && in.dims.subSpecs ~=0 dims.coils=in.dims.coils-1; else dims.coils=in.dims.coils; end -if in.dims.averages>in.dims.subSpecs +if in.dims.averages>in.dims.subSpecs && in.dims.subSpecs ~=0 dims.averages=in.dims.averages-1; else dims.averages=in.dims.averages; end -if in.dims.extras>in.dims.subSpecs +if in.dims.extras>in.dims.subSpecs && in.dims.subSpecs ~=0 dims.extras=in.dims.extras-1; else dims.extras=in.dims.extras; @@ -83,7 +94,9 @@ end end out.subspecs=1; - +if isfield(out, 'names') + out.names = out.names(index); +end %FILLING IN THE FLAGS out.flags=in.flags; out.flags.writtentostruct=1; diff --git a/libraries/FID-A/processingTools/osp_MRSIRecon.m b/libraries/FID-A/processingTools/osp_MRSIRecon.m index c1f1dc87..6fda1fc7 100644 --- a/libraries/FID-A/processingTools/osp_MRSIRecon.m +++ b/libraries/FID-A/processingTools/osp_MRSIRecon.m @@ -54,9 +54,11 @@ switch MRSCont.datatype case 'SDAT' raw = op_sortMRSIsdat(MRSCont.raw{kk}); + raw.flags.isMRSI = 1; MRSCont.raw{kk} = raw; if MRSCont.flags.hasWater raw_w = op_sortMRSIsdat(MRSCont.raw_w{kk}); + raw_w.flags.isMRSI = 1; MRSCont.raw_w{kk} = raw_w; end otherwise diff --git a/load/OspreyLoad.m b/load/OspreyLoad.m index 08c16fde..06cdc112 100644 --- a/load/OspreyLoad.m +++ b/load/OspreyLoad.m @@ -34,6 +34,9 @@ if ~isempty(MRSCont.files_mm) %re_mm adding functionality to load MM data MRSCont.flags.hasMM = 1; %re_mm end %re_mm +if ~isempty(MRSCont.files_mm_ref) + MRSCont.flags.hasMMRef = 1; +end if ~isempty(MRSCont.files_ref) MRSCont.flags.hasRef = 1; end @@ -47,10 +50,128 @@ [~,MRSCont.ver.CheckOsp ] = osp_Toolbox_Check ('OspreyLoad',MRSCont.flags.isGUI); % Determine data types -[MRSCont, retMsg] = osp_detDataType(MRSCont); +[MRSCont, retMsg,reordered] = osp_detDataType(MRSCont); +MRSCont.flags.reordered = reordered; +% Parse ECC flag entry +if length(MRSCont.opts.ECC.raw) == 1 + MRSCont.opts.ECC.raw = ones(size(MRSCont.files)) * MRSCont.opts.ECC.raw; +end +if length(MRSCont.opts.ECC.mm) == 1 && ~isempty(MRSCont.files_mm) + MRSCont.opts.ECC.mm = ones(size(MRSCont.files_mm)) * MRSCont.opts.ECC.mm; +end + + + +tempDatasets = []; +MRSCont.opts.MultipleSpectra.metab = fliplr(size(MRSCont.files)); +if length(MRSCont.opts.MultipleSpectra.metab) > 1 + tempDatasets(end+1) = MRSCont.opts.MultipleSpectra.metab(2); +else + MRSCont.opts.MultipleSpectra.metab(2) = 1; +end +MRSCont.opts.MultipleSpectra.mm = []; +MRSCont.opts.MultipleSpectra.mm_ref = []; +MRSCont.opts.MultipleSpectra.ref = []; +MRSCont.opts.MultipleSpectra.w = []; +if MRSCont.flags.hasMM + MRSCont.opts.MultipleSpectra.mm = fliplr(size(MRSCont.files_mm)); + if length(MRSCont.opts.MultipleSpectra.metab) > 1 + tempDatasets(end+1) = MRSCont.opts.MultipleSpectra.mm(2); + else + MRSCont.opts.MultipleSpectra.mm(2) = 1; + end +end +if MRSCont.flags.hasMMRef + MRSCont.opts.MultipleSpectra.mm_ref = fliplr(size(MRSCont.files_mm_ref)); + if length(MRSCont.opts.MultipleSpectra.mm_ref) > 1 + tempDatasets(end+1) = MRSCont.opts.MultipleSpectra.mm_ref(2); + else + MRSCont.opts.MultipleSpectra.mm_ref(2) = 1; + end +end +if MRSCont.flags.hasRef + MRSCont.opts.MultipleSpectra.ref = fliplr(size(MRSCont.files_ref)); + if length(MRSCont.opts.MultipleSpectra.ref) > 1 + tempDatasets(end+1) = MRSCont.opts.MultipleSpectra.ref(2); + else + MRSCont.opts.MultipleSpectra.ref(2) = 1; + end +end +if MRSCont.flags.hasWater + MRSCont.opts.MultipleSpectra.w = fliplr(size(MRSCont.files_w)); + if length(MRSCont.opts.MultipleSpectra.w) > 1 + tempDatasets(end+1) = MRSCont.opts.MultipleSpectra.w(2); + else + MRSCont.opts.MultipleSpectra.w(2) = 1; + end +end + +[maxDatasets,~] = max(tempDatasets); % Determine number of datasets -MRSCont.nDatasets = length(MRSCont.files); +MRSCont.nDatasets = size(MRSCont.files,2); +if maxDatasets > 1 + MRSCont.nDatasets(2) = maxDatasets; + if ~isfield(MRSCont.opts, 'extras') + MRSCont.opts.extras.names = {}; + MRSCont.opts.extras.exp_var = []; + for ex = 1 : MRSCont.nDatasets(2) + MRSCont.opts.extras.names{end+1} = ['Exp_' num2str(ex)]; + MRSCont.opts.extras.exp_var(end+1) = 1; + end + end +else + MRSCont.nDatasets(2) = 1; +end +if MRSCont.opts.MultipleSpectra.metab(2) < maxDatasets + MRSCont.opts.MultipleSpectra.metab = ones(1,maxDatasets); +else if maxDatasets > 1 + MRSCont.opts.MultipleSpectra.metab = [1:MRSCont.opts.MultipleSpectra.metab(2)]; + else + MRSCont.opts.MultipleSpectra.metab = [1:MRSCont.nDatasets(1)]; + end +end +if MRSCont.flags.hasMM + if MRSCont.opts.MultipleSpectra.mm(2) < maxDatasets + MRSCont.opts.MultipleSpectra.mm = ones(1,maxDatasets); + else if maxDatasets > 1 + MRSCont.opts.MultipleSpectra.mm = [1:MRSCont.opts.MultipleSpectra.mm(2)]; + else + MRSCont.opts.MultipleSpectra.mm = [1:MRSCont.nDatasets(1)]; + end + end +end +if MRSCont.flags.hasMMRef + if MRSCont.opts.MultipleSpectra.mm_ref(2) < maxDatasets + MRSCont.opts.MultipleSpectra.mm_ref = ones(1,maxDatasets); + else if maxDatasets > 1 + MRSCont.opts.MultipleSpectra.mm_ref = [1:MRSCont.opts.MultipleSpectra.mm_ref(2)]; + else + MRSCont.opts.MultipleSpectra.mm_ref = [1:MRSCont.nDatasets(1)]; + end + end +end +if MRSCont.flags.hasRef + if MRSCont.opts.MultipleSpectra.ref(2) < maxDatasets + MRSCont.opts.MultipleSpectra.ref = ones(1,maxDatasets); + else if maxDatasets > 1 + MRSCont.opts.MultipleSpectra.ref = [1:MRSCont.opts.MultipleSpectra.ref(2)]; + else + MRSCont.opts.MultipleSpectra.ref = [1:MRSCont.nDatasets(1)]; + end + end +end +if MRSCont.flags.hasWater + if MRSCont.opts.MultipleSpectra.w(2) < maxDatasets + MRSCont.opts.MultipleSpectra.w = ones(1,maxDatasets); + else if maxDatasets > 1 + MRSCont.opts.MultipleSpectra.w = [1:MRSCont.opts.MultipleSpectra.w(2)]; + else + MRSCont.opts.MultipleSpectra.w = [1:MRSCont.nDatasets(1)]; + end + end +end + % Load raw data (call loaders depending on file type) switch MRSCont.vendor @@ -144,7 +265,7 @@ end if MRSCont.flags.isUnEdited - for kk = 1:MRSCont.nDatasets + for kk = 1:MRSCont.nDatasets(1) raw = MRSCont.raw{kk}; % Get the kk-th dataset %%% MERGE MULTIPLE DIMENSIONS %%% % If the dimensionality of the dataset isn't just along the diff --git a/load/mrsi/load_mrsi_data.m b/load/mrsi/load_mrsi_data.m index e6225fed..b9787895 100644 --- a/load/mrsi/load_mrsi_data.m +++ b/load/mrsi/load_mrsi_data.m @@ -1057,6 +1057,22 @@ else out.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end + % Sequence flags + out.flags.isUnEdited = 0; + out.flags.isMEGA = 0; + out.flags.isHERMES = 0; + out.flags.isHERCULES = 0; + out.flags.isPRIAM = 0; + out.flags.isMRSI = 1; + if contains(seq_type,'SE') + out.flags.isUnEdited = 1; + end + if contains(seq_type,'MEGA') + out.flags.isMEGA = 1; + end + if contains(seq_type,'MEGA') + out.flags.isHERMES = 1; + end if ~strcmp(MRSCont.opts.MoCo.target,'none') MRSCont.MoCo{kk}.k_ph_corr = k_ph_corr; @@ -1117,6 +1133,13 @@ else out_w.flags.isISIS=(out.sz(out.dims.subSpecs)==4); end + % Sequence flags + out_w.flags.isUnEdited = 1; + out_w.flags.isMEGA = 0; + out_w.flags.isHERMES = 0; + out_w.flags.isHERCULES = 0; + out_w.flags.isPRIAM = 0; + out_w.flags.isMRSI = 1; MRSCont.raw_w{kk} = out_w; end end diff --git a/load/osp_LoadBrukerFid.m b/load/osp_LoadBrukerFid.m index cc6ba0bf..4960adcd 100644 --- a/load/osp_LoadBrukerFid.m +++ b/load/osp_LoadBrukerFid.m @@ -27,26 +27,26 @@ % Check that all datasets are complete if MRSCont.flags.hasMM %re_mm adding functionality to load MM data - if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate - for kk=2:MRSCont.nDatasets %re_mm + if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets(1)>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate + for kk=2:MRSCont.nDatasets(1) %re_mm MRSCont.files_mm{kk} = MRSCont.files_mm{1}; % re_mm allowable to specify one MM file for the whole batch end %re_mm end %re_mm - if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets) ) %re_mm + if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets(1)) ) %re_mm msg = 'Number of specified MM files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end %re_mm end %re_mm if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); @@ -60,91 +60,143 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data. - raw = io_loadspec_bruk(MRSCont.files{kk}); - MRSCont.raw{kk} = raw; - - % Read in the raw MM data. re_mm - if MRSCont.flags.hasMM %re_mm - if MRSCont.flags.isUnEdited %re_mm - raw_mm = io_loadspec_bruk(MRSCont.files_mm{kk},1); %re_mm - [raw_mm] = op_rmempty(raw_mm); %re_mm - elseif MRSCont.flags.isMEGA %re_mm - raw_mm = io_loadspec_bruk(MRSCont.files_mm{kk},2); %re_mm - if raw_mm.subspecs > 1 %re_mm - raw_mm_A = op_takesubspec(raw_mm,1); %re_mm - [raw_mm_A] = op_rmempty(raw_mm_A); % Remove empty linesv - raw_mm_B = op_takesubspec(raw_mm,2); %re_mm - [raw_mm_B] = op_rmempty(raw_mm_B); % Remove empty lines %re_mm - raw_mm = op_concatAverages(raw_mm_A,raw_mm_B); %re_mm - else %re_mm - [raw_mm] = op_rmempty(raw_mm); %re_mm - end %re_mm - elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES %re_mm - raw_mm = io_loadspec_sdat(MRSCont.files_mm{kk},1); %re_mm - if raw_mm.subspecs > 1 %re_mm - raw_mm_A = op_takesubspec(raw_mm,1); %re_mm - [raw_mm_A] = op_rmempty(raw_mm_A); % Remove empty lines %re_mm - raw_mm_B = op_takesubspec(raw_mm,2); %re_mm - [raw_mm_B] = op_rmempty(raw_mm_B); % Remove empty lines %re_mm - raw_mm_C = op_takesubspec(raw_mm,3); %re_mm - [raw_mm_C] = op_rmempty(raw_mm_C); % Remove empty lines %re_mm - raw_mm_D = op_takesubspec(raw_mm,4); %re_mm - [raw_mm_D] = op_rmempty(raw_mm_D); % Remove empty lines %re_mm - raw_mm = op_concatAverages(raw_mm_A,raw_mm_B,raw_mm_C,raw_mm_D); %re_mm - else %re_mm - [raw_mm] = op_rmempty(raw_mm); %re_mm - end %re_mm - end - MRSCont.raw_mm{kk} = raw_mm; - end %re_mm - - % Read in the raw reference data. - if MRSCont.flags.hasRef + % Read in the raw metabolite data. + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + raw = io_loadspec_bruk(MRSCont.files{metab_ll,kk}); + % Sequence flags if MRSCont.flags.isUnEdited - raw_ref = io_loadspec_bruk(MRSCont.files_ref{kk},1); - [raw_ref] = op_rmempty(raw_ref); - elseif MRSCont.flags.isMEGA - raw_ref = io_loadspec_bruk(MRSCont.files_ref{kk},2); - if raw_ref.subspecs > 1 - raw_ref_A = op_takesubspec(raw_ref,1); - [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines - raw_ref_B = op_takesubspec(raw_ref,2); - [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines - raw_ref = op_concatAverages(raw_ref_A,raw_ref_B); - else - [raw_ref] = op_rmempty(raw_ref); + raw.flags.isUnEdited = 1; + end + if MRSCont.flags.isMEGA + raw.flags.isMEGA = 1; + end + MRSCont.raw{metab_ll,kk} = raw; + + % Read in the raw MM data. re_mm + if MRSCont.flags.hasMM %re_mm + temp_ll = MRSCont.opts.MultipleSpectra.mm(ll); + if MRSCont.flags.isUnEdited %re_mm + raw_mm = io_loadspec_bruk(MRSCont.files_mm{temp_ll,kk},1); %re_mm + [raw_mm] = op_rmempty(raw_mm); %re_mm + raw_mm.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA %re_mm + raw_mm = io_loadspec_bruk(MRSCont.files_mm{temp_ll,kk},2); %re_mm + if raw_mm.subspecs > 1 %re_mm + raw_mm_A = op_takesubspec(raw_mm,1); %re_mm + [raw_mm_A] = op_rmempty(raw_mm_A); % Remove empty linesv + raw_mm_B = op_takesubspec(raw_mm,2); %re_mm + [raw_mm_B] = op_rmempty(raw_mm_B); % Remove empty lines %re_mm + raw_mm = op_concatAverages(raw_mm_A,raw_mm_B); %re_mm + else %re_mm + [raw_mm] = op_rmempty(raw_mm); %re_mm + end %re_mm + raw_mm.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES%re_mm + raw_mm = io_loadspec_bruk(MRSCont.files_mm{temp_ll,kk},1); %re_mm + if raw_mm.subspecs > 1 %re_mm + raw_mm_A = op_takesubspec(raw_mm,1); %re_mm + [raw_mm_A] = op_rmempty(raw_mm_A); % Remove empty lines %re_mm + raw_mm_B = op_takesubspec(raw_mm,2); %re_mm + [raw_mm_B] = op_rmempty(raw_mm_B); % Remove empty lines %re_mm + raw_mm_C = op_takesubspec(raw_mm,3); %re_mm + [raw_mm_C] = op_rmempty(raw_mm_C); % Remove empty lines %re_mm + raw_mm_D = op_takesubspec(raw_mm,4); %re_mm + [raw_mm_D] = op_rmempty(raw_mm_D); % Remove empty lines %re_mm + raw_mm = op_concatAverages(raw_mm_A,raw_mm_B,raw_mm_C,raw_mm_D); %re_mm + else %re_mm + [raw_mm] = op_rmempty(raw_mm); %re_mm + end %re_mm + raw_mm.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES %re_mm + raw_mm = io_loadspec_bruk(MRSCont.files_mm{temp_ll,kk},1); %re_mm + if raw_mm.subspecs > 1 %re_mm + raw_mm_A = op_takesubspec(raw_mm,1); %re_mm + [raw_mm_A] = op_rmempty(raw_mm_A); % Remove empty lines %re_mm + raw_mm_B = op_takesubspec(raw_mm,2); %re_mm + [raw_mm_B] = op_rmempty(raw_mm_B); % Remove empty lines %re_mm + raw_mm_C = op_takesubspec(raw_mm,3); %re_mm + [raw_mm_C] = op_rmempty(raw_mm_C); % Remove empty lines %re_mm + raw_mm_D = op_takesubspec(raw_mm,4); %re_mm + [raw_mm_D] = op_rmempty(raw_mm_D); % Remove empty lines %re_mm + raw_mm = op_concatAverages(raw_mm_A,raw_mm_B,raw_mm_C,raw_mm_D); %re_mm + else %re_mm + [raw_mm] = op_rmempty(raw_mm); %re_mm + end %re_mm + raw_mm.flags.isHERCULES = 1; end - elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - raw_ref = io_loadspec_sdat(MRSCont.files_ref{kk},1); - if raw_ref.subspecs > 1 - raw_ref_A = op_takesubspec(raw_ref,1); - [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines - raw_ref_B = op_takesubspec(raw_ref,2); - [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines - raw_ref_C = op_takesubspec(raw_ref,3); - [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines - raw_ref_D = op_takesubspec(raw_ref,4); - [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines - raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); - else - [raw_ref] = op_rmempty(raw_ref); + MRSCont.raw_mm{temp_ll,kk} = raw_mm; + end %re_mm + + % Read in the raw reference data. + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + if MRSCont.flags.isUnEdited + raw_ref = io_loadspec_bruk(MRSCont.files_ref{ref_ll,kk},1); + [raw_ref] = op_rmempty(raw_ref); + raw_ref.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_ref = io_loadspec_bruk(MRSCont.files_ref{ref_ll,kk},2); + if raw_ref.subspecs > 1 + raw_ref_A = op_takesubspec(raw_ref,1); + [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines + raw_ref_B = op_takesubspec(raw_ref,2); + [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines + raw_ref = op_concatAverages(raw_ref_A,raw_ref_B); + else + [raw_ref] = op_rmempty(raw_ref); + end + raw_ref.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_ref = io_loadspec_bruk(MRSCont.files_ref{ref_ll,kk},1); + if raw_ref.subspecs > 1 + raw_ref_A = op_takesubspec(raw_ref,1); + [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines + raw_ref_B = op_takesubspec(raw_ref,2); + [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines + raw_ref_C = op_takesubspec(raw_ref,3); + [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines + raw_ref_D = op_takesubspec(raw_ref,4); + [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines + raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + else + [raw_ref] = op_rmempty(raw_ref); + end + raw_ref.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_ref = io_loadspec_bruk(MRSCont.files_ref{ref_ll,kk},1); + if raw_ref.subspecs > 1 + raw_ref_A = op_takesubspec(raw_ref,1); + [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines + raw_ref_B = op_takesubspec(raw_ref,2); + [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines + raw_ref_C = op_takesubspec(raw_ref,3); + [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines + raw_ref_D = op_takesubspec(raw_ref,4); + [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines + raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + else + [raw_ref] = op_rmempty(raw_ref); + end + raw_ref.flags.isHERCULES = 1; end + MRSCont.raw_ref{ref_ll,kk} = raw_ref; + end + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = io_loadspec_bruk(MRSCont.files_w{w_ll,kk},1); + raw_w.flags.isUnEdited = 1; + MRSCont.raw_w{w_ll,kk} = raw_w; end - MRSCont.raw_ref{kk} = raw_ref; - end - if MRSCont.flags.hasWater - raw_w = io_loadspec_bruk(MRSCont.files_w{kk},1); - MRSCont.raw_w{kk} = raw_w; end - end + end end time = toc(refLoadTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,MRSCont.nDatasets(1),MRSCont.nDatasets(2),progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Set flag MRSCont.flags.coilsCombined = 1; MRSCont.runtime.Load = time; diff --git a/load/osp_LoadDATA.m b/load/osp_LoadDATA.m index 03ed79e4..28ea617e 100644 --- a/load/osp_LoadDATA.m +++ b/load/osp_LoadDATA.m @@ -21,26 +21,26 @@ close all; warning('off','all'); if MRSCont.flags.hasMM %re_mm adding functionality to load MM data - if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate - for kk=2:MRSCont.nDatasets %re_mm + if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets(1)>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate + for kk=2:MRSCont.nDatasets(1) %re_mm MRSCont.files_mm{kk} = MRSCont.files_mm{1}; % re_mm allowable to specify one MM file for the whole batch end %re_mm end %re_mm - if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets) ) %re_mm + if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets(1)) ) %re_mm msg = 'Number of specified MM files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end %re_mm end %re_mm if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); @@ -54,50 +54,66 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - - % Read in the raw metabolite data. Since the Philips DATA loader needs - % to know the number of sub-spectra (e.g. from spectral editing), the - % type of sequence needs to be differentiated here already. - if MRSCont.flags.hasStatfile - statFile = MRSCont.file_stat; - else - statFile = []; - end - - if MRSCont.flags.isUnEdited - [raw,raw_ref]=io_loadspec_data(MRSCont.files{kk},1,kk,statFile); - elseif MRSCont.flags.isMEGA - [raw,raw_ref]=io_loadspec_data(MRSCont.files{kk},2,kk,statFile); - elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - [raw,raw_ref]=io_loadspec_data(MRSCont.files{kk},4,kk,statFile); - end - MRSCont.raw_uncomb{kk} = raw; - - if ~MRSCont.flags.hasRef && ~isempty(raw_ref) - MRSCont.raw_ref_uncomb{kk} = raw_ref; - if kk == MRSCont.nDatasets - MRSCont.flags.hasRef = 1; +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + + % Read in the raw metabolite data. Since the Philips DATA loader needs + % to know the number of sub-spectra (e.g. from spectral editing), the + % type of sequence needs to be differentiated here already. + if MRSCont.flags.hasStatfile + statFile = MRSCont.file_stat; + else + statFile = []; end - else if MRSCont.flags.hasRef - [~,raw_ref]=io_loadspec_data(MRSCont.files_ref{kk},1,kk,statFile); - MRSCont.raw_ref_uncomb{kk} = raw_ref; + + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + if MRSCont.flags.isUnEdited + [raw,raw_ref]=io_loadspec_data(MRSCont.files{metab_ll,kk},1,kk,statFile); + raw.flags.UnEdited = 1; + raw_ref.flags.UnEdited = 1; + elseif MRSCont.flags.isMEGA + [raw,raw_ref]=io_loadspec_data(MRSCont.files{metab_ll,kk},2,kk,statFile); + raw.flags.isMEGA = 1; + raw_ref.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + [raw,raw_ref]=io_loadspec_data(MRSCont.files{metab_ll,kk},4,kk,statFile); + raw.flags.isHERMES = 1; + raw_ref.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + [raw,raw_ref]=io_loadspec_data(MRSCont.files{metab_ll,kk},4,kk,statFile); + raw.flags.isHERCULES = 1; + raw_ref.flags.isHERCULES = 1; + end + MRSCont.raw_uncomb{metab_ll,kk} = raw; + + if ~MRSCont.flags.hasRef && ~isempty(raw_ref) + MRSCont.raw_ref_uncomb{metab_ll,kk} = raw_ref; + if kk == MRSCont.nDatasets + MRSCont.flags.hasRef = 1; + end + else if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + [~,raw_ref]=io_loadspec_data(MRSCont.files_ref{ref_ll,kk},1,kk,statFile); + MRSCont.raw_ref_uncomb{ref_ll,kk} = raw_ref; + end + end + + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + [~,raw_w]=io_loadspec_data(MRSCont.files_w{w_ll,kk},1,kk,statFile); + raw_w.flags.UnEdited = 1; + MRSCont.raw_w_uncomb{w_ll,kk} = raw_w; end - end - - if MRSCont.flags.hasWater - [~,raw_w]=io_loadspec_data(MRSCont.files_w{kk},1,kk,statFile); - MRSCont.raw_w_uncomb{kk} = raw_w; end end end time = toc(refLoadTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,MRSCont.nDatasets(1),MRSCont.nDatasets(2),progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Set flag MRSCont.flags.coilsCombined = 0; MRSCont.runtime.Load = time; diff --git a/load/osp_LoadDICOM.m b/load/osp_LoadDICOM.m index 3e4fd4e0..5686a06e 100644 --- a/load/osp_LoadDICOM.m +++ b/load/osp_LoadDICOM.m @@ -29,21 +29,21 @@ close all; warning('off','all'); if MRSCont.flags.hasMM - if length(MRSCont.files_mm) ~= MRSCont.nDatasets + if length(MRSCont.files_mm) ~= MRSCont.nDatasets(1) msg = 'Number of specified metabolite-nulled files does not match number of specified metabolite files.'; fprintf(msg); error(msg); end end if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; fprintf(msg); error(msg); end end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; fprintf(msg); error(msg); @@ -57,44 +57,75 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data. - raw = io_loadspec_dicom(MRSCont.files{kk}); - MRSCont.raw{kk} = raw; +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - % Read in the raw reference data. - if MRSCont.flags.hasRef - raw_ref = io_loadspec_dicom(MRSCont.files_ref{kk}); - MRSCont.raw_ref{kk} = raw_ref; - if MRSCont.raw_ref{kk}.subspecs > 1 + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + % Read in the raw metabolite data. + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + raw = io_loadspec_dicom(MRSCont.files{metab_ll,kk}); + % Sequence flags + if MRSCont.flags.isUnEdited + raw.flags.isUnEdited = 1; + end + if MRSCont.flags.isMEGA + raw.flags.isMEGA = 1; + end + MRSCont.raw{ll,kk} = raw; + + % Read in the raw reference data. + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + raw_ref = io_loadspec_dicom(MRSCont.files_ref{ref_ll,kk}); + MRSCont.raw_ref{ref_ll,kk} = raw_ref; + if MRSCont.raw_ref{ref_ll,kk}.subspecs > 1 + if MRSCont.flags.isMEGA + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(raw_ref_A,raw_ref_B); + else + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + raw_ref_C = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},3); + raw_ref_D = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},4); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(op_concatAverages(raw_ref_A,raw_ref_B),op_concatAverages(raw_ref_C,raw_ref_D)); + end + end + if MRSCont.flags.isUnEdited + MRSCont.raw_ref{ref_ll,kk}.flags.isUnEdited = 1; + end if MRSCont.flags.isMEGA - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - MRSCont.raw_ref{kk} = op_concatAverages(raw_ref_A,raw_ref_B); - else - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - raw_ref_C = op_takesubspec(MRSCont.raw_ref{kk},3); - raw_ref_D = op_takesubspec(MRSCont.raw_ref{kk},4); - MRSCont.raw_ref{kk} = op_concatAverages(op_concatAverages(raw_ref_A,raw_ref_B),op_concatAverages(raw_ref_C,raw_ref_D)); + MRSCont.raw_ref{ref_ll,kk}.flags.isMEGA = 1; end end + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = io_loadspec_dicom(MRSCont.files_w{w_ll,kk}); + MRSCont.raw_w{w_ll,kk} = raw_w; + if MRSCont.flags.isUnEdited + MRSCont.raw_w{w_ll,kk}.flags.isUnEdited = 1; + end + if MRSCont.flags.isMEGA + MRSCont.raw_w{w_ll,kk}.flags.isMEGA = 1; + end + end + if MRSCont.flags.hasMM + temp_ll = MRSCont.opts.MultipleSpectra.mm(ll); + raw_mm = io_loadspec_dicom(MRSCont.files_mm{temp_ll,kk}); + MRSCont.raw_mm{temp_ll,kk} = raw_mm; + if MRSCont.flags.isUnEdited + MRSCont.raw_mm{temp_ll,kk}.flags.isUnEdited = 1; + end + if MRSCont.flags.isMEGA + MRSCont.raw_mm{temp_ll,kk}.flags.isMEGA = 1; + end + end end - if MRSCont.flags.hasWater - raw_w = io_loadspec_dicom(MRSCont.files_w{kk}); - MRSCont.raw_w{kk} = raw_w; - end - if MRSCont.flags.hasMM - raw_mm = io_loadspec_dicom(MRSCont.files_mm{kk}); - MRSCont.raw_mm{kk} = raw_mm; - end end end time = toc(refLoadTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Set flag MRSCont.flags.coilsCombined = 1; MRSCont.runtime.Load = time; diff --git a/load/osp_LoadNII.m b/load/osp_LoadNII.m index 45b147c7..edb1c73c 100644 --- a/load/osp_LoadNII.m +++ b/load/osp_LoadNII.m @@ -28,12 +28,12 @@ %re_mm adding functionality to load MM data if MRSCont.flags.hasMM - if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate - for kk=2:MRSCont.nDatasets %re_mm + if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets(1)>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate + for kk=2:MRSCont.nDatasets(1) %re_mm MRSCont.files_mm{kk} = MRSCont.files_mm{1}; % re_mm allowable to specify one MM file for the whole batch end %re_mm end %re_mm - if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets) ) %re_mm + if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets(1)) ) %re_mm msg = 'Number of specified MM files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); @@ -41,7 +41,7 @@ end %re_mm if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); @@ -49,7 +49,7 @@ end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); @@ -64,58 +64,64 @@ progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad', kk, MRSCont.nDatasets ,progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI); - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad', kk,1, MRSCont.nDatasets ,progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI); + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data. - raw = io_loadspec_niimrs(MRSCont.files{kk}); + % Read in the raw metabolite data. + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + raw = io_loadspec_niimrs(MRSCont.files{metab_ll,kk}); - % Read in the MM data. - % Leave until we have example data. - - % Read in the raw water reference data. - if MRSCont.flags.hasRef - raw_ref = io_loadspec_niimrs(MRSCont.files_ref{kk}); - end - - % Read in the short-TE water data. - if MRSCont.flags.hasWater - raw_w = io_loadspec_niimrs(MRSCont.files_w{kk}); + % Read in the MM data. + % Leave until we have example data. + + % Read in the raw water reference data. + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + raw_ref = io_loadspec_niimrs(MRSCont.files_ref{ref_ll,kk}); + end + + % Read in the short-TE water data. + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = io_loadspec_niimrs(MRSCont.files_w{w_ll,kk}); + end + + + % Set flag and save data under appropriate name + if raw.dims.coils == 0 + MRSCont.flags.coilsCombined = 1; + + MRSCont.raw{metab_ll,kk} = raw; + + if MRSCont.flags.hasRef + MRSCont.raw_ref{ref_ll,kk} = raw_ref; + end + + if MRSCont.flags.hasWater + MRSCont.raw_w{w_ll,kk} = raw_w; + end + + else + MRSCont.flags.coilsCombined = 0; + + MRSCont.raw_uncomb{metab_ll,kk} = raw; + + if MRSCont.flags.hasRef + MRSCont.raw_ref_uncomb{ref_ll,kk} = raw_ref; + end + + if MRSCont.flags.hasWater + MRSCont.raw_w_uncomb{w_ll,kk} = raw_w; + end + + end end end end time = toc(refLoadTime); -[~] = printLog('done', time, MRSCont.nDatasets, progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI); - -% Set flag and save data under appropriate name -if raw.dims.coils == 0 - MRSCont.flags.coilsCombined = 1; - - MRSCont.raw{kk} = raw; - - if MRSCont.flags.hasRef - MRSCont.raw_ref{kk} = raw_ref; - end - - if MRSCont.flags.hasWater - MRSCont.raw_w{kk} = raw_w; - end - -else - MRSCont.flags.coilsCombined = 0; - - MRSCont.raw_uncomb{kk} = raw; - - if MRSCont.flags.hasRef - MRSCont.raw_ref_uncomb{kk} = raw_ref; - end - - if MRSCont.flags.hasWater - MRSCont.raw_w_uncomb{kk} = raw_w; - end - -end +[~] = printLog('done',time,MRSCont.nDatasets(1),MRSCont.nDatasets(2),progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.Load = time; diff --git a/load/osp_LoadP.m b/load/osp_LoadP.m index 700172ca..268f3824 100644 --- a/load/osp_LoadP.m +++ b/load/osp_LoadP.m @@ -35,26 +35,39 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data. Since the GE P-file loader needs - % to know the number of sub-spectra (e.g. from spectral editing), the - % type of sequence needs to be differentiated here already. - if MRSCont.flags.isUnEdited - [raw, raw_ref] = io_loadspec_GE(MRSCont.files{kk},1); - elseif MRSCont.flags.isMEGA - [raw, raw_ref] = io_loadspec_GE(MRSCont.files{kk},2); - elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - [raw, raw_ref] = io_loadspec_GE(MRSCont.files{kk},4); +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + % Read in the raw metabolite data. Since the GE P-file loader needs + % to know the number of sub-spectra (e.g. from spectral editing), the + % type of sequence needs to be differentiated here already. + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + if MRSCont.flags.isUnEdited + [raw, raw_ref] = io_loadspec_GE(MRSCont.files{metab_ll,kk},1); + raw.flags.UnEdited = 1; + raw_ref.flags.UnEdited = 1; + elseif MRSCont.flags.isMEGA + [raw, raw_ref] = io_loadspec_GE(MRSCont.files{metab_ll,kk},2); + raw.flags.isMEGA = 1; + raw_ref.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + [raw, raw_ref] = io_loadspec_GE(MRSCont.files{metab_ll,kk},4); + raw.flags.isHERMES = 1; + raw_ref.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + [raw, raw_ref] = io_loadspec_GE(MRSCont.files{metab_ll,kk},4); + raw.flags.isHERCULES = 1; + raw_ref.flags.isHERCULES = 1; + end + MRSCont.raw_uncomb{metab_ll,kk} = raw; + MRSCont.raw_ref_uncomb{metab_ll,kk} = raw_ref; end - MRSCont.raw_uncomb{kk} = raw; - MRSCont.raw_ref_uncomb{kk} = raw_ref; end end time = toc(refLoadTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Set flag MRSCont.flags.coilsCombined = 0; MRSCont.runtime.Load = time; diff --git a/load/osp_LoadRAW.m b/load/osp_LoadRAW.m index faa4f75f..e68f87f2 100644 --- a/load/osp_LoadRAW.m +++ b/load/osp_LoadRAW.m @@ -25,26 +25,26 @@ close all; warning('off','all'); if MRSCont.flags.hasMM %re_mm adding functionality to load MM data - if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate - for kk=2:MRSCont.nDatasets %re_mm + if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets(1)>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate + for kk=2:MRSCont.nDatasets(1) %re_mm MRSCont.files_mm{kk} = MRSCont.files_mm{1}; % re_mm allowable to specify one MM file for the whole batch end %re_mm end %re_mm - if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets) ) %re_mm + if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets(1)) ) %re_mm msg = 'Number of specified MM files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end %re_mm end %re_mm if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); @@ -58,42 +58,52 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad', kk, MRSCont.nDatasets, progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI); - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data. For now, this is only defined - % for unedited data. - if MRSCont.flags.isUnEdited - raw = io_loadspec_lcmraw(MRSCont.files{kk}); - end - MRSCont.raw{kk} = raw; - - % Read in the raw MM data. re_mm - if MRSCont.flags.hasMM %re_mm - if MRSCont.flags.isUnEdited %re_mm - raw_mm = io_loadspec_lcmraw(MRSCont.files_mm{kk}); %re_mm - end - MRSCont.raw_mm{kk} = raw_mm; - end %re_mm - - % Read in the raw reference data. - if MRSCont.flags.hasRef + % Read in the raw metabolite data. For now, this is only defined + % for unedited data. + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); if MRSCont.flags.isUnEdited - raw_ref = io_loadspec_lcmraw(MRSCont.files_ref{kk}); + raw = io_loadspec_lcmraw(MRSCont.files{metab_ll,kk}); + raw.flags.isUnEdited = 1; + end + MRSCont.raw{metab_ll,kk} = raw; + + % Read in the raw MM data. re_mm + if MRSCont.flags.hasMM %re_mm + temp_ll = MRSCont.opts.MultipleSpectra.mm(ll); + if MRSCont.flags.isUnEdited %re_mm + raw_mm = io_loadspec_lcmraw(MRSCont.files_mm{temp_ll,kk}); %re_mm + raw_mm.flags.isUnEdited = 1; + end + MRSCont.raw_mm{temp_ll,kk} = raw_mm; + end %re_mm + + % Read in the raw reference data. + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + if MRSCont.flags.isUnEdited + raw_ref = io_loadspec_lcmraw(MRSCont.files_ref{ref_ll,kk}); + raw_ref.flags.isUnEdited = 1; + end + MRSCont.raw_ref{ref_ll,kk} = raw_ref; + end + + % Read in the raw short-TE water data. + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = io_loadspec_lcmraw(MRSCont.files_w{w_ll,kk}); + raw_w.flags.isUnEdited = 1; + MRSCont.raw_w{w_ll,kk} = raw_w; end - MRSCont.raw_ref{kk} = raw_ref; - end - - % Read in the raw short-TE water data. - if MRSCont.flags.hasWater - raw_w = io_loadspec_lcmraw(MRSCont.files_w{kk}); - MRSCont.raw_w{kk} = raw_w; end end end time = toc(refLoadTime); -[~] = printLog('done', time, MRSCont.nDatasets, progressText, MRSCont.flags.isGUI, MRSCont.flags.isMRSI); +[~] = printLog('done',time,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Set flags MRSCont.flags.coilsCombined = 1; diff --git a/load/osp_LoadRDA.m b/load/osp_LoadRDA.m index 92b22491..3d67196f 100644 --- a/load/osp_LoadRDA.m +++ b/load/osp_LoadRDA.m @@ -29,21 +29,21 @@ close all; warning('off','all'); if MRSCont.flags.hasMM - if length(MRSCont.files_mm) ~= MRSCont.nDatasets + if length(MRSCont.files_mm) ~= MRSCont.nDatasets(1) msg = 'Number of specified metabolite-nulled files does not match number of specified metabolite files.'; fprintf(msg); error(msg); end end if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; fprintf(msg); error(msg); end end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; fprintf(msg); error(msg); @@ -57,43 +57,75 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data. - raw = io_loadspec_rda(MRSCont.files{kk}); - MRSCont.raw{kk} = raw; +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + % Read in the raw metabolite data. + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + raw = io_loadspec_rda(MRSCont.files{metab_ll,kk}); + % Sequence flags + if MRSCont.flags.isUnEdited + raw.flags.isUnEdited = 1; + end + if MRSCont.flags.isMEGA + raw.flags.isMEGA = 1; + end + MRSCont.raw{ll,kk} = raw; - % Read in the raw reference data. - if MRSCont.flags.hasRef - raw_ref = io_loadspec_rda(MRSCont.files_ref{kk}); - MRSCont.raw_ref{kk} = raw_ref; - if MRSCont.raw_ref{kk}.subspecs > 1 + + % Read in the raw reference data. + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + raw_ref = io_loadspec_rda(MRSCont.files_ref{ref_ll,kk}); + MRSCont.raw_ref{ref_ll,kk} = raw_ref; + if MRSCont.raw_ref{ref_ll,kk}.subspecs > 1 + if MRSCont.flags.isMEGA + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(raw_ref_A,raw_ref_B); + else + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + raw_ref_C = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},3); + raw_ref_D = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},4); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + end + end + if MRSCont.flags.isUnEdited + MRSCont.raw_ref{ref_ll,kk}.flags.isUnEdited = 1; + end if MRSCont.flags.isMEGA - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - MRSCont.raw_ref{kk} = op_concatAverages(raw_ref_A,raw_ref_B); - else - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - raw_ref_C = op_takesubspec(MRSCont.raw_ref{kk},3); - raw_ref_D = op_takesubspec(MRSCont.raw_ref{kk},4); - MRSCont.raw_ref{kk} = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + MRSCont.raw_ref{ref_ll,kk}.flags.isMEGA = 1; end end + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = io_loadspec_rda(MRSCont.files_w{w_ll,kk}); + MRSCont.raw_w{w_ll,kk} = raw_w; + if MRSCont.flags.isUnEdited + MRSCont.raw_w{w_ll,kk}.flags.isUnEdited = 1; + end + if MRSCont.flags.isMEGA + MRSCont.raw_w{w_ll,kk}.flags.isMEGA = 1; + end + end + if MRSCont.flags.hasMM + temp_ll = MRSCont.opts.MultipleSpectra.mm(ll); + raw_mm = io_loadspec_rda(MRSCont.files_mm{temp_ll,kk}); + MRSCont.raw_mm{temp_ll,kk} = raw_mm; + if MRSCont.flags.isUnEdited + MRSCont.raw_mm{temp_ll,kk}.flags.isUnEdited = 1; + end + if MRSCont.flags.isMEGA + MRSCont.raw_mm{temp_ll,kk}.flags.isMEGA = 1; + end + end end - if MRSCont.flags.hasWater - raw_w = io_loadspec_rda(MRSCont.files_w{kk}); - MRSCont.raw_w{kk} = raw_w; - end - if MRSCont.flags.hasMM - raw_mm = io_loadspec_rda(MRSCont.files_mm{kk}); - MRSCont.raw_mm{kk} = raw_mm; - end end end time = toc(refLoadTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,MRSCont.nDatasets(1),MRSCont.nDatasets(2),progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Set flag MRSCont.flags.coilsCombined = 1; MRSCont.runtime.Load = time; diff --git a/load/osp_LoadSDAT.m b/load/osp_LoadSDAT.m index 135e2423..758e4e02 100644 --- a/load/osp_LoadSDAT.m +++ b/load/osp_LoadSDAT.m @@ -28,26 +28,26 @@ close all; warning('off','all'); if MRSCont.flags.hasMM %re_mm adding functionality to load MM data - if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate - for kk=2:MRSCont.nDatasets %re_mm + if ((length(MRSCont.files_mm) == 1) && (MRSCont.nDatasets(1)>1)) %re_mm seems like specificy one MM file for a batch is also an option to plan to accomodate + for kk=2:MRSCont.nDatasets(1) %re_mm MRSCont.files_mm{kk} = MRSCont.files_mm{1}; % re_mm allowable to specify one MM file for the whole batch end %re_mm end %re_mm - if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets) ) %re_mm + if ((length(MRSCont.files_mm) ~= MRSCont.nDatasets(1)) ) %re_mm msg = 'Number of specified MM files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end %re_mm end %re_mm if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); end end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; %re_mm fprintf(msg); error(msg); @@ -61,99 +61,170 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data. Since the Philips SDAT loader needs - % to know the number of sub-spectra (e.g. from spectral editing), the - % type of sequence needs to be differentiated here already. - if MRSCont.flags.isUnEdited - raw = io_loadspec_sdat(MRSCont.files{kk},1); - elseif MRSCont.flags.isMEGA - raw = io_loadspec_sdat(MRSCont.files{kk},2); - elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - raw = io_loadspec_sdat(MRSCont.files{kk},4); - end - MRSCont.raw{kk} = raw; - - % Read in the raw MM data. re_mm - if MRSCont.flags.hasMM %re_mm - if MRSCont.flags.isUnEdited %re_mm - raw_mm = io_loadspec_sdat(MRSCont.files_mm{kk},1); %re_mm - [raw_mm] = op_rmempty(raw_mm); %re_mm - elseif MRSCont.flags.isMEGA %re_mm - raw_mm = io_loadspec_sdat(MRSCont.files_mm{kk},2); %re_mm - if raw_mm.subspecs > 1 %re_mm - raw_mm_A = op_takesubspec(raw_mm,1); %re_mm - [raw_mm_A] = op_rmempty(raw_mm_A); % Remove empty linesv - raw_mm_B = op_takesubspec(raw_mm,2); %re_mm - [raw_mm_B] = op_rmempty(raw_mm_B); % Remove empty lines %re_mm - raw_mm = op_concatAverages(raw_mm_A,raw_mm_B); %re_mm - else %re_mm - [raw_mm] = op_rmempty(raw_mm); %re_mm - end %re_mm - elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES %re_mm - raw_mm = io_loadspec_sdat(MRSCont.files_mm{kk},1); %re_mm - if raw_mm.subspecs > 1 %re_mm - raw_mm_A = op_takesubspec(raw_mm,1); %re_mm - [raw_mm_A] = op_rmempty(raw_mm_A); % Remove empty lines %re_mm - raw_mm_B = op_takesubspec(raw_mm,2); %re_mm - [raw_mm_B] = op_rmempty(raw_mm_B); % Remove empty lines %re_mm - raw_mm_C = op_takesubspec(raw_mm,3); %re_mm - [raw_mm_C] = op_rmempty(raw_mm_C); % Remove empty lines %re_mm - raw_mm_D = op_takesubspec(raw_mm,4); %re_mm - [raw_mm_D] = op_rmempty(raw_mm_D); % Remove empty lines %re_mm - raw_mm = op_concatAverages(raw_mm_A,raw_mm_B,raw_mm_C,raw_mm_D); %re_mm - else %re_mm - [raw_mm] = op_rmempty(raw_mm); %re_mm - end %re_mm - end - MRSCont.raw_mm{kk} = raw_mm; - end %re_mm - - % Read in the raw reference data. - if MRSCont.flags.hasRef + % Read in the raw metabolite data. Since the Philips SDAT loader needs + % to know the number of sub-spectra (e.g. from spectral editing), the + % type of sequence needs to be differentiated here already. + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); if MRSCont.flags.isUnEdited - raw_ref = io_loadspec_sdat(MRSCont.files_ref{kk},1); - [raw_ref] = op_rmempty(raw_ref); + raw = io_loadspec_sdat(MRSCont.files{metab_ll,kk},1); + raw.flags.isUnEdited = 1; elseif MRSCont.flags.isMEGA - raw_ref = io_loadspec_sdat(MRSCont.files_ref{kk},2); - if raw_ref.subspecs > 1 - raw_ref_A = op_takesubspec(raw_ref,1); - [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines - raw_ref_B = op_takesubspec(raw_ref,2); - [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines - raw_ref = op_concatAverages(raw_ref_A,raw_ref_B); - else + raw = io_loadspec_sdat(MRSCont.files{metab_ll,kk},2); + raw.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw = io_loadspec_sdat(MRSCont.files{metab_ll,kk},4); + raw.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw = io_loadspec_sdat(MRSCont.files{metab_ll,kk},4); + raw.flags.isHERCULES = 1; + end + MRSCont.raw{metab_ll,kk} = raw; + + % Read in the raw MM data. re_mm + if MRSCont.flags.hasMM %re_mm + temp_ll = MRSCont.opts.MultipleSpectra.mm(ll); + if MRSCont.flags.isUnEdited %re_mm + raw_mm = io_loadspec_sdat(MRSCont.files_mm{temp_ll,kk},1); %re_mm + [raw_mm] = op_rmempty(raw_mm); %re_mm + raw_mm.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA %re_mm + raw_mm = io_loadspec_sdat(MRSCont.files_mm{temp_ll,kk},2); %re_mm + raw_mm.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES%re_mm + raw_mm = io_loadspec_sdat(MRSCont.files_mm{temp_ll,kk},1); %re_mm + raw_mm.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES %re_mm + raw_mm = io_loadspec_sdat(MRSCont.files_mm{temp_ll,kk},1); %re_mm + raw_mm.flags.isHERCULES = 1; + end + MRSCont.raw_mm{temp_ll,kk} = raw_mm; + end %re_mm + + % Read in the raw reference data. + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + if MRSCont.flags.isUnEdited + raw_ref = io_loadspec_sdat(MRSCont.files_ref{ref_ll,kk},1); [raw_ref] = op_rmempty(raw_ref); + raw_ref.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_ref = io_loadspec_sdat(MRSCont.files_ref{ref_ll,kk},2); + if raw_ref.subspecs > 1 + raw_ref_A = op_takesubspec(raw_ref,1); + [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines + raw_ref_B = op_takesubspec(raw_ref,2); + [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines + raw_ref = op_concatAverages(raw_ref_A,raw_ref_B); + else + [raw_ref] = op_rmempty(raw_ref); + end + raw_ref.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_ref = io_loadspec_sdat(MRSCont.files_ref{ref_ll,kk},1); + if raw_ref.subspecs > 1 + raw_ref_A = op_takesubspec(raw_ref,1); + [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines + raw_ref_B = op_takesubspec(raw_ref,2); + [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines + raw_ref_C = op_takesubspec(raw_ref,3); + [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines + raw_ref_D = op_takesubspec(raw_ref,4); + [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines + raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + else + [raw_ref] = op_rmempty(raw_ref); + end + raw_ref.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_ref = io_loadspec_sdat(MRSCont.files_ref{ref_ll,kk},1); + if raw_ref.subspecs > 1 + raw_ref_A = op_takesubspec(raw_ref,1); + [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines + raw_ref_B = op_takesubspec(raw_ref,2); + [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines + raw_ref_C = op_takesubspec(raw_ref,3); + [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines + raw_ref_D = op_takesubspec(raw_ref,4); + [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines + raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + else + [raw_ref] = op_rmempty(raw_ref); + end + raw_ref.flags.isHERCULES = 1; end - elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - raw_ref = io_loadspec_sdat(MRSCont.files_ref{kk},1); - if raw_ref.subspecs > 1 - raw_ref_A = op_takesubspec(raw_ref,1); - [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines - raw_ref_B = op_takesubspec(raw_ref,2); - [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines - raw_ref_C = op_takesubspec(raw_ref,3); - [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines - raw_ref_D = op_takesubspec(raw_ref,4); - [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines - raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); - else - [raw_ref] = op_rmempty(raw_ref); + MRSCont.raw_ref{ref_ll,kk} = raw_ref; + end + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = io_loadspec_sdat(MRSCont.files_w{w_ll,kk},1); + raw_w.flags.isUnEdited = 1; + MRSCont.raw_w{w_ll,kk} = raw_w; + end + + % Read in the MM reference data. + if MRSCont.flags.hasMMRef + temp_ll = MRSCont.opts.MultipleSpectra.mm_ref(ll); + if MRSCont.flags.isUnEdited + raw_mm_ref = io_loadspec_sdat(MRSCont.files_mm_ref{temp_ll,kk},1); + [raw_mm_ref] = op_rmempty(raw_mm_ref); + raw_mm_ref.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_mm_ref = io_loadspec_sdat(MRSCont.files_mm_ref{temp_ll,kk},2); + if raw_mm_ref.subspecs > 1 + raw_mm_ref_A = op_takesubspec(raw_mm_ref,1); + [raw_mm_ref_A] = op_rmempty(raw_mm_ref_A); % Remove empty lines + raw_mm_ref_B = op_takesubspec(raw_mm_ref,2); + [raw_mm_ref_B] = op_rmempty(raw_mm_ref_B); % Remove empty lines + raw_mm_ref = op_concatAverages(raw_mm_ref_A,raw_mm_ref_B); + else + [raw_mm_ref] = op_rmempty(raw_mm_ref); + end + raw_mm_ref.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_mm_ref = io_loadspec_sdat(MRSCont.files_mm_ref{temp_ll,kk},1); + if raw_mm_ref.subspecs > 1 + raw_mm_ref_A = op_takesubspec(raw_mm_ref,1); + [raw_mm_ref_A] = op_rmempty(raw_mm_ref_A); % Remove empty lines + raw_mm_ref_B = op_takesubspec(raw_mm_ref,2); + [raw_mm_ref_B] = op_rmempty(raw_mm_ref_B); % Remove empty lines + raw_mm_ref_C = op_takesubspec(raw_mm_ref,3); + [raw_mm_ref_C] = op_rmempty(raw_mm_ref_C); % Remove empty lines + raw_mm_ref_D = op_takesubspec(raw_mm_ref,4); + [raw_mm_ref_D] = op_rmempty(raw_mm_ref_D); % Remove empty lines + raw_mm_ref = op_concatAverages(raw_mm_ref_A,raw_mm_ref_B,raw_mm_ref_C,raw_mm_ref_D); + else + [raw_mm_ref] = op_rmempty(raw_mm_ref); + end + raw_mm_ref.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_mm_ref = io_loadspec_sdat(MRSCont.files_mm_ref{temp_ll,kk},1); + if raw_mm_ref.subspecs > 1 + raw_mm_ref_A = op_takesubspec(raw_mm_ref,1); + [raw_mm_ref_A] = op_rmempty(raw_mm_ref_A); % Remove empty lines + raw_mm_ref_B = op_takesubspec(raw_mm_ref,2); + [raw_mm_ref_B] = op_rmempty(raw_mm_ref_B); % Remove empty lines + raw_mm_ref_C = op_takesubspec(raw_mm_ref,3); + [raw_mm_ref_C] = op_rmempty(raw_mm_ref_C); % Remove empty lines + raw_mm_ref_D = op_takesubspec(raw_mm_ref,4); + [raw_mm_ref_D] = op_rmempty(raw_mm_ref_D); % Remove empty lines + raw_mm_ref = op_concatAverages(raw_mm_ref_A,raw_mm_ref_B,raw_mm_ref_C,raw_mm_ref_D); + else + [raw_mm_ref] = op_rmempty(raw_mm_ref); + end + raw_mm_ref.flags.isHERCULES = 1; end + MRSCont.raw_mm_ref{temp_ll,kk} = raw_mm_ref; end - MRSCont.raw_ref{kk} = raw_ref; - end - if MRSCont.flags.hasWater - raw_w = io_loadspec_sdat(MRSCont.files_w{kk},1); - MRSCont.raw_w{kk} = raw_w; end end end time = toc(refLoadTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,MRSCont.nDatasets(1),MRSCont.nDatasets(2),progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); % Set flag MRSCont.flags.coilsCombined = 1; MRSCont.runtime.Load = time; diff --git a/load/osp_LoadTwix.m b/load/osp_LoadTwix.m index 3a75ac05..c5a40f69 100644 --- a/load/osp_LoadTwix.m +++ b/load/osp_LoadTwix.m @@ -27,21 +27,21 @@ % Close any remaining open figures close all; if MRSCont.flags.hasMM - if length(MRSCont.files_mm) ~= MRSCont.nDatasets + if length(MRSCont.files_mm) ~= MRSCont.nDatasets(1) msg = 'Number of specified metabolite-nulled files does not match number of specified metabolite files.'; fprintf(msg); error(msg); end end if MRSCont.flags.hasRef - if length(MRSCont.files_ref) ~= MRSCont.nDatasets + if length(MRSCont.files_ref) ~= MRSCont.nDatasets(1) msg = 'Number of specified reference files does not match number of specified metabolite files.'; fprintf(msg); error(msg); end end if MRSCont.flags.hasWater - if length(MRSCont.files_w) ~= MRSCont.nDatasets + if length(MRSCont.files_w) ~= MRSCont.nDatasets(1) msg = 'Number of specified water files does not match number of specified metabolite files.'; fprintf(msg); error(msg); @@ -56,44 +56,66 @@ progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyLoad',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - % Read in the raw metabolite data - raw = io_loadspec_twix(MRSCont.files{kk}); - raw = op_leftshift(raw,raw.pointsToLeftshift); - MRSCont.raw_uncomb{kk} = raw; - % Read in the raw reference data. If a reference exists, perform the - % coil combination based on the reference, and perform an eddy current - % correction. If not, combine metabolite data based on its own signal. - if MRSCont.flags.hasRef - raw_ref = io_loadspec_twix(MRSCont.files_ref{kk}); - raw_ref = op_leftshift(raw_ref,raw_ref.pointsToLeftshift); - MRSCont.raw_ref_uncomb{kk} = raw_ref; - end - if MRSCont.flags.hasWater - raw_w = io_loadspec_twix(MRSCont.files_w{kk}); - raw_w = op_leftshift(raw_w,raw_w.pointsToLeftshift); - MRSCont.raw_w_uncomb{kk} = raw_w; - end - if MRSCont.flags.hasMM - raw_mm = io_loadspec_twix(MRSCont.files_mm{kk}); - raw_mm = op_leftshift(raw_mm,raw_mm.pointsToLeftshift); - MRSCont.raw_mm_uncomb{kk} = raw_mm; - end +for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + [~] = printLog('OspreyLoad',kk,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + + if ~(MRSCont.flags.didLoadData == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'raw') && (kk > length(MRSCont.raw))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + % Read in the raw metabolite data + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + raw = io_loadspec_twix(MRSCont.files{metab_ll,kk}); + raw = op_leftshift(raw,raw.pointsToLeftshift); + MRSCont.raw_uncomb{ll,kk} = raw; + % Read in the raw reference data. If a reference exists, perform the + % coil combination based on the reference, and perform an eddy current + % correction. If not, combine metabolite data based on its own signal. + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + raw_ref = io_loadspec_twix(MRSCont.files_ref{ref_ll,kk}); + raw_ref = op_leftshift(raw_ref,raw_ref.pointsToLeftshift); + MRSCont.raw_ref_uncomb{ref_ll,kk} = raw_ref; + end + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = io_loadspec_twix(MRSCont.files_w{w_ll,kk}); + raw_w = op_leftshift(raw_w,raw_w.pointsToLeftshift); + MRSCont.raw_w_uncomb{w_ll,kk} = raw_w; + else + w_ll = 1; + end + if MRSCont.flags.hasMM + temp_ll = MRSCont.opts.MultipleSpectra.mm(ll); + raw_mm = io_loadspec_twix(MRSCont.files_mm{temp_ll,kk}); + raw_mm = op_leftshift(raw_mm,raw_mm.pointsToLeftshift); + MRSCont.raw_mm_uncomb{temp_ll,kk} = raw_mm; + end + if MRSCont.flags.hasMMRef + temp_ll = MRSCont.opts.MultipleSpectra.mm_ref(ll); + raw_mm_ref = io_loadspec_twix(MRSCont.files_mm_ref{temp_ll,kk}); + raw_mm_ref = op_leftshift(raw_mm_ref,raw_mm_ref.pointsToLeftshift); + MRSCont.raw_mm_ref_uncomb{temp_ll,kk} = raw_mm_ref; + end - % Perform coil combination (SENSE-based reconstruction if PRIAM flag set) - if ~MRSCont.flags.isPRIAM - [MRSCont] = osp_combineCoils(MRSCont,kk); - elseif MRSCont.flags.isPRIAM - fprintf('Coming soon!'); - error('Coming soon!'); - %[MRSCont] = osp_senseRecon(MRSCont); + % Perform coil combination (SENSE-based reconstruction if PRIAM flag set) + if ~MRSCont.flags.isPRIAM + [MRSCont] = osp_combineCoils(MRSCont,kk,ll,ref_ll,w_ll); + elseif MRSCont.flags.isPRIAM + + fprintf('Coming soon!'); + error('Coming soon!'); + %[MRSCont] = osp_senseRecon(MRSCont); + end end end end +% Delete un-combined data to free up memory +raw_fields = {'raw_uncomb','raw_ref_uncomb','raw_w_uncomb'}; +for kk = 1:length(raw_fields) + if isfield(MRSCont, raw_fields{kk}) + MRSCont = rmfield(MRSCont, raw_fields{kk}); + end +end time = toc(refLoadTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,ll,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.Load = time; end \ No newline at end of file diff --git a/load/osp_detDataType.m b/load/osp_detDataType.m index c73f1df8..87a295c9 100644 --- a/load/osp_detDataType.m +++ b/load/osp_detDataType.m @@ -1,4 +1,4 @@ -function [MRSCont, retMsg] = osp_detDataType(MRSCont) +function [MRSCont, retMsg,reordered] = osp_detDataType(MRSCont) %% [MRSCont, retMsg] = osp_detDataType(MRSCont) % This function determines the MRI vendor and datatype of the filenames % provided in the MRSCont.files cells. A warning is flagged if the @@ -26,17 +26,73 @@ % % HISTORY: % 2019-02-19: First version of the code. - +reordered = 0; % Concatenate all data including MM, water and reference scans -files = MRSCont.files; -if isfield(MRSCont, 'files_mm') - files = [files MRSCont.files_mm]; +if ~iscell(MRSCont.files{1}) && ~MRSCont.flags.reordered + files = MRSCont.files; +else + if ~MRSCont.flags.reordered + files = horzcat(MRSCont.files{:}); + MRSCont.files = vertcat(MRSCont.files{:}); + MRSCont.files = MRSCont.files'; + reordered = 1; + else + files = horzcat(MRSCont.files(:))'; + end +end + +if isfield(MRSCont, 'files_mm') && ~isempty(MRSCont.files_mm) + if ~iscell(MRSCont.files_mm{1}) && ~MRSCont.flags.reordered + files = [files MRSCont.files_mm]; + else + if ~MRSCont.flags.reordered + files = [files horzcat(MRSCont.files_mm{:})]; + MRSCont.files_mm = vertcat(MRSCont.files_mm{:}); + MRSCont.files_mm = MRSCont.files_mm'; + reordered = 1; + else + files = [files horzcat(MRSCont.files_mm(:))']; + end + end +end +if isfield(MRSCont, 'files_mm_ref') && ~isempty(MRSCont.files_mm_ref) + if ~iscell(MRSCont.files_mm_ref{1}) && ~MRSCont.flags.reordered + files = [files MRSCont.files_mm_ref]; + else + if ~MRSCont.flags.reordered + files = [files horzcat(MRSCont.files_mm_ref{:})]; + MRSCont.files_mm_ref = vertcat(MRSCont.files_mm_ref{:}); + MRSCont.files_mm_ref = MRSCont.files_mm_ref'; + else + files = [files horzcat(MRSCont.files_mm_ref(:))']; + end + end end -if isfield(MRSCont, 'files_ref') - files = [files MRSCont.files_ref]; +if isfield(MRSCont, 'files_ref') && ~isempty(MRSCont.files_ref) + if ~iscell(MRSCont.files_ref{1}) && ~MRSCont.flags.reordered + files = [files MRSCont.files_ref]; + else + if ~MRSCont.flags.reordered + files = [files horzcat(MRSCont.files_ref{:})]; + MRSCont.files_ref = vertcat(MRSCont.files_ref{:}); + MRSCont.files_ref = MRSCont.files_ref'; + else + files = [files horzcat(MRSCont.files_ref(:))']; + end + end end -if isfield(MRSCont, 'files_w') - files = [files MRSCont.files_w]; +if isfield(MRSCont, 'files_w') && ~isempty(MRSCont.files_w) + if ~iscell(MRSCont.files_w{1}) && ~MRSCont.flags.reordered + files = [files MRSCont.files_w]; + else + if ~MRSCont.flags.reordered + files = [files horzcat(MRSCont.files_w{:})]; + MRSCont.files_w = vertcat(MRSCont.files_w{:}); + MRSCont.files_w = MRSCont.files_w'; + else + files = [files horzcat(MRSCont.files_w(:))']; + end + end end % Determine data and vendor for each file diff --git a/overview/OspreyOverview.m b/overview/OspreyOverview.m index 142dd8a3..14e5d81c 100755 --- a/overview/OspreyOverview.m +++ b/overview/OspreyOverview.m @@ -37,93 +37,71 @@ %%% 2. INITIALIZE VARIABLES %%% %Getting the names of the SubSpectra and Fits -SubSpecNames = fieldnames(MRSCont.processed); -NoSubSpec = length(fieldnames(MRSCont.processed)); -if MRSCont.flags.didFit - if iscell(MRSCont.fit.results) % Is DualVoxel - FitNames = fieldnames(MRSCont.fit.results{1}); - NoFit = length(fieldnames(MRSCont.fit.results{1})); - else %Is SVS - FitNames = fieldnames(MRSCont.fit.results); - NoFit = length(fieldnames(MRSCont.fit.results)); + +OrderNames = {'metab'}; +OrderNamesFit = {'metab'}; +if MRSCont.flags.hasMM + OrderNames = horzcat(OrderNames, 'mm'); + OrderNamesFit = horzcat(OrderNamesFit, 'mm'); +end + +if MRSCont.flags.hasRef + OrderNames = horzcat(OrderNames, 'ref'); + if ~strcmp(MRSCont.opts.fit.method,'LCModel') + OrderNamesFit = horzcat(OrderNamesFit, 'ref'); end +end + +if MRSCont.flags.hasMMRef + OrderNames = horzcat(OrderNames, 'mm_ref'); +end - dataPlotNames = FitNames; - tempFitNames = FitNames; +if MRSCont.flags.hasWater + OrderNames = horzcat(OrderNames, 'w'); + OrderNamesFit = horzcat(OrderNamesFit, 'w'); end +S = orderfields(MRSCont.processed,OrderNames); +dataPlotNames = fieldnames(S)'; +NoSpec = length(fieldnames(MRSCont.processed)); + -shift = 0; +for ss = 1:NoSpec + SubSpecNamesStruct.(dataPlotNames{ss}) = MRSCont.processed.(dataPlotNames{ss}){1}.names; +end +MRSCont.overview.SubSpecNamesStruct = SubSpecNamesStruct; if MRSCont.flags.didFit - %Getting the final model names (needed for concatenated fits) - for sf = 1 : NoFit - switch MRSCont.opts.fit.method - case 'Osprey' - switch FitNames{sf} - case 'off' - dataPlotNames{sf} = 'A'; - case 'conc' - if MRSCont.flags.isMEGA - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - shift = 1; - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'diff2'; - dataPlotNames{sf+2} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - tempFitNames{sf+2} = 'conc'; - shift = 2; - end - otherwise - dataPlotNames{sf + shift} = FitNames{sf}; - tempFitNames{sf + shift} = FitNames{sf}; - end - case 'OspreyAsym' - switch FitNames{sf} - case 'off' - dataPlotNames{sf} = 'A'; - case 'conc' - if MRSCont.flags.isMEGA - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - shift = 1; + S = orderfields(MRSCont.fit.results,OrderNamesFit); + FitSpecNames = fieldnames(S)'; + NoFitSpecNames = length(FitSpecNames); + if ~strcmp(MRSCont.opts.fit.method,'LCModel') + for sf = 1 : NoFitSpecNames + for sn = 1 : size(MRSCont.fit.results.(FitSpecNames{sf}).fitParams,3) + for sb = 1 : size(MRSCont.fit.results.(FitSpecNames{sf}).fitParams,1) + if ~(strcmp(FitSpecNames{sf},'ref') ||strcmp(FitSpecNames{sf},'w')) + if ~isempty(MRSCont.fit.results.(FitSpecNames{sf}).fitParams{sb,1,sn}) + FitSpecNamesStruct.(FitSpecNames{sf}){sb,sn} = MRSCont.fit.resBasisSet.(FitSpecNames{sf}).(MRSCont.info.(FitSpecNames{sf}).unique_ndatapoint_spectralwidth{1}){1,1,sn}.names{1}; end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - dataPlotNames{sf} = 'diff1'; - dataPlotNames{sf+1} = 'diff2'; - dataPlotNames{sf+2} = 'sum'; - tempFitNames{sf} = 'conc'; - tempFitNames{sf+1} = 'conc'; - tempFitNames{sf+2} = 'conc'; - shift = 2; - end - otherwise - dataPlotNames{sf + shift} = FitNames{sf}; - tempFitNames{sf + shift} = FitNames{sf}; - end - case 'LCModel' - switch FitNames{sf} - case 'off' - dataPlotNames{sf} = 'A'; - otherwise - dataPlotNames{sf} = FitNames{sf}; + else + FitSpecNamesStruct.(FitSpecNames{sf}){1} = MRSCont.fit.resBasisSet.(FitSpecNames{sf}).(MRSCont.info.(FitSpecNames{sf}).unique_ndatapoint_spectralwidth{1}){1,1,1}.names{1}; + end end + end end + else + FitSpecNamesStruct.(FitSpecNames{1}){1} = 'A'; end - FitNames = tempFitNames; - NoFit = length(FitNames); + MRSCont.overview.FitSpecNamesStruct = FitSpecNamesStruct; end + + +% shift = 0; + + %%% 3. INTERPOLATION & NORMALIZATION %%% -% Starting with the processed data +% Starting with the processed data OverviewTime = tic; %Progress text for the GUI @@ -139,9 +117,9 @@ if (MRSCont.flags.isPRIAM == 1) && isfield(MRSCont.flags,'isPRIAM') Voxels = 2; for rr = 1 : Voxels - for ss = 1 : NoSubSpec % Loop over Subspec + for ss = 1 : NoSpec % Loop over Subspec for kk = 1 : MRSCont.nDatasets - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){kk} = op_takeVoxel(MRSCont.processed.(SubSpecNames{ss}){kk},rr); + MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){kk} = op_takeVoxel(MRSCont.processed.(dataPlotNames{ss}){kk},rr); end end end @@ -149,31 +127,33 @@ Voxels = 1; MRSCont.overview.Osprey.all_data_voxel_1 = MRSCont.processed; end + + fprintf('\n'); -fprintf('Gathering spectra from subspectrum %d out of %d total subspectra...', 1, NoSubSpec); +fprintf('Gathering spectra from subspectrum %d out of %d total subspectra...', 1, NoSpec); for rr = 1 : Voxels - for ss = 1 : NoSubSpec % Loop over Subspec - msg = sprintf('Gathering spectra from subspectrum %d out of %d total subspectra...', ss, NoSubSpec); + for ss = 1 : NoSpec % Loop over Subspec + msg = sprintf('Gathering spectra from subspectrum %d out of %d total subspectra...', ss, NoSpec); reverseStr = repmat(sprintf('\b'), 1, length(msg)); fprintf([reverseStr, msg]); if MRSCont.flags.isGUI && isfield(progressText,'String') - set(progressText,'String' ,sprintf('Gathering spectra from subspectrum %d out of %d total subspectra...\n', ss, NoSubSpec)); + set(progressText,'String' ,sprintf('Gathering spectra from subspectrum %d out of %d total subspectra...\n', ss, NoSpec)); drawnow end for kk = 1 : MRSCont.nDatasets - if MRSCont.processed.(SubSpecNames{ss}){1,kk}.sz(1) < MRSCont.info.(SubSpecNames{ss}).max_ndatapoint - ppmRangeData = MRSCont.processed.(SubSpecNames{ss}){1,MRSCont.info.(SubSpecNames{ss}).max_ndatapoint_ind}.ppm'; - ppmRangeDataToInt = MRSCont.processed.(SubSpecNames{ss}){1,kk}.ppm; + if MRSCont.processed.(dataPlotNames{ss}){1,kk}.sz(1) < MRSCont.info.(dataPlotNames{ss}).max_ndatapoint + ppmRangeData = MRSCont.processed.(dataPlotNames{ss}){1,MRSCont.info.(dataPlotNames{ss}).max_ndatapoint_ind}.ppm'; + ppmRangeDataToInt = MRSCont.processed.(dataPlotNames{ss}){1,kk}.ppm; ppmIsInDataRange = (ppmRangeDataToInt < ppmRangeData(1)) & (ppmRangeDataToInt > ppmRangeData(end)); if sum(ppmIsInDataRange) == 0 ppmIsInDataRange = (ppmRangeDataToInt > ppmRangeData(1)) & (ppmRangeDataToInt < ppmRangeData(end)); end - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.specs = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.specs(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm = ppmRangeData; - if mod(size(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.specs,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.dims.t),2)==0 - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.fids=ifft(fftshift(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.specs,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.dims.t),[],MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.dims.t); + MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.specs = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.specs(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); + MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.ppm = ppmRangeData; + if mod(size(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.specs,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.dims.t),2)==0 + MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.fids=ifft(fftshift(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.specs,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.dims.t),[],MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.dims.t); else - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.fids=ifft(circshift(fftshift(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.specs,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.dims.t),1),[],MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.dims.t); + MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.fids=ifft(circshift(fftshift(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.specs,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.dims.t),1),[],MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){1,kk}.dims.t); end end @@ -181,37 +161,6 @@ end end - -% Align the spectra according to the NAA peak -for rr = 1 : Voxels - for ss = 1 : NoSubSpec - for kk = 1 : MRSCont.nDatasets - %Find the ppm of the maximum peak magnitude within the given range: - if MRSCont.flags.isUnEdited - %Find the ppm of the maximum peak magnitude within the given range: - ppmindex=find(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.specs(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.specs(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm<2.1); - ppmmax=ppmrange(ppmindex); - refShift=(ppmmax-2.013); - end - if MRSCont.flags.isMEGA - ppmindex=find(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm<2.1); - ppmmax=ppmrange(ppmindex); - refShift=(ppmmax-2.013); - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - ppmindex=find(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm(MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.ppm<2.1); - ppmmax=ppmrange(ppmindex); - refShift=(ppmmax-2.013); - end - - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){1,kk}.ppm - refShift; - end - end -end - fprintf('\n... done.\n'); if MRSCont.flags.isGUI && isfield(progressText,'String') set(progressText,'String' ,sprintf('... done.')); @@ -221,411 +170,246 @@ if MRSCont.flags.didFit % Apply the same stpes to the fits - fprintf('Gathering fit models from fit %d out of %d total fits...', 1, NoFit); + fprintf('Gathering fit models from fit %d out of %d total fits...', 1, NoFitSpecNames); for rr = 1 : Voxels%Loop over - for sf = 1 : NoFit %Loop over all fits - msg = sprintf('Gathering fit models from fit %d out of %d total fits...', sf, NoFit); - reverseStr = repmat(sprintf('\b'), 1, length(msg)); - fprintf([reverseStr, msg]); - if MRSCont.flags.isGUI && isfield(progressText,'String') - set(progressText,'String' ,sprintf('Gathering fit models from fit %d out of %d total fits...\n', sf, NoFit)); - drawnow - end - for kk = 1 : MRSCont.nDatasets %Loop over all datasets - switch MRSCont.opts.fit.method %Which model was used - case 'Osprey' - if strcmp((FitNames{sf}), 'ref') || strcmp((FitNames{sf}), 'w') % Water model - % if water, use the water model - fitRangePPM = MRSCont.opts.fit.rangeWater; - if Voxels < 2 - dataToPlot = MRSCont.processed.(dataPlotNames{sf}){kk}; - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}).water.(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); - % Get the fit parameters - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - else - dataToPlot = op_takeVoxel(MRSCont.processed.(dataPlotNames{sf}){kk},rr); - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}).water.(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); - % Get the fit parameters - fitParams = MRSCont.fit.results{rr}.(FitNames{sf}).fitParams{kk}; - end - % Pack up into structs to feed into the reconstruction functions - inputData.dataToFit = dataToPlot; - inputData.basisSet = basisSet; - if Voxels < 2 - inputSettings.scale = MRSCont.fit.scale{kk}; - else - inputSettings.scale = MRSCont.fit.scale{kk}; - end - inputSettings.fitRangePPM = fitRangePPM; - inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; - % If water, extract and apply nonlinear parameters - [ModelOutput] = fit_waterOspreyParamsToModel(inputData, inputSettings, fitParams); - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = ModelOutput.completeFit; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = ModelOutput.ppm; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = ModelOutput.data; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = ModelOutput.residual; - else % if metabolite or MM data, use the metabolite model - fitRangePPM = MRSCont.opts.fit.range; - if Voxels < 2 - dataToPlot = MRSCont.processed.(dataPlotNames{sf}){kk}; - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}).(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - else - dataToPlot = op_takeVoxel(MRSCont.processed.(dataPlotNames{sf}){kk},rr); - fitParams = MRSCont.fit.results{rr}.(FitNames{sf}).fitParams{kk}; - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}).(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); - end - % Pack up into structs to feed into the reconstruction functions - inputData.dataToFit = dataToPlot; - inputData.basisSet = basisSet; - if Voxels < 2 - inputSettings.scale = MRSCont.fit.scale{kk}; - else - inputSettings.scale = MRSCont.fit.scale{kk}; - end - inputSettings.fitRangePPM = fitRangePPM; - inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; - inputSettings.fitStyle = MRSCont.opts.fit.style; - inputSettings.flags.isMEGA = MRSCont.flags.isMEGA; - inputSettings.flags.isHERMES = MRSCont.flags.isHERMES; - inputSettings.flags.isHERCULES = MRSCont.flags.isHERCULES; - inputSettings.flags.isPRIAM = MRSCont.flags.isPRIAM; - inputSettings.concatenated.Subspec = dataPlotNames{sf}; - if strcmp(inputSettings.fitStyle,'Concatenated') - [ModelOutput] = fit_OspreyParamsToConcModel(inputData, inputSettings, fitParams); - else - [ModelOutput] = fit_OspreyParamsToModel(inputData, inputSettings, fitParams); - end - if ~isnan(ModelOutput.completeFit) %If the fit was succesful - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = ModelOutput.completeFit; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline = ModelOutput.baseline; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = ModelOutput.ppm; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = ModelOutput.residual; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = ModelOutput.data; - if strcmp(FitNames{sf}, 'mm') %re_mm loop over basis functions - for n = 1 : 4 + MRSCont.fit.basisSet.nMM - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(['fit' MRSCont.fit.basisSet.name{n}]) = ModelOutput.indivMets(:,n); - end - idx_NAA = 4; - idx_Cr = 1; - idx_CrCH2 = 2; - if ~isempty(idx_CrCH2) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr) + ModelOutput.indivMets(:,idx_CrCH2); + for ss = 1 :NoFitSpecNames %Loop over fitted supsctra + if strcmp(FitSpecNames{ss}, 'ref') || strcmp(FitSpecNames{ss}, 'w') % Water model + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}) = cell(1,MRSCont.nDatasets(1),size(FitSpecNamesStruct.(FitSpecNames{ss}),2)); + else + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}) = cell(size(FitSpecNamesStruct.(FitSpecNames{ss}),1),MRSCont.nDatasets(1),size(FitSpecNamesStruct.(FitSpecNames{ss}),2)); + end + for sf = 1 : size(FitSpecNamesStruct.(FitSpecNames{ss}),2) %Loop over all fits + for bf = 1 : size(FitSpecNamesStruct.(FitSpecNames{ss}),1) %Loop over all basis sets + msg = sprintf('Gathering fit models from fit %d out of %d total fits...', ss, NoFitSpecNames); + reverseStr = repmat(sprintf('\b'), 1, length(msg)); + fprintf([reverseStr, msg]); + if MRSCont.flags.isGUI && isfield(progressText,'String') + set(progressText,'String' ,sprintf('Gathering fit models from fit %d out of %d total fits...\n', ss, NoFitSpecNames)); + drawnow + end + if ~isempty(FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}) + for kk = 1 : MRSCont.nDatasets(1) %Loop over all datasets + switch MRSCont.opts.fit.method %Which model was used + case 'Osprey' + if strcmp(FitSpecNames{ss}, 'ref') || strcmp(FitSpecNames{ss}, 'w') % Water model + % if water, use the water model + fitRangePPM = MRSCont.opts.fit.rangeWater; + if Voxels < 2 + dataToPlot = MRSCont.processed.(FitSpecNames{ss}){kk}; + basisSet = MRSCont.fit.resBasisSet.(FitSpecNames{ss}).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){1}; + % Get the fit parameters + fitParams = MRSCont.fit.results.(FitSpecNames{ss}).fitParams{kk}; else - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr) ; + dataToPlot = op_takeVoxel(MRSCont.processed.(FitSpecNames{ss}){kk},rr); + basisSet = MRSCont.fit.resBasisSet{rr}.(FitSpecNames{bf,sf}).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){1}; + % Get the fit parameters + fitParams = MRSCont.fit.results{rr}.(FitSpecNames{ss}).fitParams{kk}; end - if MRSCont.opts.fit.fitMM == 1 - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittMM = sum(ModelOutput.indivMets(:,5:end),2); - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitNAA = sum(ModelOutput.indivMets(:,4),2); - - end - %section to write out MM_clean spectra - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.MM_clean = ModelOutput.data -sum(ModelOutput.indivMets(:,1:4),2); - else%re_mm - for n = 1 : size(ModelOutput.indivMets,2) % loop over basis functions - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(['fit' basisSet.name{n}]) = ModelOutput.indivMets(:,n); - end - % Add basis functions of metabolite combinations - % tNAA = NAA + NAAG - idx_NAA = find(strcmp(basisSet.name,'NAA')); - idx_NAAG = find(strcmp(basisSet.name,'NAAG')); - if isempty(idx_NAA) && isempty(idx_NAAG) - % do nothing - elseif isempty(idx_NAA) && ~isempty(idx_NAAG) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = ModelOutput.indivMets(:,idx_NAAG); - elseif ~isempty(idx_NAA) && isempty(idx_NAAG) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = ModelOutput.indivMets(:,idx_NAA); - elseif ~isempty(idx_NAA) && ~isempty(idx_NAAG) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = ModelOutput.indivMets(:,idx_NAA) + ModelOutput.indivMets(:,idx_NAAG); - end - - - % tCr = Cr + tCr - CrCH2 - idx_Cr = find(strcmp(basisSet.name,'Cr')); - idx_PCr = find(strcmp(basisSet.name,'PCr')); - if isempty(idx_Cr) && isempty(idx_PCr) - % do nothing - elseif isempty(idx_Cr) && ~isempty(idx_PCr) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_PCr); - elseif ~isempty(idx_Cr) && isempty(idx_PCr) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr); - elseif ~isempty(idx_Cr) && ~isempty(idx_PCr) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr) + ModelOutput.indivMets(:,idx_PCr); - end - - % if present, add CrCH2 model - idx_CrCH2 = find(strcmp(basisSet.name,'CrCH2')); - if ~isempty(idx_CrCH2) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr + ModelOutput.indivMets(:,idx_CrCH2); + % Pack up into structs to feed into the reconstruction functions + inputData.dataToFit = dataToPlot; + inputData.basisSet = basisSet; + if Voxels < 2 + inputSettings.scale = MRSCont.fit.scale{kk}; else - % do nothing - end - - % tCho = GPC + PCh - idx_GPC = find(strcmp(basisSet.name,'GPC')); - idx_PCh = find(strcmp(basisSet.name,'PCh')); - if isempty(idx_GPC) && isempty(idx_PCh) - % do nothing - elseif isempty(idx_GPC) && ~isempty(idx_PCh) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCho = ModelOutput.indivMets(:,idx_PCh); - elseif ~isempty(idx_GPC) && isempty(idx_PCh) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCho = ModelOutput.indivMets(:,idx_GPC); - elseif ~isempty(idx_GPC) && ~isempty(idx_PCh) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCho = ModelOutput.indivMets(:,idx_GPC) + ModelOutput.indivMets(:,idx_PCh); - end - - % Glx = Glu + Gln - idx_Glu = find(strcmp(basisSet.name,'Glu')); - idx_Gln = find(strcmp(basisSet.name,'Gln')); - if isempty(idx_Glu) && isempty(idx_Gln) - % do nothing - elseif isempty(idx_Glu) && ~isempty(idx_Gln) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitGlx = ModelOutput.indivMets(:,idx_Gln); - elseif ~isempty(idx_Glu) && isempty(idx_Gln) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitGlx = ModelOutput.indivMets(:,idx_Glu); - elseif ~isempty(idx_Glu) && ~isempty(idx_Gln) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitGlx = ModelOutput.indivMets(:,idx_Glu) + ModelOutput.indivMets(:,idx_Gln); + inputSettings.scale = MRSCont.fit.scale{kk}; end - - % tEA = PE + EA - idx_PE = find(strcmp(basisSet.name,'PE')); - idx_EA = find(strcmp(basisSet.name,'EA')); - if isempty(idx_PE) && isempty(idx_Gln) - % do nothing - elseif isempty(idx_PE) && ~isempty(idx_EA) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittEA = ModelOutput.indivMets(:,idx_EA); - elseif ~isempty(idx_PE) && isempty(idx_EA) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittEA = ModelOutput.indivMets(:,idx_PE); - elseif ~isempty(idx_PE) && ~isempty(idx_EA) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittEA = ModelOutput.indivMets(:,idx_PE) + ModelOutput.indivMets(:,idx_EA); - end - - % tMM = all MM functions - if MRSCont.opts.fit.fitMM == 1 - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittMM = sum(ModelOutput.indivMets(:,basisSet.nMets+1:end),2); - end - end %re_mm - else %if the fit was not succesful write nans into the corresponding fields - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = nan; - end - end - case 'OspreyAsym' - if strcmp((FitNames{sf}), 'ref') || strcmp((FitNames{sf}), 'w') % Water model - % if water, use the water model - if Voxels < 2 - dataToPlot = MRSCont.processed.(dataPlotNames{sf}){kk}; - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}).water.(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - % Get the fit parameters - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - else - dataToPlot = op_takeVoxel(MRSCont.processed.(dataPlotNames{sf}){kk},rr); - basisSet = MRSCont.fit.resBasisSet{rr}.(FitNames{sf}).water.(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - % Get the fit parameters - fitParams = MRSCont.fit.results{rr}.(FitNames{sf}).fitParams{kk}; - end - % Get the fit parameters - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - % Pack up into structs to feed into the reconstruction functions - inputData.dataToFit = dataToPlot; - inputData.basisSet = basisSet; - inputSettings.scale = MRSCont.fit.scale{kk}; - inputSettings.fitRangePPM = fitRangePPM; - inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; - % If water, extract and apply nonlinear parameters - [ModelOutput] = fit_waterOspreyParamsToModel(inputData, inputSettings, fitParams); - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = ModelOutput.completeFit; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = ModelOutput.ppm; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = ModelOutput.data; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = ModelOutput.residual; - else % if metabolite or MM data, use the metabolite model - fitRangePPM = MRSCont.opts.fit.range; - if Voxels < 2 - dataToPlot = MRSCont.processed.(dataPlotNames{sf}){kk}; - basisSet = MRSCont.fit.resBasisSet.(FitNames{sf}).water.(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - % Get the fit parameters - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - else - dataToPlot = op_takeVoxel(MRSCont.processed.(dataPlotNames{sf}){kk},rr); - basisSet = MRSCont.fit.resBasisSet{rr}.(FitNames{sf}).water.(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - % Get the fit parameters - fitParams = MRSCont.fit.results{rr}.(FitNames{sf}).fitParams{kk}; - end - % Pack up into structs to feed into the reconstruction functions - inputData.dataToFit = dataToPlot; - inputData.basisSet = basisSet; - if Voxels < 2 - inputSettings.scale = MRSCont.fit.scale{kk}; - else - inputSettings.scale = MRSCont.fit.scale{kk}(rr); - end - inputSettings.fitRangePPM = fitRangePPM; - inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; - inputSettings.fitStyle = MRSCont.opts.fit.style; - inputSettings.flags.isMEGA = MRSCont.flags.isMEGA; - inputSettings.flags.isHERMES = MRSCont.flags.isHERMES; - inputSettings.flags.isHERCULES = MRSCont.flags.isHERCULES; - inputSettings.flags.isPRIAM = MRSCont.flags.isPRIAM; - inputSettings.concatenated.Subspec = dataPlotNames{sf}; - if strcmp(inputSettings.fitStyle,'Concatenated') - [ModelOutput] = fit_OspreyParamsToConcModel(inputData, inputSettings, fitParams); - else - [ModelOutput] = fit_OspreyAsymParamsToModel(inputData, inputSettings, fitParams); - end - if ~isnan(ModelOutput.completeFit) %If the fit was succesful - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = ModelOutput.completeFit; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline = ModelOutput.baseline; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = ModelOutput.ppm; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = ModelOutput.residual; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = ModelOutput.data; - if strcmp(FitNames{sf}, 'mm') %re_mm loop over basis functions - for n = 1 : 4 + MRSCont.fit.basisSet.nMM - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(['fit' MRSCont.fit.basisSet.name{n}]) = ModelOutput.indivMets(:,n); - end - idx_NAA = 4; - idx_Cr = 1; - idx_CrCH2 = 2; - if ~isempty(idx_CrCH2) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr) + ModelOutput.indivMets(:,idx_CrCH2); + inputSettings.fitRangePPM = fitRangePPM; + inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; + % If water, extract and apply nonlinear parameters + [ModelOutput] = fit_waterOspreyParamsToModel(inputData, inputSettings, fitParams); + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fit = ModelOutput.completeFit; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.ppm = ModelOutput.ppm; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.data = ModelOutput.data; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.res = ModelOutput.residual; + else % if metabolite or MM data, use the metabolite model + fitRangePPM = MRSCont.opts.fit.range; + if Voxels < 2 + + dataToPlot = op_takesubspec(MRSCont.processed.(FitSpecNames{ss}){kk},find(strcmp(MRSCont.processed.(FitSpecNames{ss}){kk}.names,FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}))); + basisSet = MRSCont.fit.resBasisSet.(FitSpecNames{ss}).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){bf,sf}; + fitParams = MRSCont.fit.results.(FitSpecNames{ss}).fitParams{bf,kk,sf}; else - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr) ; - end - if MRSCont.opts.fit.fitMM == 1 - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittMM = sum(ModelOutput.indivMets(:,5:end),2); - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitNAA = sum(ModelOutput.indivMets(:,4),2); - - end - %section to write out MM_clean spectra - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.MM_clean = ModelOutput.data -sum(ModelOutput.indivMets(:,1:4),2); - else%re_mm - for n = 1 : size(ModelOutput.indivMets,2) % loop over basis functions - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(['fit' basisSet.name{n}]) = ModelOutput.indivMets(:,n); - end - % Add basis functions of metabolite combinations - % tNAA = NAA + NAAG - idx_NAA = find(strcmp(basisSet.name,'NAA')); - idx_NAAG = find(strcmp(basisSet.name,'NAAG')); - if isempty(idx_NAA) && isempty(idx_NAAG) - % do nothing - elseif isempty(idx_NAA) && ~isempty(idx_NAAG) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = ModelOutput.indivMets(:,idx_NAAG); - elseif ~isempty(idx_NAA) && isempty(idx_NAAG) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = ModelOutput.indivMets(:,idx_NAA); - elseif ~isempty(idx_NAA) && ~isempty(idx_NAAG) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = ModelOutput.indivMets(:,idx_NAA) + ModelOutput.indivMets(:,idx_NAAG); - end - - - % tCr = Cr + tCr - CrCH2 - idx_Cr = find(strcmp(basisSet.name,'Cr')); - idx_PCr = find(strcmp(basisSet.name,'PCr')); - if isempty(idx_Cr) && isempty(idx_PCr) - % do nothing - elseif isempty(idx_Cr) && ~isempty(idx_PCr) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_PCr); - elseif ~isempty(idx_Cr) && isempty(idx_PCr) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr); - elseif ~isempty(idx_Cr) && ~isempty(idx_PCr) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = ModelOutput.indivMets(:,idx_Cr) + ModelOutput.indivMets(:,idx_PCr); + dataToPlot = op_takeVoxel(MRSCont.processed.(dataPlotNames{ss}){kk},rr); + fitParams = MRSCont.fit.results{rr}.(FitSpecNames{ss}).fitParams{bf,kk,sf}; + basisSet = MRSCont.fit.resBasisSet{rr}.(FitSpecNames{ss}).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){bf,sf}; end - - % if present, add CrCH2 model - idx_CrCH2 = find(strcmp(basisSet.name,'CrCH2')); - if ~isempty(idx_CrCH2) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr + ModelOutput.indivMets(:,idx_CrCH2); + % Pack up into structs to feed into the reconstruction functions + inputData.dataToFit = dataToPlot; + inputData.basisSet = basisSet; + if Voxels < 2 + inputSettings.scale = MRSCont.fit.scale{kk}; else - % do nothing - end - - % tCho = GPC + PCh - idx_GPC = find(strcmp(basisSet.name,'GPC')); - idx_PCh = find(strcmp(basisSet.name,'PCh')); - if isempty(idx_GPC) && isempty(idx_PCh) - % do nothing - elseif isempty(idx_GPC) && ~isempty(idx_PCh) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCho = ModelOutput.indivMets(:,idx_PCh); - elseif ~isempty(idx_GPC) && isempty(idx_PCh) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCho = ModelOutput.indivMets(:,idx_GPC); - elseif ~isempty(idx_GPC) && ~isempty(idx_PCh) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCho = ModelOutput.indivMets(:,idx_GPC) + ModelOutput.indivMets(:,idx_PCh); + inputSettings.scale = MRSCont.fit.scale{kk}; end - - % Glx = Glu + Gln - idx_Glu = find(strcmp(basisSet.name,'Glu')); - idx_Gln = find(strcmp(basisSet.name,'Gln')); - if isempty(idx_Glu) && isempty(idx_Gln) - % do nothing - elseif isempty(idx_Glu) && ~isempty(idx_Gln) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitGlx = ModelOutput.indivMets(:,idx_Gln); - elseif ~isempty(idx_Glu) && isempty(idx_Gln) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitGlx = ModelOutput.indivMets(:,idx_Glu); - elseif ~isempty(idx_Glu) && ~isempty(idx_Gln) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fitGlx = ModelOutput.indivMets(:,idx_Glu) + ModelOutput.indivMets(:,idx_Gln); + inputSettings.fitRangePPM = fitRangePPM; + inputSettings.minKnotSpacingPPM = MRSCont.opts.fit.bLineKnotSpace; + inputSettings.fitStyle = MRSCont.opts.fit.style; + inputSettings.flags.isMEGA = MRSCont.flags.isMEGA; + inputSettings.flags.isHERMES = MRSCont.flags.isHERMES; + inputSettings.flags.isHERCULES = MRSCont.flags.isHERCULES; + inputSettings.flags.isPRIAM = MRSCont.flags.isPRIAM; + inputSettings.concatenated.Subspec = FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}; + if isfield(MRSCont.opts.fit,'GAP') + inputSettings.GAP = MRSCont.opts.fit.GAP.(FitSpecNamesStruct.(FitSpecNames{ss}){bf,sf}); + else + inputSettings.GAP = []; end - - % tEA = PE + EA - idx_PE = find(strcmp(basisSet.name,'PE')); - idx_EA = find(strcmp(basisSet.name,'EA')); - if isempty(idx_PE) && isempty(idx_Gln) - % do nothing - elseif isempty(idx_PE) && ~isempty(idx_EA) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittEA = ModelOutput.indivMets(:,idx_EA); - elseif ~isempty(idx_PE) && isempty(idx_EA) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittEA = ModelOutput.indivMets(:,idx_PE); - elseif ~isempty(idx_PE) && ~isempty(idx_EA) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittEA = ModelOutput.indivMets(:,idx_PE) + ModelOutput.indivMets(:,idx_EA); + if strcmp(inputSettings.fitStyle,'Concatenated') + [ModelOutput] = fit_OspreyParamsToConcModel(inputData, inputSettings, fitParams); + else + [ModelOutput] = fit_OspreyParamsToModel(inputData, inputSettings, fitParams); end - - % tMM = all MM functions - if MRSCont.opts.fit.fitMM == 1 - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittMM = sum(ModelOutput.indivMets(:,basisSet.nMets+1:end),2); + if ~isnan(ModelOutput.completeFit(1)) %If the fit was succesfull + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fit = ModelOutput.completeFit; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.baseline = ModelOutput.baseline; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.ppm = ModelOutput.ppm; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.res = ModelOutput.residual; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.data = ModelOutput.data; + if strcmp(FitSpecNames{ss}, 'mm') %re_mm loop over basis functions + for n = 1 : (basisSet.nMets + basisSet.nMM) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.(['fit' basisSet.name{n}]) = ModelOutput.indivMets(:,n); + end + % tMM = all MM functions + if basisSet.nMM > 0 + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittMM = sum(ModelOutput.indivMets(:,basisSet.nMets+1:end),2); + else + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittMM =nan; + end + %section to write out MM_clean spectra + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.MM_clean = ModelOutput.data -sum(ModelOutput.indivMets(:,1:basisSet.nMets),2); + else%re_mm + for n = 1 : size(ModelOutput.indivMets,2) % loop over basis functions + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.(['fit' basisSet.name{n}]) = ModelOutput.indivMets(:,n); + end + % Add basis functions of metabolite combinations + % tNAA = NAA + NAAG + idx_NAA = find(strcmp(basisSet.name,'NAA')); + idx_NAAG = find(strcmp(basisSet.name,'NAAG')); + if isempty(idx_NAA) && isempty(idx_NAAG) + % do nothing + elseif isempty(idx_NAA) && ~isempty(idx_NAAG) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittNAA = ModelOutput.indivMets(:,idx_NAAG); + elseif ~isempty(idx_NAA) && isempty(idx_NAAG) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittNAA = ModelOutput.indivMets(:,idx_NAA); + elseif ~isempty(idx_NAA) && ~isempty(idx_NAAG) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittNAA = ModelOutput.indivMets(:,idx_NAA) + ModelOutput.indivMets(:,idx_NAAG); + end + + + % tCr = Cr + tCr - CrCH2 + idx_Cr = find(strcmp(basisSet.name,'Cr')); + idx_PCr = find(strcmp(basisSet.name,'PCr')); + if isempty(idx_Cr) && isempty(idx_PCr) + % do nothing + elseif isempty(idx_Cr) && ~isempty(idx_PCr) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCr = ModelOutput.indivMets(:,idx_PCr); + elseif ~isempty(idx_Cr) && isempty(idx_PCr) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCr = ModelOutput.indivMets(:,idx_Cr); + elseif ~isempty(idx_Cr) && ~isempty(idx_PCr) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCr = ModelOutput.indivMets(:,idx_Cr) + ModelOutput.indivMets(:,idx_PCr); + end + + % if present, add CrCH2 model + idx_CrCH2 = find(strcmp(basisSet.name,'CrCH2')); + if ~isempty(idx_CrCH2) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCr = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCr + ModelOutput.indivMets(:,idx_CrCH2); + else + % do nothing + end + + % tCho = GPC + PCh + idx_GPC = find(strcmp(basisSet.name,'GPC')); + idx_PCh = find(strcmp(basisSet.name,'PCh')); + if isempty(idx_GPC) && isempty(idx_PCh) + % do nothing + elseif isempty(idx_GPC) && ~isempty(idx_PCh) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCho = ModelOutput.indivMets(:,idx_PCh); + elseif ~isempty(idx_GPC) && isempty(idx_PCh) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCho = ModelOutput.indivMets(:,idx_GPC); + elseif ~isempty(idx_GPC) && ~isempty(idx_PCh) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCho = ModelOutput.indivMets(:,idx_GPC) + ModelOutput.indivMets(:,idx_PCh); + end + + % Glx = Glu + Gln + idx_Glu = find(strcmp(basisSet.name,'Glu')); + idx_Gln = find(strcmp(basisSet.name,'Gln')); + if isempty(idx_Glu) && isempty(idx_Gln) + % do nothing + elseif isempty(idx_Glu) && ~isempty(idx_Gln) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fitGlx = ModelOutput.indivMets(:,idx_Gln); + elseif ~isempty(idx_Glu) && isempty(idx_Gln) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fitGlx = ModelOutput.indivMets(:,idx_Glu); + elseif ~isempty(idx_Glu) && ~isempty(idx_Gln) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fitGlx = ModelOutput.indivMets(:,idx_Glu) + ModelOutput.indivMets(:,idx_Gln); + end + + % tEA = PE + EA + idx_PE = find(strcmp(basisSet.name,'PE')); + idx_EA = find(strcmp(basisSet.name,'EA')); + if isempty(idx_PE) && isempty(idx_Gln) + % do nothing + elseif isempty(idx_PE) && ~isempty(idx_EA) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittEA = ModelOutput.indivMets(:,idx_EA); + elseif ~isempty(idx_PE) && isempty(idx_EA) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittEA = ModelOutput.indivMets(:,idx_PE); + elseif ~isempty(idx_PE) && ~isempty(idx_EA) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittEA = ModelOutput.indivMets(:,idx_PE) + ModelOutput.indivMets(:,idx_EA); + end + + % tMM = all MM functions + if MRSCont.opts.fit.fitMM == 1 + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittMM = sum(ModelOutput.indivMets(:,basisSet.nMets+1:end),2); + else + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittMM =nan; + end + end %re_mm + else %if the fit was not succesful write nans into the corresponding fields + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fit = nan; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.baseline = nan; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.ppm = nan; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.res = nan; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittNAA = nan; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittCr = nan; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.data = nan; end - end %re_mm - else %if the fit was not succesful write nans into the corresponding fields - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittNAA = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittCr = nan; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = nan; + end + case 'LCModel' + if (MRSCont.flags.isPRIAM == 1) + fitParams = MRSCont.fit.results{rr}.(FitSpecNames{ss}).fitParams{bf,kk,sf}; + else + fitParams = MRSCont.fit.results.(FitSpecNames{ss}).fitParams{bf,kk,sf}; + end + % Get the LCModel plots we previously extracted from .coord + % etc. + [ModelOutput] = fit_LCModelParamsToModel(fitParams); + + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fit = ModelOutput.completeFit; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.baseline = ModelOutput.baseline; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.ppm = ModelOutput.ppm'; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.res = ModelOutput.residual; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.data = ModelOutput.data; + for n = 1 : size(ModelOutput.indivMets,2) % loop over basis functions + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.(['fit' fitParams.name{n}]) = ModelOutput.indivMets(:,n); + end + % tMM = all MM functions + if MRSCont.opts.fit.fitMM == 1 + %Find all MM or Lip functions that are not + %combined + idx_tMM = horzcat(find(contains(fitParams.name,'MM')), find(contains(fitParams.name,'Lip'))); + if ~isempty(idx_tMM) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittMM = sum(ModelOutput.indivMets(:,idx_tMM),2); + else + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittMM =nan; + end + else + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(FitSpecNames{ss}){bf,kk,sf}.fittMM =nan; + end end end - case 'LCModel' - if (MRSCont.flags.isPRIAM == 1) - fitParams = MRSCont.fit.results{rr}.(FitNames{sf}).fitParams{kk}; - else - fitParams = MRSCont.fit.results.(FitNames{sf}).fitParams{kk}; - end - % Get the LCModel plots we previously extracted from .coord - % etc. - [ModelOutput] = fit_LCModelParamsToModel(fitParams); - - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = ModelOutput.completeFit; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline = ModelOutput.baseline; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = ModelOutput.ppm'; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = ModelOutput.residual; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = ModelOutput.data; - for n = 1 : size(ModelOutput.indivMets,2) % loop over basis functions - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(['fit' fitParams.name{n}]) = ModelOutput.indivMets(:,n); - end - % tMM = all MM functions - if MRSCont.opts.fit.fitMM == 1 - %Find all MM or Lip functions that are not - %combined - idx_tMM = horzcat(find(contains(fitParams.name,'MM')), find(contains(fitParams.name,'Lip'))); - if ~isempty(idx_tMM) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fittMM = sum(ModelOutput.indivMets(:,idx_tMM),2); - end - end end end end + end end fprintf('\n... done.\n'); if MRSCont.flags.isGUI && isfield(progressText,'String') @@ -633,92 +417,63 @@ pause(1); end + ModelCombs = fieldnames(MRSCont.overview.Osprey.all_models_voxel_1); + NoModelCombs = length(ModelCombs); for rr = 1 : Voxels - for sf = 1 : NoFit - for kk = 1 : MRSCont.nDatasets - temp_fit_sz.([FitNames{sf} '_' dataPlotNames{sf}])(1,kk)= length(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit); + for sc = 1 : NoModelCombs % Loop over all model combinations + for sf = 1 : size(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}),3) + for bf = 1 : size(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}),1) for bf = 1 : size(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}),1) + if isstruct(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}) + for kk = 1 : MRSCont.nDatasets + temp_fit_sz.(ModelCombs{sc})(bf,kk,sf)= length(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.fit); + end + end + end + end end - [max_point_fit.([FitNames{sf} '_' dataPlotNames{sf}]),max_ind_fit.([FitNames{sf} '_' dataPlotNames{sf}])] = max(temp_fit_sz.([FitNames{sf} '_' dataPlotNames{sf}])); + [max_point_fit.(ModelCombs{sc}),max_ind_fit.(ModelCombs{sc})] = max(temp_fit_sz.(ModelCombs{sc})(1,:,1)); end end %Interpolating models if needed to allow the calculation of mean and SD %models - fprintf('Interpolating fit models from fit %d out of %d total fits...', 1, NoFit); + fprintf('Interpolating fit models from fit %d out of %d total fits...', 1, NoModelCombs); for rr = 1 : Voxels - for sf = 1 : NoFit % loop over all fits - msg = sprintf('Interpolating fit models from fit %d out of %d total fits...', sf, NoFit); - reverseStr = repmat(sprintf('\b'), 1, length(msg)); - fprintf([reverseStr, msg]); - if MRSCont.flags.isGUI && isfield(progressText,'String') - set(progressText,'String' ,sprintf('Interpolating fit models from fit %d out of %d total fits...\n', sf, NoFit)); - drawnow - end - for kk = 1 : MRSCont.nDatasets %loop over all datasets - if length(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit) < max_point_fit.([FitNames{sf} '_' dataPlotNames{sf}]) - ppmRangeData = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,max_ind_fit.([FitNames{sf} '_' dataPlotNames{sf}])}.ppm'; - ppmRangeDataToInt = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm; - ppmIsInDataRange = (ppmRangeDataToInt < ppmRangeData(1)) & (ppmRangeDataToInt > ppmRangeData(end)); - if sum(ppmIsInDataRange) == 0 - ppmIsInDataRange = (ppmRangeDataToInt > ppmRangeData(1)) & (ppmRangeDataToInt < ppmRangeData(end)); - end - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); - if ~(strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'ref_ref') || strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'w_w')) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); - names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}); - for f = 6 : length(names) - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(names{f})= interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(names{f})(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); - end - end - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = ppmRangeData'; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data-MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit; - end - end - end - end + for sc = 1 : NoModelCombs % Loop over all model combinations + for sf = 1 : size(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}),3) + for bf = 1 : size(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}),1) + + msg = sprintf('Interpolating fit models from fit %d out of %d total fits...', sc, NoModelCombs); + reverseStr = repmat(sprintf('\b'), 1, length(msg)); + fprintf([reverseStr, msg]); + if MRSCont.flags.isGUI && isfield(progressText,'String') + set(progressText,'String' ,sprintf('Interpolating fit models from fit %d out of %d total fits...\n', sc, NoModelCombs)); + drawnow + end - % Align the spectra according to the NAA peak - for rr = 1 : Voxels - for sf = 1 : NoFit % loop over all fits - if ~strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'ref_ref') || strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'w_w') - for kk = 1 : MRSCont.nDatasets % loop over all data sets - naa = 1; - %Find the ppm of the maximum peak magnitude within the given range: - if MRSCont.flags.isUnEdited - ppmindex=find(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<2.1); - end - if MRSCont.flags.isMEGA - if isfield(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]), 'conc_diff1') - ppmindex=find(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm<2.1); - else - ppmindex=find(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<2.1); - end - if isempty(ppmindex) - ppmindex=find(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>2.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<3.1)==max(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>2.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<3.1))); - ppmrange=MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>2.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<3.1); - naa = 0; - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - if isfield(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]), 'conc_diff1') - ppmindex=find(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.ppm<2.1); - else - ppmindex=find(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.ppm<2.1)==max(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.ppm<2.1))); - ppmrange=MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.ppm(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.ppm>1.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.ppm<2.1); + for kk = 1 : MRSCont.nDatasets %loop over all datasets + if isstruct(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}) + if length(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.fit) < max_point_fit.(ModelCombs{sc}) + ppmRangeData = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){1,max_ind_fit.(ModelCombs{1})}.ppm'; + ppmRangeDataToInt = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.ppm; + ppmIsInDataRange = (ppmRangeDataToInt < ppmRangeData(1)) & (ppmRangeDataToInt > ppmRangeData(end)); + if sum(ppmIsInDataRange) == 0 + ppmIsInDataRange = (ppmRangeDataToInt > ppmRangeData(1)) & (ppmRangeDataToInt < ppmRangeData(end)); + end + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.fit = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.fit(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.data = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.data(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); + if ~(strcmp(ModelCombs{sc}, 'ref') || strcmp(ModelCombs{sc}, 'w')) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.baseline = interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.baseline(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); + names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}); + for f = 6 : length(names) + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.(names{f})= interp1(ppmRangeDataToInt(ppmIsInDataRange), MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.(names{f})(ppmIsInDataRange), ppmRangeData, 'pchip', 'extrap'); + end + end + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.ppm = ppmRangeData'; + MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.res = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.data-MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc}){bf,kk,sf}.fit; + end end - end - ppmmax=ppmrange(ppmindex); - if naa == 1 - MRSCont.overview.Osprey.refShift(kk)=(ppmmax-2.013); %ref shift value - else - MRSCont.overview.Osprey.refShift(kk)=(ppmmax-3.03); %ref shift value end - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.ppm - MRSCont.overview.Osprey.refShift(kk); end end end @@ -734,219 +489,33 @@ %%% 3. SCALING DATA %%% %Normalizing the data according to the scale value of the fit and normalize %the models according to the tCr/tNAA amplitudes -fprintf('\nScaling data from dataset %d out of %d total datasets...', 1, MRSCont.nDatasets); -if MRSCont.flags.didFit - for rr = 1 : Voxels - for kk = 1 : MRSCont.nDatasets - if Voxels < 2 - scale = MRSCont.fit.scale{kk}; - else - scale = MRSCont.fit.scale{kk}; - end - msg = sprintf('Scaling data from dataset %d out of %d total datasets...', kk, MRSCont.nDatasets); - reverseStr = repmat(sprintf('\b'), 1, length(msg)); - fprintf([reverseStr, msg]); - if MRSCont.flags.isGUI && isfield(progressText,'String') - set(progressText,'String' ,sprintf('Scaling data from dataset %d out of %d total datasets...\n', kk, MRSCont.nDatasets)); - drawnow - end - if isfield(MRSCont, 'quantify') - if MRSCont.flags.isUnEdited - if MRSCont.flags.hasMM %re_mm - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).mm{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).mm{1,kk}.specs/scale; %re_mm - names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).mm_mm{1,kk}); - for f = 1 : length(names) - if ~strcmp(names{f},'ppm') - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).mm_mm{1,kk}.(names{f})= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).mm_mm{1,kk}.(names{f})/(MRSCont.fit.results.off.fitParams{1,kk}.ampl(idx_PCr)+ MRSCont.fit.results.off.fitParams{1,kk}.ampl(idx_Cr)); - end - end - end %re_mm - if MRSCont.flags.hasRef && ~strcmp(MRSCont.opts.fit.method, 'LCModel') - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit; - end - if MRSCont.flags.hasWater && ~strcmp(MRSCont.opts.fit.method, 'LCModel') - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit; - end - names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}); - for f = 1 : length(names) - if ~strcmp(names{f},'ppm') - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.(names{f})= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.(names{f}); - end - end - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - end - - if MRSCont.flags.isMEGA - if isfield(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]), 'conc_diff1') - names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}); - for f = 1 : length(names) - if ~strcmp(names{f},'ppm') - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.(names{f})= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.(names{f}); - end - end - names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}); - for f = 1 : length(names) - if ~strcmp(names{f},'ppm') - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.(names{f})= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.(names{f}); - end - end - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs/scale; - if MRSCont.flags.hasRef - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit; - end - if MRSCont.flags.hasWater - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit; - end - else - names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}); - for f = 1 : length(names) - if ~strcmp(names{f},'ppm') - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.(names{f})= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.(names{f}); - end - end - names = fields(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}); - for f = 1 : length(names) - if ~strcmp(names{f},'ppm') - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.(names{f})= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.(names{f}); - end - end - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs/scale; - if MRSCont.flags.hasRef && ~strcmp(MRSCont.opts.fit.method, 'LCModel') - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit; - end - if MRSCont.flags.hasWater && ~strcmp(MRSCont.opts.fit.method, 'LCModel') - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit; - end - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).C{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).C{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).D{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).D{1,kk}.specs/scale; - if isfield(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]), 'conc_diff1') - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.fit= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.fit/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.fit= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.fit/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.fit= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.fit/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.baseline= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.baseline/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.baseline= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.baseline/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.baseline= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.baseline/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.res= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.res/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.res= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.res/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.res= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.res/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.data= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff1{1,kk}.data/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.data= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_diff2{1,kk}.data/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.data= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).conc_sum{1,kk}.data/scale; - else - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.fit= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.fit/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.fit= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.fit/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.fit= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.fit/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.baseline= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.baseline/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.baseline= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.baseline/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.baseline= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.baseline/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.data= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.data/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.data= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.data/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.data= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.data/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.res= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff1_diff1{1,kk}.res/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.res= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).diff2_diff2{1,kk}.res/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.res= MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).sum_sum{1,kk}.res/scale; - end - if MRSCont.flags.hasRef && ~strcmp(MRSCont.opts.fit.method, 'LCModel') - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).ref_ref{1,kk}.fit/scale; - end - if MRSCont.flags.hasWater && ~strcmp(MRSCont.opts.fit.method, 'LCModel') - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).w_w{1,kk}.fit/scale; - end - end - - else - error('This script works only on fully processed data. Run the whole Osprey pipeline first. Seg/Coreg is not needed') - end - end - end -else +fprintf('\nScaling data from dataset %d out of %d total datasets...', 1, MRSCont.nDatasets(1)); +if ~MRSCont.flags.didFit [MRSCont] = osp_fitInitialise(MRSCont); - for rr = 1 : Voxels +end + +for rr = 1 : Voxels + for ss = 1 : NoSpec % Loop over Subspec for kk = 1 : MRSCont.nDatasets if Voxels < 2 scale = MRSCont.fit.scale{kk}; else - scale = MRSCont.fit.scale{kk}; + scale = MRSCont.fit.scale{kk}; end - msg = sprintf('Scaling data from dataset %d out of %d total datasets...', kk, MRSCont.nDatasets); + msg = sprintf('Scaling data from dataset %d out of %d total datasets...', kk, MRSCont.nDatasets(1)); reverseStr = repmat(sprintf('\b'), 1, length(msg)); fprintf([reverseStr, msg]); if MRSCont.flags.isGUI && isfield(progressText,'String') - set(progressText,'String' ,sprintf('Scaling data from dataset %d out of %d total datasets...\n', kk, MRSCont.nDatasets)); + set(progressText,'String' ,sprintf('Scaling data from dataset %d out of %d total datasets...\n', kk, MRSCont.nDatasets(1))); drawnow end - if MRSCont.flags.isUnEdited - if MRSCont.flags.hasMM %re_mm - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).mm{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).mm{1,kk}.specs/scale; %re_mm - end %re_mm - if MRSCont.flags.hasRef - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - end - if MRSCont.flags.hasWater - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - end - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - end - - if MRSCont.flags.isMEGA - if isfield(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]), 'conc_diff1') - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs/scale; - if MRSCont.flags.hasRef - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - end - if MRSCont.flags.hasWater - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - end - else - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).diff1{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).sum{1,kk}.specs/scale; - if MRSCont.flags.hasRef - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - end - if MRSCont.flags.hasWater - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - end - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).A{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).B{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).C{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).C{1,kk}.specs/scale; - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).D{1,kk}.specs= MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).D{1,kk}.specs/scale; - if MRSCont.flags.hasRef - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).ref{1,kk}.specs/scale; - end - if MRSCont.flags.hasWater - MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).w{1,kk}.specs/scale; - end + if ~((strcmp(dataPlotNames{ss},'ref')||strcmp(dataPlotNames{ss},'mm_ref')||strcmp(dataPlotNames{ss},'w')) && strcmp(MRSCont.opts.fit.method, 'LCModel')) + MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){kk}.specs = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){kk}.specs/scale; end end end end +fprintf('\n... done.\n'); if MRSCont.flags.isGUI && isfield(progressText,'String') set(progressText,'String' ,sprintf('... done.')); pause(1); @@ -960,9 +529,15 @@ % to allow an easier identification. SepFileList = cell(1,length(MRSCont.files)); % Get all files -for i = 1 : MRSCont.nDatasets - SepFileList{i} = split(MRSCont.files{i}, filesep); - subject{i} = [SepFileList{i}{end-1}]; % Create subject name list +for kk = 1 : MRSCont.nDatasets(1) + SepFileList{kk} = split(MRSCont.files{kk}, filesep); + ind = find(contains(lower(SepFileList{kk}),'sub')); + if ~isempty(ind) + subject{kk} = [SepFileList{kk}{ind(1)}]; % Create subject name list + else + subject{kk} = ['sub_' num2str(kk)]; + end + end if MRSCont.flags.hasStatfile % Has stat file @@ -970,10 +545,10 @@ name = statFile.Properties.VariableNames; group_idx = find(strcmp(name,'group')); if isempty(group_idx) % No group supplied so create grand mean only - MRSCont.overview.groups = ones(MRSCont.nDatasets,1); + MRSCont.overview.groups = ones(size(MRSCont.nDatasets,1),1); MRSCont.overview.NoGroups = max(MRSCont.overview.groups); else %Get grouping variable - MRSCont.overview.groups = statFile{:,group_idx}; + MRSCont.overview.groups = statFile{:,group_idx}; MRSCont.overview.NoGroups = max(MRSCont.overview.groups); end if ~strcmp(name,'subject') % No subject names stored in the container @@ -989,7 +564,7 @@ end else % No csv file supplied - MRSCont.overview.groups = ones(MRSCont.nDatasets,1); %Create a single group + MRSCont.overview.groups = ones(MRSCont.nDatasets(1),1); %Create a single group MRSCont.overview.NoGroups = max(MRSCont.overview.groups); statFile = array2table(MRSCont.overview.groups,'VariableNames',{'group'}); if length(subject)>1 && ~strcmp(subject{1},subject{2}) %Add names to the csv file @@ -1036,7 +611,7 @@ [~,idx] = find(MRSCont.overview.groups==kk); if isempty(idx) && kk < max_g for ll = 1 : length(MRSCont.overview.groups) - if MRSCont.overview.groups(ll) > kk + if MRSCont.overview.groups(ll) > kk MRSCont.overview.groups(ll) = MRSCont.overview.groups(ll) -1; if remove == 0 max_g = max_g -1; @@ -1058,22 +633,22 @@ % Sort the spectra according to the groups for rr = 1 : Voxels - for ss = 1 : NoSubSpec % Loop over subspectra + for ss = 1 : NoSpec % Loop over subspectra for g = 1 : MRSCont.overview.NoGroups % loop over groups - MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(['g_' num2str(g)]).(SubSpecNames{ss}) = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss})(1,MRSCont.overview.groups == g); + MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(['g_' num2str(g)]).(dataPlotNames{ss}) = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss})(1,MRSCont.overview.groups == g); end - MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).GMean.(SubSpecNames{ss}) = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss})(1,MRSCont.overview.groups > 0); + MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).GMean.(dataPlotNames{ss}) = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss})(1,MRSCont.overview.groups > 0); end end if MRSCont.flags.didFit for rr = 1 : Voxels % Sort the models according to the groups - for sf = 1 : NoFit % loop over fits + for sc = 1 : NoModelCombs % Loop over all model combinations for g = 1 : MRSCont.overview.NoGroups % loop over groups - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(['g_' num2str(g)]).([FitNames{sf} '_' dataPlotNames{sf}]) = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}])(1,MRSCont.overview.groups == g); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(['g_' num2str(g)]).(ModelCombs{sc}) = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc})(:,MRSCont.overview.groups == g,:); end - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).GMean.([FitNames{sf} '_' dataPlotNames{sf}]) = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).([FitNames{sf} '_' dataPlotNames{sf}])(1,MRSCont.overview.groups > 0); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).GMean.(ModelCombs{sc}) = MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).(ModelCombs{sc})(:,MRSCont.overview.groups > 0,:); end end end @@ -1086,7 +661,7 @@ end for cor = 1 : length(name) MRSCont.overview.corr.Meas{cor} = statFile{:,cor}; - if isfield(MRSCont, 'exclude') % Exclude measures + if isfield(MRSCont, 'exclude') % Exclude measures if~isempty(MRSCont.exclude) MRSCont.overview.corr.Meas{cor}(MRSCont.exclude) = []; end @@ -1099,130 +674,79 @@ %Start with the spectra for rr = 1 : Voxels - for ss = 1 : NoSubSpec %loop over subspectra + for ss = 1 : NoSpec %loop over subspectra names = fields(MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)])); for g = 1 : length(names) % loop over groups - tempSubSpec = zeros(length(MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(SubSpecNames{ss})),MRSCont.info.(SubSpecNames{ss}).max_ndatapoint); - for kk = 1 : length(MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(SubSpecNames{ss})) % Loop over datasets to generate a matrix + tempSubSpec = zeros(length(MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(dataPlotNames{ss})),MRSCont.info.(dataPlotNames{ss}).max_ndatapoint,MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(dataPlotNames{ss}){1, 1}.subspecs); + for kk = 1 : length(MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(dataPlotNames{ss})) % Loop over datasets to generate a matrix try - tempSubSpec(kk,:) = MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(SubSpecNames{ss}){1,kk}.specs; + tempSubSpec(kk,:,:) = MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(dataPlotNames{ss}){1,kk}.specs; catch - tempSubSpec(kk,:) = ones(1,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{1}){1,1}.sz(1)) *nan; + tempSubSpec(kk,:,:) = ones(1,MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{1}){1,1}.sz(1)) *nan; end end %Calculate mean and SD - MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(['mean_' SubSpecNames{ss}]) = nanmean(real(tempSubSpec),1); - MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(['sd_' SubSpecNames{ss}]) = nanstd(real(tempSubSpec),1); + MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(['mean_' dataPlotNames{ss}]) = squeeze(nanmean(real(tempSubSpec),1)); + MRSCont.overview.Osprey.(['sort_data_voxel_' num2str(rr)]).(names{g}).(['sd_' dataPlotNames{ss}]) = squeeze(nanstd(real(tempSubSpec),1)); end %Store ppm - MRSCont.overview.Osprey.(['ppm_data_' SubSpecNames{ss}]) = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(SubSpecNames{ss}){MRSCont.info.(SubSpecNames{ss}).max_ndatapoint_ind}.ppm; + MRSCont.overview.Osprey.(['ppm_data_' dataPlotNames{ss}]) = MRSCont.overview.Osprey.(['all_data_voxel_' num2str(rr)]).(dataPlotNames{ss}){MRSCont.info.(dataPlotNames{ss}).max_ndatapoint_ind}.ppm; end end if MRSCont.flags.didFit - %Do the same for the models + %Do the same for the models for rr = 1 : Voxels - for sf = 1 : NoFit %loop over fits - names = fields(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)])); + for sc = 1 : NoModelCombs % Loop over all model combinations + names = fields(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)])); for g = 1 : length(names) %Loop over groups - tempSubSpec = zeros(length(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}])),length(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1}.ppm)); - tempSubRes = tempSubSpec; - tempSubdata = tempSubSpec; - tempSubBaseline = tempSubSpec; - tempInidivMetab = []; - for kk = 1 : length(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}])) % Loop over datasets to generate a matrices - tempSubSpec(kk,:) = MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.fit; %Fits - tempSubRes(kk,:) = MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.res; % Residuals - tempSubdata(kk,:) = MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.data; % spectra - if ~(strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'ref_ref') || strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'w_w')) %Is not water - tempSubBaseline(kk,:) = MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.baseline; % Baseline - fits = fields(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}); % names of the basis functions - for f = 6 : length(fits) % loop over basis functions - tempInidivMetab.(fits{f})(kk,:)= MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1,kk}.(fits{f}); - end - end - end - %Calculate mean and SD - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['mean_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanmean(real(tempSubSpec),1); - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['sd_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanstd(real(tempSubSpec),1); - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['mean_res_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanmean(real(tempSubRes),1); - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['sd_res_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanstd(real(tempSubRes),1); - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['mean_data_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanmean(real(tempSubdata),1); - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['sd_data_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanstd(real(tempSubdata),1); - - if ~(strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'ref_ref') || strcmp([FitNames{sf} '_' dataPlotNames{sf}], 'w_w')) %Is not water - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['mean_baseline_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanmean(real(tempSubBaseline),1); - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['sd_baseline_' [FitNames{sf} '_' dataPlotNames{sf}]]) = nanstd(real(tempSubBaseline),1); - for f = 6 : length(fits) % loop over basis functions - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['mean_' fits{f} '_' FitNames{sf} '_' dataPlotNames{sf}]) = nanmean(real(tempInidivMetab.(fits{f})),1); - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['sd_' fits{f} '_' FitNames{sf} '_' dataPlotNames{sf}]) = nanstd(real(tempInidivMetab.(fits{f})),1); - end - end - - %Store ppm - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]]) = MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).([FitNames{sf} '_' dataPlotNames{sf}]){1,1}.ppm; - end - end - end - - %Make sure the means are aligned - for rr = 1 : Voxels - for sf = 1 : NoFit %Loop over fits - names = fields(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)])); - for g = 1 : length(names) %loop over groups - if MRSCont.flags.isUnEdited - if strcmp(FitNames{sf}, 'off') - %Find the ppm of the maximum peak magnitude within the given range: - ppmindex=find(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['mean_data_' [FitNames{sf} '_' dataPlotNames{sf}]])(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]])>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]])<2.1)==max(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['mean_data_' [FitNames{sf} '_' dataPlotNames{sf}]])(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]])>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]])<2.1))); - ppmrange=MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]])(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]])>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]])<2.1); - ppmmax=ppmrange(ppmindex); - refShift=(ppmmax-2.013); - else - refShift = 0; - end - end - if MRSCont.flags.isMEGA - if isfield(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]), 'conc_diff1') - ppmindex=find(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_conc_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum<2.1)==max(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_conc_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum<2.1))); - ppmrange=MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum<2.1); - ppmmax=ppmrange(ppmindex); - refShift=(ppmmax-2.013); - else - naa = 1; - ppmindex=find(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_off_A(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_off_A>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_off_A<2.1)==max(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_off_A(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_off_A>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_off_A<2.1))); - ppmrange=MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_off_A(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_off_A>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_off_A<2.1); - if isempty(ppmindex) - ppmindex=find(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>2.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<3.1)==max(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.data(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>2.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<3.1))); - ppmrange=MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm>2.9 & MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]).off_A{1,kk}.ppm<3.1); - naa = 0; - end - ppmmax=ppmrange(ppmindex); - if length(ppmmax) > 1 - refShift = 0; - else if naa == 1 - refShift=(ppmmax-2.013); - else - refShift=(ppmmax-3.02); - + for sf = 1 : size(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}),3) + for bf = 1 : size(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}),1) + if isstruct(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,1,sf}) + tempSubSpec = zeros(size(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}),2),length(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,1,sf}.ppm)); + tempSubRes = tempSubSpec; + tempSubdata = tempSubSpec; + tempSubBaseline = tempSubSpec; + tempInidivMetab = []; + for kk = 1 : size(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}),2) % Loop over datasets to generate a matrices + tempSubSpec(kk,:) = MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,kk,sf}.fit; %Fits + tempSubRes(kk,:) = MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,kk,sf}.res; % Residuals + tempSubdata(kk,:) = MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,kk,sf}.data; % spectra + if ~(strcmp(ModelCombs{sc}, 'ref') || strcmp(ModelCombs{sc}, 'w')) %Is not water + tempSubBaseline(kk,:) = MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,kk,sf}.baseline; % Baseline + fits = fields(MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,kk,sf}); % names of the basis functions + for f = 6 : length(fits) % loop over basis functions + tempInidivMetab.(fits{f})(kk,:)= MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,kk,sf}.(fits{f}); + end + end end + %Calculate mean and SD + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['mean_fit_' ModelCombs{sc}])(bf,:,sf) = nanmean(real(tempSubSpec),1); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['sd_fit_' ModelCombs{sc}])(bf,:,sf) = nanstd(real(tempSubSpec),1); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['mean_res_' ModelCombs{sc}])(bf,:,sf) = nanmean(real(tempSubRes),1); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['sd_res_' ModelCombs{sc}])(bf,:,sf) = nanstd(real(tempSubRes),1); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['mean_data_' ModelCombs{sc}])(bf,:,sf) = nanmean(real(tempSubdata),1); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['sd_data_' ModelCombs{sc}])(bf,:,sf) = nanstd(real(tempSubdata),1); + + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['fit_' ModelCombs{sc}])(1:size(tempSubSpec,1),:,bf,sf) = real(tempSubSpec); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['res_' ModelCombs{sc}])(1:size(tempSubSpec,1),:,bf,sf) = real(tempSubRes); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['data_' ModelCombs{sc}])(1:size(tempSubSpec,1),:,bf,sf) = real(tempSubdata); + + if ~(strcmp(ModelCombs{sc}, 'ref') || strcmp(ModelCombs{sc}, 'w')) %Is not water + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['mean_baseline_' ModelCombs{sc}])(bf,:,sf) = nanmean(real(tempSubBaseline),1); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['sd_baseline_' ModelCombs{sc}])(bf,:,sf) = nanstd(real(tempSubBaseline),1); + for f = 6 : length(fits) % loop over basis functions + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['mean_' fits{f} '_' ModelCombs{sc}])(bf,:,sf) = nanmean(real(tempInidivMetab.(fits{f})),1); + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['sd_' fits{f} '_' ModelCombs{sc}])(bf,:,sf) = nanstd(real(tempInidivMetab.(fits{f})),1); + end end - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - if isfield(MRSCont.overview.Osprey.(['all_models_voxel_' num2str(rr)]), 'conc_diff1') - ppmindex=find(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_conc_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum<2.1)==max(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_conc_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum<2.1))); - ppmrange=MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_conc_sum<2.1); - ppmmax=ppmrange(ppmindex); - refShift=(ppmmax-2.013); - else - ppmindex=find(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_sum_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_sum_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_sum_sum<2.1)==max(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).mean_data_sum_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_sum_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_sum_sum<2.1))); - ppmrange=MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_sum_sum(MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_sum_sum>1.9 & MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).ppm_fit_sum_sum<2.1); - ppmmax=ppmrange(ppmindex); - refShift=(ppmmax-2.013); - end + + %Store ppm + MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' ModelCombs{sc}])(bf,:,sf) = MRSCont.overview.Osprey.(['sort_models_voxel_' num2str(rr)]).(names{g}).(ModelCombs{sc}){bf,1,sf}.ppm; end - MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]]) = MRSCont.overview.Osprey.(['sort_fit_voxel_' num2str(rr)]).(names{g}).(['ppm_fit_' [FitNames{sf} '_' dataPlotNames{sf}]]) - refShift; + end end + end end end end @@ -1276,7 +800,7 @@ end % Create the MRSinMRS markdown -if MRSCont.flags.didFit && MRSCont.flags.didQuantify && ~MRSCont.flags.isPRIAM +if MRSCont.flags.didFit && MRSCont.flags.didQuantify [MRSCont] = OspreyMinReport(MRSCont); end diff --git a/plot/osp_plotAllPDF.m b/plot/osp_plotAllPDF.m index 9f4de6a8..c1e082e6 100644 --- a/plot/osp_plotAllPDF.m +++ b/plot/osp_plotAllPDF.m @@ -33,117 +33,137 @@ function osp_plotAllPDF(MRSCont, Module) if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI switch Module case 'OspreyLoad' - for kk = 1 : MRSCont.nDatasets - osp_plotModule(MRSCont, 'OspreyLoad', kk, 'mets'); + for kk = 1 : MRSCont.nDatasets(1) + osp_plotModule(MRSCont, 'OspreyLoad', kk,[1 1], 'metabolites'); if MRSCont.flags.hasRef - osp_plotModule(MRSCont, 'OspreyLoad', kk, 'ref'); + osp_plotModule(MRSCont, 'OspreyLoad', kk,[1 1], 'ref'); end if MRSCont.flags.hasWater - osp_plotModule(MRSCont, 'OspreyLoad', kk, 'w'); + osp_plotModule(MRSCont, 'OspreyLoad', kk,[1 1], 'w'); end if MRSCont.flags.hasMM - osp_plotModule(MRSCont, 'OspreyLoad', kk, 'mm'); + osp_plotModule(MRSCont, 'OspreyLoad', kk,[1 1], 'MM'); end end case 'OspreyProcess' Names = fieldnames(MRSCont.processed); - for kk = 1 : MRSCont.nDatasets - for ss = 1 : length(Names) - osp_plotModule(MRSCont, 'OspreyProcess', kk, Names{ss}); - end - end - case 'OspreyFit' - if strcmp(MRSCont.opts.fit.style, 'Concatenated') - temp = fieldnames(MRSCont.fit.results); - if MRSCont.flags.isUnEdited - Names = fieldnames(MRSCont.fit.results); - end - if MRSCont.flags.isMEGA - Names = {'diff1','sum'}; - if length(temp) == 2 - Names{3} = temp{2}; - else if length(temp) == 3 - Names{3} = temp{2}; - Names{4} = temp{3}; + for kk = 1 : MRSCont.nDatasets(1) + for mm = 1 : length(Names) + for ss = 1 : length(MRSCont.processed.(Names{mm}){kk}.names) + if (~contains(MRSCont.processed.(Names{mm}){kk}.names{ss},'spline')) && (~contains(MRSCont.processed.(Names{mm}){kk}.names{ss},'clean')) + osp_plotModule(MRSCont, 'OspreyProcess', kk,[1 ss], Names{mm}); end end end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - Names = {'diff1','diff2','sum'}; - if length(temp) == 2 - Names{4} = temp{2}; - else if length(temp) == 3 - Names{4} = temp{2}; - Names{5} = temp{3}; + end + case 'OspreyFit' + Names = {'metab'}; + if MRSCont.flags.hasMM + Names{end+1} = 'mm'; + end + if MRSCont.flags.hasRef + Names{end+1} = 'ref'; + end + if MRSCont.flags.hasWater + Names{end+1} = 'w'; + end + + for kk = 1 : MRSCont.nDatasets(1) + for mm = 1 : length(Names) + if isfield(MRSCont.fit.results,Names{mm}) + for bb = 1 : size(MRSCont.fit.results.(Names{mm}).fitParams,1) + for ss = 1 : size(MRSCont.fit.results.(Names{mm}).fitParams,3) + osp_plotModule(MRSCont, 'OspreyFit', kk,[bb ss], Names{mm}); + end end end end - else - Names = fieldnames(MRSCont.fit.results); - end - for kk = 1 : MRSCont.nDatasets - for ss = 1 : length(Names) - osp_plotModule(MRSCont, 'OspreyFit', kk, Names{ss}); - end end case 'OspreyCoreg' - for kk = 1 : MRSCont.nDatasets + for kk = 1 : MRSCont.nDatasets(1) osp_plotModule(MRSCont, 'OspreyCoreg', kk); end case 'OspreySeg' - for kk = 1 : MRSCont.nDatasets + for kk = 1 : MRSCont.nDatasets(1) osp_plotModule(MRSCont, 'OspreySeg', kk); end case 'OspreyOverview' - Names = fieldnames(MRSCont.processed); + SubNames = fieldnames(MRSCont.overview.SubSpecNamesStruct); + k=1; + if ~isempty(SubNames) + for i = 1 : length(SubNames) + for j = 1 :size(MRSCont.overview.SubSpecNamesStruct.(SubNames{i}),2) + tempSubNames{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + k=k+1; + end + end + end + + FitNames = fieldnames(MRSCont.overview.FitSpecNamesStruct); + k=1; + if ~isempty(FitNames) + for i = 1 : length(FitNames) + for j = 1 :size(MRSCont.overview.FitSpecNamesStruct.(FitNames{i}),2) + tempFitNames{k} = ['Model ', FitNames{i}, ' ', MRSCont.overview.FitSpecNamesStruct.(FitNames{i}){1,j}]; + k=k+1; + end + end + end + Names = [tempSubNames';tempFitNames']; for ss = 1 : length(Names) - osp_plotModule(MRSCont, 'OspreySpecOverview', 1, Names{ss}); - osp_plotModule(MRSCont, 'OspreyMeanOverview', 1, Names{ss}); + osp_plotModule(MRSCont, 'OspreySpecOverview', 1,1, Names{ss}); + end + + SubNames = fieldnames(MRSCont.overview.SubSpecNamesStruct); + k=1; + if ~isempty(SubNames) + for i = 1 : length(SubNames) + for j = 1 :size(MRSCont.overview.SubSpecNamesStruct.(SubNames{i}),2) + if ~isempty(find(strcmp(FitNames,SubNames{i}))) + if (~isempty(find(strcmp(MRSCont.overview.FitSpecNamesStruct.(SubNames{i}),MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j})))) + Names{k} = ['Model ' , SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + else + Names{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + end + else + Names{k} = [SubNames{i}, ' ', MRSCont.overview.SubSpecNamesStruct.(SubNames{i}){1,j}]; + end + k=k+1; + end + end + end + for ss = 1 : length(Names) + osp_plotModule(MRSCont, 'OspreyMeanOverview', 1,1, Names{ss}); end if MRSCont.flags.isUnEdited - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'tNAA'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'tCho'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'Ins'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'off-tCr', 'Glx'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'tNAA'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'tCho'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'Ins'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-A-tCr', 'Glx'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tNAA', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tCho', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Ins', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Glx', 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tNAA', 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tCho', 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Ins', 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Glx', 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tNAA', 'FWHM'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'tCho', 'FWHM'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Ins', 'FWHM'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'off-tCr', 'Glx', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tNAA', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'tCho', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Ins', 'FWHM'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-A-tCr', 'Glx', 'FWHM'); end if MRSCont.flags.isMEGA - if ~strcmp(MRSCont.opts.fit.style, 'Concatenated') - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - else - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - end + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); end if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - if ~strcmp(MRSCont.opts.fit.style, 'Concatenated') - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{2}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{2}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'diff1-tCr', MRSCont.opts.editTarget{2}, 'FWHM'); - else - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); - osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{2}); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{2}, 'SNR'); - osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, 'conc-tCr', MRSCont.opts.editTarget{2}, 'FWHM'); - end + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{1}, 'FWHM'); + osp_plotModule(MRSCont, 'OspreyRaincloudOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{2}); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{2}, 'SNR'); + osp_plotModule(MRSCont, 'OspreyScatterOverview', 1, [1 1], 'metab-diff1-tCr', MRSCont.opts.editTarget{2}, 'FWHM'); end end end \ No newline at end of file diff --git a/plot/osp_plotFit.m b/plot/osp_plotFit.m index fd8be82b..1bd5acf3 100755 --- a/plot/osp_plotFit.m +++ b/plot/osp_plotFit.m @@ -139,13 +139,9 @@ else if strcmp(which_spec, 'conc') fitRangePPM = MRSCont.opts.fit.range; basisSet = MRSCont.fit.resBasisSet{VoxelIndex}.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - else if strcmp(which_spec, 'off') - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet{VoxelIndex}.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - else - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet{VoxelIndex}.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - end + else + fitRangePPM = MRSCont.opts.fit.range; + basisSet = MRSCont.fit.resBasisSet{VoxelIndex}.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); end end else @@ -155,13 +151,9 @@ else if strcmp(which_spec, 'conc') fitRangePPM = MRSCont.opts.fit.range; basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - else if strcmp(which_spec, 'off') - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - else - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); - end + else + fitRangePPM = MRSCont.opts.fit.range; + basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]); end end end @@ -169,29 +161,25 @@ if strcmp(which_spec, 'conc') dataToPlot = MRSCont.processed.(conc){kk}; else - if strcmp(which_spec, 'off') - dataToPlot = MRSCont.processed.A{kk}; - else - dataToPlot = MRSCont.processed.(which_spec){kk}; - end + dataToPlot = MRSCont.processed.(which_spec){kk}; end - if strcmp(which_spec, 'ref') || strcmp(which_spec, 'w') fitRangePPM = MRSCont.opts.fit.rangeWater; - basisSet = MRSCont.fit.resBasisSet.(which_spec).water.(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); + basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){VoxelIndex,1}; else if strcmp(which_spec, 'conc') fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); - else if strcmp(which_spec, 'off') - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); - else - fitRangePPM = MRSCont.opts.fit.range; - basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(round(dataToPlot.sz(1))) '_' num2str(round(dataToPlot.spectralwidth))]); - end + basisSet = MRSCont.fit.resBasisSet.(which_spec).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){VoxelIndex,1}; + else + fitRangePPM = MRSCont.opts.fit.range; + basisSet = MRSCont.fit.resBasisSet.([which_spec]).(['np_sw_' num2str(dataToPlot.sz(1)) '_' num2str(dataToPlot.spectralwidth)]){VoxelIndex(3),1,VoxelIndex(2)}; end end + if strcmp(which_spec, 'conc') + dataToPlot = MRSCont.processed.(conc){kk}; + else + dataToPlot = op_takesubspec(MRSCont.processed.(which_spec){kk},find(strcmp(MRSCont.processed.(which_spec){kk}.names,basisSet.names{1}))); + end end @@ -202,15 +190,17 @@ fitParams = MRSCont.fit.results{VoxelIndex}.(which_spec).fitParams{kk}; elseif (MRSCont.flags.isMRSI == 1) fitParams = MRSCont.fit.results{VoxelIndex(1), VoxelIndex(2)}.(which_spec).fitParams{kk}; + elseif strcmp(which_spec, 'ref') || strcmp(which_spec, 'w') + fitParams = MRSCont.fit.results.(which_spec).fitParams{VoxelIndex(3),kk}; else - fitParams = MRSCont.fit.results.(which_spec).fitParams{kk}; + fitParams = MRSCont.fit.results.(which_spec).fitParams{VoxelIndex(3),kk,VoxelIndex(2)}; end % Pack up into structs to feed into the reconstruction functions inputData.dataToFit = dataToPlot; inputData.basisSet = basisSet; - if (length(fitParams.ampl) == 3) - inputData.basisSet_mm = MRSCont.fit.basisSet_mm; - end +% if (length(fitParams.ampl) == 3) +% inputData.basisSet_mm = MRSCont.fit.basisSet_mm; +% end if (MRSCont.flags.isPRIAM == 1) inputSettings.scale = MRSCont.fit.scale{kk}; else @@ -224,6 +214,11 @@ inputSettings.flags.isHERCULES = MRSCont.flags.isHERCULES; inputSettings.flags.isPRIAM = MRSCont.flags.isPRIAM; inputSettings.concatenated.Subspec = conc; + if isfield(MRSCont.opts.fit,'GAP') && ~(strcmp(which_spec, 'ref') || strcmp(which_spec, 'w')) + inputSettings.GAP = MRSCont.opts.fit.GAP.(dataToPlot.names{1}); + else + inputSettings.GAP = []; + end case 'LCModel' fitRangePPM = MRSCont.opts.fit.range; @@ -244,7 +239,7 @@ elseif (MRSCont.flags.isMRSI == 1) fitParams = MRSCont.fit.results{VoxelIndex(1), VoxelIndex(2)}.(which_spec).fitParams{kk}; else - fitParams = MRSCont.fit.results.(which_spec).fitParams{kk}; + fitParams = MRSCont.fit.results.(which_spec).fitParams{VoxelIndex(3),kk,VoxelIndex(2)}; end end @@ -313,7 +308,7 @@ %For MM, prepare a 'clean' MM spectrum that has metabolite signals pulled %out. if (strcmp(which_spec, 'mm')) - Met_corr_spectrum = sum(ModelOutput.indivMets(:,1:4),2); + Met_corr_spectrum = sum(ModelOutput.indivMets(:,1:end),2); end if (strcmp(which_spec, 'diff1_mm')) Met_corr_spectrum = sum(ModelOutput.indivMets(:,1:2),2); diff --git a/plot/osp_plotLoad.m b/plot/osp_plotLoad.m index f47da4af..b8a8b4a6 100755 --- a/plot/osp_plotLoad.m +++ b/plot/osp_plotLoad.m @@ -1,4 +1,4 @@ -function out = osp_plotLoad(MRSCont, kk, which, VoxelIndex, stag, ppmmin, ppmmax, xlab, ylab, figTitle) +function out = osp_plotLoad(MRSCont, kk, which,ExpIndex, VoxelIndex, stag, ppmmin, ppmmax, xlab, ylab, figTitle) %% out = osp_plotLoad(MRSCont, kk, which, VoxelIndex, stag, ppmmin, ppmmax, xlab, ylab, figTitle) % Creates a figure showing raw data stored in an Osprey data container, % ie in the raw fields. This function will display the *unprocessed* @@ -43,91 +43,117 @@ %%% 1. PARSE INPUT ARGUMENTS %%% % Fall back to defaults if not provided -if nargin<10 - if ~(isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) - switch which - case 'mets' - [~,filen,ext] = fileparts(MRSCont.files{kk}); - figTitle = sprintf(['Load metabolite data plot: ' filen ext '\n']); - case 'mm'% re_mm - [~,filen,ext] = fileparts(MRSCont.files_mm{kk});% re_mm - figTitle = sprintf(['Load MM data plot: ' filen ext '\n']);% re_mm - case 'ref' - if ~(strcmp(MRSCont.datatype,'P') || strcmp(MRSCont.datatype,'DATA')) - [~,filen,ext] = fileparts(MRSCont.files_ref{kk}); - figTitle = sprintf(['Load water reference data plot: ' filen ext '\n']); - else - [~,filen,ext] = fileparts(MRSCont.files{kk}); - figTitle = sprintf(['Load interleaved water reference data plot: ' filen ext '\n']); - end - case 'w' - [~,filen,ext] = fileparts(MRSCont.files_w{kk}); - figTitle = sprintf(['Load water data plot: ' filen ext '\n']); - otherwise - error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); - end - else - if nargin<4 - VoxelIndex = 1; - end - switch which - case 'mets' - [~,filen,ext] = fileparts(MRSCont.files{kk}); - figTitle = sprintf(['Load metabolite data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); - case 'mm'% re_mm - [~,filen,ext] = fileparts(MRSCont.files_mm{kk});% re_mm - figTitle = sprintf(['Load MM data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']);% re_mm - case 'ref' - if ~(strcmp(MRSCont.datatype,'P') || strcmp(MRSCont.datatype,'DATA')) - [~,filen,ext] = fileparts(MRSCont.files_ref{kk}); - figTitle = sprintf(['Load water reference data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); - else - [~,filen,ext] = fileparts(MRSCont.files{kk}); - figTitle = sprintf(['Load interleaved water reference data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); - end - case 'w' - [~,filen,ext] = fileparts(MRSCont.files_w{kk}); - figTitle = sprintf(['Load water data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); - otherwise - error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); - end + +if nargin<11 + if nargin<4 + ExpIndex =1; end - if nargin<9 - ylab=''; - if nargin<8 - xlab='chemical shift (ppm)'; - if nargin<7 - switch which - case 'mets' - ppmmax = 4.5; - case 'mm' %re_mm - ppmmax = 4.6; %re_mm - case {'ref', 'w'} - ppmmax = 2*4.68; - otherwise - error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); - end - if nargin<6 + if ~(isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) + switch which + case 'mets' + [~,filen,ext] = fileparts(MRSCont.files{ExpIndex,kk}); + figTitle = sprintf(['Load metabolite data plot: ' filen ext '\n']); + case 'mm'% re_mm + [~,filen,ext] = fileparts(MRSCont.files_mm{ExpIndex,kk});% re_mm + figTitle = sprintf(['Load MM data plot: ' filen ext '\n']);% re_mm + case 'ref' + if ~(strcmp(MRSCont.datatype,'P') || strcmp(MRSCont.datatype,'DATA')) + [~,filen,ext] = fileparts(MRSCont.files_ref{ExpIndex,kk}); + figTitle = sprintf(['Load water reference data plot: ' filen ext '\n']); + else + [~,filen,ext] = fileparts(MRSCont.files{ExpIndex,kk}); + figTitle = sprintf(['Load interleaved water reference data plot: ' filen ext '\n']); + end + case 'mm_ref' + if ~(strcmp(MRSCont.datatype,'P') || strcmp(MRSCont.datatype,'DATA')) + [~,filen,ext] = fileparts(MRSCont.files_mm_ref{ExpIndex,kk}); + figTitle = sprintf(['Load water reference data plot: ' filen ext '\n']); + else + [~,filen,ext] = fileparts(MRSCont.files{ExpIndex,kk}); + figTitle = sprintf(['Load interleaved water reference data plot: ' filen ext '\n']); + end + case 'w' + [~,filen,ext] = fileparts(MRSCont.files_w{ExpIndex,kk}); + figTitle = sprintf(['Load water data plot: ' filen ext '\n']); + otherwise + error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); + end + else + if nargin<4 + ExpIndex =1; + end + if nargin<5 + VoxelIndex = 1; + end + switch which + case 'mets' + [~,filen,ext] = fileparts(MRSCont.files{ExpIndex,kk}); + figTitle = sprintf(['Load metabolite data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); + case 'mm'% re_mm + [~,filen,ext] = fileparts(MRSCont.files_mm{ExpIndex,kk});% re_mm + figTitle = sprintf(['Load MM data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']);% re_mm + case 'ref' + if ~(strcmp(MRSCont.datatype,'P') || strcmp(MRSCont.datatype,'DATA')) + [~,filen,ext] = fileparts(MRSCont.files_ref{ExpIndex,kk}); + figTitle = sprintf(['Load water reference data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); + else + [~,filen,ext] = fileparts(MRSCont.files{ExpIndex,kk}); + figTitle = sprintf(['Load interleaved water reference data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); + end + case 'mm_ref' + if ~(strcmp(MRSCont.datatype,'P') || strcmp(MRSCont.datatype,'DATA')) + [~,filen,ext] = fileparts(MRSCont.files_ref{ExpIndex,kk}); + figTitle = sprintf(['Load water reference data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); + else + [~,filen,ext] = fileparts(MRSCont.files{ExpIndex,kk}); + figTitle = sprintf(['Load interleaved water reference data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); + end + case 'w' + [~,filen,ext] = fileparts(MRSCont.files_w{ExpIndex,kk}); + figTitle = sprintf(['Load water data plot: ' filen ext '\n Voxel ' num2str(VoxelIndex) ' ']); + otherwise + error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); + end + end + if nargin<10 + ylab=''; + if nargin<9 + xlab='chemical shift (ppm)'; + if nargin<8 switch which case 'mets' - ppmmin = 0.2; - case 'mm' %re_mm - ppmmin = 0.0; %re_mm - case {'ref', 'w'} - ppmmin = 0; + ppmmax = 4.5; + case 'mm' %re_mm + ppmmax = 4.6; %re_mm + case {'ref', 'w','mm_ref'} + ppmmax = 2*4.68; otherwise error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); end - if nargin<5 - stag = 0; - if nargin<4 -% VoxelIndex = []; - if nargin < 3 - which = 'mets'; - if nargin < 2 - kk = 1; - if nargin<1 - error('ERROR: no input Osprey container specified. Aborting!!'); + if nargin<7 + switch which + case 'mets' + ppmmin = 0.2; + case 'mm' %re_mm + ppmmin = 0.0; %re_mm + case {'ref', 'w','mm_ref'} + ppmmin = 0; + otherwise + error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); + end + if nargin<6 + stag = 0; + if nargin<5 + % VoxelIndex = []; + if nargin<4 + ExpIndex =1; + if nargin < 3 + which = 'mets'; + if nargin < 2 + kk = 1; + if nargin<1 + error('ERROR: no input Osprey container specified. Aborting!!'); + end end end end @@ -138,9 +164,8 @@ end end end - %Get y-axis values -maxRef = ones(1,MRSCont.nDatasets); +maxRef = ones(1,MRSCont.nDatasets(1)); if isfield(MRSCont,'plot') && (MRSCont.plot.load.match == 1) if MRSCont.flags.hasRef maxRef = MRSCont.plot.load.ref.max; @@ -168,16 +193,19 @@ switch which case 'mets' - dataToPlot=op_takeVoxel(MRSCont.raw{kk},VoxelIndex); + dataToPlot=op_takeVoxel(MRSCont.raw{ExpIndex,kk},VoxelIndex); dataToPlot = op_freqrange(dataToPlot, ppmmin, ppmmax); case 'mm' %re_mm - dataToPlot=op_takeVoxel(MRSCont.raw_mm{kk},VoxelIndex); + dataToPlot=op_takeVoxel(MRSCont.raw_mm{ExpIndex,kk},VoxelIndex); dataToPlot = op_freqrange(dataToPlot, ppmmin, ppmmax); %re_mm case 'ref' - dataToPlot=op_takeVoxel(MRSCont.raw_ref{kk},VoxelIndex); + dataToPlot=op_takeVoxel(MRSCont.raw_ref{ExpIndex,kk},VoxelIndex); dataToPlot = op_freqrange(dataToPlot, ppmmin, ppmmax); + case 'mm_ref' + dataToPlot=op_takeVoxel(MRSCont.raw_mm_ref{ExpIndex,kk},VoxelIndex); + dataToPlot = op_freqrange(dataToPlot, ppmmin, ppmmax); case 'w' - dataToPlot=op_takeVoxel(MRSCont.raw_w{kk},VoxelIndex); + dataToPlot=op_takeVoxel(MRSCont.raw_w{ExpIndex,kk},VoxelIndex); dataToPlot = op_freqrange(dataToPlot, ppmmin, ppmmax); otherwise error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); @@ -186,13 +214,15 @@ else switch which case 'mets' - dataToPlot = op_freqrange(MRSCont.raw{kk}, ppmmin, ppmmax); + dataToPlot = op_freqrange(MRSCont.raw{ExpIndex,kk}, ppmmin, ppmmax); case 'mm' %re_mm - dataToPlot = op_freqrange(MRSCont.raw_mm{kk}, ppmmin, ppmmax); %re_mm + dataToPlot = op_freqrange(MRSCont.raw_mm{ExpIndex,kk}, ppmmin, ppmmax); %re_mm case 'ref' - dataToPlot = op_freqrange(MRSCont.raw_ref{kk}, ppmmin, ppmmax); + dataToPlot = op_freqrange(MRSCont.raw_ref{ExpIndex,kk}, ppmmin, ppmmax); + case 'mm_ref' + dataToPlot = op_freqrange(MRSCont.raw_mm_ref{ExpIndex,kk}, ppmmin, ppmmax); case 'w' - dataToPlot = op_freqrange(MRSCont.raw_w{kk}, ppmmin, ppmmax); + dataToPlot = op_freqrange(MRSCont.raw_w{ExpIndex,kk}, ppmmin, ppmmax); otherwise error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); end @@ -220,7 +250,7 @@ axesNames = {'A'}; TitleNames = {'A'}; end -if MRSCont.flags.isMEGA && ~(strcmp(which, 'w') || strcmp(which, 'ref')) +if MRSCont.flags.isMEGA && ~(strcmp(which, 'w') || strcmp(which, 'ref')|| strcmp(which, 'mm_ref')) axesHandles.A = subplot(2, 1, 1); axesHandles.B = subplot(2, 1, 2); nAvgs = dataToPlot.rawAverages/2; @@ -238,7 +268,7 @@ end axesNames = {'A','B'}; TitleNames = {'A','B'}; -else if MRSCont.flags.isMEGA && (strcmp(which, 'w') || strcmp(which, 'ref')) +else if MRSCont.flags.isMEGA && (strcmp(which, 'w') || strcmp(which, 'ref')|| strcmp(which, 'mm_ref')) axesHandles.A = gca(); nAvgs = dataToPlot.averages; % Loop over all averages @@ -255,7 +285,7 @@ end end if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - if ~(strcmp(which, 'w') || strcmp(which, 'ref')) + if ~(strcmp(which, 'w') || strcmp(which, 'ref')|| strcmp(which, 'mm_ref')) figTitle =''; axesHandles.A = subplot(2, 2, 1); axesHandles.B = subplot(2, 2, 2); diff --git a/plot/osp_plotMeanSpec.m b/plot/osp_plotMeanSpec.m index 3f5790b2..28f3f58b 100644 --- a/plot/osp_plotMeanSpec.m +++ b/plot/osp_plotMeanSpec.m @@ -1,4 +1,4 @@ -function out = osp_plotMeanSpec(MRSCont, which_spec, g, shift,group, xlab, ylab, figTitle) +function out = osp_plotMeanSpec(MRSCont, which_spec, g, shift,group, xlab, ylab, figTitle,basis) %% out = osp_plotMeanSpec(MRSCont, which_spec,g, shift, xlab, ylab, figTitle) % Creates a figure mean and standard deviation of the spectra. If the % chosen spectra was fitted the mean fit, baseline and residue are shown. @@ -51,20 +51,26 @@ fitStyle = MRSCont.opts.fit.style; % Fall back to defaults if not provided -if nargin<7 -ylab=''; - if nargin<6 - xlab='Frequency (ppm)'; - if nargin<5 - group = 0; - if nargin<4 - shift = 0.1; - if nargin<3 - g = 1; - if nargin < 2 - which_spec = 'A'; - if nargin<1 - error('ERROR: no input Osprey container specified. Aborting!!'); +if nargin<9 + basis = 1; + if nargin<8 + figTitle = ''; + if nargin<7 + ylab=''; + if nargin<6 + xlab='Frequency (ppm)'; + if nargin<5 + group = 0; + if nargin<4 + shift = 0.1; + if nargin<3 + g = 1; + if nargin < 2 + which_spec = 'A'; + if nargin<1 + error('ERROR: no input Osprey container specified. Aborting!!'); + end + end end end end @@ -83,7 +89,7 @@ sort_fit = 'sort_fit'; else sort_data = 'sort_data_voxel_1'; - sort_fit = 'sort_fit_voxel_1'; + sort_fit = 'sort_models_voxel_1'; end % Create a fitMethod-specific theme @@ -109,208 +115,115 @@ GroupString = 'GMean'; shift = 0; end + +which_spec_split = split(which_spec); +if length(which_spec_split) == 3 + fit = which_spec_split{1}; + spec = which_spec_split{2}; + subspec = which_spec_split{3}; +else + fit = []; + spec = which_spec_split{1}; + subspec = which_spec_split{2}; +end + if MRSCont.flags.didFit - if MRSCont.flags.isUnEdited - switch which_spec - case 'A' - fit = 'off'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + if isempty(fit) %Is data + ind = find(strcmp(MRSCont.overview.SubSpecNamesStruct.(spec),subspec)); + if ~(strcmp(spec,'ref') || strcmp(spec,'w') || strcmp(spec,'mm_ref')) + data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' spec])(:,ind)'; + if size(MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' spec]),2)<=1 + data_sd = []; + else + data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' spec])(:,ind)'; + end + else + data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' spec])(:)'; + data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' spec])(:)'; + end + ppm = MRSCont.overview.Osprey.(['ppm_data_' spec]); + else %Is fit + switch spec + case {'metab','mm'} + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(spec)(basis,:),subspec)); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fit_' spec])(basis,:,ind); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fit_' spec])(basis,:,ind); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec])(basis,:,ind); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec])(basis,:,ind); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec])(basis,:,ind); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec])(basis,:,ind); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec])(basis,:,ind); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec])(basis,:,ind); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec])(basis,:,ind); + if strcmp(spec,'mm') + MM_clean_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_MM_clean_' spec])(basis,:,ind); + MM_clean_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_MM_clean_' spec])(basis,:,ind); + end if MRSCont.opts.fit.fitMM - MM_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fittMM_' fit '_' which_spec]); - MM_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fittMM_' fit '_' which_spec]); + MM_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fittMM_' spec])(basis,:,ind); + MM_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fittMM_' spec])(basis,:,ind); end - case {'ref','w'} + case {'ref','w'} if ~strcmp(MRSCont.opts.fit.method, 'LCModel') - fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fit_' spec])(1,:,1); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fit_' spec])(1,:,1); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec])(1,:,1); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec])(1,:,1); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec])(1,:,1); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec])(1,:,1); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec])(1,:,1); else - data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' which_spec]); - ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); - end - case {'mm'} - % name = 'mm'; - % data_mean = MRSCont.overview.Osprey.sort_data.(GroupString).(['mean_' which_spec]); - % data_sd = MRSCont.overview.Osprey.sort_data.(GroupString).(['sd_' which_spec]); - % ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); - - fit = 'mm'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - MM_clean_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_MM_clean_' fit '_' which_spec]); - MM_clean_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_MM_clean_' fit '_' which_spec]); - if MRSCont.opts.fit.fitMM - MM_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fittMM_' fit '_' which_spec]); - MM_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fittMM_' fit '_' which_spec]); + data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' spec])(:,1)'; + data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' spec])(:,1)'; + ppm = MRSCont.overview.Osprey.(['ppm_data_' spec]); end end - end - if MRSCont.flags.isMEGA - switch which_spec - case 'A' - name = 'off'; - if strcmp(fitStyle,'Concatenated') - data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' which_spec]); - ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); - else - fit = 'off'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - end - case 'B' - name = 'on'; - data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' which_spec]); - ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); - case 'diff1' - if ~strcmp(fitStyle,'Concatenated') - fit = which_spec; - else - fit = 'conc'; - end - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - case {'sum'} - if ~strcmp(fitStyle,'Concatenated') - fit = which_spec; - data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' which_spec]); - ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); - else - fit = 'conc'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - end - case {'ref','w'} - fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - switch which_spec - case {'A','B','C','D'} - data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' which_spec]); - ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); - case {'diff1','diff2','sum'} - if ~strcmp(fitStyle,'Concatenated') - fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - else - fit = 'conc'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - end - case {'ref','w'} - fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + end +else + ind = find(strcmp(MRSCont.overview.SubSpecNamesStruct.(spec),subspec)); + if ~(strcmp(spec,'ref') || strcmp(spec,'w') || strcmp(spec,'mm_ref')) + data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' spec])(:,ind)'; + if size(MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' spec]),2)<=1 + data_sd = []; + else + data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' spec])(:,ind)'; end + else + data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' spec])(:)'; + data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' spec])(:)'; end -else - data_mean = MRSCont.overview.Osprey.(sort_data).(GroupString).(['mean_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_data).(GroupString).(['sd_' which_spec]); - ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); + ppm = MRSCont.overview.Osprey.(['ppm_data_' spec]); end [~,min_ppm_index] = min(ppm); if ~exist('name', 'var') - name = which_spec; + name = spec; end -if nargin<8 +if ~exist('ppmRange', 'var') if ~strcmp(GroupString,'GMean') - if (~strcmp(which_spec,'w') && ~strcmp(which_spec,'ref')) + if (~strcmp(spec,'w') && ~strcmp(spec,'ref') && ~strcmp(spec,'mm_ref')) if exist('fit_mean', 'var') - figTitle = ['mean data \pm SD & mean fit: ' which_spec]; + figTitle = ['mean data \pm SD & mean model: ' spec ' ' subspec]; else figTitle = ['mean \pm SD: ' name]; end ppmRange = MRSCont.opts.fit.range; else - figTitle = ['mean data \pm SD & mean fit: ' which_spec]; + figTitle = ['mean data \pm SD & mean model: ' spec ' ' subspec]; ppmRange = MRSCont.opts.fit.rangeWater; end else - if (~strcmp(which_spec,'w') && ~strcmp(which_spec,'ref')) + if (~strcmp(spec,'w') && ~strcmp(spec,'ref') && ~strcmp(spec,'mm_ref')) if exist('fit_mean', 'var') - figTitle = ['Grand mean data \pm SD & Grand mean fit: ' which_spec]; + figTitle = ['Grand mean data \pm SD & Grand mean model: ' spec ' ' subspec]; else figTitle = ['Grand mean \pm SD: ' name]; end ppmRange = MRSCont.opts.fit.range; else - figTitle = ['Grand mean data \pm SD & Grand mean fit: ' which_spec]; + figTitle = ['Grand mean data \pm SD & Grand mean model: ' spec ' ' subspec]; ppmRange = MRSCont.opts.fit.rangeWater; end end @@ -338,7 +251,7 @@ MM_clean_yu = MM_clean_mean + MM_clean_sd; MM_clean_yl = MM_clean_mean - MM_clean_sd; end -if exist('MM_mean', 'var') && length(MM_sd) > 1 +if exist('MM_mean', 'var') && length(MM_sd) > 1 && ~isnan(MM_mean(1)) MM_yu = MM_mean + MM_sd; MM_yl = MM_mean - MM_sd; end @@ -381,7 +294,7 @@ plot(ppm,baseline_mean+shift ,'color', MRSCont.colormap.LightAccent, 'LineWidth', 1); %Baseline end - if exist('MM_mean', 'var') + if exist('MM_mean', 'var') && ~isnan(MM_mean(1)) plot(ppm,MM_mean+baseline_mean+shift ,'color', colorFit, 'LineWidth', 1); %MM Baseline end @@ -462,28 +375,28 @@ switch which_spec case 'A' fit = 'off'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec]); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec]); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); if MRSCont.opts.fit.fitMM - MM_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fittMM_' fit '_' which_spec]); - MM_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fittMM_' fit '_' which_spec]); + MM_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fittMM_' spec]); + MM_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fittMM_' spec]); end case {'ref','w'} fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' which_spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_which_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' which_spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' which_spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' which_spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' which_spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' which_spec]); case {'mm'} % name = 'mm'; % data_mean = MRSCont.overview.Osprey.sort_data.(GroupString).(['mean_' which_spec]); @@ -491,20 +404,20 @@ % ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); fit = 'mm'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); - MM_clean_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_MM_clean_' fit '_' which_spec]); - MM_clean_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_MM_clean_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec]); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec]); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); + MM_clean_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_MM_clean_' spec]); + MM_clean_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_MM_clean_' spec]); if MRSCont.opts.fit.fitMM - MM_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fittMM_' fit '_' which_spec]); - MM_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fittMM_' fit '_' which_spec]); + MM_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_fittMM_' spec]); + MM_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_fittMM_' spec]); end end end @@ -518,15 +431,15 @@ ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); else fit = 'off'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec]); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec]); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); end case 'B' name = 'on'; @@ -539,15 +452,15 @@ else fit = 'conc'; end - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec]); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec]); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); case {'sum'} if ~strcmp(fitStyle,'Concatenated') fit = which_spec; @@ -556,25 +469,25 @@ ppm = MRSCont.overview.Osprey.(['ppm_data_' which_spec]); else fit = 'conc'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec]); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec]); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); end case {'ref','w'} fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' which_spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' which_spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' which_spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' which_spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' which_spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' which_spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' which_spec]); end end if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) @@ -586,36 +499,36 @@ case {'diff1','diff2','sum'} if ~strcmp(fitStyle,'Concatenated') fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec]); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec]); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); else fit = 'conc'; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' fit '_' which_spec]); - baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' spec]); + baseline_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_baseline_' spec]); + baseline_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_baseline_' spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); end case {'ref','w'} fit = which_spec; - fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' fit '_' which_spec]); - fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' fit '_' which_spec]); - data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' fit '_' which_spec]); - data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' fit '_' which_spec]); - residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' fit '_' which_spec]); - residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' fit '_' which_spec]); - ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' fit '_' which_spec]); + fit_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_' which_spec]); + fit_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_' which_spec]); + data_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_data_' which_spec]); + data_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_data_' which_spec]); + residual_mean = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['mean_res_' which_spec]); + residual_sd = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['sd_res_' which_spec]); + ppm = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' which_spec]); end end @@ -623,7 +536,7 @@ name = which_spec; end - if nargin<8 + if ~exist('ppmRange', 'var') if ~strcmp(GroupString,'GMean') if (~strcmp(which_spec,'w') && ~strcmp(which_spec,'ref')) if exist('fit_mean', 'var') diff --git a/plot/osp_plotModule.m b/plot/osp_plotModule.m index 2a726261..fcc8f01a 100644 --- a/plot/osp_plotModule.m +++ b/plot/osp_plotModule.m @@ -1,4 +1,4 @@ -function out = osp_plotModule(MRSCont, Module, kk, which, metab, corr) +function out = osp_plotModule(MRSCont, Module, kk,Index, which, metab, corr) %% osp_plotModule % Callback function on print figure button click. % @@ -49,6 +49,8 @@ % 'metab-X' (OspreyScatterOverview) with X indicating the metab X % 'SNR' (OspreyScatterOverview) correlation with SNR % 'FWHM' (OspreyScatterOverview) correlation with FWHM +% Index Index to basis set or subspectrum. +% OPTIONS: % % % @@ -151,32 +153,44 @@ 'HorizontalAlignment', 'left', 'String', '', 'BackgroundColor',colormapfig.Background); % Get some information about the data from MRSCont to fill the info panel - if strcmp(which,'mets') %Is metabolite data? - StatText = ['Metabolite Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw{1,kk}.te) ' / ' num2str(MRSCont.raw{1,kk}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw{1,kk}.spectralwidth) ' Hz'... - '\nraw subspecs: ' num2str(MRSCont.raw{1,kk}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw{1,kk}.rawAverages) '; averages: ' num2str(MRSCont.raw{1,kk}.averages)... - '; Sz: ' num2str(MRSCont.raw{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{3})) ' mm = '... - num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; - else if strcmp(which, 'ref') %Is water or ref data? - StatText = ['Reference Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw_ref{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw_ref{1,kk}.te) ' / ' num2str(MRSCont.raw_ref{1,kk}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_ref{1,kk}.spectralwidth) ' Hz'... - '\nraw subspecs: ' num2str(MRSCont.raw_ref{1,kk}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_ref{1,kk}.rawAverages) '; averages: ' num2str(MRSCont.raw_ref{1,kk}.averages)... - '; Sz: ' num2str(MRSCont.raw_ref{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{3})) ' mm = '... - num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw_ref{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw_ref{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; - else - StatText = ['Water Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw_w{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw_w{1,kk}.te) ' / ' num2str(MRSCont.raw_w{1,kk}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_w{1,kk}.spectralwidth) ' Hz'... - '\nraw subspecs: ' num2str(MRSCont.raw_w{1,kk}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_w{1,kk}.rawAverages) '; averages: ' num2str(MRSCont.raw_w{1,kk}.averages)... - '; Sz: ' num2str(MRSCont.raw_w{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{3})) ' mm = '... - num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw_w{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw_w{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; - end + switch which + case 'metabolites' + StatText = ['Metabolite Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw{1,kk}.te) ' / ' num2str(MRSCont.raw{1,kk}.tr) '\naverages: ' num2str(MRSCont.raw{1,kk}.averages)... + '; Sz: ' num2str(MRSCont.raw{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{3})) ' mm = '... + num2str(MRSCont.raw{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; + case 'MM' + StatText = ['MM Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw_mm{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw_mm{1,kk}.te) ' / ' num2str(MRSCont.raw_mm{1,kk}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_mm{1,kk}.spectralwidth) ' Hz'... %re_mm + '\nraw subspecs: ' num2str(MRSCont.raw_mm{1,kk}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_mm{1,kk}.rawAverages) '; averages: ' num2str(MRSCont.raw_mm{1,kk}.averages)... + '; Sz: ' num2str(MRSCont.raw_mm{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw_mm{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw_mm{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw_mm{1,kk}.geometry.size.(Geom{3})) ' mm = '... %re_mm + num2str(MRSCont.raw_mm{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw_mm{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw_mm{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; %re_mm + case 'ref' + StatText = ['Reference Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw_ref{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw_ref{1,kk}.te) ' / ' num2str(MRSCont.raw_ref{1,kk}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_ref{1,kk}.spectralwidth) ' Hz'... %re_mm + '\nraw subspecs: ' num2str(MRSCont.raw_ref{1,kk}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_ref{1,kk}.rawAverages) '; averages: ' num2str(MRSCont.raw_ref{1,kk}.averages)... + '; Sz: ' num2str(MRSCont.raw_ref{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{3})) ' mm = '... %re_mm + num2str(MRSCont.raw_ref{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw_ref{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw_ref{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; %re_mm + case 'MM reference' + StatText = ['MM reference Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw_mm_ref{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw_mm_ref{1,kk}.te) ' / ' num2str(MRSCont.raw_mm_ref{1,kk}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_mm_ref{1,kk}.spectralwidth) ' Hz'... + '\nraw subspecs: ' num2str(MRSCont.raw_mm_ref{1,kk}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_mm_ref{1,kk}.rawAverages) '; averages: ' num2str(MRSCont.raw_mm_ref{1,kk}.averages)... + '; Sz: ' num2str(MRSCont.raw_mm_ref{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw_mm_ref{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw_mm_ref{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw_mm_ref{1,kk}.geometry.size.(Geom{3})) ' mm = '... + num2str(MRSCont.raw_mm_ref{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw_mm_ref{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw_mm_ref{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; + case 'w' + StatText = ['Water Data -> Sequence: ' Seq '; B0: ' num2str(MRSCont.raw_w{1,kk}.Bo) '; TE / TR: ' num2str(MRSCont.raw_w{1,kk}.te) ' / ' num2str(MRSCont.raw_w{1,kk}.tr) ' ms ' '; spectral bandwidth: ' num2str(MRSCont.raw_w{1,kk}.spectralwidth) ' Hz'... + '\nraw subspecs: ' num2str(MRSCont.raw_w{1,kk}.rawSubspecs) '; raw averages: ' num2str(MRSCont.raw_w{1,kk}.rawAverages) '; averages: ' num2str(MRSCont.raw_w{1,kk}.averages)... + '; Sz: ' num2str(MRSCont.raw_w{1,kk}.sz) '; dimensions: ' num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{1})) ' x ' num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{2})) ' x ' num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{3})) ' mm = '... + num2str(MRSCont.raw_w{1,kk}.geometry.size.(Geom{1}) * MRSCont.raw_w{1,kk}.geometry.size.(Geom{2}) * MRSCont.raw_w{1,kk}.geometry.size.(Geom{3})/1000) ' ml']; end set(InfoText, 'String', sprintf(StatText)); %%% 2aa. VISUALIZATION PART OF OSPREYLOAD %%% % osp_plotLoad is used to visualize the raw data. Number of subplots % depends on the number of subspectra of the sequence + Exp = Index(1); + VoxelIndex = Index(2); + switch which + case 'metabolites' + temp = osp_plotLoad(MRSCont, kk,'mets',Exp); + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_metabolites.pdf']; - if strcmp(which,'mets') %Metabolite data/tab - outputFile = [filename '_OspreyLoad_mets.pdf']; - temp = osp_plotLoad(MRSCont, kk,'mets' ); if MRSCont.flags.isUnEdited % One window for UnEdited drawnow; set( temp.Children(1), 'Parent', Plot ); @@ -212,131 +226,170 @@ set(multiAload.Children(1), 'OuterPosition', [0,0,1,1]) end - else if strcmp(which,'ref') %ref data/tab - temp = osp_plotLoad(MRSCont, kk,'ref' ); - drawnow - set( temp.Children(1), 'Parent', Plot ); - outputFile = [filename '_OspreyLoad_ref.pdf']; - else %water data/tab has only one window all the time - temp = osp_plotLoad(MRSCont, kk,'w'); - drawnow - set(temp.Children(1), 'Parent', Plot ); - outputFile = [filename '_OspreyLoad_w.pdf']; - end - end + case 'MM' - set(input_figure, 'Heights', [-0.1 -0.9]); - % Get rid of the Load figure - close( temp ); + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, kk,'mm',Exp); + VoxelIndex = 1; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + temp = osp_plotLoad(MRSCont, kk,'mm',Exp,Index(2)); + VoxelIndex = Index(1); + else + temp = osp_plotLoad(MRSCont, kk,'mm',Exp,[Index(2) Index(3) Index(4)]); + end + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_MM.pdf']; + if MRSCont.flags.isUnEdited % One window for UnEdited + ViewAxes = gca(); + set( ViewAxes, 'Parent', Plot ); + end + if MRSCont.flags.isMEGA %Two windows for MEGA + set( temp.Children(2), 'Parent', Plot ); + set( temp.Children(1), 'Parent', Plot ); + set(Plot,'Heights', [-0.49 -0.49]); + set(Plot.Children(2), 'Units', 'normalized') + set(Plot.Children(2), 'OuterPosition', [0,0.5,1,0.5]) + set(Plot.Children(1), 'Units', 'normalized') + set(Plot.Children(1), 'OuterPosition', [0,0,1,0.5]) + end + if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Four windows for HERMES/HERCULES + multiACload = uix.VBox('Parent', Plot, 'Padding', 5, 'BackgroundColor',colormapfig.Background); + multiAload = uix.VBox('Parent', multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + multiCload = uix.VBox('Parent', multiACload,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + multiBDload = uix.VBox('Parent', Plot,'Padding', 5, 'BackgroundColor',colormapfig.Background); + multiBload = uix.VBox('Parent', multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + multiDload = uix.VBox('Parent', multiBDload, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + set( temp.Children(1), 'Parent', multiDload ); + set( temp.Children(1), 'Parent', multiCload ); + set( temp.Children(1), 'Parent', multiBload ); + set( temp.Children(1), 'Parent', multiAload ); + set(Plot,'Width', [-0.49 -0.49]); + set(multiDload.Children(1), 'Units', 'normalized') + set(multiDload.Children(1), 'OuterPosition', [0,0,1,1]) + set(multiCload.Children(1), 'Units', 'normalized') + set(multiCload.Children(1), 'OuterPosition', [0,0,1,1]) + set(multiBload.Children(1), 'Units', 'normalized') + set(multiBload.Children(1), 'OuterPosition', [0,0,1,1]) + set(multiAload.Children(1), 'Units', 'normalized') + set(multiAload.Children(1), 'OuterPosition', [0,0,1,1]) + + end + case 'ref' + + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, kk,'ref',Exp); + VoxelIndex = 1; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + temp = osp_plotLoad(MRSCont, kk,'ref',Exp,Index(2)); + VoxelIndex = Index(1); + else + temp = osp_plotLoad(MRSCont, kk,'ref',Exp,[Index(2) Index(3) Index(4)]); + end + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', Plot ); + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_ref.pdf']; + + + case 'w' + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotLoad(MRSCont, kk,'w',Exp); + VoxelIndex = 1; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + temp = osp_plotLoad(MRSCont, kk,'w',Exp,Index(2)); + VoxelIndex = Index(1); + else + temp = osp_plotLoad(MRSCont, kk,'w',Exp,[Index(2) Index(3) Index(4)]); + end + ViewAxes = gca(); %re_mm + set( ViewAxes, 'Parent', Plot ); + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_Exp_' num2str(Exp) '_OspreyLoad_w.pdf']; + end + set(input_figure, 'Heights', [-0.1 -0.9]); + % Get rid of the Load figure + close( temp ); %%% --- 2b. OspreyProcess --- %%% case 'OspreyProcess' outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyProcess'); [~,filename,~] = fileparts(MRSCont.files{kk}); + Exp = Index(1); + SubSpec = Index(2); + VoxelIndex = 1; Plot = uix.HBox('Parent', input_figure, ... 'Padding', 5,'BackgroundColor', colormapfig.Background); set(input_figure, 'Heights', [-0.11 -0.89]); - if MRSCont.flags.isUnEdited %Is UnEdited? - if strcmp(which, 'ref') || strcmp(which, 'w') - SNR = 'water'; - else - SNR = 'tNAA'; - end - end - if MRSCont.flags.isMEGA %Is MEGA? - if strcmp(which, 'ref') || strcmp(which, 'w') - SNR = 'water'; - else - switch which - case 'A' - SNR = 'tNAA'; - case 'B' - SNR = 'tCr'; - case 'diff1' - SNR = MRSCont.processed.diff1{1,kk}.target; - case 'sum' - SNR = 'tNAA'; + % Get parameter from file to fill the info panel + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + if strcmp(which,'metab') + StatText = ['SNR(' MRSCont.processed.metab{1,kk}.QC_names{SubSpec} '): ' num2str(MRSCont.QM.SNR.(which)(Exp,kk,SubSpec)) '; FWHM (' MRSCont.processed.metab{1,kk}.QC_names{SubSpec} '): '... + num2str(MRSCont.QM.FWHM.(which)(Exp,kk,SubSpec)) ' / ' (num2str(MRSCont.QM.FWHM.(which)(Exp,kk,SubSpec)/MRSCont.processed.(which){kk}.txfrq(Exp)*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(which)(Exp,kk,SubSpec)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.A(kk)*MRSCont.processed.(which){kk}.txfrq(Exp)/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.A(kk)*MRSCont.processed.(which){kk}.txfrq(Exp)/1e6) ' Hz']; + else + StatText = ['SNR(' MRSCont.processed.(which){1,kk}.QC_names{SubSpec} '): ' num2str(MRSCont.QM.SNR.(which)(Exp,kk)) '; FWHM (' MRSCont.processed.(which){1,kk}.QC_names{SubSpec} '): '... + num2str(MRSCont.QM.FWHM.(which)(Exp,kk)) ' / ' (num2str(MRSCont.QM.FWHM.(which)(Exp,kk)/MRSCont.processed.(which){kk}.txfrq(Exp)*1e6))... + ' Hz / ppm']; end - end - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Is HERMES\HERCULES? - if strcmp(which, 'ref') || strcmp(which, 'w') - SNR = 'water'; - else - switch which - case 'A' - SNR = 'tNAA'; - case 'B' - SNR = 'tCr'; - case 'C' - SNR = 'tNAA'; - case 'D' - SNR = 'tCr'; - case 'diff1' - SNR = MRSCont.processed.diff1{1,kk}.target; - case 'diff2' - SNR = MRSCont.processed.diff1{1,kk}.target; - case 'sum' - SNR = 'tNAA'; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + if strcmp(which,'metab') + StatText = ['SNR(' MRSCont.processed.metab{1,kk}.QC_names{SubSpec} '): ' num2str(MRSCont.QM.SNR.(which)(Exp,kk,SubSpec)) '; FWHM (' MRSCont.processed.metab{1,kk}.QC_names{SubSpec} '): '... + num2str(MRSCont.QM.FWHM.(which)(Exp,kk,SubSpec)) ' / ' (num2str(MRSCont.QM.FWHM.(which)(Exp,kk,SubSpec)/MRSCont.processed.(which){kk}.txfrq(Exp)*1e6))... + ' Hz / ppm \nReference shift: ' num2str(MRSCont.QM.freqShift.(which)(Exp,kk,SubSpec)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.A(kk)*MRSCont.processed.(which){kk}.txfrq(Exp)/1e6)... + ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.A(kk)*MRSCont.processed.(which){kk}.txfrq(Exp)/1e6) ' Hz']; + else + StatText = ['SNR(' MRSCont.processed.metab{1,kk}.QC_names{SubSpec} '): ' num2str(MRSCont.QM.SNR.(which)(Exp,kk)) '; FWHM (' MRSCont.processed.metab{1,kk}.QC_names{SubSpec} '): '... + num2str(MRSCont.QM.FWHM.(which)(Exp,kk)) ' / ' (num2str(MRSCont.QM.FWHM.(which)(Exp,kk)/MRSCont.processed.(which){kk}.txfrq(Exp)*1e6))... + ' Hz / ppm']; end end - end - % Get parameter from file to fill the info panel - if (strcmp(which,'A') || strcmp(which,'B') || strcmp(which,'C') || strcmp(which,'D') || strcmp(which,'diff1') || strcmp(which,'diff2') || strcmp(which,'sum')) - StatText = ['Metabolite Data -> SNR(' SNR '): ' num2str(MRSCont.QM.SNR.(which)(kk)) '; FWHM (' SNR '): ' ... - num2str(MRSCont.QM.FWHM.(which)(kk)) ' / ' (num2str(MRSCont.QM.FWHM.(which)(kk)/MRSCont.processed.(which){kk}.txfrq*1e6))... - ' ppm / Hz \nReference shift: ' num2str(MRSCont.QM.freqShift.(which)(kk)) ' Hz \nAverage Delta F0 Pre Registration: ' num2str(MRSCont.QM.drift.pre.AvgDeltaCr.(which)(kk)*MRSCont.processed.(which){kk}.txfrq/1e6)... - ' Hz; Average Delta F0 Post Registration: ' num2str(MRSCont.QM.drift.post.AvgDeltaCr.(which)(kk)*MRSCont.processed.(which){kk}.txfrq/1e6) ' Hz']; - else if strcmp(which,'ref') - StatText = ['Reference Data -> SNR(' SNR '): ' num2str(MRSCont.QM.SNR.(which)(kk)) '; FWHM (' SNR '): '... - num2str(MRSCont.QM.FWHM.(which)(kk)) ' / ' (num2str(MRSCont.QM.FWHM.(which)(kk)/MRSCont.processed.(which){kk}.txfrq*1e6))... - ' ppm / Hz']; - else - StatText = ['Water Data -> SNR(' SNR '): ' num2str(MRSCont.QM.SNR.(which)(kk)) '; FWHM (' SNR '): '... - num2str(MRSCont.QM.FWHM.(which)(kk)) '/' (num2str(MRSCont.QM.FWHM.(which)(kk)/MRSCont.processed.(which){kk}.txfrq*1e6))... - ' ppm / Hz']; + if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + StatText = ['Voxel ' num2str(Index(1)) ': ' StatText]; end - end - InfoText = uicontrol('Parent',Info,'style','text','FontSize', 12, 'FontName', font,... - 'HorizontalAlignment', 'left', 'String', sprintf(StatText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); - - %%% 2bb. VISUALIZATION PART OF OSPREYPROCESS %%% - %osp_plotProcess is used to visualize the processed spectra - temp = osp_plotProcess(MRSCont, kk,which); % Create figure - %Subplots are distributed here - proSpecs = uix.VBox('Parent', Plot, 'Padding', 5, 'BackgroundColor',colormapfig.Background); - proPre = uix.VBox('Parent', proSpecs,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); - proPost = uix.VBox('Parent', proSpecs,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); - proOut = uix.VBox('Parent', Plot,'Padding', 5, 'BackgroundColor',colormapfig.Background); - proDrift = uix.VBox('Parent', proOut, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); - proAlgn = uix.VBox('Parent', proOut, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); - - set( temp.Children(1), 'Parent', proDrift ); - set( temp.Children(1), 'Parent', proAlgn ); - set( temp.Children(1), 'Parent', proPost ); - set( temp.Children(1), 'Parent', proPre ); - close( temp ); - %%% 5. DATA CONTROLS FOR THIS TAB %%% - set(Plot,'Widths', [-0.49 -0.49]); - set(proPre.Children(1), 'Units', 'normalized') - set(proPre.Children(1), 'OuterPosition', [0,0,1,1]) - set(proPost.Children(1), 'Units', 'normalized') - set(proPost.Children(1), 'OuterPosition', [0,0,1,1]) - set(proDrift.Children(1), 'Units', 'normalized') - set(proDrift.Children(1), 'OuterPosition', [0,0,1,1]) - set(proDrift.Children,'Children',flipud(proDrift.Children.Children)); - set(proAlgn.Children(1), 'Units', 'normalized') - set(proAlgn.Children(1), 'OuterPosition', [0,0,1,1]) + InfoText = uicontrol('Parent',Info,'style','text','FontSize', 12, 'FontName', font,... + 'HorizontalAlignment', 'left', 'String', sprintf(StatText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + + %%% 4. VISUALIZATION PART OF THIS TAB %%% + %osp_plotProcess is used to visualize the processed spectra + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + temp = osp_plotProcess(MRSCont, kk,which,SubSpec,Exp); % Create figure + VoxelIndex = 1; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + temp = osp_plotProcess(MRSCont, kk,which,SubSpec,Exp,Index(1)); %Create figure + VoxelIndex = Index(1); + end + %Subplots are distributed here + proSpecs = uix.VBox('Parent', Plot, 'Padding', 5, 'BackgroundColor',colormapfig.Background); + proPre = uix.VBox('Parent', proSpecs,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + proPost = uix.VBox('Parent', proSpecs,'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + proOut = uix.VBox('Parent', Plot,'Padding', 5, 'BackgroundColor',colormapfig.Background); + proDrift = uix.VBox('Parent', proOut, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + proAlgn = uix.VBox('Parent', proOut, 'Padding', 5,'Units', 'Normalized', 'BackgroundColor',colormapfig.Background); + + set( temp.Children(1), 'Parent', proDrift ); + set( temp.Children(1), 'Parent', proAlgn ); + set( temp.Children(1), 'Parent', proPost ); + set( temp.Children(1), 'Parent', proPre ); + close( temp ); +%%% 5. DATA CONTROLS FOR THIS TAB %%% + set(Plot,'Widths', [-0.49 -0.49]); + set(proPre.Children(1), 'Units', 'normalized') + set(proPre.Children(1), 'OuterPosition', [0,0,1,1]) + set(proPost.Children(1), 'Units', 'normalized') + set(proPost.Children(1), 'OuterPosition', [0,0,1,1]) + set(proDrift.Children(1), 'Units', 'normalized') + set(proDrift.Children(1), 'OuterPosition', [0,0,1,1]) + set(proAlgn.Children(1), 'Units', 'normalized') + set(proAlgn.Children(1), 'OuterPosition', [0,0,1,1]) - outputFile = [filename '_OspreyProcess_' which '.pdf']; + outputFile = [filename '_Voxel_' num2str(VoxelIndex) '_OspreyProcess_' which '_' MRSCont.processed.(which){kk}.names{SubSpec} '.pdf']; %%% --- 2c. OspreyFit --- %%% case 'OspreyFit' - + basis = Index(1); + subspectrum = Index(2); % For this visualization, we will have to make a few % distinctions upfront since the modeling algorithms (LCModel % vs. Osprey) do not always return the same kinds of data, or they @@ -344,7 +397,7 @@ switch MRSCont.opts.fit.method case 'LCModel' % Number of metabolites and lipid/MM basis functions - basisNames = MRSCont.fit.results.off.fitParams{kk}.name; + basisNames = MRSCont.fit.results.metab.fitParams{kk}.name; nLip = sum(~cellfun(@isempty, strfind(basisNames, 'Lip'))); nMM = sum(~cellfun(@isempty, strfind(basisNames, 'MM'))); nMMLip = nLip + nMM; @@ -354,180 +407,352 @@ waterFitRangeString = ''; % Where are the metabolite names stored? basisSetNames = MRSCont.fit.results.(which).fitParams{kk}.name; + subSpecName = 'A'; % Smaller fonts for the results resultsFontSize = 6; case 'Osprey' - % Number of metabolites and lipid/MM basis functions - nMets = MRSCont.fit.basisSet.nMets; - nMMLip = MRSCont.fit.basisSet.nMM; % Additional info panel string for the water fit range waterFitRangeString = ['Fitting range: ' num2str(MRSCont.opts.fit.rangeWater(1)) ' to ' num2str(MRSCont.opts.fit.rangeWater(2)) ' ppm']; % Where are the metabolite names stored? if strcmp(which, 'ref') || strcmp(which, 'w') - basisSetNames = MRSCont.fit.resBasisSet.(which).water.(['np_sw_' num2str(MRSCont.processed.A{kk}.sz(1)) '_' num2str(MRSCont.processed.A{kk}.spectralwidth)]).name; + basisSet = MRSCont.fit.resBasisSet.(which).(['np_sw_' num2str(MRSCont.processed.metab{kk}.sz(1)) '_' num2str(MRSCont.processed.metab{kk}.spectralwidth)]){1}; + basisSetNames = basisSet.name; + subSpecName = which; else if strcmp(which, 'conc') - basisSetNames = MRSCont.fit.resBasisSet.(which).(['np_sw_' num2str(MRSCont.processed.A{kk}.sz(1)) '_' num2str(MRSCont.processed.A{kk}.spectralwidth)]).name; - else if strcmp(which, 'off') - basisSetNames = MRSCont.fit.resBasisSet.(which).(['np_sw_' num2str(MRSCont.processed.A{kk}.sz(1)) '_' num2str(MRSCont.processed.A{kk}.spectralwidth)]).name; - else - basisSetNames = MRSCont.fit.resBasisSet.(which).(['np_sw_' num2str(MRSCont.processed.A{kk}.sz(1)) '_' num2str(MRSCont.processed.A{kk}.spectralwidth)]).name; - end + basisSet = MRSCont.fit.resBasisSet.(which).(['np_sw_' num2str(MRSCont.processed.metab{kk}.sz(1)) '_' num2str(MRSCont.processed.metab{kk}.spectralwidth)]){basis,1}; + basisSetNames = basisSet.name; + subSpecName = basisSet.names{1}; + else + basisSet = MRSCont.fit.resBasisSet.(which).(['np_sw_' num2str(MRSCont.processed.metab{kk}.sz(1)) '_' num2str(MRSCont.processed.metab{kk}.spectralwidth)]){basis,1,subspectrum}; + basisSetNames = basisSet.name; + subSpecName = basisSet.names{1}; end end - % Larger fonts for the results + % Number of metabolites and lipid/MM basis functions + nMets = MRSCont.fit.basisSet.nMets; + nMMLip = MRSCont.fit.basisSet.nMM; + % Larger fonts for the results resultsFontSize = 11; end - - - ph0 = MRSCont.fit.results.(which).fitParams{1,kk}.ph0; - ph1 = MRSCont.fit.results.(which).fitParams{1,kk}.ph1; - - if ~strcmp(which, 'ref') && ~strcmp(which, 'w') - refShift = MRSCont.fit.results.(which).fitParams{1,kk}.refShift; - refFWHM = MRSCont.fit.results.(which).fitParams{1,kk}.refFWHM; - end % Build output folder filename outputFolder = fullfile(MRSCont.outputFolder, 'Figures', 'OspreyFit'); [~,filename,~] = fileparts(MRSCont.files{kk}); - if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(which, 'ref') || strcmp(which, 'w') %Is not concateneted or is reference/water fit - which = which; - else %Is concatenated and not water/reference - spec = which; - which = 'conc'; - end - Plot = uix.HBox('Parent', input_figure, 'Padding', 5,'BackgroundColor',colormapfig.Background); set(input_figure, 'Heights', [-0.12 -0.88]); - % Get parameter from file to fill the info panel - if ~strcmp (which, 'ref') && ~strcmp (which, 'w') %Metabolite data? - StatText = ['Metabolite Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... - '\nFitting range: ' num2str(MRSCont.opts.fit.range(1)) ' to ' num2str(MRSCont.opts.fit.range(2)) ' ppm; Baseline knot spacing: ' num2str(MRSCont.opts.fit.bLineKnotSpace) ' ppm; ph0: ' num2str(ph0,'%1.2f'),... - 'deg; ph1: ' num2str(ph1,'%1.2f') 'deg; refShift: ' num2str(refShift,'%1.2f') ' Hz; refFWHM: ' num2str(refFWHM,'%1.2f')... - ' ppm\nNumber of metabolites: ' num2str(nMets) '; Number of MM/lipids: ' num2str(nMMLip) ... - ' scale: ' num2str(MRSCont.fit.scale{kk})]; - else if strcmp (which, 'ref') %Reference data? - StatText = ['Reference Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... - '\n' waterFitRangeString]; - else %Is water data - StatText = ['Water Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... - '\n' waterFitRangeString]; - end - end - %%% 2.cc FILLING FITTED AMPLITUDE PANEL %%% % Creates the panel on the right side with the fitted amplitudes - InfoText = uicontrol('Parent',Info,'style','text',... - 'FontSize', 12, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(StatText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); - Results = uix.Panel('Parent', Plot,... - 'Title', ['Raw Amplitudes'],'FontName', font,'HighlightColor', colormapfig.Foreground,... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground, 'ShadowColor', colormapfig.Foreground); if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(which, 'ref') || strcmp(which, 'w') %Is not concateneted or is reference/water fit - Style = which; - switch MRSCont.opts.fit.method - case 'LCModel' - if strcmp(which, 'ref') || strcmp(which, 'w') - RawAmpl = MRSCont.fit.results.off.fitParams{1,kk}.h2oarea .* MRSCont.fit.scale{kk}; - else - RawAmpl = MRSCont.fit.results.(which).fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}; - CRLB = MRSCont.fit.results.(which).fitParams{1,kk}.CRLB; - end - case 'Osprey' - RawAmpl = MRSCont.fit.results.(which).fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}; + switch MRSCont.opts.fit.method + case 'LCModel' + if strcmp(which, 'ref') || strcmp(which, 'w') + RawAmpl = MRSCont.fit.results.(which).fitParams{1,kk}.h2oarea .* MRSCont.fit.scale{kk}; + else + RawAmpl = MRSCont.fit.results.(which).fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}; + CRLB = MRSCont.fit.results.(which).fitParams{1,kk}.CRLB; + end + case 'Osprey' + RawAmpl = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.ampl .* MRSCont.fit.scale{kk}; + end + else %Is concatenated and not water/reference + which = 'conc'; end - else %Is concatenated and not water/reference - Style = 'conc'; - RawAmpl = MRSCont.fit.results.(Style).fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}; - end - - if ~(MRSCont.flags.hasRef || MRSCont.flags.hasWater) %Raw amplitudes are reported as no water/reference fitting was performed - if ~(strcmp(Style, 'ref') || strcmp(Style, 'w')) %Metabolite fit - NameText = ['']; - RawAmplText = ['']; - CRLBText = ['']; - for m = 1 : length(RawAmpl) %Names and Amplitudes - NameText = [NameText, [basisSetNames{m} ' \n']]; - RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; - if strcmp(MRSCont.opts.fit.method, 'LCModel') - CRLBText = [CRLBText, [num2str(CRLB(m), '%i') '%%\n']]; + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + ph0 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.ph0; + ph1 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.ph1; + if ~strcmp(which, 'ref') && ~strcmp(which, 'w') + refShift = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.refShift; + refFWHM = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.refFWHM; + switch MRSCont.opts.fit.method + case 'Osprey' + iniph0 = MRSCont.fit.results.(which).fitParams{1,kk}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(which).fitParams{1,kk}.prelimParams.ph1; + case 'LCModel' + iniph0 = nan; + iniph1 = nan; end end - else %Water/reference fit but this should never happen in this loop - NameText = ['Water: ' ]; - RawAmplText = [num2str(RawAmpl,'%1.2e')]; - end - set(Results, 'Title', ['Raw Amplitudes']); - FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); - FitTextNames = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); - FitTextAmpl = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); - if strcmp(MRSCont.opts.fit.method, 'LCModel') - FitTextCRLB = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(CRLBText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + RawAmpl = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.ampl .* MRSCont.fit.scale{kk}; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + if ~strcmp(which, 'ref') && ~strcmp(which, 'w') + refShift = MRSCont.fit.results{1,Index(1)}.(which).fitParams{1,kk}.refShift; + refFWHM = MRSCont.fit.results{1,Index(1)}.(which).fitParams{1,kk}.refFWHM; + ph0 = MRSCont.fit.results{1,Index(1)}.(which).fitParams{1,kk}.ph0; + ph1 = MRSCont.fit.results{1,Index(1)}.(which).fitParams{1,kk}.ph1; + switch MRSCont.opts.fit.method + case 'Osprey' + iniph0 = MRSCont.fit.results.(which).fitParams{1,kk}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(which).fitParams{1,kk}.prelimParams.ph1; + case 'LCModel' + iniph0 = nan; + iniph1 = nan; + end + end + RawAmpl = MRSCont.fit.results{1,Index(1)}.(which).fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}; + else + if ~strcmp(which, 'ref') && ~strcmp(which, 'w') + refShift = MRSCont.fit.results{Index(1),Index(2)}.(which).fitParams{1,kk}.refShift; + refFWHM = MRSCont.fit.results{Index(1),Index(2)}.(which).fitParams{1,kk}.refFWHM; + ph0 = MRSCont.fit.results{Index(1),Index(2)}.(which).fitParams{1,kk}.ph0; + ph1 = MRSCont.fit.results{Index(1),Index(2)}.(which).fitParams{1,kk}.ph1; + switch MRSCont.opts.fit.method + case 'Osprey' + iniph0 = MRSCont.fit.results.(which).fitParams{1,kk}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(which).fitParams{1,kk}.prelimParams.ph1; + case 'LCModel' + iniph0 = nan; + iniph1 = nan; + end + end + RawAmpl = MRSCont.fit.results{1,Index(1)}.(which).fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}; end - else %If water/reference data is fitted Raw amplitudes are calculated with regard to water - if ~(strcmp(Style, 'ref') || strcmp(Style, 'w')) %Metabolite fit - switch MRSCont.opts.fit.method + % Get parameter from file to fill the info panel + if ~strcmp (which, 'ref') && ~strcmp (which, 'w') %Metabolite data + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + switch MRSCont.opts.fit.method case 'Osprey' + iniph0 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.prelimParams.ph1; + case 'LCModel' + iniph0 = nan; + iniph1 = nan; + end + StatText = ['Metabolite Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... + '\nFitting range: ' num2str(MRSCont.opts.fit.range(1)) ' to ' num2str(MRSCont.opts.fit.range(2)) ' ppm; Baseline knot spacing: ' num2str(MRSCont.opts.fit.bLineKnotSpace) ' ppm; ph0: ' num2str(ph0,'%1.2f'),... + 'deg; ph1: ' num2str(ph1,'%1.2f') 'deg; refShift: ' num2str(refShift,'%1.2f') ' Hz; refFWHM: ' num2str(refFWHM,'%1.2f')... + ' ppm\nNumber of metabolites: ' num2str(nMets) '; Number of MM/lipids: ' num2str(nMMLip) ... + ' scale: ' num2str(MRSCont.fit.scale{kk})]; + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + switch MRSCont.opts.fit.method + case 'Osprey' + iniph0 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.prelimParams.ph1; + case 'LCModel' + iniph0 = nan; + iniph1 = nan; + end + StatText = ['Metabolite Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... + '\nFitting range: ' num2str(MRSCont.opts.fit.range(1)) ' to ' num2str(MRSCont.opts.fit.range(2)) ' ppm; Baseline knot spacing: ' num2str(MRSCont.opts.fit.bLineKnotSpace) ' ppm; ph0: ' num2str(ph0,'%1.2f'),... + 'deg; ph1: ' num2str(ph1,'%1.2f') 'deg; refShift: ' num2str(refShift,'%1.2f') ' Hz; refFWHM: ' num2str(refFWHM,'%1.2f')... + ' ppm\nNumber of metabolites: ' num2str(nMets) '; Number of MM/lipids: ' num2str(nMMLip) ... + ' scale: ' num2str(MRSCont.fit.scale{kk})]; + else + switch MRSCont.opts.fit.method + case 'Osprey' + iniph0 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.prelimParams.ph0; + iniph1 = MRSCont.fit.results.(which).fitParams{basis,kk,subspectrum}.prelimParams.ph1; + case 'LCModel' + iniph0 = nan; + iniph1 = nan; + end + StatText = ['Metabolite Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... + '\nFitting range: ' num2str(MRSCont.opts.fit.range(1)) ' to ' num2str(MRSCont.opts.fit.range(2)) ' ppm; Baseline knot spacing: ' num2str(MRSCont.opts.fit.bLineKnotSpace) ' ppm; ph0: ' num2str(ph0,'%1.2f'),... + 'deg; ph1: ' num2str(ph1,'%1.2f') 'deg; refShift: ' num2str(refShift,'%1.2f') ' Hz; refFWHM: ' num2str(refFWHM,'%1.2f')... + ' ppm\nNumber of metabolites: ' num2str(nMets) '; Number of MM/lipids: ' num2str(nMMLip) ... + ' scale: ' num2str(MRSCont.fit.scale{kk})]; + end + + else if strcmp (which, 'ref') %Reference data? + StatText = ['Reference Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... + '\nFitting range: ' num2str(MRSCont.opts.fit.rangeWater(1)) ' to ' num2str(MRSCont.opts.fit.rangeWater(2)) ' ppm']; + else %Is water data + StatText = ['Water Data -> Sequence: ' Seq '; Fitting algorithm: ' MRSCont.opts.fit.method '; Fitting Style: ' MRSCont.opts.fit.style '; Selected subspecs: ' which,... + '\nFitting range: ' num2str(MRSCont.opts.fit.rangeWater(1)) ' to ' num2str(MRSCont.opts.fit.rangeWater(2)) ' ppm']; + end + end + %%% 4. FILLING FITTED AMPLITUDE PANEL %%% + % Creates the panel on the right side with the fitted ammplitudes + InfoText = uicontrol('Parent',Info,'style','text',... + 'FontSize', 12, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(StatText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + Results = uix.Panel('Parent', Plot,... + 'Title', ['Raw Amplitudes'],'FontName', font,'HighlightColor', colormapfig.Foreground,... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground, 'ShadowColor', colormapfig.Foreground); + if ~(isfield(MRSCont.flags,'isPRIAM') || isfield(MRSCont.flags,'isMRSI')) || ~(MRSCont.flags.isPRIAM || MRSCont.flags.isMRSI) + if ~(MRSCont.flags.hasRef || MRSCont.flags.hasWater) %Raw amplitudes are reported as no water/reference fitting was performed + if ~(strcmp(which, 'ref') || strcmp(which, 'w')) %Metabolite fit + NameText = ['']; + RawAmplText = ['']; + CRLBText = ['']; + for m = 1 : length(RawAmpl) %Names and Amplitudes + NameText = [NameText, [basisSetNames{m} ' \n']]; + RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; + if strcmp(MRSCont.opts.fit.method, 'LCModel') + CRLBText = [CRLBText, [num2str(CRLB(m), '%i') '%%\n']]; + end + end + else %Water/reference fit but this should never happen in this loop + NameText = ['Water: ' ]; + RawAmplText = [num2str(RawAmpl,'%1.2e')]; + end + set(Results, 'Title', ['Raw Amplitudes']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + else %If water/reference data is fitted Raw amplitudes are calculated with regard to water + if ~(strcmp(which, 'ref') || strcmp(which, 'w')) %Metabolite fit + switch MRSCont.opts.fit.method + case 'Osprey' + if MRSCont.flags.hasRef %Calculate Raw Water Scaled amplitudes + RawAmpl = RawAmpl ./ (MRSCont.fit.results.ref.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); + else + RawAmpl = RawAmpl ./ (MRSCont.fit.results.water.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); + end + case 'LCModel' + end + NameText = ['']; + RawAmplText = ['']; + CRLBText = ['']; + for m = 1 : length(RawAmpl) %Names and Amplitudes + NameText = [NameText, [basisSetNames{m} ' \n']]; + RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; + if strcmp(MRSCont.opts.fit.method, 'LCModel') + CRLBText = [CRLBText, [num2str(CRLB(m), '%i') '%%\n']]; + end + end + set(Results, 'Title', ['Raw Water Ratio']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + else %Water/reference fit + NameText = ['Water: ' ]; + RawAmplText = [num2str(RawAmpl,'%1.2e')]; + set(Results, 'Title', ['Raw Amplitudes']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + end + end + elseif isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + if ~(MRSCont.flags.hasRef || MRSCont.flags.hasWater) %Raw amplitudes are reported as no water/reference fitting was performed + if ~(strcmp(which, 'ref') || strcmp(which, 'w')) %Metabolite fit + NameText = ['']; + RawAmplText = ['']; + for m = 1 : length(RawAmpl) %Names and Amplitudes + NameText = [NameText, [MRSCont.fit.resBasisSet{Index(1),Index(2)}.(which).(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name{m} ': \n']]; + RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; + end + else %Water/reference fit but this should never happen in this loop + NameText = ['Water: ' ]; + RawAmplText = [num2str(RawAmpl,'%1.2e')]; + end + set(Results, 'Title', ['Raw Amplitudes']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + else %If water/reference data is fitted Raw amplitudes are calculated with regard to water + if ~(strcmp(which, 'ref') || strcmp(which, 'w')) %Metabolite fit if MRSCont.flags.hasRef %Calculate Raw Water Scaled amplitudes - RawAmpl = RawAmpl ./ (MRSCont.fit.results.ref.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); + RawAmpl = RawAmpl ./ (MRSCont.fit.results{1,Index(1)}.ref.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); else - RawAmpl = RawAmpl ./ (MRSCont.fit.results.w.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); + RawAmpl = RawAmpl ./ (MRSCont.fit.results{1,Index(1)}.w.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); end - case 'LCModel' - end - NameText = ['']; - RawAmplText = ['']; - CRLBText = ['']; - for m = 1 : length(RawAmpl) %Names and Amplitudes - NameText = [NameText, [basisSetNames{m} ' \n']]; - RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; - if strcmp(MRSCont.opts.fit.method, 'LCModel') - CRLBText = [CRLBText, [num2str(CRLB(m), '%i') '%%\n']]; + NameText = ['']; + RawAmplText = ['']; + for m = 1 : length(RawAmpl) %Names and Amplitudes + NameText = [NameText, [MRSCont.fit.resBasisSet{1,Index(1)}.(which).(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name{m} ': \n']]; + RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; + end + set(Results, 'Title', ['Raw Water Ratio']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + else %Water/reference fit + NameText = ['Water: ' ]; + RawAmplText = [num2str(RawAmpl,'%1.2e')]; + set(Results, 'Title', ['Raw Amplitudes']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); end - end - set(Results, 'Title', ['Raw Water Ratio']); - FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); - FitTextNames = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); - FitTextAmpl = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); - if strcmp(MRSCont.opts.fit.method, 'LCModel') - FitTextCRLB = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(CRLBText),... + else + if ~(MRSCont.flags.hasRef || MRSCont.flags.hasWater) %Raw amplitudes are reported as no water/reference fitting was performed + if ~(strcmp(which, 'ref') || strcmp(which, 'w')) %Metabolite fit + NameText = ['']; + RawAmplText = ['']; + for m = 1 : length(RawAmpl) %Names and Amplitudes + NameText = [NameText, [MRSCont.fit.resBasisSet{Index(1),Index(2)}.(which).(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name{m} ': \n']]; + RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; + end + else %Water/reference fit but this should never happen in this loop + NameText = ['Water: ' ]; + RawAmplText = [num2str(RawAmpl,'%1.2e')]; + end + set(Results, 'Title', ['Raw Amplitudes']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + else %If water/reference data is fitted Raw amplitudes are calculated with regard to water + if ~(strcmp(which, 'ref') || strcmp(which, 'w')) %Metabolite fit + if MRSCont.flags.hasRef %Calculate Raw Water Scaled amplitudes + RawAmpl = RawAmpl ./ (MRSCont.fit.results{1,Index(1)}.ref.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); + else + RawAmpl = RawAmpl ./ (MRSCont.fit.results{1,Index(1)}.w.fitParams{1,kk}.ampl .* MRSCont.fit.scale{kk}); + end + NameText = ['']; + RawAmplText = ['']; + for m = 1 : length(RawAmpl) %Names and Amplitudes + NameText = [NameText, [MRSCont.fit.resBasisSet{1,Index(1)}.(which).(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name{m} ': \n']]; + RawAmplText = [RawAmplText, [num2str(RawAmpl(m),'%1.2e') '\n']]; + end + set(Results, 'Title', ['Raw Water Ratio']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + else %Water/reference fit + NameText = ['Water: ' ]; + RawAmplText = [num2str(RawAmpl,'%1.2e')]; + set(Results, 'Title', ['Raw Amplitudes']); + FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); + FitTextNames = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + FitTextAmpl = uicontrol('Parent',FitText,'style','text',... + 'FontSize', 11, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... + 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); + end end - - else %Water/reference fit - NameText = ['Water: ' ]; - RawAmplText = [num2str(RawAmpl,'%1.2e')]; - set(Results, 'Title', ['Raw Amplitudes']); - FitText = uix.HBox('Parent', Results, 'Padding', 5,'BackgroundColor',colormapfig.Background); - FitTextNames = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(NameText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); - FitTextAmpl = uicontrol('Parent',FitText,'style','text',... - 'FontSize', resultsFontSize, 'FontName', font,'HorizontalAlignment', 'left', 'String', sprintf(RawAmplText),... - 'BackgroundColor',colormapfig.Background,'ForegroundColor', colormapfig.Foreground); end - end %%% 5. VISUALIZATION PART OF THIS TAB %%% %osp_plotFit is used to visualize the fits (off,diff1,diff2,sum,ref,water) temp = figure( 'Visible', 'off' ); if ~strcmp (MRSCont.opts.fit.style, 'Concatenated') || strcmp(which, 'ref') || strcmp(which, 'w') %Is not concateneted or is reference/water fit - temp = osp_plotFit(MRSCont, kk, Style); - else %Is concatenated and not water/reference - temp = osp_plotFit(MRSCont, kk, Style, 1, spec); + temp = osp_plotFit(MRSCont, kk, which,[1 subspectrum basis],which); end ViewAxes = gca(); set(ViewAxes, 'Parent', Plot ); @@ -536,7 +761,7 @@ set(Plot,'Widths', [-0.16 -0.84]); set(Plot.Children(2), 'Units', 'normalized'); set(Plot.Children(2), 'OuterPosition', [0.17,0.02,0.75,0.98]) - outputFile = [filename '_OspreyFit_' Style '_' which '.pdf']; + outputFile = [filename '_OspreyFit_' which '_' subSpecName '_basis_' num2str(basis) '.pdf']; case {'OspreyCoreg','OspreySeg'} %Coreg/Seg @@ -599,7 +824,7 @@ outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyOverview','Individual'); outputFile = [which '.pdf']; for g = 1 : MRSCont.overview.NoGroups %Loop over groups - temp = osp_plotOverviewSpec(MRSCont, which, g, 0.1); + temp = osp_plotOverviewSpec(MRSCont, which, g, 0.1,'Frequency (ppm)','','',Index); if g == 1 fig_hold = temp; set(fig_hold,'Tag','fig_hold'); @@ -634,7 +859,7 @@ outputFile = [which '.pdf']; for g = 1 : MRSCont.overview.NoGroups %Loop over groups if MRSCont.overview.NoGroups > 1 - temp = osp_plotMeanSpec(MRSCont, which,g,0.1,1); + temp = osp_plotMeanSpec(MRSCont, which,g,1,1/MRSCont.overview.NoGroups); if g == 1 fig_hold = temp; else @@ -669,15 +894,15 @@ set(input_figure, 'Heights', [-0.1 -0.9]); outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyOverview', 'Raincloud'); split_which = strsplit(which,'-'); - if strcmp(split_which{2},'AlphaCorrWaterScaled') || strcmp(split_which{2},'AlphaCorrWaterScaledGroupNormed') + if strcmp(split_which{3},'AlphaCorrWaterScaled') || strcmp(split_which{3},'AlphaCorrWaterScaledGroupNormed') metab = 'GABA'; end - fig_hold = osp_plotRaincloud(MRSCont,split_which{1},split_which{2},metab,'Raincloud plot'); + fig_hold = osp_plotRaincloud(MRSCont,split_which{2},split_which{3},metab,'Raincloud plot',0,Index(1),Index(2)); delete( fig_hold.Children(1)); set(fig_hold.Children,'Children',flipud(fig_hold.Children.Children)); set( fig_hold.Children, 'Parent', Plot ); close(fig_hold); - outputFile = [metab '_' split_which{1} '_' split_which{2} '.pdf']; + outputFile = [metab '_' split_which{1} '_' split_which{2} '_' split_which{3} '.pdf']; case 'OspreyScatterOverview' %Correlation plot set(Info,'Title', 'Descriptive Information'); groupString = ''; @@ -694,23 +919,23 @@ set(input_figure, 'Heights', [-0.1 -0.9]); outputFolder = fullfile(MRSCont.outputFolder,'Figures','OspreyOverview', 'Correlation'); split_which = strsplit(which,'-'); - if strcmp(split_which{2},'AlphaCorrWaterScaled') || strcmp(split_which{2},'AlphaCorrWaterScaledGroupNormed') + if strcmp(split_which{3},'AlphaCorrWaterScaled') || strcmp(split_which{3},'AlphaCorrWaterScaledGroupNormed') metab = 'GABA'; end MRSCont.flags.isGUI = 0; split_corr = strsplit(corr,'-'); if strcmp(split_corr{1},'corr') - fig_hold = osp_plotScatter(MRSCont,split_which{1},split_which{2},metab,MRSCont.overview.corr.Meas{str2num(split_corr{2})},MRSCont.overview.corr.Names{str2num(split_corr{2})}); - outputFile = [metab '_' split_which{1} '_' split_which{2} '_' MRSCont.overview.corr.Names{str2num(split_corr{2})} '.pdf']; + fig_hold = osp_plotScatter(MRSCont,split_which{2},split_which{3},metab,MRSCont.overview.corr.Meas{str2num(split_corr{2})},MRSCont.overview.corr.Names{str2num(split_corr{2})},1,Index(1)); + outputFile = [metab '_' split_which{2} '_' split_which{3} '_basis' num2str(Index(1)) '_' MRSCont.overview.corr.Names{str2num(split_corr{2})} '.pdf']; else if strcmp(split_corr{1},'metab') - fig_hold = osp_plotScatter(MRSCont,split_which{1},split_which{2},metab,MRSCont.overview.corr.Names{str2num(split_corr{1})},metab); - outputFile = [metab '_' split_which{1} '_' split_which{2} '_' metab '.pdf']; + fig_hold = osp_plotScatter(MRSCont,split_which{1},split_which{2},metab,MRSCont.overview.corr.Names{str2num(split_corr{1})},1,Index(1),1,Index(1)); + outputFile = [metab '_' split_which{2} '_' split_which{3} '_basis' num2str(Index(1)) '_' metab '.pdf']; else if strcmp(split_corr{1},'SNR') - fig_hold = osp_plotScatter(MRSCont,split_which{1},split_which{2},metab,MRSCont.QM.SNR.A','SNR Subspectrum A'); - outputFile = [metab '_' split_which{1} '_' split_which{2} '_SNR.pdf']; + fig_hold = osp_plotScatter(MRSCont,split_which{2},split_which{3},metab,MRSCont.QM.SNR.metab(1,:,Index(1))','SNR Subspectrum A',1,Index(1)); + outputFile = [metab '_' split_which{2} '_' split_which{3} '_basis' num2str(Index(1)) '_SNR.pdf']; else if strcmp(split_corr{1},'FWHM') - fig_hold = osp_plotScatter(MRSCont,split_which{1},split_which{2},metab,MRSCont.QM.FWHM.A','FWHM (Hz)'); - outputFile = [metab '_' split_which{1} '_' split_which{2} '_FWHM.pdf']; + fig_hold = osp_plotScatter(MRSCont,split_which{2},split_which{3},metab,MRSCont.QM.FWHM.metab(1,:,Index(1))','FWHM (Hz)',1,Index(1)); + outputFile = [metab '_' split_which{2} '_' split_which{3} '_basis' num2str(Index(1)) '_FWHM.pdf']; end end end diff --git a/plot/osp_plotOverviewSpec.m b/plot/osp_plotOverviewSpec.m index e47d588e..978e15ef 100644 --- a/plot/osp_plotOverviewSpec.m +++ b/plot/osp_plotOverviewSpec.m @@ -1,5 +1,5 @@ -function out = osp_plotOverviewSpec(MRSCont, which_spec, g, shift, xlab, ylab, figTitle) -%% out = osp_plotOverviewSpec(MRSCont, which_spec, g, shift, xlab, ylab, figTitle) +function out = osp_plotOverviewSpec(MRSCont, which_spec, g, shift, xlab, ylab, figTitle, basis) +%% out = osp_plotOverviewSpec(MRSCont, which_spec, g, shift, xlab, ylab, figTitle, basis) % Creates a figure with all spectra or fits. % % USAGE: @@ -55,20 +55,23 @@ %%% 1. PARSE INPUT ARGUMENTS %%% fitStyle = MRSCont.opts.fit.style; % Fall back to defaults if not provided -if nargin<7 -ylab=''; - if nargin<6 - xlab='Frequency (ppm)'; - if nargin<5 - group = 0; - if nargin<4 - shift = 0.1; - if nargin<3 - g = 1; - if nargin < 2 - which_spec = 'A'; - if nargin<1 - error('ERROR: no input Osprey container specified. Aborting!!'); +if nargin<8 + basis =1; + if nargin<7 + figTitle=[]; + if nargin<6 + ylab=''; + if nargin<5 + xlab='Frequency (ppm)'; + if nargin<4 + shift = 0.1; + if nargin<3 + g = 1; + if nargin < 2 + which_spec = 'metab A'; + if nargin<1 + error('ERROR: no input Osprey container specified. Aborting!!'); + end end end end @@ -77,19 +80,14 @@ end end - if strcmp(which_spec,'MM') %re_mm - which_spec = 'mm'; %re_mm - end %re_mm % Check version of Osprey - since we have changed the layout of the Overview struct with the implementation of DualVoxel if isfield(MRSCont.overview.Osprey, 'sort_data') sort_data = 'sort_data'; sort_fit = 'sort_fit'; - mm = 'all_models'; else sort_data = 'sort_data_voxel_1'; - sort_fit = 'sort_fit_voxel_1'; - mm = 'all_models_voxel_1'; + sort_fit = 'sort_models_voxel_1'; end %%% 2. EXTRACT DATA TO PLOT %%% @@ -102,190 +100,104 @@ GroupString = 'GMean'; shift = 0; end - %Is spectrum? -if (strcmp(which_spec,'A') || strcmp(which_spec,'B') || strcmp(which_spec,'C') || strcmp(which_spec,'D') || strcmp(which_spec,'diff1') || strcmp(which_spec,'diff2') || strcmp(which_spec,'sum') ||strcmp(which_spec,'mm') || strcmp(which_spec,'ref') || strcmp(which_spec,'w')) - data = MRSCont.overview.Osprey.(sort_data).(GroupString).(which_spec); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_data_voxel_2.(GroupString).(which_spec); - end - if nargin<8 - if (~strcmp(which_spec,'w') && ~strcmp(which_spec,'ref')) - figTitle = ['Individual specs: ' which_spec]; - ppmRange = MRSCont.opts.fit.range; - else - figTitle = ['Individual specs: ' which_spec]; - ppmRange = MRSCont.opts.fit.rangeWater; - end - end -else % Is fit? - fitwhich = which_spec(5:end); - if MRSCont.flags.isUnEdited %Is UnEdited - switch fitwhich - case 'off' - fit = 'A'; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fitwhich '_' fit]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fitwhich '_' fit]); - end - case {'ref','w','mm'} - fit = fitwhich; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fitwhich '_' fit]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fitwhich '_' fit]); - end +which_spec_split = split(which_spec); +if length(which_spec_split) == 3 + fit = which_spec_split{1}; + spec = which_spec_split{2}; + subspec = which_spec_split{3}; +else + fit = []; + spec = which_spec_split{1}; + subspec = which_spec_split{2}; +end - case {'lean'} - fit = fitwhich; - data = MRSCont.overview.Osprey.(mm).mm_mm; - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.(mm).mm_mm; - end - end + +if isempty(fit) %Is data + if ~(strcmp(spec,'ref') || strcmp(spec,'w') || strcmp(spec,'mm_ref')) + ind = find(strcmp(MRSCont.overview.SubSpecNamesStruct.(spec),subspec)); + ppmRange = MRSCont.opts.fit.range; + else + ind =1; + ppmRange = MRSCont.opts.fit.rangeWater; end - if MRSCont.flags.isMEGA %Is MEGA - switch fitwhich - case {'diff1','sum'} - if strcmp(fitStyle,'Concatenated') %Is Concatenated? - fit = 'conc'; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fit '_' fitwhich]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fit '_' fitwhich]); - end - else - fit = 'diff1'; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fitwhich '_' fit]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fitwhich '_' fit]); - end - end - case {'off'} - fit = 'A'; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fitwhich '_' fit]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fitwhich '_' fit]); - end - case {'ref','w','mm'} - fit = fitwhich; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fit '_' fitwhich]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fit '_' fitwhich]); - end - end + data = MRSCont.overview.Osprey.(sort_data).(GroupString).(spec); + if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + data2 = MRSCont.overview.Osprey.sort_data_voxel_2.(GroupString).(spec); end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) %Is Multiplexed - switch fitwhich - case {'diff1','diff2','sum'} - if strcmp(fitStyle,'Concatenated') %Is Concatenated? - fit = 'conc'; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fit '_' fitwhich]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fit '_' fitwhich]); - end - else - fit = fitwhich; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fit '_' fitwhich]); - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fit '_' fitwhich]); - end - end - case {'ref','w'} - fit = fitwhich; - data = MRSCont.overview.Osprey.(sort_fit).(GroupString).([fitwhich '_' fit]); + if isempty(figTitle) + figTitle = ['Individual specs: ' spec ' ' subspec]; + end +else % Is fit + switch spec + case {'metab','mm'} + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.(spec)(basis,:),subspec)); + data = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['fit_' spec]); if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).([fitwhich '_' fit]); + data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).(spec); end - end - end - - if nargin<7 - if (~strcmp(fitwhich,'w') && ~strcmp(fitwhich,'ref')) - figTitle = ['Individual fits: ' fit ' ' fitwhich]; - ppmRange = MRSCont.opts.fit.range; - else - figTitle = ['Individual fits: ' fit ' ' fitwhich]; - ppmRange = MRSCont.opts.fit.rangeWater; - end + ppm=MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); + ppmRange = MRSCont.opts.fit.range; + case {'ref','w','mm_ref'} + data = MRSCont.overview.Osprey.(sort_fit).(GroupString).(['fit_' spec]); + if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM + data2 = MRSCont.overview.Osprey.sort_fit_voxel_2.(GroupString).(spec); + end + basis = 1; + ind = 1; + ppm=MRSCont.overview.Osprey.(sort_fit).(GroupString).(['ppm_fit_' spec]); + ppmRange = MRSCont.opts.fit.rangeWater; + end + if isempty(figTitle) + figTitle = ['Individual fits: ' spec ' ' fit]; end end out = figure; %%% 3. PLOT DATA %%% -if length(which_spec)>4 - if ~strcmp(which_spec(1:4),'MM_c') %re_mm - if ~strcmp(which_spec(1:4),'Fit:') - maxshift_abs = max(abs(data{1}.specs)); +if ~isempty(fit) %Is fit + maxshift_abs = max(abs(data(:,:,basis,ind))); shift = maxshift_abs * shift; - plot(data{1}.ppm,data{1}.specs+shift ,'color', cb(g,:), 'LineWidth', 1); %data + + plot(ppm(basis,:,ind),data(1,:,basis,ind)+shift ,'color', cb(g,:), 'LineWidth', 1); %Fit hold on; - for kk = 2 : length(data) - plot(data{kk}.ppm,data{kk}.specs+shift ,'color', cb(g,:), 'LineWidth', 1); %data + if size(data,1) > 1 + for kk = 2 : size(data,1) + plot(ppm(basis,:,ind),data(kk,:,basis,ind)+shift ,'color', cb(g,:), 'LineWidth', 1); %Fit + end end if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - maxshift_abs = max(abs(data2{1}.specs)); - shift = maxshift_abs * shift + maxshift_abs*0.15; - plot(data2{1}.ppm,data2{1}.specs+shift ,':','color', cb(g,:), 'LineWidth', 2); %data + maxshift_abs = max(abs(data2{1}.fit)); + shift = maxshift_abs * shift+ maxshift_abs*0.15; + plot(data2{1}.ppm,data2{1}.fit+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %Fit hold on; - for kk = 2 : length(data2) - plot(data2{kk}.ppm,data2{kk}.specs+shift ,':','color', cb(g,:), 'LineWidth', 2); %data - end + if size(data2,1) > 1 + for kk = 2 : length(data2) + plot(data2{kk}.ppm,data2{kk}.fit+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %Fit + end + end end else - maxshift_abs = max(abs(data{1}.fit)); + maxshift_abs = max(abs(data{1}.specs(:,ind))); shift = maxshift_abs * shift; - plot(data{1}.ppm,data{1}.fit+shift ,'color', cb(g,:), 'LineWidth', 1); %Fit + plot(data{1}.ppm,data{1}.specs(:,ind)+shift ,'color', cb(g,:), 'LineWidth', 1); %data hold on; for kk = 2 : length(data) - plot(data{kk}.ppm,data{kk}.fit+shift ,'color', cb(g,:), 'LineWidth', 1); %Fit + plot(data{kk}.ppm,data{kk}.specs(:,ind)+shift ,'color', cb(g,:), 'LineWidth', 1); %data end if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - maxshift_abs = max(abs(data2{1}.fit)); - shift = maxshift_abs * shift+ maxshift_abs*0.15; - plot(data2{1}.ppm,data2{1}.fit+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %Fit + maxshift_abs = max(abs(data2{1}.specs)); + shift = maxshift_abs * shift + maxshift_abs*0.15; + plot(data2{1}.ppm,data2{1}.specs+shift ,':','color', cb(g,:), 'LineWidth', 2); %data hold on; for kk = 2 : length(data2) - plot(data2{kk}.ppm,data2{kk}.fit+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %Fit - end - end - end - else %re_mm - maxshift_abs = max(abs(data{1}.MM_clean)); - shift = maxshift_abs * shift; - plot(data{1}.ppm,data{1}.MM_clean+shift ,'color', cb(g,:), 'LineWidth', 1); %data - hold on; - for kk = 2 : length(data) - plot(data{kk}.ppm,data{kk}.MM_clean+shift ,'color', cb(g,:), 'LineWidth', 1); %data - end - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - maxshift_abs = max(abs(data2{1}.MM_clean)); - shift = maxshift_abs * shift+ maxshift_abs*0.15; - plot(data2{1}.ppm,data2{1}.MM_clean+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %data - hold on; - for kk = 2 : length(data2) - plot(data2{kk}.ppm,data2{kk}.MM_clean+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %data - end - end - end %re_mm -else - maxshift_abs = max(abs(data{1}.specs)); - shift = maxshift_abs * shift; - plot(data{1}.ppm,data{1}.specs+shift ,'color', cb(g,:), 'LineWidth', 1); %data - hold on; - for kk = 2 : length(data) - plot(data{kk}.ppm,data{kk}.specs+shift ,'color', cb(g,:), 'LineWidth', 1); %data - end - if isfield(MRSCont.flags,'isPRIAM') && MRSCont.flags.isPRIAM - maxshift_abs = max(abs(data2{1}.specs)); - shift = maxshift_abs * shift+ maxshift_abs*0.15; - plot(data2{1}.ppm,data2{1}.specs+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %data - hold on; - for kk = 2 : length(data2) - plot(data2{kk}.ppm,data2{kk}.specs+shift,':' ,'color', cb(g,:), 'LineWidth', 2); %data - end - end + plot(data2{kk}.ppm,data2{kk}.specs+shift ,':','color', cb(g,:), 'LineWidth', 2); %data + end + end end + %%% 4. DESIGN FINETUNING %%% % Adapt common style for all axes set(gca, 'XDir', 'reverse', 'XLim', [ppmRange(1), ppmRange(end)], 'XMinorTick', 'On'); diff --git a/plot/osp_plotProcess.m b/plot/osp_plotProcess.m index dfc67e47..679a4c2f 100755 --- a/plot/osp_plotProcess.m +++ b/plot/osp_plotProcess.m @@ -1,4 +1,4 @@ -function out = osp_plotProcess(MRSCont, kk, which_spec,VoxelIndex, ppmmin, ppmmax) +function out = osp_plotProcess(MRSCont, kk, which_spec,SubSpectraIndex,ExtraIndex,VoxelIndex, ppmmin, ppmmax) %% out = osp_plotProcess(MRSCont, kk, which, ppmmin, ppmmax) % Creates a figure showing processed data stored in an Osprey data container, % ie in the raw fields. This function will display the *processed and @@ -24,6 +24,7 @@ % 'sum' (for MEGA, HERMES, HERCULES) % 'ref' % 'w' +% ExtraIndex = Index for the extra dimension % VoxelIndex = Index for the Voxel % xlab = Label for the x-axis (optional. Default = 'Frequency (ppm)'); % ylab = label for the y-axis (optional. Default = ''); @@ -42,37 +43,43 @@ %%% 1. PARSE INPUT ARGUMENTS %%% % Fall back to defaults if not provided -if nargin<6 +if nargin<8 switch which_spec - case {'A', 'B', 'C', 'D', 'diff1', 'diff2','diff3', 'sum','mm'} + case {'A', 'B', 'C', 'D', 'diff1', 'diff2','diff3', 'sum','A_mm', 'B_mm', 'C_mm', 'D_mm', 'diff1_mm', 'diff2_mm','diff3_mm', 'sum_mm','mm','metab'} ppmmax = 4.2; - case {'ref', 'w'} + case {'ref', 'w','mm_ref'} ppmmax = 2*4.68; otherwise error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); end - if nargin<5 + if nargin<7 switch which_spec - case {'A', 'B', 'C', 'D', 'diff1', 'diff2','diff3', 'sum'} + case {'A', 'B', 'C', 'D', 'diff1', 'diff2','diff3', 'sum','metab'} ppmmin = 0.2; - case {'ref', 'w','mm'} + case {'ref', 'w','mm','mm_ref','A_mm', 'B_mm', 'C_mm', 'D_mm', 'diff1_mm', 'diff2_mm','diff3_mm', 'sum_mm','mm'} ppmmin = 0; otherwise error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); end - if nargin<4 + if nargin<6 if MRSCont.flags.isPRIAM VoxelIndex = 1; end if MRSCont.flags.isMRSI VoxelIndex = [1 1]; end - if nargin < 3 - which_spec = 'A'; - if nargin < 2 - kk = 1; - if nargin<1 - error('ERROR: no input Osprey container specified. Aborting!!'); + if nargin < 5 + ExtraIndex = 1; + if nargin<4 + SubSpectraIndex = 1; + if nargin < 3 + which_spec = 'A'; + if nargin < 2 + kk = 1; + if nargin<1 + error('ERROR: no input Osprey container specified. Aborting!!'); + end + end end end end @@ -90,6 +97,19 @@ colormap.Accent = [11/255 71/255 111/255]; end +% Pick right entries from the processed struct +switch which_spec + case {'A', 'B', 'C', 'D','diff1','diff2','diff3','sum','metab'} + which_sub_spec = MRSCont.processed.(which_spec){kk}.names{ExtraIndex,SubSpectraIndex}; + which_spec = 'metab'; + case {'A_mm', 'B_mm', 'C_mm', 'D_mm','diff1_mm','diff2_mm','diff3_mm','sum_mm','mm'} + which_sub_spec = MRSCont.processed.(which_spec){kk}.names{ExtraIndex,SubSpectraIndex}; + which_spec = 'mm'; + otherwise + which_sub_spec = which_spec; +end + + %%% 2. EXTRACT DATA TO PLOT %%% % Extract raw and processed spectra in the plot range @@ -176,6 +196,10 @@ rawDataToPlot=op_takeVoxel(MRSCont.raw_w{kk},VoxelIndex); procDataToPlot=op_takeVoxel(MRSCont.processed.(which_spec){kk},VoxelIndex); rawDataToScale = rawDataToPlot; + case 'mm_ref' + rawDataToPlot=op_takeVoxel(MRSCont.raw_w{kk},VoxelIndex); + procDataToPlot=op_takeVoxel(MRSCont.processed.(which_spec){kk},VoxelIndex); + rawDataToScale = rawDataToPlot; % This is used to get consistent yLims = rawDataToPlot; % This is used to get consistent yLims otherwise error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); @@ -183,81 +207,157 @@ else switch which_spec - case {'A', 'B', 'C', 'D'} - raw = MRSCont.raw{kk}; - procDataToPlot = MRSCont.processed.(which_spec){kk}; + case 'metab' + switch which_sub_spec + case {'A','B','C','D'} + raw = MRSCont.raw{ExtraIndex,kk}; + procDataToPlot = op_takeextra(MRSCont.processed.(which_spec){kk},ExtraIndex); + if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES || MRSCont.flags.isMEGA + procDataToPlot = op_takesubspec(procDataToPlot,find(strcmp(which_sub_spec,procDataToPlot.names))); + end + % Get sub-spectra, depending on whether they are stored as such + if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES + if raw.subspecs == 4 + names = {'A','B','C','D'}; + raw_A = op_takesubspec(raw,procDataToPlot.commuteOrder(1)); % Get first subspectrum + raw_B = op_takesubspec(raw,procDataToPlot.commuteOrder(2)); % Get second subspectrum + raw_C = op_takesubspec(raw,procDataToPlot.commuteOrder(3)); % Get third subspectrum + raw_D = op_takesubspec(raw,procDataToPlot.commuteOrder(4)); % Get fourth subspectrum + else + raw_A = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get first subspectrum + raw_B = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get second subspectrum + raw_C = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get third subspectrum + raw_D = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get fourth subspectrum + end + elseif MRSCont.flags.isMEGA + if raw.subspecs == 2 + raw_A = op_takesubspec(raw,1); % Get first subspectrum + raw_B = op_takesubspec(raw,2); % Get second subspectrum + else + raw_A = op_takeaverages(raw,1:2:raw.averages); % Get first subspectrum + raw_B = op_takeaverages(raw,2:2:raw.averages); % Get second subspectrum + end + if MRSCont.processed.metab{kk}.flags.orderswitched + temp_spec = raw_A; + raw_A = raw_B; + raw_B = temp_spec; + end + elseif MRSCont.flags.isUnEdited + raw_A = raw; % Get all averages + end - % Get sub-spectra, depending on whether they are stored as such - if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - if raw.subspecs == 4 - raw_A = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get first subspectrum - raw_B = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get second subspectrum - raw_C = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get third subspectrum - raw_D = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get fourth subspectrum - else - raw_A = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get first subspectrum - raw_B = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get second subspectrum - raw_C = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get third subspectrum - raw_D = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get fourth subspectrum - end - elseif MRSCont.flags.isMEGA - if raw.subspecs == 2 - raw_A = op_takesubspec(raw,1); % Get first subspectrum - raw_B = op_takesubspec(raw,2); % Get second subspectrum - else - raw_A = op_takeaverages(raw,1:2:raw.averages); % Get first subspectrum - raw_B = op_takeaverages(raw,2:2:raw.averages); % Get second subspectrum - end - if MRSCont.processed.diff1{kk}.flags.orderswitched - temp_spec = raw_A; - raw_A = raw_B; - raw_B = temp_spec; - end - elseif MRSCont.flags.isUnEdited - raw_A = raw; % Get all averages + eval(['rawDataToPlot = raw_' which_sub_spec ';']); + rawDataToScale = raw_A; % This is used to get consistent yLims + case {'diff1', 'diff2','diff3', 'sum'} + rawDataToPlot = MRSCont.raw{ExtraIndex,kk}; + procDataToPlot = op_takeextra(MRSCont.processed.(which_spec){kk},ExtraIndex); + procDataToPlot = op_takesubspec(procDataToPlot,find(strcmp(which_sub_spec,procDataToPlot.names))); + if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES + temp_spec = cat(3,rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(1)),rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(2)),... + rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(3)),rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(4))); + temp_fid = cat(3,rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(1)),rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(2)),... + rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(3)),rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(4))); + rawDataToPlot.fids = temp_fid; + rawDataToPlot.specs = temp_spec; + proc_A = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'A'))); % Get first subspectrum + proc_B = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'B'))); % Get second subspectrum + proc_C = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'C'))); % Get third subspectrum + proc_D = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'D'))); % Get fourth subspectrum + else + proc_A = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'A'))); % Get first subspectrum + proc_B = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'B'))); % Get second subspectrum + if procDataToPlot.flags.orderswitched + temp_spec = rawDataToPlot.specs(:,:,1); + rawDataToPlot.specs(:,:,1) = rawDataToPlot.specs(:,:,2); + rawDataToPlot.specs(:,:,2) = temp_spec; + temp_fids = rawDataToPlot.fids(:,:,1); + rawDataToPlot.fids(:,:,1) = rawDataToPlot.fids(:,:,2); + rawDataToPlot.fids(:,:,2) = temp_fids; + end + end + rawDataToScale = rawDataToPlot; % This is used to get consistent yLims end + case 'mm' %re_mm + switch which_sub_spec + case {'A','B','C','D'} + raw = MRSCont.raw_mm{ExtraIndex,kk}; %re_mm + procDataToPlot = op_takeextra(MRSCont.processed.mm{kk},ExtraIndex); %re_mm + if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES || MRSCont.flags.isMEGA + procDataToPlot = op_takesubspec(procDataToPlot,find(strcmp(which_sub_spec,procDataToPlot.names))); + end + % Get sub-spectra, depending on whether they are stored as such + if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES + if raw.subspecs == 4 + raw_A = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get first subspectrum + raw_B = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get second subspectrum + raw_C = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get third subspectrum + raw_D = op_takesubspec(raw,procDataToPlot.commuteOrder); % Get fourth subspectrum + else + raw_A = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get first subspectrum + raw_B = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get second subspectrum + raw_C = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get third subspectrum + raw_D = op_takeaverages(raw,procDataToPlot.commuteOrder:4:raw.averages); % Get fourth subspectrum + end + elseif MRSCont.flags.isMEGA + if raw.subspecs == 2 + raw_A = op_takesubspec(raw,1); % Get first subspectrum + raw_B = op_takesubspec(raw,2); % Get second subspectrum + else + raw_A = op_takeaverages(raw,1:2:raw.averages); % Get first subspectrum + raw_B = op_takeaverages(raw,2:2:raw.averages); % Get second subspectrum + end + if MRSCont.processed.metab{kk}.flags.orderswitched + temp_spec = raw_A; + raw_A = raw_B; + raw_B = temp_spec; + end + elseif MRSCont.flags.isUnEdited + raw_A = raw; % Get all averages + end - eval(['rawDataToPlot = raw_' which_spec ';']); - rawDataToScale = raw_A; % This is used to get consistent yLims - case {'diff1', 'diff2','diff3', 'sum'} - rawDataToPlot = MRSCont.raw{kk}; - procDataToPlot = MRSCont.processed.(which_spec){kk}; - if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - temp_spec = cat(3,rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(1)),rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(2)),... - rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(3)),rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(4))); - temp_fid = cat(3,rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(1)),rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(2)),... - rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(3)),rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(4))); - rawDataToPlot.fids = temp_fid; - rawDataToPlot.specs = temp_spec; - proc_A = MRSCont.processed.A{kk}; % Get first subspectrum - proc_B = MRSCont.processed.B{kk}; % Get second subspectrum - proc_C = MRSCont.processed.C{kk}; % Get third subspectrum - proc_D = MRSCont.processed.D{kk}; % Get fourth subspectrum - else - proc_A = MRSCont.processed.A{kk}; % Get first subspectrum - proc_B = MRSCont.processed.B{kk}; % Get second subspectrum - if procDataToPlot.flags.orderswitched - temp_spec = rawDataToPlot.specs(:,:,1); - rawDataToPlot.specs(:,:,1) = rawDataToPlot.specs(:,:,2); - rawDataToPlot.specs(:,:,2) = temp_spec; - temp_fids = rawDataToPlot.fids(:,:,1); - rawDataToPlot.fids(:,:,1) = rawDataToPlot.fids(:,:,2); - rawDataToPlot.fids(:,:,2) = temp_fids; + eval(['rawDataToPlot = raw_' which_sub_spec ';']); + rawDataToScale = raw_A; % This is used to get consistent yLims + case {'diff1', 'diff2','diff3', 'sum'} + rawDataToPlot = MRSCont.raw_mm{ExtraIndex,kk}; %re_mm + procDataToPlot = op_takeextra(MRSCont.processed.mm{kk},ExtraIndex); %re_mm + procDataToPlot = op_takesubspec(procDataToPlot,find(strcmp(which_sub_spec,procDataToPlot.names))); + if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES + temp_spec = cat(3,rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(1)),rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(2)),... + rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(3)),rawDataToPlot.specs(:,:,procDataToPlot.commuteOrder(4))); + temp_fid = cat(3,rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(1)),rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(2)),... + rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(3)),rawDataToPlot.fids(:,:,procDataToPlot.commuteOrder(4))); + rawDataToPlot.fids = temp_fid; + rawDataToPlot.specs = temp_spec; + proc_A = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'A'))); % Get first subspectrum + proc_B = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'B'))); % Get second subspectrum + proc_C = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'C'))); % Get third subspectrum + proc_D = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'D'))); % Get fourth subspectrum + else + proc_A = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'A'))); % Get first subspectrum + proc_B = op_takesubspec(MRSCont.processed.(which_spec){ExtraIndex,kk},find(strcmp(which_sub_spec,'B'))); % Get second subspectrum + if procDataToPlot.flags.orderswitched + temp_spec = rawDataToPlot.specs(:,:,1); + rawDataToPlot.specs(:,:,1) = rawDataToPlot.specs(:,:,2); + rawDataToPlot.specs(:,:,2) = temp_spec; + temp_fids = rawDataToPlot.fids(:,:,1); + rawDataToPlot.fids(:,:,1) = rawDataToPlot.fids(:,:,2); + rawDataToPlot.fids(:,:,2) = temp_fids; + end end - end - rawDataToScale = rawDataToPlot; % This is used to get consistent yLims - case 'mm' %re_mm - rawDataToPlot = MRSCont.raw_mm{kk}; %re_mm - procDataToPlot = MRSCont.processed.mm{kk}; %re_mm - rawDataToScale = rawDataToPlot; %re_mm % This is used to get consistent yLims + rawDataToScale = rawDataToPlot; % This is used to get consistent yLims + end case 'ref' - rawDataToPlot = MRSCont.raw_ref{kk}; - procDataToPlot = MRSCont.processed.ref{kk}; + rawDataToPlot = MRSCont.raw_ref{ExtraIndex,kk}; + procDataToPlot = op_takeextra(MRSCont.processed.ref{kk},ExtraIndex); rawDataToScale = rawDataToPlot; % This is used to get consistent yLims case 'w' - rawDataToPlot = MRSCont.raw_w{kk}; - procDataToPlot = MRSCont.processed.w{kk}; + rawDataToPlot = MRSCont.raw_w{ExtraIndex,kk}; + procDataToPlot = op_takeextra(MRSCont.processed.w{kk},ExtraIndex); rawDataToScale = rawDataToPlot; + case 'mm_ref' + rawDataToPlot = MRSCont.raw_mm_ref{ExtraIndex,kk}; + procDataToPlot = op_takeextra(MRSCont.processed.mm_ref{kk},ExtraIndex); + rawDataToScale = rawDataToPlot; % This is used to get consistent yLims = rawDataToPlot; % This is used to get consistent yLims otherwise error('Input for variable ''which'' not recognized. Needs to be ''mets'' (metabolite data), ''ref'' (reference data), or ''w'' (short-TE water data).'); @@ -282,7 +382,7 @@ % Generate global yLimits applyDataToScale = rawDataToScale; t = rawDataToScale.t; -switch which_spec +switch which_sub_spec case {'A', 'B', 'C', 'D'} if (isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) fs = procDataToPlot.specReg{VoxelIndex}.fs; @@ -291,8 +391,8 @@ fs = procDataToPlot.specReg{VoxelIndex(1), VoxelIndex(2)}.fs; phs = procDataToPlot.specReg{VoxelIndex(1), VoxelIndex(2)}.phs; else - fs = procDataToPlot.specReg.fs; - phs = procDataToPlot.specReg.phs; + fs = procDataToPlot.specReg{1}.fs(:,SubSpectraIndex); + phs = procDataToPlot.specReg{1}.phs(:,SubSpectraIndex); end case {'diff1', 'diff2','diff3', 'sum'} if (isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) @@ -331,35 +431,35 @@ end else if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - fs{1} = proc_A.specReg.fs; - phs{1} = proc_A.specReg.phs; - fs{2} = proc_B.specReg.fs; - phs{2} = proc_B.specReg.phs; - fs{3} = proc_C.specReg.fs; - phs{3} = proc_C.specReg.phs; - fs{4} = proc_D.specReg.fs; - phs{4} = proc_D.specReg.phs; + fs{1} = proc_A.specReg{1}.fs; + phs{1} = proc_A.specReg{1}.phs; + fs{2} = proc_B.specReg{1}.fs; + phs{2} = proc_B.specReg{1}.phs; + fs{3} = proc_C.specReg{1}.fs; + phs{3} = proc_C.specReg{1}.phs; + fs{4} = proc_D.specReg{1}.fs; + phs{4} = proc_D.specReg{1}.phs; else - fs{1} = proc_A.specReg.fs; - phs{1} = proc_A.specReg.phs; - fs{2} = proc_B.specReg.fs; - phs{2} = proc_B.specReg.phs; + fs{1} = proc_A.specReg{1}.fs; + phs{1} = proc_A.specReg{1}.phs; + fs{2} = proc_B.specReg{1}.fs; + phs{2} = proc_B.specReg{1}.phs; end end end if (isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) - if isfield(MRSCont.QM{VoxelIndex}.freqShift, which_spec) - switch which_spec + if isfield(MRSCont.QM{VoxelIndex}.freqShift, which_sub_spec) + switch which_sub_spec case {'A', 'B', 'C', 'D'} - refShift = -repmat(MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk), size(fs)); + refShift = -repmat(MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk), size(fs)); fs = fs - refShift; for jj = 1:size(applyDataToScale.fids,2) applyDataToScale.fids(:,jj) = applyDataToScale.fids(:,jj) .* ... exp(1i*fs(jj)*2*pi*t') * exp(1i*pi/180*phs(jj)); end case {'diff1', 'diff2','diff3', 'sum'} - refShift = -repmat(MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk), size(fs{1})); + refShift = -repmat(MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk), size(fs{1})); for ss = 1 : length(fs) fs{ss} = fs{ss} - refShift; for jj = 1:size(applyDataToScale.fids,2) @@ -370,17 +470,17 @@ end end elseif (isfield(MRSCont.flags,'isMRSI') && (MRSCont.flags.isMRSI == 1)) - if isfield(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift, which_spec) - switch which_spec + if isfield(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift, which_sub_spec) + switch which_sub_spec case {'A', 'B', 'C', 'D'} - refShift = -repmat(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk), size(fs)); + refShift = -repmat(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk), size(fs)); fs = fs - refShift; for jj = 1:size(applyDataToScale.fids,2) applyDataToScale.fids(:,jj) = applyDataToScale.fids(:,jj) .* ... exp(1i*fs(jj)*2*pi*t') * exp(1i*pi/180*phs(jj)); end case {'diff1', 'diff2','diff3', 'sum'} - refShift = -repmat(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk), size(fs{1})); + refShift = -repmat(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk), size(fs{1})); for ss = 1 : length(fs) fs{ss} = fs{ss} - refShift; for jj = 1:size(applyDataToScale.fids,2) @@ -391,17 +491,17 @@ end end else - if isfield(MRSCont.QM.freqShift, which_spec) - switch which_spec + if isfield(MRSCont.QM.freqShift, which_sub_spec) + switch which_sub_spec case {'A', 'B', 'C', 'D'} - refShift = -repmat(MRSCont.QM.freqShift.(which_spec)(kk), size(fs)); + refShift = -repmat(MRSCont.QM.freqShift.(which_sub_spec)(kk), size(fs)); fs = fs - refShift; for jj = 1:size(applyDataToScale.fids,2) applyDataToScale.fids(:,jj) = applyDataToScale.fids(:,jj) .* ... exp(1i*fs(jj)*2*pi*t') * exp(1i*pi/180*phs(jj)); end case {'diff1', 'diff2','diff3', 'sum'} - refShift = -repmat(MRSCont.QM.freqShift.(which_spec)(kk), size(fs{1})); + refShift = -repmat(MRSCont.QM.freqShift.(which_sub_spec)(kk), size(fs{1})); for ss = 1 : length(fs) fs{ss} = fs{ss} - refShift; for jj = 1:size(applyDataToScale.fids,2) @@ -418,13 +518,14 @@ end end + applyDataToScale.specs = fftshift(fft(applyDataToScale.fids,[],rawDataToScale.dims.t),rawDataToScale.dims.t); plotRangeScale = op_freqrange(applyDataToScale, ppmmin, ppmmax); yLims= [ min(min(real(plotRangeScale.specs(:,:)))) max(max(real(plotRangeScale.specs(:,:))))]; yLimsAbs = (abs(yLims(1)) + abs(yLims(2))); -if strcmp(which_spec, 'diff1') || strcmp(which_spec, 'diff2') || strcmp(which_spec, 'diff3') || strcmp(which_spec, 'sum') +if strcmp(which_sub_spec, 'diff1') || strcmp(which_sub_spec, 'diff2') || strcmp(which_sub_spec, 'diff3') || strcmp(which_sub_spec, 'sum') if MRSCont.flags.isMEGA yLims = [yLims(1) - (yLimsAbs*0.1) (2*yLims(2)) + (yLimsAbs*0.1)]; else @@ -451,7 +552,7 @@ end if MRSCont.flags.isMEGA - if ~strcmp(which_spec, 'w') && ~strcmp(which_spec, 'ref') && ~strcmp(which_spec, 'A') && ~strcmp(which_spec, 'B') + if ~strcmp(which_sub_spec, 'w') && ~strcmp(which_sub_spec, 'ref')&& ~strcmp(which_sub_spec, 'mm_ref') && ~strcmp(which_sub_spec, 'A') && ~strcmp(which_sub_spec, 'B') stag = [0,0.5] .* yLimsAbs; stagText = stag + (0.25.* yLimsAbs); for rr = 1:nAvgsRaw @@ -479,7 +580,7 @@ end if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - if ~strcmp(which_spec, 'w') && ~strcmp(which_spec, 'ref') && ~strcmp(which_spec, 'A') && ~strcmp(which_spec, 'B') && ~strcmp(which_spec, 'C') && ~strcmp(which_spec, 'D') + if ~strcmp(which_sub_spec, 'w') && ~strcmp(which_sub_spec, 'ref')&& ~strcmp(which_sub_spec, 'mm_ref') && ~strcmp(which_sub_spec, 'A') && ~strcmp(which_sub_spec, 'B') && ~strcmp(which_sub_spec, 'C') && ~strcmp(which_sub_spec, 'D') stag = [0,0.5,1,1.5] .* yLimsAbs; stagText = stag + (0.25.* yLimsAbs); for rr = 1:nAvgsRaw @@ -503,10 +604,10 @@ end end -if ~(strcmp(which_spec,'w') || strcmp(which_spec,'ref')) +if ~(strcmp(which_sub_spec,'w') || strcmp(which_sub_spec,'ref')|| strcmp(which_sub_spec,'mm_ref')) plot(ax_raw, [2.008 2.008], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); plot(ax_raw, [3.027 3.027], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); - if ~strcmp(which_spec, 'mm') + if ~strcmp(which_sub_spec, 'mm') plot(ax_raw, [3.200 3.200], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); else plot(ax_raw, [3.9 3.9], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); @@ -526,7 +627,7 @@ % Apply stored corrections to calculate the spectra to display applyDataToPlot = rawDataToPlot; t = rawDataToPlot.t; -switch which_spec +switch which_sub_spec case {'A', 'B', 'C', 'D'} if (isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) fs = procDataToPlot.specReg{VoxelIndex}.fs; @@ -537,9 +638,9 @@ phs = procDataToPlot.specReg{VoxelIndex(1), VoxelIndex(2)}.phs; weights = MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex(1), VoxelIndex(2)}.weights; else - fs = procDataToPlot.specReg.fs; - phs = procDataToPlot.specReg.phs; - weights = MRSCont.processed.(which_spec){kk}.specReg.weights; + fs = procDataToPlot.specReg{1}.fs; + phs = procDataToPlot.specReg{1}.phs; + weights = MRSCont.processed.(which_spec){kk}.specReg{1}.weights{find(strcmp(which_sub_spec,{'A', 'B', 'C', 'D'}))}; end case {'diff1', 'diff2', 'diff3', 'sum'} if (isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) @@ -552,13 +653,13 @@ phs{3} = proc_C.specReg{VoxelIndex}.phs; fs{4} = proc_D.specReg{VoxelIndex}.fs; phs{4} = proc_D.specReg{VoxelIndex}.phs; - weights = MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex}.weights; + weights = vertcat(MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex}.weights{:}); else fs{1} = proc_A.specReg{VoxelIndex}.fs; phs{1} = proc_A.specReg{VoxelIndex}.phs; fs{2} = proc_B.specReg{VoxelIndex}.fs; phs{2} = proc_B.specReg{VoxelIndex}.phs; - weights = MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex}.weights; + weights = vertcat(MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex}.weights{:}); end elseif(isfield(MRSCont.flags,'isMRSI') && (MRSCont.flags.isMRSI == 1)) if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES @@ -570,38 +671,38 @@ phs{3} = proc_C.specReg{VoxelIndex(1), VoxelIndex(2)}.phs; fs{4} = proc_D.specReg{VoxelIndex(1), VoxelIndex(2)}.fs; phs{4} = proc_D.specReg{VoxelIndex(1), VoxelIndex(2)}.phs; - weights = MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex(1), VoxelIndex(2)}.weights; + weights = vertcat(RSCont.processed.(which_spec){kk}.specReg{VoxelIndex(1), VoxelIndex(2)}.weights{:}); else fs{1} = proc_A.specReg{VoxelIndex(1), VoxelIndex(2)}.fs; phs{1} = proc_A.specReg{VoxelIndex(1), VoxelIndex(2)}.phs; fs{2} = proc_B.specReg{VoxelIndex(1), VoxelIndex(2)}.fs; phs{2} = proc_B.specReg{VoxelIndex(1), VoxelIndex(2)}.phs; - weights = MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex(1), VoxelIndex(2)}.weights; + weights = vertcat(MRSCont.processed.(which_spec){kk}.specReg{VoxelIndex(1), VoxelIndex(2)}.weights{:}); end else if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - fs{1} = proc_A.specReg.fs; - phs{1} = proc_A.specReg.phs; - fs{2} = proc_B.specReg.fs; - phs{2} = proc_B.specReg.phs; - fs{3} = proc_C.specReg.fs; - phs{3} = proc_C.specReg.phs; - fs{4} = proc_D.specReg.fs; - phs{4} = proc_D.specReg.phs; - weights = MRSCont.processed.(which_spec){kk}.specReg.weights; + fs{1} = proc_A.specReg{1}.fs; + phs{1} = proc_A.specReg{1}.phs; + fs{2} = proc_B.specReg{1}.fs; + phs{2} = proc_B.specReg{1}.phs; + fs{3} = proc_C.specReg{1}.fs; + phs{3} = proc_C.specReg{1}.phs; + fs{4} = proc_D.specReg{1}.fs; + phs{4} = proc_D.specReg{1}.phs; + weights = vertcat(MRSCont.processed.(which_spec){kk}.specReg{1}.weights{:}); else - fs{1} = proc_A.specReg.fs; - phs{1} = proc_A.specReg.phs; - fs{2} = proc_B.specReg.fs; - phs{2} = proc_B.specReg.phs; - weights = MRSCont.processed.(which_spec){kk}.specReg.weights; + fs{1} = proc_A.specReg{1}.fs; + phs{1} = proc_A.specReg{1}.phs; + fs{2} = proc_B.specReg{1}.fs; + phs{2} = proc_B.specReg{1}.phs; + weights = vertcat(MRSCont.processed.(which_spec){kk}.specReg{1}.weights{:}); end end end if (isfield(MRSCont.flags,'isPRIAM') && (MRSCont.flags.isPRIAM == 1)) - if isfield(MRSCont.QM{VoxelIndex(1)}.freqShift, which_spec) - switch which_spec + if isfield(MRSCont.QM{VoxelIndex(1)}.freqShift, which_sub_spec) + switch which_sub_spec case {'A', 'B', 'C', 'D'} refShift = -repmat(MRSCont.QM{VoxelIndex(1)}.freqShift.(which_spec)(kk), size(fs)); fs = fs - refShift; @@ -621,8 +722,8 @@ end end elseif (isfield(MRSCont.flags,'isMRSI') && (MRSCont.flags.isMRSI == 1)) - if isfield(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift, which_spec) - switch which_spec + if isfield(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift, which_sub_spec) + switch which_sub_spec case {'A', 'B', 'C', 'D'} refShift = -repmat(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk), size(fs)); fs = fs - refShift; @@ -642,17 +743,17 @@ end end else - if isfield(MRSCont.QM.freqShift, which_spec) - switch which_spec + if isfield(MRSCont.QM.freqShift, which_sub_spec) + switch which_sub_spec case {'A', 'B', 'C', 'D'} - refShift = -repmat(MRSCont.QM.freqShift.(which_spec)(kk), size(fs)); + refShift = -repmat(MRSCont.QM.freqShift.(which_sub_spec)(kk), size(fs)); fs = fs - refShift; for jj = 1:size(applyDataToPlot.fids,2) applyDataToPlot.fids(:,jj) = applyDataToPlot.fids(:,jj) .* ... exp(1i*fs(jj)*2*pi*t') * exp(1i*pi/180*phs(jj)); end case {'diff1', 'diff2', 'diff3', 'sum'} - refShift = -repmat(MRSCont.QM.freqShift.(which_spec)(kk), size(fs{1})); + refShift = -repmat(MRSCont.QM.freqShift.(which_sub_spec)(kk), size(fs{1})); for ss = 1 : length(fs) fs{ss} = fs{ss} - refShift; for jj = 1:size(applyDataToPlot.fids,2) @@ -680,7 +781,7 @@ end if MRSCont.flags.isMEGA - if ~strcmp(which_spec, 'w') && ~strcmp(which_spec, 'ref') && ~strcmp(which_spec, 'A') && ~strcmp(which_spec, 'B') + if ~strcmp(which_sub_spec, 'w') && ~strcmp(which_sub_spec, 'ref') && ~strcmp(which_sub_spec, 'mm_ref') && ~strcmp(which_sub_spec, 'A') && ~strcmp(which_sub_spec, 'B') stag = [0,0.5,1,1.5] .* yLimsAbs; stagText = stag + (0.25.* yLimsAbs); for rr = 1:nAvgsRaw @@ -700,7 +801,7 @@ if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) - if ~strcmp(which_spec, 'w') && ~strcmp(which_spec, 'ref') && ~strcmp(which_spec, 'A') && ~strcmp(which_spec, 'B') && ~strcmp(which_spec, 'C') && ~strcmp(which_spec, 'D') + if ~strcmp(which_sub_spec, 'w') && ~strcmp(which_sub_spec, 'ref') && ~strcmp(which_sub_spec, 'A') && ~strcmp(which_sub_spec, 'B') && ~strcmp(which_sub_spec, 'C') && ~strcmp(which_sub_spec, 'D') stag = [0,0.5,1,1.5] .* yLimsAbs; stagText = stag + (0.25.* yLimsAbs); for rr = 1:nAvgsRaw @@ -717,7 +818,7 @@ else for rr = 1:nAvgsRaw plot(ax_aligned, applyDataToPlot.ppm, real(applyDataToPlot.specs(:,rr)), 'LineWidth', 0.5, 'Color', colormap.Foreground); - if ~strcmp(which_spec, 'w') && ~strcmp(which_spec, 'ref') + if ~strcmp(which_sub_spec, 'w') && ~strcmp(which_sub_spec, 'ref') plot(ax_aligned, applyDataToPlot.ppm, real(applyDataToPlot.specs(:,rr)), 'LineWidth', 0.5, 'Color', colormap.Foreground); end end @@ -725,10 +826,10 @@ end end -if ~(strcmp(which_spec,'w') || strcmp(which_spec,'ref')) +if ~(strcmp(which_sub_spec,'w') || strcmp(which_sub_spec,'ref')|| strcmp(which_sub_spec,'mm_ref')) plot(ax_aligned, [2.008 2.008], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); plot(ax_aligned, [3.027 3.027], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); - if ~strcmp(which_spec, 'mm') + if ~strcmp(which_sub_spec, 'mm') plot(ax_aligned, [3.200 3.200], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); else plot(ax_aligned, [3.9 3.9], [y(1)-y(2) y(2)],'LineStyle', ':', 'Color', colormap.Foreground, 'LineWidth', 0.5); @@ -756,11 +857,11 @@ plot(ax_proc, procDataToPlot.ppm, real(procDataToPlot.specs)/MRSCont.plot.processed.w.max(kk), 'Color',MRSCont.colormap.Foreground, 'LineWidth', 1.5); maxRef = MRSCont.plot.processed.w.max; end - if strcmp(which_spec, 'diff1') || strcmp(which_spec, 'diff2') || strcmp(which_spec, 'sum') - if strcmp(which_spec, 'sum') + if strcmp(which_sub_spec, 'diff1') || strcmp(which_sub_spec, 'diff2') || strcmp(which_sub_spec, 'sum') + if strcmp(which_sub_spec, 'sum') y = [-0.2*max(MRSCont.plot.processed.(which_spec).max/maxRef), 1.2*max(MRSCont.plot.processed.(which_spec).max/maxRef)]; else - if strcmp(which_spec, 'diff1') + if strcmp(which_sub_spec, 'diff1') switch MRSCont.opts.editTarget{1} case 'GABA' y = [-0.2*max(MRSCont.plot.processed.(which_spec).max/maxRef), 1.2*max(MRSCont.plot.processed.(which_spec).max/maxRef)]; @@ -789,8 +890,8 @@ y = [-0.2*max(MRSCont.plot.processed.(which_spec).max/maxRef), 1.2*max(MRSCont.plot.processed.(which_spec).max/maxRef)]; end else - plot(ax_proc, procDataToPlot.ppm, real(procDataToPlot.specs), 'Color',MRSCont.colormap.Foreground, 'LineWidth', 1.5); - if strcmp(which_spec, 'diff1') || strcmp(which_spec, 'diff2') || strcmp(which_spec, 'diff3') || strcmp(which_spec, 'sum') + plot(ax_proc, procDataToPlot.ppm, real(procDataToPlot.specs(:,1)), 'Color',MRSCont.colormap.Foreground, 'LineWidth', 1.5); + if strcmp(which_sub_spec, 'diff1') || strcmp(which_sub_spec, 'diff2') || strcmp(which_sub_spec, 'diff3') || strcmp(which_sub_spec, 'sum') y = [min(MRSCont.plot.processed.(which_spec).min) max(MRSCont.plot.processed.(which_spec).max)]; else if MRSCont.flags.isMEGA || MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES @@ -801,21 +902,30 @@ end end else - plot(ax_proc, procDataToPlot.ppm, real(procDataToPlot.specs)/max(real(procDataToPlot.specs(procDataToPlot.ppm>ppmmin&procDataToPlot.ppmppmmin&procDataToPlot.ppm 1 - crDriftPre = MRSCont.QM{VoxelIndex}.drift.pre.(which_spec){kk} + MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk)/applyDataToPlot.txfrq*1e6; - crDriftPost = MRSCont.QM{VoxelIndex}.drift.post.(which_spec){kk} + MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk)/applyDataToPlot.txfrq*1e6; + if isfield(MRSCont.QM{VoxelIndex}.drift.pre, which_sub_spec) + if length(MRSCont.QM{VoxelIndex}.drift.pre.(which_sub_spec){kk}) > 1 + crDriftPre = MRSCont.QM{VoxelIndex}.drift.pre.(which_sub_spec){kk} + MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk)/applyDataToPlot.txfrq*1e6; + crDriftPost = MRSCont.QM{VoxelIndex}.drift.post.(which_sub_spec){kk} + MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk)/applyDataToPlot.txfrq*1e6; hold(ax_drift, 'on'); colors = ones(length(crDriftPre),1).*colormap.Foreground; for dots = 1 : length(crDriftPre) @@ -847,11 +957,11 @@ colors(dots,2) = colors(dots,2) + (1 - colors(dots,2)) * (1-weights(dots)); colors(dots,3) = colors(dots,3) + (1 - colors(dots,3)) * (1-weights(dots)); end - scatter(ax_drift, [1:length(crDriftPre)],crDriftPre'-(MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6),36,ones(length(crDriftPre),1).*colormap.LightAccent); - scatter(ax_drift, [1:length(crDriftPost)],crDriftPost'-(MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6),36,colors,'filled','MarkerEdgeColor',colormap.Foreground); + scatter(ax_drift, [1:length(crDriftPre)],crDriftPre'-(MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6),36,ones(length(crDriftPre),1).*colormap.LightAccent); + scatter(ax_drift, [1:length(crDriftPost)],crDriftPost'-(MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6),36,colors,'filled','MarkerEdgeColor',colormap.Foreground); - text(ax_drift, length(crDriftPre)*1.05, crDriftPre(end)-(MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6), 'Pre', 'Color', colormap.LightAccent); - text(ax_drift, length(crDriftPost)*1.05, crDriftPost(end)-(MRSCont.QM{VoxelIndex}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6), 'Post', 'Color', colormap.Foreground); + text(ax_drift, length(crDriftPre)*1.05, crDriftPre(end)-(MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6), 'Pre', 'Color', colormap.LightAccent); + text(ax_drift, length(crDriftPost)*1.05, crDriftPost(end)-(MRSCont.QM{VoxelIndex}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6), 'Post', 'Color', colormap.Foreground); set(ax_drift, 'YLim', [3.028-0.1 3.028+0.1]); yticks([3.028-0.08 3.028-0.04 3.028 3.028+0.04 3.028+0.08]); yticklabels({'2.94' '2.98' '3.02' '3.06' '3.10'}); @@ -871,10 +981,10 @@ text(ax_drift, x(2)/6, y(2)/2, 'No drift data available','Color', colormap.Foreground); end elseif (isfield(MRSCont.flags,'isMRSI') && (MRSCont.flags.isMRSI == 1)) - if isfield(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.pre, which_spec) - if length(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.pre.(which_spec){kk}) > 1 - crDriftPre = MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.pre.(which_spec){kk} + MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk)/applyDataToPlot.txfrq*1e6; - crDriftPost = MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.post.(which_spec){kk} + MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk)/applyDataToPlot.txfrq*1e6; + if isfield(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.pre, which_sub_spec) + if length(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.pre.(which_sub_spec){kk}) > 1 + crDriftPre = MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.pre.(which_sub_spec){kk} + MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk)/applyDataToPlot.txfrq*1e6; + crDriftPost = MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.drift.post.(which_sub_spec){kk} + MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk)/applyDataToPlot.txfrq*1e6; hold(ax_drift, 'on'); colors = ones(length(crDriftPre),1).*colormap.Foreground; for dots = 1 : length(crDriftPre) @@ -882,11 +992,11 @@ colors(dots,2) = colors(dots,2) + (1 - colors(dots,2)) * (1-weights(dots)); colors(dots,3) = colors(dots,3) + (1 - colors(dots,3)) * (1-weights(dots)); end - scatter(ax_drift, [1:length(crDriftPre)],crDriftPre'-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6),36,ones(length(crDriftPre),1).*colormap.LightAccent); - scatter(ax_drift, [1:length(crDriftPost)],crDriftPost'-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6),36,colors,'filled','MarkerEdgeColor',colormap.Foreground); + scatter(ax_drift, [1:length(crDriftPre)],crDriftPre'-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6),36,ones(length(crDriftPre),1).*colormap.LightAccent); + scatter(ax_drift, [1:length(crDriftPost)],crDriftPost'-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6),36,colors,'filled','MarkerEdgeColor',colormap.Foreground); - text(ax_drift, length(crDriftPre)*1.05, crDriftPre(end)-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6), 'Pre', 'Color', colormap.LightAccent); - text(ax_drift, length(crDriftPost)*1.05, crDriftPost(end)-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6), 'Post', 'Color', colormap.Foreground); + text(ax_drift, length(crDriftPre)*1.05, crDriftPre(end)-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6), 'Pre', 'Color', colormap.LightAccent); + text(ax_drift, length(crDriftPost)*1.05, crDriftPost(end)-(MRSCont.QM{VoxelIndex(1), VoxelIndex(2)}.freqShift.(which_sub_spec)(kk)/procDataToPlot.txfrq*1e6), 'Post', 'Color', colormap.Foreground); set(ax_drift, 'YLim', [3.028-0.1 3.028+0.1]); yticks([3.028-0.08 3.028-0.04 3.028 3.028+0.04 3.028+0.08]); yticklabels({'2.94' '2.98' '3.02' '3.06' '3.10'}); @@ -906,22 +1016,22 @@ text(ax_drift, x(2)/6, y(2)/2, 'No drift data available','Color', colormap.Foreground); end else - if isfield(MRSCont.QM.drift.pre, which_spec) - if length(MRSCont.QM.drift.pre.(which_spec){kk}) > 1 - crDriftPre = MRSCont.QM.drift.pre.(which_spec){kk} + MRSCont.QM.freqShift.(which_spec)(kk)/applyDataToPlot.txfrq*1e6; - crDriftPost = MRSCont.QM.drift.post.(which_spec){kk} + MRSCont.QM.freqShift.(which_spec)(kk)/applyDataToPlot.txfrq*1e6; + if isfield(MRSCont.QM.drift.pre, which_sub_spec) && ~strcmp(which_spec,'mm') + if length(MRSCont.QM.drift.pre.(which_sub_spec){kk}) > 1 + crDriftPre = MRSCont.QM.drift.pre.(which_sub_spec){kk} + MRSCont.QM.freqShift.(which_spec)(1,kk,SubSpectraIndex)/applyDataToPlot.txfrq*1e6; + crDriftPost = MRSCont.QM.drift.post.(which_sub_spec){kk} + MRSCont.QM.freqShift.(which_spec)(1,kk,SubSpectraIndex)/applyDataToPlot.txfrq*1e6; hold(ax_drift, 'on'); colors = ones(length(crDriftPre),1).*colormap.Foreground; for dots = 1 : length(crDriftPre) - colors(dots,1) = colors(dots,1) + (1 - colors(dots,1)) * (1-weights(dots)); - colors(dots,2) = colors(dots,2) + (1 - colors(dots,2)) * (1-weights(dots)); - colors(dots,3) = colors(dots,3) + (1 - colors(dots,3)) * (1-weights(dots)); + colors(dots,1) = colors(dots,1) + (1 - colors(dots,1)) * (1-weights(dots,1)); + colors(dots,2) = colors(dots,2) + (1 - colors(dots,2)) * (1-weights(dots,1)); + colors(dots,3) = colors(dots,3) + (1 - colors(dots,3)) * (1-weights(dots,1)); end - scatter(ax_drift, [1:length(crDriftPre)],crDriftPre'-(MRSCont.QM.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6),36,ones(length(crDriftPre),1).*colormap.LightAccent); - scatter(ax_drift, [1:length(crDriftPost)],crDriftPost'-(MRSCont.QM.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6),36,colors,'filled','MarkerEdgeColor',colormap.Foreground); + scatter(ax_drift, [1:length(crDriftPre)],crDriftPre'-(MRSCont.QM.freqShift.(which_spec)(1,kk,SubSpectraIndex)/procDataToPlot.txfrq*1e6),36,ones(length(crDriftPre),1).*colormap.LightAccent); + scatter(ax_drift, [1:length(crDriftPost)],crDriftPost'-(MRSCont.QM.freqShift.(which_spec)(1,kk,SubSpectraIndex)/procDataToPlot.txfrq*1e6),36,colors,'filled','MarkerEdgeColor',colormap.Foreground); - text(ax_drift, length(crDriftPre)*1.05, crDriftPre(end)-(MRSCont.QM.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6), 'Pre', 'Color', colormap.LightAccent); - text(ax_drift, length(crDriftPost)*1.05, crDriftPost(end)-(MRSCont.QM.freqShift.(which_spec)(kk)/procDataToPlot.txfrq*1e6), 'Post', 'Color', colormap.Foreground); + text(ax_drift, length(crDriftPre)*1.05, crDriftPre(end)-(MRSCont.QM.freqShift.(which_spec)(1,kk,SubSpectraIndex)/procDataToPlot.txfrq*1e6), 'Pre', 'Color', colormap.LightAccent); + text(ax_drift, length(crDriftPost)*1.05, crDriftPost(end)-(MRSCont.QM.freqShift.(which_spec)(1,kk,SubSpectraIndex)/procDataToPlot.txfrq*1e6), 'Post', 'Color', colormap.Foreground); set(ax_drift, 'YLim', [3.028-0.1 3.028+0.1]); yticks([3.028-0.08 3.028-0.04 3.028 3.028+0.04 3.028+0.08]); yticklabels({'2.94' '2.98' '3.02' '3.06' '3.10'}); @@ -939,6 +1049,7 @@ x = xlim; y = yLims; text(ax_drift, x(2)/6, y(2)/2, 'No drift data available','Color', colormap.Foreground); + set(ax_drift, 'YLim', yLims); end end xlabel(ax_drift, 'Averages', 'Color', colormap.Foreground); @@ -987,7 +1098,6 @@ if ~MRSCont.flags.isGUI [I, map] = imread('osprey.gif','gif'); axes(out, 'Position', [0, 0.85, 0.15, 0.15*11.63/14.22]); - text(gca, 0, -0.1, [MRSCont.ver.Osp ' ' MRSCont.ver.Pro],'Color', colormap.Foreground); imshow(I, map); axis off; end diff --git a/plot/osp_plotRaincloud.m b/plot/osp_plotRaincloud.m index 3915e54e..c1cf1ce4 100755 --- a/plot/osp_plotRaincloud.m +++ b/plot/osp_plotRaincloud.m @@ -1,4 +1,4 @@ -function [out_rain] = osp_plotRaincloud(MRSCont,model,quant,metab,tit,GMean,VoxelIndex) +function [out_rain] = osp_plotRaincloud(MRSCont,model,quant,metab,tit,GMean,VoxelIndex,basis) %% [out_rain] = osp_plotRaincloud(MRSCont,metab,plots,tit) % Creates raincloud plot from the quantification tables and the chosen quantifcation and metabolite % The figure contains raincloud plots with boxplots, as well as, mean @@ -38,36 +38,39 @@ %%% 1. PARSE INPUT ARGUMENTS %%% % Fall back to defaults if not provided -if nargin < 7 - VoxelIndex = 1; - if nargin < 6 - GMean = 0; - if nargin<5 - tit = ''; - if nargin<4 - metab = 'GABA'; - if nargin<3 - quant = 'tCr'; - if nargin<2 - model = ''; - if MRSCont.flags.isUnEdited - model = 'off'; - end - if MRSCont.flags.isMEGA && strcmp(MRSCont.opts.fit.style,'Separate') - model = 'diff1'; - else - model = 'conc'; - end - if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) && strcmp(MRSCont.opts.fit.style,'Separate') - model = 'diff1'; - else - model = 'conc'; - end - if strcmp(model,'') - error('ERROR: unable to retrieve default model, please specify. Aborting!!'); - end - if nargin<1 - error('ERROR: no input Osprey container specified. Aborting!!'); +if nargin < 8 + basis = 1; + if nargin < 7 + VoxelIndex = 1; + if nargin < 6 + GMean = 0; + if nargin<5 + tit = ''; + if nargin<4 + metab = 'GABA'; + if nargin<3 + quant = 'tCr'; + if nargin<2 + model = ''; + if MRSCont.flags.isUnEdited + model = 'off'; + end + if MRSCont.flags.isMEGA && strcmp(MRSCont.opts.fit.style,'Separate') + model = 'diff1'; + else + model = 'conc'; + end + if (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) && strcmp(MRSCont.opts.fit.style,'Separate') + model = 'diff1'; + else + model = 'conc'; + end + if strcmp(model,'') + error('ERROR: unable to retrieve default model, please specify. Aborting!!'); + end + if nargin<1 + error('ERROR: no input Osprey container specified. Aborting!!'); + end end end end @@ -87,19 +90,19 @@ cb(4,:) = temp; %%% 3. EXTRACT METABOLITE CONCENTRATIONS OR QM%%% + if ~strcmp(quant,'Quality') - if strcmp(quant,'AlphaCorrWaterScaled') || strcmp(quant,'AlphaCorrWaterScaledGroupNormed') - idx_1 = 1; - ConcData = MRSCont.quantify.tables.(model).(quant).(['Voxel_' num2str(VoxelIndex)]) {:,idx_1}; - else - idx_1 = find(strcmp(MRSCont.quantify.metabs.(model),metab)); - ConcData = MRSCont.quantify.tables.(model).(quant).(['Voxel_' num2str(VoxelIndex)]) {:,idx_1}; - end + ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.metab,model)); + quant_ind = [basis ind(1)]; + names_list = MRSCont.quantify.names.metab{quant_ind}; + idx_1 = find(strcmp(names_list,metab)); + metabolite_conc = MRSCont.quantify.tables.metab.(quant).(['Voxel_' num2str(VoxelIndex)]){quant_ind}; + ConcData = metabolite_conc{:,idx_1}; else quality = {'SNR','FWHM','freqShift'}; idx_1 = find(strcmp(quality,metab)); ConcData = MRSCont.QM.tables {:,idx_1}; - quality_Names = {'SNR','FWHM (ppm)','freqShift (Hz)'}; + quality_Names = {'SNR','FWHM (Hz)','freqShift (Hz)'}; end if isempty(ConcData) diff --git a/plot/osp_plotScatter.m b/plot/osp_plotScatter.m index 019755ae..3544ad2c 100755 --- a/plot/osp_plotScatter.m +++ b/plot/osp_plotScatter.m @@ -1,4 +1,4 @@ -function [out_scat] = osp_plotScatter(MRSCont,model,quant,metab,corrData,corrDataName,VoxelIndex) +function [out_scat] = osp_plotScatter(MRSCont,model,quant,metab,corrData,corrDataName,VoxelIndex,basis) %% [out_scat] = osp_plotScatter(MRSCont,model,quant,metab,corrData,corrDataName) % Creates correlation figure of the chosen quantifcation and metabolite % one figure contains a correlation analysis with subgroup correlations. @@ -37,18 +37,21 @@ % 2019-11-12: First version of the code. %%% 1. PARSE INPUT ARGUMENTS %%% % Fall back to defaults if not provided -if nargin<7 - VoxelIndex = 1; - if nargin<6 - corrDataName = 'correlation measure'; - if nargin<4 - error('No correlation data passed. Please add correlation data to the MRSCont.'); - if nargin<3 - metab = 'GABA'; - if nargin<2 - which = 'tCr'; - if nargin<1 - error('ERROR: no input Osprey container specified. Aborting!!'); +if nargin<8 + basis = 1; + if nargin<7 + VoxelIndex = 1; + if nargin<6 + corrDataName = 'correlation measure'; + if nargin<4 + error('No correlation data passed. Please add correlation data to the MRSCont.'); + if nargin<3 + metab = 'GABA'; + if nargin<2 + which = 'tCr'; + if nargin<1 + error('ERROR: no input Osprey container specified. Aborting!!'); + end end end end @@ -69,13 +72,15 @@ cb(4,:) = temp; %%% 3. EXTRACT METABOLITE CONCENTRATIONS%%% -if strcmp(quant,'AlphaCorrWaterScaled') || strcmp(quant,'AlphaCorrWaterScaledGroupNormed') - idx_1 = 1; - ConcData = MRSCont.quantify.tables.(model).(quant).(['Voxel_' num2str(VoxelIndex)]) {:,idx_1}; -else - idx_1 = find(strcmp(MRSCont.quantify.metabs.(model),metab)); - ConcData = MRSCont.quantify.tables.(model).(quant).(['Voxel_' num2str(VoxelIndex)]) {:,idx_1}; -end +ind = find(strcmp(MRSCont.overview.FitSpecNamesStruct.metab,model)); +quant_ind = [basis ind(1)]; + +names_list = MRSCont.quantify.names.metab{quant_ind}; +idx_1 = find(strcmp(names_list,metab)); +metabolite_conc = MRSCont.quantify.tables.metab.(quant).(['Voxel_' num2str(VoxelIndex)]){quant_ind}; +ConcData = metabolite_conc{:,idx_1}; + + metabFlag = 0; if isempty(ConcData) dim = size(ConcData); @@ -84,8 +89,9 @@ if ischar(corrData) metabFlag = 1; - idx_1 = find(strcmp(MRSCont.quantify.metabs.(model),corrData)); - corrData = MRSCont.quantify.tables.(model).(quant).(['Voxel_' num2str(VoxelIndex)]) {:,idx_1}; + idx_1 = find(strcmp(names_list,corrData)); + metabolite_conc = MRSCont.quantify.tables.metab.(quant).(['Voxel_' num2str(VoxelIndex)]){quant_ind}; + corrData = metabolite_conc{:,idx_1}; end if strcmp(quant, 'tCr') diff --git a/process/OspreyProcess.m b/process/OspreyProcess.m index df3fc022..ab868ad1 100644 --- a/process/OspreyProcess.m +++ b/process/OspreyProcess.m @@ -36,40 +36,670 @@ [~,MRSCont.ver.CheckOsp ] = osp_Toolbox_Check('OspreyProcess',MRSCont.flags.isGUI); -% Post-process raw data depending on sequence type -if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI - if MRSCont.flags.isUnEdited - [MRSCont] = osp_processUnEdited(MRSCont); - elseif MRSCont.flags.isMEGA - [MRSCont] = osp_processMEGA(MRSCont); - elseif MRSCont.flags.isHERMES - [MRSCont] = osp_processHERMES(MRSCont); - elseif MRSCont.flags.isHERCULES - % For now, process HERCULES like HERMES data - [MRSCont] = osp_processHERCULES(MRSCont); - else - msg = 'No flag set for sequence type!'; - fprintf(msg); - error(msg); - end +%% Data post-processing starts here +warning('off','all'); + +% Loop over all datasets +refProcessTime = tic; +if MRSCont.flags.isGUI + progressText = MRSCont.flags.inProgress; else - [MRSCont] = osp_processMultiVoxel(MRSCont); + progressText = ''; end +for kk = 1:MRSCont.nDatasets(1) %Subject loop + for ll = 1: 1:MRSCont.nDatasets(2) %Experiment loop + [~] = printLog('OspreyProcess',kk,ll,MRSCont.nDatasets(1),progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); -% Gather some more information from the processed data; + if ~(MRSCont.flags.didProcess == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'processed') && (kk > length(MRSCont.processed.A))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); +%% %%% 1. GET RAW DATA %%% + raw = MRSCont.raw{metab_ll,kk}; % Get the kk-th dataset + + % Get sequence type set up + if raw.flags.isUnEdited + seq = 'unedited'; + elseif raw.flags.isMEGA + seq = 'MEGA'; + elseif raw.flags.isHERMES + seq = 'HERMES'; + elseif raw.flags.isHERCULES + seq = 'HERCULES'; + end + +%% %%% 1B. GET MM DATA %%% + if MRSCont.flags.hasMM + mm_ll = MRSCont.opts.MultipleSpectra.mm(ll); + raw_mm = MRSCont.raw_mm{mm_ll,kk}; % Get the kk-th dataset re_mm + if raw_mm.averages > 1 && raw_mm.flags.averaged == 0 %re_mm + [raw_mm,fs,phs] = op_alignAverages(raw_mm, 1, 'n'); %re_mm + raw_mm = op_averaging(raw_mm); % Average re_mm + else %re_mm + raw_mm.flags.averaged = 1; %re_mm + raw_mm.dims.averages = 0; %re_mm + fs = 0; + phs = 0; + end + if raw_mm.flags.isUnEdited + [raw_mm,~] = op_ppmref(raw_mm,4.6,4.8,4.68); % Reference to water @ 4.68 ppm %re_mm + end + if raw_mm.flags.isUnEdited + raw_mm.names = {'A'}; + raw_mm.target = {''}; + raw_mm.specReg{1}.fs = fs; % save align parameters + raw_mm.specReg{1}.phs = phs; % save align parameters + raw_mm.specReg{1}.weights{1} = ones(size(phs)); % save align parameters + driftPre = 0; + end + if raw_mm.flags.isMEGA + raw_mm.names = {'A','B'}; + raw_mm.target = MRSCont.opts.editTarget'; + raw_mm.specReg{1}.fs = fs; % save align parameters + raw_mm.specReg{1}.phs = phs; % save align parameters + raw_mm.specReg{1}.weights{1} = ones(size(phs)); % save align parameters + raw_mm.specReg{1}.weights{2} = ones(size(phs)); % save align parameters + driftPre{1} = 0; + driftPre{2} = 0; + end + if raw_mm.flags.isHERMES || raw_mm.flags.isHERCULES + raw_mm.names = {'A', 'B', 'C', 'D'}; + raw_mm.target = MRSCont.opts.editTarget'; + raw_mm.specReg{1}.fs = fs; % save align parameters + raw_mm.specReg{1}.phs = phs; % save align parameters + raw_mm.specReg{1}.weights{1} = size(phs); % save align parameters + raw_mm.specReg{1}.weights{2} = size(phs); % save align parameters + raw_mm.specReg{1}.weights{3} = size(phs); % save align parameters + raw_mm.specReg{1}.weights{4} = size(phs); % save align parameters + driftPre{1} = 0; + driftPre{2} = 0; + driftPre{3} = 0; + driftPre{4} = 0; + end + end %re_mm + +%% %%% 1C. GET MM REFERENCE DATA %%% + if MRSCont.flags.hasMMRef + mm_ref_ll = MRSCont.opts.MultipleSpectra.mm_ref(ll); + raw_mm_ref = MRSCont.raw_mm_ref{mm_ref_ll,kk}; % Get the kk-th dataset + raw_mm_ref = combine_water_subspecs(raw_mm_ref); + end +%% %%% 1D. GET REFERENCE DATA %%% + if MRSCont.flags.hasRef + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + raw_ref = MRSCont.raw_ref{ref_ll,kk}; % Get the kk-th dataset + raw_ref = combine_water_subspecs(raw_ref); + end + +%% %%% 1E. GET SHORT-TE WATER DATA %%% + % And do the processing + if MRSCont.flags.hasWater + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + raw_w = MRSCont.raw_w{w_ll,kk}; % Get the kk-th dataset + if raw_w.averages > 1 && raw_w.flags.averaged == 0 + [raw_w,~,~] = op_alignAverages(raw_w, 1, 'n'); + raw_w = op_averaging(raw_w); % Average + else + raw_w.flags.averaged = 1; + raw_w.dims.averages = 0; + end + if ~MRSCont.flags.isMRSI + [raw_w,~] = op_eccKlose(raw_w, raw_w); % Klose eddy current correction + else + [raw_w,~]=op_autophase(raw_w,2,2*4.68); + end + [raw_w,~] = op_ppmref(raw_w,4.6,4.8,4.68); % Reference to water @ 4.68 ppm + raw_w.names = {'A'}; + MRSCont.processed.w{w_ll,kk} = raw_w; % Save back to MRSCont container + end + +%% %%% 2. PHANTOM-SPECIFIC PRE-PROCESSING %%% + % If this is phantom data (assuming room temperature), we want to + % perform a few specific pre-processing steps. + if MRSCont.flags.isPhantom + % First, we undo phase cycling by dividing by the first data + % point (this is mainly experimental at this point, but has + % proved beneficial for phase-cycled GE data). + % for rr = 1:raw.rawAverages + % phi = repelem(conj(raw.fids(1,rr))./abs(raw.fids(1,rr)),size(raw.fids,1)); + % raw.fids(:,rr) = raw.fids(:,rr) .* phi'; + % raw.specs = fftshift(fft(raw.fids,[],1)); + % end + + % Next, shift the entire metabolite spectrum by 0.15 ppm. + % This doesn't have to be completely accurate, since additional + % referencing steps are performed in the later stages of + % post-processing and modelling, but we want the prominent singlets + % to appear within 0.1 ppm of their expected in-vivo positions. + phantomShiftPPM = 0.15 * raw.txfrq*1e-6; + raw = op_freqshift(raw, -phantomShiftPPM); + + % Finally, apply some linebroadening. High-quality in-vitro + % data may have linewidth lower than the simulated basis set + % data. + raw = op_filter(raw, 2); + if MRSCont.flags.hasRef + raw_ref = op_filter(raw_ref, 2); + end + if MRSCont.flags.hasWater + raw_w = op_filter(raw_w, 2); + MRSCont.processed.w{ll,kk} = raw_w; % Save back to MRSCont container + end + end + +%% %%% 3. FREQUENCY/PHASE CORRECTION AND AVERAGING %%% + if raw.averages > 1 && raw.flags.averaged == 0 + % Calculate starting values for spectral registration + [refShift_ind_ini]=op_preref(raw,seq); + % Perform robust spectral correction with weighted averaging. + % This can obviously only be done, if the spectra have not been + % pre-averaged, i.e. in some older RDA and DICOM files (which should, + % generally, not be used). + if ~MRSCont.flags.isPhantom + switch MRSCont.opts.SpecReg %Pick spectral registration method (default is Robust Spectral Registration) + case 'ProbSpecReg' + [raw, fs, phs, weights, driftPre, driftPost] = op_probabSpecReg(raw, seq, 0,refShift_ind_ini); + case 'RobSpecReg' + [raw, fs, phs, weights, driftPre, driftPost] = op_robustSpecReg(raw, seq, 0,refShift_ind_ini); % Align and average + case 'RestrSpecReg' + if isfield(MRSCont.opts,'SpecRegRange') + [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, seq, 0,refShift_ind_ini,0,MRSCont.opts.SpecRegRange(1),MRSCont.opts.SpecRegRange(2)); % Align and average + else + [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, seq, 0,refShift_ind_ini,0,MRSCont.opts.fit.range(1),MRSCont.opts.fit.range(2)); % Align and average + end + case 'none' + [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, seq, 0,refShift_ind_ini,1); % Align and average + end + else + switch MRSCont.opts.SpecReg %Pick spectral registration method (default is Robust Spectral Registration) + case 'none' + [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, seq, 0,refShift_ind_ini,1); % Align and average + otherwise + [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, seq, 0,refShift_ind_ini,0,0.5,4.2); + end + end + + raw.specReg{1}.fs = fs; % save align parameters + raw.specReg{1}.phs = phs; % save align parameters + if raw.flags.isUnEdited + raw.specReg{1}.weights = weights; % save align parameters); + raw.specReg{1}.weights{1} = raw.specReg{1}.weights{1}'/max(raw.specReg{1}.weights{1}(1,:)); + end + if raw.flags.isMEGA + raw.specReg{1}.weights = weights; % save align parameters); + raw.specReg{1}.weights{1} = raw.specReg{1}.weights{1}'/(max(raw.specReg{1}.weights{1}(1,:))); + raw.specReg{1}.weights{2} = raw.specReg{1}.weights{2}'/(max(raw.specReg{1}.weights{2}(1,:))); + end + if raw.flags.isHERMES || raw.flags.isHERCULES + raw.specReg{1}.weights = weights; % save align parameters); + raw.specReg{1}.weights{1} = raw.specReg{1}.weights{1}'/(max(raw.specReg{1}.weights{1}(1,:))); + raw.specReg{1}.weights{2} = raw.specReg{1}.weights{2}'/(max(raw.specReg{1}.weights{2}(1,:))); + raw.specReg{1}.weights{3} = raw.specReg{1}.weights{3}'/(max(raw.specReg{1}.weights{3}(1,:))); + raw.specReg{1}.weights{4} = raw.specReg{1}.weights{4}'/(max(raw.specReg{1}.weights{4}(1,:))); + end + + else + raw.fids = squeeze(sum(raw.fids, raw.dims.averages)); + raw.specs=fftshift(fft(raw.fids,[],raw.dims.t),raw.dims.t); + if raw.dims.t>raw.dims.averages + raw.dims.t=raw.dims.t-1; + else + raw.dims.t=raw.dims.t; + end + if raw.dims.coils>raw.dims.averages + raw.dims.coils=raw.dims.coils-1; + else + raw.dims.coils=raw.dims.coils; + end + raw.dims.averages=0; + if raw.dims.subSpecs>raw.dims.averages + raw.dims.subSpecs=raw.dims.subSpecs-1; + else + raw.dims.subSpecs=raw.dims.subSpecs; + end + if raw.dims.extras>raw.dims.averages + raw.dims.extras=raw.dims.extras-1; + else + raw.dims.extras=raw.dims.extras; + end + raw.sz=size(raw.fids); + + raw.flags.averaged = 1; + if raw.flags.isUnEdited + raw.specReg{1}.fs = 0; % save align parameters + raw.specReg{1}.phs = 0; % save align parameters + raw.specReg{1}.weights{1} = 1; % save align parameters + driftPre = op_measureDrift(raw); + end + if raw.flags.isMEGA + raw.specReg{1}.fs = zeros(1,2); % save align parameters + raw.specReg{1}.phs = zeros(1,2); % save align parameters + raw.specReg{1}.weights{1} = ones(1,1); % save align parameters + raw.specReg{1}.weights{2} = ones(1,1); % save align parameters + driftPre{1} = 0; + driftPre{2} = 0; + end + if raw.flags.isHERMES || raw.flags.isHERCULES + raw.specReg{1}.fs = zeros(1,4); % save align parameters + raw.specReg{1}.phs = zeros(1,4); % save align parameters + raw.specReg{1}.weights{1} = ones(1,1); % save align parameters + raw.specReg{1}.weights{2} = ones(1,1); % save align parameters + raw.specReg{1}.weights{3} = ones(1,1); % save align parameters + raw.specReg{1}.weights{4} = ones(1,1); % save align parameters + driftPre{1} = 0; + driftPre{2} = 0; + driftPre{3} = 0; + driftPre{4} = 0; + end + driftPost = driftPre; + end + +%% %%% 4. GET REFERENCE DATA / EDDY CURRENT CORRECTION %%% + % If there are reference scans, load them here to allow eddy-current + % correction of the raw data. + if MRSCont.flags.hasRef + if MRSCont.flags.hasMM + if MRSCont.flags.hasMMRef + if MRSCont.opts.ECC.mm(mm_ref_ll,kk) + [raw_mm,raw_mm_ref] = op_eccKlose(raw_mm, raw_mm_ref); % Klose eddy current correction + else + [~,raw_mm_ref] = op_eccKlose(raw_mm, raw_mm_ref); % Klose eddy current correction + end + MRSCont.processed.mm_ref{mm_ref_ll,kk} = raw_mm_ref; % Save back to MRSCont container + else + if MRSCont.opts.ECC.mm(mm_ref_ll,kk) + [raw_mm,~] = op_eccKlose(raw_mm, raw_ref); % Klose eddy current correction + else + [~,raw_mm_ref] = op_eccKlose(raw_mm, raw_ref); % Klose eddy current correction + end + end + end + if MRSCont.opts.ECC.raw(metab_ll,kk) + [raw,raw_ref] = op_eccKlose(raw, raw_ref); % Klose eddy current correction + else + [~,raw_ref] = op_eccKlose(raw, raw_ref); % Klose eddy current correction + end + [raw_ref,~] = op_ppmref(raw_ref,4.6,4.8,4.68); % Reference to water @ 4.68 ppm + MRSCont.processed.ref{metab_ll,kk} = raw_ref; % Save back to MRSCont container + end +%% %%% 5. DETERMINE POLARITY OF SPECTRUM (EG FOR MOIST WATER SUPP) %%% + % Automate determination whether the Cr peak has positive polarity. + % For water suppression methods like MOIST, the residual water may + % actually have negative polarity, but end up positive in the data, so + % that the spectrum needs to be flipped. + if ~isfield(MRSCont.opts.SubSpecAlignment, 'polResidCr') + raw_Cr = op_freqrange(raw,2.8,3.2); + % Determine the polarity of the respective peak: if the absolute of the + % maximum minus the absolute of the minimum is positive, the polarity + % of the respective peak is positive; if the absolute of the maximum + % minus the absolute of the minimum is negative, the polarity is negative. + polResidCr = abs(max(real(raw_Cr.specs))) - abs(min(real(raw_Cr.specs))); + polResidCr = squeeze(polResidCr); + polResidCr(polResidCr<0) = -1; + polResidCr(polResidCr>0) = 1; + else + polResidCr = MRSCont.opts.SubSpecAlignment.polResidCr; + end + raw = op_ampScale(raw,polResidCr); + MRSCont.raw{metab_ll,kk} = op_ampScale(MRSCont.raw{metab_ll,kk},polResidCr); + + % Do the same for the metabolite-nulled data + if MRSCont.flags.hasMM + raw_Cr39 = op_freqrange(raw_mm,3.7,4.1); + polResidCr39 = abs(max(real(raw_Cr39.specs))) - abs(min(real(raw_Cr39.specs))); + polResidCr39(polResidCr39<0) = -1; + polResidCr39(polResidCr39>0) = 1; + if polResidCr39(1) ~= polResidCr(1) + raw_mm = op_ampScale(raw_mm,polResidCr); + else + raw_mm = op_ampScale(raw_mm,polResidCr39); + end + + end + +%% %%% 6. DETERMINE ON/OFF STATUS FOR EDITED DATA & NAMES + % Classify the MEGA sub-spectra such that the OFF spectrum is stored in + % the first entry , and the ON spectrum is the second entry along the + % subspectra dimension. For HERMES and HERCULES A,B,C,D are stored + % as first, second, third, and fourth entry, respectively. + % Parse input arguments + if raw.flags.isUnEdited + raw.names = {'A'}; + MRSCont.QM.drift.pre.A{kk} = driftPre; + MRSCont.QM.drift.post.A{kk} = driftPost; + raw.target = {''}; + end + if raw.flags.isMEGA + target = MRSCont.opts.editTarget{1}; % GABA editing as default + [raw, switchOrder] = osp_onOffClassifyMEGA(raw, target); + raw.names = {'A','B'}; + raw.target = MRSCont.opts.editTarget'; + + if switchOrder + raw.flags.orderswitched = 1; + else + raw.flags.orderswitched = 0; + end + % Save drift information back to container + if ~switchOrder + MRSCont.QM.drift.pre.A{kk} = driftPre{1}; + MRSCont.QM.drift.pre.B{kk} = driftPre{2}; + MRSCont.QM.drift.post.A{kk} = driftPost{1}; + MRSCont.QM.drift.post.B{kk} = driftPost{1}; + + else + MRSCont.QM.drift.pre.A{kk} = driftPre{2}; + MRSCont.QM.drift.pre.B{kk} = driftPre{1}; + MRSCont.QM.drift.post.A{kk} = driftPost{2}; + MRSCont.QM.drift.post.B{kk} = driftPost{1}; + raw.specReg{1}.fs = raw.specReg{1}.fs(:,[2 1]); % save align parameters + raw.specReg{1}.phs = raw.specReg{1}.phs(:,[2 1]); % save align parameters + raw.specReg{1}.weights = raw.specReg{1}.weights([2 1]); % save align parameters); + end + end + if raw.flags.isHERMES || raw.flags.isHERCULES + if (strcmp(MRSCont.opts.editTarget{1},'HERCULES1')||strcmp(MRSCont.opts.editTarget{1},'HERCULES2')) + MRSCont.opts.editTarget = {'GABA','GSH'}; + end + target1 = MRSCont.opts.editTarget{1}; + target2 = MRSCont.opts.editTarget{2}; + if length(MRSCont.opts.editTarget) > 2 + target3 = MRSCont.opts.editTarget{3}; + end + [raw, commuteOrder] = osp_onOffClassifyHERMES(raw,[target1 target2]); + raw.commuteOrder = commuteOrder; + raw.names = {'A', 'B', 'C', 'D'}; + raw.target = MRSCont.opts.editTarget'; + driftPre = driftPre(:,commuteOrder); + driftPost = driftPost(:,commuteOrder); + raw.specReg{1}.fs = raw.specReg{1}.fs(:,commuteOrder); + raw.specReg{1}.phs = raw.specReg{1}.phs(:,commuteOrder); + raw.specReg{1}.weights = raw.specReg{1}.weights(:,commuteOrder); + % Save drift information back to container + MRSCont.QM.drift.pre.A{kk} = driftPre{1}; + MRSCont.QM.drift.pre.B{kk} = driftPre{2}; + MRSCont.QM.drift.pre.C{kk} = driftPre{3}; + MRSCont.QM.drift.pre.D{kk} = driftPre{4}; + MRSCont.QM.drift.post.A{kk} = driftPost{1}; + MRSCont.QM.drift.post.B{kk} = driftPost{2}; + MRSCont.QM.drift.post.C{kk} = driftPost{3}; + MRSCont.QM.drift.post.D{kk} = driftPost{4}; + % Generate the drift plot for the entire experiment in + % the correct order + driftPre = [MRSCont.QM.drift.pre.A{kk}, MRSCont.QM.drift.pre.B{kk}, MRSCont.QM.drift.pre.C{kk}, MRSCont.QM.drift.pre.D{kk}]'; + try + driftPre = reshape(driftPre, [raw.averages, 1]); + catch + driftPre = reshape(driftPre, [raw.rawAverages, 1]); + end + MRSCont.QM.drift.pre.diff1{kk} = driftPre; + MRSCont.QM.drift.pre.diff2{kk} = driftPre; + if exist('target3', 'var') % For HERMES 4 acqusitions + MRSCont.QM.drift.pre.diff3{kk} = driftPre; + end + MRSCont.QM.drift.pre.sum{kk} = driftPre; + driftPost = [MRSCont.QM.drift.post.A{kk}, MRSCont.QM.drift.post.B{kk}, MRSCont.QM.drift.post.C{kk}, MRSCont.QM.drift.post.D{kk}]'; + try + driftPost = reshape(driftPost, [raw.averages, 1]); + catch + driftPost = reshape(driftPost, [raw.rawAverages, 1]); + end + MRSCont.QM.drift.post.diff1{kk} = driftPost; + MRSCont.QM.drift.post.diff2{kk} = driftPost; + if exist('target3', 'var') % For HERMES 4 acqusitions + MRSCont.QM.drift.post.diff3{kk} = driftPre; + end + MRSCont.QM.drift.post.sum{kk} = driftPost; + end + +%% %%% 6b. BUILD SUM AND DIFF SPECTRA %%% + % Correct the frequency axis so that Cr appears at 3.027 ppm + if raw.flags.isMEGA + % Create all Hadamard combinations to generate a well defined + % raw struct + raw=op_HadamardScans(raw,[-1 1],'diff1'); + raw=op_HadamardScans(raw,[1 1],'sum'); + if ~raw.flags.isMRSI +% [raw,~] = op_phaseCrCho(raw, 1); + [refShift_SubSpecAlign, ~] = osp_XReferencing(raw,[3.03 3.22],[1 1],[1.85 4.2]);% determine frequency shift + if abs(refShift_SubSpecAlign) > 10 % This a huge shift. Most likley wrong and we will try it again with tNAA only + [refShift_SubSpecAlign, ~] = osp_XReferencing(raw,2.01,1,[1.85 4.2]);% determine frequency shift + end +% % Apply initial referencing shift + raw = op_freqshift(raw, -refShift_SubSpecAlign); +% % Fit a double-Lorentzian to the Cr-Cho area, and phase the spectrum +% % with the negative phase of that fit + [raw,ph] = op_phaseCrCho(raw, 1); + + else + refShift_SubSpecAlign =0; + end + + switch MRSCont.opts.SubSpecAlignment.mets + case 'L1Norm' + [raw] = osp_editSubSpecAlignLNorm(raw,seq); + case 'L2Norm' + [raw] = osp_editSubSpecAlign(raw, seq, target,MRSCont.opts.UnstableWater); + otherwise + if ~MRSCont.flags.isMRSI + raw_B = op_addphase(raw_B, -ph*180/pi, 0, raw_B.centerFreq, 1); + end + end + + if MRSCont.flags.hasMM + raw_mm=op_HadamardScans(raw_mm,[-1 1],'diff1'); +% diff1_mm = op_takesubspec(raw_mm,3); +% [diff1_mm,~] = op_autophase(diff1_mm,0.5,1.1); +% raw_mm = op_mergesubspec(raw_mm,diff1_mm); +% [refShift_mm, ~] = fit_OspreyReferencingMM(raw_mm); +% [raw_mm] = op_freqshift(raw_mm,-refShift_mm); + switch MRSCont.opts.SubSpecAlignment.mm + case 'L1Norm' + [raw_mm] = osp_editSubSpecAlignLNorm(raw_mm,seq); + case 'L2Norm' + [raw_mm] = osp_editSubSpecAlign(raw_mm, seq, target,MRSCont.opts.UnstableWater); + otherwise + end + if switchOrder + raw_mm.flags.orderswitched = 1; + else + raw_mm.flags.orderswitched = 0; + end + raw_mm=op_HadamardScans(raw_mm,[-1 1],'diff1'); + raw_mm=op_HadamardScans(raw_mm,[1 1],'sum'); + end + % Create the edited difference spectrum + raw=op_HadamardScans(raw,[-1 1],'diff1'); + % Create the sum spectrum + raw=op_HadamardScans(raw,[1 1],'sum'); + raw.target = target; + end + + if raw.flags.isHERMES || raw.flags.isHERCULES + % Create all Hadamard combinations to generate a well defined + % raw struct + if ~exist('target3', 'var') + raw=op_HadamardScans(raw,[-1 1 -1 1],'diff1'); + raw=op_HadamardScans(raw,[-1 -1 1 1],'diff2'); + else % For HERMES 4 acqusitions + raw=op_HadamardScans(raw,[1 -1 -1 1],'diff1'); + raw=op_HadamardScans(raw,[-1 -1 1 1],'diff2'); + raw=op_HadamardScans(raw,[-1 1 -1 1],'diff3'); + end + raw=op_HadamardScans(raw,[1 1 1 1],'sum'); + + % Correct the frequency axis so that Cr appears at 3.027 ppm + [refShift_SubSpecAlign, ~] = osp_XReferencing(raw,[3.03 3.22],[1 1],[1.85 4.2]);% determine frequency shift + if abs(refShift_SubSpecAlign) > 10 % This a huge shift. Most likley wrong and we will try it again with tNAA only + [refShift_SubSpecAlign, ~] = osp_XReferencing(raw,2.01,1,[1.85 4.2]);% determine frequency shift + end + + % Apply initial referencing shift + raw = op_freqshift(raw, -refShift_SubSpecAlign); + % Fit a double-Lorentzian to the Cr-Cho area, and phase the spectrum + % with the negative phase of that fit + [raw,~] = op_phaseCrCho(raw, 1); + % Align the sub-spectra to one another by minimizing the difference + % between the common 'reporter' signals. + switch MRSCont.opts.SubSpecAlignment.mets + case 'L1Norm' + [raw] = osp_editSubSpecAlignLNorm(raw,seq); + case 'L2Norm' + if ~exist('target3', 'var') + [raw] = osp_editSubSpecAlign(raw, seq, target1,target2,MRSCont.opts.UnstableWater); + else + [raw] = osp_editSubSpecAlign(raw, seq, target2,target3,MRSCont.opts.UnstableWater); + end + otherwise + end + % Update all Hadamard combinations after subspectra alignment + if ~exist('target3', 'var') + raw=op_HadamardScans(raw,[-1 1 -1 1],'diff1'); + raw=op_HadamardScans(raw,[-1 -1 1 1],'diff2'); + else % For HERMES 4 acqusitions + raw=op_HadamardScans(raw,[1 -1 -1 1],'diff1'); + raw=op_HadamardScans(raw,[-1 -1 1 1],'diff2'); + raw=op_HadamardScans(raw,[-1 1 -1 1],'diff3'); + end + raw=op_HadamardScans(raw,[1 1 1 1],'sum'); + + end + +%% %%% 7. REMOVE RESIDUAL WATER %%% + % Define different water removal frequency ranges, depending on + % whether this is phantom data + if MRSCont.flags.isPhantom + waterRemovalFreqRange = [4.5 5]; + fracFID = 0.2; + else + waterRemovalFreqRange = [4.2 4.9]; + fracFID = 0.75; + end + % Apply iterative water filter + raw = op_iterativeWaterFilter(raw, waterRemovalFreqRange, 32, fracFID*length(raw.fids), 0); + if MRSCont.flags.hasMM %re_mm + raw_mm = op_iterativeWaterFilter(raw_mm, waterRemovalFreqRange, 32, fracFID*length(raw_mm.fids), 0); + end + +%% %%% 8. REFERENCE SPECTRUM CORRECTLY TO FREQUENCY AXIS AND PHASE SIEMENS + %%% DATA + [refShift, ~] = osp_XReferencing(raw,[3.03 3.22],[1 1],[1.85 4.2]);% determine frequency shift + if abs(refShift) > 10 % This a huge shift. Most likley wrong and we will try it again with tNAA only + [refShift, ~] = osp_XReferencing(raw,2.01,1,[1.85 4.2]);% determine frequency shift + end + [raw] = op_freqshift(raw,-refShift); % Reference spectra by cross-correlation + + if MRSCont.flags.hasMM %re_mm + if raw_mm.flags.isMEGA + temp = op_takesubspec(raw_mm,3); + [temp,~] = op_autophase(temp,0.5,1.1); + raw_mm = op_mergesubspec(raw_mm,temp); + end + [refShift_mm, ~] = fit_OspreyReferencingMM(raw_mm); + [raw_mm] = op_freqshift(raw_mm,-refShift_mm); % Reference spectra by cross-correlation + end + + % Save back to MRSCont container + if (strcmp(MRSCont.vendor,'Siemens') && raw.flags.isUnEdited) || MRSCont.flags.isMRSI + % Fit a double-Lorentzian to the Cr-Cho area, and phase the spectrum + % with the negative phase of that fit + [raw,globalPhase] = op_phaseCrCho(raw, 1); + raw.specReg{1}.phs = raw.specReg{1}.phs - globalPhase*180/pi; + end + +%% %%% 9. QUALITY CONTROL PARAMETERS %%% + SubSpec = raw.names; + % Calculate some spectral quality metrics here; + [raw,SNR] = op_get_Multispectra_SNR(raw); + FWHM = op_get_Multispectra_LW(raw); + MRSCont.processed.metab{metab_ll,kk} = raw; + for ss = 1 : length(SubSpec) + MRSCont.QM.SNR.metab(metab_ll,kk,ss) = SNR{ss}; + MRSCont.QM.FWHM.metab(metab_ll,kk,ss) = FWHM(ss); % in Hz + MRSCont.QM.freqShift.metab(metab_ll,kk,ss) = refShift; + MRSCont.QM.res_water_amp.metab(metab_ll,kk,ss) = sum(MRSCont.processed.metab{kk}.watersupp{ss}.amp); + if strcmp(SubSpec{ss},'diff1') ||strcmp(SubSpec{ss},'diff2') || strcmp(SubSpec{ss},'diff3') ||strcmp(SubSpec{ss},'sum') + if raw.flags.isMEGA + MRSCont.QM.drift.pre.(SubSpec{ss}){metab_ll,kk} = reshape([MRSCont.QM.drift.pre.A{kk}'; MRSCont.QM.drift.pre.B{kk}'], [], 1)'; + MRSCont.QM.drift.post.(SubSpec{ss}){metab_ll,kk} = reshape([MRSCont.QM.drift.post.A{kk}'; MRSCont.QM.drift.post.B{kk}'], [], 1)'; + else + MRSCont.QM.drift.pre.(SubSpec{ss}){metab_ll,kk} = reshape([MRSCont.QM.drift.pre.A{kk}'; MRSCont.QM.drift.pre.B{kk}'; MRSCont.QM.drift.pre.C{kk}'; MRSCont.QM.drift.pre.D{kk}'], [], 1)'; + MRSCont.QM.drift.post.(SubSpec{ss}){metab_ll,kk} = reshape([MRSCont.QM.drift.post.A{kk}'; MRSCont.QM.drift.post.B{kk}'; MRSCont.QM.drift.pre.C{kk}'; MRSCont.QM.drift.pre.D{kk}'], [], 1)'; + end + end + MRSCont.QM.drift.pre.AvgDeltaCr.(SubSpec{ss})(metab_ll,kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); + MRSCont.QM.drift.post.AvgDeltaCr.(SubSpec{ss})(metab_ll,kk) = mean(MRSCont.QM.drift.post.(SubSpec{ss}){kk} - 3.02); + end + if MRSCont.flags.hasMM + SubSpec = raw_mm.names; + [raw_mm,SNR] = op_get_Multispectra_SNR(raw_mm,1); + FWHM = op_get_Multispectra_LW(raw_mm); + MRSCont.processed.mm{ll,kk} = raw_mm; + for ss = 1 : length(SubSpec) + MRSCont.QM.SNR.mm(mm_ll,kk,ss) = SNR{ss}; + MRSCont.QM.FWHM.mm(mm_ll,kk,ss) = FWHM(ss); + end + end + if MRSCont.flags.hasRef + MRSCont.QM.SNR.ref(ref_ll,kk) = op_getSNR(MRSCont.processed.ref{kk}); + MRSCont.QM.FWHM.ref(ref_ll,kk) = op_getLW(MRSCont.processed.ref{kk},4.2,5.2); + MRSCont.processed.ref{kk}.QC_names = {'water'}; + end + if MRSCont.flags.hasWater + MRSCont.QM.SNR.w(w_ll,kk) = op_getSNR(MRSCont.processed.w{kk}); + MRSCont.QM.FWHM.w(w_ll,kk) = op_getLW(MRSCont.processed.w{kk},4.2,5.2); + MRSCont.processed.w{kk}.QC_names = {'water'}; + end + if MRSCont.flags.hasMMRef + MRSCont.QM.SNR.mm_ref(mm_ref_ll,kk) = op_getSNR(MRSCont.processed.mm_ref{kk}); + MRSCont.QM.FWHM.mm_ref(mm_ref_ll,kk) = op_getLW(MRSCont.processed.mm_ref{kk},4.2,5.2); + MRSCont.processed.mm_ref{kk}.QC_names = {'water'}; + end + end + end +end + + +time = toc(refProcessTime); +[~] = printLog('done',time,MRSCont.nDatasets(1),MRSCont.nDatasets(2),progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); + +%% %%% 10. SET FLAGS %%% +MRSCont.flags.avgsAligned = 1; +MRSCont.flags.averaged = 1; +MRSCont.flags.ECCed = 1; +MRSCont.flags.waterRemoved = 1; +MRSCont.runtime.Proc = time; +% Close any remaining open figures +close all; + +% Gather some more information from the processed data; SubSpecNames = fieldnames(MRSCont.processed); NoSubSpec = length(fieldnames(MRSCont.processed)); for ss = 1 : NoSubSpec for kk = 1 : MRSCont.nDatasets temp_sz(1,kk)= MRSCont.processed.(SubSpecNames{ss}){1,kk}.sz(1); - temp_sz_sw{1,kk} = ['np_sw_' num2str(round(MRSCont.processed.(SubSpecNames{ss}){1,kk}.sz(1))) '_' num2str(round(MRSCont.processed.(SubSpecNames{ss}){1,kk}.spectralwidth))]; + temp_sz_sw{1,kk} = ['np_sw_' num2str(round(MRSCont.processed.(SubSpecNames{ss}){1,kk}.sz(1))) '_' num2str(round(MRSCont.processed.(SubSpecNames{ss}){1,kk}.spectralwidth))]; end [MRSCont.info.(SubSpecNames{ss}).unique_ndatapoint_spectralwidth,MRSCont.info.(SubSpecNames{ss}).unique_ndatapoint_spectralwidth_ind,~] = unique(temp_sz_sw,'Stable'); [MRSCont.info.(SubSpecNames{ss}).max_ndatapoint,MRSCont.info.(SubSpecNames{ss}).max_ndatapoint_ind] = max(temp_sz); end + +%% %%% 11. COMBINE MULTI SPECTRA %%% +if MRSCont.nDatasets(2) > 1 + for ss = 1 : NoSubSpec + for kk = 1:MRSCont.nDatasets(1) + if size(MRSCont.processed.(SubSpecNames{ss}),1) > 1 + MRSCont.processed.(SubSpecNames{ss}){1,kk}.extra_names{1} = MRSCont.opts.extras.names{1}; + for ll = 2:MRSCont.nDatasets(2) + MRSCont.processed.(SubSpecNames{ss}){1,kk}= op_mergeextra(MRSCont.processed.(SubSpecNames{ss}){1,kk},MRSCont.processed.(SubSpecNames{ss}){ll,kk},MRSCont.opts.extras.names{ll}); + end + end + end + MRSCont.processed.(SubSpecNames{ss})(2:end,:) = []; + end +end + %% If DualVoxel or MRSI we want to extract y-axis scaling % Creates y-axis range to align the process plots between datasets @@ -84,66 +714,12 @@ % Set exit flags and reorder fields MRSCont.flags.didProcess = 1; diary off -[MRSCont] = osp_orderProcessFields(MRSCont); - -% Tabulate data quality measures and store in a tsv file -if MRSCont.flags.isUnEdited || MRSCont.flags.isMEGA - names = {'NAA_SNR','NAA_FWHM','residual_water_ampl','freqShift'}; - subspec = {'A'}; - if MRSCont.flags.hasRef - names = {'NAA_SNR','NAA_FWHM','water_FWHM','residual_water_ampl','freqShift'}; - end -elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - % For now, process HERCULES like HERMES data - names = {'NAA_SNR','NAA_FWHM','residual_water_ampl','freqShift'}; - subspec = {'sum'}; - if MRSCont.flags.hasRef - names = {'NAA_SNR','NAA_FWHM','water_FWHM','residual_water_ampl','freqShift'}; - end -else - msg = 'No flag set for sequence type!'; - fprintf(fileID,msg); - error(msg); -end -if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI - if ~MRSCont.flags.hasRef - QM = horzcat(MRSCont.QM.SNR.(subspec{1})',MRSCont.QM.FWHM.(subspec{1})',MRSCont.QM.res_water_amp.(subspec{1})',MRSCont.QM.freqShift.(subspec{1})'); - else - QM = horzcat(MRSCont.QM.SNR.(subspec{1})',MRSCont.QM.FWHM.(subspec{1})',MRSCont.QM.FWHM.ref',MRSCont.QM.res_water_amp.(subspec{1})',MRSCont.QM.freqShift.(subspec{1})'); - end - MRSCont.QM.tables = array2table(QM,'VariableNames',names); +% Calculate QM +MRSCont = calculate_QM(MRSCont); - MRSCont.QM.tables = addprop(MRSCont.QM.tables, {'VariableLongNames'}, {'variable'}); % add long name to table properties - % Loop over field names to populate descriptive fields of table for JSON export - for JJ = 1:length(names) - switch names{JJ} - case 'NAA_SNR' - MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'NAA_SNR'} = 'Signal to noise ratio of NAA'; - MRSCont.QM.tables.Properties.VariableDescriptions{'NAA_SNR'} = 'The maximum amplitude of the NAA peak divided by twice the standard deviation of the noise'; - MRSCont.QM.tables.Properties.VariableUnits{'NAA_SNR'} = 'arbitrary'; - case 'NAA_FWHM' - MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'NAA_FWHM'} = 'Full width at half maximum of NAA'; - MRSCont.QM.tables.Properties.VariableDescriptions{'NAA_FWHM'} = 'The width of the NAA peak at half the maximum amplitude'; - MRSCont.QM.tables.Properties.VariableUnits{'NAA_FWHM'} = 'Hz'; %CWDJ??? - case 'water_FWHM' - MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'water_FWHM'} = 'Full width at half maximum of reference water peak'; - MRSCont.QM.tables.Properties.VariableDescriptions{'water_FWHM'} = 'The width of the water peak at half the maximum amplitude'; - MRSCont.QM.tables.Properties.VariableUnits{'water_FWHM'} = 'Hz'; %CWDJ??? - case 'residual_water_ampl' - MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'residual_water_ampl'} = 'Residual water amplitude'; - MRSCont.QM.tables.Properties.VariableDescriptions{'residual_water_ampl'} = 'The ammount of signal remaining after attempting water subtraction'; - MRSCont.QM.tables.Properties.VariableUnits{'residual_water_ampl'} = 'arbitrary'; - case 'freqShift' - MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'freqShift'} = 'Frequency shift'; - MRSCont.QM.tables.Properties.VariableDescriptions{'freqShift'} = 'Frequency shift'; %CWDJ Need full description - MRSCont.QM.tables.Properties.VariableUnits{'freqShift'} = 'PPM'; %CWDJ??? - end - end - - % Write .tsv file and .json sidecar - osp_WriteBIDsTable(MRSCont.QM.tables, [outputFolder filesep 'QM_processed_spectra']) -end +% Write .tsv file and .json sidecar +osp_WriteBIDsTable(MRSCont.QM.tables, [outputFolder filesep 'QM_processed_spectra']) % Optional: Create all pdf figures if MRSCont.opts.savePDF @@ -189,3 +765,103 @@ end end +%% Functions for processing +function [raw] = combine_water_subspecs(raw) +% Some formats end up having subspectra in their reference scans +% (e.g. Philips), as well as empty lines. Intercept these cases +% here. + if raw.subspecs == 2 + raw_A = op_takesubspec(raw,1); + [raw_A] = op_rmempty(raw_A); % Remove empty lines + raw_B = op_takesubspec(raw,2); + [raw_B] = op_rmempty(raw_B); % Remove empty lines + raw = op_concatAverages(raw_A,raw_B); + end + + if raw.subspecs == 4 + raw_A = op_takesubspec(raw,1); + [raw_A] = op_rmempty(raw_A); % Remove empty lines + raw_B = op_takesubspec(raw,2); + [raw_B] = op_rmempty(raw_B); % Remove empty lines + raw_C = op_takesubspec(raw,3); + [raw_C] = op_rmempty(raw_C); % Remove empty lines + raw_D = op_takesubspec(raw,4); + [raw_D] = op_rmempty(raw_D); % Remove empty lines + raw = op_concatAverages(raw_A,raw_B,raw_C,raw_D); + end + + % Align and verage the refernce data + if raw.averages > 1 && ~raw.flags.averaged + [raw] = op_rmempty(raw); + [raw,~,~] = op_alignAverages(raw, 1, 'n'); + raw = op_averaging(raw); % Average + else + raw.flags.averaged = 1; + raw.dims.averages = 0; + end + raw.names = {'A'}; +end + +function MRSCont = calculate_QM(MRSCont) +% Sort processed field +MRSCont = osp_orderProcessFields(MRSCont); +% Store data quality measures in csv file +if MRSCont.flags.isUnEdited + subspec = 1; + name = 'A'; +elseif MRSCont.flags.isMEGA + subspec = 1; + name = 'A'; +elseif MRSCont.flags.isHERMES + subspec = 7; + name = 'sum'; +elseif MRSCont.flags.isHERCULES + subspec = 7; + name = 'sum'; +else + msg = 'No flag set for sequence type!'; + fprintf(fileID,msg); + error(msg); +end +names = {'NAA_SNR','NAA_FWHM','residual_water_ampl','freqShift'}; +if MRSCont.flags.hasRef + names = {'NAA_SNR','NAA_FWHM','water_FWHM','residual_water_ampl','freqShift'}; +end + +if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI + if ~MRSCont.flags.hasRef + QM = horzcat(MRSCont.QM.SNR.metab(1,:,subspec)',MRSCont.QM.FWHM.metab(1,:,subspec)',MRSCont.QM.res_water_amp.metab(1,:,subspec)',MRSCont.QM.freqShift.metab(1,:,subspec)'); + else + QM = horzcat(MRSCont.QM.SNR.metab(1,:,subspec)',MRSCont.QM.FWHM.metab(1,:,subspec)',MRSCont.QM.FWHM.ref(1,:)',MRSCont.QM.res_water_amp.metab(1,:,subspec)',MRSCont.QM.freqShift.metab(1,:,subspec)'); + end + MRSCont.QM.tables = array2table(QM,'VariableNames',names); + + MRSCont.QM.tables = addprop(MRSCont.QM.tables, {'VariableLongNames'}, {'variable'}); % add long name to table properties + % Loop over field names to populate descriptive fields of table for JSON export + for JJ = 1:length(names) + switch names{JJ} + case 'NAA_SNR' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'NAA_SNR'} = 'Signal to noise ratio of NAA'; + MRSCont.QM.tables.Properties.VariableDescriptions{'NAA_SNR'} = ['The maximum amplitude of the NAA peak divided by twice the standard deviation of the noise calculated from subspectrum ' name]; + MRSCont.QM.tables.Properties.VariableUnits{'NAA_SNR'} = 'arbitrary'; + case 'NAA_FWHM' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'NAA_FWHM'} = 'Full width at half maximum of NAA'; + MRSCont.QM.tables.Properties.VariableDescriptions{'NAA_FWHM'} = ['The width of the NAA peak at half the maximum amplitude calculated as the average of the FWHM of the data and the FWHM of a lorentzian fit calculated from subspectrum ' name]; + MRSCont.QM.tables.Properties.VariableUnits{'NAA_FWHM'} = 'Hz'; + case 'water_FWHM' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'water_FWHM'} = 'Full width at half maximum of reference water peak'; + MRSCont.QM.tables.Properties.VariableDescriptions{'water_FWHM'} = 'The width of the water peak at half the maximum amplitude calculated as the average of the FWHM of the data and the FWHM of a lorentzian fit'; + MRSCont.QM.tables.Properties.VariableUnits{'water_FWHM'} = 'Hz'; + case 'residual_water_ampl' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'residual_water_ampl'} = 'Residual water amplitude'; + MRSCont.QM.tables.Properties.VariableDescriptions{'residual_water_ampl'} = ['The amplitude of the water signal removed by the HSVD filter calculated from subspectrum ' name]; + MRSCont.QM.tables.Properties.VariableUnits{'residual_water_ampl'} = 'arbitrary'; + case 'freqShift' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'freqShift'} = 'Frequency shift'; + MRSCont.QM.tables.Properties.VariableDescriptions{'freqShift'} = ['Frequency shift calculated from the cross-correlation between spectrum ' name 'and the reference peaks (creatine and choline)']; + MRSCont.QM.tables.Properties.VariableUnits{'freqShift'} = 'Hz'; + end + end + +end +end \ No newline at end of file diff --git a/process/osp_AverageAllDatasetsAlongExtra.m b/process/osp_AverageAllDatasetsAlongExtra.m new file mode 100644 index 00000000..dc6e3427 --- /dev/null +++ b/process/osp_AverageAllDatasetsAlongExtra.m @@ -0,0 +1,149 @@ +function [MRSCont] = osp_AverageAllDatasetsAlongExtra(MRSCont) +%% [MRSCont] = osp_AverageAllDatasetsAlongExtra(MRSCont) +% This function averages all files of the MRSContainer along the extra +% dimension. This can be useful to combine several acquisitons from the +% same voxel. SNR and linewidth will be recalculated. Drift plots will +% not be accurate anymore! + +% Checking for version, toolbox, and previously run modules +osp_CheckRunPreviousModule(MRSCont, 'OspreyFit'); +outputFolder = MRSCont.outputFolder; +diary(fullfile(outputFolder, 'LogFile.txt')); +%% Combining data +for kk = 1:MRSCont.nDatasets(1) + MRSCont.processed.metab{1, kk}=op_average_extra(MRSCont.processed.metab{1, kk},1); + + if MRSCont.flags.hasMM + MRSCont.processed.mm{1, kk}=op_average_extra(MRSCont.processed.mm{1, kk},1); + end + + if MRSCont.flags.hasMMRef + MRSCont.processed.mm_ref{1, kk}=op_average_extra(MRSCont.processed.mm_ref{1, kk},1); + end + + if MRSCont.flags.hasRef + MRSCont.processed.ref{1, kk}=op_average_extra(MRSCont.processed.ref{1, kk},1); + end + + if MRSCont.flags.hasWater + MRSCont.processed.w{1, kk}=op_average_extra(MRSCont.processed.w{1, kk},1); + end +end + +%% Recalculate QM +for kk = 1:MRSCont.nDatasets(1) + SubSpec = MRSCont.processed.metab{1, kk}.names; + % Calculate some spectral quality metrics here; + [MRSCont.processed.metab{1, kk},SNR] = op_get_Multispectra_SNR(MRSCont.processed.metab{1, kk}); + FWHM = op_get_Multispectra_LW(MRSCont.processed.metab{1, kk}); + for ss = 1 : length(SubSpec) + MRSCont.QM.SNR.metab(1,kk,ss) = SNR{ss}; + MRSCont.QM.FWHM.metab(1,kk,ss) = FWHM(ss); % in Hz + end + if MRSCont.flags.hasMM + SubSpec = MRSCont.processed.mm{1, kk}.names; + [MRSCont.processed.mm{1, kk},SNR] = op_get_Multispectra_SNR(MRSCont.processed.mm{1, kk},1); + FWHM = op_get_Multispectra_LW(MRSCont.processed.mm{1, kk}); + for ss = 1 : length(SubSpec) + MRSCont.QM.SNR.mm(1,kk,ss) = SNR{ss}; + MRSCont.QM.FWHM.mm(1,kk,ss) = FWHM(ss); + end + end + if MRSCont.flags.hasRef + MRSCont.QM.SNR.ref(1,kk) = op_getSNR(MRSCont.processed.ref{kk}); + MRSCont.QM.FWHM.ref(1,kk) = op_getLW(MRSCont.processed.ref{kk},4.2,5.2); + MRSCont.processed.ref{kk}.QC_names = {'water'}; + end + if MRSCont.flags.hasWater + MRSCont.QM.SNR.w(1,kk) = op_getSNR(MRSCont.processed.w{kk}); + MRSCont.QM.FWHM.w(1,kk) = op_getLW(MRSCont.processed.w{kk},4.2,5.2); + MRSCont.processed.w{kk}.QC_names = {'water'}; + end + if MRSCont.flags.hasMMRef + MRSCont.QM.SNR.mm_ref(1,kk) = op_getSNR(MRSCont.processed.mm_ref{kk}); + MRSCont.QM.FWHM.mm_ref(1,kk) = op_getLW(MRSCont.processed.mm_ref{kk},4.2,5.2); + MRSCont.processed.mm_ref{kk}.QC_names = {'water'}; + end + +end + +%% Clean up and save +diary off +% Store data quality measures in csv file +if MRSCont.flags.isUnEdited + subspec = 1; + name = 'A'; +elseif MRSCont.flags.isMEGA + subspec = 1; + name = 'A'; +elseif MRSCont.flags.isHERMES + subspec = 7; + name = 'sum'; +elseif MRSCont.flags.isHERCULES + subspec = 7; + name = 'sum'; +else + msg = 'No flag set for sequence type!'; + fprintf(fileID,msg); + error(msg); +end +names = {'NAA_SNR','NAA_FWHM','residual_water_ampl','freqShift'}; +if MRSCont.flags.hasRef + names = {'NAA_SNR','NAA_FWHM','water_FWHM','residual_water_ampl','freqShift'}; +end + +if ~MRSCont.flags.isPRIAM && ~MRSCont.flags.isMRSI + if ~MRSCont.flags.hasRef + QM = horzcat(MRSCont.QM.SNR.metab(1,:,subspec)',MRSCont.QM.FWHM.metab(1,:,subspec)',MRSCont.QM.res_water_amp.metab(1,:,subspec)',MRSCont.QM.freqShift.metab(1,:,subspec)'); + else + QM = horzcat(MRSCont.QM.SNR.metab(1,:,subspec)',MRSCont.QM.FWHM.metab(1,:,subspec)',MRSCont.QM.FWHM.ref(1,:)',MRSCont.QM.res_water_amp.metab(1,:,subspec)',MRSCont.QM.freqShift.metab(1,:,subspec)'); + end + MRSCont.QM.tables = array2table(QM,'VariableNames',names); + + MRSCont.QM.tables = addprop(MRSCont.QM.tables, {'VariableLongNames'}, {'variable'}); % add long name to table properties + % Loop over field names to populate descriptive fields of table for JSON export + for JJ = 1:length(names) + switch names{JJ} + case 'NAA_SNR' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'NAA_SNR'} = 'Signal to noise ratio of NAA'; + MRSCont.QM.tables.Properties.VariableDescriptions{'NAA_SNR'} = ['The maximum amplitude of the NAA peak divided by twice the standard deviation of the noise calculated from subspectrum ' name]; + MRSCont.QM.tables.Properties.VariableUnits{'NAA_SNR'} = 'arbitrary'; + case 'NAA_FWHM' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'NAA_FWHM'} = 'Full width at half maximum of NAA'; + MRSCont.QM.tables.Properties.VariableDescriptions{'NAA_FWHM'} = ['The width of the NAA peak at half the maximum amplitude calculated as the average of the FWHM of the data and the FWHM of a lorentzian fit calculated from subspectrum ' name]; + MRSCont.QM.tables.Properties.VariableUnits{'NAA_FWHM'} = 'Hz'; + case 'water_FWHM' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'water_FWHM'} = 'Full width at half maximum of reference water peak'; + MRSCont.QM.tables.Properties.VariableDescriptions{'water_FWHM'} = 'The width of the water peak at half the maximum amplitude calculated as the average of the FWHM of the data and the FWHM of a lorentzian fit'; + MRSCont.QM.tables.Properties.VariableUnits{'water_FWHM'} = 'Hz'; + case 'residual_water_ampl' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'residual_water_ampl'} = 'Residual water amplitude'; + MRSCont.QM.tables.Properties.VariableDescriptions{'residual_water_ampl'} = ['The amplitude of the water signal removed by the HSVD filter calculated from subspectrum ' name]; + MRSCont.QM.tables.Properties.VariableUnits{'residual_water_ampl'} = 'arbitrary'; + case 'freqShift' + MRSCont.QM.tables.Properties.CustomProperties.VariableLongNames{'freqShift'} = 'Frequency shift'; + MRSCont.QM.tables.Properties.VariableDescriptions{'freqShift'} = ['Frequency shift calculated from the cross-correlation between spectrum ' name 'and the reference peaks (creatine and choline)']; + MRSCont.QM.tables.Properties.VariableUnits{'freqShift'} = 'Hz'; + end + end + + % Write .tsv file and .json sidecar + osp_WriteBIDsTable(MRSCont.QM.tables, [outputFolder filesep 'QM_processed_spectra']) +end + +% Save the output structure to the output folder +% Determine output folder +outputFile = MRSCont.outputFile; +if ~exist(outputFolder,'dir') + mkdir(outputFolder); +end + +if MRSCont.flags.isGUI + MRSCont.flags.isGUI = 0; + save(fullfile(outputFolder, outputFile), 'MRSCont','-v7.3'); + MRSCont.flags.isGUI = 1; +else + save(fullfile(outputFolder, outputFile), 'MRSCont','-v7.3'); +end + +end \ No newline at end of file diff --git a/process/osp_CrChoReferencing.m b/process/osp_CrChoReferencing.m index 3d856642..52f96006 100644 --- a/process/osp_CrChoReferencing.m +++ b/process/osp_CrChoReferencing.m @@ -28,6 +28,16 @@ % History: % 2018-10-12: First version of the code. % +% We want to be able to process spectra that are not averaged and do have +% more then one sub-spectrum. +if dataToFit.dims.averages>0 + dataToFit = op_averaging(dataToFit); +end + +if dataToFit.dims.subSpecs>0 + ind = find(strcmp(dataToFit.names,'sum')); + dataToFit = op_takesubspec(dataToFit,ind); +end % Calculate power spectrum to estimate reference shift and FWHM dataToFit=op_freqrange(dataToFit,1.85,4.2); @@ -38,12 +48,12 @@ y = zeros(size(x)); % Set up delta functions -% [a,b] = min((abs(x-2.01))); -[c,d] = min((abs(x-3.03))); -[e,f] = min((abs(x-3.22))); -% y(b) = 1; -y(d) = 1; -y(f) = 1; +[a,b] = min((abs(x-2.01))); +% [c,d] = min((abs(x-3.03))); +% [e,f] = min((abs(x-3.22))); +y(b) = 1; +% y(d) = 1; +% y(f) = 1; % Plot cross-correlation function, normalize it to its maximum r = crosscorr(powerspec,y)'; diff --git a/process/osp_XReferencing.m b/process/osp_XReferencing.m new file mode 100644 index 00000000..43c4995d --- /dev/null +++ b/process/osp_XReferencing.m @@ -0,0 +1,127 @@ +function [refShift, refFWHM] = osp_XReferencing(dataToFit,frequencies,polarity,lim,realpart) +%% [refShift, refFWHM] = osp_XReferencing(dataToFit) +% Calculates the reference shift and full-width half-maximum (FWHM) of a +% spectrum according to the LCModel algorithm. The algorithm is described in: +% S.W. Provencher, "Estimation of metabolite concentrations from +% localized in vivo NMR spectra", Magn Reson Med 30(6):672-679 (1993) +% +% The algorithm first determines the power spectrum of the input +% spectrum, before calculating the cross-correlation with a function +% containing delta functions at 2.01 ppm (NAA), 3.03 ppm (Cr), and 3.22 +% ppm (Cho). +% The frequency of the largest peak of the cross-correlation function is +% returned as the initial referencing shift of the input spectrum. +% The FWHM of the largest peak of the cross-correlation function is +% returned as an estimate of the FWHM of the input spectrum. +% +% Input: +% dataToFit = FID-A data structure +% +% Output: +% refShift = Reference frequency shift (in Hz) +% FWHM = full-width half-maximum of the input spectrum (in ppm) +% +% Author: +% Dr. Georg Oeltzschner (Johns Hopkins University, 2018-10-12) +% goeltzs1@jhmi.edu +% +% History: +% 2018-10-12: First version of the code. +% + +if nargin < 5 + realpart = 0; +end +% We want to be able to process spectra that are not averaged and do have +% more then one sub-spectrum. +if dataToFit.dims.averages>0 + dataToFit = op_averaging(dataToFit); +end + +if dataToFit.dims.subSpecs>0 + ind = find(strcmp(dataToFit.names,'sum')); + dataToFit = op_takesubspec(dataToFit,ind); +end + +% Calculate power spectrum to estimate reference shift and FWHM +LimL = lim(1); +LimR = lim(2); + +if sum(frequencies 0 + LimL = min(freq); +end + +if sum(frequencies>LimR) > 0 + LimR = max(freq); +end + +dataToFit=op_freqrange(dataToFit,LimL,LimR); +spec = dataToFit.specs; +ppm = dataToFit.ppm; +if ~realpart + corrspec = spec .* conj(spec) / length(spec); +else + corrspec = real(spec); +end +x = ppm; +y = zeros(size(x)); + +% Set up delta functions +for Xc = 1 : length(frequencies) +[~,pos] = min((abs(x-frequencies(Xc)))); +y(pos) = polarity(Xc); +end + +% Plot cross-correlation function, normalize it to its maximum +r = crosscorr(corrspec,y)'; +r = r./(max(r)); +% Set up Lorentzian fit to the central peak of the cross-correlation +% function +% x-axis of cross-correlation function +newx = [1:1:(2*length(spec)-1)]; + +% fit the center peak +limits = newx >= 0.94*length(spec) & newx <= 1.06*length(spec); +[max_value,max_ind] = max(r(limits)); +tempx = newx(limits); +tempr = r(limits); +gtHalfMax=find(tempr >= 0.5 * max_value); +HWHM=abs(tempx(gtHalfMax(1)) - tempx(gtHalfMax(end)))/2 * 0.8; +if HWHM == 0 + gtHalfMax=find(tempr >= 0.3 * max_value); + HWHM=abs(tempx(gtHalfMax(1)) - tempx(gtHalfMax(end)))/2 * 0.8; +end + +nlinopts = statset('nlinfit'); +% nlinopts = statset(nlinopts,'MaxIter',1e8,'MaxFunEvals',1e8,'TolX',1e-10,'TolFun',1e-10); +LorentzModelInit = [1 HWHM tempx(max_ind) 0]; + +try + LorentzModelParam = lsqcurvefit(@LorentzModel,LorentzModelInit,newx(limits),real(r(limits)),[1 0 tempx(1) -180],[1 2*HWHM tempx(end) 180],nlinopts); + % Return FWHM and reference shift + refFWHM = 2 * LorentzModelParam(2) * abs(ppm(1)-ppm(2)); + refShift = (LorentzModelParam(3) - length(newx)/2) * (ppm(1)-ppm(2)) * dataToFit.txfrq*1e-6; +catch + refFWHM = nan; + refShift = 0; +end + +%%% embedded Lorentzian model function +function Lorentz = LorentzModel(x,freq) +% CJE LorentzModel +% Lorentzian = (1/pi) * (hwhm) / (deltaf^2 + hwhm^2) (Wolfram) +% Peak height of Lorentzian = 4 / (pi*hwhm) +% This defnition of the Lorentzian has Area = 1 + +area = x(1); +hwhm = x(2); +f0 = x(3); +phase = x(4); + +Absorption = 1/(2*pi) * area * ones(size(freq)) .* hwhm ./ ((freq-f0).^2 + hwhm.^2); +Dispersion = 1/(2*pi) * area * (freq-f0) ./ ((freq-f0).^2 + hwhm.^2); + +Lorentz = Absorption*cos(phase) + Dispersion * sin(phase); +end + +end \ No newline at end of file diff --git a/process/osp_combineCoils.m b/process/osp_combineCoils.m index 3bfd720e..4e47ac77 100644 --- a/process/osp_combineCoils.m +++ b/process/osp_combineCoils.m @@ -1,4 +1,4 @@ -function [MRSCont] = osp_combineCoils(MRSCont,kk) +function [MRSCont] = osp_combineCoils(MRSCont,kk,ll,ref_ll,w_ll) %% [MRSCont] = osp_combineCoils(MRSCont) % This function performs a the receiver coil combination of multi-array % data. All coil-combination procedures are performed using the ratio of @@ -26,8 +26,8 @@ % AUTHOR: % Dr. Georg Oeltzschner (Johns Hopkins University, 2019-02-20) % goeltzs1@jhmi.edu -% -% CREDITS: +% +% CREDITS: % This code is based on numerous functions from the FID-A toolbox by % Dr. Jamie Near (McGill University) % https://github.com/CIC-methods/FID-A @@ -38,41 +38,66 @@ %% Calculate coil combination weights -if nargin<2 +if nargin<5 % Loop over all datasets - for kk = 1:MRSCont.nDatasets - % Check if reference scans exist, if so, get CC coefficients from there - if MRSCont.flags.hasRef - cweights = op_getcoilcombos(MRSCont.raw_ref_uncomb{kk},1,'h'); - raw_comb = op_addrcvrs(MRSCont.raw_uncomb{kk},1,'h',cweights); - raw_ref_comb = op_addrcvrs(MRSCont.raw_ref_uncomb{kk},1,'h',cweights); - MRSCont.raw{kk} = raw_comb; - MRSCont.raw_ref{kk} = raw_ref_comb; - if MRSCont.raw_ref{kk}.subspecs > 1 - if MRSCont.flags.isMEGA - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - MRSCont.raw_ref{kk} = op_concatAverages(raw_ref_A,raw_ref_B); - else - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - raw_ref_C = op_takesubspec(MRSCont.raw_ref{kk},3); - raw_ref_D = op_takesubspec(MRSCont.raw_ref{kk},4); - MRSCont.raw_ref{kk} = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + for kk = 1:MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + % Check if reference scans exist, if so, get CC coefficients from there + if MRSCont.flags.hasRef + cweights = op_getcoilcombos(MRSCont.raw_ref_uncomb{ll,kk},1,'h'); + raw_comb = op_addrcvrs(MRSCont.raw_uncomb{ll,kk},1,'h',cweights); + raw_ref_comb = op_addrcvrs(MRSCont.raw_ref_uncomb{ll,kk},1,'h',cweights); + if MRSCont.flags.isUnEdited + raw_comb.flags.isUnEdited = 1; + raw_ref_comb.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_comb.flags.isMEGA = 1; + raw_ref_comb.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_comb.flags.isHERMES = 1; + raw_ref_comb.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_comb.flags.isHERCULES = 1; + raw_ref_comb.flags.isHERCULES = 1; end - end - else - % if not, use the metabolite scan itself - cweights = op_getcoilcombos(MRSCont.raw_uncomb{kk},1,'h'); - raw_comb = op_addrcvrs(MRSCont.raw_uncomb{kk},1,'h',cweights); - MRSCont.raw{kk} = raw_comb; - end + MRSCont.raw{ll,kk} = raw_comb; + MRSCont.raw_ref{ll,kk} = raw_ref_comb; + if MRSCont.raw_ref{ll,kk}.subspecs > 1 + if MRSCont.flags.isMEGA + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ll,kk},2); + MRSCont.raw_ref{ll,kk} = op_concatAverages(raw_ref_A,raw_ref_B); + else + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ll,kk},2); + raw_ref_C = op_takesubspec(MRSCont.raw_ref{ll,kk},3); + raw_ref_D = op_takesubspec(MRSCont.raw_ref{ll,kk},4); + MRSCont.raw_ref{ll,kk} = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); + end + end + else + % if not, use the metabolite scan itself + cweights = op_getcoilcombos(MRSCont.raw_uncomb{ll,kk},1,'h'); + raw_comb = op_addrcvrs(MRSCont.raw_uncomb{ll,kk},1,'h',cweights); + if MRSCont.flags.isUnEdited + raw_comb.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_comb.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_comb.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_comb.flags.isHERCULES = 1; + end + MRSCont.raw{ll,kk} = raw_comb; + end - % Now do the same for the (short-TE) water signal - if MRSCont.flags.hasWater - cweights_w = op_getcoilcombos(MRSCont.raw_w_uncomb{kk},1,'h'); - raw_w_comb = op_addrcvrs(MRSCont.raw_w_uncomb{kk},1,'h',cweights_w); - MRSCont.raw_w{kk} = raw_w_comb; + % Now do the same for the (short-TE) water signal + if MRSCont.flags.hasWater + cweights_w = op_getcoilcombos(MRSCont.raw_w_uncomb{ll,kk},1,'h'); + raw_w_comb = op_addrcvrs(MRSCont.raw_w_uncomb{ll,kk},1,'h',cweights_w); + raw_w_comb.flags.isUnEdited = 1; + MRSCont.raw_w{ll,kk} = raw_w_comb; + end end end else @@ -80,21 +105,34 @@ if MRSCont.flags.hasRef try cweights = op_getcoilcombos(MRSCont.raw_ref_uncomb{kk},1,'h'); - raw_comb = op_addrcvrs(MRSCont.raw_uncomb{kk},1,'h',cweights); - raw_ref_comb = op_addrcvrs(MRSCont.raw_ref_uncomb{kk},1,'h',cweights); - MRSCont.raw{kk} = raw_comb; - MRSCont.raw_ref{kk} = raw_ref_comb; - if MRSCont.raw_ref{kk}.subspecs > 1 && (length(size(MRSCont.raw_ref{kk}.fids)) > 2) + raw_comb = op_addrcvrs(MRSCont.raw_uncomb{ll,kk},1,'h',cweights); + raw_ref_comb = op_addrcvrs(MRSCont.raw_ref_uncomb{ref_ll,kk},1,'h',cweights); + if MRSCont.flags.isUnEdited + raw_comb.flags.isUnEdited = 1; + raw_ref_comb.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_comb.flags.isMEGA = 1; + raw_ref_comb.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_comb.flags.isHERMES = 1; + raw_ref_comb.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_comb.flags.isHERCULES = 1; + raw_ref_comb.flags.isHERCULES = 1; + end + MRSCont.raw{ll,kk} = raw_comb; + MRSCont.raw_ref{ref_ll,kk} = raw_ref_comb; + if MRSCont.raw_ref{ref_ll,kk}.subspecs > 1 if MRSCont.flags.isMEGA - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - MRSCont.raw_ref{kk} = op_concatAverages(raw_ref_A,raw_ref_B); + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(raw_ref_A,raw_ref_B); else - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - raw_ref_C = op_takesubspec(MRSCont.raw_ref{kk},3); - raw_ref_D = op_takesubspec(MRSCont.raw_ref{kk},4); - MRSCont.raw_ref{kk} = op_concatAverages(op_concatAverages(raw_ref_A,raw_ref_B),op_concatAverages(raw_ref_C,raw_ref_D)); + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + raw_ref_C = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},3); + raw_ref_D = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},4); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(op_concatAverages(raw_ref_A,raw_ref_B),op_concatAverages(raw_ref_C,raw_ref_D)); end else MRSCont.raw_ref{kk}.subspecs = 1; @@ -102,23 +140,36 @@ end catch % if wrong number of channels etc, use the metabolite scan itself - cweights = op_getcoilcombos(MRSCont.raw_uncomb{kk},1,'h'); - raw_comb = op_addrcvrs(MRSCont.raw_uncomb{kk},1,'h',cweights); + cweights = op_getcoilcombos(MRSCont.raw_uncomb{ll,kk},1,'h'); + raw_comb = op_addrcvrs(MRSCont.raw_uncomb{ll,kk},1,'h',cweights); + cweights = op_getcoilcombos(MRSCont.raw_ref_uncomb{ref_ll,kk},1,'h'); + raw_ref_comb = op_addrcvrs(MRSCont.raw_ref_uncomb{ref_ll,kk},1,'h',cweights); + if MRSCont.flags.isUnEdited + raw_comb.flags.isUnEdited = 1; + raw_ref_comb.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_comb.flags.isMEGA = 1; + raw_ref_comb.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_comb.flags.isHERMES = 1; + raw_ref_comb.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_comb.flags.isHERCULES = 1; + raw_ref_comb.flags.isHERCULES = 1; + end MRSCont.raw{kk} = raw_comb; - cweights = op_getcoilcombos(MRSCont.raw_ref_uncomb{kk},1,'h'); - raw_ref_comb = op_addrcvrs(MRSCont.raw_ref_uncomb{kk},1,'h',cweights); - MRSCont.raw_ref{kk} = raw_ref_comb; - if MRSCont.raw_ref{kk}.subspecs > 1 && (length(size(MRSCont.raw_ref{kk}.fids)) > 2) + MRSCont.raw_ref{ref_ll,kk} = raw_ref_comb; + if MRSCont.raw_ref{ref_ll,kk}.subspecs > 1 if MRSCont.flags.isMEGA - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - MRSCont.raw_ref{kk} = op_concatAverages(raw_ref_A,raw_ref_B); + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(raw_ref_A,raw_ref_B); else - raw_ref_A = op_takesubspec(MRSCont.raw_ref{kk},1); - raw_ref_B = op_takesubspec(MRSCont.raw_ref{kk},2); - raw_ref_C = op_takesubspec(MRSCont.raw_ref{kk},3); - raw_ref_D = op_takesubspec(MRSCont.raw_ref{kk},4); - MRSCont.raw_ref{kk} = op_concatAverages(op_concatAverages(raw_ref_A,raw_ref_B),op_concatAverages(raw_ref_C,raw_ref_D)); + raw_ref_A = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},1); + raw_ref_B = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},2); + raw_ref_C = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},3); + raw_ref_D = op_takesubspec(MRSCont.raw_ref{ref_ll,kk},4); + MRSCont.raw_ref{ref_ll,kk} = op_concatAverages(op_concatAverages(raw_ref_A,raw_ref_B),op_concatAverages(raw_ref_C,raw_ref_D)); end else MRSCont.raw_ref{kk}.subspecs = 1; @@ -127,29 +178,32 @@ end else % if not, use the metabolite scan itself - cweights = op_getcoilcombos(MRSCont.raw_uncomb{kk},1,'h'); - raw_comb = op_addrcvrs(MRSCont.raw_uncomb{kk},1,'h',cweights); - MRSCont.raw{kk} = raw_comb; + cweights = op_getcoilcombos(MRSCont.raw_uncomb{ll,kk},1,'h'); + raw_comb = op_addrcvrs(MRSCont.raw_uncomb{ll,kk},1,'h',cweights); + if MRSCont.flags.isUnEdited + raw_comb.flags.isUnEdited = 1; + elseif MRSCont.flags.isMEGA + raw_comb.flags.isMEGA = 1; + elseif MRSCont.flags.isHERMES + raw_comb.flags.isHERMES = 1; + elseif MRSCont.flags.isHERCULES + raw_comb.flags.isHERCULES = 1; + end + MRSCont.raw{ll,kk} = raw_comb; end % Now do the same for the (short-TE) water signal if MRSCont.flags.hasWater - cweights_w = op_getcoilcombos(MRSCont.raw_w_uncomb{kk},1,'h'); - raw_w_comb = op_addrcvrs(MRSCont.raw_w_uncomb{kk},1,'h',cweights_w); - MRSCont.raw_w{kk} = raw_w_comb; + cweights_w = op_getcoilcombos(MRSCont.raw_w_uncomb{w_ll,kk},1,'h'); + raw_w_comb = op_addrcvrs(MRSCont.raw_w_uncomb{w_ll,kk},1,'h',cweights_w); + raw_w_comb.flags.isUnEdited = 1; + MRSCont.raw_w{w_ll,kk} = raw_w_comb; end -end +end %% Clean up and save % Set flags MRSCont.flags.coilsCombined = 1; -% Delete un-combined data to free up memory -raw_fields = {'raw_uncomb','raw_ref_uncomb','raw_w_uncomb'}; -for kk = 1:length(raw_fields) - if isfield(MRSCont, raw_fields{kk}) - MRSCont = rmfield(MRSCont, raw_fields{kk}); - end -end - -end \ No newline at end of file + +end diff --git a/process/osp_editSubSpecAlign.m b/process/osp_editSubSpecAlign.m index e2aab56a..a2695ee1 100644 --- a/process/osp_editSubSpecAlign.m +++ b/process/osp_editSubSpecAlign.m @@ -1,16 +1,14 @@ -function [varargout] = osp_editSubSpecAlign(varargin) +function [out] = osp_editSubSpecAlign(varargin) %% [varargout] = osp_editSubSpecAlign(varargin) % Aligns sub-spectra of (multiplexed) edited MRS data to minimize % subtraction artefacts. % % USAGE: -% [outA, outB, outC, outD] = osp_editSubSpecAlign(inA, inB, inC, inD, target,unstableWater); +% [outA, outB, outC, outD] = osp_editSubSpecAlign(in, seq, target,unstableWater); % % INPUTS: -% inA = Input data structure with sub-spectrum A. -% inB = Input data structure with sub-spectrum B. -% inC = Input data structure with sub-spectrum C. (optional) -% inD = Input data structure with sub-spectrum D. (optional) +% in = Input data structure with sub-spectrum A. +% seq = sequence type % target = String. Can be 'GABA' or 'GSH'. (necessary if only two % inputs inA and inB are provided) % unstableWater = Flag for unstable residual water. This ignores @@ -37,60 +35,61 @@ % HISTORY: % 2019-08-15: First version of the code. + % Determine whether there are 2 (MEGA) or 4 (HERMES/HERCULES) inputs -if nargin == 7 - seqType = 'HERMES'; - inA = varargin{1}; - inB = varargin{2}; - inC = varargin{3}; - inD = varargin{4}; - unstableWater = varargin{5}; - target1 = varargin{6}; - target2 = varargin{7}; -elseif nargin == 5 - seqType = 'HERMES'; - inA = varargin{1}; - inB = varargin{2}; - inC = varargin{3}; - inD = varargin{4}; +if nargin == 5 + in = varargin{1}; + seqType = varargin{2}; + target1 = varargin{3}; + target2 = varargin{4}; unstableWater = varargin{5}; -elseif nargin == 4 && isstruct(varargin{4}) - seqType = 'HERMES'; - inA = varargin{1}; - inB = varargin{2}; - inC = varargin{3}; - inD = varargin{4}; +elseif nargin == 4 && (strcmp(varargin{2},'HERMES') || strcmp(varargin{2},'HERCULES')) + in = varargin{1}; + seqType = varargin{2}; + target1 = varargin{3}; + target2 = varargin{4}; unstableWater = 0; -elseif nargin == 4 && ~isstruct(varargin{4}) - seqType = 'MEGA'; - inA = varargin{1}; - inB = varargin{2}; - target = varargin{3}; +elseif nargin == 4 + in = varargin{1}; + seqType = varargin{2}; + target = varargin{3}; unstableWater = varargin{4}; -elseif nargin == 3 && ischar(varargin{3}) - seqType = 'MEGA'; - inA = varargin{1}; - inB = varargin{2}; +elseif nargin == 3 && strcmp(varargin{2},'MEGA') + in = varargin{1}; + seqType = varargin{2}; target = varargin{3}; unstableWater = 0; -elseif nargin == 3 && ~ischar(varargin{3}) - error('Error in osp_editSubSpecAlign! For MEGA data, provide 2 sub-spectra, the name of the editing target, and the optional unstable water flag.'); -elseif nargin == 2 - error('Error in osp_editSubSpecAlign! For MEGA data, provide 2 sub-spectra, the name of the editing target, and the optional unstable water flag.'); else - error('Error in osp_editSubSpecAlign! Needs to have either 2 (for MEGA) or 4 (for HERMES/HERCULES) sub-spectra provided'); + error('Error in osp_editSubSpecAlign! For provide raw data struct, the sequence type, the name of the editing target, and the optional unstable water flag.') end % Check whether data is coil-combined. If not, throw error. -if ~inA.flags.addedrcvrs +if ~in.flags.addedrcvrs error('ERROR: I think it only makes sense to do this after you have combined the channels using op_addrcvrs. ABORTING!!'); end % Check whether data is averaged. If not, throw error. -if ~inA.flags.averaged +if ~in.flags.averaged error('ERROR: I think it only makes sense to do this after averaging using op_averaging. ABORTING!!'); end +switch seqType + case 'MEGA' + inA=op_takesubspec(in,1); + inB=op_takesubspec(in,2); + case 'HERMES' + inA=op_takesubspec(in,1); + inB=op_takesubspec(in,2); + inC=op_takesubspec(in,3); + inD=op_takesubspec(in,4); + case 'HERCULES' + inA=op_takesubspec(in,1); + inB=op_takesubspec(in,2); + inC=op_takesubspec(in,3); + inD=op_takesubspec(in,4); +end + + %%% 1. SET UP REQUIRED VARIABLES %%% % Define the frequency ranges over which water, NAA, and Cho subtraction artefacts % are to be minimized. Also, get a good starting estimate for the frequency @@ -112,6 +111,8 @@ % NAA freqLim(2,:) = freq <= 2.01+0.13 & freq >= 2.01-0.13; switch seqType + case 'HERCULES' + [~,i] = max([abs(real(inA.specs(freqLim(2,:)))) abs(real(inC.specs(freqLim(2,:))))]); case 'HERMES' [~,i] = max([abs(real(inA.specs(freqLim(2,:)))) abs(real(inC.specs(freqLim(2,:))))]); case 'MEGA' @@ -153,7 +154,7 @@ %%% 2. PERFORM ALIGNMENT BASED ON SEQUENCE TYPE -if strcmp(seqType, 'HERMES') +if strcmp(seqType, 'HERMES') || strcmp(seqType, 'HERCULES') if ~(exist('target1','var') && exist('target2','var')) %Fall back into default HERMES GABA GSH editing target1 = 'GABA'; @@ -162,7 +163,7 @@ target = [target1 target2]; switch target - case {'GABAGSH','GABALac'} + case {'GABAGSH','GABALac','GABAEtOH'} % For HERMES/HERCULES data, align the GSH-OFF spectra first, i.e. % minimize the residual water peak in the difference between them. @@ -298,11 +299,7 @@ outD.fids = fidsD; outD.specs = specsD; end - - varargout{1} = outA; - varargout{2} = outB; - varargout{3} = outC; - varargout{4} = outD; + out=op_mergesubspec(outA,outB,outC,outD); elseif strcmp(seqType, 'MEGA') % For MEGA-edited data, the 'reporter signal' that is used to align the @@ -364,13 +361,13 @@ % Apply the calculated frequency/phase adjustment to the inB spectrum fidsB = inB.fids.*exp(1i*pi*(t'*param(1,1)*2+param(1,2)/180)); specsB = fftshift(fft(fidsB, [], inB.dims.t), inB.dims.t); + % Create output outA = inA; outB = inB; outB.fids = fidsB; outB.specs = specsB; - varargout{1} = outA; - varargout{2} = outB; + out=op_mergesubspec(outA,outB); end diff --git a/process/osp_editSubSpecAlignLNorm.m b/process/osp_editSubSpecAlignLNorm.m index 2e8990bf..058c9d1b 100644 --- a/process/osp_editSubSpecAlignLNorm.m +++ b/process/osp_editSubSpecAlignLNorm.m @@ -5,19 +5,15 @@ % whole frequency range (Cleve et al., JMR, 2017 (https://doi.org/10.1016/j.jmr.2017.04.004) . % % USAGE: -% [outA, outB, outC, outD] = osp_editSubSpecAlign(inA, inB, inC, inD); +% [outA, outB] = osp_editSubSpecAlign(inA, inB/target); % % INPUTS: -% inA = Input data structure with sub-spectrum A. -% inB = Input data structure with sub-spectrum B. -% inC = Input data structure with sub-spectrum C. (optional) -% inD = Input data structure with sub-spectrum D. (optional) +% inA = Input data structure A. +% inB = Input data structure B. (optional) % % OUTPUTS: % outA = Output following alignment of averages. -% outB = Output following alignment of averages. -% outC = Output following alignment of averages. (optional) -% outD = Output following alignment of averages. (optional) +% outB = Output following alignment of averages. (optional) % % AUTHOR: % Dr. Helge Zollner (Johns Hopkins University, 2021-03-01) @@ -33,37 +29,58 @@ % 2021-01-01: First version of the code. % Determine whether there are 2 (MEGA) or 4 (HERMES/HERCULES) inputs -if nargin == 4 - seqType = 'HERMES'; - inA = varargin{1}; - inB = varargin{2}; - inC = varargin{3}; - inD = varargin{4}; -elseif nargin == 2 +if nargin == 2 && isstruct(varargin{2}) seqType = 'MEGA'; inA = varargin{1}; inB = varargin{2}; + if inA.subspecs > 1 || inB.subspecs > 1 + error('Error in osp_editSubSpecAlign! Both data structs must have only 1 sub-spectrum'); + end +elseif nargin == 2 && ~isstruct(varargin{2}) + in = varargin{1}; + seqType = varargin{2}; + if in.subspecs == 1 + error('Error in osp_editSubSpecAlign! The data struct must have > 1 sub-spectrum'); + end + switch seqType + case 'MEGA' + inA=op_takesubspec(in,1); + inB=op_takesubspec(in,2); + case 'HERMES' + inA=op_takesubspec(in,1); + inB=op_takesubspec(in,2); + inC=op_takesubspec(in,3); + inD=op_takesubspec(in,4); + case 'HERCULES' + inA=op_takesubspec(in,1); + inB=op_takesubspec(in,2); + inC=op_takesubspec(in,3); + inD=op_takesubspec(in,4); + end else - error('Error in osp_editSubSpecAlign! Needs to have either 2 (for MEGA) or 4 (for HERMES/HERCULES) sub-spectra provided'); + error('Error in osp_editSubSpecAlign! Needs to have either 2 spectra to align or one spectrum with sub-spectra and sequence type'); end % Check whether data is coil-combined. If not, throw error. -if ~inA.flags.addedrcvrs +if ~in.flags.addedrcvrs error('ERROR: I think it only makes sense to do this after you have combined the channels using op_addrcvrs. ABORTING!!'); end % Check whether data is averaged. If not, throw error. -if ~inA.flags.averaged +if ~in.flags.averaged error('ERROR: I think it only makes sense to do this after averaging using op_averaging. ABORTING!!'); end + + + %%% 1. SET UP REQUIRED VARIABLES %%% % Define the frequency ranges over which water, NAA, and Cho subtraction artefacts % are to be minimized. Also, get a good starting estimate for the frequency % alignment shift by determining the difference between the two maxima in % the respective peak range (water, NAA, or Cho). freq = inA.ppm; -freqLim(1,:) = freq <= 3.8 & freq >= 1.95; +freqLim(1,:) = freq <= 4 & freq >= 1.95; x0(1,:) = [0 0]; @@ -76,7 +93,7 @@ %%% 2. PERFORM ALIGNMENT BASED ON SEQUENCE TYPE -if strcmp(seqType, 'HERMES') +if strcmp(seqType, 'HERMES') || strcmp(seqType, 'HERCULES') a = max(max([abs(real(inA.specs)) abs(real(inB.specs))])); @@ -113,12 +130,9 @@ outD = inD; outD.fids = fidsD; outD.specs = specsD; - - - varargout{1} = outA; - varargout{2} = outB; - varargout{3} = outC; - varargout{4} = outD; + + % Create output + varargout{1} = op_mergesubspec(outA,outB,outC,outD); elseif strcmp(seqType, 'MEGA') % For MEGA-edited data, the 'reporter signal' that is used to align the @@ -134,13 +148,18 @@ % Apply the calculated frequency/phase adjustment to the inB spectrum fidsB = inB.fids.*exp(1i*pi*(t'*param(1,1)*2+param(1,2)/180)); specsB = fftshift(fft(fidsB, [], inB.dims.t), inB.dims.t); + % Create output outA = inA; outB = inB; outB.fids = fidsB; outB.specs = specsB; - varargout{1} = outA; - varargout{2} = outB; + if isstruct(varargin{2}) + varargout{1} = outA; + varargout{2} = outB; + else + varargout{1}=op_mergesubspec(outA,outB); + end end diff --git a/process/osp_onOffClassifyHERMES.m b/process/osp_onOffClassifyHERMES.m index aaa45ee3..d69f56ab 100644 --- a/process/osp_onOffClassifyHERMES.m +++ b/process/osp_onOffClassifyHERMES.m @@ -1,4 +1,4 @@ -function [outA, outB, outC, outD, commuteOrder] = osp_onOffClassifyHERMES(inA, inB, inC, inD, target) +function [out, commuteOrder] = osp_onOffClassifyHERMES(in, target) %% [outA, outB, outC, outD, commuteOrder] = osp_onOffClassifyHERMES(inA, inB, inC, inD) % This function decides how the four-provided HERMES/HERCULES sub-spectra are % being edited. Currently, this function works for all combinations of @@ -7,7 +7,7 @@ % % To determine the editing pattern, this function ranks the four spectra % according to the amplitude of the residual water (suppressed for GSH-ON) -% and NAA (suppressed for GABA-ON) signals. +% and NAA (suppressed for GABA-ON) signals. % % The function finally assigns: % - the GABA-OFF-GSH-OFF spectrum to field A @@ -16,26 +16,20 @@ % - the GABA-ON-GSH-ON spectrum to field D % % USAGE: -% [outA, outB, outC, outD] = osp_onOffClassifyMEGA(inA, inB, inC, inD) +% [out] = osp_onOffClassifyMEGA(in) % % INPUTS: -% inA = FID-A structure containing the 1st sub-spectrum. -% inB = FID-A structure containing the 2nd sub-spectrum. -% inC = FID-A structure containing the 3rd sub-spectrum. -% inD = FID-A structure containing the 4th sub-spectrum. +% in = FID-A structure containing the all sub-spectra. % % OUTPUTS: -% outA = FID-A structure containing the GABA-OFF-GSH-OFF spectrum. -% outB = FID-A structure containing the GABA-ON-GSH-OFF spectrum. -% outC = FID-A structure containing the GABA-OFF-GSH-ON spectrum. -% outD = FID-A structure containing the GABA-ON-GSH-ON spectrum. -% commuteOrder = Order of commuting the input spectra. +% out = FID-A structure containing sorted sub-spectra. + % % AUTHOR: % Dr. Georg Oeltzschner (Johns Hopkins University, 2019-08-15) % goeltzs1@jhmi.edu -% -% CREDITS: +% +% CREDITS: % This code is based on numerous functions from the FID-A toolbox by % Dr. Jamie Near (McGill University) % https://github.com/CIC-methods/FID-A @@ -44,10 +38,16 @@ % HISTORY: % 2019-08-15: First version of the code. -if nargin < 5 +if nargin < 2 target = 'GABAGSH'; end +inA = op_takesubspec(in,1); +inB = op_takesubspec(in,2); +inC = op_takesubspec(in,3); +inD = op_takesubspec(in,4); + + switch target case 'GABAGSH' % Determine maximum signal intensities for water and NAA in each @@ -77,49 +77,39 @@ for ll = 1:4 idx_first = find(order_first == ll); idx_second = find(order_second == ll); - + if ismember(idx_first,[3 4]) first.ON(ll) = 0; elseif ismember(idx_first,[1 2]) first.ON(ll) = 1; end - + if ismember(idx_second,[3 4]) second.ON(ll) = 0; elseif ismember(idx_second,[1 2]) second.ON(ll) = 1; end - -end -try - % Determine the sub-spectra indices belonging to each editing pattern - idx_OFF_OFF = ~second.ON & ~first.ON; - idx_ON_OFF = second.ON & ~first.ON; - idx_OFF_ON = ~second.ON & first.ON; - idx_ON_ON = second.ON & first.ON; - % Commute for output - inputVars = {'inA', 'inB', 'inC', 'inD'}; - eval(['outA = ' inputVars{idx_OFF_OFF} ';']); - eval(['outB = ' inputVars{idx_ON_OFF} ';']); - eval(['outC = ' inputVars{idx_OFF_ON} ';']); - eval(['outD = ' inputVars{idx_ON_ON} ';']); -catch - disp('HERMES classifier does not recognize the subspectra. You can change the ordering in osp_onOFFClassifyHERMES.m'); - % Determine the sub-spectra indices belonging to each editing pattern - idx_OFF_OFF = logical([0 1 0 0]); - idx_ON_OFF = logical([0 0 0 1]); - idx_OFF_ON = logical([1 0 0 0]); - idx_ON_ON = logical([0 0 1 0]); - - % Commute for output - inputVars = {'inA', 'inB', 'inC', 'inD'}; - eval(['outA = ' inputVars{idx_OFF_OFF} ';']); - eval(['outB = ' inputVars{idx_ON_OFF} ';']); - eval(['outC = ' inputVars{idx_OFF_ON} ';']); - eval(['outD = ' inputVars{idx_ON_ON} ';']); end +% Determine the sub-spectra indices belonging to each editing pattern +idx_OFF_OFF = ~second.ON & ~first.ON; +idx_ON_OFF = second.ON & ~first.ON; +idx_OFF_ON = ~second.ON & first.ON; +idx_ON_ON = second.ON & first.ON; + +% Commute for output +temp = in; +out = in; +out.specs(:,1) = temp.specs(:,idx_OFF_OFF); +out.specs(:,2) = temp.specs(:,idx_ON_OFF); +out.specs(:,3) = temp.specs(:,idx_OFF_ON); +out.specs(:,4) = temp.specs(:,idx_ON_ON); +out.fids(:,1) = temp.fids(:,idx_OFF_OFF); +out.fids(:,2) = temp.fids(:,idx_ON_OFF); +out.fids(:,3) = temp.fids(:,idx_OFF_ON); +out.fids(:,4) = temp.fids(:,idx_ON_ON); + % Save commute order commuteOrder = [find(idx_OFF_OFF), find(idx_ON_OFF), find(idx_OFF_ON), find(idx_ON_ON)]; @@ -141,7 +131,7 @@ max_w = max([abs(max(real(out_w.specs))), abs(min(real(out_w.specs)))]); max_NAA = max([abs(max(real(out_NAA.specs))), abs(min(real(out_NAA.specs)))]); end - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -158,5 +148,5 @@ max_ins = max([abs(max(real(out_ins.specs))), abs(min(real(out_ins.specs)))]); max_NAA = max([abs(max(real(out_NAA.specs))), abs(min(real(out_NAA.specs)))]); end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/process/osp_onOffClassifyMEGA.m b/process/osp_onOffClassifyMEGA.m index 655b965d..62564b61 100644 --- a/process/osp_onOffClassifyMEGA.m +++ b/process/osp_onOffClassifyMEGA.m @@ -1,5 +1,5 @@ -function [outA, outB, switchOrder] = osp_onOffClassifyMEGA(inA, inB, target) -%% [outA, outB, switchOrder] = osp_onOffClassifyMEGA(inA, inB, target) +function [out,switchOrder] = osp_onOffClassifyMEGA(in, target) +%% [outA,switchOrder] = osp_onOffClassifyMEGA(in,target) % This function decides which of the two provided MEGA sub-spectra in the % are the edit-ON or the edit-OFF. % @@ -11,16 +11,14 @@ % edit-ON spectrum to field B. % % USAGE: -% [outA, outB] = osp_onOffClassifyMEGA(inA, inB, target) +% [out] = osp_onOffClassifyMEGA(in target) % % INPUTS: -% inA = FID-A structure containing one MEGA sub-spectrum. -% inB = FID-A structure containing the other MEGA sub-spectrum. +% in = FID-A structure containing MEGA spectrum. % target = String. Can be 'GABA' or 'GSH'. % % OUTPUTS: -% outA = FID-A structure containing the edit-OFF MEGA sub-spectrum. -% outB = FID-A structure containing the edit-ON MEGA sub-spectrum. +% out = FID-A structure containing the ordered MEGA sub-spectrum. % switchOrder = Vector indicating the order in which the input % spectra are rearranged in order to generate the output order. % @@ -44,110 +42,19 @@ switch target case 'GABA' % Determine which of the differences has an upright NAA peak - tempA = op_freqrange(inA, 1.7, 2.3); - tempB = op_freqrange(inB, 1.7, 2.3); - - specA = abs(real(tempA.specs)); - specB = abs(real(tempB.specs)); - - max_diffAB = max(specA - specB); - max_diffBA = max(specB - specA); - - - if max_diffAB > max_diffBA - outA = inA; - outB = inB; - switchOrder = 0; - else - outA = inB; - outB = inA; - switchOrder = 1; - end + temp = op_freqrange(in, 1.7, 2.3); case 'GSH' % Determine which of the differences has an upright water peak - tempA = op_freqrange(inA, 4, 5); - tempB = op_freqrange(inB, 4, 5); - - specA = abs(tempA.specs); - specB = abs(tempB.specs); - - max_diffAB = max(specA - specB); - max_diffBA = max(specB - specA); - - - if max_diffAB > max_diffBA - outA = inA; - outB = inB; - switchOrder = 0; - else - outA = inB; - outB = inA; - switchOrder = 1; - end + temp = op_freqrange(in, 4, 5); case 'Lac' % Determine which of the differences has an upright water peak - tempA = op_freqrange(inA, 3.8, 4); - tempB = op_freqrange(inB, 3.8, 4); - - specA = abs(tempA.specs); - specB = abs(tempB.specs); - - max_diffAB = max(specA - specB); - max_diffBA = max(specB - specA); - - - if max_diffAB < max_diffBA - outA = inB; - outB = inA; - switchOrder = 1; - else - outA = inA; - outB = inB; - switchOrder = 0; - end + temp = op_freqrange(in, 3.8, 4); case 'PE398' % Determine which of the differences has an upright water peak - tempA = op_freqrange(inA, 3.8, 4.1); - tempB = op_freqrange(inB, 3.8, 4.1); - - specA = abs(tempA.specs); - specB = abs(tempB.specs); - - max_diffAB = max(specA - specB); - max_diffBA = max(specB - specA); - - - if max_diffAB < max_diffBA - outA = inB; - outB = inA; - switchOrder = 1; - else - outA = inA; - outB = inB; - switchOrder = 0; - end - + temp = op_freqrange(in, 3.8, 4.1); case 'PE322' % Determine which of the differences has an upright water peak - tempA = op_freqrange(inA, 3.0, 3.3); - tempB = op_freqrange(inB, 3.0, 3.3); - - specA = abs(tempA.specs); - specB = abs(tempB.specs); - - max_diffAB = max(specA - specB); - max_diffBA = max(specB - specA); - - - if max_diffAB < max_diffBA - outA = inB; - outB = inA; - switchOrder = 1; - else - outA = inA; - outB = inB; - switchOrder = 0; - end + temp = op_freqrange(in, 3.0, 3.3); otherwise disp('MEGA ON/OFF classifier does not recognize the input argument ''target''. We automatically assume no reordering. You can change that in osp_onOFFClassifyMEGA.m'); outA = inA; @@ -155,5 +62,21 @@ switchOrder = 0; end +spec = abs(real(temp.specs)); +max_diffAB = max(spec(:,1) - spec(:,2)); +max_diffBA = max(spec(:,2) - spec(:,1)); +out = in; + +if max_diffAB > max_diffBA + + switchOrder = 0; +else + temp = in; + out.specs(:,1) = temp.specs(:,2); + out.specs(:,2) = temp.specs(:,1); + out.fids(:,1) = temp.fids(:,2); + out.fids(:,2) = temp.fids(:,1); + switchOrder = 1; +end end \ No newline at end of file diff --git a/process/osp_orderProcessFields.m b/process/osp_orderProcessFields.m index 5e23216e..214f0bcc 100644 --- a/process/osp_orderProcessFields.m +++ b/process/osp_orderProcessFields.m @@ -35,86 +35,35 @@ %% Define order based on the supplied files and the sequence type -if MRSCont.flags.isUnEdited - numberstring = ['1' num2str(MRSCont.flags.hasMM) num2str(MRSCont.flags.hasRef) num2str(MRSCont.flags.hasWater)]; - switch numberstring - case '1000' - sortstring = {'A'}; - case '1100' - sortstring = {'A','mm'}; - case '1001' - sortstring = {'A','w'}; - case '1010' - sortstring = {'A','ref'}; - case '1110' - sortstring = {'A','mm','ref'}; - case '1101' - sortstring = {'A','mm','w'}; - case '1111' - sortstring = {'A','mm','ref','w'}; - otherwise - msg = 'Something is wrong in the processing!'; - fprintf(fileID,msg); - error(msg); - end - -elseif MRSCont.flags.isMEGA - numberstring = ['1' num2str(MRSCont.flags.hasRef) num2str(MRSCont.flags.hasWater)]; - switch numberstring - case '100' - sortstring = {'A','B','diff1','sum'}; - case '110' - sortstring = {'A','B','diff1','sum','ref'}; - case '101' - sortstring = {'A','B','diff1','sum','w'}; - case '111' - sortstring = {'A','B','diff1','sum','ref','w'}; - otherwise - msg = 'Something is wrong in the processing!'; - fprintf(fileID,msg); - error(msg); - end - -elseif (MRSCont.flags.isHERMES) || (MRSCont.flags.isHERCULES) - if ~(length(MRSCont.opts.editTarget) > 2) - numberstring = ['1' num2str(MRSCont.flags.hasRef) num2str(MRSCont.flags.hasWater)]; - switch numberstring - case '100' - sortstring = {'A','B','C','D','diff1','diff2','sum'}; - case '110' - sortstring = {'A','B','C','D','diff1','diff2','sum','ref'}; - case '101' - sortstring = {'A','B','C','D','diff1','diff2','sum','w'}; - case '111' - sortstring = {'A','B','C','D','diff1','diff2','sum','ref','w'}; - otherwise - msg = 'Something is wrong in the processing!'; - fprintf(fileID,msg); - error(msg); - end - else - numberstring = ['1' num2str(MRSCont.flags.hasRef) num2str(MRSCont.flags.hasWater)]; - switch numberstring - case '100' - sortstring = {'A','B','C','D','diff1','diff2','diff3','sum'}; - case '110' - sortstring = {'A','B','C','D','diff1','diff2','diff3','sum','ref'}; - case '101' - sortstring = {'A','B','C','D','diff1','diff2','diff3','sum','w'}; - case '111' - sortstring = {'A','B','C','D','diff1','diff2','diff3','sum','ref','w'}; - otherwise - msg = 'Something is wrong in the processing!'; - fprintf(fileID,msg); - error(msg); - end - end -else - msg = 'No flag set for sequence type!'; - fprintf(fileID,msg); - error(msg); +numberstring = ['1' num2str(MRSCont.flags.hasMM) num2str(MRSCont.flags.hasRef) num2str(MRSCont.flags.hasWater) num2str(MRSCont.flags.hasMMRef)]; +switch numberstring + case '10000' + sortstring = {'metab'}; + case '10110' + sortstring = {'metab','ref','w'}; + case '10100' + sortstring = {'metab','ref'}; + case '10010' + sortstring = {'metab','w'}; + case '11000' + sortstring = {'metab','mm'}; + case '11001' + sortstring = {'metab','mm','mm_ref'}; + case '11101' + sortstring = {'metab','mm','ref','mm_ref'}; + case '11110' + sortstring = {'metab','mm','ref','w'}; + case '11011' + sortstring = {'metab','mm','w','mm_ref'}; + case '11111' + sortstring = {'metab','mm','ref','w','mm_ref'}; + otherwise + msg = 'Something is wrong in the processing!'; + fprintf(fileID,msg); + error(msg); end + %% Sort the struct accordingly if exist('sortstring','var') && (length(fieldnames(MRSCont.processed)) == length(sortstring)) [MRSCont.processed, ~] = orderfields(MRSCont.processed,sortstring); diff --git a/process/osp_processHERCULES.m b/process/osp_processHERCULES.m deleted file mode 100644 index b3851045..00000000 --- a/process/osp_processHERCULES.m +++ /dev/null @@ -1,488 +0,0 @@ -function [MRSCont] = osp_processHERCULES(MRSCont,target1,target2) -%% [MRSCont] = osp_processHERCULES(MRSCont) -% This function performs the following steps to process HERCULES-edited -% (4-step) MRS data: -% - Alignment of individual averages using robust spectral registration -% - Averaging -% - Removal of residual water using HSVD filtering -% - Klose Eddy current correction (if a reference scan is provided) -% - Automated zero-order phase correction -% - Correct referencing of the ppm frequency axis -% -% USAGE: -% [MRSCont] = osp_processHERMES(MRSCont); -% -% INPUTS: -% MRSCont = Osprey MRS data container. -% -% OUTPUTS: -% MRSCont = Osprey MRS data container. -% -% AUTHOR: -% Dr. Georg Oeltzschner (Johns Hopkins University, 2019-08-15) -% goeltzs1@jhmi.edu -% -% CREDITS: -% This code is based on numerous functions from the FID-A toolbox by -% Dr. Jamie Near (McGill University) -% https://github.com/CIC-methods/FID-A -% Simpson et al., Magn Reson Med 77:23-33 (2017) -% -% HISTORY: -% 2019-08-20: First version of the code. - - -warning('off','all'); - -% Parse input arguments -if nargin < 2 - if (strcmp(MRSCont.opts.editTarget{1},'HERCULES1')||strcmp(MRSCont.opts.editTarget{1},'HERCULES2')) - MRSCont.opts.editTarget = {'GABA','GSH'}; - end - target1 = MRSCont.opts.editTarget{1}; - target2 = MRSCont.opts.editTarget{2}; -end -%% Loop over all datasets -refProcessTime = tic; -if MRSCont.flags.isGUI - progressText = MRSCont.flags.inProgress; -else - progressText = ''; -end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyProcess',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didProcess == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'processed') && (kk > length(MRSCont.processed.A))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - %%% 1. GET RAW DATA %%% - raw = MRSCont.raw{kk}; % Get the kk-th dataset - - % Get sub-spectra, depending on whether they are stored as such - if raw.subspecs == 4 - - raw_A = op_takesubspec(raw,1); % Get first subspectrum - raw_B = op_takesubspec(raw,2); % Get second subspectrum - raw_C = op_takesubspec(raw,3); % Get third subspectrum - raw_D = op_takesubspec(raw,4); % Get fourth subspectrum - - else - - raw_A = op_takeaverages(raw,1:4:raw.averages); % Get first subspectrum - raw_B = op_takeaverages(raw,2:4:raw.averages); % Get second subspectrum - raw_C = op_takeaverages(raw,3:4:raw.averages); % Get third subspectrum - raw_D = op_takeaverages(raw,4:4:raw.averages); % Get fourth subspectrum - end - - if raw.averages > 1 && raw.flags.averaged == 0 - % Calculate starting values for spectral registration - [refShift_ind_ini]=op_preref(raw,'HERCULES'); - % Perform robust spectral correction with weighted averaging. - % This can obviously only be done, if the spectra have not been - % pre-averaged, i.e. in some older RDA and DICOM files (which should, - % generally, not be used). For phantom scans the registration - % window is restricted to a certain frequency window. - if ~MRSCont.flags.isPhantom - switch MRSCont.opts.SpecReg %Pick spectral registration method (default is Robust Spectral Registration) - case 'ProbSpecReg' - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_probabSpecReg(raw_A, 'HERCULES', 0,refShift_ind_ini); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_probabSpecReg(raw_B, 'HERCULES', 0, refShift_ind_ini); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_probabSpecReg(raw_C, 'HERCULES', 0, refShift_ind_ini); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_probabSpecReg(raw_D, 'HERCULES', 0, refShift_ind_ini); - - case 'RobSpecReg' - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_robustSpecReg(raw_A, 'HERCULES', 0,refShift_ind_ini); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_robustSpecReg(raw_B, 'HERCULES', 0, refShift_ind_ini); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_robustSpecReg(raw_C, 'HERCULES', 0, refShift_ind_ini); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_robustSpecReg(raw_D, 'HERCULES', 0, refShift_ind_ini); - case 'RestrSpecReg' - [~, ~, ~, ~, commuteOrder] = osp_onOffClassifyHERMES(raw_A, raw_B, raw_C, raw_D); - temp.raw_A = raw_A; - temp.raw_B = raw_B; - temp.raw_C = raw_C; - temp.raw_D = raw_D; - inputVars = {'raw_A', 'raw_B', 'raw_C', 'raw_D'}; - eval(['raw_A = temp.' inputVars{commuteOrder(1)} ';']); - eval(['raw_B = temp.' inputVars{commuteOrder(2)} ';']); - eval(['raw_C = temp.' inputVars{commuteOrder(3)} ';']); - eval(['raw_D = temp.' inputVars{commuteOrder(4)} ';']); - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_SpecRegFreqRestrict(raw_A, 'HERCULES', 0,refShift_ind_ini,0,0.5,3.9); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_SpecRegFreqRestrict(raw_B, 'HERCULES', 0, refShift_ind_ini,0,0.5,3.8); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_SpecRegFreqRestrict(raw_C, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.9); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_SpecRegFreqRestrict(raw_D, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.8); - case 'none' - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_SpecRegFreqRestrict(raw_A, 'HERCULES', 0,refShift_ind_ini,1); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_SpecRegFreqRestrict(raw_B, 'HERCULES', 0, refShift_ind_ini,1); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_SpecRegFreqRestrict(raw_C, 'HERCULES', 0, refShift_ind_ini,1); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_SpecRegFreqRestrict(raw_D, 'HERCULES', 0, refShift_ind_ini,1); - end - else - [~, ~, ~, ~, commuteOrder] = osp_onOffClassifyHERMES(temp_rawA, temp_rawB, temp_rawC, temp_rawD); - temp.raw_A = raw_A; - temp.raw_B = raw_B; - temp.raw_C = raw_C; - temp.raw_D = raw_D; - inputVars = {'raw_A', 'raw_B', 'raw_C', 'raw_D'}; - eval(['raw_A = temp.' inputVars{commuteOrder(1)} ';']); - eval(['raw_B = temp.' inputVars{commuteOrder(2)} ';']); - eval(['raw_C = temp.' inputVars{commuteOrder(3)} ';']); - eval(['raw_D = temp.' inputVars{commuteOrder(4)} ';']); - % Next, shift the entire metabolite spectrum by 0.15 ppm. - % This doesn't have to be completely accurate, since additional - % referencing steps are performed in the later stages of - % post-processing and modelling, but we want the prominent singlets - % to appear within 0.1 ppm of their expected in-vivo positions. - phantomShiftPPM = 0.15 * raw_A.txfrq*1e-6; - raw_A = op_freqshift(raw_A, -phantomShiftPPM); - raw_B = op_freqshift(raw_B, -phantomShiftPPM); - raw_C = op_freqshift(raw_C, -phantomShiftPPM); - raw_D = op_freqshift(raw_D, -phantomShiftPPM); - % Finally, apply some linebroadening. High-quality in-vitro - % data may have linewidth lower than the simulated basis set - % data. - raw_A = op_filter(raw_A, 2); - raw_B = op_filter(raw_B, 2); - raw_C = op_filter(raw_C, 2); - raw_D = op_filter(raw_D, 2); - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_SpecRegFreqRestrict(raw_A, 'HERCULES', 0,refShift_ind_ini,0,0.5,3.9); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_SpecRegFreqRestrict(raw_B, 'HERCULES', 0, refShift_ind_ini,0,0.5,3.8); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_SpecRegFreqRestrict(raw_C, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.9); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_SpecRegFreqRestrict(raw_D, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.8); - end - - - else - raw.flags.averaged = 1; - raw.dims.averages = 0; - raw.specReg.fs = zeros(1,2); % save align parameters - raw.specReg.phs = zeros(1,2); % save align parameters - raw.specReg.weights{1} = ones(1,1); % save align parameters - raw.specReg.weights{2} = ones(1,1); % save align parameters - driftPre{1} = 0; - driftPre{2} = 0; - driftPost = driftPre; - end - - - - %%% 2. GET REFERENCE DATA / EDDY CURRENT CORRECTION %%% - % If there are reference scans, perform the same operations - if MRSCont.flags.hasRef - raw_ref = MRSCont.raw_ref{kk}; % Get the kk-th dataset - - % Some formats end up having subspectra in their reference scans - % (e.g. Philips), as well as empty lines. Intercept these cases - % here. - if raw_ref.subspecs > 1 - raw_ref_A = op_takesubspec(raw_ref,1); - [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines - raw_ref_B = op_takesubspec(raw_ref,2); - [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines - raw_ref_C = op_takesubspec(raw_ref,3); - [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines - raw_ref_D = op_takesubspec(raw_ref,4); - [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines - raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); - end - if ~raw_ref.flags.averaged - [raw_ref] = op_rmempty(raw_ref); - [raw_ref,~,~] = op_alignAverages(raw_ref,1,'n'); % Align averages - raw_ref = op_averaging(raw_ref); % Average - end - - % Apply Klose eddy current correction - [raw_A,~] = op_eccKlose(raw_A, raw_ref); - [raw_B,~] = op_eccKlose(raw_B, raw_ref); - [raw_C,~] = op_eccKlose(raw_C, raw_ref); - [raw_D,raw_ref] = op_eccKlose(raw_D, raw_ref); - - [raw_ref,~] = op_ppmref(raw_ref,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - MRSCont.processed.ref{kk} = raw_ref; % Save back to MRSCont container - end - - %%% 2a. PHANTOM-SPECIFIC PRE-PROCESSING %%% - % If this is phantom data (assuming room temperature), we want to - % perform a few specific pre-processing steps. - if MRSCont.flags.isPhantom - % First, we undo phase cycling by dividing by the first data - % point (this is mainly experimental at this point, but has - % proved beneficial for phase-cycled GE data). -% for rr = 1:raw.rawAverages -% phi = repelem(conj(raw.fids(1,rr))./abs(raw.fids(1,rr)),size(raw.fids,1)); -% raw.fids(:,rr) = raw.fids(:,rr) .* phi'; -% raw.specs = fftshift(fft(raw.fids,[],1)); -% end - % Finally, apply some linebroadening. High-quality in-vitro - % data may have linewidth lower than the simulated basis set - % data. - if MRSCont.flags.hasRef - raw_ref = op_filter(raw_ref, 2); - end - end - - - %%% 3. DETERMINE POLARITY OF SPECTRUM (EG FOR MOIST WATER SUPP) %%% - % Automate determination whether the Cr peak has positive polarity. - % For water suppression methods like MOIST, the residual water may - % actually have negative polarity, but end up positive in the data, so - % that the spectrum needs to be flipped. - raw_A_Cr = op_freqrange(raw_A,2.8,3.2); - polResidCr = abs(max(real(raw_A_Cr.specs))) - abs(min(real(raw_A_Cr.specs))); - if polResidCr < 0 - raw_A = op_ampScale(raw_A,-1); - end - - raw_B_Cr = op_freqrange(raw_B,2.8,3.2); - polResidCr = abs(max(real(raw_B_Cr.specs))) - abs(min(real(raw_B_Cr.specs))); - if polResidCr < 0 - raw_B = op_ampScale(raw_B,-1); - end - - raw_C_Cr = op_freqrange(raw_C,2.8,3.2); - polResidCr = abs(max(real(raw_C_Cr.specs))) - abs(min(real(raw_C_Cr.specs))); - if polResidCr < 0 - raw_C = op_ampScale(raw_C,-1); - end - - raw_D_Cr = op_freqrange(raw_D,2.8,3.2); - polResidCr = abs(max(real(raw_D_Cr.specs))) - abs(min(real(raw_D_Cr.specs))); - if polResidCr < 0 - raw_D = op_ampScale(raw_D,-1); - end - %%% 4. DETERMINE ON/OFF STATUS - % Classify the four sub-spectra such that the OFF spectrum is stored to - % field A, and the ON spectrum is stored to field B. - [raw_A, raw_B, raw_C, raw_D, commuteOrder] = osp_onOffClassifyHERMES(raw_A, raw_B, raw_C, raw_D); - subSpecNames = {'A', 'B', 'C', 'D'}; - % Save drift information back to container - eval(['MRSCont.QM.drift.pre.A{kk} = driftPre' subSpecNames{commuteOrder(1)} ';']); - eval(['MRSCont.QM.drift.pre.B{kk} = driftPre' subSpecNames{commuteOrder(2)} ';']); - eval(['MRSCont.QM.drift.pre.C{kk} = driftPre' subSpecNames{commuteOrder(3)} ';']); - eval(['MRSCont.QM.drift.pre.D{kk} = driftPre' subSpecNames{commuteOrder(4)} ';']); - eval(['MRSCont.QM.drift.post.A{kk} = driftPost' subSpecNames{commuteOrder(1)} ';']); - eval(['MRSCont.QM.drift.post.B{kk} = driftPost' subSpecNames{commuteOrder(2)} ';']); - eval(['MRSCont.QM.drift.post.C{kk} = driftPost' subSpecNames{commuteOrder(3)} ';']); - eval(['MRSCont.QM.drift.post.D{kk} = driftPost' subSpecNames{commuteOrder(4)} ';']); - % Generate the drift plot for the entire experiment in - % the correct order - driftPre = [MRSCont.QM.drift.pre.A{kk}, MRSCont.QM.drift.pre.B{kk}, MRSCont.QM.drift.pre.C{kk}, MRSCont.QM.drift.pre.D{kk}]'; - try - driftPre = reshape(driftPre, [raw.averages, 1]); - catch - driftPre = reshape(driftPre, [raw.rawAverages, 1]); - end - MRSCont.QM.drift.pre.diff1{kk} = driftPre; - MRSCont.QM.drift.pre.diff2{kk} = driftPre; - MRSCont.QM.drift.pre.sum{kk} = driftPre; - driftPost = [MRSCont.QM.drift.post.A{kk}, MRSCont.QM.drift.post.B{kk}, MRSCont.QM.drift.post.C{kk}, MRSCont.QM.drift.post.D{kk}]'; - try - driftPost = reshape(driftPost, [raw.averages, 1]); - catch - driftPost = reshape(driftPost, [raw.rawAverages, 1]); - end - MRSCont.QM.drift.post.diff1{kk} = driftPost; - MRSCont.QM.drift.post.diff2{kk} = driftPost; - MRSCont.QM.drift.post.sum{kk} = driftPost; - - eval(['raw_A.specReg.fs = fs_' subSpecNames{commuteOrder(1)} ';']); % save align parameters - eval(['raw_B.specReg.fs = fs_' subSpecNames{commuteOrder(2)} ';']); - eval(['raw_C.specReg.fs = fs_' subSpecNames{commuteOrder(3)} ';']); - eval(['raw_D.specReg.fs = fs_' subSpecNames{commuteOrder(4)} ';']); - eval(['raw_A.specReg.phs = phs_' subSpecNames{commuteOrder(1)} ';']); - eval(['raw_B.specReg.phs = phs_' subSpecNames{commuteOrder(2)} ';']); - eval(['raw_C.specReg.phs = phs_' subSpecNames{commuteOrder(3)} ';']); - eval(['raw_D.specReg.phs = phs_' subSpecNames{commuteOrder(4)} ';']); - eval(['raw_A.specReg.weights = weights_' subSpecNames{commuteOrder(1)} '{1}(1,:);']); - eval(['raw_B.specReg.weights = weights_' subSpecNames{commuteOrder(2)} '{1}(1,:);']); - eval(['raw_C.specReg.weights = weights_' subSpecNames{commuteOrder(3)} '{1}(1,:);']); - eval(['raw_D.specReg.weights = weights_' subSpecNames{commuteOrder(4)} '{1}(1,:);']); - raw_A.specReg.weights = raw_A.specReg.weights'/(max(raw_A.specReg.weights)); - raw_B.specReg.weights = raw_B.specReg.weights'/(max(raw_B.specReg.weights)); - raw_C.specReg.weights = raw_C.specReg.weights'/(max(raw_C.specReg.weights)); - raw_D.specReg.weights = raw_D.specReg.weights'/(max(raw_D.specReg.weights)); - % Generate the frequency and phase plots for the entire experiment in - % the correct order - fs = [raw_A.specReg.fs, raw_B.specReg.fs, raw_C.specReg.fs, raw_D.specReg.fs]'; - fs = reshape(fs, [raw.rawAverages, 1]); - phs = [raw_A.specReg.phs, raw_B.specReg.phs, raw_C.specReg.phs, raw_D.specReg.phs]'; - phs = reshape(phs, [raw.rawAverages, 1]); - weights = [raw_A.specReg.weights, raw_B.specReg.weights, raw_C.specReg.weights, raw_D.specReg.weights]'; - weights = reshape(weights, [raw.rawAverages, 1]); - MRSCont.raw{kk}.specReg.fs = fs; % save align parameters - MRSCont.raw{kk}.specReg.phs = phs; % save align parameters - MRSCont.raw{kk}.specReg.weights = weights; % save align parameters - - %%% 5. BUILD SUM AND DIFF SPECTRA %%% - % Correct the frequency axis so that Cr appears at 3.027 ppm - temp_spec = op_addScans(raw_A,raw_B); - temp_spec = op_addScans(temp_spec,raw_C); - temp_spec = op_addScans(temp_spec,raw_D); - [refShift_SubSpecAlign, ~] = osp_CrChoReferencing(temp_spec); - % Apply initial referencing shift - raw_A = op_freqshift(raw_A, -refShift_SubSpecAlign); - raw_B = op_freqshift(raw_B, -refShift_SubSpecAlign); - raw_C = op_freqshift(raw_C, -refShift_SubSpecAlign); - raw_D = op_freqshift(raw_D, -refShift_SubSpecAlign); - % Fit a double-Lorentzian to the Cr-Cho area, and phase the spectrum - % with the negative phase of that fit - [raw_A,ph] = op_phaseCrCho(raw_A, 1); - raw_B = op_addphase(raw_B, -ph*180/pi, 0, raw_B.centerFreq, 1); - raw_C = op_addphase(raw_C, -ph*180/pi, 0, raw_C.centerFreq, 1); - raw_D = op_addphase(raw_D, -ph*180/pi, 0, raw_D.centerFreq, 1); - % Align the sub-spectra to one another by minimizing the difference - % between the common 'reporter' signals. - switch MRSCont.opts.SubSpecAlignment - case 'L1Norm' - [raw_A, raw_B, raw_C, raw_D] = osp_editSubSpecAlignLNorm(raw_A, raw_B, raw_C, raw_D); - case 'L2Norm' - [raw_A, raw_B, raw_C, raw_D] = osp_editSubSpecAlign(raw_A, raw_B, raw_C, raw_D,MRSCont.opts.UnstableWater,target1,target2); - end - % Create the sum spectrum - Sum = op_addScans(raw_A,raw_B); - Sum = op_addScans(Sum,raw_C); - Sum = op_addScans(Sum,raw_D); - Sum.commuteOrder = commuteOrder; - Sum.specReg.fs = fs; - Sum.specReg.phs = phs; - Sum.specReg.weights = weights; - % Create the GABA-edited difference spectrum - diff1 = op_addScans(raw_B,raw_D); - diff1 = op_addScans(diff1,raw_A,1); - diff1 = op_addScans(diff1,raw_C,1); - diff1.target = target1; - diff1.commuteOrder = commuteOrder; - diff1.specReg.fs = fs; - diff1.specReg.phs = phs; - diff1.specReg.weights = weights; - % Create the GSH-edited difference spectrum - diff2 = op_addScans(raw_C,raw_D); - diff2 = op_addScans(diff2,raw_A,1); - diff2 = op_addScans(diff2,raw_B,1); - diff2.target = target2; - diff2.commuteOrder = commuteOrder; - diff2.specReg.fs = fs; - diff2.specReg.phs = phs; - diff2.specReg.weights = weights; - - %%% 6. REMOVE RESIDUAL WATER %%% - % Remove water and correct back to baseline. - % The spectra sometimes become NaNs after filtering with too many - % components. Loop over decreasing numbers of components here. - % Define different water removal frequency ranges, depending on - % whether this is phantom data - if MRSCont.flags.isPhantom - waterRemovalFreqRange = [4.5 5]; - fracFID = 0.2; - Kinit = 32; - else - if ~MRSCont.flags.isPRIAM - waterRemovalFreqRange = [4.5 4.9]; - fracFID = 0.75; - Kinit = 32; - else -% waterRemovalFreqRange = [4.3 5.5]; -% fracFID = 0.75; -% Kinit = 45; - waterRemovalFreqRange = [4.5 4.9]; - fracFID = 0.75; - Kinit = 32; - end - end - % Apply iterative water filter - raw_A = op_iterativeWaterFilter(raw_A, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - raw_B = op_iterativeWaterFilter(raw_B, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - raw_C = op_iterativeWaterFilter(raw_C, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - raw_D = op_iterativeWaterFilter(raw_D, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - diff1 = op_iterativeWaterFilter(diff1, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - diff2 = op_iterativeWaterFilter(diff2, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - Sum = op_iterativeWaterFilter(Sum, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - - - %%% 7. REFERENCE SPECTRUM CORRECTLY TO FREQUENCY AXIS - % Reference resulting data correctly and consistently - %[raw_A, refShift] = op_ppmref(raw_A,1.8,2.2,2.008); % Reference OFF-OFF spectrum to NAA @ 2.008 ppm - temp_spec = Sum; - [refShift_final, ~] = osp_CrChoReferencing(temp_spec);% Reference OFF-OFF spectrum to NAA @ 2.008 ppm - [raw_A] = op_freqshift(raw_A,-refShift_final); % Apply same shift to ON-OFF - [raw_B] = op_freqshift(raw_B,-refShift_final); % Apply same shift to ON-OFF - [raw_C] = op_freqshift(raw_C,-refShift_final); % Apply same shift to OFF-ON - [raw_D] = op_freqshift(raw_D,-refShift_final); % Apply same shift to ON-ON - [diff1] = op_freqshift(diff1,-refShift_final); % Apply same shift to diff1 - [diff2] = op_freqshift(diff2,-refShift_final); % Apply same shift to diff2 - [Sum] = op_freqshift(Sum,-refShift_final); % Apply same shift to sum - - % Add commuteOrder - raw_A.commuteOrder = commuteOrder(1); - raw_B.commuteOrder = commuteOrder(2); - raw_C.commuteOrder = commuteOrder(3); - raw_D.commuteOrder = commuteOrder(4); - - %%% 8. SAVE BACK TO MRSCONT CONTAINER - MRSCont.processed.A{kk} = raw_A; % Save OFF-OFF back to MRSCont container - MRSCont.processed.B{kk} = raw_B; % Save ON-OFF back to MRSCont container - MRSCont.processed.C{kk} = raw_C; % Save OFF-ON back to MRSCont container - MRSCont.processed.D{kk} = raw_D; % Save ON-ON back to MRSCont container - MRSCont.processed.diff1{kk} = diff1; % Save diff1 back to MRSCont container - MRSCont.processed.diff2{kk} = diff2; % Save diff2 back to MRSCont container - MRSCont.processed.sum{kk} = Sum; % Save sum back to MRSCont container - - - %%% 9. GET SHORT-TE WATER DATA %%% - if MRSCont.flags.hasWater - % Some formats end up having subspectra in their reference scans - % (e.g. Philips), as well as empty lines. Intercept these cases - % here. - raw_w = MRSCont.raw_w{kk}; % Get the kk-th dataset - if raw_w.subspecs > 1 - raw_w_A = op_takesubspec(raw_w,1); - [raw_w_A] = op_rmempty(raw_w_A); % Remove empty lines - raw_w_B = op_takesubspec(raw_w,2); - [raw_w_A] = op_rmempty(raw_w_A); % Remove empty lines - raw_w = op_concatAverages(raw_w_A,raw_w_B); - end - if ~raw_w.flags.averaged - [raw_w,fs_A,phs_A] = op_alignAverages(raw_w,1,'n'); % Align averages - raw_w = op_averaging(raw_w); % Average - end - [raw_w,~] = op_eccKlose(raw_w, raw_w); % Klose eddy current correction - [raw_w,~] = op_ppmref(raw_w,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - MRSCont.processed.w{kk} = raw_w; % Save back to MRSCont container - end - - - %%% 10. QUALITY CONTROL PARAMETERS %%% - % Calculate some spectral quality metrics here; - SubSpec = {'A','B','C','D','diff1','diff2','sum'}; - SNRRange = {[1.8,2.2],[2.8,3.2],[2.8,3.2],[1.8,2.2],[2.8,3.2],[2.8,3.2],[2.8,3.2]}; - if MRSCont.flags.hasRef - SubSpec{end+1} = 'ref'; - SNRRange{end+1} = [4.2,5.2]; - end - if MRSCont.flags.hasWater - SubSpec{end+1} = 'w'; - SNRRange{end+1} = [4.2,5.2]; - end - % Calculate some spectral quality metrics here; - for ss = 1 : length(SubSpec) - MRSCont.QM.SNR.(SubSpec{ss})(kk) = op_getSNR(MRSCont.processed.(SubSpec{ss}){kk}); - MRSCont.QM.FWHM.(SubSpec{ss})(kk) = op_getLW(MRSCont.processed.(SubSpec{ss}){kk},SNRRange{ss}(1),SNRRange{ss}(2)); % in Hz - if ~(strcmp(SubSpec{ss},'ref') || strcmp(SubSpec{ss},'w')) - MRSCont.QM.freqShift.(SubSpec{ss})(kk) = refShift_SubSpecAlign + refShift_final; - MRSCont.QM.res_water_amp.(SubSpec{ss})(kk) = sum(MRSCont.processed.(SubSpec{ss}){kk}.watersupp.amp); - MRSCont.QM.drift.pre.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - MRSCont.QM.drift.post.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - end - end - end -end -time = toc(refProcessTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - -%%% 11. SET FLAGS %%% -MRSCont.flags.avgsAligned = 1; -MRSCont.flags.averaged = 1; -MRSCont.flags.ECCed = 1; -MRSCont.flags.waterRemoved = 1; -MRSCont.runtime.Proc = time; -% Close any remaining open figures -close all; - -end \ No newline at end of file diff --git a/process/osp_processHERMES.m b/process/osp_processHERMES.m deleted file mode 100644 index 3808859b..00000000 --- a/process/osp_processHERMES.m +++ /dev/null @@ -1,539 +0,0 @@ -function [MRSCont] = osp_processHERMES(MRSCont,target1,target2) -%% [MRSCont] = osp_processHERMES(MRSCont) -% This function performs the following steps to process HERMES-edited -% (4-step) MRS data: -% - Alignment of individual averages using robust spectral registration -% - Averaging -% - Removal of residual water using HSVD filtering -% - Klose Eddy current correction (if a reference scan is provided) -% - Automated zero-order phase correction -% - Correct referencing of the ppm frequency axis -% -% USAGE: -% [MRSCont] = osp_processHERMES(MRSCont); -% -% INPUTS: -% MRSCont = Osprey MRS data container. -% -% OUTPUTS: -% MRSCont = Osprey MRS data container. -% -% AUTHOR: -% Dr. Georg Oeltzschner (Johns Hopkins University, 2019-08-15) -% goeltzs1@jhmi.edu -% -% CREDITS: -% This code is based on numerous functions from the FID-A toolbox by -% Dr. Jamie Near (McGill University) -% https://github.com/CIC-methods/FID-A -% Simpson et al., Magn Reson Med 77:23-33 (2017) -% -% HISTORY: -% 2019-08-20: First version of the code. - - -warning('off','all'); - -% Parse input arguments -if nargin < 2 - target1 = MRSCont.opts.editTarget{1}; - target2 = MRSCont.opts.editTarget{2}; - if length(MRSCont.opts.editTarget) > 2 - target3 = MRSCont.opts.editTarget{3}; - end -end -%% Loop over all datasets -refProcessTime = tic; -if MRSCont.flags.isGUI - progressText = MRSCont.flags.inProgress; -else - progressText = ''; -end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyProcess',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didProcess == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'processed') && (kk > length(MRSCont.processed.A))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - %%% 1. GET RAW DATA %%% - raw = MRSCont.raw{kk}; % Get the kk-th dataset - - % Get sub-spectra, depending on whether they are stored as such - if raw.subspecs == 4 - - raw_A = op_takesubspec(raw,1); % Get first subspectrum - raw_B = op_takesubspec(raw,2); % Get second subspectrum - raw_C = op_takesubspec(raw,3); % Get third subspectrum - raw_D = op_takesubspec(raw,4); % Get fourth subspectrum - - else - - raw_A = op_takeaverages(raw,1:4:raw.averages); % Get first subspectrum - raw_B = op_takeaverages(raw,2:4:raw.averages); % Get second subspectrum - raw_C = op_takeaverages(raw,3:4:raw.averages); % Get third subspectrum - raw_D = op_takeaverages(raw,4:4:raw.averages); % Get fourth subspectrum - end - - if raw.averages > 1 && raw.flags.averaged == 0 - % Calculate starting values for spectral registration - [refShift_ind_ini]=op_preref(raw,'HERMES'); - % Perform robust spectral correction with weighted averaging. - % This can obviously only be done, if the spectra have not been - % pre-averaged, i.e. in some older RDA and DICOM files (which should, - % generally, not be used). For phantom scans the registration - % window is restricted to a certain frequency window. - if ~MRSCont.flags.isPhantom - switch MRSCont.opts.SpecReg %Pick spectral registration method (default is Robust Spectral Registration) - case 'ProbSpecReg' - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_probabSpecReg(raw_A, 'HERCULES', 0,refShift_ind_ini); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_probabSpecReg(raw_B, 'HERCULES', 0, refShift_ind_ini); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_probabSpecReg(raw_C, 'HERCULES', 0, refShift_ind_ini); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_probabSpecReg(raw_D, 'HERCULES', 0, refShift_ind_ini); - - case 'RobSpecReg' - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_robustSpecReg(raw_A, 'HERCULES', 0,refShift_ind_ini); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_robustSpecReg(raw_B, 'HERCULES', 0, refShift_ind_ini); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_robustSpecReg(raw_C, 'HERCULES', 0, refShift_ind_ini); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_robustSpecReg(raw_D, 'HERCULES', 0, refShift_ind_ini); - case 'RestrSpecReg' - [~, ~, ~, ~, commuteOrder] = osp_onOffClassifyHERMES(temp_rawA, temp_rawB, temp_rawC, temp_rawD); - temp.raw_A = raw_A; - temp.raw_B = raw_B; - temp.raw_C = raw_C; - temp.raw_D = raw_D; - inputVars = {'raw_A', 'raw_B', 'raw_C', 'raw_D'}; - eval(['raw_A = temp.' inputVars{commuteOrder(1)} ';']); - eval(['raw_B = temp.' inputVars{commuteOrder(2)} ';']); - eval(['raw_C = temp.' inputVars{commuteOrder(3)} ';']); - eval(['raw_D = temp.' inputVars{commuteOrder(4)} ';']); - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_SpecRegFreqRestrict(raw_A, 'HERCULES', 0,refShift_ind_ini,0,0.5,3.9); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_SpecRegFreqRestrict(raw_B, 'HERCULES', 0, refShift_ind_ini,0,0.5,3.8); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_SpecRegFreqRestrict(raw_C, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.9); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_SpecRegFreqRestrict(raw_D, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.8); - case 'none' - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_SpecRegFreqRestrict(raw_A, 'HERCULES', 0,refShift_ind_ini,1); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_SpecRegFreqRestrict(raw_B, 'HERCULES', 0, refShift_ind_ini,1); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_SpecRegFreqRestrict(raw_C, 'HERCULES', 0, refShift_ind_ini,1); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_SpecRegFreqRestrict(raw_D, 'HERCULES', 0, refShift_ind_ini,1); - end - else - [~, ~, ~, ~, commuteOrder] = osp_onOffClassifyHERMES(temp_rawA, temp_rawB, temp_rawC, temp_rawD); - temp.raw_A = raw_A; - temp.raw_B = raw_B; - temp.raw_C = raw_C; - temp.raw_D = raw_D; - inputVars = {'raw_A', 'raw_B', 'raw_C', 'raw_D'}; - eval(['raw_A = temp.' inputVars{commuteOrder(1)} ';']); - eval(['raw_B = temp.' inputVars{commuteOrder(2)} ';']); - eval(['raw_C = temp.' inputVars{commuteOrder(3)} ';']); - eval(['raw_D = temp.' inputVars{commuteOrder(4)} ';']); - % Next, shift the entire metabolite spectrum by 0.15 ppm. - % This doesn't have to be completely accurate, since additional - % referencing steps are performed in the later stages of - % post-processing and modelling, but we want the prominent singlets - % to appear within 0.1 ppm of their expected in-vivo positions. - phantomShiftPPM = 0.15 * raw_A.txfrq*1e-6; - raw_A = op_freqshift(raw_A, -phantomShiftPPM); - raw_B = op_freqshift(raw_B, -phantomShiftPPM); - raw_C = op_freqshift(raw_C, -phantomShiftPPM); - raw_D = op_freqshift(raw_D, -phantomShiftPPM); - % Finally, apply some linebroadening. High-quality in-vitro - % data may have linewidth lower than the simulated basis set - % data. - raw_A = op_filter(raw_A, 2); - raw_B = op_filter(raw_B, 2); - raw_C = op_filter(raw_C, 2); - raw_D = op_filter(raw_D, 2); - [raw_A, fs_A, phs_A, weights_A, driftPreA, driftPostA] = op_SpecRegFreqRestrict(raw_A, 'HERCULES', 0,refShift_ind_ini,0,0.5,3.9); - [raw_B, fs_B, phs_B, weights_B, driftPreB, driftPostB] = op_SpecRegFreqRestrict(raw_B, 'HERCULES', 0, refShift_ind_ini,0,0.5,3.8); - [raw_C, fs_C, phs_C, weights_C, driftPreC, driftPostC] = op_SpecRegFreqRestrict(raw_C, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.9); - [raw_D, fs_D, phs_D, weights_D, driftPreD, driftPostD] = op_SpecRegFreqRestrict(raw_D, 'HERCULES', 0, refShift_ind_ini,0,1.85,3.8); - end - else - raw.flags.averaged = 1; - raw.dims.averages = 0; - raw.specReg.fs = zeros(1,2); % save align parameters - raw.specReg.phs = zeros(1,2); % save align parameters - raw.specReg.weights{1} = ones(1,1); % save align parameters - raw.specReg.weights{2} = ones(1,1); % save align parameters - driftPre{1} = 0; - driftPre{2} = 0; - driftPost = driftPre; - end - - - %%% 2. GET REFERENCE DATA / EDDY CURRENT CORRECTION %%% - % If there are reference scans, perform the same operations - if MRSCont.flags.hasRef - raw_ref = MRSCont.raw_ref{kk}; % Get the kk-th dataset - - % Some formats end up having subspectra in their reference scans - % (e.g. Philips), as well as empty lines. Intercept these cases - % here. - if raw_ref.subspecs > 1 - raw_ref_A = op_takesubspec(raw_ref,1); - [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines - raw_ref_B = op_takesubspec(raw_ref,2); - [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines - raw_ref_C = op_takesubspec(raw_ref,3); - [raw_ref_C] = op_rmempty(raw_ref_C); % Remove empty lines - raw_ref_D = op_takesubspec(raw_ref,4); - [raw_ref_D] = op_rmempty(raw_ref_D); % Remove empty lines - raw_ref = op_concatAverages(raw_ref_A,raw_ref_B,raw_ref_C,raw_ref_D); - end - if ~raw_ref.flags.averaged - [raw_ref] = op_rmempty(raw_ref); - [raw_ref,~,~] = op_alignAverages(raw_ref,1,'n'); % Align averages - raw_ref = op_averaging(raw_ref); % Average - end - - % Apply Klose eddy current correction - [raw_A,~] = op_eccKlose(raw_A, raw_ref); - [raw_B,~] = op_eccKlose(raw_B, raw_ref); - [raw_C,~] = op_eccKlose(raw_C, raw_ref); - [raw_D,raw_ref] = op_eccKlose(raw_D, raw_ref); - - [raw_ref,~] = op_ppmref(raw_ref,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - MRSCont.processed.ref{kk} = raw_ref; % Save back to MRSCont container - end - - %%% 2a. PHANTOM-SPECIFIC PRE-PROCESSING %%% - % If this is phantom data (assuming room temperature), we want to - % perform a few specific pre-processing steps. - if MRSCont.flags.isPhantom - % First, we undo phase cycling by dividing by the first data - % point (this is mainly experimental at this point, but has - % proved beneficial for phase-cycled GE data). -% for rr = 1:raw.rawAverages -% phi = repelem(conj(raw.fids(1,rr))./abs(raw.fids(1,rr)),size(raw.fids,1)); -% raw.fids(:,rr) = raw.fids(:,rr) .* phi'; -% raw.specs = fftshift(fft(raw.fids,[],1)); -% end - - % Finally, apply some linebroadening. High-quality in-vitro - % data may have linewidth lower than the simulated basis set - % data. - if MRSCont.flags.hasRef - raw_ref = op_filter(raw_ref, 2); - end - end - - - %%% 3. DETERMINE POLARITY OF SPECTRUM (EG FOR MOIST WATER SUPP) %%% - % Automate determination whether the Cr peak has positive polarity. - % For water suppression methods like MOIST, the residual water may - % actually have negative polarity, but end up positive in the data, so - % that the spectrum needs to be flipped. - raw_A_Cr = op_freqrange(raw_A,2.8,3.2); - polResidCr = abs(max(real(raw_A_Cr.specs))) - abs(min(real(raw_A_Cr.specs))); - if polResidCr < 0 - raw_A = op_ampScale(raw_A,-1); - end - - raw_B_Cr = op_freqrange(raw_B,2.8,3.2); - polResidCr = abs(max(real(raw_B_Cr.specs))) - abs(min(real(raw_B_Cr.specs))); - if polResidCr < 0 - raw_B = op_ampScale(raw_B,-1); - end - - raw_C_Cr = op_freqrange(raw_C,2.8,3.2); - polResidCr = abs(max(real(raw_C_Cr.specs))) - abs(min(real(raw_C_Cr.specs))); - if polResidCr < 0 - raw_C = op_ampScale(raw_C,-1); - end - - raw_D_Cr = op_freqrange(raw_D,2.8,3.2); - polResidCr = abs(max(real(raw_D_Cr.specs))) - abs(min(real(raw_D_Cr.specs))); - if polResidCr < 0 - raw_D = op_ampScale(raw_D,-1); - end - %%% 4. DETERMINE ON/OFF STATUS - % Classify the four sub-spectra such that the OFF spectrum is stored to - % field A, and the ON spectrum is stored to field B. - [raw_A, raw_B, raw_C, raw_D, commuteOrder] = osp_onOffClassifyHERMES(raw_A, raw_B, raw_C, raw_D,[target1 target2]); - subSpecNames = {'A', 'B', 'C', 'D'}; - % Save drift information back to container - eval(['MRSCont.QM.drift.pre.A{kk} = driftPre' subSpecNames{commuteOrder(1)} ';']); - eval(['MRSCont.QM.drift.pre.B{kk} = driftPre' subSpecNames{commuteOrder(2)} ';']); - eval(['MRSCont.QM.drift.pre.C{kk} = driftPre' subSpecNames{commuteOrder(3)} ';']); - eval(['MRSCont.QM.drift.pre.D{kk} = driftPre' subSpecNames{commuteOrder(4)} ';']); - eval(['MRSCont.QM.drift.post.A{kk} = driftPost' subSpecNames{commuteOrder(1)} ';']); - eval(['MRSCont.QM.drift.post.B{kk} = driftPost' subSpecNames{commuteOrder(2)} ';']); - eval(['MRSCont.QM.drift.post.C{kk} = driftPost' subSpecNames{commuteOrder(3)} ';']); - eval(['MRSCont.QM.drift.post.D{kk} = driftPost' subSpecNames{commuteOrder(4)} ';']); - % Generate the drift plot for the entire experiment in - % the correct order - driftPre = [MRSCont.QM.drift.pre.A{kk}, MRSCont.QM.drift.pre.B{kk}, MRSCont.QM.drift.pre.C{kk}, MRSCont.QM.drift.pre.D{kk}]'; - try - driftPre = reshape(driftPre, [raw.averages, 1]); - catch - driftPre = reshape(driftPre, [raw.rawAverages, 1]); - end - MRSCont.QM.drift.pre.diff1{kk} = driftPre; - MRSCont.QM.drift.pre.diff2{kk} = driftPre; - if exist('target3', 'var') % For HERMES 4 acqusitions - MRSCont.QM.drift.pre.diff3{kk} = driftPre; - end - MRSCont.QM.drift.pre.sum{kk} = driftPre; - driftPost = [MRSCont.QM.drift.post.A{kk}, MRSCont.QM.drift.post.B{kk}, MRSCont.QM.drift.post.C{kk}, MRSCont.QM.drift.post.D{kk}]'; - try - driftPost = reshape(driftPost, [raw.averages, 1]); - catch - driftPost = reshape(driftPost, [raw.rawAverages, 1]); - end - MRSCont.QM.drift.post.diff1{kk} = driftPost; - MRSCont.QM.drift.post.diff2{kk} = driftPost; - if exist('target3', 'var') % For HERMES 4 acqusitions - MRSCont.QM.drift.post.diff3{kk} = driftPre; - end - MRSCont.QM.drift.post.sum{kk} = driftPost; - - eval(['raw_A.specReg.fs = fs_' subSpecNames{commuteOrder(1)} ';']); % save align parameters - eval(['raw_B.specReg.fs = fs_' subSpecNames{commuteOrder(2)} ';']); - eval(['raw_C.specReg.fs = fs_' subSpecNames{commuteOrder(3)} ';']); - eval(['raw_D.specReg.fs = fs_' subSpecNames{commuteOrder(4)} ';']); - eval(['raw_A.specReg.phs = phs_' subSpecNames{commuteOrder(1)} ';']); - eval(['raw_B.specReg.phs = phs_' subSpecNames{commuteOrder(2)} ';']); - eval(['raw_C.specReg.phs = phs_' subSpecNames{commuteOrder(3)} ';']); - eval(['raw_D.specReg.phs = phs_' subSpecNames{commuteOrder(4)} ';']); - eval(['raw_A.specReg.weights = weights_' subSpecNames{commuteOrder(1)} '{1}(1,:);']); - eval(['raw_B.specReg.weights = weights_' subSpecNames{commuteOrder(2)} '{1}(1,:);']); - eval(['raw_C.specReg.weights = weights_' subSpecNames{commuteOrder(3)} '{1}(1,:);']); - eval(['raw_D.specReg.weights = weights_' subSpecNames{commuteOrder(4)} '{1}(1,:);']); - raw_A.specReg.weights = raw_A.specReg.weights'/(max(raw_A.specReg.weights)); - raw_B.specReg.weights = raw_B.specReg.weights'/(max(raw_B.specReg.weights)); - raw_C.specReg.weights = raw_C.specReg.weights'/(max(raw_C.specReg.weights)); - raw_D.specReg.weights = raw_D.specReg.weights'/(max(raw_D.specReg.weights)); - % Generate the frequency and phase plots for the entire experiment in - % the correct order - fs = [raw_A.specReg.fs, raw_B.specReg.fs, raw_C.specReg.fs, raw_D.specReg.fs]'; - fs = reshape(fs, [raw.rawAverages, 1]); - phs = [raw_A.specReg.phs, raw_B.specReg.phs, raw_C.specReg.phs, raw_D.specReg.phs]'; - phs = reshape(phs, [raw.rawAverages, 1]); - weights = [raw_A.specReg.weights, raw_B.specReg.weights, raw_C.specReg.weights, raw_D.specReg.weights]'; - weights = reshape(weights, [raw.rawAverages, 1]); - MRSCont.raw{kk}.specReg.fs = fs; % save align parameters - MRSCont.raw{kk}.specReg.phs = phs; % save align parameters - MRSCont.raw{kk}.specReg.weights = weights; % save align parameters - - %%% 5. BUILD SUM AND DIFF SPECTRA %%% - % Correct the frequency axis so that Cr appears at 3.027 ppm - temp_spec = op_addScans(raw_A,raw_B); - temp_spec = op_addScans(temp_spec,raw_C); - temp_spec = op_addScans(temp_spec,raw_D); - [refShift_SubSpecAlign, ~] = osp_CrChoReferencing(temp_spec); - % Apply initial referencing shift - raw_A = op_freqshift(raw_A, -refShift_SubSpecAlign); - raw_B = op_freqshift(raw_B, -refShift_SubSpecAlign); - raw_C = op_freqshift(raw_C, -refShift_SubSpecAlign); - raw_D = op_freqshift(raw_D, -refShift_SubSpecAlign); - % Fit a double-Lorentzian to the Cr-Cho area, and phase the spectrum - % with the negative phase of that fit - [raw_A,~] = op_phaseCrCho(raw_A, 1); - % Align the sub-spectra to one another by minimizing the difference - % between the common 'reporter' signals. - if ~exist('target3', 'var') - switch MRSCont.opts.SubSpecAlignment - case 'L1Norm' - [raw_A, raw_B, raw_C, raw_D] = osp_editSubSpecAlignLNorm(raw_A, raw_B, raw_C, raw_D); - case 'L2Norm' - [raw_A, raw_B, raw_C, raw_D] = osp_editSubSpecAlign(raw_A, raw_B, raw_C, raw_D,MRSCont.opts.UnstableWater,target1,target2); - otherwise - raw_B = op_addphase(raw_B, -ph*180/pi, 0, raw_B.centerFreq, 1); - raw_C = op_addphase(raw_C, -ph*180/pi, 0, raw_C.centerFreq, 1); - raw_D = op_addphase(raw_D, -ph*180/pi, 0, raw_D.centerFreq, 1); - end - else - [raw_A, raw_B, raw_C, raw_D] = osp_editSubSpecAlign(raw_A, raw_B, raw_C, raw_D,MRSCont.opts.UnstableWater,target2,target3); - end - - % Create the sum spectrum - Sum = op_addScans(raw_A,raw_B); - Sum = op_addScans(Sum,raw_C); - Sum = op_addScans(Sum,raw_D); - Sum.commuteOrder = commuteOrder; - Sum.specReg.fs = fs; - Sum.specReg.phs = phs; - Sum.specReg.weights = weights; - % Create the GABA-edited difference spectrum - diff1 = op_addScans(raw_B,raw_D); - diff1 = op_addScans(diff1,raw_A,1); - diff1 = op_addScans(diff1,raw_C,1); - diff1.target = target1; - diff1.commuteOrder = commuteOrder; - diff1.specReg.fs = fs; - diff1.specReg.phs = phs; - diff1.specReg.weights = weights; - % Create the GSH-edited difference spectrum - diff2 = op_addScans(raw_C,raw_D); - diff2 = op_addScans(diff2,raw_A,1); - diff2 = op_addScans(diff2,raw_B,1); - diff2.target = target2; - diff2.commuteOrder = commuteOrder; - diff2.specReg.fs = fs; - diff2.specReg.phs = phs; - diff2.specReg.weights = weights; - - if exist('target3', 'var') % For HERMES 4 acqusitions - % Create the Asp-edited difference spectrum - diff1 = op_addScans(raw_A,raw_B,1); - diff1 = op_addScans(diff1,raw_C,1); - diff1 = op_addScans(diff1,raw_D); - diff1.target = target1; - diff1.commuteOrder = commuteOrder; - diff1.specReg.fs = fs; - diff1.specReg.phs = phs; - diff1.specReg.weights = weights; - % Create the NAA-edited difference spectrum - diff2 = op_addScans(raw_C,raw_D); - diff2 = op_addScans(diff2,raw_A,1); - diff2 = op_addScans(diff2,raw_B,1); - diff2.target = target2; - diff2.commuteOrder = commuteOrder; - diff2.specReg.fs = fs; - diff2.specReg.phs = phs; - diff2.specReg.weights = weights; - % Create the NAAG-edited difference spectrum - diff3 = op_addScans(raw_B,raw_D); - diff3 = op_addScans(diff3,raw_A,1); - diff3 = op_addScans(diff3,raw_C,1); - diff3.target = target3; - diff3.commuteOrder = commuteOrder; - diff3.specReg.fs = fs; - diff3.specReg.phs = phs; - diff3.specReg.weights = weights; - end - - %%% 6. REMOVE RESIDUAL WATER %%% - % Remove water and correct back to baseline. - % The spectra sometimes become NaNs after filtering with too many - % components. Loop over decreasing numbers of components here. - % Define different water removal frequency ranges, depending on - % whether this is phantom data - if MRSCont.flags.isPhantom - waterRemovalFreqRange = [4.5 5]; - fracFID = 0.2; - Kinit = 32; - else - if ~MRSCont.flags.isPRIAM - waterRemovalFreqRange = [4.5 4.9]; - fracFID = 0.75; - Kinit = 32; - else -% waterRemovalFreqRange = [4.3 5.5]; -% fracFID = 0.75; -% Kinit = 45; - waterRemovalFreqRange = [4.5 4.9]; - fracFID = 0.75; - Kinit = 32; - end - end - % Apply iterative water filter - raw_A = op_iterativeWaterFilter(raw_A, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - raw_B = op_iterativeWaterFilter(raw_B, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - raw_C = op_iterativeWaterFilter(raw_C, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - raw_D = op_iterativeWaterFilter(raw_D, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - diff1 = op_iterativeWaterFilter(diff1, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - diff2 = op_iterativeWaterFilter(diff2, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - if exist('target3', 'var') % For HERMES 4 acqusitions - diff3 = op_iterativeWaterFilter(diff3, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - end - Sum = op_iterativeWaterFilter(Sum, waterRemovalFreqRange, Kinit, fracFID*length(raw.fids), 0); - - %%% 7. REFERENCE SPECTRUM CORRECTLY TO FREQUENCY AXIS - % Reference resulting data correctly and consistently - %[raw_A, refShift] = op_ppmref(raw_A,1.8,2.2,2.008); % Reference OFF-OFF spectrum to NAA @ 2.008 ppm - temp_spec = Sum; - [refShift_final, ~] = osp_CrChoReferencing(temp_spec);% Reference OFF-OFF spectrum to NAA @ 2.008 ppm - [raw_A] = op_freqshift(raw_A,-refShift_final); % Apply same shift to ON-OFF - [raw_B] = op_freqshift(raw_B,-refShift_final); % Apply same shift to ON-OFF - [raw_C] = op_freqshift(raw_C,-refShift_final); % Apply same shift to OFF-ON - [raw_D] = op_freqshift(raw_D,-refShift_final); % Apply same shift to ON-ON - [diff1] = op_freqshift(diff1,-refShift_final); % Apply same shift to diff1 - [diff2] = op_freqshift(diff2,-refShift_final); % Apply same shift to diff2 - if exist('target3', 'var') % For HERMES 4 acqusitions - [diff3] = op_freqshift(diff3,-refShift_final); % Apply same shift to diff2 - end - [Sum] = op_freqshift(Sum,-refShift_final); % Apply same shift to sum - - % Add commuteOrder - raw_A.commuteOrder = commuteOrder(1); - raw_B.commuteOrder = commuteOrder(2); - raw_C.commuteOrder = commuteOrder(3); - raw_D.commuteOrder = commuteOrder(4); - - %%% 8. SAVE BACK TO MRSCONT CONTAINER - MRSCont.processed.A{kk} = raw_A; % Save OFF-OFF back to MRSCont container - MRSCont.processed.B{kk} = raw_B; % Save ON-OFF back to MRSCont container - MRSCont.processed.C{kk} = raw_C; % Save OFF-ON back to MRSCont container - MRSCont.processed.D{kk} = raw_D; % Save ON-ON back to MRSCont container - MRSCont.processed.diff1{kk} = diff1; % Save diff1 back to MRSCont container - MRSCont.processed.diff2{kk} = diff2; % Save diff2 back to MRSCont container - if exist('target3', 'var') % For HERMES 4 acqusitions - MRSCont.processed.diff3{kk} = diff3; % Save diff3 back to MRSCont container - end - MRSCont.processed.sum{kk} = Sum; % Save sum back to MRSCont container - - - %%% 9. GET SHORT-TE WATER DATA %%% - if MRSCont.flags.hasWater - % Some formats end up having subspectra in their reference scans - % (e.g. Philips), as well as empty lines. Intercept these cases - % here. - raw_w = MRSCont.raw_w{kk}; % Get the kk-th dataset - if raw_w.subspecs > 1 - raw_w_A = op_takesubspec(raw_w,1); - [raw_w_A] = op_rmempty(raw_w_A); % Remove empty lines - raw_w_B = op_takesubspec(raw_w,2); - [raw_w_A] = op_rmempty(raw_w_A); % Remove empty lines - raw_w = op_concatAverages(raw_w_A,raw_w_B); - end - if ~raw_w.flags.averaged - [raw_w,fs_A,phs_A] = op_alignAverages(raw_w,1,'n'); % Align averages - raw_w = op_averaging(raw_w); % Average - end - [raw_w,~] = op_eccKlose(raw_w, raw_w); % Klose eddy current correction - [raw_w,~] = op_ppmref(raw_w,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - MRSCont.processed.w{kk} = raw_w; % Save back to MRSCont container - end - - - %%% 10. QUALITY CONTROL PARAMETERS %%% - SubSpec = {'A','B','C','D','diff1','diff2','sum'}; - SNRRange = {[1.8,2.2],[2.8,3.2],[2.8,3.2],[1.8,2.2],[2.8,3.2],[2.8,3.2],[2.8,3.2]}; - if exist('target3', 'var') % For HERMES 4 acqusitions - SubSpec{end+1} = 'diff3'; - SNRRange{end+1} = [2.8,3.2]; - end - if MRSCont.flags.hasRef - SubSpec{end+1} = 'ref'; - SNRRange{end+1} = [4.2,5.2]; - end - if MRSCont.flags.hasWater - SubSpec{end+1} = 'w'; - SNRRange{end+1} = [4.2,5.2]; - end - % Calculate some spectral quality metrics here; - for ss = 1 : length(SubSpec) - MRSCont.QM.SNR.(SubSpec{ss})(kk) = op_getSNR(MRSCont.processed.(SubSpec{ss}){kk}); - MRSCont.QM.FWHM.(SubSpec{ss})(kk) = op_getLW(MRSCont.processed.(SubSpec{ss}){kk},SNRRange{ss}(1),SNRRange{ss}(2)); % in Hz - if ~(strcmp(SubSpec{ss},'ref') || strcmp(SubSpec{ss},'w')) - MRSCont.QM.freqShift.(SubSpec{ss})(kk) = refShift_SubSpecAlign + refShift_final; - MRSCont.QM.res_water_amp.(SubSpec{ss})(kk) = sum(MRSCont.processed.(SubSpec{ss}){kk}.watersupp.amp); - MRSCont.QM.drift.pre.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - MRSCont.QM.drift.post.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - end - end - end -end -time = toc(refProcessTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - -%%% 11. SET FLAGS %%% -MRSCont.flags.avgsAligned = 1; -MRSCont.flags.averaged = 1; -MRSCont.flags.ECCed = 1; -MRSCont.flags.waterRemoved = 1; -MRSCont.runtime.Proc = time; -% Close any remaining open figures -close all; - -end \ No newline at end of file diff --git a/process/osp_processMEGA.m b/process/osp_processMEGA.m deleted file mode 100644 index 0c6daae6..00000000 --- a/process/osp_processMEGA.m +++ /dev/null @@ -1,401 +0,0 @@ -function [MRSCont] = osp_processMEGA(MRSCont, target) -%% [MRSCont] = osp_processMEGA(MRSCont, target) -% This function performs the following steps to process MEGA-edited -% (2-step) MRS data (e.g. MEGA-PRESS, MEGA-sLASER): -% - Alignment of individual averages using robust spectral registration -% - Averaging -% - Removal of residual water using HSVD filtering -% - Klose Eddy current correction (if a reference scan is provided) -% - Automated zero-order phase correction -% - Correct referencing of the ppm frequency axis -% -% USAGE: -% [MRSCont] = osp_processMEGA(MRSCont, 'target'); -% -% INPUTS: -% MRSCont = Osprey MRS data container. -% target = String. Can be 'GABA' or 'GSH'. Default: 'GABA' -% -% OUTPUTS: -% MRSCont = Osprey MRS data container. -% -% AUTHOR: -% Dr. Georg Oeltzschner (Johns Hopkins University, 2019-02-22) -% goeltzs1@jhmi.edu -% -% CREDITS: -% This code is based on numerous functions from the FID-A toolbox by -% Dr. Jamie Near (McGill University) -% https://github.com/CIC-methods/FID-A -% Simpson et al., Magn Reson Med 77:23-33 (2017) -% -% HISTORY: -% 2019-08-20: First public version of the code. - - -warning('off','all'); - -% Parse input arguments -if nargin < 2 - target = MRSCont.opts.editTarget{1}; % GABA editing as default -end - -%% Loop over all datasets -refProcessTime = tic; -if MRSCont.flags.isGUI - progressText = MRSCont.flags.inProgress; -else - progressText = ''; -end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyProcess',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didProcess == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'processed') && (kk > length(MRSCont.processed.A))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - %%% 1. GET RAW DATA %%% - raw = MRSCont.raw{kk}; % Get the kk-th dataset - - if raw.averages > 1 && raw.flags.averaged == 0 - % Calculate starting values for spectral registration - [refShift_ind_ini]=op_preref(raw,'MEGA'); - % Perform robust spectral correction with weighted averaging. - % This can obviously only be done, if the spectra have not been - % pre-averaged, i.e. in some older RDA and DICOM files (which should, - % generally, not be used). - if ~MRSCont.flags.isPhantom - if MRSCont.flags.isMRSI - if MRSCont.opts.MoCo.lb > 0 - raw = op_filter(raw, MRSCont.opts.MoCo.lb); - end - end - switch MRSCont.opts.SpecReg %Pick spectral registration method (default is Robust Spectral Registration) - case 'ProbSpecReg' - [raw, fs, phs, weights, driftPre, driftPost] = op_probabSpecReg(raw, 'MEGA', 0,refShift_ind_ini); - - case 'RobSpecReg' - [raw, fs, phs, weights, driftPre, driftPost] = op_robustSpecReg(raw, 'MEGA', 0,refShift_ind_ini); % Align and average - case 'RestrSpecReg' - if isfield(MRSCont.opts,'SpecRegRange') - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'MEGA', 0,refShift_ind_ini,0,MRSCont.opts.SpecRegRange(1),MRSCont.opts.SpecRegRange(2)); % Align and average - else - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'MEGA', 0,refShift_ind_ini,0,MRSCont.opts.fit.range(1),MRSCont.opts.fit.range(2)); % Align and average - end - case 'none' - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'MEGA', 0,refShift_ind_ini,1); % Align and average - end - else - % Next, shift the entire metabolite spectrum by 0.15 ppm. - % This doesn't have to be completely accurate, since additional - % referencing steps are performed in the later stages of - % post-processing and modelling, but we want the prominent singlets - % to appear within 0.1 ppm of their expected in-vivo positions. - phantomShiftPPM = 0.15 * raw.txfrq*1e-6; - raw = op_freqshift(raw, -phantomShiftPPM); - % Finally, apply some linebroadening. High-quality in-vitro - % data may have linewidth lower than the simulated basis set - % data. - raw = op_filter(raw, 2); - switch MRSCont.opts.SpecReg %Pick spectral registration method (default is Robust Spectral Registration) - case 'none' - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'MEGA', 0,refShift_ind_ini,1); % Align and average - otherwise - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'MEGA', 0,refShift_ind_ini,0,0.5,4.2); - end - - end - raw.specReg.fs = fs; % save align parameters - raw.specReg.phs = phs; % save align parameters - raw.specReg.weights = weights; % save align parameters - else - raw.flags.averaged = 1; - raw.dims.averages = 0; - raw.specReg.fs = zeros(1,2); % save align parameters - raw.specReg.phs = zeros(1,2); % save align parameters - raw.specReg.weights{1} = ones(1,1); % save align parameters - raw.specReg.weights{2} = ones(1,1); % save align parameters - driftPre{1} = 0; - driftPre{2} = 0; - driftPost = driftPre; - if MRSCont.flags.isPhantom - % Next, shift the entire metabolite spectrum by 0.15 ppm. - % This doesn't have to be completely accurate, since additional - % referencing steps are performed in the later stages of - % post-processing and modelling, but we want the prominent singlets - % to appear within 0.1 ppm of their expected in-vivo positions. - phantomShiftPPM = 0.2 * raw.txfrq*1e-6; - raw = op_freqshift(raw, -phantomShiftPPM); - % Finally, apply some linebroadening. High-quality in-vitro - % data may have linewidth lower than the simulated basis set - % data. - raw = op_filter(raw, 2); - end - end - - % Get sub-spectra, depending on whether they are stored as such - if raw.subspecs == 2 - raw_A = op_takesubspec(raw,1); % Get first subspectrum - raw_B = op_takesubspec(raw,2); % Get second subspectrum - else - raw_A = op_takeaverages(raw,1:2:raw.averages); % Get first subspectrum - raw_B = op_takeaverages(raw,2:2:raw.averages); % Get second subspectrum - end - - %%% 2. GET REFERENCE DATA / EDDY CURRENT CORRECTION %%% - % If there are reference scans, perform the same operations - if MRSCont.flags.hasRef - raw_ref = MRSCont.raw_ref{kk}; % Get the kk-th dataset - - % Some formats end up having subspectra in their reference scans - % (e.g. Philips), as well as empty lines. Intercept these cases - % here. - if raw_ref.subspecs > 1 - raw_ref_A = op_takesubspec(raw_ref,1); - [raw_ref_A] = op_rmempty(raw_ref_A); % Remove empty lines - raw_ref_B = op_takesubspec(raw_ref,2); - [raw_ref_B] = op_rmempty(raw_ref_B); % Remove empty lines - raw_ref = op_concatAverages(raw_ref_A,raw_ref_B); - end - if ~raw_ref.flags.averaged - [raw_ref,~,~] = op_alignAverages(raw_ref,1,'n'); % Align averages - raw_ref = op_averaging(raw_ref); % Average - end - [raw_A,~] = op_eccKlose(raw_A, raw_ref); - [raw_B,raw_ref] = op_eccKlose(raw_B, raw_ref); % Klose eddy current correction - - [raw_ref,~] = op_ppmref(raw_ref,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - MRSCont.processed.ref{kk} = raw_ref; % Save back to MRSCont container - end - - %%% 2a. PHANTOM-SPECIFIC PRE-PROCESSING %%% - % If this is phantom data (assuming room temperature), we want to - % perform a few specific pre-processing steps. - if MRSCont.flags.isPhantom - % First, we undo phase cycling by dividing by the first data - % point (this is mainly experimental at this point, but has - % proved beneficial for phase-cycled GE data). -% for rr = 1:raw.rawAverages -% phi = repelem(conj(raw.fids(1,rr))./abs(raw.fids(1,rr)),size(raw.fids,1)); -% raw.fids(:,rr) = raw.fids(:,rr) .* phi'; -% raw.specs = fftshift(fft(raw.fids,[],1)); -% end - if MRSCont.flags.hasRef - raw_ref = op_filter(raw_ref, 2); - end - end - - - %%% 3. DETERMINE POLARITY OF SPECTRUM (EG FOR MOIST WATER SUPP) %%% - % Automate determination whether the Cr peak has positive polarity. - % For water suppression methods like MOIST, the residual water may - % actually have negative polarity, but end up positive in the data, so - % that the spectrum needs to be flipped. - raw_A_Cr = op_freqrange(raw_A,2.8,3.2); - % Determine the polarity of the respective peak: if the absolute of the - % maximum minus the absolute of the minimum is positive, the polarity - % of the respective peak is positive; if the absolute of the maximum - % minus the absolute of the minimum is negative, the polarity is negative. - polResidCr = abs(max(real(raw_A_Cr.specs))) - abs(min(real(raw_A_Cr.specs))); - if polResidCr < 0 - raw_A = op_ampScale(raw_A,-1); - end - raw_B_Cr = op_freqrange(raw_B,2.8,3.2); - % Determine the polarity of the respective peak: if the absolute of the - % maximum minus the absolute of the minimum is positive, the polarity - % of the respective peak is positive; if the absolute of the maximum - % minus the absolute of the minimum is negative, the polarity is negative. - polResidCr = abs(max(real(raw_B_Cr.specs))) - abs(min(real(raw_B_Cr.specs))); - if polResidCr < 0 - raw_B = op_ampScale(raw_B,-1); - end - - - %%% 4. DETERMINE ON/OFF STATUS - % Classify the two sub-spectra such that the OFF spectrum is stored to - % field A, and the ON spectrum is stored to field B. - [raw_A, raw_B, switchOrder] = osp_onOffClassifyMEGA(raw_A, raw_B, target); - % Save drift information back to container - if ~switchOrder - MRSCont.QM.drift.pre.A{kk} = driftPre{1}; - MRSCont.QM.drift.pre.B{kk} = driftPre{2}; - MRSCont.QM.drift.post.A{kk} = driftPost{1}; - MRSCont.QM.drift.post.B{kk} = driftPost{1}; - else - MRSCont.QM.drift.pre.A{kk} = driftPre{2}; - MRSCont.QM.drift.pre.B{kk} = driftPre{1}; - MRSCont.QM.drift.post.A{kk} = driftPost{2}; - MRSCont.QM.drift.post.B{kk} = driftPost{1}; - end - raw_A.specReg.fs = raw.specReg.fs(:,1); % save align parameters - raw_B.specReg.fs = raw.specReg.fs(:,2); - raw_A.specReg.phs = raw.specReg.phs(:,1); - raw_B.specReg.phs = raw.specReg.phs(:,2); - raw_A.specReg.weights = raw.specReg.weights{1}(1,:); - raw_B.specReg.weights = raw.specReg.weights{2}(1,:); - raw_A.specReg.weights = raw_A.specReg.weights'/(max(raw_A.specReg.weights)); - raw_B.specReg.weights = raw_B.specReg.weights'/(max(raw_B.specReg.weights)); - % Generate the frequency and phase plots for the entire experiment in - % the correct order - fs = [raw_A.specReg.fs, raw_B.specReg.fs]'; - phs = [raw_A.specReg.phs, raw_B.specReg.phs]'; - weights = [raw_A.specReg.weights, raw_B.specReg.weights]'; - if raw.rawAverages ~= 1 - fs = reshape(fs, [raw.rawAverages, 1]); - phs = reshape(phs, [raw.rawAverages, 1]); - weights = reshape(weights, [raw.rawAverages, 1]); - end - - MRSCont.raw{kk}.specReg.fs = fs; % save align parameters - MRSCont.raw{kk}.specReg.phs = phs; % save align parameters - MRSCont.raw{kk}.specReg.weights = weights; % save align parameters - - %%% 5. BUILD SUM AND DIFF SPECTRA %%% - % Correct the frequency axis so that Cr appears at 3.027 ppm - [raw_A,~] = op_phaseCrCho(raw_A, 1); - [raw_B,~] = op_phaseCrCho(raw_B, 1); - temp_spec = op_addScans(raw_A,raw_B); - [refShift_SubSpecAlign, ~] = osp_CrChoReferencing(temp_spec); - % Apply initial referencing shift - raw_A = op_freqshift(raw_A, -refShift_SubSpecAlign); - raw_B = op_freqshift(raw_B, -refShift_SubSpecAlign); - % Fit a double-Lorentzian to the Cr-Cho area, and phase the spectrum - % with the negative phase of that fit - [raw_A,ph] = op_phaseCrCho(raw_A, 1); - raw_B = op_addphase(raw_B, -ph*180/pi, 0, raw_B.centerFreq, 1); - % Align the sub-spectra to one another by minimizing the difference - % between the common 'reporter' signals. - - switch MRSCont.opts.SubSpecAlignment - case 'L1Norm' - [raw_A, raw_B] = osp_editSubSpecAlignLNorm(raw_A, raw_B); - case 'L2Norm' - [raw_A, raw_B] = osp_editSubSpecAlign(raw_A, raw_B, target,MRSCont.opts.UnstableWater); - end - - - - % Create the sum spectrum - Sum = op_addScans(raw_A,raw_B); - if switchOrder - Sum.flags.orderswitched = 1; - else - Sum.flags.orderswitched = 0; - end - Sum.specReg.fs = fs; - Sum.specReg.phs = phs; - Sum.specReg.weights = weights; - % Create the GABA-edited difference spectrum - diff1 = op_addScans(raw_B,raw_A,1); - if switchOrder - diff1.flags.orderswitched = 1; - else - diff1.flags.orderswitched = 0; - end - diff1.target = target; - diff1.specReg.fs = fs; - diff1.specReg.phs = phs; - diff1.specReg.weights = weights; - - %%% 6. REMOVE RESIDUAL WATER %%% - % Remove water and correct back to baseline. - % The spectra sometimes become NaNs after filtering with too many - % components. Loop over decreasing numbers of components here. - % Define different water removal frequency ranges, depending on - % whether this is phantom data - if MRSCont.flags.isPhantom - waterRemovalFreqRange = [4.5 5]; - fracFID = 0.2; - else - waterRemovalFreqRange = [4.5 4.9]; - fracFID = 0.75; - end - % Apply iterative water filter - raw_A = op_iterativeWaterFilter(raw_A, waterRemovalFreqRange, 32, fracFID*length(raw.fids), 0); - raw_B = op_iterativeWaterFilter(raw_B, waterRemovalFreqRange, 32, fracFID*length(raw.fids), 0); - diff1 = op_iterativeWaterFilter(diff1, waterRemovalFreqRange, 32, fracFID*length(raw.fids), 0); - Sum = op_iterativeWaterFilter(Sum, waterRemovalFreqRange, 32, fracFID*length(raw.fids), 0); - - %%% 7. REFERENCE SPECTRUM CORRECTLY TO FREQUENCY AXIS - % Reference resulting data correctly and consistently - [refShift_final, ~] = osp_CrChoReferencing(Sum); - [raw_A] = op_freqshift(raw_A,-refShift_final); % Apply same shift to edit-OFF - [raw_B] = op_freqshift(raw_B,-refShift_final); % Apply same shift to edit-OFF - [diff1] = op_freqshift(diff1,-refShift_final); % Apply same shift to diff1 - [Sum] = op_freqshift(Sum,-refShift_final); % Apply same shift to sum - - - %%% 8. SAVE BACK TO MRSCONT CONTAINER - MRSCont.processed.A{kk} = raw_A; % Save edit-OFF back to MRSCont container - MRSCont.processed.B{kk} = raw_B; % Save edit-ON back to MRSCont container - MRSCont.processed.diff1{kk} = diff1; % Save diff1 back to MRSCont container - MRSCont.processed.sum{kk} = Sum; % Save sum back to MRSCont container - - - %%% 9. GET SHORT-TE WATER DATA %%% - if MRSCont.flags.hasWater - % Some formats end up having subspectra in their reference scans - % (e.g. Philips), as well as empty lines. Intercept these cases - % here. - raw_w = MRSCont.raw_w{kk}; % Get the kk-th dataset - if raw_w.subspecs > 1 - raw_w_A = op_takesubspec(raw_w,1); - [raw_w_A] = op_rmempty(raw_w_A); % Remove empty lines - raw_w_B = op_takesubspec(raw_w,2); - [raw_w_A] = op_rmempty(raw_w_A); % Remove empty lines - raw_w = op_concatAverages(raw_w_A,raw_w_B); - end - if ~raw_w.flags.averaged - [raw_w,~,~] = op_alignAverages(raw_w,1,'n'); % Align averages - raw_w = op_averaging(raw_w); % Average - end - if ~MRSCont.flags.isMRSI - [raw_w,~] = op_eccKlose(raw_w, raw_w); % Klose eddy current correction - else - [raw_w,~]=op_autophase(raw_w,2,2*4.68); - end - [raw_w,~] = op_ppmref(raw_w,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - MRSCont.processed.w{kk} = raw_w; % Save back to MRSCont container - end - - - %%% 10. QUALITY CONTROL PARAMETERS %%% - SubSpec = {'A','B','diff1','sum'}; - SNRRange = {[1.8,2.2],[2.8,3.2],[2.8,3.2],[2.8,3.2]}; - if MRSCont.flags.hasRef - SubSpec{end+1} = 'ref'; - SNRRange{end+1} = [4.2,5.2]; - end - if MRSCont.flags.hasWater - SubSpec{end+1} = 'w'; - SNRRange{end+1} = [4.2,5.2]; - end - % Calculate some spectral quality metrics here; - for ss = 1 : length(SubSpec) - MRSCont.QM.SNR.(SubSpec{ss})(kk) = op_getSNR(MRSCont.processed.(SubSpec{ss}){kk},SNRRange{ss}(1),SNRRange{ss}(2)); - MRSCont.QM.FWHM.(SubSpec{ss})(kk) = op_getLW(MRSCont.processed.(SubSpec{ss}){kk},SNRRange{ss}(1),SNRRange{ss}(2)); % in Hz - if ~(strcmp(SubSpec{ss},'ref') || strcmp(SubSpec{ss},'w')) - MRSCont.QM.freqShift.(SubSpec{ss})(kk) = refShift_SubSpecAlign + refShift_final; - MRSCont.QM.res_water_amp.(SubSpec{ss})(kk) = sum(MRSCont.processed.(SubSpec{ss}){kk}.watersupp.amp); - if strcmp(SubSpec{ss},'diff1') || strcmp(SubSpec{ss},'sum') - MRSCont.QM.drift.pre.(SubSpec{ss}){kk} = reshape([MRSCont.QM.drift.pre.A{kk}'; MRSCont.QM.drift.pre.B{kk}'], [], 1)'; - MRSCont.QM.drift.post.(SubSpec{ss}){kk} = reshape([MRSCont.QM.drift.post.A{kk}'; MRSCont.QM.drift.post.B{kk}'], [], 1)'; - end - MRSCont.QM.drift.pre.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - MRSCont.QM.drift.post.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - end - end - - end -end -time = toc(refProcessTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - -%%% 11. SET FLAGS %%% -MRSCont.flags.avgsAligned = 1; -MRSCont.flags.averaged = 1; -MRSCont.flags.ECCed = 1; -MRSCont.flags.waterRemoved = 1; -MRSCont.runtime.Proc = time; -% Close any remaining open figures -close all; - -end \ No newline at end of file diff --git a/process/osp_processUnEdited.m b/process/osp_processUnEdited.m deleted file mode 100644 index e6763657..00000000 --- a/process/osp_processUnEdited.m +++ /dev/null @@ -1,277 +0,0 @@ -function [MRSCont] = osp_processUnEdited(MRSCont) -%% [MRSCont] = osp_processUnEdited(MRSCont) -% This function performs the following steps to process un-edited MRS -% data (e.g. PRESS, STEAM, sLASER): -% - Alignment of individual averages using robust spectral registration -% - Averaging -% - Removal of residual water using HSVD filtering -% - Klose Eddy current correction (if a reference scan is provided) -% - Correct referencing of the ppm frequency axis -% -% USAGE: -% [MRSCont] = osp_processUnEdited(MRSCont); -% -% INPUTS: -% MRSCont = Osprey MRS data container. -% -% OUTPUTS: -% MRSCont = Osprey MRS data container. -% -% AUTHOR: -% Dr. Georg Oeltzschner (Johns Hopkins University, 2019-02-20) -% goeltzs1@jhmi.edu -% -% CREDITS: -% This code is based on numerous functions from the FID-A toolbox by -% Dr. Jamie Near (McGill University) -% https://github.com/CIC-methods/FID-A -% Simpson et al., Magn Reson Med 77:23-33 (2017) -% -% HISTORY: -% 2019-02-20: First version of the code. - -warning('off','all'); - -%% Loop over all datasets -refProcessTime = tic; -if MRSCont.flags.isGUI - progressText = MRSCont.flags.inProgress; -else - progressText = ''; -end - -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreyProcess',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - - if ~(MRSCont.flags.didProcess == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'processed') && (kk > length(MRSCont.processed.A))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) - - %%% 1. GET RAW DATA %%% - raw = MRSCont.raw{kk}; % Get the kk-th dataset - - %%% 1B. GET MM DATA %%% - if MRSCont.flags.hasMM - raw_mm = MRSCont.raw_mm{kk}; % Get the kk-th dataset re_mm - if raw_mm.averages > 1 && raw_mm.flags.averaged == 0 %re_mm - [raw_mm,~,~] = op_alignAverages(raw_mm, 1, 'n'); %re_mm - raw_mm = op_averaging(raw_mm); % Average re_mm - else %re_mm - raw_mm.flags.averaged = 1; %re_mm - raw_mm.dims.averages = 0; %re_mm - end - [raw_mm,~] = op_ppmref(raw_mm,4.6,4.8,4.68); % Reference to water @ 4.68 ppm %re_mm - end %re_mm - - - - %%% 2a. PHANTOM-SPECIFIC PRE-PROCESSING %%% - % If this is phantom data (assuming room temperature), we want to - % perform a few specific pre-processing steps. - if MRSCont.flags.isPhantom - % First, we undo phase cycling by dividing by the first data - % point (this is mainly experimental at this point, but has - % proved beneficial for phase-cycled GE data). -% for rr = 1:raw.rawAverages -% phi = repelem(conj(raw.fids(1,rr))./abs(raw.fids(1,rr)),size(raw.fids,1)); -% raw.fids(:,rr) = raw.fids(:,rr) .* phi'; -% raw.specs = fftshift(fft(raw.fids,[],1)); -% end - - % Next, shift the entire metabolite spectrum by 0.15 ppm. - % This doesn't have to be completely accurate, since additional - % referencing steps are performed in the later stages of - % post-processing and modelling, but we want the prominent singlets - % to appear within 0.1 ppm of their expected in-vivo positions. - phantomShiftPPM = 0.15 * raw.txfrq*1e-6; - raw = op_freqshift(raw, -phantomShiftPPM); - - % Finally, apply some linebroadening. High-quality in-vitro - % data may have linewidth lower than the simulated basis set - % data. - raw = op_filter(raw, 2); - if MRSCont.flags.hasRef - raw_ref = op_filter(raw_ref, 2); - end - end - - %%% 3. FREQUENCY/PHASE CORRECTION AND AVERAGING %%% - - if raw.averages > 1 && raw.flags.averaged == 0 - % Calculate starting values for spectral registration - [refShift_ind_ini]=op_preref(raw,'unedited'); - if ~MRSCont.flags.isPhantom - switch MRSCont.opts.SpecReg %Pick spectral registration method (default is Robust Spectral Registration) - case 'RobSpecReg' - [raw, fs, phs, weights, driftPre, driftPost] = op_robustSpecReg(raw, 'unedited', 0,refShift_ind_ini); % Align and average - case 'RestrSpecReg' - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'unedited', 0,refShift_ind_ini,0,MRSCont.opts.fit.range(1),MRSCont.opts.fit.range(2)); % Align and average - case 'none' - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'unedited', 0,refShift_ind_ini,1); % Align and average - end - else - [raw, fs, phs, weights, driftPre, driftPost] = op_SpecRegFreqRestrict(raw, 'unedited', 0,refShift_ind_ini,0,0.5,4.2); % Align and average - end - raw.specReg.fs = fs; % save align parameters - raw.specReg.phs = phs; % save align parameters - raw.specReg.weights = weights{1}(1,:)'; % save align parameters); - raw.specReg.weights = raw.specReg.weights/max(raw.specReg.weights); - else - raw.flags.averaged = 1; - raw.dims.averages = 0; - raw.specReg.fs = 0; % save align parameters - raw.specReg.phs = 0; % save align parameters - raw.specReg.weights = 1; % save align parameters - driftPre = op_measureDrift(raw); - driftPost = driftPre; - end - - %%% 4. GET REFERENCE DATA / EDDY CURRENT CORRECTION %%% - % If there are reference scans, load them here to allow eddy-current - % correction of the raw data. - if MRSCont.flags.hasRef - raw_ref = MRSCont.raw_ref{kk}; % Get the kk-th dataset - if raw_ref.averages > 1 && raw_ref.flags.averaged == 0 - [raw_ref,~,~] = op_alignAverages(raw_ref, 1, 'n'); - raw_ref = op_averaging(raw_ref); % Average - else - raw_ref.flags.averaged = 1; - raw_ref.dims.averages = 0; - end - - if MRSCont.flags.hasMM - [raw_mm,~] = op_eccKlose(raw_mm, raw_ref); % Klose eddy current correction - end - [raw,raw_ref] = op_eccKlose(raw, raw_ref); % Klose eddy current correction - [raw_ref,~] = op_ppmref(raw_ref,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - MRSCont.processed.ref{kk} = raw_ref; % Save back to MRSCont container - end - - %%% 5. DETERMINE POLARITY OF SPECTRUM (EG FOR MOIST WATER SUPP) %%% - % Automate determination whether the NAA peak has positive polarity. - % For water suppression methods like MOIST, the residual water may - % actually have negative polarity, but end up positive in the data, so - % that the spectrum needs to be flipped. - raw_NAA = op_freqrange(raw,1.9,2.1); - % Determine the polarity of the respective peak: if the absolute of the - % maximum minus the absolute of the minimum is positive, the polarity - % of the respective peak is positive; if the absolute of the maximum - % minus the absolute of the minimum is negative, the polarity is negative. - polResidNAA = abs(max(real(raw_NAA.specs))) - abs(min(real(raw_NAA.specs))); - if polResidNAA < 0 - raw = op_ampScale(raw,-1); - MRSCont.raw{kk} = op_ampScale(MRSCont.raw{kk},-1); - end - - - %%% 6. REMOVE RESIDUAL WATER %%% - % Define different water removal frequency ranges, depending on - % whether this is phantom data - if MRSCont.flags.isPhantom - waterRemovalFreqRange = [4.5 5]; - fracFID = 0.2; - else - waterRemovalFreqRange = [4.5 4.9]; - fracFID = 0.75; - end - % Apply iterative water filter - raw = op_iterativeWaterFilter(raw, waterRemovalFreqRange, 32, fracFID*length(raw.fids), 0); - - if MRSCont.flags.hasMM %re_mm - raw_mm = op_iterativeWaterFilter(raw_mm, waterRemovalFreqRange, 32, fracFID*length(raw_mm.fids), 0); - end - - %%% 7. REFERENCE SPECTRUM CORRECTLY TO FREQUENCY AXIS AND PHASE SIEMENS - %%% DATA - [refShift, ~] = osp_CrChoReferencing(raw); - [raw] = op_freqshift(raw,-refShift); % Reference spectra by cross-correlation - - if MRSCont.flags.hasMM %re_mm - [refShift_mm, ~] = fit_OspreyReferencingMM(raw_mm); - [raw_mm] = op_freqshift(raw_mm,-refShift_mm); % Reference spectra by cross-correlation - MRSCont.processed.mm{kk} = raw_mm; % Save back to MRSCont container %re_mm - end - - - % Save back to MRSCont container - if strcmp(MRSCont.vendor,'Siemens') || MRSCont.flags.isMRSI - % Fit a double-Lorentzian to the Cr-Cho area, and phase the spectrum - % with the negative phase of that fit - [raw,globalPhase] = op_phaseCrCho(raw, 1); - raw.specReg.phs = raw.specReg.phs - globalPhase*180/pi; - end - - MRSCont.processed.A{kk} = raw; - - - %%% 8. GET SHORT-TE WATER DATA %%% - if MRSCont.flags.hasWater - raw_w = MRSCont.raw_w{kk}; % Get the kk-th dataset - if raw_w.averages > 1 && raw_w.flags.averaged == 0 - [raw_w,~,~] = op_alignAverages(raw_w, 1, 'n'); - raw_w = op_averaging(raw_w); % Average - else - raw_w.flags.averaged = 1; - raw_w.dims.averages = 0; - end - if ~MRSCont.flags.isMRSI - [raw_w,~] = op_eccKlose(raw_w, raw_w); % Klose eddy current correction - else - [raw_w,~]=op_autophase(raw_w,2,2*4.68); - end - [raw_w,~] = op_ppmref(raw_w,4.6,4.8,4.68); % Reference to water @ 4.68 ppm - - % Apply some linebroadening, if phantom data - if MRSCont.flags.isPhantom - raw_w = op_filter(raw_w, 2); - end - - MRSCont.processed.w{kk} = raw_w; % Save back to MRSCont container - end - - - %%% 9. QUALITY CONTROL PARAMETERS %%% - SubSpec = {'A'}; - SNRRange = {[1.8,2.2]}; - if MRSCont.flags.hasMM - SubSpec{end+1} = 'mm'; - SNRRange{end+1} = [0.7,1.1]; - end - if MRSCont.flags.hasRef - SubSpec{end+1} = 'ref'; - SNRRange{end+1} = [4.2,5.2]; - end - if MRSCont.flags.hasWater - SubSpec{end+1} = 'w'; - SNRRange{end+1} = [4.2,5.2]; - end - % Calculate some spectral quality metrics here; - for ss = 1 : length(SubSpec) - MRSCont.QM.SNR.(SubSpec{ss})(kk) = op_getSNR(MRSCont.processed.(SubSpec{ss}){kk}); - MRSCont.QM.FWHM.(SubSpec{ss})(kk) = op_getLW(MRSCont.processed.(SubSpec{ss}){kk},SNRRange{ss}(1),SNRRange{ss}(2)); % in Hz - if ~(strcmp(SubSpec{ss},'ref') || strcmp(SubSpec{ss},'w') || strcmp(SubSpec{ss},'mm')) - MRSCont.QM.drift.pre.(SubSpec{ss}){kk} = driftPre; - MRSCont.QM.drift.post.(SubSpec{ss}){kk} = driftPost; - MRSCont.QM.freqShift.(SubSpec{ss})(kk) = refShift; - MRSCont.QM.res_water_amp.(SubSpec{ss})(kk) = sum(MRSCont.processed.(SubSpec{ss}){kk}.watersupp.amp); - if strcmp(SubSpec{ss},'diff1') || strcmp(SubSpec{ss},'sum') - MRSCont.QM.drift.pre.(SubSpec{ss}){kk} = reshape([MRSCont.QM.drift.pre.A'; MRSCont.QM.drift.pre.B'], [], 1)'; - MRSCont.QM.drift.post.(SubSpec{ss}){kk} = reshape([MRSCont.QM.drift.post.A'; MRSCont.QM.drift.post.B'], [], 1)'; - end - MRSCont.QM.drift.pre.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - MRSCont.QM.drift.post.AvgDeltaCr.(SubSpec{ss})(kk) = mean(MRSCont.QM.drift.pre.(SubSpec{ss}){kk} - 3.02); - end - end - end -end -time = toc(refProcessTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - -%%% 10. SET FLAGS %%% -MRSCont.flags.avgsAligned = 1; -MRSCont.flags.averaged = 1; -MRSCont.flags.ECCed = 1; -MRSCont.flags.waterRemoved = 1; -MRSCont.runtime.Proc = time; -% Close any remaining open figures -close all; - -end diff --git a/process/osp_saveJMRUI.m b/process/osp_saveJMRUI.m index 4a308630..434cca94 100644 --- a/process/osp_saveJMRUI.m +++ b/process/osp_saveJMRUI.m @@ -50,7 +50,7 @@ % Write jMRUI .TXT files depending on sequence type % Get TE and the input file name - te = MRSCont.processed.A{kk}.te; + te = MRSCont.processed.metab{kk}.te; [path,filename,~] = fileparts(MRSCont.files{kk}); % For batch analysis, get the last two sub-folders (e.g. site and % subject) @@ -60,31 +60,31 @@ end if MRSCont.flags.isUnEdited outfile = fullfile(saveDestination, [name '_jMRUI_A.TXT']); - RF = io_writejmrui(MRSCont.processed.A{kk},outfile); + RF = io_writejmrui(MRSCont.processed.metab{kk},outfile); elseif MRSCont.flags.isMEGA outfileA = fullfile(saveDestination, [name '_jMRUI_A.TXT']); - RF = io_writejmrui(MRSCont.processed.A{kk},outfileA); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA); outfileB = fullfile(saveDestination, [name '_jMRUI_B.TXT']); - RF = io_writejmrui(MRSCont.processed.B{kk},outfileB); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB); outfileDiff1 = fullfile(saveDestination, [name '_jMRUI_DIFF1.TXT']); - RF = io_writejmrui(MRSCont.processed.diff1{kk},outfileDiff1); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},3),outfileDiff1); outfileSum = fullfile(saveDestination, [name '_jMRUI_SUM.TXT']); - RF = io_writejmrui(MRSCont.processed.sum{kk},outfileSum); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},4),outfileSum); elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES outfileA = fullfile(saveDestination, [name '_jMRUI_A.TXT']); - RF = io_writejmrui(MRSCont.processed.A{kk},outfileA); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA); outfileB = fullfile(saveDestination, [name '_jMRUI_B.TXT']); - RF = io_writejmrui(MRSCont.processed.B{kk},outfileB); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB); outfileC = fullfile(saveDestination, [name '_jMRUI_C.TXT']); - RF = io_writejmrui(MRSCont.processed.C{kk},outfileC); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},3),outfileC); outfileD = fullfile(saveDestination, [name '_jMRUI_D.TXT']); - RF = io_writejmrui(MRSCont.processed.D{kk},outfileD); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},4),outfileD); outfileDiff1 = fullfile(saveDestination, [name '_jMRUI_DIFF1.TXT']); - RF = io_writejmrui(MRSCont.processed.diff1{kk},outfileDiff1); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},5),outfileDiff1); outfileDiff2 = fullfile(saveDestination, [name '_jMRUI_DIFF2.TXT']); - RF = io_writejmrui(MRSCont.processed.diff2{kk},outfileDiff2); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},6),outfileDiff2); outfileSum = fullfile(saveDestination, [name '_jMRUI_SUM.TXT']); - RF = io_writejmrui(MRSCont.processed.sum{kk},outfileSum); + RF = io_writejmrui(op_takesubspec(MRSCont.processed.metab{kk},7),outfileSum); else error('No flag set for sequence type!'); end diff --git a/process/osp_saveLCM.m b/process/osp_saveLCM.m index 89a804fc..92c2f69c 100644 --- a/process/osp_saveLCM.m +++ b/process/osp_saveLCM.m @@ -52,7 +52,7 @@ % Write LCModel .RAW files depending on sequence type % Get TE and the input file name - te = MRSCont.processed.A{kk}.te; + te = MRSCont.processed.metab{kk}.te; [path,filename,~] = fileparts(MRSCont.files{kk}); % For batch analysis, get the last two sub-folders (e.g. site and @@ -65,19 +65,19 @@ % Set up complete output filename strings, then write LCM .RAW files. if MRSCont.flags.isUnEdited outfile = fullfile(saveDestination,'metabs', [name '_LCM_A.RAW']); - RF = io_writelcm(MRSCont.processed.A{kk},outfile,te); + RF = io_writelcm(MRSCont.processed.metab{kk},outfile,te); MRSCont.opts.fit.lcmodel.outfileA{kk} = outfile; elseif MRSCont.flags.isMEGA - outfileA = fullfile(saveDestination,'metabs', [name '_LCM_A.RAW']); - RF = io_writelcm(MRSCont.processed.A{kk},outfileA,te); + outfileA = fullfile(saveDestination,'metabs', [name '_LCM_A.RAW']); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA,te); outfileB = fullfile(saveDestination,'metabs', [name '_LCM_B.RAW']); - RF = io_writelcm(MRSCont.processed.B{kk},outfileB,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB,te); outfileDiff1 = fullfile(saveDestination,'metabs', [name '_LCM_DIFF1.RAW']); - RF = io_writelcm(MRSCont.processed.diff1{kk},outfileDiff1,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},3),outfileDiff1,te); outfileSum = fullfile(saveDestination,'metabs', [name '_LCM_SUM.RAW']); - RF = io_writelcm(MRSCont.processed.sum{kk},outfileSum,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},4),outfileSum,te); MRSCont.opts.fit.lcmodel.outfileA{kk} = outfileA; MRSCont.opts.fit.lcmodel.outfileB{kk} = outfileB; @@ -86,19 +86,19 @@ elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES outfileA = fullfile(saveDestination,'metabs', [name '_LCM_A.RAW']); - RF = io_writelcm(MRSCont.processed.A{kk},outfileA,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA,te); outfileB = fullfile(saveDestination,'metabs', [name '_LCM_B.RAW']); - RF = io_writelcm(MRSCont.processed.B{kk},outfileB,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB,te); outfileC = fullfile(saveDestination,'metabs', [name '_LCM_C.RAW']); - RF = io_writelcm(MRSCont.processed.C{kk},outfileC,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},3),outfileC,te); outfileD = fullfile(saveDestination,'metabs', [name '_LCM_D.RAW']); - RF = io_writelcm(MRSCont.processed.D{kk},outfileD,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},4),outfileD,te); outfileDiff1 = fullfile(saveDestination,'metabs', [name '_LCM_DIFF1.RAW']); - RF = io_writelcm(MRSCont.processed.diff1{kk},outfileDiff1,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},5),outfileDiff1,te); outfileDiff2 = fullfile(saveDestination,'metabs', [name '_LCM_DIFF2.RAW']); - RF = io_writelcm(MRSCont.processed.diff2{kk},outfileDiff2,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},6),outfileDiff2,te); outfileSum = fullfile(saveDestination,'metabs', [name '_LCM_SUM.RAW']); - RF = io_writelcm(MRSCont.processed.sum{kk},outfileSum,te); + RF = io_writelcm(op_takesubspec(MRSCont.processed.metab{kk},7),outfileSum,te); MRSCont.opts.fit.lcmodel.outfileA{kk} = outfileA; MRSCont.opts.fit.lcmodel.outfileB{kk} = outfileB; @@ -118,7 +118,7 @@ % Get TE and the input file name. For GE, the water reference is % already contained in the P file. if strcmpi(MRSCont.vendor, 'GE') || strcmp(MRSCont.datatype,'DATA') - te_ref = MRSCont.processed.A{kk}.te; + te_ref = MRSCont.processed.metab{kk}.te; [path_ref,filename_ref,~] = fileparts(MRSCont.files{kk}); else te_ref = MRSCont.processed.ref{kk}.te; diff --git a/process/osp_saveNII.m b/process/osp_saveNII.m index d7018875..71086139 100644 --- a/process/osp_saveNII.m +++ b/process/osp_saveNII.m @@ -68,31 +68,31 @@ if MRSCont.flags.isUnEdited outfile = fullfile(saveDestination, [name '_A.nii.gz']); - RF = outputFunction(MRSCont.processed.A{kk},outfile); + RF = outputFunction(MRSCont.processed.metab{kk},outfile); elseif MRSCont.flags.isMEGA outfileA = fullfile(saveDestination, [name '_A.nii.gz']); - RF = outputFunction(MRSCont.processed.A{kk},outfileA); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA); outfileB = fullfile(saveDestination, [name '_B.nii.gz']); - RF = outputFunction(MRSCont.processed.B{kk},outfileB); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB); outfileDiff1 = fullfile(saveDestination, [name '_DIFF1.nii.gz']); - RF = outputFunction(MRSCont.processed.diff1{kk},outfileDiff1); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},3),outfileDiff1); outfileSum = fullfile(saveDestination, [name '_SUM.nii.gz']); - RF = outputFunction(MRSCont.processed.sum{kk},outfileSum); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},4),outfileSum); elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES outfileA = fullfile(saveDestination, [name '_A.nii.gz']); - RF = outputFunction(MRSCont.processed.A{kk},outfileA); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA); outfileB = fullfile(saveDestination, [name '_B.nii.gz']); - RF = outputFunction(MRSCont.processed.B{kk},outfileB); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB); outfileC = fullfile(saveDestination, [name '_C.nii.gz']); - RF = outputFunction(MRSCont.processed.C{kk},outfileC); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},3),outfileC); outfileD = fullfile(saveDestination, [name '_D.nii.gz']); - RF = outputFunction(MRSCont.processed.D{kk},outfileD); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},4),outfileD); outfileDiff1 = fullfile(saveDestination, [name '_DIFF1.nii.gz']); - RF = outputFunction(MRSCont.processed.diff1{kk},outfileDiff1); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},5),outfileDiff1); outfileDiff2 = fullfile(saveDestination, [name '_DIFF2.nii.gz']); - RF = outputFunction(MRSCont.processed.diff2{kk},outfileDiff2); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},6),outfileDiff2); outfileSum = fullfile(saveDestination, [name '_SUM.nii.gz']); - RF = outputFunction(MRSCont.processed.sum{kk},outfileSum); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},7),outfileSum); else error('No flag set for sequence type!'); end diff --git a/process/osp_saveVendor.m b/process/osp_saveVendor.m index fddde427..a6e4be60 100644 --- a/process/osp_saveVendor.m +++ b/process/osp_saveVendor.m @@ -86,31 +86,31 @@ if MRSCont.flags.isUnEdited outfile = fullfile(saveDestination, [name '_A']); - RF = outputFunction(MRSCont.processed.A{kk},outfile); + RF = outputFunction(MRSCont.processed.metab{kk},outfile); elseif MRSCont.flags.isMEGA outfileA = fullfile(saveDestination, [name '_A']); - RF = outputFunction(MRSCont.processed.A{kk},outfileA); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA); outfileB = fullfile(saveDestination, [name '_B']); - RF = outputFunction(MRSCont.processed.B{kk},outfileB); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB); outfileDiff1 = fullfile(saveDestination, [name '_DIFF1']); - RF = outputFunction(MRSCont.processed.diff1{kk},outfileDiff1); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},3),outfileDiff1); outfileSum = fullfile(saveDestination, [name '_SUM']); - RF = outputFunction(MRSCont.processed.sum{kk},outfileSum); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},4),outfileSum); elseif MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES outfileA = fullfile(saveDestination, [name '_A']); - RF = outputFunction(MRSCont.processed.A{kk},outfileA); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},1),outfileA); outfileB = fullfile(saveDestination, [name '_B']); - RF = outputFunction(MRSCont.processed.B{kk},outfileB); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},2),outfileB); outfileC = fullfile(saveDestination, [name '_C']); - RF = outputFunction(MRSCont.processed.C{kk},outfileC); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},3),outfileC); outfileD = fullfile(saveDestination, [name '_D']); - RF = outputFunction(MRSCont.processed.D{kk},outfileD); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},4),outfileD); outfileDiff1 = fullfile(saveDestination, [name '_DIFF1']); - RF = outputFunction(MRSCont.processed.diff1{kk},outfileDiff1); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},5),outfileDiff1); outfileDiff2 = fullfile(saveDestination, [name '_DIFF2']); - RF = outputFunction(MRSCont.processed.diff2{kk},outfileDiff2); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},6),outfileDiff2); outfileSum = fullfile(saveDestination, [name '_SUM']); - RF = outputFunction(MRSCont.processed.sum{kk},outfileSum); + RF = outputFunction(op_takesubspec(MRSCont.processed.metab{kk},7),outfileSum); else error('No flag set for sequence type!'); end diff --git a/quantify/OspreyQuantify.m b/quantify/OspreyQuantify.m index be61d1f1..156a2982 100644 --- a/quantify/OspreyQuantify.m +++ b/quantify/OspreyQuantify.m @@ -48,27 +48,9 @@ qtfyCr = 1; % Check which types of metabolite data are available -if MRSCont.flags.isUnEdited - getResults = {'off'}; -elseif MRSCont.flags.isMEGA - if strcmpi(MRSCont.opts.fit.style, 'Separate') - getResults = {'diff1', 'off'}; - elseif strcmpi(MRSCont.opts.fit.style, 'Concatenated') - getResults = {'conc'}; - end -elseif MRSCont.flags.isHERMES - if strcmpi(MRSCont.opts.fit.style, 'Separate') - getResults = {'diff1', 'diff2', 'sum'}; - elseif strcmpi(MRSCont.opts.fit.style, 'Concatenated') - getResults = {'conc'}; - end -elseif MRSCont.flags.isHERCULES - if strcmpi(MRSCont.opts.fit.style, 'Separate') - getResults = {'diff1', 'diff2', 'sum'}; - elseif strcmpi(MRSCont.opts.fit.style, 'Concatenated') - getResults = {'conc'}; - end -end +SubSpectraFitted =size(MRSCont.fit.results.metab.fitParams,3); +BasisSetsFitted =size(MRSCont.fit.results.metab.fitParams,1); + % Check which types of water data are available if [MRSCont.flags.hasRef MRSCont.flags.hasWater] == [1 1] @@ -92,7 +74,7 @@ % Get the fieldstrength for proper relaxation correction if qtfyH2O - Bo = MRSCont.raw{1}.Bo; + Bo = MRSCont.raw{1}.Bo; if (Bo >= 2.8 && Bo < 3.1) Bo = '3T'; else @@ -102,7 +84,7 @@ % Check whether segmentation has been run, and whether tissue parameters % exist. In that case, we can do CSF correction, and full tissue % correction. -if qtfyH2O == 1 && MRSCont.flags.didSeg && isfield(MRSCont.seg, 'tissue') +if qtfyH2O == 1 && MRSCont.flags.didSeg && isfield(MRSCont.seg, 'tissue') qtfyCSF = 1; qtfyTiss = 1; else @@ -115,7 +97,7 @@ % (Harris et al, J Magn Reson Imaging 42:1431-40 (2015)). if qtfyTiss == 1 && MRSCont.flags.isMEGA && (strcmp(MRSCont.opts.editTarget{1},'GABA')) qtfyAlpha = 1; -else if qtfyTiss == 1 && (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) && (strcmp(MRSCont.opts.editTarget{1},'GABA') || strcmp(MRSCont.opts.editTarget{2},'GABA')) +else if qtfyTiss == 1 && (MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES) && (strcmp(MRSCont.opts.editTarget{1},'GABA') || strcmp(MRSCont.opts.editTarget{2},'GABA')) qtfyAlpha = 1; else qtfyAlpha = 0; @@ -132,54 +114,55 @@ % Add combinations of metabolites to the basisset - -for ll = 1:length(getResults) +for ss = 1 : SubSpectraFitted if ~strcmp(MRSCont.opts.fit.method, 'LCModel') - if ~iscell(MRSCont.fit.results) %Is SVS - MRSCont.quantify.metabs.(getResults{ll}) = MRSCont.fit.resBasisSet.(getResults{ll}).(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name; - else %Is DualVoxel - if MRSCont.flags.isPRIAM - MRSCont.quantify.metabs.(getResults{ll}) = MRSCont.fit.resBasisSet.(getResults{ll}).(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name; - else - MRSCont.quantify.metabs.(getResults{ll}) = MRSCont.fit.resBasisSet{1,1}.(getResults{ll}).(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name; + for mm = 1 : BasisSetsFitted + if ~isempty(MRSCont.fit.resBasisSet.metab.(MRSCont.info.metab.unique_ndatapoint_spectralwidth{1}){mm,1,ss}) + if ~iscell(MRSCont.fit.results) %Is SVS + MRSCont.quantify.names.metab{mm,ss} = MRSCont.fit.resBasisSet.metab.(MRSCont.info.metab.unique_ndatapoint_spectralwidth{1}){mm,1,ss}.name; + MRSCont.quantify.names.SubSpectra{mm,ss} = MRSCont.fit.resBasisSet.metab.(MRSCont.info.metab.unique_ndatapoint_spectralwidth{1}){mm,1,ss}.names{1}; + else %Is DualVoxel + MRSCont.quantify.names.metab{mm,ss} = MRSCont.fit.resBasisSet{1,1}.metab.(MRSCont.info.metab.unique_ndatapoint_spectralwidth{1}){mm,1,ss}.name; + MRSCont.quantify.names.SubSpectra{mm,ss} = MRSCont.fit.resBasisSet{1,1}.metab.(MRSCont.info.metab.unique_ndatapoint_spectralwidth{1}){mm,1,ss}.names{1}; + end end end else - MRSCont.quantify.metabs.(getResults{ll}) = MRSCont.fit.results.off.fitParams{1, 1}.name; + MRSCont.quantify.names.metab{1,1} = MRSCont.fit.results.metab.fitParams{1, 1}.name; + MRSCont.quantify.names.SubSpectra{1,1} = MRSCont.processed.metab{1, 1}.names{1}; end - end -for kk = 1:MRSCont.nDatasets - for ll = 1:length(getResults) - if ~iscell(MRSCont.fit.results) %Is SVS %Is SVS - MRSCont.quantify.amplMets{kk}.(getResults{ll}) = MRSCont.fit.results.(getResults{ll}).fitParams{kk}.ampl; - else %Is DualVoxel - MRSCont.quantify.amplMets{kk}.(getResults{ll})(:,1) = MRSCont.fit.results{1}.(getResults{ll}).fitParams{kk}.ampl; - MRSCont.quantify.amplMets{kk}.(getResults{ll})(:,2) = MRSCont.fit.results{2}.(getResults{ll}).fitParams{kk}.ampl; +for ss = 1 : SubSpectraFitted + for kk = 1:MRSCont.nDatasets(1) + for mm = 1 : BasisSetsFitted + if ~isempty(MRSCont.quantify.names.metab{mm,ss}) + if ~iscell(MRSCont.fit.results) %Is SVS %Is SVS + MRSCont.quantify.amplMets{mm,kk,ss}.metab = MRSCont.fit.results.metab.fitParams{mm,kk,ss}.ampl; + else %Is DualVoxel + MRSCont.quantify.amplMets{mm,kk,ss}.metab(:,1) = MRSCont.fit.results{1}.metab.fitParams{mm,kk,ss}.ampl; + MRSCont.quantify.amplMets{mm,kk,ss}.metab(:,2) = MRSCont.fit.results{2}.metab.fitParams{mm,kk,ss}.ampl; + end + end end end end if strcmp(MRSCont.opts.fit.method, 'LCModel') - for kk = 1:MRSCont.nDatasets + for kk = 1:MRSCont.nDatasets(1) if ~iscell(MRSCont.fit.results) %Is SVS %Is SVS - MRSCont.quantify.CRLB{kk}.(getResults{ll}) = MRSCont.fit.results.(getResults{ll}).fitParams{kk}.CRLB'; - if qtfyH2O - MRSCont.quantify.h2oarea{kk}.(getResults{ll}) = MRSCont.fit.results.(getResults{ll}).fitParams{kk}.h2oarea; - end + MRSCont.quantify.CRLB{kk}.metab = MRSCont.fit.results.metab.fitParams{kk}.CRLB'; + MRSCont.quantify.h2oarea{kk}.metab = MRSCont.fit.results.metab.fitParams{kk}.h2oarea; else %Is DualVoxel - MRSCont.quantify.CRLB{kk}.(getResults{ll})(:,1) = MRSCont.fit.results{1}.(getResults{ll}).fitParams{kk}.CRLB'; - MRSCont.quantify.CRLB{kk}.(getResults{ll})(:,2) = MRSCont.fit.results{2}.(getResults{ll}).fitParams{kk}.CRLB'; - if qtfyH2O - MRSCont.quantify.h2oarea{kk}.(getResults{ll})(:,1) = MRSCont.fit.results{1}.(getResults{ll}).fitParams{kk}.h2oarea; - MRSCont.quantify.h2oarea{kk}.(getResults{ll})(:,2) = MRSCont.fit.results{2}.(getResults{ll}).fitParams{kk}.h2oarea; - end - end + MRSCont.quantify.CRLB{kk}.metab(:,1) = MRSCont.fit.results{1}.metab.fitParams{kk}.CRLB'; + MRSCont.quantify.CRLB{kk}.metab(:,2) = MRSCont.fit.results{2}.metab.fitParams{kk}.CRLB'; + MRSCont.quantify.h2oarea{kk}.metab(:,1) = MRSCont.fit.results{1}.metab.fitParams{kk}.h2oarea; + MRSCont.quantify.h2oarea{kk}.metab(:,2) = MRSCont.fit.results{2}.metab.fitParams{kk}.h2oarea; + end end end -MRSCont = addMetabComb(MRSCont, getResults); +MRSCont = addMetabComb(MRSCont); %% Loop over all datasets @@ -193,17 +176,12 @@ if MRSCont.flags.isGUI && isfield(MRSCont.flags,'inProgress') progressText = MRSCont.flags.inProgress; end -for kk = 1:MRSCont.nDatasets - if ~isfield(MRSCont.flags,'exclude') - [~] = printLog('OspreyQuant',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - else if ~MRSCont.flags.exclude - [~] = printLog('OspreyQuant',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); - end - end +for kk = 1:MRSCont.nDatasets(1) + [~] = printLog('OspreyQuant',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); %%% 1. GET BASIS SET AND FIT AMPLITUDES %%% - metsName = MRSCont.quantify.metabs; % just for the names - amplMets = MRSCont.quantify.amplMets{kk}; + metsName = MRSCont.quantify.names; % just for the names + amplMets = MRSCont.quantify.amplMets(:,kk,:); %%% 2. GET CREATINE RATIOS %%% @@ -211,11 +189,15 @@ if qtfyCr % Extract metabolite amplitudes from fit - tCrRatios = quantCr(metsName, amplMets, getResults); + tCrRatios = quantCr(metsName, amplMets); % Save back to Osprey data container - for ll = 1:length(getResults) - MRSCont.quantify.(getResults{ll}).tCr{kk} = tCrRatios.(getResults{ll}); + for ss = 1 :SubSpectraFitted + for mm = 1 :BasisSetsFitted + if ~isempty( tCrRatios{mm,ss}) + MRSCont.quantify.metab.tCr{mm,kk,ss} = tCrRatios{mm,ss}.metab; + end + end end end @@ -231,21 +213,21 @@ amplWater(:,2) = MRSCont.fit.results{2}.(waterType).fitParams{kk}.ampl; end else - % Get WCONC, ATTMET, and ATTH2O from control file + % Get WCONC, ATTMET, and ATTH2O from control file LCMparam = osp_readlcm_control(MRSCont.opts.fit.lcmodel.controlfileA{kk}); - if isfield(LCMparam, 'WCONC') % User-supplied WCONC + if isfield(LCMparam, 'WCONC') % User-supplied WCONC amplWater = str2double(LCMparam.WCONC); else amplWater = 35880; %LCModel default WCONC assumes pure WM end - - if isfield(LCMparam, 'ATTMET') % User-supplied ATTMET + + if isfield(LCMparam, 'ATTMET') % User-supplied ATTMET amplWater = amplWater * str2double(LCMparam.ATTMET); else %Do nothing as LCModel default ATTMET is 1 end - - if isfield(LCMparam, 'ATTH2O') % User-supplied ATTH2O + + if isfield(LCMparam, 'ATTH2O') % User-supplied ATTH2O amplWater = amplWater / str2double(LCMparam.ATTH2O); else amplWater = amplWater / 0.7; %LCModel default ATTH2O is 0.7 @@ -253,17 +235,21 @@ end % Get repetition times - metsTR = MRSCont.processed.A{kk}.tr * 1e-3; + metsTR = MRSCont.processed.metab{kk}.tr * 1e-3; waterTR = MRSCont.processed.(waterType){kk}.tr * 1e-3; % Get echo times - metsTE = MRSCont.processed.A{kk}.te * 1e-3; + metsTE = MRSCont.processed.metab{kk}.te * 1e-3; waterTE = MRSCont.processed.(waterType){kk}.te * 1e-3; % Calculate water-scaled, but not tissue-corrected metabolite levels - rawWaterScaled = quantH2O(metsName, amplMets, amplWater, getResults, metsTR, waterTR, metsTE, waterTE,Bo); + rawWaterScaled = quantH2O(metsName, amplMets, amplWater, metsTR, waterTR, metsTE, waterTE,Bo); % Save back to Osprey data container - for ll = 1:length(getResults) - MRSCont.quantify.(getResults{ll}).rawWaterScaled{kk} = rawWaterScaled.(getResults{ll}); + for ss = 1 :SubSpectraFitted + for mm = 1 :BasisSetsFitted + if ~isempty( rawWaterScaled{mm,ss}) + MRSCont.quantify.metab.rawWaterScaled{mm,kk,ss} = rawWaterScaled{mm,ss}.metab; + end + end end end @@ -274,11 +260,15 @@ % Apply CSF correction fCSF = MRSCont.seg.tissue.fCSF(kk,:); - CSFWaterScaled = quantCSF(rawWaterScaled, fCSF, getResults); + CSFWaterScaled = quantCSF(rawWaterScaled, fCSF,SubSpectraFitted); % Save back to Osprey data container - for ll = 1:length(getResults) - MRSCont.quantify.(getResults{ll}).CSFWaterScaled{kk} = CSFWaterScaled.(getResults{ll}); + for ss = 1 :SubSpectraFitted + for mm = 1 :BasisSetsFitted + if ~isempty( CSFWaterScaled{mm,ss}) + MRSCont.quantify.metab.CSFWaterScaled{mm,kk,ss} = CSFWaterScaled{mm,ss}.metab; + end + end end end @@ -289,11 +279,15 @@ % Apply tissue correction fGM = MRSCont.seg.tissue.fGM(kk,:); fWM = MRSCont.seg.tissue.fWM(kk,:); - TissCorrWaterScaled = quantTiss(metsName, amplMets, amplWater, getResults, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF,Bo); + TissCorrWaterScaled = quantTiss(metsName, amplMets, amplWater, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF,Bo); % Save back to Osprey data container - for ll = 1:length(getResults) - MRSCont.quantify.(getResults{ll}).TissCorrWaterScaled{kk} = TissCorrWaterScaled.(getResults{ll}); + for ss = 1 :SubSpectraFitted + for mm = 1 :BasisSetsFitted + if ~isempty( TissCorrWaterScaled{mm,ss}) + MRSCont.quantify.metab.TissCorrWaterScaled{mm,kk,ss} = TissCorrWaterScaled{mm,ss}.metab; + end + end end end @@ -306,7 +300,7 @@ % form of prior knowledge about their concentrations in GM and WM. fGM = MRSCont.seg.tissue.fGM; fWM = MRSCont.seg.tissue.fWM; - + % We don't want to remove excluded subjects from the alpah % correction. % if isfield(MRSCont,'exclude') @@ -314,46 +308,46 @@ % fWM(MRSCont.exclude) = nan; % end % Calculate mean WM/GM fractions - meanfGM = nanmean(fGM,1); % average GM fraction across datasets - meanfWM = nanmean(fWM,1); % average WM fraction across datasets - [AlphaCorrWaterScaled, AlphaCorrWaterScaledGroupNormed] = quantAlpha(metsName,amplMets, amplWater,getResults, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF, meanfGM, meanfWM,MRSCont.opts.fit.coMM3,Bo); + meanfGM = mean(MRSCont.seg.tissue.fGM,1); % average GM fraction across datasets + meanfWM = mean(MRSCont.seg.tissue.fWM,1); % average WM fraction across datasets + [AlphaCorrWaterScaled, AlphaCorrWaterScaledGroupNormed] = quantAlpha(metsName,amplMets, amplWater, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF, meanfGM, meanfWM,MRSCont.opts.fit.coMM3,Bo); % Save back to Osprey data container - MRSCont.quantify.(getResults{1}).AlphaCorrWaterScaled{kk} = AlphaCorrWaterScaled(kk,:)'; - MRSCont.quantify.(getResults{1}).AlphaCorrWaterScaledGroupNormed{kk} = AlphaCorrWaterScaledGroupNormed(kk,:)'; + for ss = 1 :SubSpectraFitted + for mm = 1 :BasisSetsFitted + MRSCont.quantify.metab.AlphaCorrWaterScaled{mm,kk,ss} = AlphaCorrWaterScaled{mm,ss}; + MRSCont.quantify.metab.AlphaCorrWaterScaledGroupNormed{mm,kk,ss} = AlphaCorrWaterScaledGroupNormed{mm,ss}; + end + end end end time = toc(QuantifyTime); -if MRSCont.flags.isGUI && isfield(progressText,'String') - set(progressText,'String' ,sprintf('... done.\n Elapsed time %f seconds',time)); - pause(1); -end -fprintf('... done.\n Elapsed time %f seconds\n',time); +[~] = printLog('done',time,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.Quantify = time; %% Create tables % Set up readable tables for each quantification. -[MRSCont] = osp_createTable(MRSCont,'amplMets', getResults); +[MRSCont] = osp_createTable(MRSCont,'amplMets'); if qtfyCr - [MRSCont] = osp_createTable(MRSCont,'tCr', getResults); + [MRSCont] = osp_createTable(MRSCont,'tCr'); end if qtfyH2O - [MRSCont] = osp_createTable(MRSCont,'rawWaterScaled', getResults); + [MRSCont] = osp_createTable(MRSCont,'rawWaterScaled'); end if qtfyCSF - [MRSCont] = osp_createTable(MRSCont,'CSFWaterScaled', getResults); + [MRSCont] = osp_createTable(MRSCont,'CSFWaterScaled'); end if qtfyTiss - [MRSCont] = osp_createTable(MRSCont,'TissCorrWaterScaled', getResults); + [MRSCont] = osp_createTable(MRSCont,'TissCorrWaterScaled'); end if qtfyAlpha - [MRSCont] = osp_createTable(MRSCont,'AlphaCorrWaterScaled', getResults(1)); - [MRSCont] = osp_createTable(MRSCont,'AlphaCorrWaterScaledGroupNormed', getResults(1)); + [MRSCont] = osp_createTable(MRSCont,'AlphaCorrWaterScaled'); + [MRSCont] = osp_createTable(MRSCont,'AlphaCorrWaterScaledGroupNormed'); end %Generate tables from LCModel specific outputs if strcmp(MRSCont.opts.fit.method, 'LCModel') - [MRSCont] = osp_createTable(MRSCont,'CRLB', getResults); + [MRSCont] = osp_createTable(MRSCont,'CRLB'); if qtfyH2O - [MRSCont] = osp_createTable(MRSCont,'h2oarea', getResults); + [MRSCont] = osp_createTable(MRSCont,'h2oarea'); end end %% Clean up and save @@ -361,11 +355,9 @@ MRSCont.flags.didQuantify = 1; diary off % Save the metabolite tables as TSV with JSON sidecars -exportQuant(MRSCont,saveDestination, getResults); +exportQuant(MRSCont,saveDestination); % Remove amplitudes table -for ll = 1:length(getResults) - MRSCont.quantify.tables.(getResults{ll}) = rmfield(MRSCont.quantify.tables.(getResults{ll}),{'amplMets'}); -end +MRSCont.quantify.tables.metab = rmfield(MRSCont.quantify.tables.metab,{'amplMets'}); % Save the output structure to the output folder % Determine output folder outputFolder = MRSCont.outputFolder; @@ -387,139 +379,170 @@ %% %%% Add combinations of metabolites %%% -function MRSCont = addMetabComb(MRSCont, getResults) +function MRSCont = addMetabComb(MRSCont) if ~strcmp(MRSCont.opts.fit.method, 'LCModel') %% Loop over all datasets - for kk = 1:MRSCont.nDatasets + for kk = 1:MRSCont.nDatasets(1) % tNAA NAA+NAAG - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'NAA')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'NAAG')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tNAA')); - if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'tNAA'; + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'NAA')); + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'NAAG')); + if ~isempty(idx_1) && ~isempty(idx_2) + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tNAA')); + if isempty(idx_3) + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'tNAA'; + end + idx_tNAA = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tNAA')); + tNAA = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_tNAA,:) = tNAA; end - idx_tNAA = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tNAA')); - tNAA = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_tNAA,:) = tNAA; - end end % Glx Glu+Gln - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'Glu')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'Gln')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'Glx')); - if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'Glx'; + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'Glu')); + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'Gln')); + if ~isempty(idx_1) && ~isempty(idx_2) + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'Glx')); + if isempty(idx_3) + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'Glx'; + end + idx_Glx = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'Glx')); + Glx = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_Glx,:) = Glx; end - idx_Glx = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'Glx')); - Glx = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_Glx,:) = Glx; end end % tCho GPC+PCh - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GPC')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'PCh')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tCho')); - if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'tCho'; + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GPC')); + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'PCh')); + if ~isempty(idx_1) && ~isempty(idx_2) + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tCho')); + if isempty(idx_3) + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'tCho'; + end + idx_tCho = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tCho')); + tCho = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_tCho,:) = tCho; end - idx_tCho = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tCho')); - tCho = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_tCho,:) = tCho; end end % tCr Cr+PCr - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'Cr')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'PCr')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tCr')); - if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'tCr'; + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'Cr')); + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'PCr')); + if ~isempty(idx_1) && ~isempty(idx_2) + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tCr')); + if isempty(idx_3) + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'tCr'; + end + idx_tCr = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tCr')); + tCr = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_tCr,:) = tCr; end - idx_tCr = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tCr')); - tCr = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_tCr,:) = tCr; end end % tCr Cr+PCr - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'Cr')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'PCr')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tCr')); - if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'tCr'; + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'Cr')); + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'PCr')); + if ~isempty(idx_1) && ~isempty(idx_2) + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tCr')); + if isempty(idx_3) + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'tCr'; + end + idx_tCr = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tCr')); + tCr = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_tCr,:) = tCr; end - idx_tCr = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tCr')); - tCr = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_tCr,:) = tCr; end end %PE+EA - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'PE')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'EA')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tEA')); - if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'tEA'; + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'PE')); + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'EA')); + if ~isempty(idx_1) && ~isempty(idx_2) + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tEA')); + if isempty(idx_3) + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'tEA'; + end + idx_tEA = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'tEA')); + tEA = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_tEA,:) = tEA; end - idx_tEA = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'tEA')); - tEA = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_tEA,:) = tEA; end end + + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) %GABA+coMM3 if strcmp(MRSCont.opts.fit.coMM3, '1to1GABA') % fixed GABA coMM3 model - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABA')); - if ~isempty(idx_1) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABAplus')); + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABA')); + if mm == 1 + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'MM3co')); + else + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'MMExp')); + end + if ~isempty(idx_1) && ss == 2 + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABAplus')); if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'GABAplus'; + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'GABAplus'; + end + idx_GABAp = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABAplus')); + if isempty(idx_2) + GABAp = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:); + else + GABAp = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); end - idx_GABAp = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABAplus')); - GABAp = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_GABAp,:) = GABAp; + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_GABAp,:) = GABAp; end - end + end else if strcmp(MRSCont.opts.fit.coMM3, '3to2MM') % fixed MM09 coMM3 model - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABA')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'MM09')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABAplus')); + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABA')); + if mm == 1 + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'MM09')); + else + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'MMExp')); + end + if (~isempty(idx_1) && ~isempty(idx_2)) && ss ==2 + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABAplus')); if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'GABAplus'; + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'GABAplus'; end - idx_GABAp = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABAplus')); - GABAp = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_GABAp,:) = GABAp; + idx_GABAp = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABAplus')); + GABAp = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_GABAp,:) = GABAp; + end + end + else % Models with a separate comMM3 function or without a co-edited MM function + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + idx_1 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABA')); + if mm == 1 + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'MM3co')); + else + idx_2 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'MMExp')); end - end - else % Models with a separate comMM3 function or without a co-edited MM function - for ll = 1:length(getResults) - idx_1 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABA')); - idx_2 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'MM3co')); - if ~isempty(idx_1) && ~isempty(idx_2) - idx_3 = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABAplus')); + if (~isempty(idx_1) && ~isempty(idx_2)) && ss ==2 + idx_3 = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABAplus')); if isempty(idx_3) - MRSCont.quantify.metabs.(getResults{ll}){length(MRSCont.quantify.metabs.(getResults{ll}))+1} = 'GABAplus'; + MRSCont.quantify.names.metab{mm,ss}{length(MRSCont.quantify.names.metab{mm,ss})+1} = 'GABAplus'; end - idx_GABAp = find(strcmp(MRSCont.quantify.metabs.(getResults{ll}),'GABAplus')); - GABAp = MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_1,:) + MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_2,:); - MRSCont.quantify.amplMets{kk}.(getResults{ll})(idx_GABAp,:) = GABAp; + idx_GABAp = find(strcmp(MRSCont.quantify.names.metab{mm,ss},'GABAplus')); + GABAp = MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_1,:) + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_2,:); + MRSCont.quantify.amplMets{mm,kk,ss}.metab(idx_GABAp,:) = GABAp; end end end end + end end end end @@ -527,33 +550,28 @@ %%%%%%%%%%%% BELOW ARE THE QUANTIFICATION FUNCTIONS %%%%%%%%%%%% %%% Calculate ratios to totale creatine %%% -function tCrRatios = quantCr(metsName, amplMets, getResults) -metsName = metsName.(getResults{1}); -% Calculate tCr ratios +function tCrRatios = quantCr(metsName, amplMets) +metsName = metsName.metab{1,1};% Calculate tCr ratios idx_Cr = find(strcmp(metsName,'Cr')); idx_PCr = find(strcmp(metsName,'PCr')); -for ll = 1:length(getResults) - if isempty(idx_Cr) && isempty(idx_PCr) - error('Error in OspreyQuantify: Creatine ratios cannot be calculated because neither Cr nor PCr are included in the basis set.') - elseif isempty(idx_Cr) && ~isempty(idx_PCr) - tCr.(getResults{ll}) = amplMets.(getResults{ll})(idx_PCr,:); - elseif ~isempty(idx_Cr) && isempty(idx_PCr) - tCr.(getResults{ll}) = amplMets.(getResults{ll})(idx_Cr,:); - elseif ~isempty(idx_Cr) && ~isempty(idx_PCr) - tCr.(getResults{ll}) = amplMets.(getResults{ll})(idx_Cr,:) + amplMets.(getResults{ll})(idx_PCr,:); - end +if isempty(idx_Cr) && isempty(idx_PCr) + error('Error in OspreyQuantify: Creatine ratios cannot be calculated because neither Cr nor PCr are included in the basis set.') +elseif isempty(idx_Cr) && ~isempty(idx_PCr) + tCr{1}.metab = amplMets{1,1,1}.metab(idx_PCr,:); +elseif ~isempty(idx_Cr) && isempty(idx_PCr) + tCr{1}.metab = amplMets{1,1,1}.metab(idx_Cr,:); +elseif ~isempty(idx_Cr) && ~isempty(idx_PCr) + tCr{1}.metab = amplMets{1,1,1}.metab(idx_Cr,:) + amplMets{1,1,1}.metab(idx_PCr,:); end % If separate fit of sub-spectra has been performed, normalize to 'off' or % 'sum' -if isfield(tCr, 'off') - tCrNorm = tCr.off; -elseif isfield(tCr, 'sum') - tCrNorm = tCr.sum; -elseif isfield(tCr, 'conc') - tCrNorm = tCr.conc; -end -for ll = 1:length(getResults) - tCrRatios.(getResults{ll}) = amplMets.(getResults{ll})./tCrNorm; +tCrNorm = tCr{1,1,1}.metab; +for mm = 1 : size(amplMets,1) + for ss = 1 : size(amplMets,3) + if ~isempty(amplMets{mm,1,ss}) + tCrRatios{mm,ss}.metab = amplMets{mm,1,ss}.metab./tCrNorm; + end + end end end @@ -562,7 +580,7 @@ %%% Calculate raw water-scaled estimates %%% -function rawWaterScaled = quantH2O(metsName, amplMets, amplWater, getResults, metsTR, waterTR, metsTE, waterTE,Bo) +function rawWaterScaled = quantH2O(metsName, amplMets, amplWater, metsTR, waterTR, metsTE, waterTE,Bo) % Define constants PureWaterConc = 55500; % mmol/L @@ -583,7 +601,7 @@ % GM 1331 +/- 13 110 +/- 2 T1_Water = 1.100; % average of WM and GM, Wansapura et al. 1999 (JMRI) T2_Water = 0.095; % average of WM and GM, Wansapura et al. 1999 (JMRI) - + case '7T' % 7T Water % T1 T2 @@ -593,20 +611,23 @@ T2_Water = 0.0525; % average of WM and GM, Bartha et al. 2002 (MRM) end - -% Metabolites -for ll = 1:length(getResults) - for kk = 1:length(metsName.(getResults{ll})) - [T1_Metab_GM(kk), T1_Metab_WM(kk), T2_Metab_GM(kk), T2_Metab_WM(kk)] = lookUpRelaxTimes(metsName.(getResults{1}){kk},Bo); - % average across GM and WM - T1_Metab(kk) = mean([T1_Metab_GM(kk) T1_Metab_WM(kk)]); - T2_Metab(kk) = mean([T2_Metab_GM(kk) T2_Metab_WM(kk)]); - T1_Factor(kk) = (1-exp(-waterTR./T1_Water)) ./ (1-exp(-metsTR./T1_Metab(kk))); - T2_Factor(kk) = exp(-waterTE./T2_Water) ./ exp(-metsTE./T2_Metab(kk)); - - % Calculate - rawWaterScaled.(getResults{ll})(kk,:) = (amplMets.(getResults{ll})(kk,:) ./ amplWater) .* PureWaterConc ... - .* WaterVisibility .* T1_Factor(kk) .* T2_Factor(kk); +for mm = 1 : size(amplMets,1) + % Metabolites + for ss = 1 : size(amplMets,3) + for kk = 1:length(metsName.metab{mm,ss}) + [T1_Metab_GM(kk), T1_Metab_WM(kk), T2_Metab_GM(kk), T2_Metab_WM(kk)] = lookUpRelaxTimes(metsName.metab{mm,ss},Bo); + % average across GM and WM + T1_Metab(kk) = mean([T1_Metab_GM(kk) T1_Metab_WM(kk)]); + T2_Metab(kk) = mean([T2_Metab_GM(kk) T2_Metab_WM(kk)]); + T1_Factor(kk) = (1-exp(-waterTR./T1_Water)) ./ (1-exp(-metsTR./T1_Metab(kk))); + T2_Factor(kk) = exp(-waterTE./T2_Water) ./ exp(-metsTE./T2_Metab(kk)); + + % Calculate + if ~isempty(amplMets{mm,1,ss}) + rawWaterScaled{mm,ss}.metab(kk,:) = (amplMets{mm,1,ss}.metab(kk,:) ./ amplWater) .* PureWaterConc ... + .* WaterVisibility .* T1_Factor(kk) .* T2_Factor(kk); + end + end end end end @@ -615,21 +636,24 @@ %%% Calculate CSF-corrected water-scaled estimates %%% -function CSFWaterScaled = quantCSF(rawWaterScaled, fCSF, getResults) +function CSFWaterScaled = quantCSF(rawWaterScaled, fCSF,SubSpectraFitted) % Simply divide the raw water-scaled, but tissue-uncorrected values by the % non-CSF fraction: -for ll = 1:length(getResults) - CSFWaterScaled.(getResults{ll}) = rawWaterScaled.(getResults{ll}) ./ (1 - fCSF); +for ss = 1 : SubSpectraFitted + for mm = 1 : size(rawWaterScaled,1) + if ~isempty(rawWaterScaled{mm,ss}) + CSFWaterScaled{mm,ss}.metab = rawWaterScaled{mm,ss}.metab ./ (1 - fCSF); + end + end end - end %%% /Calculate CSF-corrected water-scaled estimates %%% %%% Calculate tissue-corrected water-scaled estimates %%% -function TissCorrWaterScaled = quantTiss(metsName, amplMets, amplWater, getResults, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF,Bo) +function TissCorrWaterScaled = quantTiss(metsName, amplMets, amplWater, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF,Bo) % This function calculates water-scaled, tissue-corrected metabolite % estimates in molal units, according to Gasparovic et al, Magn Reson Med % 55:1219-26 (2006). @@ -688,22 +712,26 @@ molal_fWM = (fWM*concW_WM) ./ (fGM*concW_GM + fWM*concW_WM + fCSF*concW_CSF); molal_fCSF = (fCSF*concW_CSF) ./ (fGM*concW_GM + fWM*concW_WM + fCSF*concW_CSF); -% Metabolites -for ll = 1:length(getResults) - for kk = 1:length(metsName.(getResults{ll})) - [T1_Metab_GM(kk), T1_Metab_WM(kk), T2_Metab_GM(kk), T2_Metab_WM(kk)] = lookUpRelaxTimes(metsName.(getResults{1}){kk},Bo); - % average across GM and WM - T1_Metab(kk) = mean([T1_Metab_GM(kk) T1_Metab_WM(kk)]); - T2_Metab(kk) = mean([T2_Metab_GM(kk) T2_Metab_WM(kk)]); - - % Calculate water-scaled, tissue-corrected molal concentration - % estimates - TissCorrWaterScaled.(getResults{ll})(kk,:) = (amplMets.(getResults{ll})(kk,:) ./ amplWater) .* molal_concW ... - .* (molal_fGM * (1 - exp(-waterTR/T1w_GM)) * exp(-waterTE/T2w_GM) / ((1 - exp(-metsTR/T1_Metab(kk))) * exp(-metsTE/T2_Metab(kk))) + ... - molal_fWM * (1 - exp(-waterTR/T1w_WM)) * exp(-waterTE/T2w_WM) / ((1 - exp(-metsTR/T1_Metab(kk))) * exp(-metsTE/T2_Metab(kk))) + ... - molal_fCSF * (1 - exp(-waterTR/T1w_CSF)) * exp(-waterTE/T2w_CSF) / ((1 - exp(-metsTR/T1_Metab(kk))) * exp(-metsTE/T2_Metab(kk)))) ./ ... - (1 - molal_fCSF); - end +for mm = 1 : size(amplMets,1) + for ss = 1 : size(amplMets,3) + % Metabolites + for kk = 1:length(metsName.metab{mm,ss}) + [T1_Metab_GM(kk), T1_Metab_WM(kk), T2_Metab_GM(kk), T2_Metab_WM(kk)] = lookUpRelaxTimes(metsName.metab{mm,ss}{kk},Bo); + % average across GM and WM + T1_Metab(kk) = mean([T1_Metab_GM(kk) T1_Metab_WM(kk)]); + T2_Metab(kk) = mean([T2_Metab_GM(kk) T2_Metab_WM(kk)]); + + % Calculate water-scaled, tissue-corrected molal concentration + % estimates + if ~isempty(amplMets{mm,1,ss}) + TissCorrWaterScaled{mm,ss}.metab(kk,:) = (amplMets{mm,ss}.metab(kk,:) ./ amplWater) .* molal_concW ... + .* (molal_fGM * (1 - exp(-waterTR/T1w_GM)) * exp(-waterTE/T2w_GM) / ((1 - exp(-metsTR/T1_Metab(kk))) * exp(-metsTE/T2_Metab(kk))) + ... + molal_fWM * (1 - exp(-waterTR/T1w_WM)) * exp(-waterTE/T2w_WM) / ((1 - exp(-metsTR/T1_Metab(kk))) * exp(-metsTE/T2_Metab(kk))) + ... + molal_fCSF * (1 - exp(-waterTR/T1w_CSF)) * exp(-waterTE/T2w_CSF) / ((1 - exp(-metsTR/T1_Metab(kk))) * exp(-metsTE/T2_Metab(kk)))) ./ ... + (1 - molal_fCSF); + end + end + end end end %%% /Calculate CSF-corrected water-scaled estimates %%% @@ -711,7 +739,7 @@ %%% Calculate alpha-corrected water-scaled GABA estimates %%% -function [AlphaCorrWaterScaled, AlphaCorrWaterScaledGroupNormed] = quantAlpha(metsName, amplMets, amplWater,getResults, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF, meanfGM, meanfWM,coMM3,Bo) +function [AlphaCorrWaterScaled, AlphaCorrWaterScaledGroupNormed] = quantAlpha(metsName, amplMets, amplWater, metsTR, waterTR, metsTE, waterTE, fGM, fWM, fCSF, meanfGM, meanfWM,coMM3,Bo) % This function calculates water-scaled, alpha-corrected GABA % estimates in molal units, according to Gasparovic et al, Magn Reson Med % 55:1219-26 (2006). @@ -769,34 +797,38 @@ alpha = cWM/cGM; CorrFactor = (meanfGM + alpha.*meanfWM) ./ ((fGM + alpha.*fWM) .* (meanfGM + meanfWM)); -% GABA (Harris et al, J Magn Reson Imaging 42:1431-1440 (2015)) -idx_GABA = find(strcmp(metsName.(getResults{1}),'GABA')); -[T1_Metab_GM, T1_Metab_WM, T2_Metab_GM, T2_Metab_WM] = lookUpRelaxTimes(metsName.(getResults{1}){idx_GABA},Bo); -% average across GM and WM -T1_Metab = mean([T1_Metab_GM T1_Metab_WM]); -T2_Metab = mean([T2_Metab_GM T2_Metab_WM]); -ConcIU_TissCorr_Harris = (amplMets.(getResults{1})(idx_GABA) ./ amplWater) ... - .* (fGM * concW_GM * (1 - exp(-waterTR/T1w_GM)) * exp(-waterTE/T2w_GM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... - fWM * concW_WM * (1 - exp(-waterTR/T1w_WM)) * exp(-waterTE/T2w_WM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... - fCSF * concW_CSF * (1 - exp(-waterTR/T1w_CSF)) * exp(-waterTE/T2w_CSF) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab))); - -AlphaCorrWaterScaled = ConcIU_TissCorr_Harris ./ (fGM + alpha*fWM); -AlphaCorrWaterScaledGroupNormed = ConcIU_TissCorr_Harris .* CorrFactor; - -if ~strcmp(coMM3, 'none') - % GABA (Harris et al, J Magn Reson Imaging 42:1431-1440 (2015)) - idx_GABAp = find(strcmp(metsName.(getResults{1}),'GABAplus')); - [T1_Metab_GM, T1_Metab_WM, T2_Metab_GM, T2_Metab_WM] = lookUpRelaxTimes(metsName.(getResults{1}){idx_GABA},Bo); - % average across GM and WM - T1_Metab = mean([T1_Metab_GM T1_Metab_WM]); - T2_Metab = mean([T2_Metab_GM T2_Metab_WM]); - ConcIU_TissCorr_Harris = (amplMets.(getResults{1})(idx_GABAp) ./ amplWater) ... - .* (fGM * concW_GM * (1 - exp(-waterTR/T1w_GM)) * exp(-waterTE/T2w_GM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... - fWM * concW_WM * (1 - exp(-waterTR/T1w_WM)) * exp(-waterTE/T2w_WM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... - fCSF * concW_CSF * (1 - exp(-waterTR/T1w_CSF)) * exp(-waterTE/T2w_CSF) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab))); - - AlphaCorrWaterScaled(:,2) = ConcIU_TissCorr_Harris ./ (fGM + alpha*fWM); - AlphaCorrWaterScaledGroupNormed(:,2) = ConcIU_TissCorr_Harris .* CorrFactor; +for mm = 1 : size(amplMets,1) + for ss = 1 : size(amplMets,3) + % GABA (Harris et al, J Magn Reson Imaging 42:1431-1440 (2015)) + idx_GABA = find(strcmp(metsName.metab{mm,ss},'GABA')); + [T1_Metab_GM, T1_Metab_WM, T2_Metab_GM, T2_Metab_WM] = lookUpRelaxTimes(metsName.metab{mm,ss}{idx_GABA},Bo); + % average across GM and WM + T1_Metab = mean([T1_Metab_GM T1_Metab_WM]); + T2_Metab = mean([T2_Metab_GM T2_Metab_WM]); + ConcIU_TissCorr_Harris{mm,ss} = (amplMets{mm,ss}.metab(idx_GABA) ./ amplWater) ... + .* (fGM * concW_GM * (1 - exp(-waterTR/T1w_GM)) * exp(-waterTE/T2w_GM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... + fWM * concW_WM * (1 - exp(-waterTR/T1w_WM)) * exp(-waterTE/T2w_WM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... + fCSF * concW_CSF * (1 - exp(-waterTR/T1w_CSF)) * exp(-waterTE/T2w_CSF) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab))); + + AlphaCorrWaterScaled{mm,ss} = ConcIU_TissCorr_Harris{mm,ss} ./ (fGM + alpha*fWM); + AlphaCorrWaterScaledGroupNormed{mm,ss} = ConcIU_TissCorr_Harris{mm,ss} .* CorrFactor; + + if ~isempty(find(strcmp(metsName.metab{mm,ss},'GABAplus'))) + % GABA (Harris et al, J Magn Reson Imaging 42:1431-1440 (2015)) + idx_GABAp = find(strcmp(metsName.metab{mm,ss},'GABAplus')); + [T1_Metab_GM, T1_Metab_WM, T2_Metab_GM, T2_Metab_WM] = lookUpRelaxTimes(metsName.metab{mm,ss}{idx_GABA},Bo); + % average across GM and WM + T1_Metab = mean([T1_Metab_GM T1_Metab_WM]); + T2_Metab = mean([T2_Metab_GM T2_Metab_WM]); + ConcIU_TissCorr_Harris{mm,ss} = (amplMets{mm,ss}.metab(idx_GABAp) ./ amplWater) ... + .* (fGM * concW_GM * (1 - exp(-waterTR/T1w_GM)) * exp(-waterTE/T2w_GM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... + fWM * concW_WM * (1 - exp(-waterTR/T1w_WM)) * exp(-waterTE/T2w_WM) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab)) + ... + fCSF * concW_CSF * (1 - exp(-waterTR/T1w_CSF)) * exp(-waterTE/T2w_CSF) / ((1 - exp(-metsTR/T1_Metab)) * exp(-metsTE/T2_Metab))); + + AlphaCorrWaterScaled{mm,ss}(:,2) = ConcIU_TissCorr_Harris{mm,ss} ./ (fGM + alpha*fWM); + AlphaCorrWaterScaledGroupNormed{mm,ss}(:,2) = ConcIU_TissCorr_Harris{mm,ss} .* CorrFactor; + end + end end end %%% /Calculate alpha-corrected water-scaled GABA estimates %%% @@ -855,13 +887,13 @@ case '7T' % T2 values of water, NAA, tCr, tCho, Scyllo, Ins, Glu,GSH, Ins, % and Tau are taken from Marjanska et al. 2011 (NMR - % 10.1002/nbm.1754). It was averaged across 4 regions OCC, SM1, BG, CER - % Penner et al (2014) https://doi.org/10.1002/mrm.25380 for + % 10.1002/nbm.1754). It was averaged across 4 regions OCC, SM1, BG, CER + % Penner et al (2014) https://doi.org/10.1002/mrm.25380 for relax.Asc = [1530 1484 127 128]; % This is the average from tNAA, tCr, tCho, Glx, and Ins relax.Asp = [1530 1484 127 128]; % This is the average from tNAA, tCr, tCho, Glx, and Ins relax.Cr = [1740 1780 107 107]; % Taken from tCr relax.GABA = [1334 1334 87 87]; % Andreychenko et al. (2012) 10.1002/nbm.2997 - relax.Glc = [1530 1484 127 128]; % This is the average from tNAA, tCr, tCho, Glx, and Ins + relax.Glc = [1530 1484 127 128]; % This is the average from tNAA, tCr, tCho, Glx, and Ins relax.Gln = [1640 1740 107 107]; %T1 from Mlynarik et al. (2012) 10.1002/mrm.24352 % T2 as Gln relax.Glu = [1610 1750 107 117]; % T1 from Mlynarik et al. (2012) 10.1002/mrm.24352, T2 from https://doi.org/10.1371/journal.pone.0215210 relax.Gly = [1530 1484 127 128]; % This is the average from tNAA, tCr, tCho, Glx, and Ins @@ -870,7 +902,7 @@ relax.Lac = [1530 1484 182 182]; % The use of MEGA-sLASER with J-refocusing echo time extension to measure the proton T2 of lactate in healthy human brain at 7 T ISMRM relax.Ins = [1280 1190 111 111]; %T1 from Mlynarik et al. (2012) 10.1002/mrm.24352 relax.NAA = [1780 1830 155 155]; % This is the 2.008 ppm acetyl signal (naa in the paper); aspartyl is naa1: [1310 1310 110 110]; T1 from Mlynarik et al. (2012) 10.1002/mrm.24352 - relax.NAAG = [1210 940 155 155]; % This is the 2.042 ppm acetyl signal (naag in the paper); aspartyl is naag1: [1310 1310 (108+87)/2 180]; % glutamate is NAAG2: [1310 1310 (110+78)/2 157]; + relax.NAAG = [1210 940 155 155]; % This is the 2.042 ppm acetyl signal (naag in the paper); aspartyl is naag1: [1310 1310 (108+87)/2 180]; % glutamate is NAAG2: [1310 1310 (110+78)/2 157]; relax.PCh = [1510 1320 153 153]; % Taken from tCho relax.PCr = [1740 1780 107 107]; % Taken from tCr relax.PE = [1310 1320]; %T1 from Mlynarik et al. (2012) 10.1002/mrm.24352 @@ -901,72 +933,86 @@ %%% / Lookup function for metabolite relaxation times %%% %%% Function to create metabolite overview in MATLAB table format %%% -function [MRSCont] = osp_createTable(MRSCont, qtfyType, getResults) +function [MRSCont] = osp_createTable(MRSCont, qtfyType) if ~(strcmp(qtfyType, 'AlphaCorrWaterScaled') || strcmp(qtfyType, 'AlphaCorrWaterScaledGroupNormed')) if ~(strcmp(qtfyType, 'amplMets') || strcmp(qtfyType, 'CRLB') ||strcmp(qtfyType, 'h2oarea') ) % Extract metabolite names from basisset - for ll = 1:length(getResults) - names = MRSCont.quantify.metabs.(getResults{ll}); - for rr = 1 : size(MRSCont.quantify.(getResults{ll}).(qtfyType){1},2) - conc = zeros(MRSCont.nDatasets,length(names)); - for kk = 1:MRSCont.nDatasets - conc(kk,:) = MRSCont.quantify.(getResults{ll}).(qtfyType){kk}(:,rr); - end - % Save back to Osprey data container - if isfield(MRSCont, 'exclude') - if~isempty(MRSCont.exclude) - conc(MRSCont.exclude,:) = []; + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + names = MRSCont.quantify.names.metab{mm,ss}; + for rr = 1 : size(MRSCont.quantify.metab.(qtfyType){1,1,1},2) + if ~isempty(MRSCont.quantify.metab.(qtfyType){mm,1,ss}) + conc = zeros(MRSCont.nDatasets(1),length(names)); + for kk = 1:MRSCont.nDatasets(1) + conc(kk,:) = MRSCont.quantify.metab.(qtfyType){mm,kk,ss}(:,rr)'; + end + % Save back to Osprey data container + if isfield(MRSCont, 'exclude') + if~isempty(MRSCont.exclude) + conc(MRSCont.exclude,:) = []; + end + end + MRSCont.quantify.tables.metab.(qtfyType).(['Voxel_' num2str(rr)]){mm,ss} = array2table(conc,'VariableNames',names); end end - MRSCont.quantify.tables.(getResults{ll}).(qtfyType).(['Voxel_' num2str(rr)]) = array2table(conc,'VariableNames',names); end - end else % Extract metabolite names from basisset - for ll = 1:length(getResults) - if (strcmp(qtfyType, 'amplMets') || strcmp(qtfyType, 'CRLB')) - names = MRSCont.quantify.metabs.(getResults{ll}); - else - names = {'h2oarea'}; - end - for rr = 1 : size(MRSCont.quantify.(qtfyType){1}.(getResults{ll}),2) - conc = zeros(MRSCont.nDatasets,length(names)); - - for kk = 1:MRSCont.nDatasets - conc(kk,:) = MRSCont.quantify.(qtfyType){kk}.(getResults{ll})(:,rr); + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1: size(MRSCont.fit.results.metab.fitParams,1) + if (strcmp(qtfyType, 'amplMets') || strcmp(qtfyType, 'CRLB')) + names = MRSCont.quantify.names.metab{mm,ss}; + else + names = {'h2oarea'}; end - % Save back to Osprey data container - if isfield(MRSCont, 'exclude') - if~isempty(MRSCont.exclude) - conc(MRSCont.exclude,:) = []; + for rr = 1 : size(MRSCont.quantify.(qtfyType){1,1,1}.metab,2) + if ~isempty(MRSCont.quantify.(qtfyType){mm,1,ss}) + conc = zeros(MRSCont.nDatasets(1),length(names)); + + for kk = 1:MRSCont.nDatasets(1) + if (strcmp(qtfyType, 'h2oarea') || strcmp(qtfyType, 'CRLB')) + conc(kk,:) = MRSCont.quantify.(qtfyType){kk}.metab(:,rr); + else + conc(kk,:) = MRSCont.quantify.(qtfyType){mm,kk,ss}.metab(:,rr)'; + end + end + % Save back to Osprey data container + if isfield(MRSCont, 'exclude') + if~isempty(MRSCont.exclude) + conc(MRSCont.exclude,:) = []; + end + end + MRSCont.quantify.tables.metab.(qtfyType).(['Voxel_' num2str(rr)]){mm,ss} = array2table(conc,'VariableNames',names); end end - MRSCont.quantify.tables.(getResults{ll}).(qtfyType).(['Voxel_' num2str(rr)]) = array2table(conc,'VariableNames',names); end - end + end end else - % Extract metabolite names from basisset - names = {'GABA'}; - if ~strcmp(MRSCont.opts.fit.coMM3, 'none') - names = {'GABA','GABAplus'}; - end - - for ll = 1:length(getResults) - for rr = 1 : size(MRSCont.quantify.(getResults{ll}).(qtfyType){1},2) - conc = zeros(MRSCont.nDatasets,length(names)); - for kk = 1:MRSCont.nDatasets - conc(kk,:) = MRSCont.quantify.(getResults{ll}).(qtfyType){kk}(:,rr); - end - % Save back to Osprey data container - if isfield(MRSCont, 'exclude') - if~isempty(MRSCont.exclude) - conc(MRSCont.exclude,:) = []; - end - end - MRSCont.quantify.tables.(getResults{ll}).(qtfyType).(['Voxel_' num2str(rr)]) = array2table(conc,'VariableNames',names); - end + % Extract metabolite names from basisset + for ss = 1 : size(MRSCont.fit.results.metab.fitParams,3) + for mm = 1 : size(MRSCont.quantify.metab.(qtfyType),1) + for rr = 1 : size(MRSCont.quantify.metab.(qtfyType){1,1,1},3) + if ~isempty(MRSCont.quantify.metab.(qtfyType){mm,1,ss}) + names = {'GABA'}; + if size(MRSCont.quantify.metab.(qtfyType){1,1,2},2) == 2 + names = {'GABA','GABAplus'}; + end + conc = zeros(MRSCont.nDatasets(1),length(names)); + for kk = 1:MRSCont.nDatasets(1) + conc(kk,:) = MRSCont.quantify.metab.(qtfyType){mm,kk,ss}(rr,:)'; + end + % Save back to Osprey data container + if isfield(MRSCont, 'exclude') + if~isempty(MRSCont.exclude) + conc(MRSCont.exclude,:) = []; + end + end + MRSCont.quantify.tables.metab.(qtfyType).(['Voxel_' num2str(rr)]){mm,ss} = array2table(conc,'VariableNames',names); + end + end + end end end end diff --git a/quantify/exportQuant.m b/quantify/exportQuant.m index 6cc7b72b..f5b3f8cb 100644 --- a/quantify/exportQuant.m +++ b/quantify/exportQuant.m @@ -1,26 +1,26 @@ -function exportQuant(MRSCont,saveDestination,getResults) +function exportQuant(MRSCont,saveDestination) -quants = {'amplMets','tCr','rawWaterScaled','CSFWaterScaled','TissCorrWaterScaled','AlphaCorrWaterScaled','AlphaCorrWaterScaledGroupNormed'}; -if strcmp(MRSCont.opts.fit.method, 'LCModel') - quants = [quants, 'CRLB','h2oarea']; +if ~strcmp(MRSCont.opts.fit.method, 'LCModel') + quants = {'amplMets','tCr','rawWaterScaled','CSFWaterScaled','TissCorrWaterScaled','AlphaCorrWaterScaled','AlphaCorrWaterScaledGroupNormed'}; +else + quants = {'amplMets','tCr','rawWaterScaled','CSFWaterScaled','TissCorrWaterScaled','AlphaCorrWaterScaled','AlphaCorrWaterScaledGroupNormed','CRLB','h2oarea'}; end -for ll = 1:length(getResults) +for ss = 1:size(MRSCont.quantify.names.metab,2) for q = 1 : length(quants) - if isfield(MRSCont.quantify.tables.(getResults{ll}), quants(q)) - if isstruct(MRSCont.quantify.tables.(getResults{ll}).(quants{q})) % To make export work on older MRSContainer - if ~MRSCont.flags.isPRIAM - MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1 = PopulateJSON(MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1, quants{q}); - osp_WriteBIDsTable(MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1, [saveDestination filesep (getResults{ll}) '_' quants{q} '_Voxel_1']); - else - MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1 = PopulateJSON(MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1, quants{q}); - osp_WriteBIDsTable(MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1, [saveDestination filesep (getResults{ll}) '_' quants{q} '_Voxel_1']); - MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_2 = PopulateJSON(MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1, quants{q}); - osp_WriteBIDsTable(MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_2, [saveDestination filesep (getResults{ll}) '_' quants{q} '_Voxel_2']); + if isfield(MRSCont.quantify.tables.metab, quants(q)) + for mm = 1 : size(MRSCont.quantify.names.metab,1) + if ~isempty(MRSCont.quantify.names.metab{mm,ss}) + if ~MRSCont.flags.isPRIAM + MRSCont.quantify.tables.metab.(quants{q}).Voxel_1{mm,ss} = PopulateJSON(MRSCont.quantify.tables.metab.(quants{q}).Voxel_1{mm,ss},quants{q}); + osp_WriteBIDsTable(MRSCont.quantify.tables.metab.(quants{q}).Voxel_1{mm,ss}, [saveDestination filesep MRSCont.quantify.names.SubSpectra{mm,ss} '_' quants{q} '_Voxel_1_Basis_' num2str(mm)]); + else + MRSCont.quantify.tables.metab.(quants{q}).Voxel_1{mm,ss} = PopulateJSON(MRSCont.quantify.tables.metab.(quants{q}).Voxel_1{mm,ss},quants{q}); + osp_WriteBIDsTable(MRSCont.quantify.tables.metab.(quants{q}).Voxel_1{mm,ss}, [saveDestination filesep MRSCont.quantify.names.SubSpectra{mm,ss} '_' quants{q} '_Voxel_1_Basis_' num2str(mm)]); + MRSCont.quantify.tables.metab.(quants{q}).Voxel_2{mm,ss} = PopulateJSON(MRSCont.quantify.tables.metab.(quants{q}).Voxel_2{mm,ss},quants{q}); + osp_WriteBIDsTable(MRSCont.quantify.tables.metab.(quants{q}).Voxel_2{mm,ss}, [saveDestination filesep MRSCont.quantify.names.SubSpectra{mm,ss} '_' quants{q} '_Voxel_2_Basis_' num2str(mm)]); + end end - else - MRSCont.quantify.tables.(getResults{ll}).(quants{q}) = PopulateJSON(MRSCont.quantify.tables.(getResults{ll}).(quants{q}).Voxel_1, quants{q}); - osp_WriteBIDsTable(MRSCont.quantify.tables.(getResults{ll}).(quants{q}), [saveDestination filesep (getResults{ll}) '_' quants{q}]) end end end diff --git a/seg/OspreySeg.m b/seg/OspreySeg.m index 8aa33080..1ae9beaf 100644 --- a/seg/OspreySeg.m +++ b/seg/OspreySeg.m @@ -54,8 +54,8 @@ else progressText = ''; end -for kk = 1:MRSCont.nDatasets - [~] = printLog('OspreySeg',kk,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +for kk = 1:MRSCont.nDatasets(1) + [~] = printLog('OspreySeg',kk,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); if ~(MRSCont.flags.didSeg == 1 && MRSCont.flags.speedUp && isfield(MRSCont, 'seg') && (kk > length(MRSCont.seg.tissue.fGM))) || ~strcmp(MRSCont.ver.Osp,MRSCont.ver.CheckOsp) @@ -293,7 +293,7 @@ end end time = toc(refSegTime); -[~] = printLog('done',time,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); +[~] = printLog('done',time,1,MRSCont.nDatasets,progressText,MRSCont.flags.isGUI ,MRSCont.flags.isMRSI); MRSCont.runtime.Seg = time; %% Create table and tsv file tissueTypes = {'fGM','fWM','fCSF'}; diff --git a/settings/OspreySettings.m b/settings/OspreySettings.m index 57915a99..127ca61d 100644 --- a/settings/OspreySettings.m +++ b/settings/OspreySettings.m @@ -28,6 +28,7 @@ MRSCont.flags.isPRIAM = 0; MRSCont.flags.isMRSI = 0; MRSCont.flags.addImages = 0; +MRSCont.flags.reordered = 0; MRSCont.opts.savePDF = 0; MRSCont.opts.saveLCM = 0; MRSCont.opts.savejMRUI = 0; @@ -42,6 +43,8 @@ MRSCont.opts.fit.fitMM = 1; % Add MM and lipid basis functions to basis set? Default: 1. MRSCont.opts.fit.coMM3 = 'none'; % Add co-edited MM3 peak model for GABA editing? Default: none. MRSCont.opts.fit.FWHMcoMM3 = 14; % FWHM [Hz] of the co-edited peak Default: 14 Hz. +MRSCont.opts.ECC.raw = 1; % Do ECC for all metabolite spectra. +MRSCont.opts.ECC.mm = 1; % Do ECC for all metabolite-nulled spectra. %%% 2. FIND AND SET PATHS %%% % Osprey @@ -69,9 +72,11 @@ MRSCont.files_mm = {}; MRSCont.files_ref = {}; MRSCont.files_w = {}; +MRSCont.files_mm_ref = {}; MRSCont.flags.hasMM = 0; MRSCont.flags.hasRef = 0; MRSCont.flags.hasWater = 0; +MRSCont.flags.hasMMRef = 0; % Set default flags MRSCont.flags.didLCMWrite = 0; MRSCont.flags.didjMRUIWrite = 0; diff --git a/utilities/OspreyMinReport.m b/utilities/OspreyMinReport.m index 749acd08..ea14e617 100644 --- a/utilities/OspreyMinReport.m +++ b/utilities/OspreyMinReport.m @@ -104,7 +104,7 @@ OFF = 7.5; case 'PE398' ON = 3.98; - OFF = 7.5; + OFF = 7.5; end fprintf(fid,'|f. Additional sequence parameters
i. editing pulse frequencies | F1: %d Hz, %d points
ppmON = %.2f ppmOFF = %.2f | \n', ... MRSCont.raw{1}.spectralwidth,MRSCont.raw{1}.sz(1),ON,OFF); @@ -121,23 +121,7 @@ fprintf(fid,'|--|--| \n'); fprintf(fid,'|a. Analysis software | %s| \n', MRSCont.ver.Osp); % Here we need something for cases without fitting was done fprintf(fid,'|b. Processing steps deviating from Osprey | %s| \n', 'None'); -if MRSCont.flags.isUnEdited - try - strings = fieldnames(MRSCont.quantify.tables.A); - catch - strings = fieldnames(MRSCont.quantify.tables.off); - end -end -if MRSCont.flags.isMEGA - strings = fieldnames(MRSCont.quantify.tables.off); -end -if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - if strcmp(MRSCont.opts.fit.style,'Separate') - strings = fieldnames(MRSCont.quantify.tables.sum); - else - strings = fieldnames(MRSCont.quantify.tables.conc); - end -end +strings = fieldnames(MRSCont.quantify.tables.metab); outs = ''; for ss = 1 : length(strings) outs = [outs strings{ss}]; @@ -149,28 +133,12 @@ outs = ''; br = 1; if ~strcmp(MRSCont.opts.fit.method, 'LCModel') - if MRSCont.flags.isUnEdited - includeMetabs = MRSCont.fit.resBasisSet.off.(MRSCont.info.A.unique_ndatapoint_spectralwidth{1}).name; - end - if MRSCont.flags.isMEGA - if strcmp(MRSCont.opts.fit.style,'Separate') - includeMetabs = MRSCont.fit.resBasisSet.diff1.(MRSCont.info.diff1.unique_ndatapoint_spectralwidth{1}).name; - else - includeMetabs = MRSCont.fit.resBasisSet.conc.(MRSCont.info.diff1.unique_ndatapoint_spectralwidth{1}).name; - end - end - if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - if strcmp(MRSCont.opts.fit.style,'Separate') - includeMetabs = MRSCont.fit.resBasisSet.diff1.(MRSCont.info.diff1.unique_ndatapoint_spectralwidth{1}).name; - else - includeMetabs = MRSCont.fit.resBasisSet.conc.(MRSCont.info.diff1.unique_ndatapoint_spectralwidth{1}).name; - end - end + includeMetabs = MRSCont.quantify.names.metab{1, 1}; for ss = 1 : length(includeMetabs) if br < 10 - outs = [outs includeMetabs{ss}]; + outs = [outs includeMetabs{ss}]; else - outs = [outs includeMetabs{ss} ',
']; + outs = [outs includeMetabs{ss} ',
']; br = 1; end if ss ~= length(includeMetabs) && br ~= 1 @@ -180,7 +148,7 @@ end else if MRSCont.flags.isUnEdited - includeMetabs = MRSCont.fit.results.off.fitParams{1, 1}.name; + includeMetabs = MRSCont.fit.results.metab.fitParams{1, 1}.name; end end fprintf(fid,'|d. Quantification references and assumptions, fitting model assumptions| Basis set list:
%s
Fitting method: %s basline knot spacing %.2f ppm\n', outs,MRSCont.opts.fit.method,MRSCont.opts.fit.bLineKnotSpace ); @@ -190,10 +158,10 @@ fprintf(fid,'|4. Data quality| | \n'); fprintf(fid,'|--|--| \n'); if MRSCont.flags.isUnEdited || MRSCont.flags.isMEGA - fprintf(fid,'|a. SNR (NAA), linewidth (NAA) [Hz] | SNR: %.0f +- %.0f, linewidth %.2f +- %.2f Hz| \n', round(mean(MRSCont.QM.SNR.A)),round(std(MRSCont.QM.SNR.A),2),round(mean(MRSCont.QM.FWHM.A),2),round(std(MRSCont.QM.FWHM.A),2)); % Here we need something for cases without fitting was done + fprintf(fid,'|a. SNR (NAA), linewidth (NAA) [Hz] | SNR: %.0f +- %.0f, linewidth %.2f +- %.2f Hz| \n', round(mean(MRSCont.QM.SNR.metab(1,:,1))),round(std(MRSCont.QM.SNR.metab(1,:,1)),2),round(mean(MRSCont.QM.FWHM.metab(1,:,1)),2),round(std(MRSCont.QM.FWHM.metab(1,:,1)),2)); % Here we need something for cases without fitting was done end if MRSCont.flags.isHERMES || MRSCont.flags.isHERCULES - fprintf(fid,'|a. SNR (NAA), linewidth (NAA) [Hz] | SNR: %.0f +- %.0f, linewidth %.2f +- %.2f Hz| \n', round(mean(MRSCont.QM.SNR.sum)),round(std(MRSCont.QM.SNR.sum),2),round(mean(MRSCont.QM.FWHM.sum),2),round(std(MRSCont.QM.FWHM.sum),2)); % Here we need something for cases without fitting was done + fprintf(fid,'|a. SNR (NAA), linewidth (NAA) [Hz] | SNR: %.0f +- %.0f, linewidth %.2f +- %.2f Hz| \n', round(mean(MRSCont.QM.SNR.metab(1,:,7))),round(std(MRSCont.QM.SNR.metab(1,:,7)),2),round(mean(MRSCont.QM.FWHM.metab(1,:,7)),2),round(std(MRSCont.QM.FWHM.metab(1,:,7)),2)); % Here we need something for cases without fitting was done end fprintf(fid,'|b. Data exclusion criteria | %s| \n', 'None'); if MRSCont.flags.isUnEdited @@ -208,4 +176,4 @@ fprintf(fid,'|d. Mean spectrum created with OspreyOverview| %s \n', 'Figure 1' ); fclose(fid); -end \ No newline at end of file +end diff --git a/utilities/osp_scale_yaxis.m b/utilities/osp_scale_yaxis.m index c77275bc..f55cfec8 100644 --- a/utilities/osp_scale_yaxis.m +++ b/utilities/osp_scale_yaxis.m @@ -3,66 +3,92 @@ case 'OspreyLoad' ppmmax = 4.5; ppmmin = 0.2; - Range = zeros(2,MRSCont.nDatasets); - for kk = 1 : MRSCont.nDatasets - temp_spec = op_freqrange(MRSCont.raw{kk}, ppmmin, ppmmax); - Range(1,kk) = op_findMaxMedian(temp_spec); - Range(2,kk) = op_findMinMedian(temp_spec); + Range = zeros(2,MRSCont.nDatasets(1),MRSCont.nDatasets(2)); + for kk = 1 : MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + metab_ll = MRSCont.opts.MultipleSpectra.metab(ll); + temp_spec = op_freqrange(MRSCont.raw{metab_ll,kk}, ppmmin, ppmmax); + Range(1,kk,metab_ll) = op_findMaxMedian(temp_spec); + Range(2,kk,metab_ll) = op_findMinMedian(temp_spec); + end end - MRSCont.plot.load.mets.max = Range(1,:); - MRSCont.plot.load.mets.min = Range(2,:); - MRSCont.plot.load.mets.ContMax = max(Range(1,:)); - MRSCont.plot.load.mets.ContMin = min(Range(2,:)); + MRSCont.plot.load.mets.max = Range(1,:,:); + MRSCont.plot.load.mets.min = Range(2,:,:); + MRSCont.plot.load.mets.ContMax = max(max(Range(1,:))); + MRSCont.plot.load.mets.ContMin = min(min(Range(2,:))); if MRSCont.flags.hasRef ppmmax = 2*4.68; ppmmin = 0; - Range = zeros(2,MRSCont.nDatasets); - for kk = 1 : MRSCont.nDatasets - temp_spec = op_freqrange(MRSCont.raw_ref{kk}, ppmmin, ppmmax); - Range(1,kk) = op_findMaxMedian(temp_spec); - Range(2,kk) = op_findMinMedian(temp_spec); + Range = zeros(2,MRSCont.nDatasets(1)); + for kk = 1 : MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + ref_ll = MRSCont.opts.MultipleSpectra.ref(ll); + temp_spec = op_freqrange(MRSCont.raw_ref{ref_ll,kk}, ppmmin, ppmmax); + Range(1,kk,ref_ll) = op_findMaxMedian(temp_spec); + Range(2,kk,ref_ll) = op_findMinMedian(temp_spec); + end end - MRSCont.plot.load.ref.max = Range(1,:); - MRSCont.plot.load.ref.min = Range(2,:); - MRSCont.plot.load.ref.ContMax = max(Range(1,:)); - MRSCont.plot.load.ref.ContMin = min(Range(2,:)); + MRSCont.plot.load.ref.max = Range(1,:,:); + MRSCont.plot.load.ref.min = Range(2,:,:); + MRSCont.plot.load.ref.ContMax = max(max(Range(1,:))); + MRSCont.plot.load.ref.ContMin = min(min(Range(2,:))); end if MRSCont.flags.hasWater ppmmax = 2*4.68; ppmmin = 0; - Range = zeros(2,MRSCont.nDatasets); - for kk = 1 : MRSCont.nDatasets - temp_spec = op_freqrange(MRSCont.raw_w{kk}, ppmmin, ppmmax); - Range(1,kk) = op_findMaxMedian(temp_spec,1); - Range(2,kk) = op_findMinMedian(temp_spec,1); + Range = zeros(2,MRSCont.nDatasets(1)); + for kk = 1 : MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + w_ll = MRSCont.opts.MultipleSpectra.w(ll); + temp_spec = op_freqrange(MRSCont.raw_w{w_ll,kk}, ppmmin, ppmmax); + Range(1,kk,w_ll) = op_findMaxMedian(temp_spec,1); + Range(2,kk,w_ll) = op_findMinMedian(temp_spec,1); + end + end + MRSCont.plot.load.w.max = Range(1,:,:); + MRSCont.plot.load.w.min = Range(2,:,:); + MRSCont.plot.load.w.ContMax = max(max(Range(1,:))); + MRSCont.plot.load.w.ContMin = min(min(Range(2,:))); + end + if MRSCont.flags.hasMMRef + ppmmax = 2*4.68; + ppmmin = 0; + Range = zeros(2,MRSCont.nDatasets(1)); + for kk = 1 : MRSCont.nDatasets(1) + for ll = 1: 1:MRSCont.nDatasets(2) + mm_ref_ll = MRSCont.opts.MultipleSpectra.mm_ref(ll); + temp_spec = op_freqrange(MRSCont.raw_mm_ref{mm_ref_ll,kk}, ppmmin, ppmmax); + Range(1,kk,mm_ref_ll) = op_findMaxMedian(temp_spec,1); + Range(2,kk,mm_ref_ll) = op_findMinMedian(temp_spec,1); + end end - MRSCont.plot.load.w.max = Range(1,:); - MRSCont.plot.load.w.min = Range(2,:); - MRSCont.plot.load.w.ContMax = max(Range(1,:)); - MRSCont.plot.load.w.ContMin = min(Range(2,:)); + MRSCont.plot.load.mm_ref.max = Range(1,:,:); + MRSCont.plot.load.mm_ref.min = Range(2,:,:); + MRSCont.plot.load.mm_ref.ContMax = max(max(Range(1,:))); + MRSCont.plot.load.mm_ref.ContMin = min(min(Range(2,:))); end case 'OspreyProcess' SubSpecNames = fieldnames(MRSCont.processed); NoSubSpec = length(fieldnames(MRSCont.processed)); for ss = 1 : NoSubSpec - Range = zeros(2,MRSCont.nDatasets); + Range = zeros(2,MRSCont.nDatasets(1)); switch SubSpecNames{ss} - case {'A', 'B', 'C', 'D', 'diff1', 'diff2', 'sum','mm'} + case {'metab','mm'} ppmmax = 4.5; - case {'ref', 'w'} + case {'ref', 'w', 'mm_ref'} ppmmax = 2*4.68; end switch SubSpecNames{ss} - case {'A', 'B', 'C', 'D', 'diff1', 'diff2', 'sum'} + case {'metab'} ppmmin = 0.2; - case {'ref', 'w','mm'} + case {'ref', 'w','mm','mm_ref'} ppmmin = 0; end - for kk = 1 : MRSCont.nDatasets + for kk = 1 : MRSCont.nDatasets(1) temp_spec = op_freqrange(MRSCont.processed.(SubSpecNames{ss}){kk}, ppmmin, ppmmax); - if ~(strcmp(SubSpecNames{ss},'ref') || strcmp(SubSpecNames{ss},'w')) + if ~(strcmp(SubSpecNames{ss},'ref') || strcmp(SubSpecNames{ss},'w')|| strcmp(SubSpecNames{ss},'mm_ref')) Range(1,kk) = op_findMaxMedian(temp_spec); Range(2,kk) = op_findMinMedian(temp_spec); else diff --git a/utilities/printLog.m b/utilities/printLog.m index 746d9cb5..b150e381 100644 --- a/utilities/printLog.m +++ b/utilities/printLog.m @@ -1,4 +1,4 @@ -function [msg] = printLog(Module,kk,nDatasets,progressText,GUI,MRSI,LCModel) +function [msg] = printLog(Module,kk,ll,nDatasets,progressText,GUI,MRSI,LCModel) %% [MRSCont] = printLog(MRSCont) % This function allows you to rebase your derviatives folder and files in % case you have processed them on another machine @@ -25,44 +25,44 @@ % HISTORY: % 2021-05-06: First version of the code. -if nargin < 7 +if nargin < 8 LCModel = 0; end msg = ''; %% Load if strcmp(Module,'OspreyLoad') - if kk == 1 - msg = sprintf('Loading raw data from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + if kk == 1 && ll ==1 + msg = sprintf('Loading raw data from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); else - msg = sprintf('Loading raw data from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('Loading raw data from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); reverseStr = repmat(sprintf('\b'), 1, length(msg)); fprintf([reverseStr, msg]); end if GUI - set(progressText,'String' ,sprintf('Loading raw data from dataset %d out of %d total datasets...\n', kk, nDatasets)); + set(progressText,'String' ,sprintf('Loading raw data from dataset %d out of %d total datasets...\n', kk, nDatasets(1))); drawnow end end if strcmp(Module,'OspreyLoadWater') - if kk == 1 - msg = sprintf('Loading raw data from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + if kk == 1 && ll ==1 + msg = sprintf('Loading raw water data from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); else - msg = sprintf('Loading raw data from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('Loading raw water data from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); reverseStr = repmat(sprintf('\b'), 1, length(msg)); fprintf([reverseStr, msg]); end if GUI - set(progressText,'String' ,sprintf('Loading raw data from dataset %3i out of %3i total datasets...\n', kk, nDatasets)); + set(progressText,'String' ,sprintf('Loading raw water data from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1))); drawnow end end %% Process if strcmp(Module,'OspreyProcess') && ~MRSI - if kk == 1 + if kk == 1 && ll ==1 msg = sprintf('Processing data from dataset %3i out of %3i total datasets...\n', kk, nDatasets); fprintf(msg); else @@ -91,20 +91,16 @@ end %% Fit if strcmp(Module,'OspreyFit') && ~MRSI - if ~LCModel - msg = sprintf('\nFitting metabolite spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + if kk == 1 + msg = sprintf('Fitting metabolite spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); - else if kk == 1 - msg = sprintf('Fitting metabolite spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets); - fprintf(msg); - else - msg = sprintf('Fitting metabolite spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets); - reverseStr = repmat(sprintf('\b'), 1, length(msg)); - fprintf([reverseStr, msg]); - end + else + msg = sprintf('Fitting metabolite spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); + reverseStr = repmat(sprintf('\b'), 1, length(msg)); + fprintf([reverseStr, msg]); end if GUI - set(progressText,'String' ,sprintf('Fitting metabolite spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets)); + set(progressText,'String' ,sprintf('Fitting metabolite spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1))); drawnow end end @@ -125,10 +121,10 @@ end if strcmp(Module,'OspreyFitRef') && ~MRSI - msg = sprintf('\nFitting water reference spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('\nFitting water reference spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); if GUI - set(progressText,'String' ,sprintf('Fitting water reference spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets)); + set(progressText,'String' ,sprintf('Fitting water reference spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1))); drawnow end end @@ -148,10 +144,10 @@ end if strcmp(Module,'OspreyFitShortTE') && ~MRSI - msg = sprintf('\nFitting short-TE water spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('\nFitting short-TE water spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); if GUI - set(progressText,'String' ,sprintf('Fitting short-TE water spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets)); + set(progressText,'String' ,sprintf('Fitting short-TE water spectra from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1))); drawnow end end @@ -172,40 +168,40 @@ %% Coreg if strcmp(Module,'OspreyCoreg') if kk == 1 - msg = sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); else - msg = sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); reverseStr = repmat(sprintf('\b'), 1, length(msg)); fprintf([reverseStr, msg]); end if GUI - set(progressText,'String' ,sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets)); + set(progressText,'String' ,sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1))); drawnow end end %% Segmentation if strcmp(Module,'OspreySeg') if kk == 1 - msg = sprintf('\nSegmenting structural image from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('\nSegmenting structural image from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); else - msg = sprintf('\nSegmenting structural image from dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('\nSegmenting structural image from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); reverseStr = repmat(sprintf('\b'), 1, length(msg)); fprintf([reverseStr, msg]); end if GUI - set(progressText,'String' ,sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets)); + set(progressText,'String' ,sprintf('Coregistering voxel from dataset %3i out of %3i total datasets...\n', kk, nDatasets(1))); drawnow end end %% Quantification if strcmp(Module,'OspreyQuant') if kk == 1 - msg = sprintf('Quantifying dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('Quantifying dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); fprintf(msg); else - msg = sprintf('Quantifying dataset %3i out of %3i total datasets...\n', kk, nDatasets); + msg = sprintf('Quantifying dataset %3i out of %3i total datasets...\n', kk, nDatasets(1)); reverseStr = repmat(sprintf('\b'), 1, length(msg)); fprintf([reverseStr, msg]); end