From d792649f7cf00c6a3d90e31368d2099161ae4d70 Mon Sep 17 00:00:00 2001 From: Thomas Hiller Date: Thu, 1 Feb 2024 16:42:43 +0100 Subject: [PATCH] see CHANGELOG --- CHANGELOG.md | 11 + NUCLEUSinv/NUCLEUSinv.m | 5 +- NUCLEUSinv/NUCLEUSinv_createGUI.m | 4 +- NUCLEUSinv/NUCLEUSinv_createMenus.m | 3 + .../NUCLEUSinv_createPanelInversionStd.m | 20 + NUCLEUSinv/NUCLEUSinv_createPanelPlots.m | 7 + NUCLEUSinv/NUCLEUSinv_loadDefaults.m | 20 +- NUCLEUSinv/NUCLEUSinv_updateInterface.m | 44 +- NUCLEUSmod/NUCLEUSmod.m | 4 +- README.md | 68 +- callbacks/contextmenus/onContextPlotsRTD.m | 16 + callbacks/listboxes/onListboxData.m | 3 + callbacks/menus/onMenuExpert.m | 8 + callbacks/push/onPushRun.m | 2 + callbacks/radio/onRadioGates.m | 3 + doc/nucleus/NUCLEUSinv/NUCLEUSinv.html | 107 +- .../NUCLEUSinv/NUCLEUSinv_createGUI.html | 4 +- .../NUCLEUSinv/NUCLEUSinv_createMenus.html | 227 +-- .../NUCLEUSinv_createPanelInversionStd.html | 320 +-- .../NUCLEUSinv_createPanelPlots.html | 161 +- .../NUCLEUSinv/NUCLEUSinv_loadDefaults.html | 348 ++-- .../NUCLEUSinv_updateInterface.html | 1742 +++++++++-------- doc/nucleus/NUCLEUSmod/NUCLEUSmod.html | 4 +- .../contextmenus/onContextPlotsRTD.html | 78 +- .../callbacks/listboxes/onListboxData.html | 279 +-- doc/nucleus/callbacks/menus/onMenuExpert.html | 190 +- doc/nucleus/callbacks/menus/onMenuSolver.html | 2 +- doc/nucleus/callbacks/push/onPushRun.html | 72 +- doc/nucleus/callbacks/radio/onRadioGates.html | 147 +- .../functions/interface/UncertView.html | 1585 +++++++++++++++ .../functions/interface/beautifyAxes.html | 2 +- .../functions/interface/clearAllAxes.html | 2 +- .../functions/interface/clearInversion.html | 150 +- .../functions/interface/clearSingleAxis.html | 57 +- .../interface/enableGUIelements.html | 194 +- .../interface/getVersionNoFromString.html | 63 +- .../functions/interface/importASCIIdata.html | 206 +- .../functions/interface/importEXCELdata.html | 206 +- .../functions/interface/importINV2INV.html | 548 ++++-- doc/nucleus/functions/interface/menu.html | 2 +- .../functions/interface/minimizePanel.html | 120 +- .../interface/processNMRDataControl.html | 75 +- .../interface/runInversionBatch.html | 253 ++- .../functions/interface/runInversionStd.html | 482 +++-- .../functions/interface/switchToolTips.html | 2 +- .../functions/interface/updateInfo.html | 948 ++++----- .../interface/updatePlotsDistribution.html | 1085 +++++----- .../updatePlotsDistributionInfo.html | 8 +- .../interface/updatePlotsJointInversion.html | 2 +- .../interface/updatePlotsSignal.html | 796 ++++---- .../inversion/createKernelMatrix.html | 2 +- .../functions/inversion/estimateJacobian.html | 2 +- .../inversion/estimateUncertainty.html | 867 ++++---- .../inversion/fcn_fitMultiModal.html | 2 +- .../functions/inversion/fitDataFree.html | 2 +- .../functions/inversion/fitDataLSQ.html | 195 +- .../functions/inversion/fitDataLUdecomp.html | 14 +- .../inversion/fitDataMultiModal.html | 464 ++--- doc/nucleus/functions/inversion/getAAD.html | 176 ++ .../functions/inversion/getConfInterval.html | 2 +- .../functions/inversion/getFitErrors.html | 2 +- .../functions/inversion/getTLogMean.html | 86 +- doc/nucleus/functions/inversion/menu.html | 2 +- .../inversion/runUncertaintyCalculation.html | 188 ++ externals/kde/kde.m | 145 ++ externals/kde/license.txt | 27 + functions/interface/UncertView.m | 1497 ++++++++++++++ functions/interface/clearInversion.m | 4 + functions/interface/clearSingleAxis.m | 3 + functions/interface/enableGUIelements.m | 32 +- functions/interface/getVersionNoFromString.m | 7 +- functions/interface/importASCIIdata.m | 78 +- functions/interface/importEXCELdata.m | 70 +- functions/interface/importINV2INV.m | 126 +- functions/interface/minimizePanel.m | 58 +- functions/interface/processNMRDataControl.m | 1 + functions/interface/runInversionBatch.m | 25 +- functions/interface/runInversionStd.m | 22 +- functions/interface/switchToolTips.m | 2 +- functions/interface/updateInfo.m | 170 +- functions/interface/updatePlotsDistribution.m | 343 ++-- .../interface/updatePlotsDistributionInfo.m | 8 +- .../interface/updatePlotsJointInversion.m | 2 +- functions/interface/updatePlotsSignal.m | 120 +- functions/inversion/estimateUncertainty.m | 526 ++--- functions/inversion/fitDataLSQ.m | 7 +- functions/inversion/fitDataLUdecomp.m | 2 + functions/inversion/fitDataMultiModal.m | 20 +- functions/inversion/getAAD.m | 102 + functions/inversion/getTLogMean.m | 14 +- .../inversion/runUncertaintyCalculation.m | 115 ++ nucleusinv_gui.png | Bin 124974 -> 129764 bytes nucleusmod_gui.png | Bin 129420 -> 98228 bytes uncertview_gui.png | Bin 0 -> 89408 bytes 94 files changed, 10413 insertions(+), 5802 deletions(-) create mode 100644 doc/nucleus/functions/interface/UncertView.html create mode 100644 doc/nucleus/functions/inversion/getAAD.html create mode 100644 doc/nucleus/functions/inversion/runUncertaintyCalculation.html create mode 100644 externals/kde/kde.m create mode 100644 externals/kde/license.txt create mode 100644 functions/interface/UncertView.m create mode 100644 functions/inversion/getAAD.m create mode 100644 functions/inversion/runUncertaintyCalculation.m create mode 100644 uncertview_gui.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 2274cc9..ad7cd1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [0.2.0] - 2024-02-01 + +### Added +- New functionality to estimate the uncertainty of relaxation time distributions (RTDs) by using a simple bootstrapping method +- New sub GUI *UncertView* in **NUCLEUSinv** to process and evaluate the uncertainty data + +### Fixed + - Fixed an issue when importing **NUCLEUSinv** session files older than version v.0.1.14 (there is a new general *T* field for *mono* and *N free exp. (2-5)* inversion results which was not initialized) +- Several minor improvements in GUI handling, usability and visualization. + ## [0.1.14] - 2023-09-27 ### Added @@ -190,6 +200,7 @@ Initial Version +[0.2.0]: https://github.com/ThoHiller/nmr-nucleus/compare/v.0.1.14...v.0.2.0 [0.1.14]: https://github.com/ThoHiller/nmr-nucleus/compare/v.0.1.13...v.0.1.14 [0.1.13]: https://github.com/ThoHiller/nmr-nucleus/compare/v.0.1.12...v.0.1.13 [0.1.12]: https://github.com/ThoHiller/nmr-nucleus/compare/v.0.1.11...v.0.1.12 diff --git a/NUCLEUSinv/NUCLEUSinv.m b/NUCLEUSinv/NUCLEUSinv.m index 0a0df4d..fa6cea7 100644 --- a/NUCLEUSinv/NUCLEUSinv.m +++ b/NUCLEUSinv/NUCLEUSinv.m @@ -38,8 +38,8 @@ if ~isempty(h0); close(h0); end %% GUI 'header' info and defaults -myui.version = '0.1.14'; -myui.date = '27.09.2023'; +myui.version = '0.2.0'; +myui.date = '01.02.2024'; myui.author = {'Stephan Costabel','Thomas Hiller'}; myui.email = 'thomas.hiller[at]bgr.de'; myui.fontsize = 10; @@ -65,6 +65,7 @@ data.process = defaults.process; data.param = defaults.param; data.invstd = defaults.invstd; +data.uncert = defaults.uncert; data.calib = defaults.calib; data.invjoint = defaults.invjoint; data.pressure = defaults.pressure; diff --git a/NUCLEUSinv/NUCLEUSinv_createGUI.m b/NUCLEUSinv/NUCLEUSinv_createGUI.m index dfd6bca..53f0f81 100644 --- a/NUCLEUSinv/NUCLEUSinv_createGUI.m +++ b/NUCLEUSinv/NUCLEUSinv_createGUI.m @@ -118,11 +118,11 @@ function NUCLEUSinv_createGUI(h,wbon) 'TitleColor',myui.colors.BoxCPS,'ForegroundColor',myui.colors.BoxTitle); % adjust the heights of all left-column-panels -myui.heights = [250 22 22 22 22; -1 109 165 190 299]; +myui.heights = [250 22 22 22 22; -1 109 165 221 299]; % panel header is always 22 high set(gui.panels.main,'Heights',myui.heights(2,:),... 'MinimumHeights',[250 22 22 22 22]); -set(gui.left,'Heights',-1,'MinimumHeights',250+109+22+190+22); +set(gui.left,'Heights',-1,'MinimumHeights',250+109+22+221+22); % 1. data panel if wbon diff --git a/NUCLEUSinv/NUCLEUSinv_createMenus.m b/NUCLEUSinv/NUCLEUSinv_createMenus.m index e132cee..dc10a03 100644 --- a/NUCLEUSinv/NUCLEUSinv_createMenus.m +++ b/NUCLEUSinv/NUCLEUSinv_createMenus.m @@ -315,6 +315,9 @@ % 2.8 FixedTime VIEW gui.menu.extra_fixedtime = uimenu(gui.menu.view,... 'Label','FixedTimeView GUI','Enable','off','Callback',@FixedTimeView); +% 2.9 Uncertainty VIEW +gui.menu.extra_uncert = uimenu(gui.menu.view,... + 'Label','UncertView GUI','Enable','off','Callback',@UncertView); %% 3. Extras gui.menu.extra = uimenu(gui.figh,... diff --git a/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m b/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m index e2dd4ef..ce5aab7 100644 --- a/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m +++ b/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m @@ -54,6 +54,9 @@ % RUN button gui.panels.invstd.HBox6 = uix.HBox('Parent',gui.panels.invstd.VBox,... 'Spacing',3); +% RTD uncertainty +gui.panels.invstd.HBox7 = uix.HBox('Parent',gui.panels.invstd.VBox,... + 'Spacing',3); %% inversion method gui.text_handles.invstd_InvType = uicontrol('Parent',gui.panels.invstd.HBox1,... @@ -168,6 +171,21 @@ 'Tag','std','UserData',1,'Callback',@onPushRun); set(gui.panels.invstd.HBox6,'Widths',[200 -1]); +%% RTD uncertainty +gui.text_handles.uncert = uicontrol('Parent',gui.panels.invstd.HBox7,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','RTD uncertainty | # models'); +tstr = 'Number of uncertainty models to calculate.'; +gui.edit_handles.uncert_N = uicontrol('Parent',gui.panels.invstd.HBox7,... + 'Style','edit','String',num2str(data.uncert.N),... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.uncert.N 1 1]),... + 'Tag','uncert_N','FontSize',myui.fontsize,... + 'Enable','off','Callback',@onEditValue); +gui.push_handles.uncert = uicontrol('Parent',gui.panels.invstd.HBox7,'Enable','off',... + 'String','CALC.','FontSize',myui.fontsize,'BackGroundColor','g',... + 'Tag','uncert','UserData',1,'Callback',@onPushRun); +set(gui.panels.invstd.HBox7,'Widths',[200 -1 -1]); + %% Java Hack to adjust vertical alignment of text fields jh = findjobj(gui.text_handles.invstd_InvType); jh.setVerticalAlignment(javax.swing.JLabel.CENTER); @@ -181,6 +199,8 @@ jh.setVerticalAlignment(javax.swing.JLabel.CENTER); jh = findjobj(gui.text_handles.invstd_run); jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +jh = findjobj(gui.text_handles.uncert); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER); return diff --git a/NUCLEUSinv/NUCLEUSinv_createPanelPlots.m b/NUCLEUSinv/NUCLEUSinv_createPanelPlots.m index f91d292..dcda270 100644 --- a/NUCLEUSinv/NUCLEUSinv_createPanelPlots.m +++ b/NUCLEUSinv/NUCLEUSinv_createPanelPlots.m @@ -155,6 +155,13 @@ gui.cm_handles.axes_rtd_view_cum = uimenu(gui.cm_handles.axes_rtd_view,... 'Label','cum','Tag','view','Callback',@onContextPlotsRTD); set(gui.axes_handles.rtd,'UIContextMenu',gui.cm_handles.axes_rtd); +gui.cm_handles.axes_rtd_uncert = uimenu(gui.cm_handles.axes_rtd,... + 'Label','uncert','Enable','off'); +gui.cm_handles.axes_rtd_uncert_lines = uimenu(gui.cm_handles.axes_rtd_uncert,... + 'Label','lines','Tag','uncert','Checked','on','Callback',@onContextPlotsRTD); +gui.cm_handles.axes_rtd_uncert_patch = uimenu(gui.cm_handles.axes_rtd_uncert,... + 'Label','patch','Tag','uncert','Callback',@onContextPlotsRTD); +set(gui.axes_handles.rtd,'UIContextMenu',gui.cm_handles.axes_rtd); %% 2.2 the PSD panel gui.plots.Dist.PSD.box = uicontainer('Parent',gui.plots.Dist.PSDTab); diff --git a/NUCLEUSinv/NUCLEUSinv_loadDefaults.m b/NUCLEUSinv/NUCLEUSinv_loadDefaults.m index 38b8a15..6eeac62 100644 --- a/NUCLEUSinv/NUCLEUSinv_loadDefaults.m +++ b/NUCLEUSinv/NUCLEUSinv_loadDefaults.m @@ -40,6 +40,8 @@ out.info.RTDflag = 'freq'; out.info.PSDflag = 'freq'; out.info.PSDJflag = 'freq'; +% plot switch for uncertainty line / patch plot +out.info.RTDuncert = 'lines'; % flags indicating expert mode / joint inversion / inversion info / tool % tips out.info.ExpertMode = 'off'; @@ -60,6 +62,8 @@ % re-sampling (gating) of the raw signal 'log' | 'lin' | 'none' % depends on signal type 'T1' or 'T2' out.process.gatetype = 'log'; +% gateing flag for convenience +out.process.isgated = false; % maximum number of echoes per gate out.process.Nechoes = 50; % normalize signal to 1 (no=0, yes=1) @@ -135,12 +139,16 @@ % porosity value between 0 and 1 [-] out.invstd.porosity = 1; -out.invstd.useUncert = 1; -out.invstd.uncertMethod = 'thresh'; -out.invstd.uncertThresh = 0.05; -out.invstd.uncertChi2 = 0.005; -out.invstd.uncertN = 100; -out.invstd.uncertMax = 1e4; +% uncertainty flag (intended for batch use) +out.uncert.use = 1; +% default uncertainty calculation method +out.uncert.Method = 'RMS_bound'; +% uncertaintyx treshold (only need for method 'threshold') +out.uncert.Thresh = 0.05; +% number of uncertainty models to calculate +out.uncert.N = 10; +% number of unsuccesful tries before calculation stops +out.uncert.Max = 1e4; %% joint inversion panel defaults % joint inversion methods to choose 'free' | 'fixed' | 'shape' diff --git a/NUCLEUSinv/NUCLEUSinv_updateInterface.m b/NUCLEUSinv/NUCLEUSinv_updateInterface.m index b47f550..966cf3e 100644 --- a/NUCLEUSinv/NUCLEUSinv_updateInterface.m +++ b/NUCLEUSinv/NUCLEUSinv_updateInterface.m @@ -86,6 +86,11 @@ gui = updateLambda(gui,data.invstd.regtype,0,0,0); gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); gui = updateInvstdTime(gui,data.invstd.invtype,0,0); + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','off',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','off'); % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','off',... @@ -108,6 +113,11 @@ gui = updateLambda(gui,data.invstd.regtype,0,0,0); gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); gui = updateInvstdTime(gui,data.invstd.invtype,0,0); + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','off',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','off'); % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','off',... @@ -148,7 +158,12 @@ gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... data.invstd.Ntime); - + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','on',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','on'); + % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','on',... 'String',num2str(data.invstd.Tbulk)); @@ -180,6 +195,11 @@ gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... data.invstd.Ntime); + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','on',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','on'); % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','on',... @@ -208,6 +228,11 @@ % lambda, smoothness constraint and RTD limits gui = updateLambda(gui,data.invstd.regtype,0,0,0); gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','on',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','on'); % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','on',... @@ -570,6 +595,11 @@ gui = updateLambda(gui,data.invstd.regtype,0,0,0); gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); gui = updateInvstdTime(gui,data.invstd.invtype,0,0); + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','off',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','off'); % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','off',... @@ -586,12 +616,17 @@ 'Value',data.invstd.freeDT,... 'String',{'1','2','3','4','5'}); set(gui.text_handles.invstd_InvTypeOpt,... - 'String','No. of relaxation decay times T'); + 'String','No. of free relaxation times T'); % lambda, smoothness constraint and RTD limits gui = updateLambda(gui,data.invstd.regtype,0,0,0); gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); gui = updateInvstdTime(gui,data.invstd.invtype,0,0); + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','off',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','off'); % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','off',... @@ -631,6 +666,11 @@ 'String',num2str(data.invstd.time(2))); set(gui.edit_handles.invstd_Ntime,'Enable','off',... 'String',num2str(data.invstd.Ntime)); + + % RTD uncertainty + set(gui.edit_handles.uncert_N,'Enable','on',... + 'String',num2str(data.uncert.N)); + set(gui.push_handles.uncert,'Enable','on'); % Tbulk & Tdiff set(gui.edit_handles.invstd_Tbulk,'Enable','on',... diff --git a/NUCLEUSmod/NUCLEUSmod.m b/NUCLEUSmod/NUCLEUSmod.m index 1b1d52a..1db2ee6 100644 --- a/NUCLEUSmod/NUCLEUSmod.m +++ b/NUCLEUSmod/NUCLEUSmod.m @@ -41,8 +41,8 @@ if ~isempty(h0); close(h0); end %% GUI 'header' info and defaults -myui.version = '0.1.14'; -myui.date = '27.09.2023'; +myui.version = '0.2.0'; +myui.date = '01.02.2024'; myui.author = {'Stephan Costabel','Thomas Hiller'}; myui.email = 'thomas.hiller[at]bgr.de'; myui.fontsize = 10; diff --git a/README.md b/README.md index b5c2b44..e752e88 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## NUCLEUS +# NUCLEUS BLOCHUS icon @@ -8,7 +8,7 @@ modeling and i**N**version of n**UCL**ear magnetic r**E**sonance data with ang** [![DOI](https://zenodo.org/badge/165993294.svg)](https://zenodo.org/badge/latestdoi/165993294) - - - -### Table of Contents +## Table of Contents 1. [About](#about) 2. [Requirements](#requirements) 3. [Installation](#installation) @@ -19,12 +19,14 @@ modeling and i**N**version of n**UCL**ear magnetic r**E**sonance data with ang** 8. [Changelog](CHANGELOG.md) - - - + -### About + +## About **NUCLEUS** is a set of MATLABTM tools, that allow forward and inverse modeling of nuclear magnetic resonance (NMR) relaxometry data (T1 and T2 relaxation). The main front-ends to these tools are two graphical user interfaces, **NUCLEUSmod** and **NUCLEUSinv** for forward and inverse modeling, respectively. For simple NMR relaxometry data inversion, the **NUCLEUSinv** GUI may be a little *feature-rich*. But one of the ideas, when starting to develop this code, was to help students understand the basic concepts of NMR relaxometry data inversion. -###### NUCLEUSmod basic features: +### NUCLEUSmod basic features 1. Generate pore size distributions (PSD) that can have a cylindrical, rectangular or polygonal cross section 2. Calculate a capillary pressure saturation curve (CPSC) for the PSD by applying a range of non-zero air pressures (the capillaries are assumed to be water filled and completely water-wet); different saturations for drainage and imbibition conditions are considered @@ -32,43 +34,48 @@ modeling and i**N**version of n**UCL**ear magnetic r**E**sonance data with ang** NUCLEUSmod -###### NUCLEUSinv basic features: + +### NUCLEUSinv basic features 1. Can import **NUCLEUSmod** data (directly from the open GUI or from a saved session file) and a wide range of different laboratory NMR data files (please contact me if you need a specific import routine for your data) 2. Expert mode for more features (Standard mode has basic settings which should be sufficient for most users) 3. Simple pre-processing of NMR signals (cutting, gating, normalizing) -4. Different inversion options to process NMR data (e.g. mono-exponential fit, bi-exponential fit, multi-exponential fit) +4. Different inversion options to process NMR data (e.g. mono-exponential fit, bi-exponential fit, multi-exponential fit) and estimate the uncertainty of the resulting relaxation time distributions (RTDs) 5. Different regularization options for multi-exponential fitting (e.g. manual, L-curve, SVD tools) 6. Joint inversion of NMR and CPS data to directly infer a PSD (non-linear inversion of surface relaxivity and PSD) -NUCLEUSmod - +NUCLEUSinv UncertView - - - + -### Requirements + +## Requirements In order to work properly you need to meet the following requirements: 1. The [Mathworks](https://www.mathworks.com) MATLABTM software development environment (tested with R2014b and newer) - - The Optimization toolbox (optional) - - The Statistics toolbox (optional) + - The Optimization toolbox (optional) + - The Statistics toolbox (optional) 2. The GUI Layout Toolbox (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/47982-gui-layout-toolbox)) (required) 3. The regularization toolbox from P. Hansen (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/52-regtools) or find out more about it [here](http://www.imm.dtu.dk/~pcha/Regutools/)) (required) 4. `findjobj` (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects)) (required) 5. `fminsearchbnd` (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/8277-fminsearchbnd-fminsearchcon)) (required) 6. `dynamicDateTicks` (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/27075-intelligent-dynamic-date-ticks)) (optional) +7. `kde` kernel density estimator (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/14034-kernel-density-estimator)) (optional) -If you do not have the Optimization or Statistics toolboxes then not all features are available (especially parts of the joint inversion). However, the general functionality of obtaining relaxation time distributions (RTD) form NMR relaxometry data is of course working. +If you do not have the Optimization or Statistics toolboxes then not all features are available (especially parts of the joint inversion). However, the general functionality of obtaining relaxation time distributions (RTDs) form NMR relaxometry data is of course working. -#### Operating System +### Operating System I tested it successfully under Windows 7 (64bit) and 10 (64bit) with Matlab R2016b and newer. Always with the latest version of the GUI Layout Toolbox (current version is afaik v2.3.6) **NOTE:** So far I did not test anything on Linux or a Mac. If you get it to work on either of the two systems (which it basically should I guess) please let me know. - - - + -### Installation + +## Installation 1. It is recommended to install the GUI Layout Toolbox directly into MATLABTM via the mltbx-file (but it should also work via the old-school way of adding the toolbox folders to the MATLABTM path) 2. To use **NUCLEUS** you just need to place the `nucleus` folder from the git repository on your hard drive and use the start scripts `startNUCLEUSinv` and `startNUCLEUSmod`, respectively (within these scripts all necessary **NUCLEUS** folders are added to the MATLABTM path) @@ -76,49 +83,58 @@ I tested it successfully under Windows 7 (64bit) and 10 (64bit) with Matlab R201 **NOTE:** It is recommended to have only *one* version of **NUCLEUS** on your current MATLABTM path. - - - + -### Usage + +## Usage 1. By executing the start scripts (see above) 2. Simply type `NUCLEUSinv` or `NUCLEUSmod` on the MATLABTM prompt (make sure the `nucleus` folder is on the MATLABTM path) 3. Check the demo scripts for the usage of the core functions without the GUI (inside the `scripts` folder) - - - + -### Documentation + +## Documentation A basic documentation to **NUCLEUS** can be found in the `nucleus\doc` folder. Just open the `index.html` in the web browser of your choice. The documentation was created with [m2html](https://www.artefact.tk/software/matlab/m2html/) by Guillaume Flandin. - - - + -### TODO + +## TODO In no particular order and without guarantee that it will ever happen :-) : 1. A Manual (this is on top of my agenda) 2. Adapt the core functionality in a Python module 3. NUCLEUSinv: - - An import wizard to get rid of the import menu - - Easy way to set optimization settings - - For noise estimation: select manually a range of the NMR raw signal + - An import wizard to get rid of the import menu + - Easy way to set optimization settings + - For noise estimation: select manually a range of the NMR raw signal 4. ... - - - + -### Cite as + +## Cite as If you use NUCLEUS for your research, please cite it as: -Thomas Hiller. (2023, Sep 27). ThoHiller/nmr-nucleus: v0.1.14 (Version v0.1.14). Zenodo. [https://doi.org/10.5281/zenodo.4022195] +Thomas Hiller. (2024, Feb 01). ThoHiller/nmr-nucleus: v0.2.0 (Version v0.2.0). Zenodo. [https://doi.org/10.5281/zenodo.4022195] Note: Even though the version number might change due to updates, this DOI is permanent (represents all versions) and always links to the latest version. -### References +## References 1. Costabel, S., Hiller, T. and Houben, G. "Nuclear magnetic resonance at the laboratory and field scale as a tool for detecting redox fronts in aquifers", *GEOPHYSICS*, **88**(2), 2023, KS13-KS25, [DOI](https://doi.org/10.1190/geo2022-0127.1) 2. Costabel, S., Hiller, T., Dlugosch, R., Kruschwitz, S. and Müller-Petke, M. "Evaluation of single-sided nuclear magnetic resonance technology for usage in geosciences", *Measurement Science and Technology*, **34**(1), 2023, 015112, [DOI](https://dx.doi.org/10.1088/1361-6501/ac9800) -1. Hiller, T., Costabel, S., Radic, T., Dlugosch, R. and Müller-Petke, M. "Feasibility study on prepolarized surface nuclear magnetic resonance for soil moisture measurements", *Vadose Zone Journal*, **20**(5), 2021, e20138, [DOI](https://doi.org/10.1002/vzj2.20138) -2. Costabel, S. and Hiller, T., "Soil hydraulic interpretation of nuclear magnetic resonance measurements based on circular and triangular capillary models", *Vadose Zone Journal*, **20**(2), 2021, e20104, [DOI](https://doi.org/10.1002/vzj2.20104) -3. Hiller, T. and Klitzsch, N., "Joint inversion of nuclear magnetic resonance data from partially saturated rocks using a triangular pore model", *GEOPHYSICS*, **83**(4), JM15-JM28, 2018, [DOI](https://doi.org/10.1190/geo2017-0697.1) +3. Hiller, T., Costabel, S., Radic, T., Dlugosch, R. and Müller-Petke, M. "Feasibility study on prepolarized surface nuclear magnetic resonance for soil moisture measurements", *Vadose Zone Journal*, **20**(5), 2021, e20138, [DOI](https://doi.org/10.1002/vzj2.20138) +4. Costabel, S. and Hiller, T., "Soil hydraulic interpretation of nuclear magnetic resonance measurements based on circular and triangular capillary models", *Vadose Zone Journal*, **20**(2), 2021, e20104, [DOI](https://doi.org/10.1002/vzj2.20104) +5. Hiller, T. and Klitzsch, N., "Joint inversion of nuclear magnetic resonance data from partially saturated rocks using a triangular pore model", *GEOPHYSICS*, **83**(4), JM15-JM28, 2018, [DOI](https://doi.org/10.1190/geo2017-0697.1) - - - +

MATLAB is a registered trademark of The Mathworks, Inc.

\ No newline at end of file diff --git a/callbacks/contextmenus/onContextPlotsRTD.m b/callbacks/contextmenus/onContextPlotsRTD.m index 91ec38d..a308766 100644 --- a/callbacks/contextmenus/onContextPlotsRTD.m +++ b/callbacks/contextmenus/onContextPlotsRTD.m @@ -58,6 +58,22 @@ function onContextPlotsRTD(src,~) setappdata(fig,'gui',gui); % update the plot axes updatePlotsDistribution; + case 'uncert' + data.info.RTDuncert = label; + switch label + case 'lines' + set(src,'Checked','on'); + set(gui.cm_handles.axes_rtd_uncert_patch,'Checked','off'); + case 'patch' + set(src,'Checked','on'); + set(gui.cm_handles.axes_rtd_uncert_lines,'Checked','off'); + end + % update the GUI data + setappdata(fig,'data',data); + setappdata(fig,'gui',gui); + % update the plot axes + updatePlotsSignal; + updatePlotsDistribution; otherwise disp('onContextPlotsRTD: something is utterly wrong.'); end diff --git a/callbacks/listboxes/onListboxData.m b/callbacks/listboxes/onListboxData.m index 1adc6b3..a60aa15 100644 --- a/callbacks/listboxes/onListboxData.m +++ b/callbacks/listboxes/onListboxData.m @@ -99,6 +99,7 @@ function onListboxData(src,~) data = removeInversionFields(data); % set format and T1/T2 dependent GUI elements + data.process.isgated = false; switch data.import.NMR.data{id}.flag case 'T1' data.process.gatetype = 'raw'; @@ -177,6 +178,8 @@ function onListboxData(src,~) % clear inversion axes clearSingleAxis(gui.axes_handles.rtd); clearSingleAxis(gui.axes_handles.psd); + % switch-off uncert context menu + set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); end % set focus on data diff --git a/callbacks/menus/onMenuExpert.m b/callbacks/menus/onMenuExpert.m index f7505cf..53273b3 100644 --- a/callbacks/menus/onMenuExpert.m +++ b/callbacks/menus/onMenuExpert.m @@ -66,6 +66,12 @@ function onMenuExpert(src,~) delete(fig_fixedtime); end set(gui.menu.extra_fixedtime,'Enable','off'); + % check if the figure is already open + fig_uncert = findobj('Tag','UNCERTVIEW'); + if ~isempty(fig_uncert) + delete(fig_uncert); + end + set(gui.menu.extra_uncert,'Enable','off'); % deactivate solver menu and set to default onMenuSolver(gui.menu.extra_solver_lsqnonneg); @@ -101,6 +107,8 @@ function onMenuExpert(src,~) % activate FixedTime View GUI set(gui.menu.extra_fixedtime,'Enable','on'); + % activate Uncertainty View GUI + set(gui.menu.extra_uncert,'Enable','on'); % activate solver menu if optimization toolbox is available switch data.info.has_optim diff --git a/callbacks/push/onPushRun.m b/callbacks/push/onPushRun.m index 8ad7eb4..e136561 100644 --- a/callbacks/push/onPushRun.m +++ b/callbacks/push/onPushRun.m @@ -47,6 +47,8 @@ function onPushRun(src,~) runInversionStd; case 'joint' runInversionJoint; + case 'uncert' + runUncertaintyCalculation; end case 'MOD' tag = get(src,'Tag'); diff --git a/callbacks/radio/onRadioGates.m b/callbacks/radio/onRadioGates.m index 51404ec..00676af 100644 --- a/callbacks/radio/onRadioGates.m +++ b/callbacks/radio/onRadioGates.m @@ -50,12 +50,15 @@ function onRadioGates(src,~) % change settings depending on the chosen radio button % for gated signals the lambda value is generally smaller % (just a rule of thumb) + data.process.isgated = false; switch str case 'log' + data.process.isgated = true; data.process.gatetype = 'log'; lambdaFAK = 100; case 'lin' + data.process.isgated = true; data.process.gatetype = 'lin'; lambdaFAK = 100; diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv.html index 84214d8..0ac7368 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv.html @@ -111,8 +111,8 @@

SOURCE CODE ^if ~isempty(h0); close(h0); end 0039 0040 %% GUI 'header' info and defaults -0041 myui.version = '0.1.14'; -0042 myui.date = '27.09.2023'; +0041 myui.version = '0.2.0'; +0042 myui.date = '01.02.2024'; 0043 myui.author = {'Stephan Costabel','Thomas Hiller'}; 0044 myui.email = 'thomas.hiller[at]bgr.de'; 0045 myui.fontsize = 10; @@ -138,57 +138,58 @@

SOURCE CODE ^%% Check toolbox availability -0074 % check if the Optimization & Statistics Toolbox are available -0075 % if not then alternative routines will be used -0076 Mver = ver; -0077 for i = 1:size(Mver,2) -0078 if strcmp(Mver(i).Name,'Optimization Toolbox') -0079 data.info.has_optim = 'on'; -0080 end -0081 if strfind(Mver(i).Name,'Statistics') -0082 data.info.stat = 'on'; -0083 end -0084 end -0085 -0086 % save the data struct within the GUI -0087 setappdata(gui.figh,'data',data); -0088 setappdata(gui.figh,'gui',gui); -0089 -0090 %% Create GUI elements -0091 NUCLEUSinv_createGUI(gui.figh,1); -0092 -0093 end -0094 -0095 %------------- END OF CODE -------------- -0096 -0097 %% License: -0098 % MIT License -0099 % -0100 % Copyright (c) 2018 Thomas Hiller -0101 % -0102 % Permission is hereby granted, free of charge, to any person obtaining a copy -0103 % of this software and associated documentation files (the "Software"), to deal -0104 % in the Software without restriction, including without limitation the rights -0105 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0106 % copies of the Software, and to permit persons to whom the Software is -0107 % furnished to do so, subject to the following conditions: -0108 % -0109 % The above copyright notice and this permission notice shall be included in all -0110 % copies or substantial portions of the Software. -0111 % -0112 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0113 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0114 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0115 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0116 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0117 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0118 % SOFTWARE. +0068 data.uncert = defaults.uncert; +0069 data.calib = defaults.calib; +0070 data.invjoint = defaults.invjoint; +0071 data.pressure = defaults.pressure; +0072 gui.myui = myui; +0073 +0074 %% Check toolbox availability +0075 % check if the Optimization & Statistics Toolbox are available +0076 % if not then alternative routines will be used +0077 Mver = ver; +0078 for i = 1:size(Mver,2) +0079 if strcmp(Mver(i).Name,'Optimization Toolbox') +0080 data.info.has_optim = 'on'; +0081 end +0082 if strfind(Mver(i).Name,'Statistics') +0083 data.info.stat = 'on'; +0084 end +0085 end +0086 +0087 % save the data struct within the GUI +0088 setappdata(gui.figh,'data',data); +0089 setappdata(gui.figh,'gui',gui); +0090 +0091 %% Create GUI elements +0092 NUCLEUSinv_createGUI(gui.figh,1); +0093 +0094 end +0095 +0096 %------------- END OF CODE -------------- +0097 +0098 %% License: +0099 % MIT License +0100 % +0101 % Copyright (c) 2018 Thomas Hiller +0102 % +0103 % Permission is hereby granted, free of charge, to any person obtaining a copy +0104 % of this software and associated documentation files (the "Software"), to deal +0105 % in the Software without restriction, including without limitation the rights +0106 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0107 % copies of the Software, and to permit persons to whom the Software is +0108 % furnished to do so, subject to the following conditions: +0109 % +0110 % The above copyright notice and this permission notice shall be included in all +0111 % copies or substantial portions of the Software. +0112 % +0113 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0114 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0115 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0116 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0117 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0118 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0119 % SOFTWARE.
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createGUI.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createGUI.html index a7f0549..cb38a92 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createGUI.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createGUI.html @@ -200,11 +200,11 @@

SOURCE CODE ^'TitleColor',myui.colors.BoxCPS,'ForegroundColor',myui.colors.BoxTitle); 0119 0120 % adjust the heights of all left-column-panels -0121 myui.heights = [250 22 22 22 22; -1 109 165 190 299]; +0121 myui.heights = [250 22 22 22 22; -1 109 165 221 299]; 0122 % panel header is always 22 high 0123 set(gui.panels.main,'Heights',myui.heights(2,:),... 0124 'MinimumHeights',[250 22 22 22 22]); -0125 set(gui.left,'Heights',-1,'MinimumHeights',250+109+22+190+22); +0125 set(gui.left,'Heights',-1,'MinimumHeights',250+109+22+221+22); 0126 0127 % 1. data panel 0128 if wbon diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createMenus.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createMenus.html index fd8a866..1a2745b 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createMenus.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createMenus.html @@ -59,7 +59,7 @@

DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

This function calls: +
  • onMenuExpert handles the call from the menu that activates / deactivates
  • onMenuExportData handles the calls from the export menu
  • onMenuExportGraphics handles the graphics export menu and calls the export
  • onMenuExtraColor handles the color theme menu of both GUIs
  • onMenuExtraRhoBounds sets inversion bounds for the surface relaxivity
  • onMenuHelp shows the Help Information for both GUIs
  • onMenuImport handles the import menu entries
  • onMenuJointInversion handles the call from the menu that activates / deactivates
  • onMenuRestartQuit restarts or closes the GUIs
  • onMenuSolver handles the call from the menu that allows to choose the LSQ
  • onMenuView handles the view menu entries
  • onMenuViewFigures handles the extra menu entries to show additional
  • FixedTimeView is an extra subGUI to fix certain relaxation times during
  • PhaseView is an extra subGUI to visualize the phase of a T2 signal
  • UncertView is an extra subGUI to show results of the uncertainty
  • This function is called by: @@ -385,119 +385,122 @@

    SOURCE CODE ^% 2.8 FixedTime VIEW 0316 gui.menu.extra_fixedtime = uimenu(gui.menu.view,... 0317 'Label','FixedTimeView GUI','Enable','off','Callback',@FixedTimeView); -0318 -0319 %% 3. Extras -0320 gui.menu.extra = uimenu(gui.figh,... -0321 'Label','Extra','Enable','off'); -0322 -0323 % 3.1 expert mode (on/off) -0324 gui.menu.extra_expert = uimenu(gui.menu.extra,... -0325 'Label','Expert Mode','Callback',@onMenuExpert); -0326 switch gui.myui.inidata.expertmode -0327 case 'on' -0328 set(gui.menu.extra_expert,'Checked','on'); -0329 case 'off' -0330 set(gui.menu.extra_expert,'Checked','of'); -0331 end -0332 -0333 % 3.2 optimization toolbox (on/off) -0334 switch gui.myui.inidata.expertmode -0335 case 'on' -0336 switch data.info.has_optim -0337 case 'on' -0338 gui.menu.extra_solver = uimenu(gui.menu.extra,... -0339 'Label','LSQ Solver','Enable','on'); -0340 case 'off' +0318 % 2.9 Uncertainty VIEW +0319 gui.menu.extra_uncert = uimenu(gui.menu.view,... +0320 'Label','UncertView GUI','Enable','off','Callback',@UncertView); +0321 +0322 %% 3. Extras +0323 gui.menu.extra = uimenu(gui.figh,... +0324 'Label','Extra','Enable','off'); +0325 +0326 % 3.1 expert mode (on/off) +0327 gui.menu.extra_expert = uimenu(gui.menu.extra,... +0328 'Label','Expert Mode','Callback',@onMenuExpert); +0329 switch gui.myui.inidata.expertmode +0330 case 'on' +0331 set(gui.menu.extra_expert,'Checked','on'); +0332 case 'off' +0333 set(gui.menu.extra_expert,'Checked','of'); +0334 end +0335 +0336 % 3.2 optimization toolbox (on/off) +0337 switch gui.myui.inidata.expertmode +0338 case 'on' +0339 switch data.info.has_optim +0340 case 'on' 0341 gui.menu.extra_solver = uimenu(gui.menu.extra,... -0342 'Label','LSQ Solver','Enable','off'); -0343 end -0344 case 'off' -0345 gui.menu.extra_solver = uimenu(gui.menu.extra,... -0346 'Label','LSQ Solver','Enable','off'); -0347 end -0348 gui.menu.extra_solver_lsqlin = uimenu(gui.menu.extra_solver,... -0349 'Label','LSQLIN (Optim. TB)','Callback',@onMenuSolver); -0350 gui.menu.extra_solver_lsqnonneg = uimenu(gui.menu.extra_solver,... -0351 'Label','LSQNONNEG (default)','Checked','on','Callback',@onMenuSolver); -0352 -0353 % 3.3 joint inversion (on/off) -0354 gui.menu.extra_joint = uimenu(gui.menu.extra,... -0355 'Label','Joint Inversion','Checked','off','Separator','on',... -0356 'Callback',@onMenuJointInversion); -0357 switch gui.myui.inidata.expertmode -0358 case 'on' -0359 set(gui.menu.extra_joint,'Enable','on'); -0360 case 'off' -0361 set(gui.menu.extra_joint,'Enable','off'); -0362 end -0363 -0364 % 3.4 set inversion bounds for surface relaxivity rho -0365 gui.menu.extra_joint_rhobounds = uimenu(gui.menu.extra,... -0366 'Label','Surface relaxivity bounds','Enable','off',... -0367 'Callback',@onMenuExtraRhoBounds); -0368 -0369 -0370 %% 4. Color theme -0371 gui.menu.color_theme = uimenu(gui.figh,... -0372 'Label','Color Theme','Enable','off'); -0373 -0374 % 4.1 default color theme -0375 gui.menu.color_theme_standard = uimenu(gui.menu.color_theme,... -0376 'Label','standard','Callback',@onMenuExtraColor); -0377 % 4.2 basic color theme -0378 gui.menu.color_theme_basic = uimenu(gui.menu.color_theme,... -0379 'Label','basic','Callback',@onMenuExtraColor); -0380 % 4.3 dark color theme -0381 gui.menu.color_theme_dark = uimenu(gui.menu.color_theme,... -0382 'Label','dark','Callback',@onMenuExtraColor); -0383 % 4.4 black color theme -0384 gui.menu.color_theme_black = uimenu(gui.menu.color_theme,... -0385 'Label','black','Callback',@onMenuExtraColor); -0386 switch gui.myui.inidata.colortheme -0387 case 'standard' -0388 set(gui.menu.color_theme_standard,'Checked','on'); -0389 case 'basic' -0390 set(gui.menu.color_theme_basic,'Checked','on'); -0391 case 'dark' -0392 set(gui.menu.color_theme_dark,'Checked','on'); -0393 case 'black' -0394 set(gui.menu.color_theme_black,'Checked','on'); -0395 end -0396 -0397 %% 5. Help -0398 gui.menu.help = uimenu(gui.figh,... -0399 'Label','Help','Enable','off'); -0400 -0401 % 5.1 About -0402 gui.menu.help_about = uimenu(gui.menu.help,... -0403 'Label','About','Callback',@onMenuHelp); -0404 -0405 return -0406 -0407 %------------- END OF CODE -------------- -0408 -0409 %% License: -0410 % MIT License -0411 % -0412 % Copyright (c) 2018 Thomas Hiller -0413 % -0414 % Permission is hereby granted, free of charge, to any person obtaining a copy -0415 % of this software and associated documentation files (the "Software"), to deal -0416 % in the Software without restriction, including without limitation the rights -0417 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0418 % copies of the Software, and to permit persons to whom the Software is -0419 % furnished to do so, subject to the following conditions: -0420 % -0421 % The above copyright notice and this permission notice shall be included in all -0422 % copies or substantial portions of the Software. +0342 'Label','LSQ Solver','Enable','on'); +0343 case 'off' +0344 gui.menu.extra_solver = uimenu(gui.menu.extra,... +0345 'Label','LSQ Solver','Enable','off'); +0346 end +0347 case 'off' +0348 gui.menu.extra_solver = uimenu(gui.menu.extra,... +0349 'Label','LSQ Solver','Enable','off'); +0350 end +0351 gui.menu.extra_solver_lsqlin = uimenu(gui.menu.extra_solver,... +0352 'Label','LSQLIN (Optim. TB)','Callback',@onMenuSolver); +0353 gui.menu.extra_solver_lsqnonneg = uimenu(gui.menu.extra_solver,... +0354 'Label','LSQNONNEG (default)','Checked','on','Callback',@onMenuSolver); +0355 +0356 % 3.3 joint inversion (on/off) +0357 gui.menu.extra_joint = uimenu(gui.menu.extra,... +0358 'Label','Joint Inversion','Checked','off','Separator','on',... +0359 'Callback',@onMenuJointInversion); +0360 switch gui.myui.inidata.expertmode +0361 case 'on' +0362 set(gui.menu.extra_joint,'Enable','on'); +0363 case 'off' +0364 set(gui.menu.extra_joint,'Enable','off'); +0365 end +0366 +0367 % 3.4 set inversion bounds for surface relaxivity rho +0368 gui.menu.extra_joint_rhobounds = uimenu(gui.menu.extra,... +0369 'Label','Surface relaxivity bounds','Enable','off',... +0370 'Callback',@onMenuExtraRhoBounds); +0371 +0372 +0373 %% 4. Color theme +0374 gui.menu.color_theme = uimenu(gui.figh,... +0375 'Label','Color Theme','Enable','off'); +0376 +0377 % 4.1 default color theme +0378 gui.menu.color_theme_standard = uimenu(gui.menu.color_theme,... +0379 'Label','standard','Callback',@onMenuExtraColor); +0380 % 4.2 basic color theme +0381 gui.menu.color_theme_basic = uimenu(gui.menu.color_theme,... +0382 'Label','basic','Callback',@onMenuExtraColor); +0383 % 4.3 dark color theme +0384 gui.menu.color_theme_dark = uimenu(gui.menu.color_theme,... +0385 'Label','dark','Callback',@onMenuExtraColor); +0386 % 4.4 black color theme +0387 gui.menu.color_theme_black = uimenu(gui.menu.color_theme,... +0388 'Label','black','Callback',@onMenuExtraColor); +0389 switch gui.myui.inidata.colortheme +0390 case 'standard' +0391 set(gui.menu.color_theme_standard,'Checked','on'); +0392 case 'basic' +0393 set(gui.menu.color_theme_basic,'Checked','on'); +0394 case 'dark' +0395 set(gui.menu.color_theme_dark,'Checked','on'); +0396 case 'black' +0397 set(gui.menu.color_theme_black,'Checked','on'); +0398 end +0399 +0400 %% 5. Help +0401 gui.menu.help = uimenu(gui.figh,... +0402 'Label','Help','Enable','off'); +0403 +0404 % 5.1 About +0405 gui.menu.help_about = uimenu(gui.menu.help,... +0406 'Label','About','Callback',@onMenuHelp); +0407 +0408 return +0409 +0410 %------------- END OF CODE -------------- +0411 +0412 %% License: +0413 % MIT License +0414 % +0415 % Copyright (c) 2018 Thomas Hiller +0416 % +0417 % Permission is hereby granted, free of charge, to any person obtaining a copy +0418 % of this software and associated documentation files (the "Software"), to deal +0419 % in the Software without restriction, including without limitation the rights +0420 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0421 % copies of the Software, and to permit persons to whom the Software is +0422 % furnished to do so, subject to the following conditions: 0423 % -0424 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0425 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0426 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0427 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0428 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0429 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0430 % SOFTWARE. +0424 % The above copyright notice and this permission notice shall be included in all +0425 % copies or substantial portions of the Software. +0426 % +0427 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0428 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0429 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0430 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0431 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0432 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0433 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.html index 4789d6b..9614092 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.html @@ -126,160 +126,180 @@

    SOURCE CODE ^% RUN button 0055 gui.panels.invstd.HBox6 = uix.HBox('Parent',gui.panels.invstd.VBox,... 0056 'Spacing',3); -0057 -0058 %% inversion method -0059 gui.text_handles.invstd_InvType = uicontrol('Parent',gui.panels.invstd.HBox1,... -0060 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... -0061 'String','inversion method'); -0062 switch data.info.ExpertMode -0063 case 'on' -0064 tstr = ' '; -0065 istring = {'Mono exp.','N free exp. (2-5)','Multi exp. (LSQ)','Multi exp. (LU decomp.)','Multi modal'}; -0066 case 'off' +0057 % RTD uncertainty +0058 gui.panels.invstd.HBox7 = uix.HBox('Parent',gui.panels.invstd.VBox,... +0059 'Spacing',3); +0060 +0061 %% inversion method +0062 gui.text_handles.invstd_InvType = uicontrol('Parent',gui.panels.invstd.HBox1,... +0063 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0064 'String','inversion method'); +0065 switch data.info.ExpertMode +0066 case 'on' 0067 tstr = ' '; -0068 istring = {'Mono exp.','N free exp. (2-5)','Multi exp. (LSQ)'}; -0069 end -0070 gui.popup_handles.invstd_InvType = uicontrol('Parent',gui.panels.invstd.HBox1,... -0071 'Style','popup','String',istring,'FontSize',myui.fontsize,'Enable','off','Value',3,... -0072 'UserData',struct('Tooltipstr',tstr),'Callback',@onPopupInvstdType); -0073 set(gui.panels.invstd.HBox1,'Widths',[200 -1]); -0074 -0075 %% min and max values of relaxation time distribution -0076 gui.text_handles.invstd_RTDtimes = uicontrol('Parent',gui.panels.invstd.HBox2,... -0077 'Style','text','FontSize',myui.fontsize,'String','RTD - min [s] | max [s] | # / dec'); -0078 tstr = 'Lower bound of relaxation time spectra.'; -0079 gui.edit_handles.invstd_time_min = uicontrol('Parent',gui.panels.invstd.HBox2,... -0080 'Style','edit','String',num2str(data.invstd.time(1,1)),'FontSize',myui.fontsize,... -0081 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.time(1,1) 1 1]),... -0082 'Tag','invstd_time','Enable','off','Callback',@onEditValue); -0083 tstr = 'Upper bound of relaxation time spectra.'; -0084 gui.edit_handles.invstd_time_max = uicontrol('Parent',gui.panels.invstd.HBox2,... -0085 'Style','edit','String',num2str(data.invstd.time(1,2)),'FontSize',myui.fontsize,... -0086 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.time(1,2) 1 2]),... -0087 'Tag','invstd_time','Enable','off','Callback',@onEditValue); -0088 tstr = 'Number of steps per decade.'; -0089 gui.edit_handles.invstd_Ntime = uicontrol('Parent',gui.panels.invstd.HBox2,... -0090 'Style','edit','String',num2str(data.invstd.Ntime),'FontSize',myui.fontsize,... -0091 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.Ntime 1 1]),... -0092 'Tag','invstd_Ntime','Enable','off','Callback',@onEditValue); -0093 set(gui.panels.invstd.HBox2,'Widths',[200 -1 -1 -1]); -0094 -0095 %% optional inversion settings depending on inversion type -0096 gui.text_handles.invstd_InvTypeOpt = uicontrol('Parent',gui.panels.invstd.HBox3,... -0097 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... -0098 'String','regularization options'); -0099 switch data.info.ExpertMode -0100 case 'on' -0101 tstr = ' '; -0102 rstring = {'Manual','Tikhonov (SVD)','TSVD (SVD)',... -0103 'DSVD (SVD)','Discrep. (SVD)','L-curve'}; -0104 case 'off' -0105 tstr = ' '; -0106 rstring = {'Manual','L-curve'}; -0107 end -0108 gui.popup_handles.invstd_InvTypeOpt = uicontrol('Parent',gui.panels.invstd.HBox3,... -0109 'Style','popup','String',rstring,'FontSize',myui.fontsize,'Enable','off','Value',1,... -0110 'UserData',struct('Tooltipstr',tstr),'Callback',@onPopupInvstdTypeOptional); -0111 set(gui.panels.invstd.HBox3,'Widths',[200 -1]); -0112 -0113 %% smoothness constraint / order of regularized solution -0114 gui.text_handles.invstd_Lorder = uicontrol('Parent',gui.panels.invstd.HBox4,... -0115 'Style','text','FontSize',myui.fontsize,... -0116 'HorizontalAlignment','center','String','smoothness constraint (L-order)'); -0117 tstr = ['<HTML>Choose the smoothness constraint for the multi-exponential fitting routines.<br><br>',... -0118 '<u>Available options:</u><br>',... -0119 '<font color="red">Mono exp. | Several free exp. (2-5):<br>',... -0120 '<font color="black"><b>none</b><br>',... -0121 '<font color="red">Multi exp. (LSQ) | Multi exp. (LU decomp.):<br>',... -0122 '<font color="black">',... -0123 '<b>0</b> Zeroth-order smoothness constraint.<br>',... -0124 '<b>1</b> First-order smoothness constraint.<br>',... -0125 '<b>2</b> Second-order smoothness constraint.<br><br>',... -0126 '<u>Default value:</u><br>',... -0127 '<b>1</b><br>']; -0128 gui.radio_handles.invstd_Lorder0 = uicontrol('Parent',gui.panels.invstd.HBox4,... -0129 'Style','radiobutton','String','0','Tag','invstd','FontSize',myui.fontsize,... -0130 'UserData',struct('Tooltipstr',tstr),'Enable','off','Callback',@onRadioLorder); -0131 gui.radio_handles.invstd_Lorder1 = uicontrol('Parent',gui.panels.invstd.HBox4,... -0132 'Style','radiobutton','String','1','Tag','invstd','FontSize',myui.fontsize,... +0068 istring = {'Mono exp.','N free exp. (2-5)','Multi exp. (LSQ)','Multi exp. (LU decomp.)','Multi modal'}; +0069 case 'off' +0070 tstr = ' '; +0071 istring = {'Mono exp.','N free exp. (2-5)','Multi exp. (LSQ)'}; +0072 end +0073 gui.popup_handles.invstd_InvType = uicontrol('Parent',gui.panels.invstd.HBox1,... +0074 'Style','popup','String',istring,'FontSize',myui.fontsize,'Enable','off','Value',3,... +0075 'UserData',struct('Tooltipstr',tstr),'Callback',@onPopupInvstdType); +0076 set(gui.panels.invstd.HBox1,'Widths',[200 -1]); +0077 +0078 %% min and max values of relaxation time distribution +0079 gui.text_handles.invstd_RTDtimes = uicontrol('Parent',gui.panels.invstd.HBox2,... +0080 'Style','text','FontSize',myui.fontsize,'String','RTD - min [s] | max [s] | # / dec'); +0081 tstr = 'Lower bound of relaxation time spectra.'; +0082 gui.edit_handles.invstd_time_min = uicontrol('Parent',gui.panels.invstd.HBox2,... +0083 'Style','edit','String',num2str(data.invstd.time(1,1)),'FontSize',myui.fontsize,... +0084 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.time(1,1) 1 1]),... +0085 'Tag','invstd_time','Enable','off','Callback',@onEditValue); +0086 tstr = 'Upper bound of relaxation time spectra.'; +0087 gui.edit_handles.invstd_time_max = uicontrol('Parent',gui.panels.invstd.HBox2,... +0088 'Style','edit','String',num2str(data.invstd.time(1,2)),'FontSize',myui.fontsize,... +0089 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.time(1,2) 1 2]),... +0090 'Tag','invstd_time','Enable','off','Callback',@onEditValue); +0091 tstr = 'Number of steps per decade.'; +0092 gui.edit_handles.invstd_Ntime = uicontrol('Parent',gui.panels.invstd.HBox2,... +0093 'Style','edit','String',num2str(data.invstd.Ntime),'FontSize',myui.fontsize,... +0094 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.Ntime 1 1]),... +0095 'Tag','invstd_Ntime','Enable','off','Callback',@onEditValue); +0096 set(gui.panels.invstd.HBox2,'Widths',[200 -1 -1 -1]); +0097 +0098 %% optional inversion settings depending on inversion type +0099 gui.text_handles.invstd_InvTypeOpt = uicontrol('Parent',gui.panels.invstd.HBox3,... +0100 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0101 'String','regularization options'); +0102 switch data.info.ExpertMode +0103 case 'on' +0104 tstr = ' '; +0105 rstring = {'Manual','Tikhonov (SVD)','TSVD (SVD)',... +0106 'DSVD (SVD)','Discrep. (SVD)','L-curve'}; +0107 case 'off' +0108 tstr = ' '; +0109 rstring = {'Manual','L-curve'}; +0110 end +0111 gui.popup_handles.invstd_InvTypeOpt = uicontrol('Parent',gui.panels.invstd.HBox3,... +0112 'Style','popup','String',rstring,'FontSize',myui.fontsize,'Enable','off','Value',1,... +0113 'UserData',struct('Tooltipstr',tstr),'Callback',@onPopupInvstdTypeOptional); +0114 set(gui.panels.invstd.HBox3,'Widths',[200 -1]); +0115 +0116 %% smoothness constraint / order of regularized solution +0117 gui.text_handles.invstd_Lorder = uicontrol('Parent',gui.panels.invstd.HBox4,... +0118 'Style','text','FontSize',myui.fontsize,... +0119 'HorizontalAlignment','center','String','smoothness constraint (L-order)'); +0120 tstr = ['<HTML>Choose the smoothness constraint for the multi-exponential fitting routines.<br><br>',... +0121 '<u>Available options:</u><br>',... +0122 '<font color="red">Mono exp. | Several free exp. (2-5):<br>',... +0123 '<font color="black"><b>none</b><br>',... +0124 '<font color="red">Multi exp. (LSQ) | Multi exp. (LU decomp.):<br>',... +0125 '<font color="black">',... +0126 '<b>0</b> Zeroth-order smoothness constraint.<br>',... +0127 '<b>1</b> First-order smoothness constraint.<br>',... +0128 '<b>2</b> Second-order smoothness constraint.<br><br>',... +0129 '<u>Default value:</u><br>',... +0130 '<b>1</b><br>']; +0131 gui.radio_handles.invstd_Lorder0 = uicontrol('Parent',gui.panels.invstd.HBox4,... +0132 'Style','radiobutton','String','0','Tag','invstd','FontSize',myui.fontsize,... 0133 'UserData',struct('Tooltipstr',tstr),'Enable','off','Callback',@onRadioLorder); -0134 gui.radio_handles.invstd_Lorder2 = uicontrol('Parent',gui.panels.invstd.HBox4,... -0135 'Style','radiobutton','String','2','Tag','invstd','FontSize',myui.fontsize,... +0134 gui.radio_handles.invstd_Lorder1 = uicontrol('Parent',gui.panels.invstd.HBox4,... +0135 'Style','radiobutton','String','1','Tag','invstd','FontSize',myui.fontsize,... 0136 'UserData',struct('Tooltipstr',tstr),'Enable','off','Callback',@onRadioLorder); -0137 set(gui.panels.invstd.HBox4,'Widths',[200 -1 -1 -1]); -0138 -0139 %% min and max values of the L-curve -0140 gui.text_handles.invstd_lambda = uicontrol('Parent',gui.panels.invstd.HBox5,... -0141 'Style','text','FontSize',myui.fontsize,... -0142 'String','lambda - min | max | #'); -0143 tstr = 'Lambda value / Smallest Lambda in range.'; -0144 gui.edit_handles.invstd_lambda_min = uicontrol('Parent',gui.panels.invstd.HBox5,... -0145 'Style','edit','String',num2str(data.invstd.lambda),'FontSize',myui.fontsize,... -0146 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.lambdaR(1,1) 1 1]),... -0147 'Tag','invstd_lambdaR','Enable','off','Callback',@onEditValue); -0148 tstr = 'Largest Lambda in range.'; -0149 gui.edit_handles.invstd_lambda_max = uicontrol('Parent',gui.panels.invstd.HBox5,... -0150 'Style','edit','String',num2str(data.invstd.lambdaR(1,2)),... -0151 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.lambdaR(1,2) 1 2]),... -0152 'Tag','invstd_lambdaR','FontSize',myui.fontsize,... -0153 'Enable','off','Callback',@onEditValue); -0154 tstr = 'Number of Lambdas in L-curve.'; -0155 gui.edit_handles.invstd_NlambdaR = uicontrol('Parent',gui.panels.invstd.HBox5,... -0156 'Style','edit','String',num2str(data.invstd.NlambdaR),... -0157 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.NlambdaR 1 1]),... -0158 'Tag','invstd_NlambdaR','FontSize',myui.fontsize,... -0159 'Enable','off','Callback',@onEditValue); -0160 set(gui.panels.invstd.HBox5,'Widths',[200 -1 -1 -1]); -0161 -0162 %% RUN button -0163 gui.text_handles.invstd_run = uicontrol('Parent',gui.panels.invstd.HBox6,... -0164 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... -0165 'String','run Inversion'); -0166 gui.push_handles.invstd_run = uicontrol('Parent',gui.panels.invstd.HBox6,'Enable','off',... -0167 'String','<HTML><u>R</u>UN','FontSize',myui.fontsize,'BackGroundColor','g',... -0168 'Tag','std','UserData',1,'Callback',@onPushRun); -0169 set(gui.panels.invstd.HBox6,'Widths',[200 -1]); -0170 -0171 %% Java Hack to adjust vertical alignment of text fields -0172 jh = findjobj(gui.text_handles.invstd_InvType); -0173 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0174 jh = findjobj(gui.text_handles.invstd_RTDtimes); -0175 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0176 jh = findjobj(gui.text_handles.invstd_InvTypeOpt); -0177 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0178 jh = findjobj(gui.text_handles.invstd_Lorder); -0179 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0180 jh = findjobj(gui.text_handles.invstd_lambda); -0181 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0182 jh = findjobj(gui.text_handles.invstd_run); -0183 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0184 -0185 return -0186 -0187 %------------- END OF CODE -------------- +0137 gui.radio_handles.invstd_Lorder2 = uicontrol('Parent',gui.panels.invstd.HBox4,... +0138 'Style','radiobutton','String','2','Tag','invstd','FontSize',myui.fontsize,... +0139 'UserData',struct('Tooltipstr',tstr),'Enable','off','Callback',@onRadioLorder); +0140 set(gui.panels.invstd.HBox4,'Widths',[200 -1 -1 -1]); +0141 +0142 %% min and max values of the L-curve +0143 gui.text_handles.invstd_lambda = uicontrol('Parent',gui.panels.invstd.HBox5,... +0144 'Style','text','FontSize',myui.fontsize,... +0145 'String','lambda - min | max | #'); +0146 tstr = 'Lambda value / Smallest Lambda in range.'; +0147 gui.edit_handles.invstd_lambda_min = uicontrol('Parent',gui.panels.invstd.HBox5,... +0148 'Style','edit','String',num2str(data.invstd.lambda),'FontSize',myui.fontsize,... +0149 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.lambdaR(1,1) 1 1]),... +0150 'Tag','invstd_lambdaR','Enable','off','Callback',@onEditValue); +0151 tstr = 'Largest Lambda in range.'; +0152 gui.edit_handles.invstd_lambda_max = uicontrol('Parent',gui.panels.invstd.HBox5,... +0153 'Style','edit','String',num2str(data.invstd.lambdaR(1,2)),... +0154 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.lambdaR(1,2) 1 2]),... +0155 'Tag','invstd_lambdaR','FontSize',myui.fontsize,... +0156 'Enable','off','Callback',@onEditValue); +0157 tstr = 'Number of Lambdas in L-curve.'; +0158 gui.edit_handles.invstd_NlambdaR = uicontrol('Parent',gui.panels.invstd.HBox5,... +0159 'Style','edit','String',num2str(data.invstd.NlambdaR),... +0160 'UserData',struct('Tooltipstr',tstr,'defaults',[data.invstd.NlambdaR 1 1]),... +0161 'Tag','invstd_NlambdaR','FontSize',myui.fontsize,... +0162 'Enable','off','Callback',@onEditValue); +0163 set(gui.panels.invstd.HBox5,'Widths',[200 -1 -1 -1]); +0164 +0165 %% RUN button +0166 gui.text_handles.invstd_run = uicontrol('Parent',gui.panels.invstd.HBox6,... +0167 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0168 'String','run Inversion'); +0169 gui.push_handles.invstd_run = uicontrol('Parent',gui.panels.invstd.HBox6,'Enable','off',... +0170 'String','<HTML><u>R</u>UN','FontSize',myui.fontsize,'BackGroundColor','g',... +0171 'Tag','std','UserData',1,'Callback',@onPushRun); +0172 set(gui.panels.invstd.HBox6,'Widths',[200 -1]); +0173 +0174 %% RTD uncertainty +0175 gui.text_handles.uncert = uicontrol('Parent',gui.panels.invstd.HBox7,... +0176 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0177 'String','RTD uncertainty | # models'); +0178 tstr = 'Number of uncertainty models to calculate.'; +0179 gui.edit_handles.uncert_N = uicontrol('Parent',gui.panels.invstd.HBox7,... +0180 'Style','edit','String',num2str(data.uncert.N),... +0181 'UserData',struct('Tooltipstr',tstr,'defaults',[data.uncert.N 1 1]),... +0182 'Tag','uncert_N','FontSize',myui.fontsize,... +0183 'Enable','off','Callback',@onEditValue); +0184 gui.push_handles.uncert = uicontrol('Parent',gui.panels.invstd.HBox7,'Enable','off',... +0185 'String','CALC.','FontSize',myui.fontsize,'BackGroundColor','g',... +0186 'Tag','uncert','UserData',1,'Callback',@onPushRun); +0187 set(gui.panels.invstd.HBox7,'Widths',[200 -1 -1]); 0188 -0189 %% License: -0190 % MIT License -0191 % -0192 % Copyright (c) 2018 Thomas Hiller -0193 % -0194 % Permission is hereby granted, free of charge, to any person obtaining a copy -0195 % of this software and associated documentation files (the "Software"), to deal -0196 % in the Software without restriction, including without limitation the rights -0197 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0198 % copies of the Software, and to permit persons to whom the Software is -0199 % furnished to do so, subject to the following conditions: -0200 % -0201 % The above copyright notice and this permission notice shall be included in all -0202 % copies or substantial portions of the Software. -0203 % -0204 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0205 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0206 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0207 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0208 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0209 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0210 % SOFTWARE. +0189 %% Java Hack to adjust vertical alignment of text fields +0190 jh = findjobj(gui.text_handles.invstd_InvType); +0191 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0192 jh = findjobj(gui.text_handles.invstd_RTDtimes); +0193 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0194 jh = findjobj(gui.text_handles.invstd_InvTypeOpt); +0195 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0196 jh = findjobj(gui.text_handles.invstd_Lorder); +0197 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0198 jh = findjobj(gui.text_handles.invstd_lambda); +0199 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0200 jh = findjobj(gui.text_handles.invstd_run); +0201 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0202 jh = findjobj(gui.text_handles.uncert); +0203 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0204 +0205 return +0206 +0207 %------------- END OF CODE -------------- +0208 +0209 %% License: +0210 % MIT License +0211 % +0212 % Copyright (c) 2018 Thomas Hiller +0213 % +0214 % Permission is hereby granted, free of charge, to any person obtaining a copy +0215 % of this software and associated documentation files (the "Software"), to deal +0216 % in the Software without restriction, including without limitation the rights +0217 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0218 % copies of the Software, and to permit persons to whom the Software is +0219 % furnished to do so, subject to the following conditions: +0220 % +0221 % The above copyright notice and this permission notice shall be included in all +0222 % copies or substantial portions of the Software. +0223 % +0224 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0225 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0226 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0227 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0228 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0229 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0230 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelPlots.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelPlots.html index 0c76271..e667ff4 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelPlots.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelPlots.html @@ -227,85 +227,92 @@

    SOURCE CODE ^... 0156 'Label','cum','Tag','view','Callback',@onContextPlotsRTD); 0157 set(gui.axes_handles.rtd,'UIContextMenu',gui.cm_handles.axes_rtd); -0158 -0159 %% 2.2 the PSD panel -0160 gui.plots.Dist.PSD.box = uicontainer('Parent',gui.plots.Dist.PSDTab); -0161 -0162 % now the actual axes -0163 gui.axes_handles.psd = axes('Parent',gui.plots.Dist.PSD.box,'Box','on'); -0164 set(get(gui.axes_handles.psd,'XLabel'),'String','equiv. pore size [m]'); -0165 set(get(gui.axes_handles.psd,'YLabel'),'String','water content [vol. %]'); -0166 % the axes has a context menu -0167 gui.cm_handles.axes_psd = uicontextmenu(gui.figh); -0168 gui.cm_handles.axes_psd_view = uimenu(gui.cm_handles.axes_psd,... -0169 'Label','view','Enable','off'); -0170 gui.cm_handles.axes_psd_view_freq = uimenu(gui.cm_handles.axes_psd_view,... -0171 'Label','freq','Tag','view','Checked','on','Callback',@onContextPlotsPSD); -0172 gui.cm_handles.axes_psd_view_cum = uimenu(gui.cm_handles.axes_psd_view,... -0173 'Label','cum','Tag','view','Callback',@onContextPlotsPSD); -0174 set(gui.axes_handles.psd,'UIContextMenu',gui.cm_handles.axes_psd); -0175 -0176 %% 2.3 the PSD(joint) panel -0177 gui.plots.Dist.PSDJ.box = uicontainer('Parent',gui.plots.Dist.PSDJTab); -0178 -0179 % now the actual axes -0180 gui.axes_handles.psdj = axes('Parent',gui.plots.Dist.PSDJ.box,'Box','on'); -0181 set(get(gui.axes_handles.psdj,'XLabel'),'String','equiv. pore size [m]'); -0182 set(get(gui.axes_handles.psdj,'YLabel'),'String','water content [vol. %]'); -0183 % the axes has a context menu -0184 gui.cm_handles.axes_psdj = uicontextmenu(gui.figh); -0185 gui.cm_handles.axes_psdj_view = uimenu(gui.cm_handles.axes_psdj,... -0186 'Label','view','Enable','off'); -0187 gui.cm_handles.axes_psdj_view_freq = uimenu(gui.cm_handles.axes_psdj_view,... -0188 'Label','freq','Tag','view','Checked','on','Callback',@onContextPlotsPSDJ); -0189 gui.cm_handles.axes_psdj_view_cum = uimenu(gui.cm_handles.axes_psdj_view,... -0190 'Label','cum','Tag','view','Callback',@onContextPlotsPSDJ); -0191 set(gui.axes_handles.psdj,'UIContextMenu',gui.cm_handles.axes_psdj); -0192 -0193 %% 3. panel - CPS data -0194 gui.plots.CPSTab = uix.HBox('Parent',gui.plots.CPSPanel,... -0195 'Spacing',0,'Padding',0); -0196 gui.plots.CPSPanel.Title = 'CPS (joint)'; -0197 -0198 %% 3.1 the CPS axes -0199 % inside a uicontainer for proper resizing -0200 gui.plots.CPS.box = uicontainer('Parent',gui.plots.CPSTab,... -0201 'Tag','CPS_INV','SizeChangedFcn',@fixAxes); -0202 -0203 % now the actual axes -0204 gui.axes_handles.cps = axes('Parent',gui.plots.CPS.box,'Box','on'); -0205 set(get(gui.axes_handles.cps,'XLabel'),'String','pressure [Pa]'); -0206 set(get(gui.axes_handles.cps,'YLabel'),'String','saturation [-]'); -0207 -0208 % set some axes layout defaults -0209 beautifyAxes(gui.figh); -0210 -0211 return -0212 -0213 %------------- END OF CODE -------------- +0158 gui.cm_handles.axes_rtd_uncert = uimenu(gui.cm_handles.axes_rtd,... +0159 'Label','uncert','Enable','off'); +0160 gui.cm_handles.axes_rtd_uncert_lines = uimenu(gui.cm_handles.axes_rtd_uncert,... +0161 'Label','lines','Tag','uncert','Checked','on','Callback',@onContextPlotsRTD); +0162 gui.cm_handles.axes_rtd_uncert_patch = uimenu(gui.cm_handles.axes_rtd_uncert,... +0163 'Label','patch','Tag','uncert','Callback',@onContextPlotsRTD); +0164 set(gui.axes_handles.rtd,'UIContextMenu',gui.cm_handles.axes_rtd); +0165 +0166 %% 2.2 the PSD panel +0167 gui.plots.Dist.PSD.box = uicontainer('Parent',gui.plots.Dist.PSDTab); +0168 +0169 % now the actual axes +0170 gui.axes_handles.psd = axes('Parent',gui.plots.Dist.PSD.box,'Box','on'); +0171 set(get(gui.axes_handles.psd,'XLabel'),'String','equiv. pore size [m]'); +0172 set(get(gui.axes_handles.psd,'YLabel'),'String','water content [vol. %]'); +0173 % the axes has a context menu +0174 gui.cm_handles.axes_psd = uicontextmenu(gui.figh); +0175 gui.cm_handles.axes_psd_view = uimenu(gui.cm_handles.axes_psd,... +0176 'Label','view','Enable','off'); +0177 gui.cm_handles.axes_psd_view_freq = uimenu(gui.cm_handles.axes_psd_view,... +0178 'Label','freq','Tag','view','Checked','on','Callback',@onContextPlotsPSD); +0179 gui.cm_handles.axes_psd_view_cum = uimenu(gui.cm_handles.axes_psd_view,... +0180 'Label','cum','Tag','view','Callback',@onContextPlotsPSD); +0181 set(gui.axes_handles.psd,'UIContextMenu',gui.cm_handles.axes_psd); +0182 +0183 %% 2.3 the PSD(joint) panel +0184 gui.plots.Dist.PSDJ.box = uicontainer('Parent',gui.plots.Dist.PSDJTab); +0185 +0186 % now the actual axes +0187 gui.axes_handles.psdj = axes('Parent',gui.plots.Dist.PSDJ.box,'Box','on'); +0188 set(get(gui.axes_handles.psdj,'XLabel'),'String','equiv. pore size [m]'); +0189 set(get(gui.axes_handles.psdj,'YLabel'),'String','water content [vol. %]'); +0190 % the axes has a context menu +0191 gui.cm_handles.axes_psdj = uicontextmenu(gui.figh); +0192 gui.cm_handles.axes_psdj_view = uimenu(gui.cm_handles.axes_psdj,... +0193 'Label','view','Enable','off'); +0194 gui.cm_handles.axes_psdj_view_freq = uimenu(gui.cm_handles.axes_psdj_view,... +0195 'Label','freq','Tag','view','Checked','on','Callback',@onContextPlotsPSDJ); +0196 gui.cm_handles.axes_psdj_view_cum = uimenu(gui.cm_handles.axes_psdj_view,... +0197 'Label','cum','Tag','view','Callback',@onContextPlotsPSDJ); +0198 set(gui.axes_handles.psdj,'UIContextMenu',gui.cm_handles.axes_psdj); +0199 +0200 %% 3. panel - CPS data +0201 gui.plots.CPSTab = uix.HBox('Parent',gui.plots.CPSPanel,... +0202 'Spacing',0,'Padding',0); +0203 gui.plots.CPSPanel.Title = 'CPS (joint)'; +0204 +0205 %% 3.1 the CPS axes +0206 % inside a uicontainer for proper resizing +0207 gui.plots.CPS.box = uicontainer('Parent',gui.plots.CPSTab,... +0208 'Tag','CPS_INV','SizeChangedFcn',@fixAxes); +0209 +0210 % now the actual axes +0211 gui.axes_handles.cps = axes('Parent',gui.plots.CPS.box,'Box','on'); +0212 set(get(gui.axes_handles.cps,'XLabel'),'String','pressure [Pa]'); +0213 set(get(gui.axes_handles.cps,'YLabel'),'String','saturation [-]'); 0214 -0215 %% License: -0216 % MIT License -0217 % -0218 % Copyright (c) 2018 Thomas Hiller -0219 % -0220 % Permission is hereby granted, free of charge, to any person obtaining a copy -0221 % of this software and associated documentation files (the "Software"), to deal -0222 % in the Software without restriction, including without limitation the rights -0223 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0224 % copies of the Software, and to permit persons to whom the Software is -0225 % furnished to do so, subject to the following conditions: +0215 % set some axes layout defaults +0216 beautifyAxes(gui.figh); +0217 +0218 return +0219 +0220 %------------- END OF CODE -------------- +0221 +0222 %% License: +0223 % MIT License +0224 % +0225 % Copyright (c) 2018 Thomas Hiller 0226 % -0227 % The above copyright notice and this permission notice shall be included in all -0228 % copies or substantial portions of the Software. -0229 % -0230 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0231 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0232 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0233 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0234 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0235 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0236 % SOFTWARE. +0227 % Permission is hereby granted, free of charge, to any person obtaining a copy +0228 % of this software and associated documentation files (the "Software"), to deal +0229 % in the Software without restriction, including without limitation the rights +0230 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0231 % copies of the Software, and to permit persons to whom the Software is +0232 % furnished to do so, subject to the following conditions: +0233 % +0234 % The above copyright notice and this permission notice shall be included in all +0235 % copies or substantial portions of the Software. +0236 % +0237 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0238 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0239 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0240 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0241 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0242 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0243 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html index 8edb209..dcb5504 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html @@ -109,177 +109,185 @@

    SOURCE CODE ^'freq'; 0041 out.info.PSDflag = 'freq'; 0042 out.info.PSDJflag = 'freq'; -0043 % flags indicating expert mode / joint inversion / inversion info / tool -0044 % tips -0045 out.info.ExpertMode = 'off'; -0046 out.info.JointInv = 'off'; -0047 out.info.InvInfo = 'on'; -0048 out.info.ToolTips = 'off'; -0049 % Optimization and Statistics toolbox availability is checked later -0050 % lsqnonneg is the default lsq-solver -0051 out.info.has_optim = 'off'; -0052 out.info.solver = 'lsqnonneg'; -0053 out.info.stat = 'off'; -0054 -0055 %% process panel defaults -0056 % first data sample of the signal -0057 out.process.start = 1; -0058 % last data sample of the signal (0 resets it to take the full signal) -0059 out.process.end = 0; -0060 % re-sampling (gating) of the raw signal 'log' | 'lin' | 'none' -0061 % depends on signal type 'T1' or 'T2' -0062 out.process.gatetype = 'log'; -0063 % maximum number of echoes per gate -0064 out.process.Nechoes = 50; -0065 % normalize signal to 1 (no=0, yes=1) -0066 out.process.norm = 0; -0067 % scale factor for normalization -0068 out.process.normfac = 1; -0069 % time scale of the signal 's' | 'ms' -0070 out.process.timescale = 's'; -0071 % corresponding scale factor (s=1) | (ms=1000) -0072 out.process.timefac = 1; -0073 -0074 %% petrophysical parameters panel -0075 % surface relaxivity [µm/s] -0076 out.param.rho = 10; -0077 % surface to volume ratio factor a [-] 1/T = rho*(S/V) = rho*a/R -0078 out.param.a = 2; -0079 % T cutoff time between clay bound (CBW) and irreducible water (BVI) in [ms] -0080 out.param.CBWcutoff = 3; -0081 % T cutoff time between irreducible (BVI) and movable water (BVM) in [ms] -0082 out.param.BVIcutoff = 33; -0083 % calibration sample volume -0084 out.param.calibVol = 1; -0085 % calibration sample NMR amplitude -0086 out.param.calibAmp = 1; -0087 % sample volume -0088 out.param.sampVol = 1; -0089 -0090 % NMR porosity calibration data -0091 % calibration volume (water -0092 out.calib.vol = 1; -0093 % calibration amplitude (water) -0094 out.calib.amp = 1; -0095 % calibration factor -0096 out.calib.fac = 1; -0097 % calibration name -0098 out.calib.name = ''; -0099 -0100 %% standard inversion panel defaults -0101 % inversion methods to choose from -0102 % 'mono' | 'free' | 'NNLS' | 'LU' -0103 out.invstd.invtype = 'NNLS'; -0104 % when inversion method is 'free' choose No. of free relaxation times -0105 out.invstd.freeDT = 2; -0106 % option to fix some of the 'free' relaxation times to a certain value -0107 out.invstd.Tfixed_bool = [0 0 0 0 0]; -0108 out.invstd.Tfixed_val = [0 0 0 0 0]; -0109 % regularization options for multi-exponential fitting routines -0110 % 'NNLS' and 'LU' -0111 out.invstd.regtype = 'manual'; -0112 % smoothness constraint (order) for multi-exponential fitting routines -0113 % 'NNLS' and 'LU' -0114 out.invstd.Lorder = 1; -0115 % regularization parameter for multi-exponential fitting routines -0116 % 'NNLS' and 'LU' -0117 out.invstd.lambda = 1; -0118 % L-curve range (lambda) for multi-exponential fitting routine 'NNLS' -0119 out.invstd.lambdaR = [1e-3 1e2]; -0120 % initial L-curve range (lambda) for multi-exponential fitting routine -0121 % 'NNLS' -0122 out.invstd.lambdaRinit = [1e-3 1e2]; -0123 % number of lambda values in L-curve -0124 out.invstd.NlambdaR = 20; -0125 % range for RTD [min max] in [s] -0126 out.invstd.time = [1e-4 1e2]; -0127 % number of points per decade in RTD -0128 out.invstd.Ntime = 30; -0129 % noise level (taken from data if available) -0130 out.invstd.noise = 0; -0131 % water bulk relaxation time [s] -0132 out.invstd.Tbulk = 1e6; -0133 % diffusion relaxation time [s] -0134 out.invstd.Tdiff = 1e6; -0135 % porosity value between 0 and 1 [-] -0136 out.invstd.porosity = 1; -0137 -0138 out.invstd.useUncert = 1; -0139 out.invstd.uncertMethod = 'thresh'; -0140 out.invstd.uncertThresh = 0.05; -0141 out.invstd.uncertChi2 = 0.005; -0142 out.invstd.uncertN = 100; -0143 out.invstd.uncertMax = 1e4; -0144 -0145 %% joint inversion panel defaults -0146 % joint inversion methods to choose 'free' | 'fixed' | 'shape' -0147 out.invjoint.invtype = 'free'; -0148 % pore size distribution in [m] -0149 out.invjoint.radii = [1e-8 1e-2]; -0150 % No. of steps per decade in pore size distribution -0151 out.invjoint.Nradii = 25; -0152 % regularization options for joint inversion 'free' -0153 out.invjoint.regtype = 'manual'; -0154 % smoothness constraint (order) for joint inversion 'free' -0155 out.invjoint.Lorder = 1; -0156 % regularization parameter for joint inversion 'free' -0157 out.invjoint.lambda = 1; -0158 % L-curve range (lambda) for joint inversion 'free' -0159 out.invjoint.lambdaR = [1e-3 1e2]; -0160 % initial L-curve range (lambda) for joint inversion 'free' -0161 out.invjoint.lambdaRinit = [1e-3 1e2]; -0162 out.invjoint.NlambdaR = 20; -0163 % available pore geometries 'cyl' | 'ang' | 'poly' -0164 out.invjoint.geometry_type = 'cyl'; -0165 % number of polygon sides for geometry 'poly' (3 to 12) -0166 out.invjoint.polyN = 3; -0167 % angle alpha [deg] - fixed to 90° -0168 out.invjoint.alpha = 90; -0169 % angle beta [deg] - changed by user -0170 out.invjoint.beta = 60; -0171 % gamma [deg] - alpha-beta -0172 out.invjoint.gamma = 30; -0173 % start value rho [µm/s] -0174 out.invjoint.rhostart = 20; -0175 % lower and upper boundary for rho [µm/s] -0176 out.invjoint.rhobounds = [0.01 1000]; -0177 % sart value beta [deg] -0178 out.invjoint.anglestart = 25; -0179 -0180 % pressure settings -0181 % CPS table initial values (use,p,S,drain/imb) -0182 out.pressure.table = {true,0,1,'D'}; -0183 % pressure units 'Pa' | 'kPa' | 'MPa' | 'bar' -0184 out.pressure.unit = 'Pa'; -0185 % corresponding scale factors - 1 | 1e-3 | 1e-6 | 1e-5 -0186 out.pressure.unitfac = 1; +0043 % plot switch for uncertainty line / patch plot +0044 out.info.RTDuncert = 'lines'; +0045 % flags indicating expert mode / joint inversion / inversion info / tool +0046 % tips +0047 out.info.ExpertMode = 'off'; +0048 out.info.JointInv = 'off'; +0049 out.info.InvInfo = 'on'; +0050 out.info.ToolTips = 'off'; +0051 % Optimization and Statistics toolbox availability is checked later +0052 % lsqnonneg is the default lsq-solver +0053 out.info.has_optim = 'off'; +0054 out.info.solver = 'lsqnonneg'; +0055 out.info.stat = 'off'; +0056 +0057 %% process panel defaults +0058 % first data sample of the signal +0059 out.process.start = 1; +0060 % last data sample of the signal (0 resets it to take the full signal) +0061 out.process.end = 0; +0062 % re-sampling (gating) of the raw signal 'log' | 'lin' | 'none' +0063 % depends on signal type 'T1' or 'T2' +0064 out.process.gatetype = 'log'; +0065 % gateing flag for convenience +0066 out.process.isgated = false; +0067 % maximum number of echoes per gate +0068 out.process.Nechoes = 50; +0069 % normalize signal to 1 (no=0, yes=1) +0070 out.process.norm = 0; +0071 % scale factor for normalization +0072 out.process.normfac = 1; +0073 % time scale of the signal 's' | 'ms' +0074 out.process.timescale = 's'; +0075 % corresponding scale factor (s=1) | (ms=1000) +0076 out.process.timefac = 1; +0077 +0078 %% petrophysical parameters panel +0079 % surface relaxivity [µm/s] +0080 out.param.rho = 10; +0081 % surface to volume ratio factor a [-] 1/T = rho*(S/V) = rho*a/R +0082 out.param.a = 2; +0083 % T cutoff time between clay bound (CBW) and irreducible water (BVI) in [ms] +0084 out.param.CBWcutoff = 3; +0085 % T cutoff time between irreducible (BVI) and movable water (BVM) in [ms] +0086 out.param.BVIcutoff = 33; +0087 % calibration sample volume +0088 out.param.calibVol = 1; +0089 % calibration sample NMR amplitude +0090 out.param.calibAmp = 1; +0091 % sample volume +0092 out.param.sampVol = 1; +0093 +0094 % NMR porosity calibration data +0095 % calibration volume (water +0096 out.calib.vol = 1; +0097 % calibration amplitude (water) +0098 out.calib.amp = 1; +0099 % calibration factor +0100 out.calib.fac = 1; +0101 % calibration name +0102 out.calib.name = ''; +0103 +0104 %% standard inversion panel defaults +0105 % inversion methods to choose from +0106 % 'mono' | 'free' | 'NNLS' | 'LU' +0107 out.invstd.invtype = 'NNLS'; +0108 % when inversion method is 'free' choose No. of free relaxation times +0109 out.invstd.freeDT = 2; +0110 % option to fix some of the 'free' relaxation times to a certain value +0111 out.invstd.Tfixed_bool = [0 0 0 0 0]; +0112 out.invstd.Tfixed_val = [0 0 0 0 0]; +0113 % regularization options for multi-exponential fitting routines +0114 % 'NNLS' and 'LU' +0115 out.invstd.regtype = 'manual'; +0116 % smoothness constraint (order) for multi-exponential fitting routines +0117 % 'NNLS' and 'LU' +0118 out.invstd.Lorder = 1; +0119 % regularization parameter for multi-exponential fitting routines +0120 % 'NNLS' and 'LU' +0121 out.invstd.lambda = 1; +0122 % L-curve range (lambda) for multi-exponential fitting routine 'NNLS' +0123 out.invstd.lambdaR = [1e-3 1e2]; +0124 % initial L-curve range (lambda) for multi-exponential fitting routine +0125 % 'NNLS' +0126 out.invstd.lambdaRinit = [1e-3 1e2]; +0127 % number of lambda values in L-curve +0128 out.invstd.NlambdaR = 20; +0129 % range for RTD [min max] in [s] +0130 out.invstd.time = [1e-4 1e2]; +0131 % number of points per decade in RTD +0132 out.invstd.Ntime = 30; +0133 % noise level (taken from data if available) +0134 out.invstd.noise = 0; +0135 % water bulk relaxation time [s] +0136 out.invstd.Tbulk = 1e6; +0137 % diffusion relaxation time [s] +0138 out.invstd.Tdiff = 1e6; +0139 % porosity value between 0 and 1 [-] +0140 out.invstd.porosity = 1; +0141 +0142 % uncertainty flag (intended for batch use) +0143 out.uncert.use = 1; +0144 % default uncertainty calculation method +0145 out.uncert.Method = 'RMS_bound'; +0146 % uncertaintyx treshold (only need for method 'threshold') +0147 out.uncert.Thresh = 0.05; +0148 % number of uncertainty models to calculate +0149 out.uncert.N = 10; +0150 % number of unsuccesful tries before calculation stops +0151 out.uncert.Max = 1e4; +0152 +0153 %% joint inversion panel defaults +0154 % joint inversion methods to choose 'free' | 'fixed' | 'shape' +0155 out.invjoint.invtype = 'free'; +0156 % pore size distribution in [m] +0157 out.invjoint.radii = [1e-8 1e-2]; +0158 % No. of steps per decade in pore size distribution +0159 out.invjoint.Nradii = 25; +0160 % regularization options for joint inversion 'free' +0161 out.invjoint.regtype = 'manual'; +0162 % smoothness constraint (order) for joint inversion 'free' +0163 out.invjoint.Lorder = 1; +0164 % regularization parameter for joint inversion 'free' +0165 out.invjoint.lambda = 1; +0166 % L-curve range (lambda) for joint inversion 'free' +0167 out.invjoint.lambdaR = [1e-3 1e2]; +0168 % initial L-curve range (lambda) for joint inversion 'free' +0169 out.invjoint.lambdaRinit = [1e-3 1e2]; +0170 out.invjoint.NlambdaR = 20; +0171 % available pore geometries 'cyl' | 'ang' | 'poly' +0172 out.invjoint.geometry_type = 'cyl'; +0173 % number of polygon sides for geometry 'poly' (3 to 12) +0174 out.invjoint.polyN = 3; +0175 % angle alpha [deg] - fixed to 90° +0176 out.invjoint.alpha = 90; +0177 % angle beta [deg] - changed by user +0178 out.invjoint.beta = 60; +0179 % gamma [deg] - alpha-beta +0180 out.invjoint.gamma = 30; +0181 % start value rho [µm/s] +0182 out.invjoint.rhostart = 20; +0183 % lower and upper boundary for rho [µm/s] +0184 out.invjoint.rhobounds = [0.01 1000]; +0185 % sart value beta [deg] +0186 out.invjoint.anglestart = 25; 0187 -0188 return -0189 -0190 %------------- END OF CODE -------------- -0191 -0192 %% License: -0193 % MIT License -0194 % -0195 % Copyright (c) 2018 Thomas Hiller -0196 % -0197 % Permission is hereby granted, free of charge, to any person obtaining a copy -0198 % of this software and associated documentation files (the "Software"), to deal -0199 % in the Software without restriction, including without limitation the rights -0200 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0201 % copies of the Software, and to permit persons to whom the Software is -0202 % furnished to do so, subject to the following conditions: -0203 % -0204 % The above copyright notice and this permission notice shall be included in all -0205 % copies or substantial portions of the Software. -0206 % -0207 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0208 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0209 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0210 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0211 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0212 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0213 % SOFTWARE. +0188 % pressure settings +0189 % CPS table initial values (use,p,S,drain/imb) +0190 out.pressure.table = {true,0,1,'D'}; +0191 % pressure units 'Pa' | 'kPa' | 'MPa' | 'bar' +0192 out.pressure.unit = 'Pa'; +0193 % corresponding scale factors - 1 | 1e-3 | 1e-6 | 1e-5 +0194 out.pressure.unitfac = 1; +0195 +0196 return +0197 +0198 %------------- END OF CODE -------------- +0199 +0200 %% License: +0201 % MIT License +0202 % +0203 % Copyright (c) 2018 Thomas Hiller +0204 % +0205 % Permission is hereby granted, free of charge, to any person obtaining a copy +0206 % of this software and associated documentation files (the "Software"), to deal +0207 % in the Software without restriction, including without limitation the rights +0208 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0209 % copies of the Software, and to permit persons to whom the Software is +0210 % furnished to do so, subject to the following conditions: +0211 % +0212 % The above copyright notice and this permission notice shall be included in all +0213 % copies or substantial portions of the Software. +0214 % +0215 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0216 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0217 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0218 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0219 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0220 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0221 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_updateInterface.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_updateInterface.html index d1d526e..854faf4 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_updateInterface.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_updateInterface.html @@ -166,877 +166,917 @@

    SOURCE CODE ^updateLambda(gui,data.invstd.regtype,0,0,0); 0087 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); 0088 gui = updateInvstdTime(gui,data.invstd.invtype,0,0); -0089 -0090 % Tbulk & Tdiff -0091 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... -0092 'String',num2str(data.invstd.Tbulk)); -0093 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... -0094 'String',num2str(data.invstd.Tdiff)); -0095 -0096 case 'free' -0097 % inversion method popup -0098 set(gui.popup_handles.invstd_InvType,'Value',2,'Enable','on'); -0099 -0100 % additional inversion settings -0101 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... -0102 'Value',data.invstd.freeDT,... -0103 'String',{'1','2','3','4','5'}); -0104 set(gui.text_handles.invstd_InvTypeOpt,... -0105 'String','No. of free relaxation times T'); -0106 -0107 % lambda, smoothness constraint and RTD limits -0108 gui = updateLambda(gui,data.invstd.regtype,0,0,0); -0109 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); -0110 gui = updateInvstdTime(gui,data.invstd.invtype,0,0); +0089 +0090 % RTD uncertainty +0091 set(gui.edit_handles.uncert_N,'Enable','off',... +0092 'String',num2str(data.uncert.N)); +0093 set(gui.push_handles.uncert,'Enable','off'); +0094 +0095 % Tbulk & Tdiff +0096 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... +0097 'String',num2str(data.invstd.Tbulk)); +0098 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... +0099 'String',num2str(data.invstd.Tdiff)); +0100 +0101 case 'free' +0102 % inversion method popup +0103 set(gui.popup_handles.invstd_InvType,'Value',2,'Enable','on'); +0104 +0105 % additional inversion settings +0106 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... +0107 'Value',data.invstd.freeDT,... +0108 'String',{'1','2','3','4','5'}); +0109 set(gui.text_handles.invstd_InvTypeOpt,... +0110 'String','No. of free relaxation times T'); 0111 -0112 % Tbulk & Tdiff -0113 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... -0114 'String',num2str(data.invstd.Tbulk)); -0115 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... -0116 'String',num2str(data.invstd.Tdiff)); -0117 -0118 case 'NNLS' -0119 % inversion method popup -0120 set(gui.popup_handles.invstd_InvType,'Value',3,'Enable','on'); +0112 % lambda, smoothness constraint and RTD limits +0113 gui = updateLambda(gui,data.invstd.regtype,0,0,0); +0114 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); +0115 gui = updateInvstdTime(gui,data.invstd.invtype,0,0); +0116 +0117 % RTD uncertainty +0118 set(gui.edit_handles.uncert_N,'Enable','off',... +0119 'String',num2str(data.uncert.N)); +0120 set(gui.push_handles.uncert,'Enable','off'); 0121 -0122 % additional inversion settings -0123 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... -0124 'String',{'Manual','Tikhonov (SVD)','TSVD (SVD)',... -0125 'DSVD (SVD)','Discrep. (SVD)','L-curve'}); -0126 set(gui.text_handles.invstd_InvTypeOpt,... -0127 'String','regularization options'); -0128 -0129 % regularization options -0130 switch data.invstd.regtype -0131 case 'manual' -0132 set(gui.popup_handles.invstd_InvTypeOpt,'Value',1); -0133 case 'gcv_tikh' -0134 set(gui.popup_handles.invstd_InvTypeOpt,'Value',2); -0135 case 'gcv_trunc' -0136 set(gui.popup_handles.invstd_InvTypeOpt,'Value',3); -0137 case 'gcv_damp' -0138 set(gui.popup_handles.invstd_InvTypeOpt,'Value',4); -0139 case 'discrep' -0140 set(gui.popup_handles.invstd_InvTypeOpt,'Value',5); -0141 case 'lcurve' -0142 set(gui.popup_handles.invstd_InvTypeOpt,'Value',6); -0143 end -0144 -0145 % lambda, smoothness constraint and RTD limits -0146 gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... -0147 data.invstd.lambdaR,data.invstd.NlambdaR); -0148 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); -0149 gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... -0150 data.invstd.Ntime); -0151 -0152 % Tbulk & Tdiff -0153 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... -0154 'String',num2str(data.invstd.Tbulk)); -0155 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... -0156 'String',num2str(data.invstd.Tdiff)); -0157 -0158 case 'LU' -0159 % inversion method popup -0160 set(gui.popup_handles.invstd_InvType,'Value',4,'Enable','on'); -0161 -0162 % additional inversion settings -0163 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... -0164 'String',{'Manual','Automatic'}); -0165 set(gui.text_handles.invstd_InvTypeOpt,... -0166 'String','regularization options'); -0167 -0168 % regularization options -0169 switch data.invstd.regtype -0170 case 'manual' -0171 set(gui.popup_handles.invstd_InvTypeOpt,'Value',1); -0172 case 'auto' -0173 set(gui.popup_handles.invstd_InvTypeOpt,'Value',2); -0174 data.invstd.lambda = -1; -0175 end +0122 % Tbulk & Tdiff +0123 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... +0124 'String',num2str(data.invstd.Tbulk)); +0125 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... +0126 'String',num2str(data.invstd.Tdiff)); +0127 +0128 case 'NNLS' +0129 % inversion method popup +0130 set(gui.popup_handles.invstd_InvType,'Value',3,'Enable','on'); +0131 +0132 % additional inversion settings +0133 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... +0134 'String',{'Manual','Tikhonov (SVD)','TSVD (SVD)',... +0135 'DSVD (SVD)','Discrep. (SVD)','L-curve'}); +0136 set(gui.text_handles.invstd_InvTypeOpt,... +0137 'String','regularization options'); +0138 +0139 % regularization options +0140 switch data.invstd.regtype +0141 case 'manual' +0142 set(gui.popup_handles.invstd_InvTypeOpt,'Value',1); +0143 case 'gcv_tikh' +0144 set(gui.popup_handles.invstd_InvTypeOpt,'Value',2); +0145 case 'gcv_trunc' +0146 set(gui.popup_handles.invstd_InvTypeOpt,'Value',3); +0147 case 'gcv_damp' +0148 set(gui.popup_handles.invstd_InvTypeOpt,'Value',4); +0149 case 'discrep' +0150 set(gui.popup_handles.invstd_InvTypeOpt,'Value',5); +0151 case 'lcurve' +0152 set(gui.popup_handles.invstd_InvTypeOpt,'Value',6); +0153 end +0154 +0155 % lambda, smoothness constraint and RTD limits +0156 gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... +0157 data.invstd.lambdaR,data.invstd.NlambdaR); +0158 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); +0159 gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... +0160 data.invstd.Ntime); +0161 +0162 % RTD uncertainty +0163 set(gui.edit_handles.uncert_N,'Enable','on',... +0164 'String',num2str(data.uncert.N)); +0165 set(gui.push_handles.uncert,'Enable','on'); +0166 +0167 % Tbulk & Tdiff +0168 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... +0169 'String',num2str(data.invstd.Tbulk)); +0170 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... +0171 'String',num2str(data.invstd.Tdiff)); +0172 +0173 case 'LU' +0174 % inversion method popup +0175 set(gui.popup_handles.invstd_InvType,'Value',4,'Enable','on'); 0176 -0177 % lambda, smoothness constraint and RTD limits -0178 gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... -0179 data.invstd.lambdaR,data.invstd.NlambdaR); -0180 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); -0181 gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... -0182 data.invstd.Ntime); -0183 -0184 % Tbulk & Tdiff -0185 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... -0186 'String',num2str(data.invstd.Tbulk)); -0187 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... -0188 'String',num2str(data.invstd.Tdiff)); -0189 -0190 case 'MUMO' -0191 % inversion method popup -0192 set(gui.popup_handles.invstd_InvType,'Value',5,'Enable','on'); -0193 -0194 % additional inversion settings -0195 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... -0196 'Value',data.invstd.freeDT,... -0197 'String',{'1','2','3','4','5'}); -0198 set(gui.text_handles.invstd_InvTypeOpt,... -0199 'String','No. of modes'); -0200 -0201 % % lambda, smoothness constraint and RTD limits -0202 % gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... -0203 % data.invstd.lambdaR,data.invstd.NlambdaR); -0204 % gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); -0205 gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... -0206 data.invstd.Ntime); -0207 -0208 % lambda, smoothness constraint and RTD limits -0209 gui = updateLambda(gui,data.invstd.regtype,0,0,0); -0210 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); -0211 -0212 % Tbulk & Tdiff -0213 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... -0214 'String',num2str(data.invstd.Tbulk)); -0215 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... -0216 'String',num2str(data.invstd.Tdiff)); -0217 end -0218 -0219 % updates CBW, BVI, rho and a -0220 gui = updateParams(gui,data.invstd.invtype,data.param); -0221 -0222 %% update joint inversion panel -0223 % depending if it is activated or not -0224 switch data.info.JointInv -0225 case 'on' -0226 % inversion method dependent -0227 switch data.invjoint.invtype -0228 case 'free' -0229 % inversion method popup -0230 set(gui.popup_handles.invjoint_InvType,'Value',1,'Enable','on'); -0231 -0232 % PSD limits -0233 gui = updateInvjointRadii(gui,data.invjoint.invtype,... -0234 data.invjoint.radii,data.invjoint.Nradii); -0235 -0236 % additional inversion settings -0237 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','on'); -0238 -0239 % regularization options -0240 switch data.invjoint.regtype -0241 case 'manual' -0242 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',1); -0243 case 'lcurve' -0244 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',2); -0245 end -0246 -0247 % smoothness constraint and lambda -0248 gui = updateLorderJoint(gui,data.invjoint.invtype,... -0249 data.invjoint.Lorder); -0250 gui = updateLambdaJoint(gui,data.invjoint.regtype,... -0251 data.invjoint.lambda,data.invjoint.lambdaR,... -0252 data.invjoint.NlambdaR,data.invstd.regtype); -0253 -0254 % start values -0255 set(gui.edit_handles.invjoint_rhostart,'Enable','on'); -0256 set(gui.edit_handles.invjoint_anglestart,'Enable','off'); -0257 -0258 % geometry type dependent -0259 switch data.invjoint.geometry_type -0260 case 'cyl' -0261 % geometry popup -0262 set(gui.popup_handles.invjoint_geometry_type,... -0263 'Value',1,'Enable','on'); -0264 -0265 % polygon sides and corresponding angle beta -0266 set(gui.popup_handles.invjoint_polyN,'Enable','off',... -0267 'Value',data.invjoint.polyN-2); -0268 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0269 -0270 % angles -0271 set(gui.edit_handles.invjoint_alpha,'String',''); -0272 set(gui.edit_handles.invjoint_beta,'String',''); -0273 set(gui.edit_handles.invjoint_gamma,'String',''); -0274 -0275 case 'ang' -0276 % geometry popup -0277 set(gui.popup_handles.invjoint_geometry_type,... -0278 'Value',2,'Enable','on'); -0279 -0280 % polygon sides and corresponding angle beta -0281 set(gui.popup_handles.invjoint_polyN,'Enable','off',... -0282 'Value',data.invjoint.polyN-2); -0283 set(gui.edit_handles.invjoint_beta,'Enable','on'); -0284 -0285 % angles -0286 set(gui.edit_handles.invjoint_alpha,... -0287 'String',num2str(data.invjoint.alpha)); -0288 set(gui.edit_handles.invjoint_beta,... -0289 'String',num2str(data.invjoint.beta)); -0290 set(gui.edit_handles.invjoint_gamma,... -0291 'String',num2str(data.invjoint.gamma)); -0292 -0293 case 'poly' -0294 % geometry popup -0295 set(gui.popup_handles.invjoint_geometry_type,... -0296 'Value',3,'Enable','on'); -0297 -0298 % polygon sides and corresponding angle beta -0299 set(gui.popup_handles.invjoint_polyN,'Enable','on',... -0300 'Value',data.invjoint.polyN-2); -0301 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0302 -0303 % angles -0304 polyangle = ((data.invjoint.polyN-2)/data.invjoint.polyN)*180; -0305 set(gui.edit_handles.invjoint_alpha,... -0306 'String',''); -0307 set(gui.edit_handles.invjoint_beta,... -0308 'String',num2str(polyangle)); -0309 set(gui.edit_handles.invjoint_gamma,... -0310 'String',''); -0311 end -0312 -0313 case 'fixed' -0314 % inversion method popup -0315 set(gui.popup_handles.invjoint_InvType,'Value',2,'Enable','on'); -0316 -0317 % PSD limits -0318 gui = updateInvjointRadii(gui,data.invjoint.invtype,... -0319 data.invjoint.radii,data.invjoint.Nradii); -0320 -0321 % additional inversion settings -0322 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','off'); -0323 -0324 % regularization options -0325 switch data.invjoint.regtype -0326 case 'manual' -0327 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',1); -0328 case 'lcurve' -0329 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',2); -0330 end -0331 -0332 % smoothness constraint and lambda -0333 gui = updateLorderJoint(gui,data.invjoint.invtype,... -0334 data.invjoint.Lorder); -0335 gui = updateLambdaJoint(gui,'none',data.invjoint.lambda,... -0336 data.invjoint.lambdaR,data.invjoint.NlambdaR,... -0337 data.invstd.regtype); -0338 -0339 % start values -0340 set(gui.edit_handles.invjoint_rhostart,'Enable','on'); -0341 set(gui.edit_handles.invjoint_anglestart,'Enable','off'); -0342 -0343 % geometry type dependent -0344 switch data.invjoint.geometry_type -0345 case 'cyl' -0346 % geometry popup -0347 set(gui.popup_handles.invjoint_geometry_type,... -0348 'Value',1,'Enable','on'); -0349 -0350 % polygon sides and corresponding angle beta -0351 set(gui.popup_handles.invjoint_polyN,'Enable','off',... -0352 'Value',data.invjoint.polyN-2); -0353 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0354 -0355 % angles -0356 set(gui.edit_handles.invjoint_alpha,'String',''); -0357 set(gui.edit_handles.invjoint_beta,'String',''); -0358 set(gui.edit_handles.invjoint_gamma,'String',''); -0359 -0360 case 'ang' -0361 % geometry popup -0362 set(gui.popup_handles.invjoint_geometry_type,... -0363 'Value',2,'Enable','on'); -0364 -0365 % polygon sides and corresponding angle beta -0366 set(gui.popup_handles.invjoint_polyN,'Enable','off',... -0367 'Value',data.invjoint.polyN-2); -0368 set(gui.edit_handles.invjoint_beta,'Enable','on'); -0369 -0370 % angles -0371 set(gui.edit_handles.invjoint_alpha,... -0372 'String',num2str(data.invjoint.alpha)); -0373 set(gui.edit_handles.invjoint_beta,... -0374 'String',num2str(data.invjoint.beta)); -0375 set(gui.edit_handles.invjoint_gamma,... -0376 'String',num2str(data.invjoint.gamma)); -0377 -0378 case 'poly' -0379 % geometry popup -0380 set(gui.popup_handles.invjoint_geometry_type,... -0381 'Value',3,'Enable','on'); -0382 -0383 % polygon sides and corresponding angle beta -0384 set(gui.popup_handles.invjoint_polyN,'Enable','on',... -0385 'Value',data.invjoint.polyN-2); -0386 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0387 -0388 % angles -0389 polyangle = ((data.invjoint.polyN-2)/data.invjoint.polyN)*180; -0390 set(gui.edit_handles.invjoint_alpha,... -0391 'String',''); -0392 set(gui.edit_handles.invjoint_beta,... -0393 'String',num2str(polyangle)); -0394 set(gui.edit_handles.invjoint_gamma,... -0395 'String',''); -0396 end -0397 -0398 case 'shape' -0399 % inversion method popup -0400 set(gui.popup_handles.invjoint_InvType,'Value',3,'Enable','on'); -0401 -0402 % PSD limits -0403 gui = updateInvjointRadii(gui,data.invjoint.invtype,... -0404 data.invjoint.radii,data.invjoint.Nradii); -0405 -0406 % additional inversion settings -0407 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','off'); -0408 -0409 % regularization options -0410 switch data.invjoint.regtype -0411 case 'manual' -0412 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',1); -0413 case 'lcurve' -0414 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',2); -0415 end -0416 -0417 % smoothness constraint and lambda -0418 gui = updateLorderJoint(gui,data.invjoint.invtype,... -0419 data.invjoint.Lorder); -0420 gui = updateLambdaJoint(gui,'none',data.invjoint.lambda,... -0421 data.invjoint.lambdaR,data.invjoint.NlambdaR,data.invstd.regtype); +0177 % additional inversion settings +0178 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... +0179 'String',{'Manual','Automatic'}); +0180 set(gui.text_handles.invstd_InvTypeOpt,... +0181 'String','regularization options'); +0182 +0183 % regularization options +0184 switch data.invstd.regtype +0185 case 'manual' +0186 set(gui.popup_handles.invstd_InvTypeOpt,'Value',1); +0187 case 'auto' +0188 set(gui.popup_handles.invstd_InvTypeOpt,'Value',2); +0189 data.invstd.lambda = -1; +0190 end +0191 +0192 % lambda, smoothness constraint and RTD limits +0193 gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... +0194 data.invstd.lambdaR,data.invstd.NlambdaR); +0195 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); +0196 gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... +0197 data.invstd.Ntime); +0198 +0199 % RTD uncertainty +0200 set(gui.edit_handles.uncert_N,'Enable','on',... +0201 'String',num2str(data.uncert.N)); +0202 set(gui.push_handles.uncert,'Enable','on'); +0203 +0204 % Tbulk & Tdiff +0205 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... +0206 'String',num2str(data.invstd.Tbulk)); +0207 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... +0208 'String',num2str(data.invstd.Tdiff)); +0209 +0210 case 'MUMO' +0211 % inversion method popup +0212 set(gui.popup_handles.invstd_InvType,'Value',5,'Enable','on'); +0213 +0214 % additional inversion settings +0215 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... +0216 'Value',data.invstd.freeDT,... +0217 'String',{'1','2','3','4','5'}); +0218 set(gui.text_handles.invstd_InvTypeOpt,... +0219 'String','No. of modes'); +0220 +0221 % % lambda, smoothness constraint and RTD limits +0222 % gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... +0223 % data.invstd.lambdaR,data.invstd.NlambdaR); +0224 % gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); +0225 gui = updateInvstdTime(gui,data.invstd.invtype,data.invstd.time,... +0226 data.invstd.Ntime); +0227 +0228 % lambda, smoothness constraint and RTD limits +0229 gui = updateLambda(gui,data.invstd.regtype,0,0,0); +0230 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); +0231 +0232 % RTD uncertainty +0233 set(gui.edit_handles.uncert_N,'Enable','on',... +0234 'String',num2str(data.uncert.N)); +0235 set(gui.push_handles.uncert,'Enable','on'); +0236 +0237 % Tbulk & Tdiff +0238 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... +0239 'String',num2str(data.invstd.Tbulk)); +0240 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... +0241 'String',num2str(data.invstd.Tdiff)); +0242 end +0243 +0244 % updates CBW, BVI, rho and a +0245 gui = updateParams(gui,data.invstd.invtype,data.param); +0246 +0247 %% update joint inversion panel +0248 % depending if it is activated or not +0249 switch data.info.JointInv +0250 case 'on' +0251 % inversion method dependent +0252 switch data.invjoint.invtype +0253 case 'free' +0254 % inversion method popup +0255 set(gui.popup_handles.invjoint_InvType,'Value',1,'Enable','on'); +0256 +0257 % PSD limits +0258 gui = updateInvjointRadii(gui,data.invjoint.invtype,... +0259 data.invjoint.radii,data.invjoint.Nradii); +0260 +0261 % additional inversion settings +0262 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','on'); +0263 +0264 % regularization options +0265 switch data.invjoint.regtype +0266 case 'manual' +0267 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',1); +0268 case 'lcurve' +0269 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',2); +0270 end +0271 +0272 % smoothness constraint and lambda +0273 gui = updateLorderJoint(gui,data.invjoint.invtype,... +0274 data.invjoint.Lorder); +0275 gui = updateLambdaJoint(gui,data.invjoint.regtype,... +0276 data.invjoint.lambda,data.invjoint.lambdaR,... +0277 data.invjoint.NlambdaR,data.invstd.regtype); +0278 +0279 % start values +0280 set(gui.edit_handles.invjoint_rhostart,'Enable','on'); +0281 set(gui.edit_handles.invjoint_anglestart,'Enable','off'); +0282 +0283 % geometry type dependent +0284 switch data.invjoint.geometry_type +0285 case 'cyl' +0286 % geometry popup +0287 set(gui.popup_handles.invjoint_geometry_type,... +0288 'Value',1,'Enable','on'); +0289 +0290 % polygon sides and corresponding angle beta +0291 set(gui.popup_handles.invjoint_polyN,'Enable','off',... +0292 'Value',data.invjoint.polyN-2); +0293 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0294 +0295 % angles +0296 set(gui.edit_handles.invjoint_alpha,'String',''); +0297 set(gui.edit_handles.invjoint_beta,'String',''); +0298 set(gui.edit_handles.invjoint_gamma,'String',''); +0299 +0300 case 'ang' +0301 % geometry popup +0302 set(gui.popup_handles.invjoint_geometry_type,... +0303 'Value',2,'Enable','on'); +0304 +0305 % polygon sides and corresponding angle beta +0306 set(gui.popup_handles.invjoint_polyN,'Enable','off',... +0307 'Value',data.invjoint.polyN-2); +0308 set(gui.edit_handles.invjoint_beta,'Enable','on'); +0309 +0310 % angles +0311 set(gui.edit_handles.invjoint_alpha,... +0312 'String',num2str(data.invjoint.alpha)); +0313 set(gui.edit_handles.invjoint_beta,... +0314 'String',num2str(data.invjoint.beta)); +0315 set(gui.edit_handles.invjoint_gamma,... +0316 'String',num2str(data.invjoint.gamma)); +0317 +0318 case 'poly' +0319 % geometry popup +0320 set(gui.popup_handles.invjoint_geometry_type,... +0321 'Value',3,'Enable','on'); +0322 +0323 % polygon sides and corresponding angle beta +0324 set(gui.popup_handles.invjoint_polyN,'Enable','on',... +0325 'Value',data.invjoint.polyN-2); +0326 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0327 +0328 % angles +0329 polyangle = ((data.invjoint.polyN-2)/data.invjoint.polyN)*180; +0330 set(gui.edit_handles.invjoint_alpha,... +0331 'String',''); +0332 set(gui.edit_handles.invjoint_beta,... +0333 'String',num2str(polyangle)); +0334 set(gui.edit_handles.invjoint_gamma,... +0335 'String',''); +0336 end +0337 +0338 case 'fixed' +0339 % inversion method popup +0340 set(gui.popup_handles.invjoint_InvType,'Value',2,'Enable','on'); +0341 +0342 % PSD limits +0343 gui = updateInvjointRadii(gui,data.invjoint.invtype,... +0344 data.invjoint.radii,data.invjoint.Nradii); +0345 +0346 % additional inversion settings +0347 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','off'); +0348 +0349 % regularization options +0350 switch data.invjoint.regtype +0351 case 'manual' +0352 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',1); +0353 case 'lcurve' +0354 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',2); +0355 end +0356 +0357 % smoothness constraint and lambda +0358 gui = updateLorderJoint(gui,data.invjoint.invtype,... +0359 data.invjoint.Lorder); +0360 gui = updateLambdaJoint(gui,'none',data.invjoint.lambda,... +0361 data.invjoint.lambdaR,data.invjoint.NlambdaR,... +0362 data.invstd.regtype); +0363 +0364 % start values +0365 set(gui.edit_handles.invjoint_rhostart,'Enable','on'); +0366 set(gui.edit_handles.invjoint_anglestart,'Enable','off'); +0367 +0368 % geometry type dependent +0369 switch data.invjoint.geometry_type +0370 case 'cyl' +0371 % geometry popup +0372 set(gui.popup_handles.invjoint_geometry_type,... +0373 'Value',1,'Enable','on'); +0374 +0375 % polygon sides and corresponding angle beta +0376 set(gui.popup_handles.invjoint_polyN,'Enable','off',... +0377 'Value',data.invjoint.polyN-2); +0378 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0379 +0380 % angles +0381 set(gui.edit_handles.invjoint_alpha,'String',''); +0382 set(gui.edit_handles.invjoint_beta,'String',''); +0383 set(gui.edit_handles.invjoint_gamma,'String',''); +0384 +0385 case 'ang' +0386 % geometry popup +0387 set(gui.popup_handles.invjoint_geometry_type,... +0388 'Value',2,'Enable','on'); +0389 +0390 % polygon sides and corresponding angle beta +0391 set(gui.popup_handles.invjoint_polyN,'Enable','off',... +0392 'Value',data.invjoint.polyN-2); +0393 set(gui.edit_handles.invjoint_beta,'Enable','on'); +0394 +0395 % angles +0396 set(gui.edit_handles.invjoint_alpha,... +0397 'String',num2str(data.invjoint.alpha)); +0398 set(gui.edit_handles.invjoint_beta,... +0399 'String',num2str(data.invjoint.beta)); +0400 set(gui.edit_handles.invjoint_gamma,... +0401 'String',num2str(data.invjoint.gamma)); +0402 +0403 case 'poly' +0404 % geometry popup +0405 set(gui.popup_handles.invjoint_geometry_type,... +0406 'Value',3,'Enable','on'); +0407 +0408 % polygon sides and corresponding angle beta +0409 set(gui.popup_handles.invjoint_polyN,'Enable','on',... +0410 'Value',data.invjoint.polyN-2); +0411 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0412 +0413 % angles +0414 polyangle = ((data.invjoint.polyN-2)/data.invjoint.polyN)*180; +0415 set(gui.edit_handles.invjoint_alpha,... +0416 'String',''); +0417 set(gui.edit_handles.invjoint_beta,... +0418 'String',num2str(polyangle)); +0419 set(gui.edit_handles.invjoint_gamma,... +0420 'String',''); +0421 end 0422 -0423 % start values -0424 set(gui.edit_handles.invjoint_rhostart,'Enable','on'); -0425 set(gui.edit_handles.invjoint_anglestart,'Enable','on'); +0423 case 'shape' +0424 % inversion method popup +0425 set(gui.popup_handles.invjoint_InvType,'Value',3,'Enable','on'); 0426 -0427 % geometry type dependent -0428 switch data.invjoint.geometry_type -0429 case 'cyl' -0430 % geometry popup -0431 set(gui.popup_handles.invjoint_geometry_type,... -0432 'Value',1,'Enable','on'); -0433 -0434 % polygon sides and corresponding angle beta -0435 set(gui.popup_handles.invjoint_polyN,'Enable','off',... -0436 'Value',data.invjoint.polyN-2); -0437 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0438 -0439 % angles -0440 set(gui.edit_handles.invjoint_alpha,'String',''); -0441 set(gui.edit_handles.invjoint_beta,'String',''); -0442 set(gui.edit_handles.invjoint_gamma,'String',''); -0443 -0444 case 'ang' -0445 % geometry popup -0446 set(gui.popup_handles.invjoint_geometry_type,... -0447 'Value',2,'Enable','on'); -0448 -0449 % polygon sides and corresponding angle beta -0450 set(gui.popup_handles.invjoint_polyN,'Enable','off',... -0451 'Value',data.invjoint.polyN-2); -0452 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0453 -0454 % angles -0455 set(gui.edit_handles.invjoint_alpha,... -0456 'String',num2str(data.invjoint.alpha)); -0457 set(gui.edit_handles.invjoint_beta,... -0458 'String',num2str(data.invjoint.beta)); -0459 set(gui.edit_handles.invjoint_gamma,... -0460 'String',num2str(data.invjoint.gamma)); -0461 -0462 case 'poly' -0463 % geometry popup -0464 set(gui.popup_handles.invjoint_geometry_type,... -0465 'Value',3,'Enable','on'); -0466 -0467 % polygon sides and corresponding angle beta -0468 set(gui.popup_handles.invjoint_polyN,'Enable','on',... -0469 'Value',data.invjoint.polyN-2); -0470 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0471 -0472 % angles -0473 polyangle = ((data.invjoint.polyN-2)/data.invjoint.polyN)*180; -0474 set(gui.edit_handles.invjoint_alpha,... -0475 'String',''); -0476 set(gui.edit_handles.invjoint_beta,... -0477 'String',num2str(polyangle)); -0478 set(gui.edit_handles.invjoint_gamma,... -0479 'String',''); -0480 end -0481 end -0482 -0483 case 'off' -0484 % inversion method popup -0485 set(gui.popup_handles.invjoint_InvType,'Value',1,'Enable','off'); -0486 -0487 % PSD limits -0488 gui = updateInvjointRadii(gui,'off',0,0); -0489 -0490 % additional inversion settings -0491 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','off'); -0492 -0493 % smoothness constraint and lambda -0494 gui = updateLorderJoint(gui,'off',0); -0495 gui = updateLambdaJoint(gui,'none',data.invjoint.lambda,... -0496 data.invjoint.lambdaR,data.invjoint.NlambdaR,data.invstd.regtype); -0497 -0498 % polygon sides and angles -0499 set(gui.popup_handles.invjoint_polyN,'Enable','off'); -0500 set(gui.edit_handles.invjoint_alpha,'Enable','off'); -0501 set(gui.edit_handles.invjoint_beta,'Enable','off'); -0502 set(gui.edit_handles.invjoint_gamma,'Enable','off'); -0503 -0504 % start values -0505 set(gui.edit_handles.invjoint_rhostart,'Enable','off'); -0506 set(gui.edit_handles.invjoint_anglestart,'Enable','off'); -0507 end -0508 -0509 % this is always updated -0510 switch data.pressure.unit -0511 case 'Pa' -0512 set(gui.popup_handles.invjoint_pressure_units,'Value',1); -0513 case 'kPa' -0514 set(gui.popup_handles.invjoint_pressure_units,'Value',2); -0515 case 'MPa' -0516 set(gui.popup_handles.invjoint_pressure_units,'Value',3); -0517 case 'bar' -0518 set(gui.popup_handles.invjoint_pressure_units,'Value',4); -0519 end -0520 set(gui.table_handles.invjoint_table,... -0521 'ColumnName',{'use',['p [',data.pressure.unit,']'],'S [-]','D / I'}) -0522 -0523 table = data.pressure.table; -0524 for i = 1:size(table,1) -0525 table{i,2} = table{i,2}.*data.pressure.unitfac; -0526 end -0527 set(gui.table_handles.invjoint_table,'Data',table); -0528 -0529 case 'off' -0530 %% update the processing panel -0531 set(gui.edit_handles.process_start,'Enable','on',... -0532 'String',num2str(data.process.start)); -0533 set(gui.edit_handles.process_end,'Enable','on',... -0534 'String',num2str(data.process.end)); -0535 set(gui.edit_handles.process_Nechoes,'Enable','on',... -0536 'String',num2str(data.process.Nechoes)); -0537 -0538 gui = updateGatetype(gui,data.process.gatetype); -0539 set(gui.radio_handles.process_normalize_on,'Enable','off','Value',0); -0540 set(gui.radio_handles.process_normalize_off,'Enable','off','Value',1); -0541 set(gui.radio_handles.process_timescale_s,'Enable','off','Value',1); -0542 set(gui.radio_handles.process_timescale_ms,'Enable','off','Value',0); -0543 -0544 if data.invstd.porosity <= 1 -0545 set(gui.edit_handles.invstd_porosity,'Enable','on',... -0546 'BackgroundColor','w',... -0547 'String',num2str(data.invstd.porosity)); -0548 else -0549 set(gui.edit_handles.invstd_porosity,'Enable','on',... -0550 'BackgroundColor','r',... -0551 'String',num2str(data.invstd.porosity)); -0552 end +0427 % PSD limits +0428 gui = updateInvjointRadii(gui,data.invjoint.invtype,... +0429 data.invjoint.radii,data.invjoint.Nradii); +0430 +0431 % additional inversion settings +0432 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','off'); +0433 +0434 % regularization options +0435 switch data.invjoint.regtype +0436 case 'manual' +0437 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',1); +0438 case 'lcurve' +0439 set(gui.popup_handles.invjoint_InvTypeOpt,'Value',2); +0440 end +0441 +0442 % smoothness constraint and lambda +0443 gui = updateLorderJoint(gui,data.invjoint.invtype,... +0444 data.invjoint.Lorder); +0445 gui = updateLambdaJoint(gui,'none',data.invjoint.lambda,... +0446 data.invjoint.lambdaR,data.invjoint.NlambdaR,data.invstd.regtype); +0447 +0448 % start values +0449 set(gui.edit_handles.invjoint_rhostart,'Enable','on'); +0450 set(gui.edit_handles.invjoint_anglestart,'Enable','on'); +0451 +0452 % geometry type dependent +0453 switch data.invjoint.geometry_type +0454 case 'cyl' +0455 % geometry popup +0456 set(gui.popup_handles.invjoint_geometry_type,... +0457 'Value',1,'Enable','on'); +0458 +0459 % polygon sides and corresponding angle beta +0460 set(gui.popup_handles.invjoint_polyN,'Enable','off',... +0461 'Value',data.invjoint.polyN-2); +0462 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0463 +0464 % angles +0465 set(gui.edit_handles.invjoint_alpha,'String',''); +0466 set(gui.edit_handles.invjoint_beta,'String',''); +0467 set(gui.edit_handles.invjoint_gamma,'String',''); +0468 +0469 case 'ang' +0470 % geometry popup +0471 set(gui.popup_handles.invjoint_geometry_type,... +0472 'Value',2,'Enable','on'); +0473 +0474 % polygon sides and corresponding angle beta +0475 set(gui.popup_handles.invjoint_polyN,'Enable','off',... +0476 'Value',data.invjoint.polyN-2); +0477 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0478 +0479 % angles +0480 set(gui.edit_handles.invjoint_alpha,... +0481 'String',num2str(data.invjoint.alpha)); +0482 set(gui.edit_handles.invjoint_beta,... +0483 'String',num2str(data.invjoint.beta)); +0484 set(gui.edit_handles.invjoint_gamma,... +0485 'String',num2str(data.invjoint.gamma)); +0486 +0487 case 'poly' +0488 % geometry popup +0489 set(gui.popup_handles.invjoint_geometry_type,... +0490 'Value',3,'Enable','on'); +0491 +0492 % polygon sides and corresponding angle beta +0493 set(gui.popup_handles.invjoint_polyN,'Enable','on',... +0494 'Value',data.invjoint.polyN-2); +0495 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0496 +0497 % angles +0498 polyangle = ((data.invjoint.polyN-2)/data.invjoint.polyN)*180; +0499 set(gui.edit_handles.invjoint_alpha,... +0500 'String',''); +0501 set(gui.edit_handles.invjoint_beta,... +0502 'String',num2str(polyangle)); +0503 set(gui.edit_handles.invjoint_gamma,... +0504 'String',''); +0505 end +0506 end +0507 +0508 case 'off' +0509 % inversion method popup +0510 set(gui.popup_handles.invjoint_InvType,'Value',1,'Enable','off'); +0511 +0512 % PSD limits +0513 gui = updateInvjointRadii(gui,'off',0,0); +0514 +0515 % additional inversion settings +0516 set(gui.popup_handles.invjoint_InvTypeOpt,'Enable','off'); +0517 +0518 % smoothness constraint and lambda +0519 gui = updateLorderJoint(gui,'off',0); +0520 gui = updateLambdaJoint(gui,'none',data.invjoint.lambda,... +0521 data.invjoint.lambdaR,data.invjoint.NlambdaR,data.invstd.regtype); +0522 +0523 % polygon sides and angles +0524 set(gui.popup_handles.invjoint_polyN,'Enable','off'); +0525 set(gui.edit_handles.invjoint_alpha,'Enable','off'); +0526 set(gui.edit_handles.invjoint_beta,'Enable','off'); +0527 set(gui.edit_handles.invjoint_gamma,'Enable','off'); +0528 +0529 % start values +0530 set(gui.edit_handles.invjoint_rhostart,'Enable','off'); +0531 set(gui.edit_handles.invjoint_anglestart,'Enable','off'); +0532 end +0533 +0534 % this is always updated +0535 switch data.pressure.unit +0536 case 'Pa' +0537 set(gui.popup_handles.invjoint_pressure_units,'Value',1); +0538 case 'kPa' +0539 set(gui.popup_handles.invjoint_pressure_units,'Value',2); +0540 case 'MPa' +0541 set(gui.popup_handles.invjoint_pressure_units,'Value',3); +0542 case 'bar' +0543 set(gui.popup_handles.invjoint_pressure_units,'Value',4); +0544 end +0545 set(gui.table_handles.invjoint_table,... +0546 'ColumnName',{'use',['p [',data.pressure.unit,']'],'S [-]','D / I'}) +0547 +0548 table = data.pressure.table; +0549 for i = 1:size(table,1) +0550 table{i,2} = table{i,2}.*data.pressure.unitfac; +0551 end +0552 set(gui.table_handles.invjoint_table,'Data',table); 0553 -0554 %% update standard inversion panel -0555 % inversion method popup -0556 istring = {'Mono exp.','Several free exp. (2-5)','Multi exp. (LSQ)'}; -0557 set(gui.popup_handles.invstd_InvType,'String',istring); -0558 switch data.invstd.invtype -0559 case 'mono' -0560 % inversion method popup -0561 set(gui.popup_handles.invstd_InvType,'Value',1,'Enable','on'); -0562 -0563 % additional inversion settings -0564 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','off',... -0565 'Value',1,'String','none'); -0566 set(gui.text_handles.invstd_InvTypeOpt,... -0567 'String','No extra options'); -0568 -0569 % lambda, smoothness constraint and RTD limits -0570 gui = updateLambda(gui,data.invstd.regtype,0,0,0); -0571 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); -0572 gui = updateInvstdTime(gui,data.invstd.invtype,0,0); -0573 -0574 % Tbulk & Tdiff -0575 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... -0576 'String',num2str(data.invstd.Tbulk)); -0577 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... -0578 'String',num2str(data.invstd.Tdiff)); -0579 -0580 case 'free' -0581 % inversion method popup -0582 set(gui.popup_handles.invstd_InvType,'Value',2,'Enable','on'); -0583 -0584 % additional inversion settings -0585 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... -0586 'Value',data.invstd.freeDT,... -0587 'String',{'1','2','3','4','5'}); -0588 set(gui.text_handles.invstd_InvTypeOpt,... -0589 'String','No. of relaxation decay times T'); -0590 -0591 % lambda, smoothness constraint and RTD limits -0592 gui = updateLambda(gui,data.invstd.regtype,0,0,0); -0593 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); -0594 gui = updateInvstdTime(gui,data.invstd.invtype,0,0); -0595 -0596 % Tbulk & Tdiff -0597 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... -0598 'String',num2str(data.invstd.Tbulk)); -0599 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... -0600 'String',num2str(data.invstd.Tdiff)); -0601 -0602 case 'NNLS' -0603 % inversion method popup -0604 set(gui.popup_handles.invstd_InvType,'Value',3,'Enable','on'); -0605 -0606 % additional inversion settings -0607 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... -0608 'String',{'Manual','L-curve'}); -0609 set(gui.text_handles.invstd_InvTypeOpt,... -0610 'String','regularization options'); -0611 -0612 % regularization options -0613 switch data.invstd.regtype -0614 case 'manual' -0615 set(gui.popup_handles.invstd_InvTypeOpt,'Value',1); -0616 case 'lcurve' -0617 set(gui.popup_handles.invstd_InvTypeOpt,'Value',2); -0618 end -0619 -0620 % lambda, smoothness constraint and RTD limits -0621 gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... -0622 data.invstd.lambdaR,data.invstd.NlambdaR); -0623 data.invstd.Lorder = 1; -0624 set(gui.radio_handles.invstd_Lorder0,'Value',0,'Enable','off'); -0625 set(gui.radio_handles.invstd_Lorder1,'Value',1,'Enable','off'); -0626 set(gui.radio_handles.invstd_Lorder2,'Value',0,'Enable','off'); -0627 -0628 set(gui.edit_handles.invstd_time_min,'Enable','on',... -0629 'String',num2str(data.invstd.time(1))); -0630 set(gui.edit_handles.invstd_time_max,'Enable','on',... -0631 'String',num2str(data.invstd.time(2))); -0632 set(gui.edit_handles.invstd_Ntime,'Enable','off',... -0633 'String',num2str(data.invstd.Ntime)); -0634 -0635 % Tbulk & Tdiff -0636 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... -0637 'String',num2str(data.invstd.Tbulk)); -0638 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... -0639 'String',num2str(data.invstd.Tdiff)); -0640 end -0641 -0642 %% update petro parameter panel -0643 data.param.CBWcutoff = 3; -0644 data.param.BVIcutoff = 33; -0645 data.param.rho = 10; -0646 data.param.a = 2; -0647 setappdata(fig,'data',data); -0648 set(gui.edit_handles.param_CBW,'Enable','off',... -0649 'String',num2str(data.param.CBWcutoff)); -0650 set(gui.edit_handles.param_BVI,'Enable','off',... -0651 'String',num2str(data.param.BVIcutoff)); -0652 set(gui.edit_handles.param_rho,'Enable','off',... -0653 'String',num2str(data.param.rho)); -0654 set(gui.edit_handles.param_geom,'Enable','off',... -0655 'String',num2str(data.param.a)); -0656 set(gui.edit_handles.param_calibVol,'Enable','on',... -0657 'String',num2str(data.param.calibVol)); -0658 set(gui.edit_handles.param_calibAmp,'Enable','on',... -0659 'String',num2str(data.param.calibAmp)); -0660 set(gui.edit_handles.param_sampVol,'Enable','on',... -0661 'String',num2str(data.param.sampVol)); -0662 end -0663 -0664 % Matlab needs some time -0665 pause(0.001); -0666 -0667 end -0668 -0669 %% sub functions -0670 function gui = updateGatetype(gui,gatetype) -0671 -0672 set(gui.radio_handles.process_gates_log,'Enable','on'); -0673 set(gui.radio_handles.process_gates_lin,'Enable','on'); -0674 set(gui.radio_handles.process_gates_none,'Enable','on'); -0675 -0676 switch gatetype -0677 -0678 case 'log' -0679 set(gui.radio_handles.process_gates_log,'Value',1); -0680 set(gui.radio_handles.process_gates_lin,'Value',0); -0681 set(gui.radio_handles.process_gates_none,'Value',0); -0682 set(gui.edit_handles.process_Nechoes,'Enable','on'); -0683 -0684 case 'lin' -0685 set(gui.radio_handles.process_gates_log,'Value',0); -0686 set(gui.radio_handles.process_gates_lin,'Value',1); -0687 set(gui.radio_handles.process_gates_none,'Value',0); -0688 set(gui.edit_handles.process_Nechoes,'Enable','on'); -0689 -0690 case 'raw' -0691 set(gui.radio_handles.process_gates_log,'Value',0); -0692 set(gui.radio_handles.process_gates_lin,'Value',0); -0693 set(gui.radio_handles.process_gates_none,'Value',1); -0694 set(gui.edit_handles.process_Nechoes,'Enable','off'); -0695 -0696 end -0697 -0698 end -0699 -0700 function gui = updateNormalize(gui,norm) -0701 -0702 switch norm -0703 case 0 -0704 set(gui.radio_handles.process_normalize_on,'Enable','on','Value',0); -0705 set(gui.radio_handles.process_normalize_off,'Enable','on','Value',1); -0706 -0707 case 1 -0708 set(gui.radio_handles.process_normalize_on,'Enable','on','Value',1); -0709 set(gui.radio_handles.process_normalize_off,'Enable','on','Value',0); -0710 end +0554 case 'off' +0555 %% update the processing panel +0556 set(gui.edit_handles.process_start,'Enable','on',... +0557 'String',num2str(data.process.start)); +0558 set(gui.edit_handles.process_end,'Enable','on',... +0559 'String',num2str(data.process.end)); +0560 set(gui.edit_handles.process_Nechoes,'Enable','on',... +0561 'String',num2str(data.process.Nechoes)); +0562 +0563 gui = updateGatetype(gui,data.process.gatetype); +0564 set(gui.radio_handles.process_normalize_on,'Enable','off','Value',0); +0565 set(gui.radio_handles.process_normalize_off,'Enable','off','Value',1); +0566 set(gui.radio_handles.process_timescale_s,'Enable','off','Value',1); +0567 set(gui.radio_handles.process_timescale_ms,'Enable','off','Value',0); +0568 +0569 if data.invstd.porosity <= 1 +0570 set(gui.edit_handles.invstd_porosity,'Enable','on',... +0571 'BackgroundColor','w',... +0572 'String',num2str(data.invstd.porosity)); +0573 else +0574 set(gui.edit_handles.invstd_porosity,'Enable','on',... +0575 'BackgroundColor','r',... +0576 'String',num2str(data.invstd.porosity)); +0577 end +0578 +0579 %% update standard inversion panel +0580 % inversion method popup +0581 istring = {'Mono exp.','Several free exp. (2-5)','Multi exp. (LSQ)'}; +0582 set(gui.popup_handles.invstd_InvType,'String',istring); +0583 switch data.invstd.invtype +0584 case 'mono' +0585 % inversion method popup +0586 set(gui.popup_handles.invstd_InvType,'Value',1,'Enable','on'); +0587 +0588 % additional inversion settings +0589 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','off',... +0590 'Value',1,'String','none'); +0591 set(gui.text_handles.invstd_InvTypeOpt,... +0592 'String','No extra options'); +0593 +0594 % lambda, smoothness constraint and RTD limits +0595 gui = updateLambda(gui,data.invstd.regtype,0,0,0); +0596 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); +0597 gui = updateInvstdTime(gui,data.invstd.invtype,0,0); +0598 +0599 % RTD uncertainty +0600 set(gui.edit_handles.uncert_N,'Enable','off',... +0601 'String',num2str(data.uncert.N)); +0602 set(gui.push_handles.uncert,'Enable','off'); +0603 +0604 % Tbulk & Tdiff +0605 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... +0606 'String',num2str(data.invstd.Tbulk)); +0607 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... +0608 'String',num2str(data.invstd.Tdiff)); +0609 +0610 case 'free' +0611 % inversion method popup +0612 set(gui.popup_handles.invstd_InvType,'Value',2,'Enable','on'); +0613 +0614 % additional inversion settings +0615 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... +0616 'Value',data.invstd.freeDT,... +0617 'String',{'1','2','3','4','5'}); +0618 set(gui.text_handles.invstd_InvTypeOpt,... +0619 'String','No. of free relaxation times T'); +0620 +0621 % lambda, smoothness constraint and RTD limits +0622 gui = updateLambda(gui,data.invstd.regtype,0,0,0); +0623 gui = updateLorder(gui,data.invstd.invtype,data.invstd.Lorder); +0624 gui = updateInvstdTime(gui,data.invstd.invtype,0,0); +0625 +0626 % RTD uncertainty +0627 set(gui.edit_handles.uncert_N,'Enable','off',... +0628 'String',num2str(data.uncert.N)); +0629 set(gui.push_handles.uncert,'Enable','off'); +0630 +0631 % Tbulk & Tdiff +0632 set(gui.edit_handles.invstd_Tbulk,'Enable','off',... +0633 'String',num2str(data.invstd.Tbulk)); +0634 set(gui.edit_handles.invstd_Tdiff,'Enable','off',... +0635 'String',num2str(data.invstd.Tdiff)); +0636 +0637 case 'NNLS' +0638 % inversion method popup +0639 set(gui.popup_handles.invstd_InvType,'Value',3,'Enable','on'); +0640 +0641 % additional inversion settings +0642 set(gui.popup_handles.invstd_InvTypeOpt,'Enable','on',... +0643 'String',{'Manual','L-curve'}); +0644 set(gui.text_handles.invstd_InvTypeOpt,... +0645 'String','regularization options'); +0646 +0647 % regularization options +0648 switch data.invstd.regtype +0649 case 'manual' +0650 set(gui.popup_handles.invstd_InvTypeOpt,'Value',1); +0651 case 'lcurve' +0652 set(gui.popup_handles.invstd_InvTypeOpt,'Value',2); +0653 end +0654 +0655 % lambda, smoothness constraint and RTD limits +0656 gui = updateLambda(gui,data.invstd.regtype,data.invstd.lambda,... +0657 data.invstd.lambdaR,data.invstd.NlambdaR); +0658 data.invstd.Lorder = 1; +0659 set(gui.radio_handles.invstd_Lorder0,'Value',0,'Enable','off'); +0660 set(gui.radio_handles.invstd_Lorder1,'Value',1,'Enable','off'); +0661 set(gui.radio_handles.invstd_Lorder2,'Value',0,'Enable','off'); +0662 +0663 set(gui.edit_handles.invstd_time_min,'Enable','on',... +0664 'String',num2str(data.invstd.time(1))); +0665 set(gui.edit_handles.invstd_time_max,'Enable','on',... +0666 'String',num2str(data.invstd.time(2))); +0667 set(gui.edit_handles.invstd_Ntime,'Enable','off',... +0668 'String',num2str(data.invstd.Ntime)); +0669 +0670 % RTD uncertainty +0671 set(gui.edit_handles.uncert_N,'Enable','on',... +0672 'String',num2str(data.uncert.N)); +0673 set(gui.push_handles.uncert,'Enable','on'); +0674 +0675 % Tbulk & Tdiff +0676 set(gui.edit_handles.invstd_Tbulk,'Enable','on',... +0677 'String',num2str(data.invstd.Tbulk)); +0678 set(gui.edit_handles.invstd_Tdiff,'Enable','on',... +0679 'String',num2str(data.invstd.Tdiff)); +0680 end +0681 +0682 %% update petro parameter panel +0683 data.param.CBWcutoff = 3; +0684 data.param.BVIcutoff = 33; +0685 data.param.rho = 10; +0686 data.param.a = 2; +0687 setappdata(fig,'data',data); +0688 set(gui.edit_handles.param_CBW,'Enable','off',... +0689 'String',num2str(data.param.CBWcutoff)); +0690 set(gui.edit_handles.param_BVI,'Enable','off',... +0691 'String',num2str(data.param.BVIcutoff)); +0692 set(gui.edit_handles.param_rho,'Enable','off',... +0693 'String',num2str(data.param.rho)); +0694 set(gui.edit_handles.param_geom,'Enable','off',... +0695 'String',num2str(data.param.a)); +0696 set(gui.edit_handles.param_calibVol,'Enable','on',... +0697 'String',num2str(data.param.calibVol)); +0698 set(gui.edit_handles.param_calibAmp,'Enable','on',... +0699 'String',num2str(data.param.calibAmp)); +0700 set(gui.edit_handles.param_sampVol,'Enable','on',... +0701 'String',num2str(data.param.sampVol)); +0702 end +0703 +0704 % Matlab needs some time +0705 pause(0.001); +0706 +0707 end +0708 +0709 %% sub functions +0710 function gui = updateGatetype(gui,gatetype) 0711 -0712 end -0713 -0714 function gui = updateTimescale(gui,timescale) +0712 set(gui.radio_handles.process_gates_log,'Enable','on'); +0713 set(gui.radio_handles.process_gates_lin,'Enable','on'); +0714 set(gui.radio_handles.process_gates_none,'Enable','on'); 0715 -0716 switch timescale +0716 switch gatetype 0717 -0718 case 's' -0719 set(gui.radio_handles.process_timescale_s,'Enable','on','Value',1); -0720 set(gui.radio_handles.process_timescale_ms,'Enable','on','Value',0); -0721 set(gui.text_handles.invstd_RTDtimes,'String','RTD - min [s] | max [s] | # / dec',... -0722 'FontSize',10); -0723 set(gui.text_handles.petro_Tbulk,'String','Tbulk [s] | Tdiff [s]'); -0724 set(gui.text_handles.petro_rho,'String',[char(hex2dec('03C1')),' [µm/s] | geom ']); -0725 -0726 case 'ms' -0727 set(gui.radio_handles.process_timescale_s,'Enable','on','Value',0); -0728 set(gui.radio_handles.process_timescale_ms,'Enable','on','Value',1); -0729 set(gui.text_handles.invstd_RTDtimes,'String','RTD - min [ms] | max [ms] | # / dec',... -0730 'FontSize',9); -0731 set(gui.text_handles.petro_Tbulk,'String','Tbulk [ms] | Tdiff [ms]'); -0732 set(gui.text_handles.petro_rho,'String',[char(hex2dec('03C1')),' [µm/s] | geom ']); -0733 end -0734 -0735 end -0736 -0737 function gui = updateInvstdTime(gui,invtype,time,Ntime) -0738 -0739 switch invtype -0740 -0741 case {'mono','free'} -0742 set(gui.edit_handles.invstd_time_min,'Enable','off'); -0743 set(gui.edit_handles.invstd_time_max,'Enable','off'); -0744 set(gui.edit_handles.invstd_Ntime,'Enable','off'); -0745 -0746 case {'LU','NNLS','MUMO'} -0747 set(gui.edit_handles.invstd_time_min,'Enable','on','String',num2str(time(1))); -0748 set(gui.edit_handles.invstd_time_max,'Enable','on','String',num2str(time(2))); -0749 set(gui.edit_handles.invstd_Ntime,'Enable','on','String',num2str(Ntime)); +0718 case 'log' +0719 set(gui.radio_handles.process_gates_log,'Value',1); +0720 set(gui.radio_handles.process_gates_lin,'Value',0); +0721 set(gui.radio_handles.process_gates_none,'Value',0); +0722 set(gui.edit_handles.process_Nechoes,'Enable','on'); +0723 +0724 case 'lin' +0725 set(gui.radio_handles.process_gates_log,'Value',0); +0726 set(gui.radio_handles.process_gates_lin,'Value',1); +0727 set(gui.radio_handles.process_gates_none,'Value',0); +0728 set(gui.edit_handles.process_Nechoes,'Enable','on'); +0729 +0730 case 'raw' +0731 set(gui.radio_handles.process_gates_log,'Value',0); +0732 set(gui.radio_handles.process_gates_lin,'Value',0); +0733 set(gui.radio_handles.process_gates_none,'Value',1); +0734 set(gui.edit_handles.process_Nechoes,'Enable','off'); +0735 +0736 end +0737 +0738 end +0739 +0740 function gui = updateNormalize(gui,norm) +0741 +0742 switch norm +0743 case 0 +0744 set(gui.radio_handles.process_normalize_on,'Enable','on','Value',0); +0745 set(gui.radio_handles.process_normalize_off,'Enable','on','Value',1); +0746 +0747 case 1 +0748 set(gui.radio_handles.process_normalize_on,'Enable','on','Value',1); +0749 set(gui.radio_handles.process_normalize_off,'Enable','on','Value',0); 0750 end 0751 0752 end 0753 -0754 function gui = updateInvjointRadii(gui,invtype,radii,Nradii) +0754 function gui = updateTimescale(gui,timescale) 0755 -0756 switch invtype -0757 case {'fixed','shape','off'} -0758 set(gui.edit_handles.invjoint_radii_min,'Enable','off'); -0759 set(gui.edit_handles.invjoint_radii_max,'Enable','off'); -0760 set(gui.edit_handles.invjoint_Nradii,'Enable','off'); -0761 -0762 case {'free'} -0763 set(gui.edit_handles.invjoint_radii_min,'Enable','on','String',num2str(radii(1))); -0764 set(gui.edit_handles.invjoint_radii_max,'Enable','on','String',num2str(radii(2))); -0765 set(gui.edit_handles.invjoint_Nradii,'Enable','on','String',num2str(Nradii)); -0766 end -0767 -0768 end -0769 -0770 function gui = updateLambda(gui,regtype,lambda,lambdaR,NlambdaR) -0771 -0772 switch regtype -0773 case 'none' -0774 set(gui.edit_handles.invstd_lambda_min,'Enable','off'); -0775 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); -0776 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); -0777 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; -0778 -0779 case 'manual' -0780 set(gui.edit_handles.invstd_lambda_min,'Enable','on','String',num2str(lambda)); -0781 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); -0782 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); -0783 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; -0784 -0785 case 'auto' -0786 set(gui.edit_handles.invstd_lambda_min,'Enable','off','String',num2str(lambda)); -0787 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); -0788 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); -0789 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; -0790 -0791 case 'lcurve' -0792 set(gui.edit_handles.invstd_lambda_min,'Enable','on','String',num2str(lambdaR(1))); -0793 set(gui.edit_handles.invstd_lambda_max,'Enable','on','String',num2str(lambdaR(2))); -0794 set(gui.edit_handles.invstd_NlambdaR,'Enable','on','String',num2str(NlambdaR)); -0795 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; -0796 -0797 case {'gcv_tikh','gcv_trunc','gcv_damp','discrep'} -0798 set(gui.edit_handles.invstd_lambda_min,'Enable','off','String',num2str(lambda)); -0799 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); -0800 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); -0801 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; -0802 end -0803 -0804 end -0805 -0806 function gui = updateLambdaJoint(gui,regtype,lambda,lambdaR,NlambdaR,regtypestd) +0756 switch timescale +0757 +0758 case 's' +0759 set(gui.radio_handles.process_timescale_s,'Enable','on','Value',1); +0760 set(gui.radio_handles.process_timescale_ms,'Enable','on','Value',0); +0761 set(gui.text_handles.invstd_RTDtimes,'String','RTD - min [s] | max [s] | # / dec',... +0762 'FontSize',10); +0763 set(gui.text_handles.petro_Tbulk,'String','Tbulk [s] | Tdiff [s]'); +0764 set(gui.text_handles.petro_rho,'String',[char(hex2dec('03C1')),' [µm/s] | geom ']); +0765 +0766 case 'ms' +0767 set(gui.radio_handles.process_timescale_s,'Enable','on','Value',0); +0768 set(gui.radio_handles.process_timescale_ms,'Enable','on','Value',1); +0769 set(gui.text_handles.invstd_RTDtimes,'String','RTD - min [ms] | max [ms] | # / dec',... +0770 'FontSize',9); +0771 set(gui.text_handles.petro_Tbulk,'String','Tbulk [ms] | Tdiff [ms]'); +0772 set(gui.text_handles.petro_rho,'String',[char(hex2dec('03C1')),' [µm/s] | geom ']); +0773 end +0774 +0775 end +0776 +0777 function gui = updateInvstdTime(gui,invtype,time,Ntime) +0778 +0779 switch invtype +0780 +0781 case {'mono','free'} +0782 set(gui.edit_handles.invstd_time_min,'Enable','off'); +0783 set(gui.edit_handles.invstd_time_max,'Enable','off'); +0784 set(gui.edit_handles.invstd_Ntime,'Enable','off'); +0785 +0786 case {'LU','NNLS','MUMO'} +0787 set(gui.edit_handles.invstd_time_min,'Enable','on','String',num2str(time(1))); +0788 set(gui.edit_handles.invstd_time_max,'Enable','on','String',num2str(time(2))); +0789 set(gui.edit_handles.invstd_Ntime,'Enable','on','String',num2str(Ntime)); +0790 end +0791 +0792 end +0793 +0794 function gui = updateInvjointRadii(gui,invtype,radii,Nradii) +0795 +0796 switch invtype +0797 case {'fixed','shape','off'} +0798 set(gui.edit_handles.invjoint_radii_min,'Enable','off'); +0799 set(gui.edit_handles.invjoint_radii_max,'Enable','off'); +0800 set(gui.edit_handles.invjoint_Nradii,'Enable','off'); +0801 +0802 case {'free'} +0803 set(gui.edit_handles.invjoint_radii_min,'Enable','on','String',num2str(radii(1))); +0804 set(gui.edit_handles.invjoint_radii_max,'Enable','on','String',num2str(radii(2))); +0805 set(gui.edit_handles.invjoint_Nradii,'Enable','on','String',num2str(Nradii)); +0806 end 0807 -0808 switch regtype -0809 case 'none' -0810 switch regtypestd -0811 case 'lcurve' -0812 set(gui.edit_handles.invjoint_lambda_min,'Enable','off'); -0813 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); -0814 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); -0815 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; -0816 -0817 otherwise -0818 set(gui.edit_handles.invjoint_lambda_min,'Enable','off'); -0819 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); -0820 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); -0821 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; -0822 end -0823 -0824 case 'manual' -0825 switch regtypestd -0826 case 'lcurve' -0827 set(gui.edit_handles.invjoint_lambda_min,'Enable','on','String',num2str(lambda)); -0828 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); -0829 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); -0830 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; -0831 -0832 otherwise -0833 set(gui.edit_handles.invjoint_lambda_min,'Enable','on','String',num2str(lambda)); -0834 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); -0835 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); -0836 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; -0837 end -0838 -0839 case 'lcurve' -0840 set(gui.edit_handles.invjoint_lambda_min,'Enable','on','String',num2str(lambdaR(1))); -0841 set(gui.edit_handles.invjoint_lambda_max,'Enable','on','String',num2str(lambdaR(2))); -0842 set(gui.edit_handles.invjoint_NlambdaR,'Enable','on','String',num2str(NlambdaR)); -0843 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; +0808 end +0809 +0810 function gui = updateLambda(gui,regtype,lambda,lambdaR,NlambdaR) +0811 +0812 switch regtype +0813 case 'none' +0814 set(gui.edit_handles.invstd_lambda_min,'Enable','off'); +0815 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); +0816 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); +0817 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; +0818 +0819 case 'manual' +0820 set(gui.edit_handles.invstd_lambda_min,'Enable','on','String',num2str(lambda)); +0821 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); +0822 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); +0823 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; +0824 +0825 case 'auto' +0826 set(gui.edit_handles.invstd_lambda_min,'Enable','off','String',num2str(lambda)); +0827 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); +0828 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); +0829 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; +0830 +0831 case 'lcurve' +0832 set(gui.edit_handles.invstd_lambda_min,'Enable','on','String',num2str(lambdaR(1))); +0833 set(gui.edit_handles.invstd_lambda_max,'Enable','on','String',num2str(lambdaR(2))); +0834 set(gui.edit_handles.invstd_NlambdaR,'Enable','on','String',num2str(NlambdaR)); +0835 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; +0836 +0837 case {'gcv_tikh','gcv_trunc','gcv_damp','discrep'} +0838 set(gui.edit_handles.invstd_lambda_min,'Enable','off','String',num2str(lambda)); +0839 set(gui.edit_handles.invstd_lambda_max,'Enable','off'); +0840 set(gui.edit_handles.invstd_NlambdaR,'Enable','off'); +0841 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; +0842 end +0843 0844 end 0845 -0846 end +0846 function gui = updateLambdaJoint(gui,regtype,lambda,lambdaR,NlambdaR,regtypestd) 0847 -0848 function gui = updateLorder(gui,invtype,Lorder) -0849 -0850 switch invtype -0851 case {'mono','free','MUMO'} -0852 set(gui.radio_handles.invstd_Lorder0,'Enable','off'); -0853 set(gui.radio_handles.invstd_Lorder1,'Enable','off'); -0854 set(gui.radio_handles.invstd_Lorder2,'Enable','off'); -0855 -0856 case {'LU','NNLS'} -0857 set(gui.radio_handles.invstd_Lorder0,'Enable','on'); -0858 set(gui.radio_handles.invstd_Lorder1,'Enable','on'); -0859 set(gui.radio_handles.invstd_Lorder2,'Enable','on'); -0860 -0861 switch Lorder -0862 case 0 -0863 set(gui.radio_handles.invstd_Lorder0,'Value',1); -0864 set(gui.radio_handles.invstd_Lorder1,'Value',0); -0865 set(gui.radio_handles.invstd_Lorder2,'Value',0); -0866 -0867 case 1 -0868 set(gui.radio_handles.invstd_Lorder0,'Value',0); -0869 set(gui.radio_handles.invstd_Lorder1,'Value',1); -0870 set(gui.radio_handles.invstd_Lorder2,'Value',0); +0848 switch regtype +0849 case 'none' +0850 switch regtypestd +0851 case 'lcurve' +0852 set(gui.edit_handles.invjoint_lambda_min,'Enable','off'); +0853 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); +0854 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); +0855 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; +0856 +0857 otherwise +0858 set(gui.edit_handles.invjoint_lambda_min,'Enable','off'); +0859 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); +0860 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); +0861 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; +0862 end +0863 +0864 case 'manual' +0865 switch regtypestd +0866 case 'lcurve' +0867 set(gui.edit_handles.invjoint_lambda_min,'Enable','on','String',num2str(lambda)); +0868 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); +0869 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); +0870 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; 0871 -0872 case 2 -0873 set(gui.radio_handles.invstd_Lorder0,'Value',0); -0874 set(gui.radio_handles.invstd_Lorder1,'Value',0); -0875 set(gui.radio_handles.invstd_Lorder2,'Value',1); -0876 end -0877 end -0878 -0879 end -0880 -0881 function gui = updateLorderJoint(gui,invtype,Lorder) -0882 -0883 switch invtype -0884 case {'fixed','shape','off'} -0885 set(gui.radio_handles.invjoint_Lorder0,'Enable','off'); -0886 set(gui.radio_handles.invjoint_Lorder1,'Enable','off'); -0887 set(gui.radio_handles.invjoint_Lorder2,'Enable','off'); -0888 -0889 case 'free' -0890 set(gui.radio_handles.invjoint_Lorder0,'Enable','on'); -0891 set(gui.radio_handles.invjoint_Lorder1,'Enable','on'); -0892 set(gui.radio_handles.invjoint_Lorder2,'Enable','on'); -0893 -0894 switch Lorder -0895 case 0 -0896 set(gui.radio_handles.invjoint_Lorder0,'Value',1); -0897 set(gui.radio_handles.invjoint_Lorder1,'Value',0); -0898 set(gui.radio_handles.invjoint_Lorder2,'Value',0); -0899 -0900 case 1 -0901 set(gui.radio_handles.invjoint_Lorder0,'Value',0); -0902 set(gui.radio_handles.invjoint_Lorder1,'Value',1); -0903 set(gui.radio_handles.invjoint_Lorder2,'Value',0); -0904 -0905 case 2 -0906 set(gui.radio_handles.invjoint_Lorder0,'Value',0); -0907 set(gui.radio_handles.invjoint_Lorder1,'Value',0); -0908 set(gui.radio_handles.invjoint_Lorder2,'Value',1); -0909 end -0910 end -0911 -0912 end -0913 -0914 function gui = updateParams(gui,invtype,p) -0915 -0916 switch invtype -0917 case {'mono','free'} -0918 set(gui.edit_handles.param_CBW,'Enable','off','String',num2str(p.CBWcutoff)); -0919 set(gui.edit_handles.param_BVI,'Enable','off','String',num2str(p.BVIcutoff)); -0920 set(gui.edit_handles.param_rho,'Enable','on','String',num2str(p.rho)); -0921 set(gui.edit_handles.param_geom,'Enable','on','String',num2str(p.a)); -0922 -0923 case {'LU','NNLS','MUMO'} -0924 set(gui.edit_handles.param_CBW,'Enable','on','String',num2str(p.CBWcutoff)); -0925 set(gui.edit_handles.param_BVI,'Enable','on','String',num2str(p.BVIcutoff)); -0926 set(gui.edit_handles.param_rho,'Enable','on','String',num2str(p.rho)); -0927 set(gui.edit_handles.param_geom,'Enable','on','String',num2str(p.a)); +0872 otherwise +0873 set(gui.edit_handles.invjoint_lambda_min,'Enable','on','String',num2str(lambda)); +0874 set(gui.edit_handles.invjoint_lambda_max,'Enable','off'); +0875 set(gui.edit_handles.invjoint_NlambdaR,'Enable','off'); +0876 gui.plots.DistPanel.TabTitles = {'RTD','PSD','PSD (joint)'}; +0877 end +0878 +0879 case 'lcurve' +0880 set(gui.edit_handles.invjoint_lambda_min,'Enable','on','String',num2str(lambdaR(1))); +0881 set(gui.edit_handles.invjoint_lambda_max,'Enable','on','String',num2str(lambdaR(2))); +0882 set(gui.edit_handles.invjoint_NlambdaR,'Enable','on','String',num2str(NlambdaR)); +0883 gui.plots.DistPanel.TabTitles = {'L-CURVE','RMS','PSD (joint)'}; +0884 end +0885 +0886 end +0887 +0888 function gui = updateLorder(gui,invtype,Lorder) +0889 +0890 switch invtype +0891 case {'mono','free','MUMO'} +0892 set(gui.radio_handles.invstd_Lorder0,'Enable','off'); +0893 set(gui.radio_handles.invstd_Lorder1,'Enable','off'); +0894 set(gui.radio_handles.invstd_Lorder2,'Enable','off'); +0895 +0896 case {'LU','NNLS'} +0897 set(gui.radio_handles.invstd_Lorder0,'Enable','on'); +0898 set(gui.radio_handles.invstd_Lorder1,'Enable','on'); +0899 set(gui.radio_handles.invstd_Lorder2,'Enable','on'); +0900 +0901 switch Lorder +0902 case 0 +0903 set(gui.radio_handles.invstd_Lorder0,'Value',1); +0904 set(gui.radio_handles.invstd_Lorder1,'Value',0); +0905 set(gui.radio_handles.invstd_Lorder2,'Value',0); +0906 +0907 case 1 +0908 set(gui.radio_handles.invstd_Lorder0,'Value',0); +0909 set(gui.radio_handles.invstd_Lorder1,'Value',1); +0910 set(gui.radio_handles.invstd_Lorder2,'Value',0); +0911 +0912 case 2 +0913 set(gui.radio_handles.invstd_Lorder0,'Value',0); +0914 set(gui.radio_handles.invstd_Lorder1,'Value',0); +0915 set(gui.radio_handles.invstd_Lorder2,'Value',1); +0916 end +0917 end +0918 +0919 end +0920 +0921 function gui = updateLorderJoint(gui,invtype,Lorder) +0922 +0923 switch invtype +0924 case {'fixed','shape','off'} +0925 set(gui.radio_handles.invjoint_Lorder0,'Enable','off'); +0926 set(gui.radio_handles.invjoint_Lorder1,'Enable','off'); +0927 set(gui.radio_handles.invjoint_Lorder2,'Enable','off'); 0928 -0929 end -0930 set(gui.edit_handles.param_calibVol,'Enable','on','String',num2str(p.calibVol)); -0931 set(gui.edit_handles.param_calibAmp,'Enable','on','String',num2str(p.calibAmp)); -0932 set(gui.edit_handles.param_sampVol,'Enable','on','String',num2str(p.sampVol)); -0933 -0934 end -0935 -0936 %------------- END OF CODE -------------- -0937 -0938 %% License: -0939 % MIT License -0940 % -0941 % Copyright (c) 2018 Thomas Hiller -0942 % -0943 % Permission is hereby granted, free of charge, to any person obtaining a copy -0944 % of this software and associated documentation files (the "Software"), to deal -0945 % in the Software without restriction, including without limitation the rights -0946 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0947 % copies of the Software, and to permit persons to whom the Software is -0948 % furnished to do so, subject to the following conditions: -0949 % -0950 % The above copyright notice and this permission notice shall be included in all -0951 % copies or substantial portions of the Software. -0952 % -0953 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0954 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0955 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0956 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0957 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0958 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0959 % SOFTWARE. +0929 case 'free' +0930 set(gui.radio_handles.invjoint_Lorder0,'Enable','on'); +0931 set(gui.radio_handles.invjoint_Lorder1,'Enable','on'); +0932 set(gui.radio_handles.invjoint_Lorder2,'Enable','on'); +0933 +0934 switch Lorder +0935 case 0 +0936 set(gui.radio_handles.invjoint_Lorder0,'Value',1); +0937 set(gui.radio_handles.invjoint_Lorder1,'Value',0); +0938 set(gui.radio_handles.invjoint_Lorder2,'Value',0); +0939 +0940 case 1 +0941 set(gui.radio_handles.invjoint_Lorder0,'Value',0); +0942 set(gui.radio_handles.invjoint_Lorder1,'Value',1); +0943 set(gui.radio_handles.invjoint_Lorder2,'Value',0); +0944 +0945 case 2 +0946 set(gui.radio_handles.invjoint_Lorder0,'Value',0); +0947 set(gui.radio_handles.invjoint_Lorder1,'Value',0); +0948 set(gui.radio_handles.invjoint_Lorder2,'Value',1); +0949 end +0950 end +0951 +0952 end +0953 +0954 function gui = updateParams(gui,invtype,p) +0955 +0956 switch invtype +0957 case {'mono','free'} +0958 set(gui.edit_handles.param_CBW,'Enable','off','String',num2str(p.CBWcutoff)); +0959 set(gui.edit_handles.param_BVI,'Enable','off','String',num2str(p.BVIcutoff)); +0960 set(gui.edit_handles.param_rho,'Enable','on','String',num2str(p.rho)); +0961 set(gui.edit_handles.param_geom,'Enable','on','String',num2str(p.a)); +0962 +0963 case {'LU','NNLS','MUMO'} +0964 set(gui.edit_handles.param_CBW,'Enable','on','String',num2str(p.CBWcutoff)); +0965 set(gui.edit_handles.param_BVI,'Enable','on','String',num2str(p.BVIcutoff)); +0966 set(gui.edit_handles.param_rho,'Enable','on','String',num2str(p.rho)); +0967 set(gui.edit_handles.param_geom,'Enable','on','String',num2str(p.a)); +0968 +0969 end +0970 set(gui.edit_handles.param_calibVol,'Enable','on','String',num2str(p.calibVol)); +0971 set(gui.edit_handles.param_calibAmp,'Enable','on','String',num2str(p.calibAmp)); +0972 set(gui.edit_handles.param_sampVol,'Enable','on','String',num2str(p.sampVol)); +0973 +0974 end +0975 +0976 %------------- END OF CODE -------------- +0977 +0978 %% License: +0979 % MIT License +0980 % +0981 % Copyright (c) 2018 Thomas Hiller +0982 % +0983 % Permission is hereby granted, free of charge, to any person obtaining a copy +0984 % of this software and associated documentation files (the "Software"), to deal +0985 % in the Software without restriction, including without limitation the rights +0986 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0987 % copies of the Software, and to permit persons to whom the Software is +0988 % furnished to do so, subject to the following conditions: +0989 % +0990 % The above copyright notice and this permission notice shall be included in all +0991 % copies or substantial portions of the Software. +0992 % +0993 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0994 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0995 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0996 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0997 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0998 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0999 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSmod/NUCLEUSmod.html b/doc/nucleus/NUCLEUSmod/NUCLEUSmod.html index aa903e2..a39b1ea 100644 --- a/doc/nucleus/NUCLEUSmod/NUCLEUSmod.html +++ b/doc/nucleus/NUCLEUSmod/NUCLEUSmod.html @@ -117,8 +117,8 @@

    SOURCE CODE ^if ~isempty(h0); close(h0); end 0042 0043 %% GUI 'header' info and defaults -0044 myui.version = '0.1.14'; -0045 myui.date = '27.09.2023'; +0044 myui.version = '0.2.0'; +0045 myui.date = '01.02.2024'; 0046 myui.author = {'Stephan Costabel','Thomas Hiller'}; 0047 myui.email = 'thomas.hiller[at]bgr.de'; 0048 myui.fontsize = 10; diff --git a/doc/nucleus/callbacks/contextmenus/onContextPlotsRTD.html b/doc/nucleus/callbacks/contextmenus/onContextPlotsRTD.html index 453e9a7..fc0fa3f 100644 --- a/doc/nucleus/callbacks/contextmenus/onContextPlotsRTD.html +++ b/doc/nucleus/callbacks/contextmenus/onContextPlotsRTD.html @@ -60,7 +60,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • updatePlotsDistribution plots the RTD and PSD curves into NUCLEUSinv
  • updatePlotsSignal plots the raw and processed NMR signals in NUCLEUSinv
  • This function is called by: @@ -129,36 +129,52 @@

    SOURCE CODE ^'gui',gui); 0059 % update the plot axes 0060 updatePlotsDistribution; -0061 otherwise -0062 disp('onContextPlotsRTD: something is utterly wrong.'); -0063 end -0064 -0065 end -0066 -0067 %------------- END OF CODE -------------- -0068 -0069 %% License: -0070 % MIT License -0071 % -0072 % Copyright (c) 2018 Thomas Hiller -0073 % -0074 % Permission is hereby granted, free of charge, to any person obtaining a copy -0075 % of this software and associated documentation files (the "Software"), to deal -0076 % in the Software without restriction, including without limitation the rights -0077 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0078 % copies of the Software, and to permit persons to whom the Software is -0079 % furnished to do so, subject to the following conditions: -0080 % -0081 % The above copyright notice and this permission notice shall be included in all -0082 % copies or substantial portions of the Software. -0083 % -0084 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0085 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0086 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0087 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0088 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0089 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0090 % SOFTWARE. +0061 case 'uncert' +0062 data.info.RTDuncert = label; +0063 switch label +0064 case 'lines' +0065 set(src,'Checked','on'); +0066 set(gui.cm_handles.axes_rtd_uncert_patch,'Checked','off'); +0067 case 'patch' +0068 set(src,'Checked','on'); +0069 set(gui.cm_handles.axes_rtd_uncert_lines,'Checked','off'); +0070 end +0071 % update the GUI data +0072 setappdata(fig,'data',data); +0073 setappdata(fig,'gui',gui); +0074 % update the plot axes +0075 updatePlotsSignal; +0076 updatePlotsDistribution; +0077 otherwise +0078 disp('onContextPlotsRTD: something is utterly wrong.'); +0079 end +0080 +0081 end +0082 +0083 %------------- END OF CODE -------------- +0084 +0085 %% License: +0086 % MIT License +0087 % +0088 % Copyright (c) 2018 Thomas Hiller +0089 % +0090 % Permission is hereby granted, free of charge, to any person obtaining a copy +0091 % of this software and associated documentation files (the "Software"), to deal +0092 % in the Software without restriction, including without limitation the rights +0093 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0094 % copies of the Software, and to permit persons to whom the Software is +0095 % furnished to do so, subject to the following conditions: +0096 % +0097 % The above copyright notice and this permission notice shall be included in all +0098 % copies or substantial portions of the Software. +0099 % +0100 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0101 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0102 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0103 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0104 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0105 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0106 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/listboxes/onListboxData.html b/doc/nucleus/callbacks/listboxes/onListboxData.html index 42d9183..5963462 100644 --- a/doc/nucleus/callbacks/listboxes/onListboxData.html +++ b/doc/nucleus/callbacks/listboxes/onListboxData.html @@ -177,146 +177,149 @@

    SOURCE CODE ^removeInversionFields(data); 0100 0101 % set format and T1/T2 dependent GUI elements -0102 switch data.import.NMR.data{id}.flag -0103 case 'T1' -0104 data.process.gatetype = 'raw'; -0105 data.process.start = 1; -0106 case 'T2' -0107 switch data.import.fileformat -0108 case {'dart','excel','field','helios','mouse','NMRMOD'} -0109 data.process.gatetype = 'raw'; -0110 data.process.start = 1; -0111 otherwise -0112 % standard T2 -0113 data.process.gatetype = 'log'; -0114 data.process.start = 1; -0115 end -0116 otherwise -0117 disp('onListboxData: Something is utterly wrong.') -0118 end -0119 -0120 % take all echoes -0121 data.process.end = length(data.import.NMR.data{id}.signal); -0122 -0123 % --- -0124 % special treatments -0125 % there is no volume or porosity -0126 data.param.sampVol = 1; -0127 if isfield(data.import,'BGR') -0128 data.invstd.porosity = data.import.BGR.porosity; -0129 else -0130 data.invstd.porosity = 1; -0131 end -0132 if isfield(data.import,'LIAG') -0133 data.param.sampVol = data.import.LIAG.sampleVol(id); -0134 if ~isempty(strfind(data.import.NMR.filesShort{id},' - calibration')) -0135 data.param.calibVol = data.import.LIAG.sampleVol(id); -0136 % update the GUI data -0137 setappdata(fig,'data',data); -0138 % set mono fit as default -0139 set(gui.popup_handles.invstd_InvType,'Value',1); -0140 onPopupInvstdType(gui.popup_handles.invstd_InvType); -0141 data = getappdata(fig,'data'); -0142 end -0143 if isempty(strfind(data.import.NMR.filesShort{id},' - calibration')) -0144 data.invstd.Tbulk = data.import.LIAG.Tbulk; -0145 % update the GUI data -0146 setappdata(fig,'data',data); -0147 % set mono fit as default -0148 set(gui.popup_handles.invstd_InvType,'Value',3); -0149 onPopupInvstdType(gui.popup_handles.invstd_InvType); -0150 data = getappdata(fig,'data'); -0151 end -0152 else -0153 data.param.sampVol = 1; -0154 end -0155 if isfield(data.import,'NMRMOD') -0156 data.param.rho = data.import.NMR.para{id}.rho*1e6; -0157 data.invstd.Tbulk = data.import.NMR.para{id}.Tbulk; -0158 data.invstd.Tdiff = data.import.NMR.para{id}.Tdiff; -0159 data.invstd.porosity = data.import.NMR.para{id}.porosity; -0160 end -0161 % --- -0162 -0163 % update the figure data -0164 setappdata(fig,'data',data); -0165 -0166 % process the NMR data -0167 processNMRDataControl(fig,id); -0168 % update interface -0169 NUCLEUSinv_updateInterface; -0170 -0171 % update the data plot axes -0172 updatePlotsSignal; -0173 % update the info fields -0174 updateInfo(gui.plots.SignalPanel); -0175 gui = getappdata(fig,'gui'); -0176 -0177 % clear inversion axes -0178 clearSingleAxis(gui.axes_handles.rtd); -0179 clearSingleAxis(gui.axes_handles.psd); -0180 end -0181 -0182 % set focus on data -0183 % set(gui.plots.SignalPanel,'Selection',1); -0184 % set(gui.plots.DistPanel,'Selection',1); -0185 -0186 % reset all RUN buttons -0187 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... -0188 'BackgroundColor','g','Enable','on','Callback',@onPushRun); -0189 set(gui.push_handles.invjoint_run,'String','<HTML><u>R</u>UN',... -0190 'BackgroundColor','g','Enable','on','Callback',@onPushRun); -0191 -0192 % if the Fit Statistics window is open update it -0193 if ~isempty(findobj('Tag','FITSTATS')) -0194 showFitStatistics; -0195 end -0196 % if the PhaseView window is open update it -0197 if ~isempty(findobj('Tag','PHASEVIEW')) -0198 PhaseView(gui.menu.extra_phaseview); -0199 end -0200 % if the FixedTimeView window is open update it -0201 if ~isempty(findobj('Tag','FIXEDTIMEVIEW')) -0202 FixedTimeView(gui.menu.extra_fixedtime); -0203 end -0204 else -0205 helpdlg({'onListboxData:','Only choose one data set at a time.'},... -0206 'too many data'); -0207 end -0208 else -0209 helpdlg('Nothing to do because there is no data loaded!',... -0210 'onListboxData: Load NMR data first.'); -0211 end -0212 -0213 % update the figure data -0214 setappdata(fig,'gui',gui); +0102 data.process.isgated = false; +0103 switch data.import.NMR.data{id}.flag +0104 case 'T1' +0105 data.process.gatetype = 'raw'; +0106 data.process.start = 1; +0107 case 'T2' +0108 switch data.import.fileformat +0109 case {'dart','excel','field','helios','mouse','NMRMOD'} +0110 data.process.gatetype = 'raw'; +0111 data.process.start = 1; +0112 otherwise +0113 % standard T2 +0114 data.process.gatetype = 'log'; +0115 data.process.start = 1; +0116 end +0117 otherwise +0118 disp('onListboxData: Something is utterly wrong.') +0119 end +0120 +0121 % take all echoes +0122 data.process.end = length(data.import.NMR.data{id}.signal); +0123 +0124 % --- +0125 % special treatments +0126 % there is no volume or porosity +0127 data.param.sampVol = 1; +0128 if isfield(data.import,'BGR') +0129 data.invstd.porosity = data.import.BGR.porosity; +0130 else +0131 data.invstd.porosity = 1; +0132 end +0133 if isfield(data.import,'LIAG') +0134 data.param.sampVol = data.import.LIAG.sampleVol(id); +0135 if ~isempty(strfind(data.import.NMR.filesShort{id},' - calibration')) +0136 data.param.calibVol = data.import.LIAG.sampleVol(id); +0137 % update the GUI data +0138 setappdata(fig,'data',data); +0139 % set mono fit as default +0140 set(gui.popup_handles.invstd_InvType,'Value',1); +0141 onPopupInvstdType(gui.popup_handles.invstd_InvType); +0142 data = getappdata(fig,'data'); +0143 end +0144 if isempty(strfind(data.import.NMR.filesShort{id},' - calibration')) +0145 data.invstd.Tbulk = data.import.LIAG.Tbulk; +0146 % update the GUI data +0147 setappdata(fig,'data',data); +0148 % set mono fit as default +0149 set(gui.popup_handles.invstd_InvType,'Value',3); +0150 onPopupInvstdType(gui.popup_handles.invstd_InvType); +0151 data = getappdata(fig,'data'); +0152 end +0153 else +0154 data.param.sampVol = 1; +0155 end +0156 if isfield(data.import,'NMRMOD') +0157 data.param.rho = data.import.NMR.para{id}.rho*1e6; +0158 data.invstd.Tbulk = data.import.NMR.para{id}.Tbulk; +0159 data.invstd.Tdiff = data.import.NMR.para{id}.Tdiff; +0160 data.invstd.porosity = data.import.NMR.para{id}.porosity; +0161 end +0162 % --- +0163 +0164 % update the figure data +0165 setappdata(fig,'data',data); +0166 +0167 % process the NMR data +0168 processNMRDataControl(fig,id); +0169 % update interface +0170 NUCLEUSinv_updateInterface; +0171 +0172 % update the data plot axes +0173 updatePlotsSignal; +0174 % update the info fields +0175 updateInfo(gui.plots.SignalPanel); +0176 gui = getappdata(fig,'gui'); +0177 +0178 % clear inversion axes +0179 clearSingleAxis(gui.axes_handles.rtd); +0180 clearSingleAxis(gui.axes_handles.psd); +0181 % switch-off uncert context menu +0182 set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); +0183 end +0184 +0185 % set focus on data +0186 % set(gui.plots.SignalPanel,'Selection',1); +0187 % set(gui.plots.DistPanel,'Selection',1); +0188 +0189 % reset all RUN buttons +0190 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... +0191 'BackgroundColor','g','Enable','on','Callback',@onPushRun); +0192 set(gui.push_handles.invjoint_run,'String','<HTML><u>R</u>UN',... +0193 'BackgroundColor','g','Enable','on','Callback',@onPushRun); +0194 +0195 % if the Fit Statistics window is open update it +0196 if ~isempty(findobj('Tag','FITSTATS')) +0197 showFitStatistics; +0198 end +0199 % if the PhaseView window is open update it +0200 if ~isempty(findobj('Tag','PHASEVIEW')) +0201 PhaseView(gui.menu.extra_phaseview); +0202 end +0203 % if the FixedTimeView window is open update it +0204 if ~isempty(findobj('Tag','FIXEDTIMEVIEW')) +0205 FixedTimeView(gui.menu.extra_fixedtime); +0206 end +0207 else +0208 helpdlg({'onListboxData:','Only choose one data set at a time.'},... +0209 'too many data'); +0210 end +0211 else +0212 helpdlg('Nothing to do because there is no data loaded!',... +0213 'onListboxData: Load NMR data first.'); +0214 end 0215 -0216 end -0217 -0218 %------------- END OF CODE -------------- -0219 -0220 %% License: -0221 % MIT License -0222 % -0223 % Copyright (c) 2018 Thomas Hiller -0224 % -0225 % Permission is hereby granted, free of charge, to any person obtaining a copy -0226 % of this software and associated documentation files (the "Software"), to deal -0227 % in the Software without restriction, including without limitation the rights -0228 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0229 % copies of the Software, and to permit persons to whom the Software is -0230 % furnished to do so, subject to the following conditions: -0231 % -0232 % The above copyright notice and this permission notice shall be included in all -0233 % copies or substantial portions of the Software. +0216 % update the figure data +0217 setappdata(fig,'gui',gui); +0218 +0219 end +0220 +0221 %------------- END OF CODE -------------- +0222 +0223 %% License: +0224 % MIT License +0225 % +0226 % Copyright (c) 2018 Thomas Hiller +0227 % +0228 % Permission is hereby granted, free of charge, to any person obtaining a copy +0229 % of this software and associated documentation files (the "Software"), to deal +0230 % in the Software without restriction, including without limitation the rights +0231 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0232 % copies of the Software, and to permit persons to whom the Software is +0233 % furnished to do so, subject to the following conditions: 0234 % -0235 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0236 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0237 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0238 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0239 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0240 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0241 % SOFTWARE. +0235 % The above copyright notice and this permission notice shall be included in all +0236 % copies or substantial portions of the Software. +0237 % +0238 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0239 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0240 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0241 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0242 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0243 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0244 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/menus/onMenuExpert.html b/doc/nucleus/callbacks/menus/onMenuExpert.html index 3b2a2f2..b12af7f 100644 --- a/doc/nucleus/callbacks/menus/onMenuExpert.html +++ b/doc/nucleus/callbacks/menus/onMenuExpert.html @@ -143,97 +143,105 @@

    SOURCE CODE ^end 0068 set(gui.menu.extra_fixedtime,'Enable','off'); -0069 -0070 % deactivate solver menu and set to default -0071 onMenuSolver(gui.menu.extra_solver_lsqnonneg); -0072 % get changed GUI data -0073 data = getappdata(fig,'data'); -0074 set(gui.menu.extra_solver,'Enable','off'); -0075 -0076 % update GUI data -0077 setappdata(fig,'data',data); -0078 setappdata(fig,'gui',gui); -0079 -0080 % deactivate joint inversion panels -0081 set(gui.menu.extra_joint,'Checked','on'); -0082 onMenuJointInversion(gui.menu.extra_joint); -0083 % get changed GUI data -0084 data = getappdata(fig,'data'); -0085 INVdata = getappdata(fig,'INVdata'); -0086 % default std inversion settings -0087 data.invstd.invtype = 'NNLS'; -0088 data.invstd.regtype = 'manual'; -0089 data.invstd.lambda = 1; -0090 % deactivate joint inversion menu -0091 set(gui.menu.extra_joint,'Enable','off'); -0092 -0093 set(gui.menu.extra_graphics_amp,'Enable','off'); -0094 set(gui.menu.extra_graphics_amp2,'Enable','off'); -0095 set(gui.menu.extra_graphics_rtd,'Enable','off'); -0096 -0097 case 'off' % it it's off, switch it on -0098 data.info.ExpertMode = 'on'; -0099 % menu entry -0100 set(gui.menu.extra_expert,'Checked','on'); -0101 -0102 % activate FixedTime View GUI -0103 set(gui.menu.extra_fixedtime,'Enable','on'); -0104 -0105 % activate solver menu if optimization toolbox is available -0106 switch data.info.has_optim -0107 case 'on' -0108 set(gui.menu.extra_solver,'Enable','on'); -0109 case 'off' -0110 set(gui.menu.extra_solver,'Enable','off'); -0111 end -0112 -0113 % activate joint inversion menu -0114 set(gui.menu.extra_joint,'Enable','on'); -0115 -0116 set(gui.menu.extra_graphics_amp,'Enable','on'); -0117 set(gui.menu.extra_graphics_amp2,'Enable','on'); -0118 set(gui.menu.extra_graphics_rtd,'Enable','on'); -0119 end -0120 -0121 % update GUI data -0122 setappdata(fig,'data',data); -0123 setappdata(fig,'gui',gui); -0124 % update ini-file -0125 gui.myui.inidata.expertmode = data.info.ExpertMode; -0126 gui = makeINIfile(gui,'update'); -0127 % update interface -0128 NUCLEUSinv_updateInterface; -0129 % update status information -0130 updateStatusInformation(fig); -0131 updateToolTips; -0132 onFigureSizeChange(fig); -0133 -0134 end -0135 -0136 %------------- END OF CODE -------------- -0137 -0138 %% License: -0139 % MIT License -0140 % -0141 % Copyright (c) 2018 Thomas Hiller -0142 % -0143 % Permission is hereby granted, free of charge, to any person obtaining a copy -0144 % of this software and associated documentation files (the "Software"), to deal -0145 % in the Software without restriction, including without limitation the rights -0146 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0147 % copies of the Software, and to permit persons to whom the Software is -0148 % furnished to do so, subject to the following conditions: -0149 % -0150 % The above copyright notice and this permission notice shall be included in all -0151 % copies or substantial portions of the Software. -0152 % -0153 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0154 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0155 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0156 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0157 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0158 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0159 % SOFTWARE. +0069 % check if the figure is already open +0070 fig_uncert = findobj('Tag','UNCERTVIEW'); +0071 if ~isempty(fig_uncert) +0072 delete(fig_uncert); +0073 end +0074 set(gui.menu.extra_uncert,'Enable','off'); +0075 +0076 % deactivate solver menu and set to default +0077 onMenuSolver(gui.menu.extra_solver_lsqnonneg); +0078 % get changed GUI data +0079 data = getappdata(fig,'data'); +0080 set(gui.menu.extra_solver,'Enable','off'); +0081 +0082 % update GUI data +0083 setappdata(fig,'data',data); +0084 setappdata(fig,'gui',gui); +0085 +0086 % deactivate joint inversion panels +0087 set(gui.menu.extra_joint,'Checked','on'); +0088 onMenuJointInversion(gui.menu.extra_joint); +0089 % get changed GUI data +0090 data = getappdata(fig,'data'); +0091 INVdata = getappdata(fig,'INVdata'); +0092 % default std inversion settings +0093 data.invstd.invtype = 'NNLS'; +0094 data.invstd.regtype = 'manual'; +0095 data.invstd.lambda = 1; +0096 % deactivate joint inversion menu +0097 set(gui.menu.extra_joint,'Enable','off'); +0098 +0099 set(gui.menu.extra_graphics_amp,'Enable','off'); +0100 set(gui.menu.extra_graphics_amp2,'Enable','off'); +0101 set(gui.menu.extra_graphics_rtd,'Enable','off'); +0102 +0103 case 'off' % it it's off, switch it on +0104 data.info.ExpertMode = 'on'; +0105 % menu entry +0106 set(gui.menu.extra_expert,'Checked','on'); +0107 +0108 % activate FixedTime View GUI +0109 set(gui.menu.extra_fixedtime,'Enable','on'); +0110 % activate Uncertainty View GUI +0111 set(gui.menu.extra_uncert,'Enable','on'); +0112 +0113 % activate solver menu if optimization toolbox is available +0114 switch data.info.has_optim +0115 case 'on' +0116 set(gui.menu.extra_solver,'Enable','on'); +0117 case 'off' +0118 set(gui.menu.extra_solver,'Enable','off'); +0119 end +0120 +0121 % activate joint inversion menu +0122 set(gui.menu.extra_joint,'Enable','on'); +0123 +0124 set(gui.menu.extra_graphics_amp,'Enable','on'); +0125 set(gui.menu.extra_graphics_amp2,'Enable','on'); +0126 set(gui.menu.extra_graphics_rtd,'Enable','on'); +0127 end +0128 +0129 % update GUI data +0130 setappdata(fig,'data',data); +0131 setappdata(fig,'gui',gui); +0132 % update ini-file +0133 gui.myui.inidata.expertmode = data.info.ExpertMode; +0134 gui = makeINIfile(gui,'update'); +0135 % update interface +0136 NUCLEUSinv_updateInterface; +0137 % update status information +0138 updateStatusInformation(fig); +0139 updateToolTips; +0140 onFigureSizeChange(fig); +0141 +0142 end +0143 +0144 %------------- END OF CODE -------------- +0145 +0146 %% License: +0147 % MIT License +0148 % +0149 % Copyright (c) 2018 Thomas Hiller +0150 % +0151 % Permission is hereby granted, free of charge, to any person obtaining a copy +0152 % of this software and associated documentation files (the "Software"), to deal +0153 % in the Software without restriction, including without limitation the rights +0154 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0155 % copies of the Software, and to permit persons to whom the Software is +0156 % furnished to do so, subject to the following conditions: +0157 % +0158 % The above copyright notice and this permission notice shall be included in all +0159 % copies or substantial portions of the Software. +0160 % +0161 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0162 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0163 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0164 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0165 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0166 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0167 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/menus/onMenuSolver.html b/doc/nucleus/callbacks/menus/onMenuSolver.html index c497fb5..48b417e 100644 --- a/doc/nucleus/callbacks/menus/onMenuSolver.html +++ b/doc/nucleus/callbacks/menus/onMenuSolver.html @@ -63,7 +63,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=NUCLEUSinv_updateInterface updates all GUI elements
  • updateStatusInformation updates all fields inside the bottom status bar
  • updateToolTips updates tool tip entries dependent on the chosen settings
  • This function is called by: +
  • NUCLEUSinv_createMenus creates all GUI menus
  • onMenuExpert handles the call from the menu that activates / deactivates
  • importINV2INV imports a previously saved NUCLEUSinv session
  • diff --git a/doc/nucleus/callbacks/push/onPushRun.html b/doc/nucleus/callbacks/push/onPushRun.html index 9efaa6b..e1078df 100644 --- a/doc/nucleus/callbacks/push/onPushRun.html +++ b/doc/nucleus/callbacks/push/onPushRun.html @@ -62,7 +62,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • calculateNMR calculates the NMR signals for the full and partially saturated
  • caluclatePressureSaturation calculates the geometry dependent pressure
  • runInversionJoint controls the joint inversion process to infer a pore size
  • runInversionStd controls the standard inversion process to invert a
  • runUncertaintyCalculation caluclates inverison statistics in some kind of
  • This function is called by: @@ -120,44 +120,46 @@

    SOURCE CODE ^runInversionStd; 0048 case 'joint' 0049 runInversionJoint; -0050 end -0051 case 'MOD' -0052 tag = get(src,'Tag'); -0053 % switch depending on calculation -0054 switch tag -0055 case 'pressure' -0056 caluclatePressureSaturation; -0057 case 'nmr' -0058 calculateNMR; -0059 end -0060 end -0061 +0050 case 'uncert' +0051 runUncertaintyCalculation; +0052 end +0053 case 'MOD' +0054 tag = get(src,'Tag'); +0055 % switch depending on calculation +0056 switch tag +0057 case 'pressure' +0058 caluclatePressureSaturation; +0059 case 'nmr' +0060 calculateNMR; +0061 end 0062 end 0063 -0064 %------------- END OF CODE -------------- +0064 end 0065 -0066 %% License: -0067 % MIT License -0068 % -0069 % Copyright (c) 2018 Thomas Hiller +0066 %------------- END OF CODE -------------- +0067 +0068 %% License: +0069 % MIT License 0070 % -0071 % Permission is hereby granted, free of charge, to any person obtaining a copy -0072 % of this software and associated documentation files (the "Software"), to deal -0073 % in the Software without restriction, including without limitation the rights -0074 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0075 % copies of the Software, and to permit persons to whom the Software is -0076 % furnished to do so, subject to the following conditions: -0077 % -0078 % The above copyright notice and this permission notice shall be included in all -0079 % copies or substantial portions of the Software. -0080 % -0081 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0082 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0083 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0084 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0085 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0086 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0087 % SOFTWARE. +0071 % Copyright (c) 2018 Thomas Hiller +0072 % +0073 % Permission is hereby granted, free of charge, to any person obtaining a copy +0074 % of this software and associated documentation files (the "Software"), to deal +0075 % in the Software without restriction, including without limitation the rights +0076 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0077 % copies of the Software, and to permit persons to whom the Software is +0078 % furnished to do so, subject to the following conditions: +0079 % +0080 % The above copyright notice and this permission notice shall be included in all +0081 % copies or substantial portions of the Software. +0082 % +0083 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0084 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0085 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0086 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0087 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0088 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0089 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/radio/onRadioGates.html b/doc/nucleus/callbacks/radio/onRadioGates.html index 6b576d9..23a4082 100644 --- a/doc/nucleus/callbacks/radio/onRadioGates.html +++ b/doc/nucleus/callbacks/radio/onRadioGates.html @@ -122,80 +122,83 @@

    SOURCE CODE ^% change settings depending on the chosen radio button 0051 % for gated signals the lambda value is generally smaller 0052 % (just a rule of thumb) -0053 switch str -0054 case 'log' -0055 data.process.gatetype = 'log'; -0056 lambdaFAK = 100; -0057 -0058 case 'lin' -0059 data.process.gatetype = 'lin'; -0060 lambdaFAK = 100; -0061 -0062 case 'none' -0063 data.process.gatetype = 'raw'; -0064 lambdaFAK = 1; -0065 end -0066 -0067 % set the lambda range when L-curve is the regularization method -0068 if strcmp(data.invstd.regtype,'lcurve') -0069 data.invstd.lambdaR = data.invstd.lambdaRinit./lambdaFAK; -0070 end -0071 if strcmp(data.invjoint.regtype,'lcurve') -0072 data.invjoint.lambdaR = data.invjoint.lambdaRinit./lambdaFAK; +0053 data.process.isgated = false; +0054 switch str +0055 case 'log' +0056 data.process.isgated = true; +0057 data.process.gatetype = 'log'; +0058 lambdaFAK = 100; +0059 +0060 case 'lin' +0061 data.process.isgated = true; +0062 data.process.gatetype = 'lin'; +0063 lambdaFAK = 100; +0064 +0065 case 'none' +0066 data.process.gatetype = 'raw'; +0067 lambdaFAK = 1; +0068 end +0069 +0070 % set the lambda range when L-curve is the regularization method +0071 if strcmp(data.invstd.regtype,'lcurve') +0072 data.invstd.lambdaR = data.invstd.lambdaRinit./lambdaFAK; 0073 end -0074 -0075 % update GUI data -0076 setappdata(fig,'data',data); -0077 % update interface -0078 NUCLEUSinv_updateInterface; -0079 % process NMR signal -0080 processNMRDataControl(fig,id); -0081 % update plots -0082 updatePlotsSignal; -0083 updateInfo(src); -0084 % clear axes -0085 clearSingleAxis(gui.axes_handles.rtd); -0086 clearSingleAxis(gui.axes_handles.psd); -0087 % set focus on data -0088 set(gui.plots.SignalPanel,'Selection',1); -0089 -0090 else -0091 % reset to defaults -0092 data.process.gatetype = 'log'; -0093 % update GUI data -0094 setappdata(fig,'data',data); -0095 % update interface -0096 NUCLEUSinv_updateInterface; -0097 helpdlg('Nothing to do because no data set is selected!',... -0098 'onRadioGates: Select NMR data first.'); -0099 end -0100 -0101 end -0102 -0103 %------------- END OF CODE -------------- -0104 -0105 %% License: -0106 % MIT License -0107 % -0108 % Copyright (c) 2018 Thomas Hiller -0109 % -0110 % Permission is hereby granted, free of charge, to any person obtaining a copy -0111 % of this software and associated documentation files (the "Software"), to deal -0112 % in the Software without restriction, including without limitation the rights -0113 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0114 % copies of the Software, and to permit persons to whom the Software is -0115 % furnished to do so, subject to the following conditions: -0116 % -0117 % The above copyright notice and this permission notice shall be included in all -0118 % copies or substantial portions of the Software. +0074 if strcmp(data.invjoint.regtype,'lcurve') +0075 data.invjoint.lambdaR = data.invjoint.lambdaRinit./lambdaFAK; +0076 end +0077 +0078 % update GUI data +0079 setappdata(fig,'data',data); +0080 % update interface +0081 NUCLEUSinv_updateInterface; +0082 % process NMR signal +0083 processNMRDataControl(fig,id); +0084 % update plots +0085 updatePlotsSignal; +0086 updateInfo(src); +0087 % clear axes +0088 clearSingleAxis(gui.axes_handles.rtd); +0089 clearSingleAxis(gui.axes_handles.psd); +0090 % set focus on data +0091 set(gui.plots.SignalPanel,'Selection',1); +0092 +0093 else +0094 % reset to defaults +0095 data.process.gatetype = 'log'; +0096 % update GUI data +0097 setappdata(fig,'data',data); +0098 % update interface +0099 NUCLEUSinv_updateInterface; +0100 helpdlg('Nothing to do because no data set is selected!',... +0101 'onRadioGates: Select NMR data first.'); +0102 end +0103 +0104 end +0105 +0106 %------------- END OF CODE -------------- +0107 +0108 %% License: +0109 % MIT License +0110 % +0111 % Copyright (c) 2018 Thomas Hiller +0112 % +0113 % Permission is hereby granted, free of charge, to any person obtaining a copy +0114 % of this software and associated documentation files (the "Software"), to deal +0115 % in the Software without restriction, including without limitation the rights +0116 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0117 % copies of the Software, and to permit persons to whom the Software is +0118 % furnished to do so, subject to the following conditions: 0119 % -0120 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0121 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0122 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0123 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0124 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0125 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0126 % SOFTWARE. +0120 % The above copyright notice and this permission notice shall be included in all +0121 % copies or substantial portions of the Software. +0122 % +0123 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0124 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0125 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0126 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0127 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0128 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0129 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/UncertView.html b/doc/nucleus/functions/interface/UncertView.html new file mode 100644 index 0000000..c86bf53 --- /dev/null +++ b/doc/nucleus/functions/interface/UncertView.html @@ -0,0 +1,1585 @@ + + + + Description of UncertView + + + + + + + + + + + +

    UncertView +

    + +

    PURPOSE ^

    +
    is an extra subGUI to show results of the uncertainty
    + +

    SYNOPSIS ^

    +
    function UncertView(src,~)
    + +

    DESCRIPTION ^

    +
    UncertView is an extra subGUI to show results of the uncertainty
    +calculation
    +
    + Syntax:
    +       UncertView
    +
    + Inputs:
    +       src - handle of the calling object
    +
    + Outputs:
    +       none
    +
    + Example:
    +       UncertView(src,~)
    +
    + Other m-files required:
    +       beautifyAxes
    +       clearAllAxes
    +       estimateUncertainty
    +       createKernelMatrix
    +       updatePlotsSignal
    +       updatePlotsDistribution
    +       updateInfo
    +
    + Subfunctions:
    +       uv_closeme
    +       uv_onEditValue
    +       uv_updateMASK
    +       uv_onPushRun
    +       uv_onPushUpdate
    +       uv_onPushReset
    +       uv_updateInformation
    +       uv_updatePlots
    +
    + MAT-files required:
    +       none
    +
    + See also: NUCLEUSinv
    + Author: see AUTHORS.md
    + email: see AUTHORS.md
    + License: MIT License (at end)
    + + +

    CROSS-REFERENCE INFORMATION ^

    +This function calls: + +This function is called by: + + + +

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function UncertView(src,~)
    +0002 %UncertView is an extra subGUI to show results of the uncertainty
    +0003 %calculation
    +0004 %
    +0005 % Syntax:
    +0006 %       UncertView
    +0007 %
    +0008 % Inputs:
    +0009 %       src - handle of the calling object
    +0010 %
    +0011 % Outputs:
    +0012 %       none
    +0013 %
    +0014 % Example:
    +0015 %       UncertView(src,~)
    +0016 %
    +0017 % Other m-files required:
    +0018 %       beautifyAxes
    +0019 %       clearAllAxes
    +0020 %       estimateUncertainty
    +0021 %       createKernelMatrix
    +0022 %       updatePlotsSignal
    +0023 %       updatePlotsDistribution
    +0024 %       updateInfo
    +0025 %
    +0026 % Subfunctions:
    +0027 %       uv_closeme
    +0028 %       uv_onEditValue
    +0029 %       uv_updateMASK
    +0030 %       uv_onPushRun
    +0031 %       uv_onPushUpdate
    +0032 %       uv_onPushReset
    +0033 %       uv_updateInformation
    +0034 %       uv_updatePlots
    +0035 %
    +0036 % MAT-files required:
    +0037 %       none
    +0038 %
    +0039 % See also: NUCLEUSinv
    +0040 % Author: see AUTHORS.md
    +0041 % email: see AUTHORS.md
    +0042 % License: MIT License (at end)
    +0043 
    +0044 %------------- BEGIN CODE --------------
    +0045 
    +0046 %% get GUI handle and data
    +0047 figh_nucleus = ancestor(src,'figure','toplevel');
    +0048 nucleus.data = getappdata(figh_nucleus,'data');
    +0049 nucleus.gui = getappdata(figh_nucleus,'gui');
    +0050 myui = nucleus.gui.myui;
    +0051 colors = myui.colors;
    +0052 
    +0053 %% proceed only if there is already uncertainty data
    +0054 if isfield(nucleus.data.results.invstd,'uncert')
    +0055     nucleus_data = nucleus.data;
    +0056 
    +0057     % check if the figure is already open
    +0058     fig_uncert = findobj('Tag','UNCERTVIEW');
    +0059     % if not, create it
    +0060     if isempty(fig_uncert)
    +0061         % draw the figure on top of NUCLEUSinv
    +0062         fig_uncert = figure('Name','NUCLEUSinv - RTD Uncertainty',...
    +0063             'NumberTitle','off','Resize','on','ToolBar','none',...
    +0064             'CloseRequestFcn',@uv_closeme,...
    +0065             'MenuBar','figure','Tag','UNCERTVIEW');
    +0066         pos0 = get(figh_nucleus,'Position');
    +0067         cent(1) = (pos0(1)+pos0(3)/2);
    +0068         cent(2) = (pos0(2)+pos0(4)/2);
    +0069         posf = [cent(1)-pos0(3)/3 pos0(2)+22 pos0(3)/1.5 pos0(4)-22];
    +0070         %         posf = [cent(1)-pos0(3)/6 pos0(2)+pos0(4)-140 350 145];
    +0071         set(fig_uncert,'Position',posf);
    +0072 
    +0073         % create the main layout
    +0074         gui.main = uix.HBox('Parent',fig_uncert,'BackGroundColor',colors.panelBG,...
    +0075             'Spacing',5,'Padding',5,'Visible','off');
    +0076         gui.left = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,...
    +0077             'Spacing',5,'Padding',0); % controls
    +0078         gui.right = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,...
    +0079             'Spacing',5,'Padding',0); % plots
    +0080 
    +0081         set(gui.main,'Widths',[300 -1 ]);
    +0082 
    +0083         % waitbar indicating the loading of the GUI
    +0084         steps = 5;
    +0085         hwb = waitbar(0,'loading ...','Name','UncertView initialization','Visible','off');
    +0086         set(hwb,'Units','Pixel')
    +0087         posw = get(hwb,'Position');
    +0088         set(hwb,'Position',[posf(1)+posf(3)/2-posw(3)/2 posf(2)+posf(4)/2-posw(4)/2 posw(3:4)]);
    +0089         set(hwb,'Visible','on');
    +0090 
    +0091         % --- control panel ---
    +0092         waitbar(1/steps,hwb,'loading GUI elements - control');
    +0093         gui.panels.control.main = uix.BoxPanel('Parent',gui.left,...
    +0094             'Title','Recalculate RTD Uncertainty','MinimizeFcn',@minimizePanel,...
    +0095             'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle);
    +0096         gui.panels.control.VBox = uix.VBox('Parent',gui.panels.control.main,...
    +0097             'Spacing',3,'Padding',3);
    +0098         % uncertainty method
    +0099         gui.panels.control.HBox1 = uix.HBox('Parent',gui.panels.control.VBox,...
    +0100             'Spacing',3);
    +0101         gui.text_handles.uncertMethod = uicontrol('Parent',gui.panels.control.HBox1,...
    +0102             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0103             'String','Method');
    +0104         tstr = ['<HTML>Choose the uncertainty calculation method.<br><br>',...
    +0105             '<u>Available options:</u><br>',...
    +0106             '<font color="red">Multi exp. (LSQ) | Multi exp. (LU decomp.):<br>',...
    +0107             '<font color="black">',...
    +0108             '<b>RMS - unbounded</b> Keep all uncert models.<br>',...
    +0109             '<b>RMS - bounded</b> Only keep models within Lm and chi2 bounds.<br>',...
    +0110             '<font color="red">Multi modal:<br>',...
    +0111             '<font color="black">',...
    +0112             '<b>RMS - unbounded</b> Keep all uncert models.<br>',...
    +0113             '<b>RMS - bounded</b> Only keep models within Lm and chi2 bounds.<br>',...
    +0114             '<b>Threshold</b> Vary fit parameter by threshold.<br>',...
    +0115             '<b>Conf. Interval</b> Vary fit parameter randomly within confidence interval.<br><br>',...
    +0116             '<u>Default value:</u><br>',...
    +0117             '<b>RMS - bounded</b><br>'];
    +0118         gui.popup_handles.uncertMethod = uicontrol('Parent',gui.panels.control.HBox1,...
    +0119             'Style','popup','String',{'RMS - unbounded','RMS - bounded'},...
    +0120             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0121             'FontSize',myui.fontsize,'Tag','control','Callback',@uv_onPopupMethod);
    +0122         set(gui.panels.control.HBox1,'Widths',[150 -1]);
    +0123         % number of uncertainty models
    +0124         gui.panels.control.HBox2 = uix.HBox('Parent',gui.panels.control.VBox,...
    +0125             'Spacing',3);        
    +0126         gui.text_handles.uncertN = uicontrol('Parent',gui.panels.control.HBox2,...
    +0127             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0128             'String','#models');
    +0129         uix.Empty('Parent',gui.panels.control.HBox2);
    +0130         tstr = 'Number of uncertainty models to calculate.';
    +0131         gui.edit_handles.uncertN = uicontrol('Parent',gui.panels.control.HBox2,...
    +0132             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','uncertN',...
    +0133             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0134             'Callback',@uv_onEditValue);
    +0135         set(gui.panels.control.HBox2,'Widths',[150 -1 -1]);
    +0136         % bound1: chi2 range
    +0137         gui.panels.control.HBox3 = uix.HBox('Parent',gui.panels.control.VBox,...
    +0138             'Spacing',3);
    +0139         gui.text_handles.uncertchi2 = uicontrol('Parent',gui.panels.control.HBox3,...
    +0140             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0141             'String',[char(hex2dec('03A7')),char(hex2dec('00B2')),...
    +0142             ' range          min | max']);
    +0143         tstr = 'Lower bound of chi2 range.';
    +0144         gui.edit_handles.uncertchi2_min = uicontrol('Parent',gui.panels.control.HBox3,...
    +0145             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',...
    +0146             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0147             'Enable','off','Callback',@uv_onEditValue);
    +0148         tstr = 'Upper bound of chi2 range.';
    +0149         gui.edit_handles.uncertchi2_max = uicontrol('Parent',gui.panels.control.HBox3,...
    +0150             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',...
    +0151             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0152             'Enable','off','Callback',@uv_onEditValue);
    +0153         set(gui.panels.control.HBox3,'Widths',[150 -1 -1]);
    +0154         % bound2: model norm range
    +0155         gui.panels.control.HBox4 = uix.HBox('Parent',gui.panels.control.VBox,...
    +0156             'Spacing',3);
    +0157         gui.text_handles.uncertmnorm = uicontrol('Parent',gui.panels.control.HBox4,...
    +0158             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0159             'String',['|Lm|',char(hex2dec('2082')),' range      min | max']);
    +0160         tstr = 'Lower bound of model norm range.';
    +0161         gui.edit_handles.uncertmnorm_min = uicontrol('Parent',gui.panels.control.HBox4,...
    +0162             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',...
    +0163             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0164             'Enable','off','Callback',@uv_onEditValue);
    +0165         tstr = 'Upper bound of model norm range.';
    +0166         gui.edit_handles.uncertmnorm_max = uicontrol('Parent',gui.panels.control.HBox4,...
    +0167             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',...
    +0168             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0169             'Enable','off','Callback',@uv_onEditValue);
    +0170         set(gui.panels.control.HBox4,'Widths',[150 -1 -1]);
    +0171         % bound3: threshold
    +0172         gui.panels.control.HBox5 = uix.HBox('Parent',gui.panels.control.VBox,...
    +0173             'Spacing',3);
    +0174         gui.text_handles.uncertThresh = uicontrol('Parent',gui.panels.control.HBox5,...
    +0175             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0176             'String','Threshold');
    +0177         uix.Empty('Parent',gui.panels.control.HBox5);
    +0178         tstr = 'Threshold value (0.05 = 5%).';
    +0179         gui.edit_handles.uncertThresh = uicontrol('Parent',gui.panels.control.HBox5,...
    +0180             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','uncertThresh',...
    +0181             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0182             'Enable','off','Callback',@uv_onEditValue);
    +0183         set(gui.panels.control.HBox5,'Widths',[150 -1 -1]);
    +0184         % max tries
    +0185         gui.panels.control.HBox6 = uix.HBox('Parent',gui.panels.control.VBox,...
    +0186             'Spacing',3);
    +0187         gui.text_handles.uncertMax = uicontrol('Parent',gui.panels.control.HBox6,...
    +0188             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0189             'String','Max. #tries');
    +0190         uix.Empty('Parent',gui.panels.control.HBox6);
    +0191         tstr = 'Maximum number of unsuccesful tries.';
    +0192         gui.edit_handles.uncertMax = uicontrol('Parent',gui.panels.control.HBox6,...
    +0193             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','uncertMax',...
    +0194             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0195             'Enable','off','Callback',@uv_onEditValue);
    +0196         set(gui.panels.control.HBox6,'Widths',[150 -1 -1]);
    +0197         % RUN button
    +0198         gui.panels.control.HBox7 = uix.HBox('Parent',gui.panels.control.VBox,...
    +0199             'Spacing',3);
    +0200         uix.Empty('Parent',gui.panels.control.HBox7);
    +0201         uix.Empty('Parent',gui.panels.control.HBox7);
    +0202         tstr = ['<HTML>RUN uncertainty calculation.<br>',...
    +0203             'Regularization is the same as in main NUCLEUSinv GUI.'];
    +0204         gui.push_handles.reset = uicontrol('Parent',gui.panels.control.HBox7,...
    +0205             'String','RUN','FontSize',myui.fontsize,'Tag','process',...
    +0206             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0207             'BackGroundColor','g','Callback',@uv_onPushRun);
    +0208         set(gui.panels.control.HBox7,'Widths',[150 -1 -1]);
    +0209 
    +0210         % --- process panel ---
    +0211         waitbar(2/steps,hwb,'loading GUI elements - process');
    +0212         gui.panels.process.main = uix.BoxPanel('Parent',gui.left,...
    +0213             'Title','Process Uncertainty Runs','MinimizeFcn',@minimizePanel,...
    +0214             'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle);
    +0215         gui.panels.process.VBox = uix.VBox('Parent',gui.panels.process.main,...
    +0216             'Spacing',3,'Padding',3);
    +0217         % chi2 range
    +0218         gui.panels.process.HBox1 = uix.HBox('Parent',gui.panels.process.VBox,...
    +0219             'Spacing',3);
    +0220         gui.text_handles.chi2 = uicontrol('Parent',gui.panels.process.HBox1,...
    +0221             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0222             'String',[char(hex2dec('03A7')),char(hex2dec('00B2')),...
    +0223             ' range          min | max']);
    +0224         tstr = 'Lower bound of chi2 range.';
    +0225         gui.edit_handles.chi2_min = uicontrol('Parent',gui.panels.process.HBox1,...
    +0226             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','process',...
    +0227             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0228             'Callback',@uv_onEditValue);
    +0229         tstr = 'Upper bound of chi2 range.';
    +0230         gui.edit_handles.chi2_max = uicontrol('Parent',gui.panels.process.HBox1,...
    +0231             'Style','edit','String','2','FontSize',myui.fontsize,'Tag','process',...
    +0232             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0233             'Callback',@uv_onEditValue);
    +0234         set(gui.panels.process.HBox1,'Widths',[150 -1 -1]);
    +0235         % model norm range
    +0236         gui.panels.process.HBox2 = uix.HBox('Parent',gui.panels.process.VBox,...
    +0237             'Spacing',3);
    +0238         gui.text_handles.mnorm = uicontrol('Parent',gui.panels.process.HBox2,...
    +0239             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0240             'String',['|Lm|',char(hex2dec('2082')),' range      min | max']);
    +0241         tstr = 'Lower bound of model norm range.';
    +0242         gui.edit_handles.mnorm_min = uicontrol('Parent',gui.panels.process.HBox2,...
    +0243             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','process',...
    +0244             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0245             'Callback',@uv_onEditValue);
    +0246         tstr = 'Upper bound of model norm range.';
    +0247         gui.edit_handles.mnorm_max = uicontrol('Parent',gui.panels.process.HBox2,...
    +0248             'Style','edit','String','2','FontSize',myui.fontsize,'Tag','process',...
    +0249             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0250             'Callback',@uv_onEditValue);
    +0251         set(gui.panels.process.HBox2,'Widths',[150 -1 -1]);
    +0252         % RESET button
    +0253         gui.panels.process.HBox3 = uix.HBox('Parent',gui.panels.process.VBox,...
    +0254             'Spacing',3);
    +0255         uix.Empty('Parent',gui.panels.process.HBox3);
    +0256         tstr = 'SEND bounds to recaluclation panel above.';
    +0257         gui.push_handles.send = uicontrol('Parent',gui.panels.process.HBox3,...
    +0258             'String','SEND','FontSize',myui.fontsize,'Tag','process',...
    +0259             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0260             'Callback',@uv_onPushSend);
    +0261         tstr = 'RESET processing bounds and plots.';
    +0262         gui.push_handles.reset = uicontrol('Parent',gui.panels.process.HBox3,...
    +0263             'String','RESET','FontSize',myui.fontsize,'Tag','process',...
    +0264             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0265             'Callback',@uv_onPushReset);
    +0266         set(gui.panels.process.HBox3,'Widths',[150 -1 -1]);
    +0267 
    +0268         % --- RTD panel ---
    +0269         waitbar(3/steps,hwb,'loading GUI elements - RTD bounds');
    +0270         gui.panels.rtd.main = uix.BoxPanel('Parent',gui.left,...
    +0271             'Title','RTD Calculation Bounds','MinimizeFcn',@minimizePanel,...
    +0272             'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle);
    +0273         gui.panels.rtd.VBox = uix.VBox('Parent',gui.panels.rtd.main,...
    +0274             'Spacing',3,'Padding',3);
    +0275         % RTD range
    +0276         gui.panels.rtd.HBox1 = uix.HBox('Parent',gui.panels.rtd.VBox,...
    +0277             'Spacing',3);
    +0278         gui.text_handles.rtd = uicontrol('Parent',gui.panels.rtd.HBox1,...
    +0279             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0280             'String','RTD range       min | max');
    +0281         tstr = ['<HTML>Minimum relaxation time in RTDs used<br>',...
    +0282             'for calculating statistics on E0 & TLGM.'];
    +0283         gui.edit_handles.rtd_min = uicontrol('Parent',gui.panels.rtd.HBox1,...
    +0284             'Style','edit','String','0','FontSize',myui.fontsize,'Tag','rtd',...
    +0285             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0286             'Callback',@uv_onEditValue);
    +0287         tstr = ['<HTML>Maximum relaxation time in RTDs used<br>',...
    +0288             'for calculating statistics on E0 & TLGM.'];
    +0289         gui.edit_handles.rtd_max = uicontrol('Parent',gui.panels.rtd.HBox1,...
    +0290             'Style','edit','String','2','FontSize',myui.fontsize,'Tag','rtd',...
    +0291             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0292             'Callback',@uv_onEditValue);
    +0293         set(gui.panels.rtd.HBox1,'Widths',[150 -1 -1]);
    +0294         % RESET button
    +0295         gui.panels.rtd.HBox3 = uix.HBox('Parent',gui.panels.rtd.VBox,...
    +0296             'Spacing',3);
    +0297         uix.Empty('Parent',gui.panels.rtd.HBox3);
    +0298         uix.Empty('Parent',gui.panels.rtd.HBox3);
    +0299         tstr = 'RESET RTDs calculation bounds.';
    +0300         gui.push_handles.reset_rtd = uicontrol('Parent',gui.panels.rtd.HBox3,...
    +0301             'String','RESET','FontSize',myui.fontsize,'Tag','rtd',...
    +0302             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0303             'Callback',@uv_onPushReset);
    +0304         set(gui.panels.rtd.HBox3,'Widths',[150 -1 -1]);
    +0305 
    +0306         % --- Statistics panel ---
    +0307         waitbar(4/steps,hwb,'loading GUI elements - statistics');
    +0308         gui.panels.info.main = uix.BoxPanel('Parent',gui.left,...
    +0309             'Title','Uncertainty Statistics','MinimizeFcn',@minimizePanel,...
    +0310             'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle);
    +0311         gui.panels.info.VBox = uix.VBox('Parent',gui.panels.info.main,...
    +0312             'Spacing',3,'Padding',3);
    +0313         % mean TLGM
    +0314         gui.panels.info.HBox1 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0315             'Spacing',3);
    +0316         gui.text_handles.TLGM = uicontrol('Parent',gui.panels.info.HBox1,...
    +0317             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0318             'String','TLGM            mean | std');
    +0319         tstr = 'MEAN of all TLGM values.';
    +0320         gui.edit_handles.TLGM_mean = uicontrol('Parent',gui.panels.info.HBox1,...
    +0321             'Style','edit','String','0','FontSize',myui.fontsize,...
    +0322             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0323             'BackgroundColor',colors.BoxPRC);
    +0324         tstr = 'STD of all TLGM values.';
    +0325         gui.edit_handles.TLGM_std = uicontrol('Parent',gui.panels.info.HBox1,...
    +0326             'Style','edit','String','2','FontSize',myui.fontsize,...
    +0327             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0328             'BackgroundColor',colors.BoxPRC);
    +0329         set(gui.panels.info.HBox1,'Widths',[150 -1 -1]);
    +0330         % aad TLGM
    +0331         gui.panels.info.HBox2 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0332             'Spacing',3);
    +0333         gui.text_handles.TLGM_aad = uicontrol('Parent',gui.panels.info.HBox2,...
    +0334             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0335             'String','TLGM            aad(mean)');
    +0336         uix.Empty('Parent',gui.panels.info.HBox2);
    +0337         tstr = 'AAD (average absolute deviation from mean) of all TLGM values.';
    +0338         gui.edit_handles.TLGM_aad = uicontrol('Parent',gui.panels.info.HBox2,...
    +0339             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0340             'Style','edit','String','2','FontSize',myui.fontsize);
    +0341         set(gui.panels.info.HBox2,'Widths',[150 -1 -1]);
    +0342         % median TLGM
    +0343         gui.panels.info.HBox3 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0344             'Spacing',3);
    +0345         gui.text_handles.TLGM_med = uicontrol('Parent',gui.panels.info.HBox3,...
    +0346             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0347             'String','TLGM median | aad(med)');
    +0348         tstr = 'MEDIAN of all TLGM values.';
    +0349         gui.edit_handles.TLGM_med = uicontrol('Parent',gui.panels.info.HBox3,...
    +0350             'Style','edit','String','0','FontSize',myui.fontsize,...
    +0351             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0352             'BackgroundColor',colors.BoxCPS);
    +0353         tstr = 'AAD (average absolute deviation from median) of all TLGM values.';
    +0354         gui.edit_handles.TLGM_aadmed = uicontrol('Parent',gui.panels.info.HBox3,...
    +0355             'Style','edit','String','2','FontSize',myui.fontsize,...
    +0356             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0357             'BackgroundColor',colors.BoxCPS);
    +0358         set(gui.panels.info.HBox3,'Widths',[150 -1 -1]);
    +0359         % mean E0
    +0360         gui.panels.info.HBox4 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0361             'Spacing',3);
    +0362         gui.text_handles.E0 = uicontrol('Parent',gui.panels.info.HBox4,...
    +0363             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0364             'String','E0                mean | std');
    +0365         tstr = 'MEAN of all E0 values.';
    +0366         gui.edit_handles.E0_mean = uicontrol('Parent',gui.panels.info.HBox4,...
    +0367             'Style','edit','String','0','FontSize',myui.fontsize,...
    +0368             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0369             'BackgroundColor',colors.BoxPRC);
    +0370         tstr = 'STD of all E0 values.';
    +0371         gui.edit_handles.E0_std = uicontrol('Parent',gui.panels.info.HBox4,...
    +0372             'Style','edit','String','2','FontSize',myui.fontsize,...
    +0373             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0374             'BackgroundColor',colors.BoxPRC);
    +0375         set(gui.panels.info.HBox4,'Widths',[150 -1 -1]);
    +0376         % aad E0
    +0377         gui.panels.info.HBox5 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0378             'Spacing',3);
    +0379         gui.text_handles.E0_aad = uicontrol('Parent',gui.panels.info.HBox5,...
    +0380             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0381             'String','E0                aad(mean)');
    +0382         uix.Empty('Parent',gui.panels.info.HBox5);
    +0383         tstr = 'AAD (average absolute deviation from mean) of all E0 values.';
    +0384         gui.edit_handles.E0_aad = uicontrol('Parent',gui.panels.info.HBox5,...
    +0385             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0386             'Style','edit','String','2','FontSize',myui.fontsize);
    +0387         set(gui.panels.info.HBox5,'Widths',[150 -1 -1]);
    +0388         % median E0
    +0389         gui.panels.info.HBox6 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0390             'Spacing',3);
    +0391         gui.text_handles.E0_med = uicontrol('Parent',gui.panels.info.HBox6,...
    +0392             'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0393             'String','E0     median | aad(med)');
    +0394         tstr = 'MEDIAN of all E0 values.';
    +0395         gui.edit_handles.E0_med = uicontrol('Parent',gui.panels.info.HBox6,...
    +0396             'Style','edit','String','0','FontSize',myui.fontsize,...
    +0397             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0398             'BackgroundColor',colors.BoxCPS);
    +0399         tstr = 'AAD (average absolute deviation from median) of all E0 values.';
    +0400         gui.edit_handles.E0_aadmed = uicontrol('Parent',gui.panels.info.HBox6,...
    +0401             'Style','edit','String','2','FontSize',myui.fontsize,...
    +0402             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0403             'BackgroundColor',colors.BoxCPS);
    +0404         set(gui.panels.info.HBox6,'Widths',[150 -1 -1]);
    +0405 
    +0406         % --- update MAIN GUI button ---
    +0407         tstr = 'UPDATE uncertainty data in main NUCLEUSinv GUI.';
    +0408         gui.push_handles.update = uicontrol('Parent',gui.left,...
    +0409             'String','UPDATE MAIN GUI','FontSize',myui.fontsize,'Tag','update',...
    +0410             'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0411             'Callback',@uv_onPushUpdate);
    +0412 
    +0413         % fix text vertical alignment
    +0414         jh = findjobj(gui.text_handles.uncertMethod);
    +0415         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0416         jh = findjobj(gui.text_handles.uncertN);
    +0417         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0418         jh = findjobj(gui.text_handles.uncertchi2);
    +0419         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0420         jh = findjobj(gui.text_handles.uncertmnorm);
    +0421         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0422         jh = findjobj(gui.text_handles.uncertThresh);
    +0423         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0424         jh = findjobj(gui.text_handles.uncertMax);
    +0425         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0426         jh = findjobj(gui.text_handles.chi2);
    +0427         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0428         jh = findjobj(gui.text_handles.mnorm);
    +0429         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0430         jh = findjobj(gui.text_handles.rtd);
    +0431         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0432         jh = findjobj(gui.text_handles.TLGM);
    +0433         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0434         jh = findjobj(gui.text_handles.TLGM_aad);
    +0435         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0436         jh = findjobj(gui.text_handles.TLGM_med);
    +0437         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0438         jh = findjobj(gui.text_handles.E0);
    +0439         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0440         jh = findjobj(gui.text_handles.E0_aad);
    +0441         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0442         jh = findjobj(gui.text_handles.E0_med);
    +0443         jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0444 
    +0445         % empty space at bottom of left side
    +0446         uix.Empty('Parent',gui.left);
    +0447         % adjust the heights of all left-column-panels
    +0448         heights = [22 22 22 22 28 -1; 22+7*24+9*3 22+3*24+5*3 22+2*24+4*4 22+6*24+8*3 28 -1];
    +0449         % panel header is always 22 high
    +0450         set(gui.left,'Heights',heights(2,:),...
    +0451             'MinimumHeights',[22 22 22 22 28 0]);        
    +0452 
    +0453         % --- plot boxes ---
    +0454         waitbar(5/steps,hwb,'loading GUI elements - graphics');
    +0455         gui.rightPanel = uix.TabPanel('Parent',gui.right,...
    +0456             'BackGroundColor',colors.panelBG);
    +0457         % -- tab1
    +0458         gui.righttop1 = uix.HBox('Parent',gui.rightPanel,...
    +0459             'BackGroundColor',colors.panelBG,'Spacing',5);
    +0460         gui.pbox11 = uicontainer('Parent',gui.righttop1,...
    +0461             'BackGroundColor',colors.panelBG);
    +0462         gui.pbox12 = uicontainer('Parent',gui.righttop1,...
    +0463             'BackGroundColor',colors.panelBG);
    +0464         set(gui.righttop1,'Widths',[-1 -1 ]);
    +0465         gui.rightbot = uix.HBox('Parent',gui.right,...
    +0466             'BackGroundColor',colors.panelBG,'Spacing',5);
    +0467         gui.pbox2 = uicontainer('Parent',gui.rightbot,...
    +0468             'BackGroundColor',colors.panelBG);
    +0469 
    +0470         % -- tab2
    +0471         gui.righttop2 = uix.HBox('Parent',gui.rightPanel,...
    +0472             'BackGroundColor',colors.panelBG,'Spacing',5);
    +0473         gui.pbox21 = uicontainer('Parent',gui.righttop2,...
    +0474             'BackGroundColor',colors.panelBG);
    +0475         gui.pbox22 = uicontainer('Parent',gui.righttop2,...
    +0476             'BackGroundColor',colors.panelBG);
    +0477         set(gui.righttop2,'Widths',[-1 -1 ]);
    +0478 
    +0479         gui.rightPanel.TabTitles = {'Statistics','Histograms'};
    +0480         gui.rightPanel.TabWidth = 75;
    +0481         gui.rightPanel.TabEnables = {'on','on'};
    +0482 
    +0483         % -- plot axes --
    +0484         gui.axes11 = axes('Parent',gui.pbox12,'Box','on');
    +0485         gui.axes12 = axes('Parent',gui.pbox11,'Box','on');
    +0486         gui.axes2 = axes('Parent',gui.pbox2,'Box','on');
    +0487         gui.axes21 = axes('Parent',gui.pbox21,'Box','on');
    +0488         gui.axes22 = axes('Parent',gui.pbox22,'Box','on');
    +0489 
    +0490         % the chi2 vs. xn plot has a context menu
    +0491         gui.cm_handles.axes_chi2 = uicontextmenu(fig_uncert);
    +0492         gui.cm_handles.axes_color = uimenu(gui.cm_handles.axes_chi2,...
    +0493             'Label','color by');
    +0494         gui.cm_handles.axes_color_none = uimenu(gui.cm_handles.axes_color,...
    +0495             'Label','none','Tag','none','Checked','on',...
    +0496             'Callback',@uv_onContextPlotsColor);
    +0497         gui.cm_handles.axes_color_chi2 = uimenu(gui.cm_handles.axes_color,...
    +0498             'Label','chi2','Tag','chi2','Callback',@uv_onContextPlotsColor);
    +0499         gui.cm_handles.axes_color_mnorm = uimenu(gui.cm_handles.axes_color,...
    +0500             'Label','xn','Tag','xn','Callback',@uv_onContextPlotsColor);
    +0501         set(gui.axes12,'UIContextMenu',gui.cm_handles.axes_chi2);
    +0502 
    +0503         % the RTD plot has a context menu
    +0504         gui.cm_handles.axes_rtd = uicontextmenu(fig_uncert);
    +0505         gui.cm_handles.axes_rtd_lines = uimenu(gui.cm_handles.axes_rtd,...
    +0506             'Label','lines','Tag','lines','Checked','on',...
    +0507             'Callback',@uv_onContextPlotsRTD);
    +0508         gui.cm_handles.axes_rtd_patch = uimenu(gui.cm_handles.axes_rtd,...
    +0509             'Label','patch');
    +0510         gui.cm_handles.axes_rtd_patch_mean = uimenu(gui.cm_handles.axes_rtd_patch,...
    +0511             'Label','mean / std','Tag','patchmean',...
    +0512             'Callback',@uv_onContextPlotsRTD);
    +0513         gui.cm_handles.axes_rtd_patch_median = uimenu(gui.cm_handles.axes_rtd_patch,...
    +0514             'Label','median / aad','Tag','patchmedian',...
    +0515             'Callback',@uv_onContextPlotsRTD);
    +0516         set(gui.axes2,'UIContextMenu',gui.cm_handles.axes_rtd);
    +0517 
    +0518         % --- store main GUI settings ---
    +0519         gui.myui = nucleus.gui.myui;
    +0520         gui.myui.heights = heights;
    +0521         gui.figh_nucleus = figh_nucleus;
    +0522 
    +0523         % --- save gui data to GUI ---
    +0524         setappdata(fig_uncert,'gui',gui);
    +0525 
    +0526         % make GUI visible
    +0527         delete(hwb);
    +0528         set(gui.main,'Visible','on');
    +0529 
    +0530         % initialize color style
    +0531         uv.colorstyle = 'none';
    +0532         % initialize RTD plot style
    +0533         uv.rtd_plotstyle = 'lines';
    +0534     else
    +0535         data = getappdata(fig_uncert,'data');
    +0536         uv = data.uv;
    +0537     end
    +0538     % if the figure is already open load the GUI data
    +0539     gui = getappdata(fig_uncert,'gui');
    +0540     % update new NUCLEUSinv data
    +0541     setappdata(fig_uncert,'data',nucleus_data);
    +0542     data = getappdata(fig_uncert,'data');
    +0543     % clear axes
    +0544     clearAllAxes(fig_uncert);
    +0545 
    +0546     % round all chi2 and xn values to 6 digits
    +0547     chi2_all = data.results.invstd.uncert.chi2_all;
    +0548     chi2_all = round(1e6.*chi2_all)./1e6;
    +0549     data.results.invstd.uncert.chi2_all = chi2_all;
    +0550     mnorm_all = data.results.invstd.uncert.mnorm_all;
    +0551     mnorm_all = round(1e6.*mnorm_all)./1e6;
    +0552     data.results.invstd.uncert.mnorm_all = mnorm_all;
    +0553 
    +0554     % create logical mask
    +0555     uv.touse = ones(nucleus_data.uncert.N,1);
    +0556     % --- fill the edit fields ---
    +0557     invstd = data.results.invstd;
    +0558     uncert = invstd.uncert;
    +0559     % 1.) control
    +0560     uv.uncertMethod = uncert.params.uncert.Method;
    +0561     uv.uncertN = uncert.params.uncert.N;
    +0562     set(gui.edit_handles.uncertN,'String',num2str(uv.uncertN));
    +0563     uv.uncertThresh = uncert.params.uncert.Thresh;
    +0564     set(gui.edit_handles.uncertThresh,'String',num2str(uv.uncertThresh));
    +0565     uv.uncertMax = uncert.params.uncert.Max;
    +0566     set(gui.edit_handles.uncertMax,'String',num2str(uv.uncertMax));
    +0567     uv.chi2_range_calc  = [min(uncert.chi2_all) max(uncert.chi2_all)];
    +0568     uv.mnorm_range_calc = [min(uncert.mnorm_all) max(uncert.mnorm_all)];
    +0569     % set popup menu
    +0570     switch invstd.invtype
    +0571         case {'LU','NNLS'}
    +0572             set(gui.popup_handles.uncertMethod,...
    +0573                 'String',{'RMS - unbounded','RMS - bounded'})
    +0574             switch uncert.params.uncert.Method
    +0575                 case 'RMS_free'
    +0576                     set(gui.popup_handles.uncertMethod,'Value',1);
    +0577                 case 'RMS_bound'
    +0578                     set(gui.popup_handles.uncertMethod,'Value',2);
    +0579             end
    +0580         case 'MUMO'
    +0581             set(gui.popup_handles.uncertMethod,...
    +0582                 'String',{'RMS - unbounded','RMS - bounded','Threshold','Conf. Interval'})
    +0583             switch uncert.params.uncert.Method
    +0584                 case 'RMS_free'
    +0585                     set(gui.popup_handles.uncertMethod,'Value',1);
    +0586                 case 'RMS_bound'
    +0587                     set(gui.popup_handles.uncertMethod,'Value',2);
    +0588                 case 'thresh'
    +0589                     set(gui.popup_handles.uncertMethod,'Value',3);
    +0590                 case 'ci'
    +0591                     set(gui.popup_handles.uncertMethod,'Value',4);
    +0592             end
    +0593     end
    +0594     set(gui.edit_handles.uncertN,'String',num2str(uncert.params.uncert.N));
    +0595     % 2.) process
    +0596     chi2_range  = uv.chi2_range_calc;
    +0597     mnorm_range = uv.mnorm_range_calc;
    +0598     set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',chi2_range(1,1)));
    +0599     set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',chi2_range(1,2)));
    +0600     set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',mnorm_range(1,1)));
    +0601     set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',mnorm_range(1,2)));
    +0602     % 3.) RTD range
    +0603     rtd_range = data.invstd.time;
    +0604     set(gui.edit_handles.rtd_min,'String',num2str(rtd_range(1,1)));
    +0605     set(gui.edit_handles.rtd_max,'String',num2str(rtd_range(1,2)));
    +0606     uv.chi2_range = chi2_range;
    +0607     uv.mnorm_range = mnorm_range;
    +0608     uv.rtd_range = rtd_range;
    +0609 
    +0610     % update data
    +0611     data.uv = uv;
    +0612     setappdata(fig_uncert,'data',data);
    +0613     uv_onPopupMethod(gui.popup_handles.uncertMethod);
    +0614 
    +0615     % plot all uncertainty data
    +0616     uv_updateInformation(fig_uncert);
    +0617     beautifyAxes(fig_uncert);
    +0618 else
    +0619     helpdlg({'function: UNCERTVIEW',...
    +0620         'Cannot continue because there is no data!'},...
    +0621         'No uncertainty data.');
    +0622 end
    +0623 
    +0624 end
    +0625 
    +0626 %% subfunction to update the edit fields
    +0627 function uv_onEditValue(src,~)
    +0628 figh = ancestor(src,'figure','toplevel');
    +0629 gui = getappdata(figh,'gui');
    +0630 data = getappdata(figh,'data');
    +0631 uv = data.uv;
    +0632 
    +0633 % get the edit field value
    +0634 val = str2double(get(src,'String'));
    +0635 
    +0636 switch get(src,'Tag')
    +0637     case 'uncertN'
    +0638         if val < 10
    +0639             uncertN = 10;
    +0640         else
    +0641             uncertN = round(val);
    +0642         end
    +0643         set(src,'String',num2str(uncertN));
    +0644         uv.uncertN = uncertN;
    +0645         data.uv = uv;
    +0646     case 'uncertThresh'
    +0647     case 'uncertMax'
    +0648     case 'control'
    +0649         % set the value with the desired layout
    +0650         set(src,'String',sprintf('%7.6f',val));
    +0651         chi2_range_calc(1,1) = str2double(get(gui.edit_handles.uncertchi2_min,'String'));
    +0652         chi2_range_calc(1,2) = str2double(get(gui.edit_handles.uncertchi2_max,'String'));
    +0653         mnorm_range_calc(1,1) = str2double(get(gui.edit_handles.uncertmnorm_min,'String'));
    +0654         mnorm_range_calc(1,2) = str2double(get(gui.edit_handles.uncertmnorm_max,'String'));
    +0655         % update data
    +0656         uv.chi2_range_calc = chi2_range_calc;
    +0657         uv.mnorm_range_calc = mnorm_range_calc;
    +0658         data.uv = uv;
    +0659     case 'process'
    +0660         % set the value with the desired layout
    +0661         set(src,'String',sprintf('%7.6f',val));
    +0662         % get all range values
    +0663         chi2_range(1,1) = str2double(get(gui.edit_handles.chi2_min,'String'));
    +0664         chi2_range(1,2) = str2double(get(gui.edit_handles.chi2_max,'String'));
    +0665         mnorm_range(1,1) = str2double(get(gui.edit_handles.mnorm_min,'String'));
    +0666         mnorm_range(1,2) = str2double(get(gui.edit_handles.mnorm_max,'String'));
    +0667         % fix wrong user input
    +0668         if chi2_range(2) <= chi2_range(1)
    +0669             warndlg({'function: UNCERTVIEW',...
    +0670             'Lower bound is larger than upper bound!'},...
    +0671             'Resetting.');
    +0672             chi2_range(1) = min(data.results.invstd.uncert.chi2_all);
    +0673             chi2_range(2) = max(data.results.invstd.uncert.chi2_all);            
    +0674             set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',chi2_range(1)));
    +0675             set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',chi2_range(2)));
    +0676         end
    +0677         if mnorm_range(2) <= mnorm_range(1)            
    +0678             warndlg({'function: UNCERTVIEW',...
    +0679             'Lower bound is larger than upper bound!'},...
    +0680             'Resetting.');
    +0681             mnorm_range(1) = min(data.results.invstd.uncert.mnorm_all);
    +0682             mnorm_range(2) = max(data.results.invstd.uncert.mnorm_all);
    +0683             set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',mnorm_range(1)));
    +0684             set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',mnorm_range(2)));
    +0685         end
    +0686         % update data
    +0687         uv.chi2_range = chi2_range;
    +0688         uv.mnorm_range = mnorm_range;
    +0689         data.uv = uv;
    +0690         % update logical mask for plotting
    +0691         data = uv_updateMASK(data);
    +0692     case 'rtd'
    +0693         % set the value with the desired layout
    +0694         set(src,'String',num2str(val));
    +0695         % get all range values
    +0696         rtd_range(1,1) = str2double(get(gui.edit_handles.rtd_min,'String'));
    +0697         rtd_range(1,2) = str2double(get(gui.edit_handles.rtd_max,'String'));
    +0698         % update data
    +0699         uv.rtd_range = rtd_range;
    +0700         data.uv = uv;
    +0701 end
    +0702 
    +0703 % update GUI data
    +0704 setappdata(figh,'data',data);
    +0705 % update information
    +0706 uv_updateInformation(figh);
    +0707 end
    +0708 
    +0709 %% subfunction to copy the chi2 and xn range to the control panel
    +0710 function uv_onPushSend(src,~)
    +0711 figh = ancestor(src,'figure','toplevel');
    +0712 gui = getappdata(figh,'gui');
    +0713 data = getappdata(figh,'data');
    +0714 uv = data.uv;
    +0715 
    +0716 % get all data
    +0717 chi2_range(1,1) = str2double(get(gui.edit_handles.chi2_min,'String'));
    +0718 chi2_range(1,2) = str2double(get(gui.edit_handles.chi2_max,'String'));
    +0719 mnorm_range(1,1) = str2double(get(gui.edit_handles.mnorm_min,'String'));
    +0720 mnorm_range(1,2) = str2double(get(gui.edit_handles.mnorm_max,'String'));
    +0721 
    +0722 % copy data to calc
    +0723 uv.chi2_range_calc = chi2_range;
    +0724 uv.mnorm_range_calc = mnorm_range;
    +0725 data.uv = uv;
    +0726 
    +0727 % write values to edit field
    +0728 set(gui.edit_handles.uncertchi2_min,...
    +0729     'String',sprintf('%7.6f',uv.chi2_range_calc(1)));
    +0730 set(gui.edit_handles.uncertchi2_max,...
    +0731     'String',sprintf('%7.6f',uv.chi2_range_calc(2)));
    +0732 set(gui.edit_handles.uncertmnorm_min,...
    +0733     'String',sprintf('%7.6f',uv.mnorm_range_calc(1)));
    +0734 set(gui.edit_handles.uncertmnorm_max,...
    +0735     'String',sprintf('%7.6f',uv.mnorm_range_calc(2)));
    +0736 
    +0737 % update GUI data
    +0738 setappdata(figh,'data',data);
    +0739 end
    +0740 
    +0741 %% subfunction to control the line color
    +0742 function uv_onContextPlotsColor(src,~)
    +0743 figh = ancestor(src,'figure','toplevel');
    +0744 gui = getappdata(figh,'gui');
    +0745 data = getappdata(figh,'data');
    +0746 uv = data.uv;
    +0747 
    +0748 % switch through different plot options
    +0749 switch get(src,'Tag')
    +0750     case 'none'
    +0751         set(gui.cm_handles.axes_color_none,'Checked','on');
    +0752         set(gui.cm_handles.axes_color_chi2,'Checked','off');
    +0753         set(gui.cm_handles.axes_color_mnorm,'Checked','off');
    +0754     case 'chi2'
    +0755         set(gui.cm_handles.axes_color_none,'Checked','off');
    +0756         set(gui.cm_handles.axes_color_chi2,'Checked','on');
    +0757         set(gui.cm_handles.axes_color_mnorm,'Checked','off');
    +0758     case 'xn'
    +0759         set(gui.cm_handles.axes_color_none,'Checked','off');
    +0760         set(gui.cm_handles.axes_color_chi2,'Checked','off');
    +0761         set(gui.cm_handles.axes_color_mnorm,'Checked','on');
    +0762 end
    +0763 uv.colorstyle = get(src,'Tag');
    +0764 
    +0765 % update GUI data
    +0766 data.uv = uv;
    +0767 setappdata(figh,'data',data);
    +0768 % update information and plots
    +0769 uv_updateInformation(figh);
    +0770 end
    +0771 
    +0772 %% subfunction to control RTD axes context menu
    +0773 function uv_onContextPlotsRTD(src,~)
    +0774 figh = ancestor(src,'figure','toplevel');
    +0775 gui = getappdata(figh,'gui');
    +0776 data = getappdata(figh,'data');
    +0777 uv = data.uv;
    +0778 
    +0779 % switch through different plot options
    +0780 switch get(src,'Tag')
    +0781     case 'lines'
    +0782         set(gui.cm_handles.axes_rtd_lines,'Checked','on');
    +0783         set(gui.cm_handles.axes_rtd_patch_mean,'Checked','off');
    +0784         set(gui.cm_handles.axes_rtd_patch_median,'Checked','off');
    +0785     case 'patchmean'
    +0786         set(gui.cm_handles.axes_rtd_lines,'Checked','off');
    +0787         set(gui.cm_handles.axes_rtd_patch_mean,'Checked','on');
    +0788         set(gui.cm_handles.axes_rtd_patch_median,'Checked','off');
    +0789     case 'patchmedian'
    +0790         set(gui.cm_handles.axes_rtd_lines,'Checked','off');
    +0791         set(gui.cm_handles.axes_rtd_patch_mean,'Checked','off');
    +0792         set(gui.cm_handles.axes_rtd_patch_median,'Checked','on');
    +0793 end
    +0794 uv.rtd_plotstyle = get(src,'Tag');
    +0795 
    +0796 % update GUI data
    +0797 data.uv = uv;
    +0798 setappdata(figh,'data',data);
    +0799 % update information and plots
    +0800 uv_updateInformation(figh);
    +0801 end
    +0802 
    +0803 %% subfunction to update the logical mask
    +0804 function data = uv_updateMASK(data)
    +0805 uncert = data.results.invstd.uncert;
    +0806 uv = data.uv;
    +0807 
    +0808 mask1 = uncert.chi2_all >= uv.chi2_range(1) & uncert.chi2_all <= uv.chi2_range(2);
    +0809 mask2 = uncert.mnorm_all >= uv.mnorm_range(1) & uncert.mnorm_all <= uv.mnorm_range(2);
    +0810 uv.touse = mask1 & mask2;
    +0811 
    +0812 data.uv = uv;
    +0813 end
    +0814 
    +0815 %% subfunction to update control panel based on uncertainty method
    +0816 function uv_onPopupMethod(src,~)
    +0817 figh = ancestor(src,'figure','toplevel');
    +0818 gui = getappdata(figh,'gui');
    +0819 data = getappdata(figh,'data');
    +0820 uv = data.uv;
    +0821 invstd = data.results.invstd;
    +0822 
    +0823 val = get(gui.popup_handles.uncertMethod,'Value');
    +0824 
    +0825 switch invstd.invtype
    +0826     case {'LU','NNLS'}
    +0827         switch val
    +0828             case 1 % RMS_free
    +0829                 uv.uncertMethod = 'RMS_free';
    +0830                 set(gui.edit_handles.uncertchi2_min,'Enable','off');
    +0831                 set(gui.edit_handles.uncertchi2_max,'Enable','off');
    +0832                 set(gui.edit_handles.uncertmnorm_min,'Enable','off');
    +0833                 set(gui.edit_handles.uncertmnorm_max,'Enable','off');
    +0834                 set(gui.edit_handles.uncertThresh,'Enable','off');
    +0835                 set(gui.edit_handles.uncertMax,'Enable','off');
    +0836             case 2 % RMS_bound
    +0837                 uv.uncertMethod = 'RMS_bound';
    +0838                 set(gui.edit_handles.uncertchi2_min,'Enable','on',...
    +0839                     'String',sprintf('%7.6f',uv.chi2_range_calc(1)));
    +0840                 set(gui.edit_handles.uncertchi2_max,'Enable','on',...
    +0841                     'String',sprintf('%7.6f',uv.chi2_range_calc(2)));
    +0842                 set(gui.edit_handles.uncertmnorm_min,'Enable','on',...
    +0843                     'String',sprintf('%7.6f',uv.mnorm_range_calc(1)));
    +0844                 set(gui.edit_handles.uncertmnorm_max,'Enable','on',...
    +0845                     'String',sprintf('%7.6f',uv.mnorm_range_calc(2)));
    +0846                 set(gui.edit_handles.uncertThresh,'Enable','off');
    +0847                 set(gui.edit_handles.uncertMax,'Enable','on',...
    +0848                     'String',num2str(uv.uncertMax));
    +0849         end
    +0850     case 'MUMO'
    +0851         switch val
    +0852             case 1 % RMS_free
    +0853                 uv.uncertMethod = 'RMS_free';
    +0854                 set(gui.edit_handles.uncertchi2_min,'Enable','off');
    +0855                 set(gui.edit_handles.uncertchi2_max,'Enable','off');
    +0856                 set(gui.edit_handles.uncertmnorm_min,'Enable','off');
    +0857                 set(gui.edit_handles.uncertmnorm_max,'Enable','off');
    +0858                 set(gui.edit_handles.uncertThresh,'Enable','off');
    +0859                 set(gui.edit_handles.uncertMax,'Enable','off');
    +0860             case 2 % RMS_bound
    +0861                 uv.uncertMethod = 'RMS_bound';
    +0862                 set(gui.edit_handles.uncertchi2_min,'Enable','on',...
    +0863                     'String',sprintf('%7.6f',uv.chi2_range_calc(1)));
    +0864                 set(gui.edit_handles.uncertchi2_max,'Enable','on',...
    +0865                     'String',sprintf('%7.6f',uv.chi2_range_calc(2)));
    +0866                 set(gui.edit_handles.uncertmnorm_min,'Enable','on',...
    +0867                     'String',sprintf('%7.6f',uv.mnorm_range_calc(1)));
    +0868                 set(gui.edit_handles.uncertmnorm_max,'Enable','on',...
    +0869                     'String',sprintf('%7.6f',uv.mnorm_range_calc(2)));
    +0870                 set(gui.edit_handles.uncertThresh,'Enable','off');
    +0871                 set(gui.edit_handles.uncertMax,'Enable','on',...
    +0872                     'String',num2str(uv.uncertMax));
    +0873             case 3 % threshold
    +0874                 uv.uncertMethod = 'thresh';
    +0875                 uv.chi2_range_calc = [0 10];
    +0876                 uv.mnorm_range_calc = [0 10];
    +0877                 set(gui.edit_handles.uncertchi2_min,'Enable','on',...
    +0878                     'String',sprintf('%7.6f',uv.chi2_range_calc(1)));
    +0879                 set(gui.edit_handles.uncertchi2_max,'Enable','on',...
    +0880                     'String',sprintf('%7.6f',uv.chi2_range_calc(2)));
    +0881                 set(gui.edit_handles.uncertmnorm_min,'Enable','on',...
    +0882                     'String',sprintf('%7.6f',uv.mnorm_range_calc(1)));
    +0883                 set(gui.edit_handles.uncertmnorm_max,'Enable','on',...
    +0884                     'String',sprintf('%7.6f',uv.mnorm_range_calc(2)));
    +0885                 set(gui.edit_handles.uncertThresh,'Enable','on');
    +0886                 set(gui.edit_handles.uncertMax,'Enable','on',...
    +0887                     'String',num2str(uv.uncertMax));
    +0888             case 4 % ci - confidence intrval
    +0889                 uv.uncertMethod = 'ci';
    +0890                 uv.chi2_range_calc = [0 10];
    +0891                 uv.mnorm_range_calc = [0 10];
    +0892                 set(gui.edit_handles.uncertchi2_min,'Enable','on',...
    +0893                     'String',sprintf('%7.6f',uv.chi2_range_calc(1)));
    +0894                 set(gui.edit_handles.uncertchi2_max,'Enable','on',...
    +0895                     'String',sprintf('%7.6f',uv.chi2_range_calc(2)));
    +0896                 set(gui.edit_handles.uncertmnorm_min,'Enable','on',...
    +0897                     'String',sprintf('%7.6f',uv.mnorm_range_calc(1)));
    +0898                 set(gui.edit_handles.uncertmnorm_max,'Enable','on',...
    +0899                     'String',sprintf('%7.6f',uv.mnorm_range_calc(2)));
    +0900                 set(gui.edit_handles.uncertThresh,'Enable','off');
    +0901                 set(gui.edit_handles.uncertMax,'Enable','on',...
    +0902                     'String',num2str(uv.uncertMax));
    +0903         end
    +0904 end
    +0905 
    +0906 % update GUI data
    +0907 data.uv = uv;
    +0908 setappdata(figh,'data',data);
    +0909 end
    +0910 
    +0911 %% subfunction to start a new uncertainty calculation
    +0912 function uv_onPushRun(src,~)
    +0913 figh = ancestor(src,'figure','toplevel');
    +0914 gui = getappdata(figh,'gui');
    +0915 data = getappdata(figh,'data');
    +0916 uv = data.uv;
    +0917 invstd = data.results.invstd;
    +0918 uncert = invstd.uncert;
    +0919 
    +0920 % original fit parameter
    +0921 iparam = invstd.invparams;
    +0922 % original uncertainty parameter
    +0923 uparam = uncert.params;
    +0924 % new uncertainty parameter from GUI
    +0925 uparam.uncert.Method = uv.uncertMethod;
    +0926 uparam.uncert.Thresh = uv.uncertThresh;
    +0927 uparam.uncert.chi2_range = uv.chi2_range_calc;
    +0928 uparam.uncert.mnorm_range = uv.mnorm_range_calc;
    +0929 uparam.uncert.N = uv.uncertN;
    +0930 uparam.uncert.Max = uv.uncertMax;
    +0931 invstd = estimateUncertainty(invstd.invtype,invstd,iparam,uparam);
    +0932 
    +0933 % save updated inversion results
    +0934 invstd.uncert.params = uparam;
    +0935 data.results.invstd = invstd;
    +0936 
    +0937 % update GUI data
    +0938 % round all chi2 and xn values to 6 digits
    +0939 chi2_all = data.results.invstd.uncert.chi2_all;
    +0940 chi2_all = round(1e6.*chi2_all)./1e6;
    +0941 data.results.invstd.uncert.chi2_all = chi2_all;
    +0942 mnorm_all = data.results.invstd.uncert.mnorm_all;
    +0943 mnorm_all = round(1e6.*mnorm_all)./1e6;
    +0944 data.results.invstd.uncert.mnorm_all = mnorm_all;
    +0945 
    +0946 % create logical mask
    +0947 uv.touse = ones(uv.uncertN,1);
    +0948 
    +0949 % 1.) control
    +0950 uv.chi2_range_calc = [min(chi2_all) max(chi2_all)];
    +0951 uv.mnorm_range_calc = [min(mnorm_all) max(mnorm_all)];
    +0952 
    +0953 % 2.) process
    +0954 uv.chi2_range = uv.chi2_range_calc;
    +0955 uv.mnorm_range = uv.mnorm_range_calc;
    +0956 set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',uv.chi2_range(1,1)));
    +0957 set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',uv.chi2_range(1,2)));
    +0958 set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',uv.mnorm_range(1,1)));
    +0959 set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',uv.mnorm_range(1,2)));
    +0960 
    +0961 % update data
    +0962 data.uv = uv;
    +0963 setappdata(figh,'data',data);
    +0964 
    +0965 % plot all uncertainty data
    +0966 uv_updateInformation(figh);
    +0967 beautifyAxes(figh);
    +0968 end
    +0969 
    +0970 %% subfunction to update the main NUCLEUSinv GUI
    +0971 function uv_onPushUpdate(src,~)
    +0972 figh = ancestor(src,'figure','toplevel');
    +0973 % local GUI data
    +0974 uvgui = getappdata(figh,'gui');
    +0975 uvdata = getappdata(figh,'data');
    +0976 % NUCLEUSinv data
    +0977 gui = getappdata(uvgui.figh_nucleus,'gui');
    +0978 data = getappdata(uvgui.figh_nucleus,'data');
    +0979 INVdata = getappdata(uvgui.figh_nucleus,'INVdata');
    +0980 
    +0981 % get signal id
    +0982 id = data.results.invstd.uncert.params.id;
    +0983 % get data
    +0984 INVdata0 = INVdata{id};
    +0985 
    +0986 % --- update data ---
    +0987 % -- general settings --
    +0988 data.uncert.N = uvdata.uv.uncertN;
    +0989 data.uncert.Method = uvdata.uv.uncertMethod;
    +0990 data.uncert.Thresh = uvdata.uv.uncertThresh;
    +0991 data.uncert.Max = uvdata.uv.uncertMax;
    +0992 
    +0993 % -- check if data was excluded --
    +0994 if sum(uvdata.uv.touse == 0) > 0
    +0995     % if yes, proceed
    +0996     in = uvdata.uv.touse == 1;
    +0997     data.uncert.N = sum(in);
    +0998     uvdata.results.invstd.uncert.params.uncert.N = sum(in);
    +0999     uvdata.results.invstd.uncert.chi2_all = uvdata.results.invstd.uncert.chi2_all(in);
    +1000     uvdata.results.invstd.uncert.mnorm_all = uvdata.results.invstd.uncert.mnorm_all(in);
    +1001     uvdata.results.invstd.uncert.rnorm_all = uvdata.results.invstd.uncert.rnorm_all(in);
    +1002     uvdata.results.invstd.uncert.interp_f = uvdata.results.invstd.uncert.interp_f(in,:);
    +1003     uvdata.results.invstd.uncert.interp_s = uvdata.results.invstd.uncert.interp_s(:,in');
    +1004     uvdata.results.invstd.uncert.interp_E0 = uvdata.results.invstd.uncert.interp_E0(in);
    +1005     uvdata.results.invstd.uncert.E0 = [mean(uvdata.results.invstd.uncert.interp_E0) std(uvdata.results.invstd.uncert.interp_E0)];
    +1006     uvdata.results.invstd.uncert.interp_Tlgm = uvdata.results.invstd.uncert.interp_Tlgm(in);
    +1007     uvdata.results.invstd.uncert.Tlgm = [mean(uvdata.results.invstd.uncert.interp_Tlgm) std(uvdata.results.invstd.uncert.interp_Tlgm)];
    +1008 end
    +1009 
    +1010 % update data structs
    +1011 data.results.invstd.uncert = uvdata.results.invstd.uncert;
    +1012 INVdata0.results.invstd = uvdata.results.invstd;
    +1013 
    +1014 % update INVdata
    +1015 INVdata{id} = INVdata0;
    +1016 % update GUI data
    +1017 setappdata(uvgui.figh_nucleus,'data',data);
    +1018 % update GUI INVdata
    +1019 setappdata(uvgui.figh_nucleus,'INVdata',INVdata);
    +1020 
    +1021 % update relevant GUI elements
    +1022 set(gui.edit_handles.uncert_N,'String',num2str(data.results.invstd.uncert.params.uncert.N))
    +1023 
    +1024 % update plots and INFO fields in main NUCLEUS GUI
    +1025 updatePlotsSignal;
    +1026 updatePlotsDistribution;
    +1027 updateInfo(gui.plots.SignalPanel);
    +1028 
    +1029 end
    +1030 
    +1031 %% subfunction to reset chi2 and model norm bounds
    +1032 function uv_onPushReset(src,~)
    +1033 figh = ancestor(src,'figure','toplevel');
    +1034 gui = getappdata(figh,'gui');
    +1035 data = getappdata(figh,'data');
    +1036 uv = data.uv;
    +1037 invstd = data.results.invstd;
    +1038 uncert = invstd.uncert;
    +1039 
    +1040 switch get(src,'Tag')
    +1041     case 'process'
    +1042         % reset to original values
    +1043         chi2_range  = [min(uncert.chi2_all) max(uncert.chi2_all)];
    +1044         mnorm_range = [min(uncert.mnorm_all) max(uncert.mnorm_all)];
    +1045         % update edit fields
    +1046         set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',chi2_range(1,1)));
    +1047         set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',chi2_range(1,2)));
    +1048         set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',mnorm_range(1,1)));
    +1049         set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',mnorm_range(1,2)));
    +1050         % update data
    +1051         uv.chi2_range = chi2_range;
    +1052         uv.mnorm_range = mnorm_range;
    +1053         data.uv = uv;
    +1054         % update logical mask for plotting
    +1055         data = uv_updateMASK(data);
    +1056     case 'rtd'
    +1057         % reset to original values
    +1058         rtd_range = data.invstd.time;
    +1059         % update edit fields
    +1060         set(gui.edit_handles.rtd_min,'String',num2str(rtd_range(1,1)));
    +1061         set(gui.edit_handles.rtd_max,'String',num2str(rtd_range(1,2)));
    +1062         % update data
    +1063         uv.rtd_range = rtd_range;
    +1064         data.uv = uv;
    +1065 end
    +1066 
    +1067 setappdata(figh,'data',data);
    +1068 % update information
    +1069 uv_updateInformation(figh);
    +1070 end
    +1071 
    +1072 %% subfunction to update the information output
    +1073 function uv_updateInformation(figh)
    +1074 gui = getappdata(figh,'gui');
    +1075 data = getappdata(figh,'data');
    +1076 invstd = data.results.invstd;
    +1077 uncert = invstd.uncert;
    +1078 uv = data.uv;
    +1079 
    +1080 % which models to use
    +1081 in = data.uv.touse == 1;
    +1082 % RTD time vector
    +1083 T = data.results.invstd.T1T2me;
    +1084 % RTD mask
    +1085 mask = T >= uv.rtd_range(1) & T <= uv.rtd_range(2);
    +1086 
    +1087 % kernel matrices for pure (single) E0 estimation
    +1088 iparam = invstd.invparams;
    +1089 switch iparam.T1T2
    +1090     case 'T1'
    +1091         K0 = createKernelMatrix(10*data.results.nmrproc.t(end),T',...
    +1092             iparam.Tb,iparam.Td,'T1',iparam.T1IRfac);
    +1093     case 'T2'
    +1094         K0 = createKernelMatrix(0,T',iparam.Tb,...
    +1095             iparam.Td,'T2',iparam.T1IRfac);
    +1096 end
    +1097 
    +1098 TLGM_tmp = zeros(sum(in),1);
    +1099 E0_tmp = zeros(sum(in),1);
    +1100 c = 0;
    +1101 for i = 1:size(uncert.interp_f,1)
    +1102     if in(i)
    +1103         F = uncert.interp_f(i,:);
    +1104         c = c + 1;
    +1105         TLGM_tmp(c,1) = getTLogMean(T,F,mask);
    +1106         E0_tmp(c,1) = K0(mask')*F(mask')';
    +1107     end
    +1108 end
    +1109 
    +1110 % TLGM
    +1111 uv.Tlgm = [mean(TLGM_tmp) std(TLGM_tmp)];
    +1112 set(gui.edit_handles.TLGM_mean,'String',sprintf('%5.4f',uv.Tlgm(1)));
    +1113 set(gui.edit_handles.TLGM_std,'String',sprintf('%5.4f',2*uv.Tlgm(2)));
    +1114 % aad - mean
    +1115 uv.Tlgm_aad = getAAD(TLGM_tmp,0);
    +1116 set(gui.edit_handles.TLGM_aad,'String',sprintf('%5.4f',2*uv.Tlgm_aad));
    +1117 % aad - median
    +1118 uv.Tlgm_aadmed = [median(TLGM_tmp) getAAD(TLGM_tmp,1)];
    +1119 set(gui.edit_handles.TLGM_med,'String',sprintf('%5.4f',uv.Tlgm_aadmed(1)));
    +1120 set(gui.edit_handles.TLGM_aadmed,'String',sprintf('%5.4f',2*uv.Tlgm_aadmed(2)));
    +1121 % E0
    +1122 uv.E0 = [mean(E0_tmp) std(E0_tmp)];
    +1123 set(gui.edit_handles.E0_mean,'String',sprintf('%5.4f',uv.E0(1)));
    +1124 set(gui.edit_handles.E0_std,'String',sprintf('%5.4f',2*uv.E0(2)));
    +1125 % aad - mean
    +1126 uv.E0_aad = getAAD(E0_tmp,0);
    +1127 set(gui.edit_handles.E0_aad,'String',sprintf('%5.4f',2*uv.E0_aad));
    +1128 % aad - median
    +1129 uv.E0_aadmed = [median(E0_tmp) getAAD(E0_tmp,1)];
    +1130 set(gui.edit_handles.E0_med,'String',sprintf('%5.4f',uv.E0_aadmed(1)));
    +1131 set(gui.edit_handles.E0_aadmed,'String',sprintf('%5.4f',2*uv.E0_aadmed(2)));
    +1132 
    +1133 % update GUI data
    +1134 data.uv = uv;
    +1135 setappdata(figh,'data',data);
    +1136 % update plots
    +1137 uv_updatePlots(figh);
    +1138 
    +1139 end
    +1140 
    +1141 %% subfunction to update all plots
    +1142 function uv_updatePlots(figh)
    +1143 gui = getappdata(figh,'gui');
    +1144 data = getappdata(figh,'data');
    +1145 
    +1146 % clear axes
    +1147 clearAllAxes(figh);
    +1148 hold(gui.axes11,'on');
    +1149 hold(gui.axes12,'on');
    +1150 hold(gui.axes2,'on');
    +1151 hold(gui.axes21,'on');
    +1152 hold(gui.axes22,'on');
    +1153 
    +1154 % get relevant data
    +1155 uv = data.uv;
    +1156 invstd = data.results.invstd;
    +1157 uncert = invstd.uncert;
    +1158 col = gui.myui.colors;
    +1159 
    +1160 % get indices for models to use and not to use
    +1161 in = data.uv.touse == 1;
    +1162 out = data.uv.touse == 0;
    +1163 
    +1164 switch uv.colorstyle
    +1165     case 'none'
    +1166         % default gray
    +1167         lcolors = [0.5 0.5 0.5];
    +1168         tmpchi2 = uncert.chi2_all(in);
    +1169         tmpmnorm = uncert.mnorm_all(in);
    +1170         tmpE0 = uncert.interp_E0(in);
    +1171         tmpTlgm = uncert.interp_Tlgm(in);
    +1172         clims = [0 1];
    +1173     case 'chi2'
    +1174         tmp = uncert.chi2_all(in);
    +1175         [tmpchi2,idx] = sort(tmp);
    +1176         lcolors = tmpchi2;
    +1177         tmpmnorm = uncert.mnorm_all(in);
    +1178         tmpmnorm = tmpmnorm(idx);
    +1179         tmpE0 = uncert.interp_E0(in);
    +1180         tmpE0 = tmpE0(idx);
    +1181         tmpTlgm = uncert.interp_Tlgm(in);
    +1182         tmpTlgm = tmpTlgm(idx);
    +1183         clims = [min(uncert.chi2_all) max(uncert.chi2_all)];
    +1184     case 'xn'
    +1185         tmp = uncert.mnorm_all(in);
    +1186         [tmpmnorm,idx] = sort(tmp);
    +1187         lcolors = tmpmnorm;
    +1188         tmpchi2 = uncert.chi2_all(in);
    +1189         tmpchi2 = tmpchi2(idx);
    +1190         tmpE0 = uncert.interp_E0(in);
    +1191         tmpE0 = tmpE0(idx);
    +1192         tmpTlgm = uncert.interp_Tlgm(in);
    +1193         tmpTlgm = tmpTlgm(idx);
    +1194         clims = [min(uncert.mnorm_all) max(uncert.mnorm_all)];
    +1195 end
    +1196 
    +1197 % --- chi2 vs model norm ---
    +1198 scatter(uncert.chi2_all(out),uncert.mnorm_all(out),[],'red',...
    +1199     'LineWidth',1,'Parent',gui.axes12);
    +1200 scatter(gui.axes12,tmpchi2,tmpmnorm,[],lcolors,...
    +1201     'LineWidth',1);
    +1202 plot(invstd.chi2,invstd.xn,'+','MarkerSize',10,'Color',col.FIT,'Parent',gui.axes12);
    +1203 % axis limits
    +1204 xlims = [min([uncert.chi2_all(in); invstd.chi2]) max([uncert.chi2_all(in); invstd.chi2])];
    +1205 dx = xlims(2)-xlims(1);
    +1206 xlims = [xlims(1)-dx/5 xlims(2)+dx/5];
    +1207 ylims = [min([uncert.mnorm_all(in); invstd.xn]) max([uncert.mnorm_all(in); invstd.xn])];
    +1208 dy = ylims(2)-ylims(1);
    +1209 ylims = [ylims(1)-dy/5 ylims(2)+dy/5];
    +1210 % -- lines indicating TLGM and E0 bounds --
    +1211 line([min(uncert.chi2_all(in)) min(uncert.chi2_all(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],...
    +1212     'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines');
    +1213 line([max(uncert.chi2_all(in)) max(uncert.chi2_all(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],...
    +1214     'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines');
    +1215 line([xlims(1) xlims(2)],[min(uncert.mnorm_all(in)) min(uncert.mnorm_all(in))],'Color',[0.25 0.25 0.25],...
    +1216     'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines');
    +1217 line([xlims(1) xlims(2)],[max(uncert.mnorm_all(in)) max(uncert.mnorm_all(in))],'Color',[0.25 0.25 0.25],...
    +1218     'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines');
    +1219 % axis setings
    +1220 set(gui.axes12,'XScale','lin','XLim',xlims);
    +1221 set(gui.axes12,'YScale','log','YLim',ylims);
    +1222 set(gui.axes12,'CLim',clims);
    +1223 set(get(gui.axes12,'XLabel'),'String','X² (error weighted residuals)');
    +1224 set(get(gui.axes12,'YLabel'),'String','model norm |Lm|_{2}');
    +1225 
    +1226 % --- TLGM vs E0 ---
    +1227 scatter(uncert.interp_Tlgm(out),uncert.interp_E0(out),[],'red',...
    +1228     'LineWidth',1,'DisplayName','runs (out)','Parent',gui.axes11);
    +1229 scatter(tmpTlgm,tmpE0,[],lcolors,...
    +1230     'LineWidth',1,'DisplayName','runs (in)','Parent',gui.axes11);
    +1231 plot(invstd.Tlgm,invstd.E0,'+','MarkerSize',10,'Color',col.FIT,...
    +1232     'DisplayName','init','Parent',gui.axes11);
    +1233 errorbar(uv.Tlgm(1),uv.E0(1),2*uv.E0(2),2*uv.E0(2),2*uv.Tlgm(2),2*uv.Tlgm(2),...
    +1234     'Color',col.BoxPRC,'LineWidth',2,'DisplayName','mean (2*std)','Parent',gui.axes11);
    +1235 errorbar(uv.Tlgm_aadmed(1),uv.E0_aadmed(1),2*uv.E0_aadmed(2),2*uv.E0_aadmed(2),2*uv.Tlgm_aadmed(2),2*uv.Tlgm_aadmed(2),...
    +1236     'Color',col.BoxCPS,'LineWidth',2,'DisplayName','median (2*aad)','Parent',gui.axes11);
    +1237 % axis limits
    +1238 % xlims = [min([uncert.interp_Tlgm; invstd.Tlgm; uv.Tlgm(1)])*0.95 ...
    +1239 %     max([uncert.interp_Tlgm; invstd.Tlgm; uv.Tlgm(1)])*1.05];
    +1240 % ylims = [min([uncert.interp_E0; invstd.E0; uv.E0(1)])*0.95 ...
    +1241 %     max([uncert.interp_E0; invstd.E0; uv.E0(1)])*1.05];
    +1242 xlims = [min([uncert.interp_Tlgm(in); invstd.Tlgm; uv.Tlgm(1)])*0.975 ...
    +1243     max([uncert.interp_Tlgm(in); invstd.Tlgm; uv.Tlgm(1)])*1.025];
    +1244 ylims = [min([uncert.interp_E0(in); invstd.E0; uv.E0(1)])*0.975 ...
    +1245     max([uncert.interp_E0(in); invstd.E0; uv.E0(1)])*1.025];
    +1246 % -- lines indicating TLGM and E0 bounds --
    +1247 line([min(uncert.interp_Tlgm(in)) min(uncert.interp_Tlgm(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],...
    +1248     'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines');
    +1249 line([max(uncert.interp_Tlgm(in)) max(uncert.interp_Tlgm(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],...
    +1250     'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines');
    +1251 line([xlims(1) xlims(2)],[min(uncert.interp_E0(in)) min(uncert.interp_E0(in))],'Color',[0.25 0.25 0.25],...
    +1252     'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines');
    +1253 line([xlims(1) xlims(2)],[max(uncert.interp_E0(in)) max(uncert.interp_E0(in))],'Color',[0.25 0.25 0.25],...
    +1254     'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines');
    +1255 legend(gui.axes11,'Location','NorthEast');
    +1256 % axis settings
    +1257 set(gui.axes11,'XScale','lin','XLim',xlims);
    +1258 set(gui.axes11,'YScale','lin','YLim',ylims);
    +1259 set(gui.axes11,'CLim',clims);
    +1260 set(get(gui.axes11,'XLabel'),'String','TLGM');
    +1261 set(get(gui.axes11,'YLabel'),'String','initial amplitude E0');
    +1262 
    +1263 % --- RTDs ---
    +1264 plotmethod = 1;
    +1265 switch uv.rtd_plotstyle
    +1266     case 'patchmean'
    +1267         plotmethod = 2;
    +1268     case 'patchmedian'
    +1269         plotmethod = 3;
    +1270     otherwise
    +1271         % nothing to do because 'lines' is default
    +1272 end
    +1273 
    +1274 % the 'init' RTD
    +1275 F0 = invstd.T1T2f;
    +1276 % normalize all curves to the median of all E0 values
    +1277 E0norm = uv.E0_aadmed(1);
    +1278 if sum(F0)>0
    +1279     F = (data.invstd.porosity*100).*F0./E0norm;
    +1280     ylims = [0 max(F)*1.05];
    +1281 else
    +1282     ylims = [-1 1];
    +1283 end
    +1284 % the uncertainty runs
    +1285 % only the selected ones within the chi2 and xn bounds
    +1286 FDIST = uncert.interp_f(in,:);
    +1287 % scaling
    +1288 FDIST = (data.invstd.porosity*100).*FDIST./E0norm;
    +1289 
    +1290 % if selected plot lines
    +1291 if plotmethod == 1
    +1292     % find maximum for axis limts
    +1293     f_max = max([ylims(2) max(FDIST(:))]);
    +1294     switch uv.colorstyle
    +1295         case {'chi2','xn'}
    +1296             % get colormap from chi2 vs xn axis
    +1297             cmap = get(gui.axes12,'Colormap');
    +1298             % make vector of values to sort
    +1299             idc = linspace(clims(1),clims(2),size(cmap,1));
    +1300             for i1 = 1:sum(in)
    +1301                 % find closest value (need for coloring)
    +1302                 idc1 = find(abs(idc-tmp(idx(i1)))==min(abs(idc-tmp(idx(i1)))));
    +1303                 % idc1 = abs(idc-tmp(idx(i1)))==min(abs(idc-tmp(idx(i1))));
    +1304                 % plot line with correct color
    +1305                 plot(invstd.T1T2me,FDIST(idx(i1),:),'-','Color',cmap(idc1(1),:),...
    +1306                     'LineWidth',1,'Displayname',num2str(tmp(idx(i1))),'Parent',gui.axes2);
    +1307             end
    +1308             % adjust color limits
    +1309             set(gui.axes2,'CLim',clims);
    +1310         otherwise
    +1311             % need to plot transpose of FDIST because 'x' is a column vector
    +1312             % otherwise plot goes bananas if numel(x) = #models
    +1313             plot(invstd.T1T2me,FDIST','-','Color',[0.5 0.5 0.5],...
    +1314                 'LineWidth',1,'Parent',gui.axes2);
    +1315     end
    +1316 end
    +1317 
    +1318 % if selcted plot patch
    +1319 if plotmethod > 1
    +1320     % what kind of patch is created
    +1321     if plotmethod == 2 % mean +- std
    +1322         mean_f = mean(FDIST);
    +1323         std_f = std(FDIST);
    +1324     else % median +- mad
    +1325         mean_f = median(FDIST);
    +1326         std_f = getAAD(FDIST,1);
    +1327     end
    +1328 
    +1329     % patch lower and upper bounds
    +1330     patch_f_std1 = [mean_f+std_f;mean_f-std_f];
    +1331     patch_f_std2 = [mean_f+2*std_f;mean_f-2*std_f];
    +1332     patch_f_std3 = [mean_f+3*std_f;mean_f-3*std_f];
    +1333     patch_f_std1(patch_f_std1<0) = 0;
    +1334     patch_f_std2(patch_f_std2<0) = 0;
    +1335     patch_f_std3(patch_f_std3<0) = 0;
    +1336     f_max = max([ylims(2) max(patch_f_std1) max(patch_f_std2) max(patch_f_std3)]);
    +1337 
    +1338     % draw all three patches on top of each other
    +1339     verts = [invstd.T1T2me patch_f_std3(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std3(1,:)')];
    +1340     faces = 1:1:size(verts,1);
    +1341     patch('Faces',faces,'Vertices',verts,'FaceColor',[0.6 0.6 0.6],...
    +1342         'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2);
    +1343     verts = [invstd.T1T2me patch_f_std2(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std2(1,:)')];
    +1344     faces = 1:1:size(verts,1);
    +1345     patch('Faces',faces,'Vertices',verts,'FaceColor',[0.4 0.4 0.4],...
    +1346         'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2);
    +1347     verts = [invstd.T1T2me patch_f_std1(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std1(1,:)')];
    +1348     faces = 1:1:size(verts,1);
    +1349     patch('Faces',faces,'Vertices',verts,'FaceColor',[0.2 0.2 0.2],...
    +1350         'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2);
    +1351 end
    +1352 
    +1353 % adjust y-limits
    +1354 ylims(2) = max([ylims(2) max(f_max)*1.05]);
    +1355 
    +1356 % plot original solution
    +1357 plot(invstd.T1T2me,F,'-','Color',col.FIT,'Parent',gui.axes2);
    +1358 
    +1359 % -- RTD bounds --
    +1360 uv = data.uv;
    +1361 line([uv.rtd_range(1) uv.rtd_range(1)],[0 ylims(2)],'Color',[0.25 0.25 0.25],...
    +1362     'LineStyle','-.','LineWidth',2,'Parent',gui.axes2,'Tag','infolines');
    +1363 line([uv.rtd_range(2) uv.rtd_range(2)],[0 ylims(2)],'Color',[0.25 0.25 0.25],...
    +1364     'LineStyle','-.','LineWidth',2,'Parent',gui.axes2,'Tag','infolines');
    +1365 
    +1366 % axes properties:
    +1367 ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me)));
    +1368 set(gui.axes2,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks);
    +1369 set(gui.axes2,'YScale','lin','YLim',ylims);
    +1370 set(get(gui.axes2,'XLabel'),'String','relaxation time');
    +1371 set(get(gui.axes2,'YLabel'),'String','amplitude');
    +1372 grid(gui.axes2,'on');
    +1373 
    +1374 % --- Histograms ---
    +1375 hasStatBox = strcmp(data.info.stat,'off');
    +1376 % get the kernel density estimate (more precise compared to a simple histogram)
    +1377 if hasStatBox
    +1378     % Statistics ToolBox
    +1379     [f1,xi1] = ksdensity(uncert.interp_E0(in));
    +1380     [f2,xi2] = ksdensity(uncert.interp_Tlgm(in));
    +1381 else
    +1382     % FEX contribution
    +1383     [~,f1,xi1] = kde(uncert.interp_E0(in),numel(uncert.interp_E0(in)));
    +1384     [~,f2,xi2] = kde(uncert.interp_Tlgm(in),numel(uncert.interp_Tlgm(in)));
    +1385 end
    +1386 
    +1387 % plot the KDEs
    +1388 plot(xi1,f1,'Color',[0.5 0.5 0.5],'DisplayName','KDE','Parent',gui.axes21);
    +1389 plot(xi2,f2,'Color',[0.5 0.5 0.5],'DisplayName','KDE','Parent',gui.axes22);
    +1390 
    +1391 % "init" E0
    +1392 line([invstd.E0 invstd.E0],[0 max(f1)],'Color',col.FIT,...
    +1393     'LineStyle',':','LineWidth',2,'Parent',gui.axes21,'DisplayName','init',...
    +1394     'Tag','infolines');
    +1395 % "init" TLGM
    +1396 line([invstd.Tlgm invstd.Tlgm],[0 max(f2)],'Color',col.FIT,...
    +1397     'LineStyle',':','LineWidth',2,'Parent',gui.axes22,'DisplayName','init',...
    +1398     'Tag','infolines');
    +1399 
    +1400 % mean E0
    +1401 line([uv.E0(1) uv.E0(1)],[0 max(f1)],'Color',col.BoxPRC,...
    +1402     'LineStyle','-','LineWidth',2,'Parent',gui.axes21,'DisplayName','mean');
    +1403 line([uv.E0(1)+2*uv.E0(2) uv.E0(1)+2*uv.E0(2)],[0 max(f1)],'Color',col.BoxPRC,...
    +1404     'LineStyle','--','LineWidth',1,'Parent',gui.axes21,'DisplayName','2*std');
    +1405 line([uv.E0(1)-2*uv.E0(2) uv.E0(1)-2*uv.E0(2)],[0 max(f1)],'Color',col.BoxPRC,...
    +1406     'LineStyle','--','LineWidth',1,'Parent',gui.axes21,'DisplayName','2*std',...
    +1407     'HandleVisibility','off','Tag','infolines');
    +1408 
    +1409 % mean TLGM
    +1410 line([uv.Tlgm(1) uv.Tlgm(1)],[0 max(f2)],'Color',col.BoxPRC,...
    +1411     'LineStyle','-','LineWidth',2,'Parent',gui.axes22,'DisplayName','mean');
    +1412 line([uv.Tlgm(1)+2*uv.Tlgm(2) uv.Tlgm(1)+2*uv.Tlgm(2)],[0 max(f2)],'Color',col.BoxPRC,...
    +1413     'LineStyle','--','LineWidth',1,'Parent',gui.axes22,'DisplayName','2*std');
    +1414 line([uv.Tlgm(1)-2*uv.Tlgm(2) uv.Tlgm(1)-2*uv.Tlgm(2)],[0 max(f2)],'Color',col.BoxPRC,...
    +1415     'LineStyle','--','LineWidth',1,'Parent',gui.axes22,'DisplayName','2*std',...
    +1416     'HandleVisibility','off','Tag','infolines');
    +1417 
    +1418 % median E0
    +1419 line([uv.E0_aadmed(1) uv.E0_aadmed(1)],[0 max(f1)],'Color',col.BoxCPS,...
    +1420     'LineStyle','-','LineWidth',2,'Parent',gui.axes21,'DisplayName','median');
    +1421 line([uv.E0_aadmed(1)+2*uv.E0_aadmed(2) uv.E0_aadmed(1)+2*uv.E0_aadmed(2)],...
    +1422     [0 max(f1)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,...
    +1423     'Parent',gui.axes21,'DisplayName','2*aad');
    +1424 line([uv.E0_aadmed(1)-2*uv.E0_aadmed(2) uv.E0_aadmed(1)-2*uv.E0_aadmed(2)],...
    +1425     [0 max(f1)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,...
    +1426     'Parent',gui.axes21,'DisplayName','2*aad','HandleVisibility','off',...
    +1427     'Tag','infolines');
    +1428 
    +1429 % median TLGM
    +1430 line([uv.Tlgm_aadmed(1) uv.Tlgm_aadmed(1)],[0 max(f2)],'Color',col.BoxCPS,...
    +1431     'LineStyle','-','LineWidth',2,'Parent',gui.axes22,'DisplayName','median');
    +1432 line([uv.Tlgm_aadmed(1)+2*uv.Tlgm_aadmed(2) uv.Tlgm_aadmed(1)+2*uv.Tlgm_aadmed(2)],...
    +1433     [0 max(f2)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,...
    +1434     'Parent',gui.axes22,'DisplayName','2*aad');
    +1435 line([uv.Tlgm_aadmed(1)-2*uv.Tlgm_aadmed(2) uv.Tlgm_aadmed(1)-2*uv.Tlgm_aadmed(2)],...
    +1436     [0 max(f2)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,...
    +1437     'Parent',gui.axes22,'DisplayName','2*aad','HandleVisibility','off',...
    +1438     'Tag','infolines');
    +1439 
    +1440 legend(gui.axes22,'Location','NorthWest');
    +1441 
    +1442 % axes properties
    +1443 set(get(gui.axes21,'XLabel'),'String','E0');
    +1444 set(get(gui.axes21,'YLabel'),'String','kernel denisty estimate');
    +1445 set(get(gui.axes22,'XLabel'),'String','TLGM');
    +1446 set(get(gui.axes22,'YLabel'),'String','kernel density estimate');
    +1447 
    +1448 % hold off all axes
    +1449 hold(gui.axes11,'off');
    +1450 hold(gui.axes12,'off');
    +1451 hold(gui.axes2,'off');
    +1452 hold(gui.axes21,'off');
    +1453 hold(gui.axes22,'off');
    +1454 end
    +1455 
    +1456 %% close function
    +1457 function uv_closeme(src,~)
    +1458 figh = ancestor(src,'figure','toplevel');
    +1459 % try to close the sub GUI in a clean manner
    +1460 try
    +1461     % NOTE: maybe needed at some later point
    +1462     %     gui = getappdata(figh,'gui');
    +1463     %     data = getappdata(gui.figh_nucleus,'data');
    +1464     %     % update NUCLEUSinv
    +1465     %     setappdata(gui.figh_nucleus,'data',data);
    +1466     delete(figh);
    +1467 catch
    +1468     % if this is not working: just close it
    +1469     delete(figh);
    +1470 end
    +1471 
    +1472 end
    +1473 
    +1474 %------------- END OF CODE --------------
    +1475 
    +1476 %% License:
    +1477 % MIT License
    +1478 %
    +1479 % Copyright (c) 2024 Thomas Hiller
    +1480 %
    +1481 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +1482 % of this software and associated documentation files (the "Software"), to deal
    +1483 % in the Software without restriction, including without limitation the rights
    +1484 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +1485 % copies of the Software, and to permit persons to whom the Software is
    +1486 % furnished to do so, subject to the following conditions:
    +1487 %
    +1488 % The above copyright notice and this permission notice shall be included in all
    +1489 % copies or substantial portions of the Software.
    +1490 %
    +1491 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +1492 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +1493 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +1494 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +1495 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +1496 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +1497 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/interface/beautifyAxes.html b/doc/nucleus/functions/interface/beautifyAxes.html index 86d5663..2f7745f 100644 --- a/doc/nucleus/functions/interface/beautifyAxes.html +++ b/doc/nucleus/functions/interface/beautifyAxes.html @@ -61,7 +61,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • NUCLEUSinv_createPanelPlots creates graphics panel
  • NUCLEUSmod_createPanelPlots creates graphics panel
  • updatePlotsJointInversion plots the joint-inversion results in NUCLEUSinv
  • updatePlotsLcurve plots the results of the L-curve calculation
  • updatePlotsNMR plots the forward modeled NMR data in NUCLEUSmod
  • updatePlotsPSD plots the pore size distribution in NUCLEUSmod
  • updatePlotsSignal plots the raw and processed NMR signals in NUCLEUSinv
  • +
  • NUCLEUSinv_createPanelPlots creates graphics panel
  • NUCLEUSmod_createPanelPlots creates graphics panel
  • UncertView is an extra subGUI to show results of the uncertainty
  • updatePlotsJointInversion plots the joint-inversion results in NUCLEUSinv
  • updatePlotsLcurve plots the results of the L-curve calculation
  • updatePlotsNMR plots the forward modeled NMR data in NUCLEUSmod
  • updatePlotsPSD plots the pore size distribution in NUCLEUSmod
  • updatePlotsSignal plots the raw and processed NMR signals in NUCLEUSinv
  • diff --git a/doc/nucleus/functions/interface/clearAllAxes.html b/doc/nucleus/functions/interface/clearAllAxes.html index 72ebb9f..85a6dda 100644 --- a/doc/nucleus/functions/interface/clearAllAxes.html +++ b/doc/nucleus/functions/interface/clearAllAxes.html @@ -61,7 +61,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=clearSingleAxis clears an individual axis This function is called by: +
  • ConductView is an extra subGUI to visualize hydraulic conductivity
  • PhaseView is an extra subGUI to visualize the phase of a T2 signal
  • UncertView is an extra subGUI to show results of the uncertainty
  • calculateGeometry calculates the shape dependent geometry parameters
  • clearInversion removes inversion results from the internal data structure
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importMOD2INV
  • importNMRdata is the general import routine for NMR data
  • removeSignalFromList removes the chosen NMR signal from the GUI
  • runInversionStd controls the standard inversion process to invert a
  • showFitStatistics shows an extra fit statistics figure (for T2 data)
  • diff --git a/doc/nucleus/functions/interface/clearInversion.html b/doc/nucleus/functions/interface/clearInversion.html index 7921d54..9e212c4 100644 --- a/doc/nucleus/functions/interface/clearInversion.html +++ b/doc/nucleus/functions/interface/clearInversion.html @@ -139,81 +139,85 @@

    SOURCE CODE ^% clear inversion axes 0066 clearSingleAxis(gui.axes_handles.rtd); 0067 clearSingleAxis(gui.axes_handles.psd); -0068 % clear the info fields -0069 set(gui.listbox_handles.info_signal,'String',' '); -0070 set(gui.listbox_handles.info_dist,'String',' '); -0071 set(gui.listbox_handles.info_cps,'String',' '); -0072 -0073 else -0074 helpdlg('Cannot CLEAR inversion because there is no inversion set!',... -0075 'clearInversion: Run inversion first.'); -0076 end -0077 -0078 else % clear all inversions +0068 % switch-off uncert context menu +0069 set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); +0070 % clear the info fields +0071 set(gui.listbox_handles.info_signal,'String',' '); +0072 set(gui.listbox_handles.info_dist,'String',' '); +0073 set(gui.listbox_handles.info_cps,'String',' '); +0074 +0075 else +0076 helpdlg('Cannot CLEAR inversion because there is no inversion set!',... +0077 'clearInversion: Run inversion first.'); +0078 end 0079 -0080 % if all inversions are deleted also all axes can be cleared -0081 clearAllAxes(fig); -0082 -0083 % check if there is at least one inversion set -0084 foundINV = checkIfInversionExists(INVdata); -0085 -0086 if foundINV -0087 INVdata = cell(length(data.import.NMR.filesShort),1); -0088 -0089 % remove temporary data fields -0090 data = removeInversionFields(data); -0091 % remove the green color -0092 strL = data.import.NMR.filesShort'; -0093 set(gui.listbox_handles.signal,'String',strL); -0094 -0095 setappdata(fig,'data',data); -0096 setappdata(fig,'INVdata',INVdata); -0097 % update interface -0098 NUCLEUSinv_updateInterface; -0099 % update the data plot axes -0100 updatePlotsSignal; -0101 -0102 % clear inversion axes -0103 clearSingleAxis(gui.axes_handles.rtd); -0104 clearSingleAxis(gui.axes_handles.psd); -0105 % clear the info fields -0106 set(gui.listbox_handles.info_signal,'String',' '); -0107 set(gui.listbox_handles.info_dist,'String',' '); -0108 set(gui.listbox_handles.info_cps,'String',' '); -0109 -0110 else -0111 helpdlg('Cannot CLEAR inversions because there is no inversion set!',... -0112 'removeInversionSetAll: Run inversion first.'); -0113 end -0114 -0115 end -0116 -0117 end -0118 -0119 %------------- END OF CODE -------------- +0080 else % clear all inversions +0081 +0082 % if all inversions are deleted also all axes can be cleared +0083 clearAllAxes(fig); +0084 +0085 % check if there is at least one inversion set +0086 foundINV = checkIfInversionExists(INVdata); +0087 +0088 if foundINV +0089 INVdata = cell(length(data.import.NMR.filesShort),1); +0090 +0091 % remove temporary data fields +0092 data = removeInversionFields(data); +0093 % remove the green color +0094 strL = data.import.NMR.filesShort'; +0095 set(gui.listbox_handles.signal,'String',strL); +0096 +0097 setappdata(fig,'data',data); +0098 setappdata(fig,'INVdata',INVdata); +0099 % update interface +0100 NUCLEUSinv_updateInterface; +0101 % update the data plot axes +0102 updatePlotsSignal; +0103 +0104 % clear inversion axes +0105 clearSingleAxis(gui.axes_handles.rtd); +0106 clearSingleAxis(gui.axes_handles.psd); +0107 % switch-off uncert context menu +0108 set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); +0109 % clear the info fields +0110 set(gui.listbox_handles.info_signal,'String',' '); +0111 set(gui.listbox_handles.info_dist,'String',' '); +0112 set(gui.listbox_handles.info_cps,'String',' '); +0113 +0114 else +0115 helpdlg('Cannot CLEAR inversions because there is no inversion set!',... +0116 'removeInversionSetAll: Run inversion first.'); +0117 end +0118 +0119 end 0120 -0121 %% License: -0122 % MIT License -0123 % -0124 % Copyright (c) 2018 Thomas Hiller -0125 % -0126 % Permission is hereby granted, free of charge, to any person obtaining a copy -0127 % of this software and associated documentation files (the "Software"), to deal -0128 % in the Software without restriction, including without limitation the rights -0129 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0130 % copies of the Software, and to permit persons to whom the Software is -0131 % furnished to do so, subject to the following conditions: -0132 % -0133 % The above copyright notice and this permission notice shall be included in all -0134 % copies or substantial portions of the Software. -0135 % -0136 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0137 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0138 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0139 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0140 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0141 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0142 % SOFTWARE. +0121 end +0122 +0123 %------------- END OF CODE -------------- +0124 +0125 %% License: +0126 % MIT License +0127 % +0128 % Copyright (c) 2018 Thomas Hiller +0129 % +0130 % Permission is hereby granted, free of charge, to any person obtaining a copy +0131 % of this software and associated documentation files (the "Software"), to deal +0132 % in the Software without restriction, including without limitation the rights +0133 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0134 % copies of the Software, and to permit persons to whom the Software is +0135 % furnished to do so, subject to the following conditions: +0136 % +0137 % The above copyright notice and this permission notice shall be included in all +0138 % copies or substantial portions of the Software. +0139 % +0140 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0141 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0142 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0143 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0144 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0145 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0146 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/clearSingleAxis.html b/doc/nucleus/functions/interface/clearSingleAxis.html index 97ff03f..0c9306c 100644 --- a/doc/nucleus/functions/interface/clearSingleAxis.html +++ b/doc/nucleus/functions/interface/clearSingleAxis.html @@ -112,35 +112,38 @@

    SOURCE CODE ^'Tag','fits'); 0044 if ~isempty(ph); set(ph,'HandleVisibility','on'); end 0045 -0046 %% clear the axis itself -0047 cla(axh); +0046 ph = findall(axh,'Tag','infolines'); +0047 if ~isempty(ph); set(ph,'HandleVisibility','on'); end 0048 -0049 end -0050 -0051 %------------- END OF CODE -------------- -0052 -0053 %% License: -0054 % MIT License -0055 % -0056 % Copyright (c) 2018 Thomas Hiller -0057 % -0058 % Permission is hereby granted, free of charge, to any person obtaining a copy -0059 % of this software and associated documentation files (the "Software"), to deal -0060 % in the Software without restriction, including without limitation the rights -0061 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0062 % copies of the Software, and to permit persons to whom the Software is -0063 % furnished to do so, subject to the following conditions: -0064 % -0065 % The above copyright notice and this permission notice shall be included in all -0066 % copies or substantial portions of the Software. +0049 %% clear the axis itself +0050 cla(axh); +0051 +0052 end +0053 +0054 %------------- END OF CODE -------------- +0055 +0056 %% License: +0057 % MIT License +0058 % +0059 % Copyright (c) 2018 Thomas Hiller +0060 % +0061 % Permission is hereby granted, free of charge, to any person obtaining a copy +0062 % of this software and associated documentation files (the "Software"), to deal +0063 % in the Software without restriction, including without limitation the rights +0064 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0065 % copies of the Software, and to permit persons to whom the Software is +0066 % furnished to do so, subject to the following conditions: 0067 % -0068 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0069 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0070 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0071 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0072 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0073 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0074 % SOFTWARE. +0068 % The above copyright notice and this permission notice shall be included in all +0069 % copies or substantial portions of the Software. +0070 % +0071 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0072 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0073 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0074 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0075 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0076 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0077 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/enableGUIelements.html b/doc/nucleus/functions/interface/enableGUIelements.html index 0583b02..e8d60ab 100644 --- a/doc/nucleus/functions/interface/enableGUIelements.html +++ b/doc/nucleus/functions/interface/enableGUIelements.html @@ -110,106 +110,100 @@

    SOURCE CODE ^case {'ASCII','EXCEL','MOD'} 0041 % process panel 0042 data.process.end = 0; -0043 data.process.gatetype = 'raw'; -0044 data.process.norm = 0; -0045 data.process.timescale = 's'; -0046 data.process.timefac = 1; -0047 % invstd panel -0048 data.invstd.invtype = 'NNLS'; -0049 data.invstd.regtype = 'manual'; -0050 data.invstd.lambda = 1; -0051 data.invstd.Lorder = 1; -0052 set(gui.push_handles.invstd_run,'Enable','on'); -0053 case 'NMR' -0054 % process panel -0055 data.process.end = 0; -0056 switch data.import.fileformat -0057 case {'dart','field','helios'} -0058 data.process.gatetype = 'raw'; -0059 otherwise -0060 data.process.gatetype = 'log'; -0061 end -0062 data.process.norm = 0; -0063 data.process.timescale = 's'; -0064 data.process.timefac = 1; -0065 % invstd panel -0066 data.invstd.invtype = 'NNLS'; -0067 data.invstd.regtype = 'manual'; -0068 data.invstd.lambda = 1; -0069 data.invstd.Lorder = 1; -0070 set(gui.push_handles.invstd_run,'Enable','on'); -0071 end -0072 -0073 % petro panel -0074 data.param.calibVol = 1; -0075 data.param.calibAmp = 1; -0076 % RAW plot panel -0077 data.param.sampVol = 1; -0078 data.invstd.porosity = 1; -0079 data.calib.vol = data.param.calibVol; -0080 data.calib.amp = data.param.calibAmp; -0081 data.calib.fac = 1; -0082 data.calib.name = ''; -0083 -0084 % PROC plot panel -0085 set(gui.cm_handles.axes_proc_xaxis,'Enable','on'); -0086 set(gui.cm_handles.axes_proc_yaxis,'Enable','on'); -0087 % RAW plot panel -0088 set(gui.cm_handles.axes_raw_xaxis,'Enable','on'); -0089 set(gui.cm_handles.axes_raw_yaxis,'Enable','on'); -0090 % ALL plot panel -0091 set(gui.cm_handles.axes_all_xaxis,'Enable','on'); -0092 set(gui.cm_handles.axes_all_yaxis,'Enable','on'); -0093 % RTD plot panel -0094 set(gui.cm_handles.axes_rtd_view,'Enable','on'); -0095 % PSD plot panel -0096 set(gui.cm_handles.axes_psd_view,'Enable','on'); -0097 % PSDJ plot panel -0098 set(gui.cm_handles.axes_psdj_view,'Enable','on'); -0099 % INFO fields -0100 set(gui.listbox_handles.info_signal,'String',' '); -0101 set(gui.listbox_handles.info_dist,'String',' '); -0102 set(gui.listbox_handles.info_cps,'String',' '); -0103 -0104 % update GUI data -0105 setappdata(fig,'data',data); -0106 setappdata(fig,'gui',gui); -0107 -0108 switch data.info.ExpertMode -0109 case 'on' -0110 set(gui.menu.extra_expert,'Checked','off'); -0111 case 'off' -0112 set(gui.menu.extra_expert,'Checked','on'); -0113 end -0114 onMenuExpert(gui.menu.extra_expert); -0115 -0116 -0117 end -0118 -0119 %------------- END OF CODE -------------- -0120 -0121 %% License: -0122 % MIT License -0123 % -0124 % Copyright (c) 2018 Thomas Hiller -0125 % -0126 % Permission is hereby granted, free of charge, to any person obtaining a copy -0127 % of this software and associated documentation files (the "Software"), to deal -0128 % in the Software without restriction, including without limitation the rights -0129 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0130 % copies of the Software, and to permit persons to whom the Software is -0131 % furnished to do so, subject to the following conditions: -0132 % -0133 % The above copyright notice and this permission notice shall be included in all -0134 % copies or substantial portions of the Software. -0135 % -0136 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0137 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0138 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0139 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0140 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0141 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0142 % SOFTWARE. +0043 data.process.gatetype = 'raw'; +0044 case 'NMR' +0045 % process panel +0046 data.process.end = 0; +0047 switch data.import.fileformat +0048 case {'dart','field','helios'} +0049 data.process.gatetype = 'raw'; +0050 otherwise +0051 data.process.gatetype = 'log'; +0052 end +0053 end +0054 +0055 % process panel - contd +0056 data.process.norm = 0; +0057 data.process.timescale = 's'; +0058 data.process.timefac = 1; +0059 +0060 % invstd panel +0061 data.invstd.invtype = 'NNLS'; +0062 data.invstd.regtype = 'manual'; +0063 data.invstd.lambda = 1; +0064 data.invstd.Lorder = 1; +0065 set(gui.push_handles.invstd_run,'Enable','on'); +0066 +0067 % petro panel +0068 data.param.calibVol = 1; +0069 data.param.calibAmp = 1; +0070 % RAW plot panel +0071 data.param.sampVol = 1; +0072 data.invstd.porosity = 1; +0073 data.calib.vol = data.param.calibVol; +0074 data.calib.amp = data.param.calibAmp; +0075 data.calib.fac = 1; +0076 data.calib.name = ''; +0077 +0078 % PROC plot panel +0079 set(gui.cm_handles.axes_proc_xaxis,'Enable','on'); +0080 set(gui.cm_handles.axes_proc_yaxis,'Enable','on'); +0081 % RAW plot panel +0082 set(gui.cm_handles.axes_raw_xaxis,'Enable','on'); +0083 set(gui.cm_handles.axes_raw_yaxis,'Enable','on'); +0084 % ALL plot panel +0085 set(gui.cm_handles.axes_all_xaxis,'Enable','on'); +0086 set(gui.cm_handles.axes_all_yaxis,'Enable','on'); +0087 % RTD plot panel +0088 set(gui.cm_handles.axes_rtd_view,'Enable','on'); +0089 % PSD plot panel +0090 set(gui.cm_handles.axes_psd_view,'Enable','on'); +0091 % PSDJ plot panel +0092 set(gui.cm_handles.axes_psdj_view,'Enable','on'); +0093 % INFO fields +0094 set(gui.listbox_handles.info_signal,'String',' '); +0095 set(gui.listbox_handles.info_dist,'String',' '); +0096 set(gui.listbox_handles.info_cps,'String',' '); +0097 +0098 % update GUI data +0099 setappdata(fig,'data',data); +0100 setappdata(fig,'gui',gui); +0101 +0102 switch data.info.ExpertMode +0103 case 'on' +0104 set(gui.menu.extra_expert,'Checked','off'); +0105 case 'off' +0106 set(gui.menu.extra_expert,'Checked','on'); +0107 end +0108 onMenuExpert(gui.menu.extra_expert); +0109 +0110 +0111 end +0112 +0113 %------------- END OF CODE -------------- +0114 +0115 %% License: +0116 % MIT License +0117 % +0118 % Copyright (c) 2018 Thomas Hiller +0119 % +0120 % Permission is hereby granted, free of charge, to any person obtaining a copy +0121 % of this software and associated documentation files (the "Software"), to deal +0122 % in the Software without restriction, including without limitation the rights +0123 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0124 % copies of the Software, and to permit persons to whom the Software is +0125 % furnished to do so, subject to the following conditions: +0126 % +0127 % The above copyright notice and this permission notice shall be included in all +0128 % copies or substantial portions of the Software. +0129 % +0130 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0131 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0132 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0133 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0134 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0135 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0136 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/getVersionNoFromString.html b/doc/nucleus/functions/interface/getVersionNoFromString.html index 0b599b5..aeaea69 100644 --- a/doc/nucleus/functions/interface/getVersionNoFromString.html +++ b/doc/nucleus/functions/interface/getVersionNoFromString.html @@ -98,37 +98,38 @@

    SOURCE CODE ^%------------- BEGIN CODE -------------- 0031 -0032 % remove points -0033 version_str = strrep(version_str,'.',''); -0034 % convert string to numeric value -0035 version = str2double(version_str); -0036 -0037 end -0038 -0039 %------------- END OF CODE -------------- -0040 -0041 %% License: -0042 % MIT License -0043 % -0044 % Copyright (c) 2019 Thomas Hiller -0045 % -0046 % Permission is hereby granted, free of charge, to any person obtaining a copy -0047 % of this software and associated documentation files (the "Software"), to deal -0048 % in the Software without restriction, including without limitation the rights -0049 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0050 % copies of the Software, and to permit persons to whom the Software is -0051 % furnished to do so, subject to the following conditions: -0052 % -0053 % The above copyright notice and this permission notice shall be included in all -0054 % copies or substantial portions of the Software. -0055 % -0056 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0057 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0058 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0059 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0060 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0061 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0062 % SOFTWARE. +0032 % find first point +0033 idx = strfind(version_str,'.'); +0034 version_str = version_str(idx(1)+1:end); +0035 % convert string to numeric value +0036 version = str2double(version_str)*100; +0037 +0038 end +0039 +0040 %------------- END OF CODE -------------- +0041 +0042 %% License: +0043 % MIT License +0044 % +0045 % Copyright (c) 2019 Thomas Hiller +0046 % +0047 % Permission is hereby granted, free of charge, to any person obtaining a copy +0048 % of this software and associated documentation files (the "Software"), to deal +0049 % in the Software without restriction, including without limitation the rights +0050 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0051 % copies of the Software, and to permit persons to whom the Software is +0052 % furnished to do so, subject to the following conditions: +0053 % +0054 % The above copyright notice and this permission notice shall be included in all +0055 % copies or substantial portions of the Software. +0056 % +0057 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0058 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0059 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0060 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0061 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0062 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0063 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/importASCIIdata.html b/doc/nucleus/functions/interface/importASCIIdata.html index 40207fd..2b9e466 100644 --- a/doc/nucleus/functions/interface/importASCIIdata.html +++ b/doc/nucleus/functions/interface/importASCIIdata.html @@ -113,7 +113,7 @@

    SOURCE CODE ^'Label'); 0042 0043 % get file name -0044 ASCIIpath = -1; +0044 ASCIIpath = -1; %#ok<*NASGU> 0045 ASCIIfile = -1; 0046 if isfield(data.import,'path') 0047 [ASCIIfile,ASCIIpath] = uigetfile(fullfile(data.import.path,'*.*'),... @@ -194,87 +194,129 @@

    SOURCE CODE ^% the NMR data 0123 data.import.NMR.data{c}.flag = T1T2; 0124 data.import.NMR.data{c}.time = tmp_data(:,1); -0125 if size(tmp_data,2)>2 -0126 tmp_signal = complex(tmp_data(:,2),tmp_data(:,3)); -0127 [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); -0128 data.import.NMR.data{c}.signal = tmp_signal; -0129 data.import.NMR.data{c}.phase = tmp_phase; -0130 else -0131 data.import.NMR.data{c}.signal = tmp_data(:,2); -0132 data.import.NMR.data{c}.phase = 0; -0133 -0134 param.T1IRfac = 1; -0135 param.noise = 0; -0136 param.optim = 'off'; -0137 invstd = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... -0138 'T2',param,5); -0139 data.import.NMR.data{c}.noise = invstd.rms; -0140 end -0141 data.import.NMR.data{c}.T1IRfac = 1; -0142 data.import.NMR.data{c}.raw.time = data.import.NMR.data{c}.time; -0143 data.import.NMR.data{c}.raw.signal = data.import.NMR.data{c}.signal; -0144 data.import.NMR.data{c}.phase = 0; -0145 -0146 % dummy parameter data -0147 data.import.NMR.para{c} = 0; -0148 end -0149 end -0150 -0151 % save file names -0152 data.import.NMR.files = fnames; -0153 data.import.NMR.filesShort = shownames; -0154 -0155 % update the ini-file -0156 gui.myui.inidata.importpath = data.import.path; -0157 gui = makeINIfile(gui,'update'); -0158 -0159 % update the list of file names -0160 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); -0161 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); -0162 -0163 % create a global INVdata struct for every file in the list -0164 if isstruct(getappdata(fig,'INVdata')) -0165 setappdata(fig,'INVdata',[]); -0166 end -0167 INVdata = cell(length(data.import.NMR.filesShort),1); -0168 setappdata(fig,'INVdata',INVdata); -0169 -0170 % clear all axes -0171 clearAllAxes(gui.figh); -0172 -0173 % update GUI data and interface -0174 setappdata(fig,'data',data); -0175 setappdata(fig,'gui',gui); -0176 enableGUIelements('ASCII'); -0177 NUCLEUSinv_updateInterface; -0178 end -0179 -0180 end -0181 -0182 %------------- END OF CODE -------------- -0183 -0184 %% License: -0185 % MIT License -0186 % -0187 % Copyright (c) 2018 Thomas Hiller -0188 % -0189 % Permission is hereby granted, free of charge, to any person obtaining a copy -0190 % of this software and associated documentation files (the "Software"), to deal -0191 % in the Software without restriction, including without limitation the rights -0192 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0193 % copies of the Software, and to permit persons to whom the Software is -0194 % furnished to do so, subject to the following conditions: -0195 % -0196 % The above copyright notice and this permission notice shall be included in all -0197 % copies or substantial portions of the Software. -0198 % -0199 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0200 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0201 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0202 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0203 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0204 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0205 % SOFTWARE. +0125 % switch between T1 and T2 data +0126 switch T1T2 +0127 case 'T1' +0128 data.import.NMR.data{c}.signal = tmp_data(:,2); +0129 data.import.NMR.data{c}.phase = 0; +0130 +0131 % try saturation recovery first +0132 param.T1IRfac = 1; +0133 param.noise = 0; +0134 param.optim = 'off'; +0135 param.Tfixed_bool = [0 0 0 0 0]; +0136 param.Tfixed_val = [0 0 0 0 0]; +0137 invstd1 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... +0138 data.import.NMR.data{c}.flag,param,5); +0139 +0140 % now inversion recovery +0141 param.T1IRfac = 2; +0142 param.noise = 0; +0143 param.optim = 'off'; +0144 param.Tfixed_bool = [0 0 0 0 0]; +0145 param.Tfixed_val = [0 0 0 0 0]; +0146 invstd2 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... +0147 data.import.NMR.data{c}.flag,param,5); +0148 +0149 % compare the residuals +0150 if invstd1.resnorm < invstd2.resnorm +0151 % data is possibly saturation recovery +0152 invstd = invstd1; +0153 T1IRfac = 1; +0154 else +0155 % data is possibly inversion recovery +0156 invstd = invstd2; +0157 T1IRfac = 2; +0158 end +0159 % save the "dummy" RMS as noise estimate +0160 data.import.NMR.data{c}.noise = invstd.rms; +0161 case 'T2' +0162 T1IRfac = 1; +0163 if size(tmp_data,2)>2 +0164 tmp_signal = complex(tmp_data(:,2),tmp_data(:,3)); +0165 [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); +0166 data.import.NMR.data{c}.signal = tmp_signal; +0167 data.import.NMR.data{c}.phase = tmp_phase; +0168 else +0169 data.import.NMR.data{c}.signal = tmp_data(:,2); +0170 data.import.NMR.data{c}.phase = 0; +0171 +0172 % noise estimate +0173 param.T1IRfac = 1; +0174 param.noise = 0; +0175 param.optim = 'off'; +0176 param.Tfixed_bool = [0 0 0 0 0]; +0177 param.Tfixed_val = [0 0 0 0 0]; +0178 invstd = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... +0179 data.import.NMR.data{c}.flag,param,5); +0180 % save the "dummy" RMS as noise estimate +0181 data.import.NMR.data{c}.noise = invstd.rms; +0182 end +0183 end +0184 data.import.NMR.data{c}.T1IRfac = T1IRfac; +0185 data.import.NMR.data{c}.raw.time = data.import.NMR.data{c}.time; +0186 data.import.NMR.data{c}.raw.signal = data.import.NMR.data{c}.signal; +0187 +0188 % dummy parameter data +0189 data.import.NMR.para{c} = 0; +0190 end +0191 end +0192 +0193 % save file names +0194 data.import.NMR.files = fnames; +0195 data.import.NMR.filesShort = shownames; +0196 +0197 % update the ini-file +0198 gui.myui.inidata.importpath = data.import.path; +0199 gui = makeINIfile(gui,'update'); +0200 +0201 % update the list of file names +0202 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); +0203 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); +0204 +0205 % create a global INVdata struct for every file in the list +0206 if isstruct(getappdata(fig,'INVdata')) +0207 setappdata(fig,'INVdata',[]); +0208 end +0209 INVdata = cell(length(data.import.NMR.filesShort),1); +0210 setappdata(fig,'INVdata',INVdata); +0211 +0212 % clear all axes +0213 clearAllAxes(gui.figh); +0214 +0215 % update GUI data and interface +0216 setappdata(fig,'data',data); +0217 setappdata(fig,'gui',gui); +0218 enableGUIelements('ASCII'); +0219 NUCLEUSinv_updateInterface; +0220 end +0221 +0222 end +0223 +0224 %------------- END OF CODE -------------- +0225 +0226 %% License: +0227 % MIT License +0228 % +0229 % Copyright (c) 2018 Thomas Hiller +0230 % +0231 % Permission is hereby granted, free of charge, to any person obtaining a copy +0232 % of this software and associated documentation files (the "Software"), to deal +0233 % in the Software without restriction, including without limitation the rights +0234 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0235 % copies of the Software, and to permit persons to whom the Software is +0236 % furnished to do so, subject to the following conditions: +0237 % +0238 % The above copyright notice and this permission notice shall be included in all +0239 % copies or substantial portions of the Software. +0240 % +0241 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0242 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0243 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0244 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0245 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0246 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0247 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/importEXCELdata.html b/doc/nucleus/functions/interface/importEXCELdata.html index 0f4e5d0..f7f3432 100644 --- a/doc/nucleus/functions/interface/importEXCELdata.html +++ b/doc/nucleus/functions/interface/importEXCELdata.html @@ -62,7 +62,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • NUCLEUSinv_updateInterface updates all GUI elements
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • cleanupGUIData removes unnecessary fields from the global "data" struct
  • clearAllAxes clears all axes of a given figure
  • enableGUIelements activates all necessary GUI elements after successful
  • makeINIfile creates or updates the ini-File
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • This function is called by: @@ -228,82 +228,134 @@

    SOURCE CODE ^% the NMR data 0156 data.import.NMR.data{c}.flag = T1T2; 0157 data.import.NMR.data{c}.time = num(:,1); -0158 if size(num,2)>2 -0159 tmp_signal = complex(num(:,2),num(:,3)); -0160 [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); -0161 data.import.NMR.data{c}.signal = tmp_signal; -0162 data.import.NMR.data{c}.phase = tmp_phase; -0163 else -0164 data.import.NMR.data{c}.signal = num(:,2); -0165 end -0166 data.import.NMR.data{c}.T1IRfac = 1; -0167 data.import.NMR.data{c}.raw.time = data.import.NMR.data{c}.time; -0168 data.import.NMR.data{c}.raw.signal = data.import.NMR.data{c}.signal; -0169 -0170 % dummy parameter data -0171 data.import.NMR.para{c} = 0; -0172 end -0173 end -0174 -0175 % save file names -0176 data.import.NMR.files = fnames; -0177 data.import.NMR.filesShort = shownames; -0178 -0179 % update the ini-file -0180 gui.myui.inidata.importpath = data.import.path; -0181 gui = makeINIfile(gui,'update'); -0182 -0183 % update the list of file names -0184 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); -0185 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); -0186 -0187 % create a global INVdata struct for every file in the list -0188 if isstruct(getappdata(fig,'INVdata')) -0189 setappdata(fig,'INVdata',[]); -0190 end -0191 INVdata = cell(length(data.import.NMR.filesShort),1); -0192 setappdata(fig,'INVdata',INVdata); -0193 -0194 % clear all axes -0195 clearAllAxes(gui.figh); -0196 -0197 % update GUI data and interface -0198 setappdata(fig,'data',data); -0199 setappdata(fig,'gui',gui); -0200 enableGUIelements('EXCEL'); -0201 NUCLEUSinv_updateInterface; -0202 else -0203 helpdlg({'importEXCELdata:','File is not a valid Excel file'},... -0204 'File not recognized'); -0205 end -0206 end -0207 -0208 end -0209 -0210 %------------- END OF CODE -------------- -0211 -0212 %% License: -0213 % MIT License -0214 % -0215 % Copyright (c) 2018 Thomas Hiller -0216 % -0217 % Permission is hereby granted, free of charge, to any person obtaining a copy -0218 % of this software and associated documentation files (the "Software"), to deal -0219 % in the Software without restriction, including without limitation the rights -0220 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0221 % copies of the Software, and to permit persons to whom the Software is -0222 % furnished to do so, subject to the following conditions: -0223 % -0224 % The above copyright notice and this permission notice shall be included in all -0225 % copies or substantial portions of the Software. -0226 % -0227 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0228 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0229 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0230 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0231 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0232 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0233 % SOFTWARE. +0158 % switch between T1 and T2 data +0159 switch T1T2 +0160 case 'T1' +0161 data.import.NMR.data{c}.signal = num(:,2); +0162 data.import.NMR.data{c}.phase = 0; +0163 +0164 % try saturation recovery first +0165 param.T1IRfac = 1; +0166 param.noise = 0; +0167 param.optim = 'off'; +0168 param.Tfixed_bool = [0 0 0 0 0]; +0169 param.Tfixed_val = [0 0 0 0 0]; +0170 invstd1 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... +0171 data.import.NMR.data{c}.flag,param,5); +0172 +0173 % now inversion recovery +0174 param.T1IRfac = 2; +0175 param.noise = 0; +0176 param.optim = 'off'; +0177 param.Tfixed_bool = [0 0 0 0 0]; +0178 param.Tfixed_val = [0 0 0 0 0]; +0179 invstd2 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... +0180 data.import.NMR.data{c}.flag,param,5); +0181 +0182 % compare the residuals +0183 if invstd1.resnorm < invstd2.resnorm +0184 % data is possibly saturation recovery +0185 invstd = invstd1; +0186 T1IRfac = 1; +0187 else +0188 % data is possibly inversion recovery +0189 invstd = invstd2; +0190 T1IRfac = 2; +0191 end +0192 % save the "dummy" RMS as noise estimate +0193 data.import.NMR.data{c}.noise = invstd.rms; +0194 case 'T2' +0195 T1IRfac = 1; +0196 if size(num,2)>2 +0197 tmp_signal = complex(num(:,2),num(:,3)); +0198 [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); +0199 data.import.NMR.data{c}.signal = tmp_signal; +0200 data.import.NMR.data{c}.phase = tmp_phase; +0201 else +0202 data.import.NMR.data{c}.signal = num(:,2); +0203 data.import.NMR.data{c}.phase = 0; +0204 +0205 % noise estimate +0206 param.T1IRfac = 1; +0207 param.noise = 0; +0208 param.optim = 'off'; +0209 param.Tfixed_bool = [0 0 0 0 0]; +0210 param.Tfixed_val = [0 0 0 0 0]; +0211 invstd = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... +0212 data.import.NMR.data{c}.flag,param,5); +0213 % save the "dummy" RMS as noise estimate +0214 data.import.NMR.data{c}.noise = invstd.rms; +0215 end +0216 +0217 end +0218 data.import.NMR.data{c}.T1IRfac = T1IRfac; +0219 data.import.NMR.data{c}.raw.time = data.import.NMR.data{c}.time; +0220 data.import.NMR.data{c}.raw.signal = data.import.NMR.data{c}.signal; +0221 +0222 % dummy parameter data +0223 data.import.NMR.para{c} = 0; +0224 end +0225 end +0226 +0227 % save file names +0228 data.import.NMR.files = fnames; +0229 data.import.NMR.filesShort = shownames; +0230 +0231 % update the ini-file +0232 gui.myui.inidata.importpath = data.import.path; +0233 gui = makeINIfile(gui,'update'); +0234 +0235 % update the list of file names +0236 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); +0237 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); +0238 +0239 % create a global INVdata struct for every file in the list +0240 if isstruct(getappdata(fig,'INVdata')) +0241 setappdata(fig,'INVdata',[]); +0242 end +0243 INVdata = cell(length(data.import.NMR.filesShort),1); +0244 setappdata(fig,'INVdata',INVdata); +0245 +0246 % clear all axes +0247 clearAllAxes(gui.figh); +0248 +0249 % update GUI data and interface +0250 setappdata(fig,'data',data); +0251 setappdata(fig,'gui',gui); +0252 enableGUIelements('EXCEL'); +0253 NUCLEUSinv_updateInterface; +0254 else +0255 helpdlg({'importEXCELdata:','File is not a valid Excel file'},... +0256 'File not recognized'); +0257 end +0258 end +0259 +0260 end +0261 +0262 %------------- END OF CODE -------------- +0263 +0264 %% License: +0265 % MIT License +0266 % +0267 % Copyright (c) 2018 Thomas Hiller +0268 % +0269 % Permission is hereby granted, free of charge, to any person obtaining a copy +0270 % of this software and associated documentation files (the "Software"), to deal +0271 % in the Software without restriction, including without limitation the rights +0272 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0273 % copies of the Software, and to permit persons to whom the Software is +0274 % furnished to do so, subject to the following conditions: +0275 % +0276 % The above copyright notice and this permission notice shall be included in all +0277 % copies or substantial portions of the Software. +0278 % +0279 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0280 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0281 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0282 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0283 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0284 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0285 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/importINV2INV.html b/doc/nucleus/functions/interface/importINV2INV.html index cf148f6..0e69f80 100644 --- a/doc/nucleus/functions/interface/importINV2INV.html +++ b/doc/nucleus/functions/interface/importINV2INV.html @@ -62,7 +62,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • NUCLEUSinv_updateInterface updates all GUI elements
  • onListboxData handles the calls from the context menu of the data
  • onMenuExpert handles the call from the menu that activates / deactivates
  • onMenuJointInversion handles the call from the menu that activates / deactivates
  • onMenuSolver handles the call from the menu that allows to choose the LSQ
  • onMenuView handles the view menu entries
  • displayStatusText shows status information either in the GUI or on the
  • enableGUIelements activates all necessary GUI elements after successful
  • getVersionNoFromString converts the version string to a numeric value
  • makeINIfile creates or updates the ini-File
  • This function is called by: @@ -110,220 +110,342 @@

    SOURCE CODE ^'Tag','INV'); 0038 gui = getappdata(fig,'gui'); 0039 data = getappdata(fig,'data'); -0040 -0041 % get the file name -0042 Sessionpath = -1; -0043 Sessionfile = -1; -0044 % if there is already a data folder present start from there -0045 if isfield(data.import,'path') -0046 [Sessionfile,Sessionpath] = uigetfile(data.import.path,... -0047 'Choose NUCLEUSinv session file'); -0048 else -0049 % otherwise start at the current working directory -0050 % 'pathstr' hold s the name of the chosen data path -0051 here = mfilename('fullpath'); -0052 [pathstr,~,~] = fileparts(here); -0053 [Sessionfile,Sessionpath] = uigetfile(pathstr,... -0054 'Choose NUCLEUSinv session file'); -0055 end -0056 -0057 % only continue if user didn't cancel -0058 if sum(Sessionpath) > 0 -0059 % display info text -0060 displayStatusText(gui,'Importing GUI session from mat-file ...'); -0061 -0062 % check if it is a valid session file -0063 tmp = load(fullfile(Sessionpath,Sessionfile),'savedata'); -0064 if isfield(tmp,'savedata') && isfield(tmp.savedata,'data') && ... -0065 isfield(tmp.savedata,'id') && isfield(tmp.savedata,'INVdata') -0066 savedata = tmp.savedata; -0067 -0068 % check import uimenu -0069 set(src,'Checked','on'); -0070 -0071 % backward compatibility with older versions -0072 % display info text -0073 displayStatusText(gui,'Importing GUI session from mat-file ... backward compatibility.'); -0074 % current GUI version -0075 version = getVersionNoFromString(gui.myui.version); -0076 % import GUI version -0077 version_in = getVersionNoFromString(savedata.myui.version); -0078 if version_in < version -0079 if version_in < 19 % changes introduced with v.0.1.9 -0080 % rename 'ILA' to 'LU' in savedata -0081 if strcmp(savedata.data.invstd.invtype,'ILA') -0082 savedata.data.invstd.invtype = 'LU'; -0083 end -0084 for i = 1:numel(savedata.INVdata) -0085 if isstruct(savedata.INVdata{i}) && ... -0086 strcmp(savedata.INVdata{i}.invstd.invtype,'ILA') -0087 savedata.INVdata{i}.invstd.invtype = 'LU'; -0088 end -0089 end -0090 end -0091 if version_in < 112 % changes introduced with v.0.1.12 -0092 % add 'Tdiff' field to savedata -0093 savedata.data.invstd.Tdiff = data.invstd.Tdiff; -0094 for i = 1:numel(savedata.INVdata) -0095 if isstruct(savedata.INVdata{i}) -0096 savedata.INVdata{i}.invstd.Tdiff = data.invstd.Tdiff; -0097 end -0098 end -0099 end -0100 if version_in < 114 % changes introduced with v.0.1.14 -0101 % add 'Tfixed_bool' & 'Tfixed_val' field to savedata -0102 savedata.data.invstd.Tfixed_bool = data.invstd.Tfixed_bool; -0103 savedata.data.invstd.Tfixed_val = data.invstd.Tfixed_val; -0104 for i = 1:numel(savedata.INVdata) -0105 if isstruct(savedata.INVdata{i}) -0106 savedata.INVdata{i}.invstd.Tfixed_bool = data.invstd.Tfixed_bool; -0107 savedata.INVdata{i}.invstd.Tfixed_val = data.invstd.Tfixed_val; -0108 end -0109 end -0110 end -0111 end -0112 -0113 % update GUI data from session mat-file -0114 data = savedata.data; -0115 INVdata = savedata.INVdata; -0116 -0117 % display info text -0118 displayStatusText(gui,'Importing GUI session from mat-file ... update GUI data.'); -0119 % check if the import path exists on this machine -0120 isdir_import = dir(data.import.path); -0121 % if not replace it with the path the session-file was loaded from -0122 if isempty(isdir_import) -0123 data.import.path = Sessionpath; -0124 end -0125 % update the path info field with "path" ("file") -0126 if data.import.file > 0 -0127 tmpstr = fullfile(data.import.path,data.import.file); -0128 else -0129 tmpstr = data.import.path; -0130 end -0131 % update GUI data -0132 setappdata(fig,'data',data); -0133 setappdata(fig,'gui',gui); -0134 setappdata(fig,'INVdata',INVdata); -0135 -0136 % update the ini-file -0137 gui.myui.inidata.importpath = data.import.path; -0138 gui = makeINIfile(gui,'update'); -0139 setappdata(fig,'gui',gui); -0140 -0141 if length(tmpstr)>50 -0142 set(gui.text_handles.data_path,'String',['...',tmpstr(end-50:end)],... -0143 'HorizontalAlignment','left'); -0144 else -0145 set(gui.text_handles.data_path,'String',tmpstr,... -0146 'HorizontalAlignment','left'); -0147 end -0148 set(gui.text_handles.data_path,'TooltipString',tmpstr); -0149 -0150 % update the list of file names -0151 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); -0152 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); -0153 -0154 % display info text -0155 displayStatusText(gui,'Importing GUI session from mat-file ... update GUI interface.'); -0156 % update GUI interface -0157 NUCLEUSinv_updateInterface; -0158 -0159 % color the file names where there is an inversion set -0160 for id = 1:size(INVdata,1) -0161 if isstruct(INVdata{id}) -0162 strL = get(gui.listbox_handles.signal,'String'); -0163 str1 = strL{id}; -0164 str2 = ['<HTML><BODY bgcolor="rgb(',... -0165 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',... -0166 str1,'</BODY></HTML>']; -0167 strL{id} = str2; -0168 set(gui.listbox_handles.signal,'String',strL); -0169 end -0170 end -0171 -0172 % display info text -0173 displayStatusText(gui,'Importing GUI session from mat-file ... update GUI menus.'); -0174 % adjust menu entry for expert mode -0175 switch savedata.data.info.ExpertMode -0176 case 'on' -0177 set(gui.menu.extra_expert,'Checked','off'); -0178 case 'off' -0179 set(gui.menu.extra_expert,'Checked','on'); -0180 end -0181 onMenuExpert(gui.menu.extra_expert); -0182 -0183 % adjust menu entry for joint inversion -0184 switch savedata.data.info.JointInv -0185 case 'on' -0186 set(gui.menu.extra_joint,'Checked','off'); -0187 case 'off' -0188 set(gui.menu.extra_joint,'Checked','on'); -0189 end -0190 onMenuJointInversion(gui.menu.extra_joint); -0191 enableGUIelements('NMR'); -0192 -0193 % adjust menu entry for comand line inversion info -0194 switch savedata.data.info.InvInfo -0195 case 'on' -0196 set(gui.menu.view_invinfo,'Checked','off'); -0197 case 'off' -0198 set(gui.menu.view_invinfo,'Checked','on'); -0199 end -0200 onMenuView(gui.menu.view_invinfo); -0201 -0202 % adjust menu entry for tool tips -0203 switch savedata.data.info.ToolTips -0204 case 'on' -0205 set(gui.menu.view_tooltips,'Checked','off'); -0206 case 'off' -0207 set(gui.menu.view_tooltips,'Checked','on'); -0208 end -0209 onMenuView(gui.menu.view_tooltips); -0210 -0211 % display info text -0212 displayStatusText(gui,'Importing GUI session from mat-file ... show last file.'); -0213 % set focus on last file used in previous session -0214 set(gui.listbox_handles.signal,'Value',savedata.id); -0215 % and simulate click to update all relevant GUI elements -0216 onListboxData(gui.listbox_handles.signal); +0040 data0 = data; +0041 +0042 % get the file name +0043 % Sessionpath = -1; +0044 % Sessionfile = -1; +0045 % if there is already a data folder present start from there +0046 if isfield(data.import,'path') +0047 [Sessionfile,Sessionpath] = uigetfile(data.import.path,... +0048 'Choose NUCLEUSinv session file'); +0049 else +0050 % otherwise start at the current working directory +0051 % 'pathstr' hold s the name of the chosen data path +0052 here = mfilename('fullpath'); +0053 [pathstr,~,~] = fileparts(here); +0054 [Sessionfile,Sessionpath] = uigetfile(pathstr,... +0055 'Choose NUCLEUSinv session file'); +0056 end +0057 +0058 % only continue if user didn't cancel +0059 if sum(Sessionpath) > 0 +0060 % display info text +0061 displayStatusText(gui,'Importing GUI session from mat-file ...'); +0062 +0063 % check if it is a valid session file +0064 tmp = load(fullfile(Sessionpath,Sessionfile),'savedata'); +0065 if isfield(tmp,'savedata') && isfield(tmp.savedata,'data') && ... +0066 isfield(tmp.savedata,'id') && isfield(tmp.savedata,'INVdata') +0067 savedata = tmp.savedata; +0068 +0069 % check import uimenu +0070 set(src,'Checked','on'); +0071 +0072 % backward compatibility with older versions +0073 % display info text +0074 displayStatusText(gui,'Importing GUI session from mat-file ... backward compatibility.'); +0075 % current GUI version +0076 version = getVersionNoFromString(gui.myui.version); +0077 % import GUI version +0078 version_in = getVersionNoFromString(savedata.myui.version); +0079 if version_in < version +0080 if version_in < 19 % changes introduced with v.0.1.9 +0081 % rename 'ILA' to 'LU' in savedata +0082 if strcmp(savedata.data.invstd.invtype,'ILA') +0083 savedata.data.invstd.invtype = 'LU'; +0084 end +0085 for i = 1:numel(savedata.INVdata) +0086 if isstruct(savedata.INVdata{i}) && ... +0087 strcmp(savedata.INVdata{i}.invstd.invtype,'ILA') +0088 savedata.INVdata{i}.invstd.invtype = 'LU'; +0089 end +0090 end +0091 end +0092 if version_in < 112 % changes introduced with v.0.1.12 +0093 % add 'Tdiff' field to savedata +0094 savedata.data.invstd.Tdiff = data.invstd.Tdiff; +0095 for i = 1:numel(savedata.INVdata) +0096 if isstruct(savedata.INVdata{i}) +0097 savedata.INVdata{i}.invstd.Tdiff = data.invstd.Tdiff; +0098 end +0099 end +0100 end +0101 if version_in < 114 % changes introduced with v.0.1.14 +0102 % add 'Tfixed_bool' & 'Tfixed_val' field to savedata +0103 savedata.data.invstd.Tfixed_bool = data.invstd.Tfixed_bool; +0104 savedata.data.invstd.Tfixed_val = data.invstd.Tfixed_val; +0105 for i = 1:numel(savedata.INVdata) +0106 if isstruct(savedata.INVdata{i}) +0107 if strcmp(savedata.INVdata{i}.invstd.invtype,'mono') || .... +0108 strcmp(savedata.INVdata{i}.invstd.invtype,'free') +0109 switch savedata.INVdata{i}.results.nmrproc.T1T2 +0110 case 'T1' +0111 savedata.INVdata{i}.results.invstd.T = ... +0112 savedata.INVdata{i}.results.invstd.T1; +0113 case 'T2' +0114 savedata.INVdata{i}.results.invstd.T = ... +0115 savedata.INVdata{i}.results.invstd.T2; +0116 end +0117 end +0118 savedata.INVdata{i}.invstd.Tfixed_bool = data.invstd.Tfixed_bool; +0119 savedata.INVdata{i}.invstd.Tfixed_val = data.invstd.Tfixed_val; +0120 end +0121 end +0122 end +0123 if version_in < 200 % changes introduced with v.0.2.0 +0124 % new 'RTDuncert' info flag +0125 savedata.data.info.RTDuncert = data.info.RTDuncert; +0126 % new 'isgated' field +0127 savedata.data.process.isgated = data.process.isgated; +0128 % clean-up possible old 'uncert' fields that were not used +0129 % prior to version 0.2.0 +0130 if isfield(savedata.data.invstd,'useUncert') +0131 savedata.data.invstd = rmfield(savedata.data.invstd,'useUncert'); +0132 savedata.data.invstd = rmfield(savedata.data.invstd,'uncertMethod'); +0133 savedata.data.invstd = rmfield(savedata.data.invstd,'uncertThresh'); +0134 savedata.data.invstd = rmfield(savedata.data.invstd,'uncertChi2'); +0135 savedata.data.invstd = rmfield(savedata.data.invstd,'uncertN'); +0136 savedata.data.invstd = rmfield(savedata.data.invstd,'uncertMax'); +0137 end +0138 % now create the new 'uncert' struct +0139 savedata.data.uncert = data.uncert; +0140 +0141 for i = 1:numel(savedata.INVdata) +0142 if isstruct(savedata.INVdata{i}) +0143 savedata.INVdata{i}.info.RTDuncert = data.info.RTDuncert; +0144 if strcmp(savedata.INVdata{i}.process.gatetype,'raw') +0145 savedata.INVdata{i}.process.isgated = false; +0146 savedata.INVdata{i}.results.nmrproc.isgated = false; +0147 else +0148 savedata.INVdata{i}.process.isgated = true; +0149 savedata.INVdata{i}.results.nmrproc.isgated = true; +0150 end +0151 +0152 % clean-up possible old 'uncert' fields that were +0153 % not used prior to version 0.2.0 +0154 if isfield(savedata.INVdata{i}.invstd,'useUncert') +0155 savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'useUncert'); +0156 savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertMethod'); +0157 savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertThresh'); +0158 savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertChi2'); +0159 savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertN'); +0160 savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertMax'); +0161 end +0162 % now create the new 'uncert' struct +0163 savedata.INVdata{i}.uncert = data.uncert; +0164 +0165 % now invtype is also stored in the results data +0166 savedata.INVdata{i}.results.invstd.invtype = savedata.INVdata{i}.invstd.invtype; +0167 +0168 % new 'invparams' field +0169 invparams.info = 'off'; +0170 switch savedata.INVdata{i}.invstd.invtype +0171 case {'mono','free'} +0172 invparams.T1IRfac = savedata.INVdata{i}.results.nmrproc.T1IRfac; +0173 invparams.noise = savedata.INVdata{i}.results.nmrproc.noise; +0174 invparams.optim = data.info.has_optim; +0175 invparams.Tfixed_bool = savedata.INVdata{i}.invstd.Tfixed_bool; +0176 invparams.Tfixed_val = savedata.INVdata{i}.invstd.Tfixed_val; +0177 if isfield(savedata.INVdata{i}.results.nmrproc,'W') +0178 invparams.W = savedata.INVdata{i}.results.nmrproc.W; +0179 end +0180 invparams.t_raw = savedata.INVdata{i}.results.nmrraw.t; +0181 invparams.s_raw = savedata.INVdata{i}.results.nmrraw.s; +0182 +0183 otherwise +0184 invparams.T1T2 = savedata.INVdata{i}.results.nmrproc.T1T2; +0185 invparams.T1IRfac = savedata.INVdata{i}.results.nmrproc.T1IRfac; +0186 invparams.Tb = savedata.INVdata{i}.invstd.Tbulk; +0187 invparams.Td = savedata.INVdata{i}.invstd.Tdiff; +0188 invparams.Tint = [log10(savedata.INVdata{i}.invstd.time) savedata.INVdata{i}.invstd.Ntime]; +0189 invparams.noise = savedata.INVdata{i}.results.nmrproc.noise; +0190 if isfield(savedata.INVdata{i}.results.nmrproc,'W') +0191 invparams.W = savedata.INVdata{i}.results.nmrproc.W; +0192 end +0193 switch savedata.INVdata{i}.invstd.invtype +0194 case 'LU' +0195 invparams.Lorder = savedata.INVdata{i}.invstd.Lorder; +0196 invparams.lambda = savedata.INVdata{i}.invstd.lambda; +0197 case 'NNLS' +0198 invparams.regMethod = savedata.INVdata{i}.invstd.regtype; +0199 invparams.Lorder = savedata.INVdata{i}.invstd.Lorder; +0200 invparams.lambda = savedata.INVdata{i}.invstd.lambda; +0201 invparams.solver = savedata.data.info.solver; +0202 case 'MUMO' +0203 invparams.nModes = savedata.INVdata{i}.invstd.freeDT; +0204 invparams.optim = data.info.has_optim; +0205 end +0206 end +0207 % add the new field to the inversion results +0208 savedata.INVdata{i}.results.invstd.invparams = invparams; +0209 end +0210 end +0211 end +0212 end +0213 +0214 % update GUI data from session mat-file +0215 data = savedata.data; +0216 INVdata = savedata.INVdata; 0217 0218 % display info text -0219 displayStatusText(gui,'Importing GUI session from mat-file ... done.'); -0220 else -0221 % display info text -0222 displayStatusText(gui,'Importing GUI session from mat-file ... cancelled.'); -0223 -0224 helpdlg({'importINV2INV:';... -0225 'This seems to be not a valid NUCLEUSinv session file'},... -0226 'No session data found'); -0227 end -0228 end -0229 -0230 %------------- END OF CODE -------------- -0231 -0232 %% License: -0233 % MIT License -0234 % -0235 % Copyright (c) 2018 Thomas Hiller -0236 % -0237 % Permission is hereby granted, free of charge, to any person obtaining a copy -0238 % of this software and associated documentation files (the "Software"), to deal -0239 % in the Software without restriction, including without limitation the rights -0240 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0241 % copies of the Software, and to permit persons to whom the Software is -0242 % furnished to do so, subject to the following conditions: -0243 % -0244 % The above copyright notice and this permission notice shall be included in all -0245 % copies or substantial portions of the Software. -0246 % -0247 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0248 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0249 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0250 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0251 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0252 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0253 % SOFTWARE. +0219 displayStatusText(gui,'Importing GUI session from mat-file ... update GUI data.'); +0220 % check if the import path exists on this machine +0221 isdir_import = dir(data.import.path); +0222 % if not replace it with the path the session-file was loaded from +0223 if isempty(isdir_import) +0224 data.import.path = Sessionpath; +0225 end +0226 % update the path info field with "path" ("file") +0227 if data.import.file > 0 +0228 tmpstr = fullfile(data.import.path,data.import.file); +0229 else +0230 tmpstr = data.import.path; +0231 end +0232 % update GUI data +0233 setappdata(fig,'data',data); +0234 setappdata(fig,'gui',gui); +0235 setappdata(fig,'INVdata',INVdata); +0236 +0237 % update the ini-file +0238 gui.myui.inidata.importpath = data.import.path; +0239 gui = makeINIfile(gui,'update'); +0240 setappdata(fig,'gui',gui); +0241 +0242 if length(tmpstr)>50 +0243 set(gui.text_handles.data_path,'String',['...',tmpstr(end-50:end)],... +0244 'HorizontalAlignment','left'); +0245 else +0246 set(gui.text_handles.data_path,'String',tmpstr,... +0247 'HorizontalAlignment','left'); +0248 end +0249 set(gui.text_handles.data_path,'TooltipString',tmpstr); +0250 +0251 % update the list of file names +0252 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); +0253 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); +0254 +0255 % display info text +0256 displayStatusText(gui,'Importing GUI session from mat-file ... update GUI interface.'); +0257 % update GUI interface +0258 NUCLEUSinv_updateInterface; +0259 +0260 % color the file names where there is an inversion set +0261 for id = 1:size(INVdata,1) +0262 if isstruct(INVdata{id}) +0263 strL = get(gui.listbox_handles.signal,'String'); +0264 str1 = strL{id}; +0265 str2 = ['<HTML><BODY bgcolor="rgb(',... +0266 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',... +0267 str1,'</BODY></HTML>']; +0268 strL{id} = str2; +0269 set(gui.listbox_handles.signal,'String',strL); +0270 end +0271 end +0272 +0273 % display info text +0274 displayStatusText(gui,'Importing GUI session from mat-file ... update GUI menus.'); +0275 % adjust menu entry for expert mode +0276 switch savedata.data.info.ExpertMode +0277 case 'on' +0278 set(gui.menu.extra_expert,'Checked','off'); +0279 case 'off' +0280 set(gui.menu.extra_expert,'Checked','on'); +0281 end +0282 onMenuExpert(gui.menu.extra_expert); +0283 +0284 % adjust menu entry for LSQ solver +0285 % first check if we have the optimization toolbox +0286 switch data0.info.has_optim +0287 case 'on' +0288 % if yes, set the solver accordingly +0289 switch savedata.data.info.solver +0290 case 'lsqlin' +0291 set(gui.menu.extra_solver_lsqlin,'Checked','on'); +0292 onMenuSolver(gui.menu.extra_solver_lsqlin); +0293 case 'lsqnonneg' +0294 set(gui.menu.extra_solver_lsqnonneg,'Checked','on'); +0295 onMenuSolver(gui.menu.extra_solver_lsqnonneg); +0296 end +0297 case 'off' +0298 % if not set solver to LSQNONNEG +0299 data.info.has_optim = 'off'; +0300 set(gui.menu.extra_solver_lsqnonneg,'Checked','on'); +0301 onMenuSolver(gui.menu.extra_solver_lsqnonneg); +0302 set(gui.menu.extra_solver,'Enable','off'); +0303 end +0304 +0305 % adjust menu entry for joint inversion +0306 switch savedata.data.info.JointInv +0307 case 'on' +0308 set(gui.menu.extra_joint,'Checked','off'); +0309 case 'off' +0310 set(gui.menu.extra_joint,'Checked','on'); +0311 end +0312 onMenuJointInversion(gui.menu.extra_joint); +0313 enableGUIelements('NMR'); +0314 +0315 % adjust menu entry for comand line inversion info +0316 switch savedata.data.info.InvInfo +0317 case 'on' +0318 set(gui.menu.view_invinfo,'Checked','off'); +0319 case 'off' +0320 set(gui.menu.view_invinfo,'Checked','on'); +0321 end +0322 onMenuView(gui.menu.view_invinfo); +0323 +0324 % adjust menu entry for tool tips +0325 switch savedata.data.info.ToolTips +0326 case 'on' +0327 set(gui.menu.view_tooltips,'Checked','off'); +0328 case 'off' +0329 set(gui.menu.view_tooltips,'Checked','on'); +0330 end +0331 onMenuView(gui.menu.view_tooltips); +0332 +0333 % display info text +0334 displayStatusText(gui,'Importing GUI session from mat-file ... show last file.'); +0335 % set focus on last file used in previous session +0336 set(gui.listbox_handles.signal,'Value',savedata.id); +0337 % and simulate click to update all relevant GUI elements +0338 onListboxData(gui.listbox_handles.signal); +0339 +0340 % display info text +0341 displayStatusText(gui,'Importing GUI session from mat-file ... done.'); +0342 else +0343 % display info text +0344 displayStatusText(gui,'Importing GUI session from mat-file ... cancelled.'); +0345 +0346 helpdlg({'importINV2INV:';... +0347 'This seems to be not a valid NUCLEUSinv session file'},... +0348 'No session data found'); +0349 end +0350 end +0351 +0352 %------------- END OF CODE -------------- +0353 +0354 %% License: +0355 % MIT License +0356 % +0357 % Copyright (c) 2018 Thomas Hiller +0358 % +0359 % Permission is hereby granted, free of charge, to any person obtaining a copy +0360 % of this software and associated documentation files (the "Software"), to deal +0361 % in the Software without restriction, including without limitation the rights +0362 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0363 % copies of the Software, and to permit persons to whom the Software is +0364 % furnished to do so, subject to the following conditions: +0365 % +0366 % The above copyright notice and this permission notice shall be included in all +0367 % copies or substantial portions of the Software. +0368 % +0369 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0370 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0371 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0372 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0373 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0374 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0375 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/menu.html b/doc/nucleus/functions/interface/menu.html index d9bca19..2f90c25 100644 --- a/doc/nucleus/functions/interface/menu.html +++ b/doc/nucleus/functions/interface/menu.html @@ -18,7 +18,7 @@

    Index for nucleus\functions\interface

    Matlab files in this directory:

    +
  • ConductView
  • FixedTimeView
  • PhaseView
  • UncertView
  • beautifyAxes
  • calculateGeometry
  • calculateGuiOnMonitorPosition
  • calculateNMR
  • calibratePorosity
  • caluclatePressureSaturation
  • changeColorTheme
  • checkIfInversionExists
  • cleanupGUIData
  • clearAllAxes
  • clearInversion
  • clearSingleAxis
  • displayStatusText
  • enableGUIelements
  • exportData
  • exportGraphics
  • exportINV
  • findParentOfType
  • fixAxes
  • getColorIndex
  • getColorTheme
  • getVersionNoFromString
  • importASCIIdata
  • importCPSdata
  • importCalibrationData
  • importEXCELdata
  • importINV2INV
  • importMOD2INV
  • importMOD2MOD
  • importNMRdata
  • makeINIfile
  • minimizePanel
  • moveEntryInList
  • onFigureSizeChange
  • processNMRData
  • processNMRDataControl
  • readINIfile
  • removeCalculationFields
  • removeInversionFields
  • removeSignalFromList
  • resortDataList
  • runInversionBatch
  • runInversionJoint
  • runInversionStd
  • showExtraGraphics
  • showFitStatistics
  • showParameterInfo
  • switchToolTips
  • uncheckImportMenus
  • updateCPSTable
  • updateCPSTableSize
  • updateInfo
  • updateNMRsignals
  • updatePlotsCPS
  • updatePlotsDistribution
  • updatePlotsDistributionInfo
  • updatePlotsGeometryType
  • updatePlotsJointInversion
  • updatePlotsLcurve
  • updatePlotsNMR
  • updatePlotsPSD
  • updatePlotsSignal
  • updateStatusInformation
  • updateToolTips
  • useSignalAsCalibration
  • Other Matlab-specific files in this directory:

    This function is called by: +
  • NUCLEUSinv_createGUI controls the creation of all GUI elements
  • NUCLEUSinv_createPanelPlots creates graphics panel
  • NUCLEUSmod_createGUI controls the creation of all GUI elements
  • NUCLEUSmod_createPanelPlots creates graphics panel
  • UncertView is an extra subGUI to show results of the uncertainty
  • @@ -118,14 +118,14 @@

    SOURCE CODE ^% switch depending on figure tag -0051 switch fig_tag -0052 case 'INV' +0051 switch fig_tag +0052 case 'INV' 0053 panel_1 = 'Simple Processing'; 0054 panel_2 = 'Petro Parameter'; 0055 panel_3 = 'Standard Inversion'; 0056 panel_4 = 'Joint Inversion'; 0057 panel_5 = 'CPS (joint)'; -0058 +0058 0059 switch paneltitle 0060 case panel_1 0061 id = 2; @@ -134,12 +134,12 @@

    SOURCE CODE ^case panel_3 0065 id = 4; 0066 case panel_4 -0067 id = 5; +0067 id = 5; 0068 otherwise 0069 helpdlg({'function: minimizePanel',... 0070 'Something is utterly wrong.'},'Info'); 0071 end -0072 +0072 0073 switch paneltitle 0074 case {panel_1,panel_2,panel_3,panel_4} 0075 % all heights of the left panels @@ -177,15 +177,15 @@

    SOURCE CODE ^'function: minimizePanel',... 0108 'Something is utterly wrong.'},'Info'); 0109 end -0110 -0111 case 'MOD' +0110 +0111 case 'MOD' 0112 panel_1 = 'Geometry'; 0113 panel_2 = 'Pressure / Saturation'; 0114 panel_3 = 'NMR'; 0115 panel_4 = 'Pore Size Distribution'; 0116 panel_5 = 'Capillary Pressure Saturation Curve'; 0117 panel_6 = 'NMR Signals'; -0118 +0118 0119 switch paneltitle 0120 case {panel_1,panel_4} 0121 id = 1; @@ -197,7 +197,7 @@

    SOURCE CODE ^'function: minimizePanel',... 0128 'Something is utterly wrong.'},'Info'); 0129 end -0130 +0130 0131 switch paneltitle 0132 case {panel_1,panel_2,panel_3} 0133 % all heights of the left panels @@ -233,36 +233,76 @@

    SOURCE CODE ^'function: minimizePanel',... 0164 'Something is utterly wrong.'},'Info'); 0165 end -0166 end -0167 % update GUI data -0168 setappdata(fig,'gui',gui); -0169 -0170 end -0171 -0172 %------------- END OF CODE -------------- -0173 -0174 %% License: -0175 % MIT License -0176 % -0177 % Copyright (c) 2018 Thomas Hiller -0178 % -0179 % Permission is hereby granted, free of charge, to any person obtaining a copy -0180 % of this software and associated documentation files (the "Software"), to deal -0181 % in the Software without restriction, including without limitation the rights -0182 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0183 % copies of the Software, and to permit persons to whom the Software is -0184 % furnished to do so, subject to the following conditions: -0185 % -0186 % The above copyright notice and this permission notice shall be included in all -0187 % copies or substantial portions of the Software. -0188 % -0189 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0190 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0191 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0192 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0193 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0194 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0195 % SOFTWARE. +0166 +0167 case 'UNCERTVIEW' +0168 panel_1 = 'Recalculate RTD Uncertainty'; +0169 panel_2 = 'Process Uncertainty Runs'; +0170 panel_3 = 'RTD Calculation Bounds'; +0171 panel_4 = 'Uncertainty Statistics'; +0172 +0173 switch paneltitle +0174 case panel_1 +0175 id = 1; +0176 case panel_2 +0177 id = 2; +0178 case panel_3 +0179 id = 3; +0180 case panel_4 +0181 id = 4; +0182 otherwise +0183 helpdlg({'function: minimizePanel',... +0184 'Something is utterly wrong.'},'Info'); +0185 end +0186 +0187 switch paneltitle +0188 case {panel_1,panel_2,panel_3,panel_4} +0189 % all heights of the left panels +0190 heights = get(gui.left,'Heights'); +0191 % default height of this panel +0192 pheight = def_heights(2,id); +0193 if isminimized % maximize panel +0194 heights(id) = pheight; +0195 set(gui.left,'Heights',heights); +0196 set(panel,'Minimized',false); +0197 else % minimize panel +0198 heights(id) = pheightmin; +0199 set(gui.left,'Heights',heights); +0200 set(panel,'Minimized',true) +0201 end +0202 otherwise +0203 helpdlg({'function: minimizePanel',... +0204 'Something is utterly wrong.'},'Info'); +0205 end +0206 end +0207 % update GUI data +0208 setappdata(fig,'gui',gui); +0209 +0210 end +0211 +0212 %------------- END OF CODE -------------- +0213 +0214 %% License: +0215 % MIT License +0216 % +0217 % Copyright (c) 2018 Thomas Hiller +0218 % +0219 % Permission is hereby granted, free of charge, to any person obtaining a copy +0220 % of this software and associated documentation files (the "Software"), to deal +0221 % in the Software without restriction, including without limitation the rights +0222 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0223 % copies of the Software, and to permit persons to whom the Software is +0224 % furnished to do so, subject to the following conditions: +0225 % +0226 % The above copyright notice and this permission notice shall be included in all +0227 % copies or substantial portions of the Software. +0228 % +0229 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0230 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0231 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0232 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0233 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0234 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0235 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/processNMRDataControl.html b/doc/nucleus/functions/interface/processNMRDataControl.html index e507fb4..ebaa85b 100644 --- a/doc/nucleus/functions/interface/processNMRDataControl.html +++ b/doc/nucleus/functions/interface/processNMRDataControl.html @@ -128,43 +128,44 @@

    SOURCE CODE ^processNMRData(nmrraw,nmrproc); -0064 data.results.nmrraw = nmrraw; -0065 data.results.nmrproc = nmrproc; -0066 data.process.normfac = nmrproc.normfac; -0067 -0068 % update GUI data -0069 setappdata(fig,'data',data); -0070 -0071 end -0072 -0073 %------------- END OF CODE -------------- -0074 -0075 %% License: -0076 % MIT License -0077 % -0078 % Copyright (c) 2018 Thomas Hiller -0079 % -0080 % Permission is hereby granted, free of charge, to any person obtaining a copy -0081 % of this software and associated documentation files (the "Software"), to deal -0082 % in the Software without restriction, including without limitation the rights -0083 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0084 % copies of the Software, and to permit persons to whom the Software is -0085 % furnished to do so, subject to the following conditions: -0086 % -0087 % The above copyright notice and this permission notice shall be included in all -0088 % copies or substantial portions of the Software. -0089 % -0090 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0091 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0092 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0093 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0094 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0095 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0096 % SOFTWARE. +0060 nmrproc.isgated = data.process.isgated; +0061 nmrproc.gatetype = data.process.gatetype; +0062 nmrproc.Nechoes = data.process.Nechoes; +0063 +0064 [nmrraw,nmrproc] = processNMRData(nmrraw,nmrproc); +0065 data.results.nmrraw = nmrraw; +0066 data.results.nmrproc = nmrproc; +0067 data.process.normfac = nmrproc.normfac; +0068 +0069 % update GUI data +0070 setappdata(fig,'data',data); +0071 +0072 end +0073 +0074 %------------- END OF CODE -------------- +0075 +0076 %% License: +0077 % MIT License +0078 % +0079 % Copyright (c) 2018 Thomas Hiller +0080 % +0081 % Permission is hereby granted, free of charge, to any person obtaining a copy +0082 % of this software and associated documentation files (the "Software"), to deal +0083 % in the Software without restriction, including without limitation the rights +0084 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0085 % copies of the Software, and to permit persons to whom the Software is +0086 % furnished to do so, subject to the following conditions: +0087 % +0088 % The above copyright notice and this permission notice shall be included in all +0089 % copies or substantial portions of the Software. +0090 % +0091 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0092 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0093 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0094 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0095 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0096 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0097 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/runInversionBatch.html b/doc/nucleus/functions/interface/runInversionBatch.html index c829eeb..d3734ac 100644 --- a/doc/nucleus/functions/interface/runInversionBatch.html +++ b/doc/nucleus/functions/interface/runInversionBatch.html @@ -67,7 +67,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • onListboxData handles the calls from the context menu of the data
  • onPushRun handles the callbacks to all RUN push buttons in both GUIs and
  • onPushStop recognizes that a STOP push button was pressed and resets the
  • displayStatusText shows status information either in the GUI or on the
  • processNMRDataControl prepares simple NMR raw data processing
  • removeInversionFields deletes all inversion result fields from NUCLEUSinv
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • This function is called by: @@ -265,135 +265,134 @@

    SOURCE CODE ^'Inversion using ''fminsearchbnd'' ... '; 0188 end 0189 displayStatusText(gui,infostring); -0190 invstd = fitDataMultiModal(data.results.nmrproc.t,... +0190 invstd = fitDataMultiModal(data.results.nmrproc.t,... 0191 data.results.nmrproc.s,param,data.invstd.freeDT); 0192 0193 % estimate uncertainty -0194 if data.invstd.useUncert -0195 % original fit parameter -0196 iparam = param; -0197 % uncertainty parameter -0198 uparam.time = data.results.nmrproc.t; -0199 uparam.signal = data.results.nmrproc.s; -0200 uparam.uncertMethod = data.invstd.uncertMethod; -0201 uparam.uncertThresh = data.invstd.uncertThresh; -0202 uparam.uncertChi2 = data.invstd.uncertChi2; -0203 uparam.uncertN = data.invstd.uncertN; -0204 uparam.uncertMax = data.invstd.uncertMax; -0205 invstd = estimateUncertainty(data.invstd.invtype,invstd,iparam,uparam); -0206 end -0207 end -0208 -0209 % save inversion results -0210 data.results.invstd = invstd; -0211 if id == 1 -0212 % get possible parameter file information -0213 if isfield(data.import.NMR,'para') -0214 data.info.parameter = data.import.NMR.para{id}; -0215 else -0216 data.info.parameter = 'No parameter data available.'; -0217 end -0218 INVdata{id} = []; -0219 INVdata{id} = data; -0220 INVdata{id} = rmfield(INVdata{id},'import'); -0221 INVdata{id} = rmfield(INVdata{id},'info'); -0222 INVdata{id} = rmfield(INVdata{id},'calib'); -0223 INVdata{id} = rmfield(INVdata{id},'pressure'); -0224 % copy data to all INVdata fields to allocate memory -0225 % this speeds up the overall runtime -0226 INVdata = repmat(INVdata(id),[length(data.import.NMR.filesShort),1]); -0227 else -0228 % save individual results -0229 INVdata{id}.process = data.process; -0230 INVdata{id}.results = data.results; -0231 if isfield(data.import.NMR,'para') -0232 INVdata{id}.info.parameter = data.import.NMR.para{id}; -0233 else -0234 INVdata{id}.info.parameter = 'No parameter data available.'; -0235 end -0236 end -0237 -0238 % color the list entries that already have an inversion result -0239 strL = get(gui.listbox_handles.signal,'String'); -0240 str1 = strL{id}; -0241 str2 = ['<HTML><BODY bgcolor="rgb(',... -0242 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',str1,'</BODY></HTML>']; -0243 strL{id} = str2; -0244 set(gui.listbox_handles.signal,'String',strL); -0245 -0246 % update wait-bar -0247 if wbopts.show -0248 % for a small number of signals always update the wait-bar -0249 if size(INVdata,1) <= 50 -0250 waitbar(id / steps,hwb,['processing ...',num2str(id),... -0251 ' / ',num2str(steps),' NMR signals']); -0252 else -0253 % otherwise only update every 25 signals -0254 % NOTE: Matlab's wait-bar SLOWS DOWN the calculation -0255 % MASSIVELY -0256 if id == 1 || mod(id,25) == 0 -0257 waitbar(id / steps,hwb,['processing ...',num2str(id),... -0258 ' / ',num2str(steps),' NMR signals']); -0259 end -0260 end -0261 end -0262 else -0263 displayStatusText(gui,[infostring,' was canceled']); -0264 % remove temporary data fields -0265 data = removeInversionFields(data); -0266 % remove data from fields not processed -0267 INVdata{id} = []; -0268 end -0269 end -0270 % delete wait-bar -0271 if wbopts.show -0272 delete(hwb); -0273 end -0274 if get(gui.push_handles.invstd_run,'UserData') == 1 % STOP was not pressed -0275 displayStatusText(gui,[infostring,'done']); -0276 end -0277 -0278 % update INVdata to GUI -0279 setappdata(fig,'INVdata',INVdata); -0280 % make the STOP button a RUN again -0281 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... -0282 'BackgroundColor','g','Callback',@onPushRun); -0283 % update GUI data -0284 setappdata(fig,'gui',gui); -0285 % set focus on the first entry in the list -0286 set(gui.listbox_handles.signal,'Value',1); -0287 onListboxData(gui.listbox_handles.signal); -0288 else -0289 helpdlg('Nothing to do because there is no data loaded!',... -0290 'runInversioBatch: Load NMR data first.'); -0291 end -0292 -0293 end -0294 -0295 %------------- END OF CODE -------------- -0296 -0297 %% License: -0298 % MIT License -0299 % -0300 % Copyright (c) 2018 Thomas Hiller -0301 % -0302 % Permission is hereby granted, free of charge, to any person obtaining a copy -0303 % of this software and associated documentation files (the "Software"), to deal -0304 % in the Software without restriction, including without limitation the rights -0305 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0306 % copies of the Software, and to permit persons to whom the Software is -0307 % furnished to do so, subject to the following conditions: -0308 % -0309 % The above copyright notice and this permission notice shall be included in all -0310 % copies or substantial portions of the Software. -0311 % -0312 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0313 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0314 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0315 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0316 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0317 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0318 % SOFTWARE. +0194 % if data.invstd.useUncert +0195 % % original fit parameter +0196 % iparam = param; +0197 % % uncertainty parameter +0198 % uparam.time = data.results.nmrproc.t; +0199 % uparam.signal = data.results.nmrproc.s; +0200 % uparam.uncertMethod = data.invstd.uncertMethod; +0201 % uparam.uncertThresh = data.invstd.uncertThresh; +0202 % uparam.uncertN = data.invstd.uncertN; +0203 % uparam.uncertMax = data.invstd.uncertMax; +0204 % invstd = estimateUncertainty(data.invstd.invtype,invstd,iparam,uparam); +0205 % end +0206 end +0207 +0208 % save inversion results +0209 data.results.invstd = invstd; +0210 if id == 1 +0211 % get possible parameter file information +0212 if isfield(data.import.NMR,'para') +0213 data.info.parameter = data.import.NMR.para{id}; +0214 else +0215 data.info.parameter = 'No parameter data available.'; +0216 end +0217 INVdata{id} = []; +0218 INVdata{id} = data; +0219 INVdata{id} = rmfield(INVdata{id},'import'); +0220 INVdata{id} = rmfield(INVdata{id},'info'); +0221 INVdata{id} = rmfield(INVdata{id},'calib'); +0222 INVdata{id} = rmfield(INVdata{id},'pressure'); +0223 % copy data to all INVdata fields to allocate memory +0224 % this speeds up the overall runtime +0225 INVdata = repmat(INVdata(id),[length(data.import.NMR.filesShort),1]); +0226 else +0227 % save individual results +0228 INVdata{id}.process = data.process; +0229 INVdata{id}.results = data.results; +0230 if isfield(data.import.NMR,'para') +0231 INVdata{id}.info.parameter = data.import.NMR.para{id}; +0232 else +0233 INVdata{id}.info.parameter = 'No parameter data available.'; +0234 end +0235 end +0236 +0237 % color the list entries that already have an inversion result +0238 strL = get(gui.listbox_handles.signal,'String'); +0239 str1 = strL{id}; +0240 str2 = ['<HTML><BODY bgcolor="rgb(',... +0241 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',str1,'</BODY></HTML>']; +0242 strL{id} = str2; +0243 set(gui.listbox_handles.signal,'String',strL); +0244 +0245 % update wait-bar +0246 if wbopts.show +0247 % for a small number of signals always update the wait-bar +0248 if size(INVdata,1) <= 50 +0249 waitbar(id / steps,hwb,['processing ...',num2str(id),... +0250 ' / ',num2str(steps),' NMR signals']); +0251 else +0252 % otherwise only update every 25 signals +0253 % NOTE: Matlab's wait-bar SLOWS DOWN the calculation +0254 % MASSIVELY +0255 if id == 1 || mod(id,25) == 0 +0256 waitbar(id / steps,hwb,['processing ...',num2str(id),... +0257 ' / ',num2str(steps),' NMR signals']); +0258 end +0259 end +0260 end +0261 else +0262 displayStatusText(gui,[infostring,' was canceled']); +0263 % remove temporary data fields +0264 data = removeInversionFields(data); +0265 % remove data from fields not processed +0266 INVdata{id} = []; +0267 end +0268 end +0269 % delete wait-bar +0270 if wbopts.show +0271 delete(hwb); +0272 end +0273 if get(gui.push_handles.invstd_run,'UserData') == 1 % STOP was not pressed +0274 displayStatusText(gui,[infostring,'done']); +0275 end +0276 +0277 % update INVdata to GUI +0278 setappdata(fig,'INVdata',INVdata); +0279 % make the STOP button a RUN again +0280 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... +0281 'BackgroundColor','g','Callback',@onPushRun); +0282 % update GUI data +0283 setappdata(fig,'gui',gui); +0284 % set focus on the first entry in the list +0285 set(gui.listbox_handles.signal,'Value',1); +0286 onListboxData(gui.listbox_handles.signal); +0287 else +0288 helpdlg('Nothing to do because there is no data loaded!',... +0289 'runInversioBatch: Load NMR data first.'); +0290 end +0291 +0292 end +0293 +0294 %------------- END OF CODE -------------- +0295 +0296 %% License: +0297 % MIT License +0298 % +0299 % Copyright (c) 2018 Thomas Hiller +0300 % +0301 % Permission is hereby granted, free of charge, to any person obtaining a copy +0302 % of this software and associated documentation files (the "Software"), to deal +0303 % in the Software without restriction, including without limitation the rights +0304 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0305 % copies of the Software, and to permit persons to whom the Software is +0306 % furnished to do so, subject to the following conditions: +0307 % +0308 % The above copyright notice and this permission notice shall be included in all +0309 % copies or substantial portions of the Software. +0310 % +0311 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0312 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0313 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0314 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0315 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0316 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0317 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/runInversionStd.html b/doc/nucleus/functions/interface/runInversionStd.html index fb4e3ed..07b15b2 100644 --- a/doc/nucleus/functions/interface/runInversionStd.html +++ b/doc/nucleus/functions/interface/runInversionStd.html @@ -77,7 +77,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • NUCLEUSinv_updateInterface updates all GUI elements
  • onPushRun handles the callbacks to all RUN push buttons in both GUIs and
  • onPushShowHide shows/hides the INFO column on the right side of NUCLEUSinv
  • onPushStop recognizes that a STOP push button was pressed and resets the
  • FixedTimeView is an extra subGUI to fix certain relaxation times during
  • calibratePorosity determines a sample's porosity from a calibration
  • clearAllAxes clears all axes of a given figure
  • clearSingleAxis clears an individual axis
  • displayStatusText shows status information either in the GUI or on the
  • removeInversionFields deletes all inversion result fields from NUCLEUSinv
  • showFitStatistics shows an extra fit statistics figure (for T2 data)
  • updateInfo updates the information shown in all information list boxes
  • updatePlotsDistribution plots the RTD and PSD curves into NUCLEUSinv
  • updatePlotsLcurve plots the results of the L-curve calculation
  • updatePlotsSignal plots the raw and processed NMR signals in NUCLEUSinv
  • useSignalAsCalibration uses E0 as porosity calibration factor.
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • getLambdaFromLCurve estimates the regularization parameter lambda according
  • This function is called by:
    • onPushRun handles the callbacks to all RUN push buttons in both GUIs and
    @@ -299,253 +299,241 @@

    SOURCE CODE ^'Inversion using ''fminsearchbnd'' ... '; 0212 end 0213 displayStatusText(gui,infostring); -0214 invstd = fitDataFree(data.results.nmrproc.t,... -0215 data.results.nmrproc.s,flag,param,1); -0216 data.invstd.Tfixed_val = [invstd.T zeros(1,4)]; -0217 -0218 case 'free' % N free single-exponential inversion -0219 flag = data.results.nmrproc.T1T2; -0220 param.T1IRfac = data.results.nmrproc.T1IRfac; -0221 param.noise = data.results.nmrproc.noise; -0222 param.optim = data.info.has_optim; -0223 param.Tfixed_bool = data.invstd.Tfixed_bool; -0224 param.Tfixed_val = data.invstd.Tfixed_val; -0225 if isfield(data.results.nmrproc,'W') -0226 param.W = data.results.nmrproc.W; -0227 end -0228 % status bar information -0229 switch data.info.has_optim -0230 case 'on' -0231 infostring = 'Inversion using ''Optimization Toolbox'' ... '; -0232 case 'off' -0233 infostring = 'Inversion using ''fminsearchbnd'' ... '; -0234 end -0235 displayStatusText(gui,infostring); -0236 invstd = fitDataFree(data.results.nmrproc.t,... -0237 data.results.nmrproc.s,flag,param,data.invstd.freeDT); -0238 data.invstd.Tfixed_val = [invstd.T(1:data.invstd.freeDT)... -0239 zeros(1,5-data.invstd.freeDT)]; -0240 -0241 case 'LU' % multi-exponential inversion -0242 % general parameter -0243 param.T1T2 = data.results.nmrproc.T1T2; -0244 param.T1IRfac = data.results.nmrproc.T1IRfac; -0245 param.Tb = data.invstd.Tbulk; -0246 param.Td = data.invstd.Tdiff; -0247 param.Tint = [log10(data.invstd.time) data.invstd.Ntime]; -0248 param.Lorder = data.invstd.Lorder; -0249 param.lambda = data.invstd.lambda; -0250 param.noise = data.results.nmrproc.noise; -0251 if isfield(data.results.nmrproc,'W') -0252 param.W = data.results.nmrproc.W; -0253 end -0254 % status bar information -0255 infostring = 'Inversion using LU decomposition ... '; -0256 displayStatusText(gui,infostring); -0257 invstd = fitDataLUdecomp(data.results.nmrproc.t,... -0258 data.results.nmrproc.s,param); -0259 -0260 case 'NNLS' % multi-exponential inversion with manual regularization -0261 % general parameter -0262 param.T1T2 = data.results.nmrproc.T1T2; -0263 param.T1IRfac = data.results.nmrproc.T1IRfac; -0264 param.Tb = data.invstd.Tbulk; -0265 param.Td = data.invstd.Tdiff; -0266 param.Tint = [log10(data.invstd.time) data.invstd.Ntime]; -0267 param.regMethod = data.invstd.regtype; -0268 param.Lorder = data.invstd.Lorder; -0269 param.lambda = data.invstd.lambda; -0270 param.noise = data.results.nmrproc.noise; -0271 param.solver = data.info.solver; -0272 if isfield(data.results.nmrproc,'W') -0273 param.W = data.results.nmrproc.W; -0274 end -0275 -0276 % status bar information -0277 switch data.info.solver -0278 case 'lsqlin' -0279 infostring = 'Inversion using ''Optimization Toolbox'' ... '; -0280 case 'lsqnonneg' -0281 infostring = 'Inversion using ''lsqnonneg'' ... '; -0282 end -0283 displayStatusText(gui,infostring); -0284 invstd = fitDataLSQ(data.results.nmrproc.t,... -0285 data.results.nmrproc.s,param); -0286 -0287 case 'MUMO' % N free distribution inversion -0288 param.T1T2 = data.results.nmrproc.T1T2; -0289 param.T1IRfac = data.results.nmrproc.T1IRfac; -0290 param.Tb = data.invstd.Tbulk; -0291 param.Td = data.invstd.Tdiff; -0292 param.Tint = [log10(data.invstd.time) data.invstd.Ntime]; -0293 param.noise = data.results.nmrproc.noise; -0294 param.optim = data.info.has_optim; -0295 if isfield(data.results.nmrproc,'W') -0296 param.W = data.results.nmrproc.W; -0297 end -0298 -0299 % status bar information -0300 switch data.info.solver -0301 case 'lsqlin' -0302 infostring = 'Inversion using ''Optimization Toolbox'' ... '; -0303 case 'lsqnonneg' -0304 infostring = 'Inversion using ''fminsearchbnd'' ... '; -0305 end -0306 displayStatusText(gui,infostring); -0307 invstd = fitDataMultiModal(data.results.nmrproc.t,... -0308 data.results.nmrproc.s,param,data.invstd.freeDT); -0309 -0310 % estimate uncertainty -0311 if data.invstd.useUncert -0312 % original fit parameter -0313 iparam = param; -0314 % uncertainty parameter -0315 uparam.time = data.results.nmrproc.t; -0316 uparam.signal = data.results.nmrproc.s; -0317 uparam.uncertMethod = data.invstd.uncertMethod; -0318 uparam.uncertThresh = data.invstd.uncertThresh; -0319 uparam.uncertChi2 = data.invstd.uncertChi2; -0320 uparam.uncertN = data.invstd.uncertN; -0321 uparam.uncertMax = data.invstd.uncertMax; -0322 invstd = estimateUncertainty(data.invstd.invtype,invstd,iparam,uparam); -0323 end -0324 end -0325 % normalize to 1 -0326 if data.process.norm == 1 -0327 switch data.invstd.invtype -0328 case {'LU','NNLS','MUMO'} -0329 % normalization with sum() -> sum(f)=1 -0330 % this is the standard way of doing it -0331 invstd.T1T2f = invstd.T1T2f./sum(invstd.T1T2f); -0332 % alternatives depending on the objective: -0333 % 1.) normalization with sum(f*dt) -> area~=1 -0334 % dt = log10(invstd.T1T2me(2))-log10(invstd.T1T2me(1)); -0335 % invstd.T1T2f = invstd.T1T2f/sum(invstd.T1T2f*dt); -0336 % 2.) normalization with trapz() -> area=1 but sum(f)>1 -0337 % invstd.T1T2f = invstd.T1T2f./trapz(invstd.T1T2me,invstd.T1T2f); -0338 otherwise -0339 % nothing to do -0340 end -0341 end -0342 runtime = toc; -0343 displayStatusText(gui,[infostring,'done | inversion took ',... -0344 sprintf('%5.2f',runtime),' s']); -0345 % save inversion results -0346 data.results.invstd = invstd; -0347 setappdata(fig,'data',data); -0348 end -0349 % as long as the "UserData" is 1 the STOP button was not pressed and -0350 % the inversion result gets saved in "INVdata" -0351 if get(gui.push_handles.invstd_run,'UserData') == 1 && ... -0352 ( isfield(data.results,'invstd') || ... -0353 isfield(data.results,'lcurve') ) -0354 INVdata{id} = []; -0355 INVdata{id} = data; -0356 INVdata{id} = rmfield(INVdata{id},'import'); -0357 INVdata{id} = rmfield(INVdata{id},'info'); -0358 INVdata{id} = rmfield(INVdata{id},'calib'); -0359 INVdata{id} = rmfield(INVdata{id},'pressure'); -0360 -0361 % color the list entries that already have an inversion result -0362 strL = get(gui.listbox_handles.signal,'String'); -0363 str1 = strL{id}; -0364 str2 = ['<HTML><BODY bgcolor="rgb(',... -0365 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',str1,'</BODY></HTML>']; -0366 strL{id} = str2; -0367 set(gui.listbox_handles.signal,'String',strL); -0368 -0369 % update GUI INVdata -0370 setappdata(fig,'INVdata',INVdata); -0371 -0372 % --- -0373 % special treatment for LIAG processing -0374 if isfield(data.import,'LIAG') && ~strcmp(data.invstd.regtype,'lcurve') -0375 if contains(str1,' - calibration') -0376 % save Tbulk from the calibration sample -0377 btn1 = 'Yes keep it'; -0378 btn2 = 'No, reset to 1e6 [s]'; -0379 if data.results.invstd.T2 < 0.2 -0380 answer = questdlg(['Tbulk seems very short with ',... -0381 sprintf('%4.3f',data.results.invstd.T2),' [s] ',... -0382 'Do you want to keep it?'], ... -0383 'Keep relaxation time as Tbulk', ... -0384 btn1,btn2,btn2); -0385 % Handle response -0386 switch answer -0387 case btn1 -0388 data.import.LIAG.Tbulk = data.results.invstd.T2; -0389 case btn2 -0390 data.import.LIAG.Tbulk = 1e6; -0391 end -0392 else -0393 data.import.LIAG.Tbulk = data.results.invstd.T2; -0394 end -0395 % update GUI data -0396 setappdata(fig,'data',data); -0397 % save calibration data -0398 useSignalAsCalibration(id); -0399 else -0400 calibratePorosity; -0401 end -0402 end -0403 % --- -0404 else % STOP was pressed (because "UserData" is 0) -0405 % reset "UserData" -0406 set(gui.push_handles.invstd_run,'UserData',1); -0407 end -0408 % update plots and INFO fields -0409 updatePlotsSignal; -0410 updatePlotsDistribution; -0411 updateInfo(gui.plots.SignalPanel); -0412 % set focus on results -0413 set(gui.plots.SignalPanel,'Selection',1); -0414 set(gui.plots.DistPanel,'Selection',1); -0415 % open INFO field -0416 set(gui.push_handles.info,'String','<'); -0417 onPushShowHide(gui.push_handles.info); -0418 if ~isempty(findobj('Tag','FITSTATS')) -0419 showFitStatistics; -0420 end -0421 if ~isempty(findobj('Tag','FIXEDTIMEVIEW')) -0422 FixedTimeView(gui.menu.extra_fixedtime); -0423 end -0424 NUCLEUSinv_updateInterface; -0425 else -0426 helpdlg('Cannot start inversion because no data set is selected!',... -0427 'Select NMR data first.'); -0428 end -0429 -0430 %% at the end, no matter what reset the RUN button -0431 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... -0432 'BackgroundColor','g','Enable','on','Callback',@onPushRun); -0433 setappdata(fig,'gui',gui); -0434 -0435 end -0436 -0437 %------------- END OF CODE -------------- -0438 -0439 %% License: -0440 % MIT License +0214 param.t_raw = data.results.nmrraw.t; +0215 param.s_raw = data.results.nmrraw.s; +0216 invstd = fitDataFree(data.results.nmrproc.t,... +0217 data.results.nmrproc.s,flag,param,1); +0218 data.invstd.Tfixed_val = [invstd.T zeros(1,4)]; +0219 +0220 case 'free' % N free single-exponential inversion +0221 flag = data.results.nmrproc.T1T2; +0222 param.T1IRfac = data.results.nmrproc.T1IRfac; +0223 param.noise = data.results.nmrproc.noise; +0224 param.optim = data.info.has_optim; +0225 param.Tfixed_bool = data.invstd.Tfixed_bool; +0226 param.Tfixed_val = data.invstd.Tfixed_val; +0227 if isfield(data.results.nmrproc,'W') +0228 param.W = data.results.nmrproc.W; +0229 end +0230 % status bar information +0231 switch data.info.has_optim +0232 case 'on' +0233 infostring = 'Inversion using ''Optimization Toolbox'' ... '; +0234 case 'off' +0235 infostring = 'Inversion using ''fminsearchbnd'' ... '; +0236 end +0237 displayStatusText(gui,infostring); +0238 invstd = fitDataFree(data.results.nmrproc.t,... +0239 data.results.nmrproc.s,flag,param,data.invstd.freeDT); +0240 data.invstd.Tfixed_val = [invstd.T(1:data.invstd.freeDT)... +0241 zeros(1,5-data.invstd.freeDT)]; +0242 +0243 case 'LU' % multi-exponential inversion +0244 % general parameter +0245 param.T1T2 = data.results.nmrproc.T1T2; +0246 param.T1IRfac = data.results.nmrproc.T1IRfac; +0247 param.Tb = data.invstd.Tbulk; +0248 param.Td = data.invstd.Tdiff; +0249 param.Tint = [log10(data.invstd.time) data.invstd.Ntime]; +0250 param.Lorder = data.invstd.Lorder; +0251 param.lambda = data.invstd.lambda; +0252 param.noise = data.results.nmrproc.noise; +0253 if isfield(data.results.nmrproc,'W') +0254 param.W = data.results.nmrproc.W; +0255 end +0256 % status bar information +0257 infostring = 'Inversion using LU decomposition ... '; +0258 displayStatusText(gui,infostring); +0259 invstd = fitDataLUdecomp(data.results.nmrproc.t,... +0260 data.results.nmrproc.s,param); +0261 +0262 case 'NNLS' % multi-exponential inversion with manual regularization +0263 % general parameter +0264 param.T1T2 = data.results.nmrproc.T1T2; +0265 param.T1IRfac = data.results.nmrproc.T1IRfac; +0266 param.Tb = data.invstd.Tbulk; +0267 param.Td = data.invstd.Tdiff; +0268 param.Tint = [log10(data.invstd.time) data.invstd.Ntime]; +0269 param.regMethod = data.invstd.regtype; +0270 param.Lorder = data.invstd.Lorder; +0271 param.lambda = data.invstd.lambda; +0272 param.noise = data.results.nmrproc.noise; +0273 param.solver = data.info.solver; +0274 if isfield(data.results.nmrproc,'W') +0275 param.W = data.results.nmrproc.W; +0276 end +0277 +0278 % status bar information +0279 switch data.info.solver +0280 case 'lsqlin' +0281 infostring = 'Inversion using ''Optimization Toolbox'' ... '; +0282 case 'lsqnonneg' +0283 infostring = 'Inversion using ''lsqnonneg'' ... '; +0284 end +0285 displayStatusText(gui,infostring); +0286 invstd = fitDataLSQ(data.results.nmrproc.t,... +0287 data.results.nmrproc.s,param); +0288 +0289 case 'MUMO' % N free distribution inversion +0290 param.nModes = data.invstd.freeDT; +0291 param.T1T2 = data.results.nmrproc.T1T2; +0292 param.T1IRfac = data.results.nmrproc.T1IRfac; +0293 param.Tb = data.invstd.Tbulk; +0294 param.Td = data.invstd.Tdiff; +0295 param.Tint = [log10(data.invstd.time) data.invstd.Ntime]; +0296 param.noise = data.results.nmrproc.noise; +0297 param.optim = data.info.has_optim; +0298 if isfield(data.results.nmrproc,'W') +0299 param.W = data.results.nmrproc.W; +0300 end +0301 +0302 % status bar information +0303 switch data.info.solver +0304 case 'lsqlin' +0305 infostring = 'Inversion using ''Optimization Toolbox'' ... '; +0306 case 'lsqnonneg' +0307 infostring = 'Inversion using ''fminsearchbnd'' ... '; +0308 end +0309 displayStatusText(gui,infostring); +0310 invstd = fitDataMultiModal(data.results.nmrproc.t,... +0311 data.results.nmrproc.s,param); +0312 end +0313 % normalize to 1 +0314 if data.process.norm == 1 +0315 switch data.invstd.invtype +0316 case {'LU','NNLS','MUMO'} +0317 % normalization with sum() -> sum(f)=1 +0318 % this is the standard way of doing it +0319 invstd.T1T2f = invstd.T1T2f./sum(invstd.T1T2f); +0320 % alternatives depending on the objective: +0321 % 1.) normalization with sum(f*dt) -> area~=1 +0322 % dt = log10(invstd.T1T2me(2))-log10(invstd.T1T2me(1)); +0323 % invstd.T1T2f = invstd.T1T2f/sum(invstd.T1T2f*dt); +0324 % 2.) normalization with trapz() -> area=1 but sum(f)>1 +0325 % invstd.T1T2f = invstd.T1T2f./trapz(invstd.T1T2me,invstd.T1T2f); +0326 otherwise +0327 % nothing to do +0328 end +0329 end +0330 runtime = toc; +0331 displayStatusText(gui,[infostring,'done | inversion took ',... +0332 sprintf('%5.2f',runtime),' s']); +0333 % save inversion results +0334 data.results.invstd = invstd; +0335 setappdata(fig,'data',data); +0336 end +0337 % as long as the "UserData" is 1 the STOP button was not pressed and +0338 % the inversion result gets saved in "INVdata" +0339 if get(gui.push_handles.invstd_run,'UserData') == 1 && ... +0340 ( isfield(data.results,'invstd') || ... +0341 isfield(data.results,'lcurve') ) +0342 INVdata{id} = []; +0343 INVdata{id} = data; +0344 INVdata{id} = rmfield(INVdata{id},'import'); +0345 INVdata{id} = rmfield(INVdata{id},'info'); +0346 INVdata{id} = rmfield(INVdata{id},'calib'); +0347 INVdata{id} = rmfield(INVdata{id},'pressure'); +0348 +0349 % color the list entries that already have an inversion result +0350 strL = get(gui.listbox_handles.signal,'String'); +0351 str1 = strL{id}; +0352 str2 = ['<HTML><BODY bgcolor="rgb(',... +0353 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',str1,'</BODY></HTML>']; +0354 strL{id} = str2; +0355 set(gui.listbox_handles.signal,'String',strL); +0356 +0357 % update GUI INVdata +0358 setappdata(fig,'INVdata',INVdata); +0359 +0360 % --- +0361 % special treatment for LIAG processing +0362 if isfield(data.import,'LIAG') && ~strcmp(data.invstd.regtype,'lcurve') +0363 if contains(str1,' - calibration') +0364 % save Tbulk from the calibration sample +0365 btn1 = 'Yes keep it'; +0366 btn2 = 'No, reset to 1e6 [s]'; +0367 if data.results.invstd.T2 < 0.2 +0368 answer = questdlg(['Tbulk seems very short with ',... +0369 sprintf('%4.3f',data.results.invstd.T2),' [s] ',... +0370 'Do you want to keep it?'], ... +0371 'Keep relaxation time as Tbulk', ... +0372 btn1,btn2,btn2); +0373 % Handle response +0374 switch answer +0375 case btn1 +0376 data.import.LIAG.Tbulk = data.results.invstd.T2; +0377 case btn2 +0378 data.import.LIAG.Tbulk = 1e6; +0379 end +0380 else +0381 data.import.LIAG.Tbulk = data.results.invstd.T2; +0382 end +0383 % update GUI data +0384 setappdata(fig,'data',data); +0385 % save calibration data +0386 useSignalAsCalibration(id); +0387 else +0388 calibratePorosity; +0389 end +0390 end +0391 % --- +0392 else % STOP was pressed (because "UserData" is 0) +0393 % reset "UserData" +0394 set(gui.push_handles.invstd_run,'UserData',1); +0395 end +0396 % update plots and INFO fields +0397 updatePlotsSignal; +0398 updatePlotsDistribution; +0399 updateInfo(gui.plots.SignalPanel); +0400 % set focus on results +0401 set(gui.plots.SignalPanel,'Selection',1); +0402 set(gui.plots.DistPanel,'Selection',1); +0403 % open INFO field +0404 set(gui.push_handles.info,'String','<'); +0405 onPushShowHide(gui.push_handles.info); +0406 if ~isempty(findobj('Tag','FITSTATS')) +0407 showFitStatistics; +0408 end +0409 if ~isempty(findobj('Tag','FIXEDTIMEVIEW')) +0410 FixedTimeView(gui.menu.extra_fixedtime); +0411 end +0412 NUCLEUSinv_updateInterface; +0413 else +0414 helpdlg('Cannot start inversion because no data set is selected!',... +0415 'Select NMR data first.'); +0416 end +0417 +0418 %% at the end, no matter what reset the RUN button +0419 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... +0420 'BackgroundColor','g','Enable','on','Callback',@onPushRun); +0421 setappdata(fig,'gui',gui); +0422 +0423 end +0424 +0425 %------------- END OF CODE -------------- +0426 +0427 %% License: +0428 % MIT License +0429 % +0430 % Copyright (c) 2018 Thomas Hiller +0431 % +0432 % Permission is hereby granted, free of charge, to any person obtaining a copy +0433 % of this software and associated documentation files (the "Software"), to deal +0434 % in the Software without restriction, including without limitation the rights +0435 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0436 % copies of the Software, and to permit persons to whom the Software is +0437 % furnished to do so, subject to the following conditions: +0438 % +0439 % The above copyright notice and this permission notice shall be included in all +0440 % copies or substantial portions of the Software. 0441 % -0442 % Copyright (c) 2018 Thomas Hiller -0443 % -0444 % Permission is hereby granted, free of charge, to any person obtaining a copy -0445 % of this software and associated documentation files (the "Software"), to deal -0446 % in the Software without restriction, including without limitation the rights -0447 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0448 % copies of the Software, and to permit persons to whom the Software is -0449 % furnished to do so, subject to the following conditions: -0450 % -0451 % The above copyright notice and this permission notice shall be included in all -0452 % copies or substantial portions of the Software. -0453 % -0454 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0455 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0456 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0457 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0458 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0459 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0460 % SOFTWARE. +0442 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0443 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0444 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0445 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0446 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0447 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0448 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/switchToolTips.html b/doc/nucleus/functions/interface/switchToolTips.html index 1254a45..a1b315f 100644 --- a/doc/nucleus/functions/interface/switchToolTips.html +++ b/doc/nucleus/functions/interface/switchToolTips.html @@ -130,7 +130,7 @@

    SOURCE CODE ^'ud = get(gui.',h{i},'.',fnames{j},... 0061 ',''UserData'');']); 0062 if isfield(ud,'Tooltipstr') -0063 tstr = ud.Tooltipstr; +0063 % tstr = ud.Tooltipstr; 0064 eval(['set(gui.',h{i},'.',fnames{j},... 0065 ',''ToolTipString'','''');']); 0066 end diff --git a/doc/nucleus/functions/interface/updateInfo.html b/doc/nucleus/functions/interface/updateInfo.html index 44b354f..6f2c1a4 100644 --- a/doc/nucleus/functions/interface/updateInfo.html +++ b/doc/nucleus/functions/interface/updateInfo.html @@ -61,7 +61,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • NUCLEUSinv_createPanelPlots creates graphics panel
  • onEditValue updates all edit field values, checks for wrong inputs and
  • onListboxData handles the calls from the context menu of the data
  • onMenuJointInversion handles the call from the menu that activates / deactivates
  • onRadioGates selects the re-sampling / gating method ("log", "lin" or "none")
  • onRadioNormalize selects whether to normalize a NMR signal to 1
  • runInversionJoint controls the joint inversion process to infer a pore size
  • runInversionStd controls the standard inversion process to invert a
  • +
  • NUCLEUSinv_createPanelPlots creates graphics panel
  • onEditValue updates all edit field values, checks for wrong inputs and
  • onListboxData handles the calls from the context menu of the data
  • onMenuJointInversion handles the call from the menu that activates / deactivates
  • onRadioGates selects the re-sampling / gating method ("log", "lin" or "none")
  • onRadioNormalize selects whether to normalize a NMR signal to 1
  • UncertView is an extra subGUI to show results of the uncertainty
  • runInversionJoint controls the joint inversion process to infer a pore size
  • runInversionStd controls the standard inversion process to invert a
  • runUncertaintyCalculation caluclates inverison statistics in some kind of
  • @@ -167,466 +167,510 @@

    SOURCE CODE ^end 0099 0100 end -0101 info{end+1,1} = ['<HTML><BODY>noise&nbsp= ',sprintf('%4.2e',nmrproc.noise),'</BODY></HTML>']; +0101 info{end+1,1} = ['<HTML><BODY>noise&nbsp= ',sprintf('%4.3f',nmrproc.noise),'</BODY></HTML>']; 0102 info{end+1,1} = ' '; 0103 0104 % possible inversion results/statistics 0105 if isfield(data.results,'invstd') 0106 invstd = data.results.invstd; 0107 invtype = data.invstd.invtype; -0108 -0109 switch invtype -0110 case 'mono' -0111 ciE0 = sum(full(invstd.ci(1:2:end))); -0112 switch nmrproc.T1T2 -0113 case 'T1' -0114 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... -0115 sprintf('%4.2e',sum(invstd.E0)),... -0116 ' &#8723 (',sprintf('%4.2e',ciE0),')','</BODY></HTML>']; -0117 case 'T2' -0118 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... -0119 sprintf('%4.2e',sum(invstd.E0)),... -0120 ' &#8723 (',sprintf('%4.2e',ciE0),')','</BODY></HTML>']; -0121 end -0122 info{end+1,1} = ' '; -0123 if isfield(invstd,'chi2') -0124 if ~isnan(invstd.chi2) -0125 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%4.2f',invstd.chi2)]; -0126 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0127 end -0128 end -0129 str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; -0130 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0131 % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 -0132 if nmrproc.noise ~= 0 -0133 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; -0134 end -0135 -0136 case 'free' -0137 ciE0s = sum(full(invstd.ci(1:2:end))); -0138 E0 = invstd.E0; -0139 switch nmrproc.T1T2 -0140 case 'T1' -0141 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... -0142 sprintf('%4.2e',sum(E0)),... -0143 ' &#8723 (',sprintf('%4.2e',ciE0s),')','</BODY></HTML>']; -0144 case 'T2' -0145 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... -0146 sprintf('%4.2e',sum(E0)),... -0147 ' &#8723 (',sprintf('%4.2e',ciE0s),')','</BODY></HTML>']; -0148 end -0149 info{end+1,1} = ' '; -0150 if isfield(invstd,'chi2') -0151 if ~isnan(invstd.chi2) -0152 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%4.2f',invstd.chi2)]; -0153 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0154 end -0155 end -0156 str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; -0157 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0158 -0159 % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 -0160 if nmrproc.noise ~= 0 -0161 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; -0162 end +0108 hasUncert = false; +0109 if isfield(invstd,'uncert') +0110 hasUncert = true; +0111 uncert = invstd.uncert; +0112 end +0113 +0114 switch invtype +0115 case 'mono' +0116 ciE0 = sum(full(invstd.ci(1:2:end))); +0117 switch nmrproc.T1T2 +0118 case 'T1' +0119 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... +0120 sprintf('%5.3f',sum(invstd.E0)),... +0121 ' &#8723 (',sprintf('%5.3f',ciE0),')','</BODY></HTML>']; +0122 case 'T2' +0123 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... +0124 sprintf('%5.3f',sum(invstd.E0)),... +0125 ' &#8723 (',sprintf('%5.3f',ciE0),')','</BODY></HTML>']; +0126 end +0127 info{end+1,1} = ' '; +0128 if isfield(invstd,'chi2') +0129 if ~isnan(invstd.chi2) +0130 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%5.3f',invstd.chi2)]; +0131 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; +0132 end +0133 end +0134 str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; +0135 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; +0136 % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 +0137 if nmrproc.noise ~= 0 +0138 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; +0139 end +0140 +0141 case 'free' +0142 ciE0s = sum(full(invstd.ci(1:2:end))); +0143 E0 = invstd.E0; +0144 switch nmrproc.T1T2 +0145 case 'T1' +0146 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... +0147 sprintf('%5.3f',sum(E0)),... +0148 ' &#8723 (',sprintf('%5.3f',ciE0s),')','</BODY></HTML>']; +0149 case 'T2' +0150 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... +0151 sprintf('%5.3f',sum(E0)),... +0152 ' &#8723 (',sprintf('%5.3f',ciE0s),')','</BODY></HTML>']; +0153 end +0154 info{end+1,1} = ' '; +0155 if isfield(invstd,'chi2') +0156 if ~isnan(invstd.chi2) +0157 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%5.3f',invstd.chi2)]; +0158 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; +0159 end +0160 end +0161 str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; +0162 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; 0163 -0164 case {'LU','NNLS'} -0165 switch nmrproc.T1T2 -0166 case 'T1' -0167 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... -0168 sprintf('%4.2e',sum(invstd.E0)),'</BODY></HTML>']; -0169 case 'T2' -0170 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... -0171 sprintf('%4.2e',sum(invstd.E0)),'</BODY></HTML>']; -0172 end -0173 info{end+1,1} = ' '; -0174 if isfield(invstd,'chi2') -0175 if ~isnan(invstd.chi2) -0176 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%4.2f',invstd.chi2)]; -0177 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0178 end -0179 end -0180 str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; -0181 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0182 -0183 % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 -0184 if nmrproc.noise ~= 0 -0185 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; -0186 end -0187 -0188 info{end+1,1} = ['<HTML><BODY>&lambda = ',sprintf('%6.5f',invstd.lambda_out),'</BODY></HTML>']; -0189 info{end+1,1} = ' '; -0190 case {'MUMO'} -0191 switch nmrproc.T1T2 -0192 case 'T1' -0193 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... -0194 sprintf('%4.2e',sum(invstd.E0)),... -0195 ' &#8723 (',sprintf('%4.2e',invstd.ciE0),')','</BODY></HTML>']; -0196 case 'T2' -0197 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... -0198 sprintf('%4.2e',sum(invstd.E0)),... -0199 ' &#8723 (',sprintf('%4.2e',invstd.ciE0),')','</BODY></HTML>']; -0200 end -0201 info{end+1,1} = ' '; -0202 -0203 if isfield(invstd,'chi2') -0204 if ~isnan(invstd.chi2) -0205 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%4.2f',invstd.chi2)]; -0206 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0207 end -0208 end -0209 str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; -0210 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; -0211 -0212 % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 -0213 if nmrproc.noise ~= 0 -0214 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; -0215 end -0216 info{end+1,1} = ' '; -0217 end -0218 end -0219 end -0220 -0221 case 2 % RAW -0222 if isfield(data,'results') -0223 % add filename & date information -0224 id = get(gui.listbox_handles.signal,'Value'); -0225 info{end+1,1} = data.import.NMR.filesShort{id}; -0226 info{end+1,1} = data.import.NMR.data{id}.date; -0227 info{end+1,1} = ' '; -0228 info{end+1,1} = ['<HTML><BODY>t_min &nbsp= ',... -0229 sprintf('%4.3e',data.results.nmrraw.t(1)),'</BODY></HTML>']; -0230 info{end+1,1} = ['<HTML><BODY>t_max &nbsp= ',... -0231 sprintf('%4.3e',data.results.nmrraw.t(end)),'</BODY></HTML>']; -0232 switch data.results.nmrproc.T1T2 -0233 case 'T1' -0234 info{end+1,1} = ' '; -0235 info{end+1,1} = ['<HTML><BODY>Sampl. = ',... -0236 sprintf('%d',length(data.results.nmrproc.t)),... -0237 '</BODY></HTML>']; -0238 case 'T2' -0239 info{end+1,1} = ['<HTML><BODY>t_echo = ',... -0240 sprintf('%4.3e',data.results.nmrproc.echotime),'</BODY></HTML>']; -0241 info{end+1,1} = ['<HTML><BODY>t_dead = ',... -0242 sprintf('%4.3e',data.results.nmrproc.dead),'</BODY></HTML>']; -0243 info{end+1,1} = ' '; -0244 info{end+1,1} = ['<HTML><BODY>Echos &nbsp= ',... -0245 sprintf('%d',length(data.results.nmrraw.t)),... -0246 '</BODY></HTML>']; +0164 if nmrproc.noise ~= 0 +0165 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; +0166 end +0167 +0168 case {'LU','NNLS'} +0169 switch nmrproc.T1T2 +0170 case 'T1' +0171 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0172 ')">E<sub>&infin</sub> = ',... +0173 sprintf('%5.3f',sum(invstd.E0)),'</BODY></HTML>']; +0174 case 'T2' +0175 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0176 ')">E<sub><font size="',num2str(subfs),'">0</sub> = ',... +0177 sprintf('%5.3f',sum(invstd.E0)),'</BODY></HTML>']; +0178 end +0179 if hasUncert +0180 switch nmrproc.T1T2 +0181 case 'T1' +0182 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... +0183 sprintf('%5.3f',uncert.E0(1)),... +0184 ' &#8723 (',sprintf('%5.3f',2*uncert.E0(2)),')','</BODY></HTML>']; +0185 case 'T2' +0186 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... +0187 sprintf('%5.3f',uncert.E0(1)),... +0188 ' &#8723 (',sprintf('%5.3f',2*uncert.E0(2)),')','</BODY></HTML>']; +0189 end +0190 end +0191 info{end+1,1} = ' '; +0192 if isfield(invstd,'chi2') +0193 if ~isnan(invstd.chi2) +0194 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%5.3f',invstd.chi2)]; +0195 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; +0196 end +0197 end +0198 str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; +0199 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; +0200 +0201 if nmrproc.noise ~= 0 +0202 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; +0203 end +0204 +0205 info{end+1,1} = ['<HTML><BODY>&lambda = ',sprintf('%5.3f',invstd.lambda_out),'</BODY></HTML>']; +0206 info{end+1,1} = ' '; +0207 case {'MUMO'} +0208 switch nmrproc.T1T2 +0209 case 'T1' +0210 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0211 ')">E<sub>&infin</sub> = ',... +0212 sprintf('%5.3f',sum(invstd.E0)),'</BODY></HTML>']; +0213 case 'T2' +0214 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0215 ')">E<sub><font size="',num2str(subfs),'">0</sub> = ',... +0216 sprintf('%5.3f',sum(invstd.E0)),'</BODY></HTML>']; +0217 end +0218 if hasUncert +0219 switch nmrproc.T1T2 +0220 case 'T1' +0221 info{end+1,1} = ['<HTML><BODY>E<sub>&infin</sub> = ',... +0222 sprintf('%5.3f',uncert.E0(1)),... +0223 ' &#8723 (',sprintf('%5.3f',2*uncert.E0(2)),')','</BODY></HTML>']; +0224 case 'T2' +0225 info{end+1,1} = ['<HTML><BODY>E<sub><font size="',num2str(subfs),'">0</sub> = ',... +0226 sprintf('%5.3f',uncert.E0(1)),... +0227 ' &#8723 (',sprintf('%5.3f',2*uncert.E0(2)),')','</BODY></HTML>']; +0228 end +0229 end +0230 info{end+1,1} = ' '; +0231 +0232 if isfield(invstd,'chi2') +0233 if ~isnan(invstd.chi2) +0234 str = ['&Chi<sup><font size="',num2str(subfs),'">2</sup> = ',sprintf('%5.3f',invstd.chi2)]; +0235 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; +0236 end +0237 end +0238 str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; +0239 info{end+1,1} = ['<HTML><BODY>',str,'</BODY></HTML>']; +0240 +0241 +0242 if nmrproc.noise ~= 0 +0243 info{end+1,1} = ['<HTML><BODY>S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'</BODY></HTML>']; +0244 end +0245 info{end+1,1} = ' '; +0246 end 0247 end -0248 if max(data.results.nmrproc.s) < 1e-3 -0249 info{end+1,1} = ['<HTML><BODY>A_max &nbsp= ',... -0250 sprintf('%4.3e',max(data.results.nmrproc.s)),... -0251 '</BODY></HTML>']; -0252 else -0253 info{end+1,1} = ['<HTML><BODY>A_max &nbsp= ',... -0254 sprintf('%5.4f',max(data.results.nmrproc.s)),... -0255 '</BODY></HTML>']; -0256 end -0257 info{end+1,1} = ' '; -0258 -0259 if isfield(data.import,'BAM') -0260 a = data.import.NMR.data{id}.phase_bam; -0261 info{end+1,1} = ['<HTML><BODY>phase TOM&nbsp= ',... -0262 sprintf('%5.2f',rad2deg(a)),... -0263 '°</BODY></HTML>']; -0264 end -0265 if isfield(data.results.nmrraw,'phase') -0266 info{end+1,1} = ['<HTML><BODY>phase fit&nbsp= ',... -0267 sprintf('%5.2f',rad2deg(data.results.nmrraw.phase)),... -0268 '°</BODY></HTML>']; -0269 end -0270 info{end+1,1} = ' '; -0271 end -0272 -0273 case 3 % ALL -0274 if isfield(data,'results') -0275 if isfield(data.results,'invjoint') -0276 invjoint = data.results.invjoint; -0277 nmr = invjoint.idata.nmr; -0278 levels = invjoint.levels; -0279 -0280 % global fit error -0281 info{end+1,1} = ['ErrNorm: ',sprintf('%4.3e',invjoint.errnorm)]; -0282 info{end+1,1} = ['RMS: ',sprintf('%4.3e',invjoint.rms)]; -0283 info{end+1,1} = ['<HTML><BODY>&Chi<sup><font size="',num2str(subfs),'">2</sup>: ',... -0284 sprintf('%5.4f',invjoint.chi2),'</BODY></HTML>']; -0285 info{end+1,1} = ' '; -0286 info{end+1,1} = '-----'; -0287 info{end+1,1} = ' '; -0288 -0289 for i = 1:numel(levels) -0290 info{end+1,1} = nmr{levels(i)}.name; -0291 info{end+1,1} = ['RMS: ',sprintf('%4.3e',nmr{levels(i)}.rms)]; -0292 info{end+1,1} = ['<HTML><BODY>&Chi<sup><font size="',num2str(subfs),'">2</sup>: ',... -0293 sprintf('%5.4f',nmr{levels(i)}.chi2),'</BODY></HTML>']; -0294 info{end+1,1} = ' '; -0295 end -0296 end -0297 end -0298 end -0299 % and update the text box -0300 set(gui.listbox_handles.info_signal,'String',info,'Value',[],'Max',2,'Min',0); -0301 -0302 %% RTD panel info -0303 clear info; -0304 info{1,1} = ' '; -0305 switch whichdist -0306 case 1 % RTD -0307 if isfield(data,'results') -0308 if isfield(data.results,'invstd') -0309 nmrproc = data.results.nmrproc; -0310 invstd = data.results.invstd; -0311 invtype = data.invstd.invtype; -0312 -0313 switch invtype -0314 case 'mono' -0315 info{end+1,1} = invtype; -0316 info{end+1,1} = ' '; -0317 ciT = sum(full(invstd.ci(2:2:end))); -0318 -0319 if data.invstd.Tfixed_bool(1) -0320 col = gui.myui.colors.listINV.*255; -0321 else -0322 col = [1 1 1].*255; -0323 end -0324 -0325 switch nmrproc.T1T2 -0326 case 'T1' -0327 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... -0328 sprintf('%d,%d,%d',col),')">T<sub><font size="',num2str(subfs),'">1</sub> = ',... -0329 sprintf('%5.4f',invstd.T1),... -0330 ' &#8723 (',sprintf('%5.4f',ciT),')','</BODY></HTML>']; -0331 case 'T2' -0332 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... -0333 sprintf('%d,%d,%d',col),')">T<sub><font size="',num2str(subfs),'">2</sub> = ',... -0334 sprintf('%5.4f',invstd.T2),... -0335 ' &#8723 (',sprintf('%5.4f',ciT),')','</BODY></HTML>']; -0336 end -0337 info{end+1,1} = ' '; -0338 -0339 case 'free' -0340 str = [invtype,' ',num2str(data.invstd.freeDT)]; -0341 info{end+1,1} = str; -0342 info{end+1,1} = ' '; -0343 -0344 E0 = invstd.E0; -0345 ciE0 = full(invstd.ci(1:2:end)); -0346 ciT = full(invstd.ci(2:2:end)); -0347 -0348 switch nmrproc.T1T2 -0349 case 'T1' -0350 T = invstd.T1; -0351 case 'T2' -0352 T = invstd.T2; -0353 end -0354 -0355 for i = 1:length(T) -0356 -0357 if data.invstd.Tfixed_bool(i) -0358 col = gui.myui.colors.listINV.*255; -0359 else -0360 col = [1 1 1].*255; -0361 end -0362 -0363 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... -0364 sprintf('%d,%d,%d',col),')">T(',num2str(i),') = ',sprintf('%5.4f',T(i)),... -0365 ' &#8723 (',sprintf('%5.4f',ciT(i)),')','</BODY></HTML>']; %#ok<*AGROW> -0366 info{end+1,1} = ['<HTML><BODY>E(',num2str(i),') = ',sprintf('%5.4f',E0(i)),... -0367 ' &#8723 (',sprintf('%5.4f',ciE0(i)),')','</BODY></HTML>']; -0368 info{end+1,1} = ' '; -0369 end -0370 -0371 case {'LU','NNLS'} -0372 % info is a cell array -0373 str = [invtype,' ',data.invstd.regtype,' ',num2str(data.invstd.Lorder)]; -0374 info{end+1,1} = str; -0375 info{end+1,1} = ' '; -0376 -0377 % TLGM -0378 info{end+1,1} = ['<HTML><BODY>TLGM</sub> = ',sprintf('%5.4f',invstd.Tlgm),'</BODY></HTML>']; -0379 info{end+1,1} = ' '; -0380 -0381 % clay-bound water CBW < tcut ms -0382 % irreducible water / capillary water BVI ccut - tcut ms -0383 % movable water BVM > tcut ms -0384 switch data.process.timescale -0385 case 's' -0386 ccut = data.param.CBWcutoff/1000; -0387 tcut = data.param.BVIcutoff/1000; -0388 case 'ms' -0389 ccut = data.param.CBWcutoff; -0390 tcut = data.param.BVIcutoff; -0391 end -0392 por = data.invstd.porosity; -0393 CBW = abs(sum(invstd.T1T2f(invstd.T1T2me<=ccut))/sum(invstd.T1T2f)); -0394 BVI = abs(sum(invstd.T1T2f(invstd.T1T2me>ccut & invstd.T1T2me<=tcut))/sum(invstd.T1T2f)); -0395 BVM = abs(sum(invstd.T1T2f(invstd.T1T2me>tcut))/sum(invstd.T1T2f)); -0396 info{end+1,1} = ['CBW(',sprintf('%2d',data.param.CBWcutoff),... -0397 ') = ',sprintf('%5.2f',por*CBW*100),' [vol. %]']; -0398 -0399 info{end+1,1} = ['BVI(',sprintf('%2d',data.param.BVIcutoff),... -0400 ') = ',sprintf('%5.2f',por*BVI*100),' [vol. %]']; -0401 info{end+1,1} = ['BVM = ',sprintf('%5.2f',por*BVM*100),' [vol. %]']; -0402 -0403 case {'MUMO'} +0248 end +0249 +0250 case 2 % RAW +0251 if isfield(data,'results') +0252 % add filename & date information +0253 id = get(gui.listbox_handles.signal,'Value'); +0254 info{end+1,1} = data.import.NMR.filesShort{id}; +0255 info{end+1,1} = data.import.NMR.data{id}.date; +0256 info{end+1,1} = ' '; +0257 info{end+1,1} = ['<HTML><BODY>t_min &nbsp= ',... +0258 sprintf('%5.3e',data.results.nmrraw.t(1)),'</BODY></HTML>']; +0259 info{end+1,1} = ['<HTML><BODY>t_max &nbsp= ',... +0260 sprintf('%5.3e',data.results.nmrraw.t(end)),'</BODY></HTML>']; +0261 switch data.results.nmrproc.T1T2 +0262 case 'T1' +0263 info{end+1,1} = ' '; +0264 info{end+1,1} = ['<HTML><BODY>Sampl. = ',... +0265 sprintf('%d',length(data.results.nmrproc.t)),... +0266 '</BODY></HTML>']; +0267 case 'T2' +0268 info{end+1,1} = ['<HTML><BODY>t_echo = ',... +0269 sprintf('%5.3e',data.results.nmrproc.echotime),'</BODY></HTML>']; +0270 info{end+1,1} = ['<HTML><BODY>t_dead = ',... +0271 sprintf('%5.3e',data.results.nmrproc.dead),'</BODY></HTML>']; +0272 info{end+1,1} = ' '; +0273 info{end+1,1} = ['<HTML><BODY>Echos &nbsp= ',... +0274 sprintf('%d',length(data.results.nmrraw.t)),... +0275 '</BODY></HTML>']; +0276 end +0277 if max(data.results.nmrproc.s) < 1e-3 +0278 info{end+1,1} = ['<HTML><BODY>A_max &nbsp= ',... +0279 sprintf('%4.3e',max(data.results.nmrproc.s)),... +0280 '</BODY></HTML>']; +0281 else +0282 info{end+1,1} = ['<HTML><BODY>A_max &nbsp= ',... +0283 sprintf('%5.4f',max(data.results.nmrproc.s)),... +0284 '</BODY></HTML>']; +0285 end +0286 info{end+1,1} = ' '; +0287 +0288 if isfield(data.import,'BAM') +0289 a = data.import.NMR.data{id}.phase_bam; +0290 info{end+1,1} = ['<HTML><BODY>phase TOM&nbsp= ',... +0291 sprintf('%5.2f',rad2deg(a)),... +0292 '°</BODY></HTML>']; +0293 end +0294 if isfield(data.results.nmrraw,'phase') +0295 info{end+1,1} = ['<HTML><BODY>phase fit&nbsp= ',... +0296 sprintf('%5.2f',rad2deg(data.results.nmrraw.phase)),... +0297 '°</BODY></HTML>']; +0298 end +0299 info{end+1,1} = ' '; +0300 end +0301 +0302 case 3 % ALL +0303 if isfield(data,'results') +0304 if isfield(data.results,'invjoint') +0305 invjoint = data.results.invjoint; +0306 nmr = invjoint.idata.nmr; +0307 levels = invjoint.levels; +0308 +0309 % global fit error +0310 info{end+1,1} = ['ErrNorm: ',sprintf('%5.3f',invjoint.errnorm)]; +0311 info{end+1,1} = ['RMS: ',sprintf('%5.3f',invjoint.rms)]; +0312 info{end+1,1} = ['<HTML><BODY>&Chi<sup><font size="',num2str(subfs),'">2</sup>: ',... +0313 sprintf('%5.3f',invjoint.chi2),'</BODY></HTML>']; +0314 info{end+1,1} = ' '; +0315 info{end+1,1} = '-----'; +0316 info{end+1,1} = ' '; +0317 +0318 for i = 1:numel(levels) +0319 info{end+1,1} = nmr{levels(i)}.name; +0320 info{end+1,1} = ['RMS: ',sprintf('%5.3f',nmr{levels(i)}.rms)]; +0321 info{end+1,1} = ['<HTML><BODY>&Chi<sup><font size="',num2str(subfs),'">2</sup>: ',... +0322 sprintf('%5.3f',nmr{levels(i)}.chi2),'</BODY></HTML>']; +0323 info{end+1,1} = ' '; +0324 end +0325 end +0326 end +0327 end +0328 % and update the text box +0329 set(gui.listbox_handles.info_signal,'String',info,'Value',[],'Max',2,'Min',0); +0330 +0331 %% RTD panel info +0332 clear info; +0333 info{1,1} = ' '; +0334 switch whichdist +0335 case 1 % RTD +0336 if isfield(data,'results') +0337 if isfield(data.results,'invstd') +0338 nmrproc = data.results.nmrproc; +0339 invstd = data.results.invstd; +0340 invtype = data.invstd.invtype; +0341 hasUncert = false; +0342 if isfield(invstd,'uncert') +0343 hasUncert = true; +0344 uncert = invstd.uncert; +0345 end +0346 +0347 switch invtype +0348 case 'mono' +0349 info{end+1,1} = invtype; +0350 info{end+1,1} = ' '; +0351 ciT = sum(full(invstd.ci(2:2:end))); +0352 +0353 if data.invstd.Tfixed_bool(1) +0354 col = gui.myui.colors.listINV.*255; +0355 else +0356 col = [1 1 1].*255; +0357 end +0358 +0359 switch nmrproc.T1T2 +0360 case 'T1' +0361 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... +0362 sprintf('%d,%d,%d',col),')">T<sub><font size="',num2str(subfs),'">1</sub> = ',... +0363 sprintf('%5.3f',invstd.T1),... +0364 ' &#8723 (',sprintf('%5.3f',ciT),')','</BODY></HTML>']; +0365 case 'T2' +0366 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... +0367 sprintf('%d,%d,%d',col),')">T<sub><font size="',num2str(subfs),'">2</sub> = ',... +0368 sprintf('%5.3f',invstd.T2),... +0369 ' &#8723 (',sprintf('%5.3f',ciT),')','</BODY></HTML>']; +0370 end +0371 info{end+1,1} = ' '; +0372 +0373 case 'free' +0374 str = [invtype,' ',num2str(data.invstd.freeDT)]; +0375 info{end+1,1} = str; +0376 info{end+1,1} = ' '; +0377 +0378 E0 = invstd.E0; +0379 ciE0 = full(invstd.ci(1:2:end)); +0380 ciT = full(invstd.ci(2:2:end)); +0381 +0382 switch nmrproc.T1T2 +0383 case 'T1' +0384 T = invstd.T1; +0385 case 'T2' +0386 T = invstd.T2; +0387 end +0388 +0389 for i = 1:length(T) +0390 +0391 if data.invstd.Tfixed_bool(i) +0392 col = gui.myui.colors.listINV.*255; +0393 else +0394 col = [1 1 1].*255; +0395 end +0396 +0397 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... +0398 sprintf('%d,%d,%d',col),')">T(',num2str(i),') = ',sprintf('%5.3f',T(i)),... +0399 ' &#8723 (',sprintf('%5.3f',ciT(i)),')','</BODY></HTML>']; %#ok<*AGROW> +0400 info{end+1,1} = ['<HTML><BODY>E(',num2str(i),') = ',sprintf('%5.3f',E0(i)),... +0401 ' &#8723 (',sprintf('%5.3f',ciE0(i)),')','</BODY></HTML>']; +0402 info{end+1,1} = ' '; +0403 end 0404 -0405 % info is a cell array -0406 str = [invtype,' ',num2str(data.invstd.freeDT)]; -0407 info{end+1,1} = str; -0408 info{end+1,1} = ' '; -0409 -0410 % TLGM -0411 info{end+1,1} = ['<HTML><BODY>TLGM</sub> = ',sprintf('%5.4f',invstd.Tlgm),'</BODY></HTML>']; -0412 info{end+1,1} = ' '; -0413 -0414 % clay-bound water CBW < tcut ms -0415 % irreducible water / capillary water BVI ccut - tcut ms -0416 % movable water BVM > tcut ms -0417 switch data.process.timescale -0418 case 's' -0419 ccut = data.param.CBWcutoff/1000; -0420 tcut = data.param.BVIcutoff/1000; -0421 case 'ms' -0422 ccut = data.param.CBWcutoff; -0423 tcut = data.param.BVIcutoff; -0424 end -0425 por = data.invstd.porosity; -0426 CBW = abs(sum(invstd.T1T2f(invstd.T1T2me<=ccut))/sum(invstd.T1T2f)); -0427 BVI = abs(sum(invstd.T1T2f(invstd.T1T2me>ccut & invstd.T1T2me<=tcut))/sum(invstd.T1T2f)); -0428 BVM = abs(sum(invstd.T1T2f(invstd.T1T2me>tcut))/sum(invstd.T1T2f)); -0429 info{end+1,1} = ['CBW(',sprintf('%2d',data.param.CBWcutoff),... -0430 ') = ',sprintf('%5.2f',por*CBW*100),' [vol. %]']; -0431 -0432 info{end+1,1} = ['BVI(',sprintf('%2d',data.param.BVIcutoff),... -0433 ') = ',sprintf('%5.2f',por*BVI*100),' [vol. %]']; -0434 info{end+1,1} = ['BVM = ',sprintf('%5.2f',por*BVM*100),' [vol. %]']; -0435 info{end+1,1} = ' '; -0436 -0437 % values for T, sigma and amplitude -0438 T = invstd.T; ciT = invstd.ci(1:3:end); -0439 S = invstd.S; ciS = invstd.ci(2:3:end); -0440 E = invstd.E; ciE = invstd.ci(3:3:end); -0441 % transform ciT because it is in log scale -0442 tmpT = log(T)-ciT'; -0443 ciT = T - exp(tmpT); -0444 -0445 for i = 1:length(T) -0446 info{end+1,1} = ['<HTML><BODY>T(',num2str(i),') = ',sprintf('%5.4f',T(i)),... -0447 ' &#8723 (',sprintf('%5.4f',ciT(i)),')','</BODY></HTML>']; %#ok<*AGROW> -0448 info{end+1,1} = ['<HTML><BODY>S(',num2str(i),') = ',sprintf('%5.4f',S(i)),... -0449 ' &#8723 (',sprintf('%5.4f',ciS(i)),')','</BODY></HTML>']; -0450 info{end+1,1} = ['<HTML><BODY>E(',num2str(i),') = ',sprintf('%5.4f',E(i)),... -0451 ' &#8723 (',sprintf('%5.4f',ciE(i)),')','</BODY></HTML>']; -0452 info{end+1,1} = ' '; -0453 end -0454 end -0455 end -0456 end -0457 -0458 case 2 % PSD -0459 info{end+1,1} = 'PSD'; -0460 info{end+1,1} = ' '; -0461 -0462 case 3 % PSDJ -0463 if isfield(data,'results') -0464 if isfield(data.results,'invjoint') -0465 invjoint = data.results.invjoint; -0466 -0467 info{end+1,1} = ['Inversion type: ',data.invjoint.invtype]; -0468 info{end+1,1} = ' '; -0469 switch data.invjoint.geometry_type -0470 case 'cyl' -0471 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type]; -0472 info{end+1,1} = ['Geom.: ',sprintf('%4.2f',invjoint.iGEOM.a)]; -0473 case 'ang' -0474 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,' ',... -0475 num2str(invjoint.iGEOM.angles(1)),' ',... -0476 num2str(invjoint.iGEOM.angles(2)),' ',... -0477 num2str(invjoint.iGEOM.angles(3))]; -0478 info{end+1,1} = ['Geom.: ',sprintf('%4.2f',invjoint.iGEOM.a)]; -0479 case 'poly' -0480 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,... -0481 ' ',num2str(data.invjoint.polyN),' sides']; -0482 info{end+1,1} = ['Geom.: ',sprintf('%4.2f',invjoint.iGEOM.a)]; -0483 end -0484 info{end+1,1} = ' '; -0485 info{end+1,1} = ['rho (INV): ',sprintf('%5.3f',invjoint.irho*1e6),' [µm/s]']; -0486 if isfield(data.import,'NMRMOD') -0487 info{end+1,1} = ['rho (MOD): ',... -0488 sprintf('%5.3f',data.import.NMRMOD.nmr.rho*1e6),' [µm/s]']; -0489 end -0490 end -0491 end -0492 end -0493 % and update the text box -0494 set(gui.listbox_handles.info_dist,'String',info,'Value',[],'Max',2,'Min',0); -0495 -0496 %% CPS panel info -0497 % check if the CPS panel is maximized -0498 isminimized = get(gui.plots.CPSPanel,'Minimized'); -0499 if ~isminimized -0500 clear info; -0501 info{1,1} = ' '; -0502 if isfield(data,'results') -0503 if isfield(data.results,'invjoint') -0504 invjoint = data.results.invjoint; -0505 nmr = invjoint.idata.nmr; -0506 levels = invjoint.levels; -0507 -0508 for i = 1:numel(levels) -0509 info{end+1,1} = nmr{levels(i)}.name; -0510 info{end+1,1} = ['press. : ',... -0511 sprintf('%5.4f',invjoint.p0(levels(i))*data.pressure.unitfac),... -0512 ' [',data.pressure.unit,']']; -0513 switch invjoint.T1T2 -0514 case 'T1' -0515 info{end+1,1} = ['sat. (INV) : ',... -0516 sprintf('%4.2f',invjoint.idata.nmr{levels(i)}.fit_g(end))]; -0517 case 'T2' -0518 info{end+1,1} = ['sat. (INV) : ',... -0519 sprintf('%4.2f',invjoint.idata.nmr{levels(i)}.fit_g(1))]; -0520 end -0521 info{end+1,1} = ['sat. (MOD) : ',... -0522 sprintf('%4.2f',invjoint.S0(levels(i)))]; -0523 info{end+1,1} = ' '; -0524 end -0525 end -0526 end -0527 set(gui.listbox_handles.info_cps,'String',info,'Value',[],'Max',2,'Min',0); -0528 end -0529 -0530 % update GUI data -0531 setappdata(fig,'data',data); -0532 setappdata(fig,'gui',gui); -0533 end -0534 -0535 end -0536 -0537 %------------- END OF CODE -------------- -0538 -0539 %% License: -0540 % MIT License -0541 % -0542 % Copyright (c) 2018 Thomas Hiller -0543 % -0544 % Permission is hereby granted, free of charge, to any person obtaining a copy -0545 % of this software and associated documentation files (the "Software"), to deal -0546 % in the Software without restriction, including without limitation the rights -0547 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0548 % copies of the Software, and to permit persons to whom the Software is -0549 % furnished to do so, subject to the following conditions: -0550 % -0551 % The above copyright notice and this permission notice shall be included in all -0552 % copies or substantial portions of the Software. -0553 % -0554 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0555 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0556 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0557 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0558 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0559 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0560 % SOFTWARE. +0405 case {'LU','NNLS'} +0406 % info is a cell array +0407 str = [invtype,' ',data.invstd.regtype,' ',num2str(data.invstd.Lorder)]; +0408 info{end+1,1} = str; +0409 info{end+1,1} = ' '; +0410 +0411 % TLGM +0412 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0413 ')">TLGM</sub> = ',sprintf('%5.3f',invstd.Tlgm),'</BODY></HTML>']; +0414 if hasUncert +0415 info{end+1,1} = ['<HTML><BODY>TLGM</sub> = ',sprintf('%5.3f',uncert.Tlgm(1)),... +0416 ' &#8723 (',sprintf('%5.3f',2*uncert.Tlgm(2)),')','</BODY></HTML>']; +0417 end +0418 info{end+1,1} = ' '; +0419 +0420 % clay-bound water CBW < tcut ms +0421 % irreducible water / capillary water BVI ccut - tcut ms +0422 % movable water BVM > tcut ms +0423 switch data.process.timescale +0424 case 's' +0425 ccut = data.param.CBWcutoff/1000; +0426 tcut = data.param.BVIcutoff/1000; +0427 case 'ms' +0428 ccut = data.param.CBWcutoff; +0429 tcut = data.param.BVIcutoff; +0430 end +0431 por = data.invstd.porosity; +0432 CBW = abs(sum(invstd.T1T2f(invstd.T1T2me<=ccut))/sum(invstd.T1T2f)); +0433 BVI = abs(sum(invstd.T1T2f(invstd.T1T2me>ccut & invstd.T1T2me<=tcut))/sum(invstd.T1T2f)); +0434 BVM = abs(sum(invstd.T1T2f(invstd.T1T2me>tcut))/sum(invstd.T1T2f)); +0435 info{end+1,1} = ['CBW(',sprintf('%2d',data.param.CBWcutoff),... +0436 ') = ',sprintf('%5.2f',por*CBW*100),' [vol. %]']; +0437 +0438 info{end+1,1} = ['BVI(',sprintf('%2d',data.param.BVIcutoff),... +0439 ') = ',sprintf('%5.2f',por*BVI*100),' [vol. %]']; +0440 info{end+1,1} = ['BVM = ',sprintf('%5.2f',por*BVM*100),' [vol. %]']; +0441 +0442 case {'MUMO'} +0443 +0444 % info is a cell array +0445 str = [invtype,' ',num2str(data.invstd.freeDT)]; +0446 info{end+1,1} = str; +0447 info{end+1,1} = ' '; +0448 +0449 % TLGM +0450 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0451 ')">TLGM</sub> = ',sprintf('%5.3f',invstd.Tlgm),'</BODY></HTML>']; +0452 if hasUncert +0453 info{end+1,1} = ['<HTML><BODY>TLGM</sub> = ',sprintf('%5.3f',uncert.Tlgm(1)),... +0454 ' &#8723 (',sprintf('%5.3f',2*uncert.Tlgm(2)),')','</BODY></HTML>']; +0455 end +0456 info{end+1,1} = ' '; +0457 +0458 % clay-bound water CBW < tcut ms +0459 % irreducible water / capillary water BVI ccut - tcut ms +0460 % movable water BVM > tcut ms +0461 switch data.process.timescale +0462 case 's' +0463 ccut = data.param.CBWcutoff/1000; +0464 tcut = data.param.BVIcutoff/1000; +0465 case 'ms' +0466 ccut = data.param.CBWcutoff; +0467 tcut = data.param.BVIcutoff; +0468 end +0469 por = data.invstd.porosity; +0470 CBW = abs(sum(invstd.T1T2f(invstd.T1T2me<=ccut))/sum(invstd.T1T2f)); +0471 BVI = abs(sum(invstd.T1T2f(invstd.T1T2me>ccut & invstd.T1T2me<=tcut))/sum(invstd.T1T2f)); +0472 BVM = abs(sum(invstd.T1T2f(invstd.T1T2me>tcut))/sum(invstd.T1T2f)); +0473 info{end+1,1} = ['CBW(',sprintf('%2d',data.param.CBWcutoff),... +0474 ') = ',sprintf('%5.2f',por*CBW*100),' [vol. %]']; +0475 +0476 info{end+1,1} = ['BVI(',sprintf('%2d',data.param.BVIcutoff),... +0477 ') = ',sprintf('%5.2f',por*BVI*100),' [vol. %]']; +0478 info{end+1,1} = ['BVM = ',sprintf('%5.2f',por*BVM*100),' [vol. %]']; +0479 info{end+1,1} = ' '; +0480 +0481 % values for T, sigma and amplitude +0482 T = invstd.T; ciT = invstd.ci(1:3:end); +0483 S = invstd.S; ciS = invstd.ci(2:3:end); +0484 E = invstd.E; ciE = invstd.ci(3:3:end); +0485 % transform ciT because it is in log scale +0486 tmpT = log(T)-ciT'; +0487 ciT = T - exp(tmpT); +0488 +0489 for i = 1:length(T) +0490 info{end+1,1} = ['<HTML><BODY>T(',num2str(i),') = ',sprintf('%5.3f',T(i)),... +0491 ' &#8723 (',sprintf('%5.3f',ciT(i)),')','</BODY></HTML>']; %#ok<*AGROW> +0492 info{end+1,1} = ['<HTML><BODY>S(',num2str(i),') = ',sprintf('%5.3f',S(i)),... +0493 ' &#8723 (',sprintf('%5.3f',ciS(i)),')','</BODY></HTML>']; +0494 info{end+1,1} = ['<HTML><BODY>E(',num2str(i),') = ',sprintf('%5.3f',E(i)),... +0495 ' &#8723 (',sprintf('%5.3f',ciE(i)),')','</BODY></HTML>']; +0496 info{end+1,1} = ' '; +0497 end +0498 end +0499 end +0500 end +0501 +0502 case 2 % PSD +0503 info{end+1,1} = 'PSD'; +0504 info{end+1,1} = ' '; +0505 +0506 case 3 % PSDJ +0507 if isfield(data,'results') +0508 if isfield(data.results,'invjoint') +0509 invjoint = data.results.invjoint; +0510 +0511 info{end+1,1} = ['Inversion type: ',data.invjoint.invtype]; +0512 info{end+1,1} = ' '; +0513 switch data.invjoint.geometry_type +0514 case 'cyl' +0515 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type]; +0516 info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; +0517 case 'ang' +0518 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,' ',... +0519 num2str(invjoint.iGEOM.angles(1)),' ',... +0520 num2str(invjoint.iGEOM.angles(2)),' ',... +0521 num2str(invjoint.iGEOM.angles(3))]; +0522 info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; +0523 case 'poly' +0524 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,... +0525 ' ',num2str(data.invjoint.polyN),' sides']; +0526 info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; +0527 end +0528 info{end+1,1} = ' '; +0529 info{end+1,1} = ['rho (INV): ',sprintf('%5.3f',invjoint.irho*1e6),' [µm/s]']; +0530 if isfield(data.import,'NMRMOD') +0531 info{end+1,1} = ['rho (MOD): ',... +0532 sprintf('%5.3f',data.import.NMRMOD.nmr.rho*1e6),' [µm/s]']; +0533 end +0534 end +0535 end +0536 end +0537 % and update the text box +0538 set(gui.listbox_handles.info_dist,'String',info,'Value',[],'Max',2,'Min',0); +0539 +0540 %% CPS panel info +0541 % check if the CPS panel is maximized +0542 isminimized = get(gui.plots.CPSPanel,'Minimized'); +0543 if ~isminimized +0544 clear info; +0545 info{1,1} = ' '; +0546 if isfield(data,'results') +0547 if isfield(data.results,'invjoint') +0548 invjoint = data.results.invjoint; +0549 nmr = invjoint.idata.nmr; +0550 levels = invjoint.levels; +0551 +0552 for i = 1:numel(levels) +0553 info{end+1,1} = nmr{levels(i)}.name; +0554 info{end+1,1} = ['press. : ',... +0555 sprintf('%5.3f',invjoint.p0(levels(i))*data.pressure.unitfac),... +0556 ' [',data.pressure.unit,']']; +0557 switch invjoint.T1T2 +0558 case 'T1' +0559 info{end+1,1} = ['sat. (INV) : ',... +0560 sprintf('%5.3f',invjoint.idata.nmr{levels(i)}.fit_g(end))]; +0561 case 'T2' +0562 info{end+1,1} = ['sat. (INV) : ',... +0563 sprintf('%5.3f',invjoint.idata.nmr{levels(i)}.fit_g(1))]; +0564 end +0565 info{end+1,1} = ['sat. (MOD) : ',... +0566 sprintf('%5.3f',invjoint.S0(levels(i)))]; +0567 info{end+1,1} = ' '; +0568 end +0569 end +0570 end +0571 set(gui.listbox_handles.info_cps,'String',info,'Value',[],'Max',2,'Min',0); +0572 end +0573 +0574 % update GUI data +0575 setappdata(fig,'data',data); +0576 setappdata(fig,'gui',gui); +0577 end +0578 +0579 end +0580 +0581 %------------- END OF CODE -------------- +0582 +0583 %% License: +0584 % MIT License +0585 % +0586 % Copyright (c) 2018 Thomas Hiller +0587 % +0588 % Permission is hereby granted, free of charge, to any person obtaining a copy +0589 % of this software and associated documentation files (the "Software"), to deal +0590 % in the Software without restriction, including without limitation the rights +0591 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0592 % copies of the Software, and to permit persons to whom the Software is +0593 % furnished to do so, subject to the following conditions: +0594 % +0595 % The above copyright notice and this permission notice shall be included in all +0596 % copies or substantial portions of the Software. +0597 % +0598 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0599 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0600 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0601 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0602 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0603 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0604 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/updatePlotsDistribution.html b/doc/nucleus/functions/interface/updatePlotsDistribution.html index 2ecd551..a0d8ea0 100644 --- a/doc/nucleus/functions/interface/updatePlotsDistribution.html +++ b/doc/nucleus/functions/interface/updatePlotsDistribution.html @@ -61,7 +61,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=clearSingleAxis clears an individual axis
  • updatePlotsDistributionInfo plots cut-offs and diffusion regime lines
  • This function is called by: +
  • onContextPlotsPSD checks the label of the distribution axis context menu
  • onContextPlotsRTD checks the label of the distribution axis context menu
  • onEditValue updates all edit field values, checks for wrong inputs and
  • onListboxData handles the calls from the context menu of the data
  • UncertView is an extra subGUI to show results of the uncertainty
  • calibratePorosity determines a sample's porosity from a calibration
  • changeColorTheme changes the color theme of the calling figure
  • runInversionStd controls the standard inversion process to invert a
  • runUncertaintyCalculation caluclates inverison statistics in some kind of
  • SUBFUNCTIONS ^

    @@ -106,542 +106,561 @@

    SOURCE CODE ^'data'); 0036 col = gui.myui.colors; 0037 -0038 nmrproc = data.results.nmrproc; -0039 % only continue if there is actual data to show -0040 if isfield(data.results,'invstd') -0041 invstd = data.results.invstd; -0042 -0043 %% RTD -0044 % RTD axis -0045 ax = gui.axes_handles.rtd; -0046 clearSingleAxis(ax); -0047 hold(ax,'on'); -0048 set(gui.cm_handles.axes_rtd_view,'Enable','on'); -0049 -0050 % x-axis label -0051 switch data.process.timescale -0052 case 's' -0053 xlstring = 'relaxation time [s]'; -0054 case 'ms' -0055 xlstring = 'relaxation time [ms]'; -0056 end -0057 -0058 switch data.invstd.invtype -0059 case 'mono' -0060 switch nmrproc.T1T2 -0061 case 'T1' -0062 T = invstd.T1; -0063 case 'T2' -0064 T = invstd.T2; -0065 end -0066 -0067 stem(T,invstd.E0,'o-','Color',col.FIT,'LineWidth',2,'Parent',ax); -0068 -0069 % limits -0070 ticks = floor(log10(min(T)))-2 :1: ceil(log10(max(T)))+2; -0071 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0072 set(ax,'YScale','lin','YLim',[0 invstd.E0*1.05]); -0073 % labels -0074 set(get(ax,'XLabel'),'String',xlstring); -0075 set(get(ax,'YLabel'),'String','initial amplitude E0'); -0076 % grid -0077 grid(ax,'on'); +0038 % assume there is no uncertainty data +0039 hasUncert = false; +0040 set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); +0041 +0042 if isfield(data,'results') && isfield(data.results,'nmrproc') +0043 nmrproc = data.results.nmrproc; +0044 end +0045 % only continue if there is actual data to show +0046 if isfield(data,'results') && isfield(data.results,'invstd') +0047 invstd = data.results.invstd; +0048 +0049 if isfield(invstd,'uncert') +0050 hasUncert = true; +0051 uncert = invstd.uncert; +0052 set(gui.cm_handles.axes_rtd_uncert,'Enable','on'); +0053 end +0054 +0055 %% RTD +0056 % RTD axis +0057 ax = gui.axes_handles.rtd; +0058 clearSingleAxis(ax); +0059 hold(ax,'on'); +0060 set(gui.cm_handles.axes_rtd_view,'Enable','on'); +0061 +0062 % x-axis label +0063 switch data.process.timescale +0064 case 's' +0065 xlstring = 'relaxation time [s]'; +0066 case 'ms' +0067 xlstring = 'relaxation time [ms]'; +0068 end +0069 +0070 switch data.invstd.invtype +0071 case 'mono' +0072 switch nmrproc.T1T2 +0073 case 'T1' +0074 T = invstd.T1; +0075 case 'T2' +0076 T = invstd.T2; +0077 end 0078 -0079 case 'free' -0080 mymark = {'o-','+-','s-','d-','x-'}; -0081 mycols = [0.8941 0.1020 0.1098;0.3020 0.6863 0.2902; -0082 0.2157 0.4941 0.7216;0.5961 0.3059 0.6392;0.6510 0.3373 0.1569]; -0083 switch nmrproc.T1T2 -0084 case 'T1' -0085 T = invstd.T1; -0086 case 'T2' -0087 T = invstd.T2; -0088 end -0089 -0090 lgdstr = cell(1,1); -0091 for i = 1:data.invstd.freeDT -0092 stem(T(i),invstd.E0(i),mymark{i},'Color',mycols(i,:),'LineWidth',2,'Parent',ax); -0093 lgdstr{i} = ['T',num2str(i)]; -0094 end -0095 -0096 % limits -0097 ticks = floor(log10(min(T)))-2 :1: ceil(log10(max(T)))+2; -0098 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0099 set(ax,'YScale','lin','YLim',[0 max(invstd.E0)*1.05]); -0100 % labels -0101 set(get(ax,'XLabel'),'String',xlstring); -0102 set(get(ax,'YLabel'),'String','individual amplitudes Ex [-]'); -0103 % grid -0104 grid(ax,'on'); -0105 -0106 case {'LU'} -0107 % scale distribution by porosity -0108 F = invstd.T1T2f; -0109 if sum(F)>0 -0110 F = (data.invstd.porosity*100).*F./sum(F); -0111 ylims = [0 max(F)*1.05]; -0112 else -0113 ylims = [-1 1]; -0114 end -0115 if data.invstd.porosity == 1 -0116 ylab1 = 'amplitudes [-]'; -0117 ylab2 = 'cumulative amplitudes [-]'; -0118 else -0119 ylab1 = 'water content [vol. %]'; -0120 ylab2 = 'cumulative water content [vol. %]'; -0121 end -0122 % F = data.invstd.porosity.*F./trapz(T,F); -0123 -0124 switch data.info.RTDflag -0125 case 'freq' -0126 plot(invstd.T1T2me,F,'o-','Color',col.FIT,... -0127 'LineWidth',2,'Parent',ax); -0128 % find approx. TLGM amplitude -0129 amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); -0130 stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... -0131 'LineWidth',2,'Tag','TLGM','Parent',ax); -0132 -0133 % y-limits -0134 set(ax,'YScale','lin','YLim',ylims); -0135 % y-label -0136 set(get(ax,'YLabel'),'String',ylab1); -0137 -0138 case 'cum' -0139 plot(invstd.T1T2me,cumsum(F),'o-','Color',col.FIT,... -0140 'LineWidth',2,'Parent',ax); -0141 % find approx. TLGM amplitude -0142 amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); -0143 stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... -0144 'LineWidth',2,'Tag','TLGM','Parent',ax); -0145 -0146 % y-limits -0147 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); -0148 % y-label -0149 set(get(ax,'YLabel'),'String',ylab2); -0150 end -0151 -0152 % x-limits -0153 ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me))); -0154 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0155 % x-label -0156 set(get(ax,'XLabel'),'String',xlstring); -0157 % grid -0158 grid(ax,'on'); -0159 -0160 case {'NNLS'} -0161 % scale distribution by porosity -0162 F = invstd.T1T2f; -0163 if sum(F)>0 -0164 % apply same scaling to the uncertainty patch -0165 if isfield(data.results.invstd,'uncert') -0166 f_min = data.results.invstd.uncert.interp_f_min; -0167 f_max = data.results.invstd.uncert.interp_f_max; -0168 f_min = (data.invstd.porosity*100).*f_min./sum(F); -0169 f_max = (data.invstd.porosity*100).*f_max./sum(F); -0170 end -0171 F = (data.invstd.porosity*100).*F./sum(F); -0172 -0173 ylims = [0 max(F)*1.05]; -0174 else -0175 ylims = [-1 1]; -0176 end -0177 if data.invstd.porosity == 1 -0178 ylab1 = 'amplitudes [-]'; -0179 ylab2 = 'cumulative amplitudes [-]'; -0180 else -0181 ylab1 = 'water content [vol. %]'; -0182 ylab2 = 'cumulative water content [vol. %]'; -0183 end -0184 % F = data.invstd.porosity.*F./trapz(T,F); -0185 -0186 switch data.info.RTDflag -0187 case 'freq' -0188 if isfield(data.results.invstd,'uncert') -0189 % plot uncertainty -0190 for i = 1:size(invstd.uncert.interp_f,1) -0191 plot(invstd.T1T2me,(data.invstd.porosity*100).*invstd.uncert.interp_f(i,:)./sum(invstd.T1T2f),... -0192 '-','Color',[0.5 0.5 0.5],'LineWidth',1,'Parent',ax); -0193 end -0194 % verts = [invstd.T1T2me f_min'; flipud(invstd.T1T2me) flipud(f_max')]; -0195 % faces = 1:1:size(verts,1); -0196 % patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -0197 % 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); -0198 % adjust y-limits -0199 ylims(2) = max([ylims(2) max(f_max)*1.05]); -0200 end -0201 -0202 plot(invstd.T1T2me,F,'o-','Color',col.FIT,... -0203 'LineWidth',2,'Parent',ax); -0204 % find approx. TLGM amplitude -0205 amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); -0206 stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... -0207 'LineWidth',2,'Tag','TLGM','Parent',ax); -0208 -0209 % y-limits -0210 set(ax,'YScale','lin','YLim',ylims); -0211 % y-label -0212 set(get(ax,'YLabel'),'String',ylab1); -0213 -0214 case 'cum' -0215 if isfield(data.results.invstd,'uncert') -0216 verts = [invstd.T1T2me cumsum(F)-f_min'; flipud(invstd.T1T2me) flipud(cumsum(F)+f_max')]; -0217 faces = 1:1:size(verts,1); -0218 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -0219 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); -0220 end -0221 plot(invstd.T1T2me,cumsum(F),'o-','Color',col.FIT,... -0222 'LineWidth',2,'Parent',ax); -0223 % find approx. TLGM amplitude -0224 amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); -0225 stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... -0226 'LineWidth',2,'Tag','TLGM','Parent',ax); -0227 -0228 % y-limits -0229 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); -0230 % y-label -0231 set(get(ax,'YLabel'),'String',ylab2); -0232 end -0233 -0234 % x-limits -0235 ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me))); -0236 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0237 % x-label -0238 set(get(ax,'XLabel'),'String',xlstring); -0239 % grid -0240 grid(ax,'on'); -0241 -0242 case {'MUMO'} -0243 % single distributions for different T, sigma and amplitude -0244 dist = zeros(length(invstd.x)/3,numel(invstd.T1T2me)); -0245 for i = 1:length(invstd.x)/3 -0246 mu = invstd.T(i); -0247 sigma = invstd.S(i); -0248 amp = invstd.E(i); -0249 -0250 tmp = 1./( sigma*sqrt(2*pi)).*exp(-((log(invstd.T1T2me) - log(mu))/ sqrt(2)/sigma).^2); +0079 stem(T,invstd.E0,'o-','Color',col.FIT,'LineWidth',2,'Parent',ax); +0080 +0081 % limits +0082 ticks = floor(log10(min(T)))-2 :1: ceil(log10(max(T)))+2; +0083 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0084 set(ax,'YScale','lin','YLim',[0 invstd.E0*1.05]); +0085 % labels +0086 set(get(ax,'XLabel'),'String',xlstring); +0087 set(get(ax,'YLabel'),'String','initial amplitude E0'); +0088 % grid +0089 grid(ax,'on'); +0090 +0091 case 'free' +0092 mymark = {'o-','+-','s-','d-','x-'}; +0093 mycols = [0.8941 0.1020 0.1098;0.3020 0.6863 0.2902; +0094 0.2157 0.4941 0.7216;0.5961 0.3059 0.6392;0.6510 0.3373 0.1569]; +0095 switch nmrproc.T1T2 +0096 case 'T1' +0097 T = invstd.T1; +0098 case 'T2' +0099 T = invstd.T2; +0100 end +0101 +0102 lgdstr = cell(1,1); +0103 for i = 1:data.invstd.freeDT +0104 stem(T(i),invstd.E0(i),mymark{i},'Color',mycols(i,:),'LineWidth',2,'Parent',ax); +0105 lgdstr{i} = ['T',num2str(i)]; +0106 end +0107 +0108 % limits +0109 ticks = floor(log10(min(T)))-2 :1: ceil(log10(max(T)))+2; +0110 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0111 set(ax,'YScale','lin','YLim',[0 max(invstd.E0)*1.05]); +0112 % labels +0113 set(get(ax,'XLabel'),'String',xlstring); +0114 set(get(ax,'YLabel'),'String','individual amplitudes Ex [-]'); +0115 % grid +0116 grid(ax,'on'); +0117 +0118 case {'LU','NNLS'} +0119 % scale distribution by porosity +0120 F0 = invstd.T1T2f; +0121 if sum(F0)>0 +0122 F = (data.invstd.porosity*100).*F0./sum(F0); +0123 ylims = [0 max(F)*1.05]; +0124 else +0125 ylims = [-1 1]; +0126 end +0127 if data.invstd.porosity == 1 +0128 ylab1 = 'amplitudes [-]'; +0129 ylab2 = 'cumulative amplitudes [-]'; +0130 else +0131 ylab1 = 'water content [vol. %]'; +0132 ylab2 = 'cumulative water content [vol. %]'; +0133 end +0134 % F = data.invstd.porosity.*F./trapz(T,F); +0135 +0136 switch data.info.RTDflag +0137 case 'freq' +0138 % check if there is uncertainty data +0139 if hasUncert +0140 % plot uncertainty models +0141 f_max = 0; +0142 FDIST = uncert.interp_f; +0143 % scaling +0144 FDIST = (data.invstd.porosity*100).*FDIST./sum(F0); +0145 +0146 switch data.info.RTDuncert +0147 case 'lines' +0148 f_max = max([ylims(2) max(FDIST(:))]); +0149 % need to plot transpose of FDIST because 'x' +0150 % is a column vector otherwise plot goes +0151 % bananas if numel(x) = #models +0152 plot(invstd.T1T2me,FDIST(1,:)','-','Color',[0.5 0.5 0.5],... +0153 'LineWidth',1,... +0154 'DisplayName','uncert models','Parent',ax); +0155 plot(invstd.T1T2me,FDIST(2:end,:)','-','Color',[0.5 0.5 0.5],... +0156 'LineWidth',1,'HandleVisibility','off',... +0157 'Tag','infolines','Parent',ax); +0158 case 'patch' +0159 % get mean and std of all uncert models +0160 mean_f = mean(FDIST); +0161 std_f = std(FDIST); +0162 +0163 % patch lower and upper bounds +0164 patch_f_std1 = [mean_f+std_f;mean_f-std_f]; +0165 patch_f_std2 = [mean_f+2*std_f;mean_f-2*std_f]; +0166 patch_f_std3 = [mean_f+3*std_f;mean_f-3*std_f]; +0167 patch_f_std1(patch_f_std1<0) = 0; +0168 patch_f_std2(patch_f_std2<0) = 0; +0169 patch_f_std3(patch_f_std3<0) = 0; +0170 f_max = max([ylims(2) max(patch_f_std1)... +0171 max(patch_f_std2) max(patch_f_std3)]); +0172 +0173 % draw all three patches on top of each other +0174 verts = [invstd.T1T2me patch_f_std3(2,:)';.... +0175 flipud(invstd.T1T2me) flipud(patch_f_std3(1,:)')]; +0176 faces = 1:1:size(verts,1); +0177 patch('Faces',faces,'Vertices',verts,... +0178 'FaceColor',[0.6 0.6 0.6],... +0179 'FaceAlpha',0.75,'EdgeColor','none',... +0180 'DisplayName','mean (3*std)','Parent',ax); +0181 verts = [invstd.T1T2me patch_f_std2(2,:)';... +0182 flipud(invstd.T1T2me) flipud(patch_f_std2(1,:)')]; +0183 faces = 1:1:size(verts,1); +0184 patch('Faces',faces,'Vertices',verts,... +0185 'FaceColor',[0.4 0.4 0.4],... +0186 'FaceAlpha',0.75,'EdgeColor','none',... +0187 'DisplayName','mean (2*std)','Parent',ax); +0188 verts = [invstd.T1T2me patch_f_std1(2,:)';... +0189 flipud(invstd.T1T2me) flipud(patch_f_std1(1,:)')]; +0190 faces = 1:1:size(verts,1); +0191 patch('Faces',faces,'Vertices',verts,... +0192 'FaceColor',[0.2 0.2 0.2],... +0193 'FaceAlpha',0.75,'EdgeColor','none',... +0194 'DisplayName','mean (std)','Parent',ax); +0195 end +0196 % adjust y-limits +0197 ylims(2) = max([ylims(2) max(f_max)*1.05]); +0198 +0199 % plot original solution +0200 plot(invstd.T1T2me,F,'-','Color',col.FIT,... +0201 'DisplayName','fit','LineWidth',2,'Parent',ax); +0202 else +0203 plot(invstd.T1T2me,F,'o-','Color',col.FIT,... +0204 'DisplayName','fit','LineWidth',2,'Parent',ax); +0205 end +0206 +0207 % find approx. TLGM amplitude +0208 amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); +0209 stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... +0210 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); +0211 +0212 % y-limits +0213 set(ax,'YScale','lin','YLim',ylims); +0214 % y-label +0215 set(get(ax,'YLabel'),'String',ylab1); +0216 % legend +0217 legend(ax,'Location','NorthEast'); +0218 +0219 case 'cum' +0220 % in the case of the cumulative plot, no uncertainty is +0221 % shown +0222 plot(invstd.T1T2me,cumsum(F),'o-','Color',col.FIT,... +0223 'DisplayName','fit','LineWidth',2,'Parent',ax); +0224 +0225 % find approx. TLGM amplitude +0226 amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); +0227 stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... +0228 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); +0229 +0230 % y-limits +0231 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); +0232 % y-label +0233 set(get(ax,'YLabel'),'String',ylab2); +0234 end +0235 +0236 % x-limits +0237 ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me))); +0238 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0239 % x-label +0240 set(get(ax,'XLabel'),'String',xlstring); +0241 % grid +0242 grid(ax,'on'); +0243 +0244 case {'MUMO'} +0245 % single distributions for different T, sigma and amplitude +0246 dist = zeros(length(invstd.x)/3,numel(invstd.T1T2me)); +0247 for i = 1:length(invstd.x)/3 +0248 mu = invstd.T(i); +0249 sigma = invstd.S(i); +0250 amp = invstd.E(i); 0251 -0252 % scale to amplitude -0253 dist(i,:) = (tmp/sum(tmp)) * amp; -0254 end -0255 -0256 % scale distribution by porosity -0257 F = invstd.T1T2f; -0258 if sum(F)>0 -0259 for i = 1:length(invstd.x)/3 -0260 dist(i,:) = (data.invstd.porosity*100).*dist(i,:)./sum(F); -0261 end -0262 % apply same scaling to the uncertainty patch -0263 if isfield(data.results.invstd,'uncert') -0264 f_min = data.results.invstd.uncert.interp_f_min; -0265 f_max = data.results.invstd.uncert.interp_f_max; -0266 f_min = (data.invstd.porosity*100).*f_min./sum(F); -0267 f_max = (data.invstd.porosity*100).*f_max./sum(F); -0268 end -0269 F = (data.invstd.porosity*100).*F./sum(F); -0270 -0271 ylims = [0 max(F)*1.05]; -0272 else -0273 ylims = [-1 1]; -0274 end -0275 if data.invstd.porosity == 1 -0276 ylab1 = 'amplitudes [-]'; -0277 ylab2 = 'cumulative amplitudes [-]'; -0278 else -0279 ylab1 = 'water content [vol. %]'; -0280 ylab2 = 'cumulative water content [vol. %]'; -0281 end -0282 % F = data.invstd.porosity.*F./trapz(T,F); +0252 tmp = 1./( sigma*sqrt(2*pi)).*exp(-((log(invstd.T1T2me) - log(mu))/ sqrt(2)/sigma).^2); +0253 +0254 % scale to amplitude +0255 dist(i,:) = (tmp/sum(tmp)) * amp; +0256 end +0257 +0258 % scale RTD(s) by porosity +0259 F0 = invstd.T1T2f; +0260 if sum(F0)>0 +0261 % individual RTDs +0262 for i = 1:length(invstd.x)/3 +0263 dist(i,:) = (data.invstd.porosity*100).*dist(i,:)./sum(F0); +0264 end +0265 % combined (total) RTD +0266 F = (data.invstd.porosity*100).*F0./sum(F0); +0267 +0268 ylims = [0 max(F)*1.05]; +0269 else +0270 ylims = [-1 1]; +0271 end +0272 if data.invstd.porosity == 1 +0273 ylab1 = 'amplitudes [-]'; +0274 ylab2 = 'cumulative amplitudes [-]'; +0275 else +0276 ylab1 = 'water content [vol. %]'; +0277 ylab2 = 'cumulative water content [vol. %]'; +0278 end +0279 % F = data.invstd.porosity.*F./trapz(T,F); +0280 +0281 mycols = [0.2157 0.4941 0.7216;0.3020 0.6863 0.2902; +0282 0.5961 0.3059 0.6392;0.6510 0.3373 0.1569;0.8941 0.1020 0.1098]; 0283 -0284 mycols = [0.2157 0.4941 0.7216;0.3020 0.6863 0.2902; -0285 0.5961 0.3059 0.6392;0.6510 0.3373 0.1569;0.8941 0.1020 0.1098]; -0286 -0287 switch data.info.RTDflag -0288 case 'freq' -0289 if isfield(data.results.invstd,'uncert') -0290 % plot uncertainty -0291 % lines -0292 % for i = 1:size(invstd.TDIST,1) -0293 % plot(invstd.T1T2me,(data.invstd.porosity*100).*invstd.TDIST(i,:)./sum(invstd.T1T2f),... -0294 % '-','Color',[0.5 0.5 0.5],'LineWidth',1,'Parent',ax); -0295 % end -0296 % patch -0297 % TDIST = invstd.TDIST; -0298 % for i = 1:size(invstd.TDIST,1) -0299 % TDIST(i,:) = (data.invstd.porosity*100).*invstd.TDIST(i,:)./sum(invstd.T1T2f); -0300 % end -0301 % TDISTmin = min(TDIST); -0302 % TDISTmax = max(TDIST); -0303 % verts = [nmrproc.t(nmrproc.t>0) s_min; flipud(nmrproc.t(nmrproc.t>0)) flipud(s_max)]; -0304 % faces = 1:1:size(verts,1); -0305 % -0306 verts = [invstd.T1T2me f_min'; flipud(invstd.T1T2me) flipud(f_max')]; -0307 faces = 1:1:size(verts,1); -0308 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -0309 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); -0310 % adjust y-limits -0311 ylims(2) = max([ylims(2) max(f_max)*1.05]); -0312 end -0313 -0314 % plot total RTD -0315 plot(invstd.T1T2me,F,'-','Color',col.FIT,... -0316 'LineWidth',2,'Parent',ax); -0317 % plot individual RTDs -0318 for i = 1:length(invstd.x)/3 -0319 plot(invstd.T1T2me,dist(i,:),'--','Color',mycols(i,:),... -0320 'LineWidth',2,'Parent',ax); -0321 end -0322 % find approx. TLGM amplitude -0323 amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); -0324 stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... -0325 'LineWidth',2,'Tag','TLGM','Parent',ax); -0326 -0327 % y-limits -0328 set(ax,'YScale','lin','YLim',ylims); -0329 % y-label -0330 set(get(ax,'YLabel'),'String',ylab1); -0331 -0332 case 'cum' -0333 if isfield(data.results.invstd,'uncert') -0334 verts = [invstd.T1T2me cumsum(F)-f_min'; flipud(invstd.T1T2me) flipud(cumsum(F)+f_max')]; -0335 faces = 1:1:size(verts,1); -0336 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -0337 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); -0338 end -0339 plot(invstd.T1T2me,cumsum(F),'-','Color',col.FIT,... -0340 'LineWidth',2,'Parent',ax); -0341 for i = 1:length(invstd.x)/3 -0342 plot(invstd.T1T2me,cumsum(dist(i,:)),'--','Color',mycols(i,:),... -0343 'LineWidth',2,'Parent',ax); -0344 end -0345 % find approx. TLGM amplitude -0346 amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); -0347 stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... -0348 'LineWidth',2,'Tag','TLGM','Parent',ax); -0349 -0350 % y-limits -0351 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); -0352 % y-label -0353 set(get(ax,'YLabel'),'String',ylab2); -0354 end -0355 -0356 % x-limits -0357 ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me))); -0358 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0359 % x-label -0360 set(get(ax,'XLabel'),'String',xlstring); -0361 % grid -0362 grid(ax,'on'); -0363 end -0364 -0365 %% PSD -0366 % PSD axis -0367 ax = gui.axes_handles.psd; -0368 clearSingleAxis(ax); -0369 hold(ax,'on'); -0370 set(gui.cm_handles.axes_psd_view,'Enable','on'); -0371 -0372 % x-axis label -0373 switch data.process.timescale -0374 case 's' -0375 xlstring = 'equiv. pore size [m]'; -0376 case 'ms' -0377 xlstring = 'equiv. pore size [mm]'; -0378 end -0379 -0380 rho = data.param.rho/1e6; % surface relaxivity [m/s] -0381 a = data.param.a; % geometry parameter -0382 -0383 switch data.invstd.invtype -0384 case 'mono' -0385 switch nmrproc.T1T2 -0386 case 'T1' -0387 T = invstd.T1; -0388 case 'T2' -0389 T = invstd.T2; -0390 end -0391 -0392 stem(T.*rho.*a,invstd.E0,'o-','Color',col.FIT,'LineWidth',2,'Parent',ax); -0393 -0394 % limits -0395 ticks = floor(log10(min(T.*rho.*a)))-2 :1: ceil(log10(max(T.*rho.*a)))+2; -0396 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0397 set(ax,'YScale','lin','YLim',[0 invstd.E0*1.05]); -0398 % labels -0399 set(get(ax,'XLabel'),'String',xlstring); -0400 set(get(ax,'YLabel'),'String','initial amplitude E0'); -0401 % grid -0402 grid(ax,'on'); -0403 -0404 case 'free' -0405 mymark = {'o-','+-','s-','d-','x-'}; -0406 mycols = [0.8941 0.1020 0.1098;0.3020 0.6863 0.2902; -0407 0.2157 0.4941 0.7216;0.5961 0.3059 0.6392;0.6510 0.3373 0.1569]; -0408 switch nmrproc.T1T2 -0409 case 'T1' -0410 T = invstd.T1; -0411 case 'T2' -0412 T = invstd.T2; -0413 end -0414 -0415 lgdstr = cell(1,1); -0416 for i = 1:data.invstd.freeDT -0417 stem(T(i).*rho.*a,invstd.E0(i),mymark{i},'Color',mycols(i,:),'LineWidth',2,'Parent',ax); -0418 lgdstr{i} = ['T',num2str(i)]; -0419 end -0420 -0421 % limits -0422 ticks = floor(log10(min(T.*rho.*a)))-2 :1: ceil(log10(max(T.*rho.*a)))+2; -0423 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0424 set(ax,'YScale','lin','YLim',[0 max(invstd.E0)*1.05]); -0425 % labels -0426 set(get(ax,'XLabel'),'String',xlstring); -0427 set(get(ax,'YLabel'),'String','individual amplitudes Ex [-]'); -0428 % grid -0429 grid(ax,'on'); -0430 -0431 case {'LU','NNLS'} -0432 % very basic RTD to PSD conversion -0433 requiv = invstd.T1T2me.*rho.*a; -0434 Rlgm = invstd.Tlgm.*rho.*a; -0435 -0436 switch data.info.PSDflag -0437 case 'freq' -0438 plot(requiv,F,'o-','Color',col.FIT,... -0439 'LineWidth',2,'Parent',ax); -0440 % find approx. RLGM amplitude -0441 amp = findApproxTlgmAmplitude(requiv,F,Rlgm); -0442 stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); -0443 -0444 % y-limits -0445 set(ax,'YScale','lin','YLim',ylims); -0446 % y-label -0447 set(get(ax,'YLabel'),'String',ylab1); -0448 -0449 case 'cum' -0450 plot(requiv,cumsum(F),'o-','Color',col.FIT,... -0451 'LineWidth',2,'Parent',ax); -0452 % find approx. RLGM amplitude -0453 amp = findApproxTlgmAmplitude(requiv,cumsum(F),Rlgm); -0454 stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); -0455 -0456 % y-limits -0457 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); -0458 % y-label -0459 set(get(ax,'YLabel'),'String',ylab2); -0460 end +0284 switch data.info.RTDflag +0285 case 'freq' +0286 if hasUncert +0287 % plot uncertainty models +0288 f_max = 0; +0289 FDIST = uncert.interp_f; +0290 % scaling +0291 FDIST = (data.invstd.porosity*100).*FDIST./sum(F0); +0292 +0293 switch data.info.RTDuncert +0294 case 'lines' +0295 f_max = max([ylims(2) max(FDIST(:))]); +0296 % need to plot transpose of FDIST because 'x' +0297 % is a column vector otherwise plot goes +0298 % bananas if numel(x) = #models +0299 plot(invstd.T1T2me,FDIST(1,:)','-','Color',[0.5 0.5 0.5],... +0300 'LineWidth',1,'DisplayName','uncert models',... +0301 'Parent',ax); +0302 plot(invstd.T1T2me,FDIST(2:end,:)','-','Color',[0.5 0.5 0.5],... +0303 'LineWidth',1,'HandleVisibility','off',... +0304 'Tag','infolines','Parent',ax); +0305 case 'patch' +0306 % get mean and std of all uncert models +0307 mean_f = mean(FDIST); +0308 std_f = std(FDIST); +0309 +0310 % patch lower and upper bounds +0311 patch_f_std1 = [mean_f+std_f;mean_f-std_f]; +0312 patch_f_std2 = [mean_f+2*std_f;mean_f-2*std_f]; +0313 patch_f_std3 = [mean_f+3*std_f;mean_f-3*std_f]; +0314 patch_f_std1(patch_f_std1<0) = 0; +0315 patch_f_std2(patch_f_std2<0) = 0; +0316 patch_f_std3(patch_f_std3<0) = 0; +0317 f_max = max([ylims(2) max(patch_f_std1)... +0318 max(patch_f_std2) max(patch_f_std3)]); +0319 +0320 % draw all three patches on top of each other +0321 verts = [invstd.T1T2me patch_f_std3(2,:)';.... +0322 flipud(invstd.T1T2me) flipud(patch_f_std3(1,:)')]; +0323 faces = 1:1:size(verts,1); +0324 patch('Faces',faces,'Vertices',verts,... +0325 'FaceColor',[0.6 0.6 0.6],... +0326 'FaceAlpha',0.75,'EdgeColor','none',... +0327 'DisplayName','mean (3*std)','Parent',ax); +0328 verts = [invstd.T1T2me patch_f_std2(2,:)';... +0329 flipud(invstd.T1T2me) flipud(patch_f_std2(1,:)')]; +0330 faces = 1:1:size(verts,1); +0331 patch('Faces',faces,'Vertices',verts,... +0332 'FaceColor',[0.4 0.4 0.4],... +0333 'FaceAlpha',0.75,'EdgeColor','none',... +0334 'DisplayName','mean (2*std)','Parent',ax); +0335 verts = [invstd.T1T2me patch_f_std1(2,:)';... +0336 flipud(invstd.T1T2me) flipud(patch_f_std1(1,:)')]; +0337 faces = 1:1:size(verts,1); +0338 patch('Faces',faces,'Vertices',verts,... +0339 'FaceColor',[0.2 0.2 0.2],... +0340 'FaceAlpha',0.75,'EdgeColor','none',... +0341 'DisplayName','mean (std)','Parent',ax); +0342 end +0343 % adjust y-limits +0344 ylims(2) = max([ylims(2) max(f_max)*1.05]); +0345 end +0346 +0347 % plot total RTD +0348 plot(invstd.T1T2me,F,'-','Color',col.FIT,... +0349 'DisplayName','fit','LineWidth',2,'Parent',ax); +0350 % plot individual RTDs +0351 for i = 1:length(invstd.x)/3 +0352 plot(invstd.T1T2me,dist(i,:),'--','Color',mycols(i,:),... +0353 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); +0354 end +0355 % find approx. TLGM amplitude +0356 amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); +0357 stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... +0358 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); +0359 +0360 % y-limits +0361 set(ax,'YScale','lin','YLim',ylims); +0362 % y-label +0363 set(get(ax,'YLabel'),'String',ylab1); +0364 % legend +0365 legend(ax,'Location','NorthEast'); +0366 +0367 case 'cum' +0368 % in the case of the cumulative plot, no uncertainty is +0369 % shown +0370 plot(invstd.T1T2me,cumsum(F),'-','Color',col.FIT,... +0371 'DisplayName','fit','LineWidth',2,'Parent',ax); +0372 for i = 1:length(invstd.x)/3 +0373 plot(invstd.T1T2me,cumsum(dist(i,:)),'--','Color',mycols(i,:),... +0374 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); +0375 end +0376 % find approx. TLGM amplitude +0377 amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); +0378 stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... +0379 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); +0380 +0381 % y-limits +0382 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); +0383 % y-label +0384 set(get(ax,'YLabel'),'String',ylab2); +0385 end +0386 +0387 % x-limits +0388 ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me))); +0389 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0390 % x-label +0391 set(get(ax,'XLabel'),'String',xlstring); +0392 % grid +0393 grid(ax,'on'); +0394 end +0395 +0396 %% PSD +0397 % PSD axis +0398 ax = gui.axes_handles.psd; +0399 clearSingleAxis(ax); +0400 hold(ax,'on'); +0401 set(gui.cm_handles.axes_psd_view,'Enable','on'); +0402 +0403 % x-axis label +0404 switch data.process.timescale +0405 case 's' +0406 xlstring = 'equiv. pore size [m]'; +0407 case 'ms' +0408 xlstring = 'equiv. pore size [mm]'; +0409 end +0410 +0411 rho = data.param.rho/1e6; % surface relaxivity [m/s] +0412 a = data.param.a; % geometry parameter +0413 +0414 switch data.invstd.invtype +0415 case 'mono' +0416 switch nmrproc.T1T2 +0417 case 'T1' +0418 T = invstd.T1; +0419 case 'T2' +0420 T = invstd.T2; +0421 end +0422 +0423 stem(T.*rho.*a,invstd.E0,'o-','Color',col.FIT,'LineWidth',2,'Parent',ax); +0424 +0425 % limits +0426 ticks = floor(log10(min(T.*rho.*a)))-2 :1: ceil(log10(max(T.*rho.*a)))+2; +0427 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0428 set(ax,'YScale','lin','YLim',[0 invstd.E0*1.05]); +0429 % labels +0430 set(get(ax,'XLabel'),'String',xlstring); +0431 set(get(ax,'YLabel'),'String','initial amplitude E0'); +0432 % grid +0433 grid(ax,'on'); +0434 +0435 case 'free' +0436 mymark = {'o-','+-','s-','d-','x-'}; +0437 mycols = [0.8941 0.1020 0.1098;0.3020 0.6863 0.2902; +0438 0.2157 0.4941 0.7216;0.5961 0.3059 0.6392;0.6510 0.3373 0.1569]; +0439 switch nmrproc.T1T2 +0440 case 'T1' +0441 T = invstd.T1; +0442 case 'T2' +0443 T = invstd.T2; +0444 end +0445 +0446 lgdstr = cell(1,1); +0447 for i = 1:data.invstd.freeDT +0448 stem(T(i).*rho.*a,invstd.E0(i),mymark{i},'Color',mycols(i,:),'LineWidth',2,'Parent',ax); +0449 lgdstr{i} = ['T',num2str(i)]; +0450 end +0451 +0452 % limits +0453 ticks = floor(log10(min(T.*rho.*a)))-2 :1: ceil(log10(max(T.*rho.*a)))+2; +0454 set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0455 set(ax,'YScale','lin','YLim',[0 max(invstd.E0)*1.05]); +0456 % labels +0457 set(get(ax,'XLabel'),'String',xlstring); +0458 set(get(ax,'YLabel'),'String','individual amplitudes Ex [-]'); +0459 % grid +0460 grid(ax,'on'); 0461 -0462 % x-limits -0463 ticks = floor(log10(min(requiv))) :1: ceil(log10(max(requiv))); -0464 % set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0465 set(ax,'XScale','log','XLim',[min(requiv) max(requiv)],'XTick',10.^ticks); -0466 % x-label -0467 set(get(ax,'XLabel'),'String',xlstring); -0468 % grid -0469 grid(ax,'on'); -0470 -0471 case {'MUMO'} -0472 % very basic RTD to PSD conversion -0473 requiv = invstd.T1T2me.*rho.*a; -0474 Rlgm = invstd.Tlgm.*rho.*a; -0475 -0476 switch data.info.PSDflag -0477 case 'freq' -0478 if isfield(data.results.invstd,'uncert') -0479 verts = [requiv f_min'; flipud(requiv) flipud(f_max')]; -0480 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -0481 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); -0482 % adjust y-limits -0483 ylims(2) = max([ylims(2) max(f_max)*1.05]); -0484 end -0485 plot(requiv,F,'-','Color',col.FIT,... -0486 'LineWidth',2,'Parent',ax); -0487 for i = 1:length(invstd.x)/3 -0488 plot(requiv,dist(i,:),'--','Color',mycols(i,:),... -0489 'LineWidth',2,'Parent',ax); -0490 end -0491 % find approx. RLGM amplitude -0492 amp = findApproxTlgmAmplitude(requiv,F,Rlgm); -0493 stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); -0494 -0495 % y-limits -0496 set(ax,'YScale','lin','YLim',ylims); -0497 % y-label -0498 set(get(ax,'YLabel'),'String',ylab1); -0499 -0500 case 'cum' -0501 if isfield(data.results.invstd,'uncert') -0502 verts = [requiv cumsum(F)-f_min'; flipud(requiv) flipud(cumsum(F)+f_max')]; -0503 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -0504 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); -0505 end -0506 plot(requiv,cumsum(F),'-','Color',col.FIT,... -0507 'LineWidth',2,'Parent',ax); -0508 for i = 1:length(invstd.x)/3 -0509 plot(requiv,cumsum(dist(i,:)),'--','Color',mycols(i,:),... -0510 'LineWidth',2,'Parent',ax); -0511 end -0512 % find approx. RLGM amplitude -0513 amp = findApproxTlgmAmplitude(requiv,cumsum(F),Rlgm); -0514 stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); -0515 -0516 % y-limits -0517 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); -0518 % y-label -0519 set(get(ax,'YLabel'),'String',ylab2); -0520 end -0521 -0522 % x-limits -0523 ticks = floor(log10(min(requiv))) :1: ceil(log10(max(requiv))); -0524 % set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); -0525 set(ax,'XScale','log','XLim',[min(requiv) max(requiv)],'XTick',10.^ticks); -0526 % x-label -0527 set(get(ax,'XLabel'),'String',xlstring); -0528 % grid -0529 grid(ax,'on'); -0530 end -0531 -0532 % show CBW and diffusion regime lines -0533 updatePlotsDistributionInfo; -0534 end -0535 -0536 end -0537 -0538 %% -0539 function amp = findApproxTlgmAmplitude(t,f,TLGM) -0540 -0541 if isnan(TLGM) -0542 amp = NaN; -0543 else -0544 index = find(abs(t-TLGM)==min(abs(t-TLGM))); -0545 amp = interp1(t(index-1:index+1),f(index-1:index+1),TLGM); -0546 end -0547 -0548 end -0549 -0550 %------------- END OF CODE -------------- -0551 -0552 %% License: -0553 % MIT License -0554 % -0555 % Copyright (c) 2018 Thomas Hiller -0556 % -0557 % Permission is hereby granted, free of charge, to any person obtaining a copy -0558 % of this software and associated documentation files (the "Software"), to deal -0559 % in the Software without restriction, including without limitation the rights -0560 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0561 % copies of the Software, and to permit persons to whom the Software is -0562 % furnished to do so, subject to the following conditions: -0563 % -0564 % The above copyright notice and this permission notice shall be included in all -0565 % copies or substantial portions of the Software. -0566 % -0567 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0568 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0569 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0570 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0571 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0572 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0573 % SOFTWARE. +0462 case {'LU','NNLS'} +0463 % very basic RTD to PSD conversion +0464 requiv = invstd.T1T2me.*rho.*a; +0465 Rlgm = invstd.Tlgm.*rho.*a; +0466 +0467 switch data.info.PSDflag +0468 case 'freq' +0469 plot(requiv,F,'o-','Color',col.FIT,... +0470 'DisplayName','fit','LineWidth',2,'Parent',ax); +0471 % find approx. RLGM amplitude +0472 amp = findApproxTlgmAmplitude(requiv,F,Rlgm); +0473 stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); +0474 +0475 % y-limits +0476 set(ax,'YScale','lin','YLim',ylims); +0477 % y-label +0478 set(get(ax,'YLabel'),'String',ylab1); +0479 +0480 case 'cum' +0481 plot(requiv,cumsum(F),'o-','Color',col.FIT,... +0482 'DisplayName','fit','LineWidth',2,'Parent',ax); +0483 % find approx. RLGM amplitude +0484 amp = findApproxTlgmAmplitude(requiv,cumsum(F),Rlgm); +0485 stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); +0486 +0487 % y-limits +0488 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); +0489 % y-label +0490 set(get(ax,'YLabel'),'String',ylab2); +0491 end +0492 +0493 % x-limits +0494 ticks = floor(log10(min(requiv))) :1: ceil(log10(max(requiv))); +0495 % set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0496 set(ax,'XScale','log','XLim',[min(requiv) max(requiv)],'XTick',10.^ticks); +0497 % x-label +0498 set(get(ax,'XLabel'),'String',xlstring); +0499 % grid +0500 grid(ax,'on'); +0501 +0502 case {'MUMO'} +0503 % very basic RTD to PSD conversion +0504 requiv = invstd.T1T2me.*rho.*a; +0505 Rlgm = invstd.Tlgm.*rho.*a; +0506 +0507 switch data.info.PSDflag +0508 case 'freq' +0509 plot(requiv,F,'-','Color',col.FIT,... +0510 'DisplayName','fit','LineWidth',2,'Parent',ax); +0511 for i = 1:length(invstd.x)/3 +0512 plot(requiv,dist(i,:),'--','Color',mycols(i,:),... +0513 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); +0514 end +0515 % find approx. RLGM amplitude +0516 amp = findApproxTlgmAmplitude(requiv,F,Rlgm); +0517 stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); +0518 +0519 % y-limits +0520 set(ax,'YScale','lin','YLim',ylims); +0521 % y-label +0522 set(get(ax,'YLabel'),'String',ylab1); +0523 +0524 case 'cum' +0525 plot(requiv,cumsum(F),'-','Color',col.FIT,... +0526 'DisplayName','fit','LineWidth',2,'Parent',ax); +0527 for i = 1:length(invstd.x)/3 +0528 plot(requiv,cumsum(dist(i,:)),'--','Color',mycols(i,:),... +0529 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); +0530 end +0531 % find approx. RLGM amplitude +0532 amp = findApproxTlgmAmplitude(requiv,cumsum(F),Rlgm); +0533 stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); +0534 +0535 % y-limits +0536 set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); +0537 % y-label +0538 set(get(ax,'YLabel'),'String',ylab2); +0539 end +0540 +0541 % x-limits +0542 ticks = floor(log10(min(requiv))) :1: ceil(log10(max(requiv))); +0543 % set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +0544 set(ax,'XScale','log','XLim',[min(requiv) max(requiv)],'XTick',10.^ticks); +0545 % x-label +0546 set(get(ax,'XLabel'),'String',xlstring); +0547 % grid +0548 grid(ax,'on'); +0549 end +0550 +0551 % show CBW and diffusion regime lines +0552 updatePlotsDistributionInfo; +0553 end +0554 +0555 end +0556 +0557 %% +0558 function amp = findApproxTlgmAmplitude(t,f,TLGM) +0559 +0560 if isnan(TLGM) +0561 amp = NaN; +0562 else +0563 index = find(abs(t-TLGM)==min(abs(t-TLGM))); +0564 amp = interp1(t(index-1:index+1),f(index-1:index+1),TLGM); +0565 end +0566 +0567 end +0568 +0569 %------------- END OF CODE -------------- +0570 +0571 %% License: +0572 % MIT License +0573 % +0574 % Copyright (c) 2018 Thomas Hiller +0575 % +0576 % Permission is hereby granted, free of charge, to any person obtaining a copy +0577 % of this software and associated documentation files (the "Software"), to deal +0578 % in the Software without restriction, including without limitation the rights +0579 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0580 % copies of the Software, and to permit persons to whom the Software is +0581 % furnished to do so, subject to the following conditions: +0582 % +0583 % The above copyright notice and this permission notice shall be included in all +0584 % copies or substantial portions of the Software. +0585 % +0586 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0587 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0588 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0589 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0590 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0591 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0592 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/updatePlotsDistributionInfo.html b/doc/nucleus/functions/interface/updatePlotsDistributionInfo.html index 90de642..b0eb868 100644 --- a/doc/nucleus/functions/interface/updatePlotsDistributionInfo.html +++ b/doc/nucleus/functions/interface/updatePlotsDistributionInfo.html @@ -125,9 +125,9 @@

    SOURCE CODE ^'XLim'); 0056 yy = get(ax,'YLim'); 0057 line([CBW CBW],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0058 'LineWidth',2,'Parent',ax,'Tag','infolines'); +0058 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); 0059 line([BVI BVI],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0060 'LineWidth',2,'Parent',ax,'Tag','infolines'); +0060 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); 0061 0062 if CBW > xx(1) 0063 xx1 = mean([log10(xx(1)) log10(CBW)]); @@ -173,9 +173,9 @@

    SOURCE CODE ^'XLim'); 0104 yy = get(ax,'YLim'); 0105 line([fast fast],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0106 'LineWidth',2,'Parent',ax,'Tag','infolines'); +0106 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); 0107 line([slow slow],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0108 'LineWidth',2,'Parent',ax,'Tag','infolines'); +0108 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); 0109 0110 if fast > xx(1) 0111 xx2 = mean([log10(xx(1)) log10(fast)]); diff --git a/doc/nucleus/functions/interface/updatePlotsJointInversion.html b/doc/nucleus/functions/interface/updatePlotsJointInversion.html index b80ef6e..dc25739 100644 --- a/doc/nucleus/functions/interface/updatePlotsJointInversion.html +++ b/doc/nucleus/functions/interface/updatePlotsJointInversion.html @@ -111,7 +111,7 @@

    SOURCE CODE ^% proceed only if there is data -0043 if isfield(data.results,'invjoint') +0043 if isfield(data,'results') && isfield(data.results,'invjoint') 0044 % get al relevant data 0045 invjoint = data.results.invjoint; 0046 nmr = invjoint.idata.nmr; diff --git a/doc/nucleus/functions/interface/updatePlotsSignal.html b/doc/nucleus/functions/interface/updatePlotsSignal.html index 6b68f54..b7cfeba 100644 --- a/doc/nucleus/functions/interface/updatePlotsSignal.html +++ b/doc/nucleus/functions/interface/updatePlotsSignal.html @@ -62,7 +62,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=beautifyAxes can be used to globally change the general appearance of axes
  • clearSingleAxis clears an individual axis
  • getColorIndex exports graphics from both GUIs into various formats
  • This function is called by: +
  • onContextAxisLogLin changes the label of an axis context menu which allows to
  • onContextPlotsRTD checks the label of the distribution axis context menu
  • onEditCPSTable updates entries made in the CPS table of NUCLEUSinv
  • onEditValue updates all edit field values, checks for wrong inputs and
  • onListboxData handles the calls from the context menu of the data
  • onMenuJointInversion handles the call from the menu that activates / deactivates
  • onRadioGates selects the re-sampling / gating method ("log", "lin" or "none")
  • onRadioNormalize selects whether to normalize a NMR signal to 1
  • onRadioTimescale selects whether the time scale should be "s" or "ms"
  • UncertView is an extra subGUI to show results of the uncertainty
  • changeColorTheme changes the color theme of the calling figure
  • clearInversion removes inversion results from the internal data structure
  • runInversionStd controls the standard inversion process to invert a
  • runUncertaintyCalculation caluclates inverison statistics in some kind of
  • @@ -110,88 +110,88 @@

    SOURCE CODE ^'Checked'),'on'); 0041 0042 % proceed if there is data -0043 if isfield(data.results,'nmrraw') && isfield(data.results,'nmrproc') -0044 % get NMR data -0045 nmrraw = data.results.nmrraw; -0046 nmrproc = data.results.nmrproc; -0047 if isfield(data.results,'invstd') -0048 invstd = data.results.invstd; -0049 end -0050 %% RAW data axis -0051 ax = gui.axes_handles.raw; -0052 axI = gui.axes_handles.imag; -0053 clearSingleAxis(ax); -0054 clearSingleAxis(axI); -0055 hold(ax,'on'); -0056 hold(axI,'on'); -0057 -0058 % data -0059 if isreal(nmrraw.s) -0060 plot(nmrraw.t,real(nmrraw.s),'Color',col.RE,'Parent',ax); -0061 else -0062 plot(nmrraw.t,real(nmrraw.s),'Color',col.RE,'Parent',ax); -0063 plot(nmrraw.t,imag(nmrraw.s),'Color',col.IM,'LineWidth',1,'Parent',axI); -0064 end -0065 -0066 % limits & ticks -0067 loglinx = get(gui.cm_handles.axes_raw_xaxis,'Label'); -0068 switch loglinx -0069 case 'x-axis -> lin' % log axes -0070 ticks = floor(min(log10(nmrraw.t(nmrraw.t>0)))):1:ceil(log10(nmrraw.t(end))); -0071 set(ax,'XScale','log','XLim',[10^(ticks(1)) nmrraw.t(end)],... -0072 'XTick',10.^ticks); -0073 case 'x-axis -> log' % lin axes -0074 set(ax,'XScale','lin','XLim',[nmrproc.echotime nmrraw.t(end)],... -0075 'XTickMode','auto'); -0076 end -0077 logliny = get(gui.cm_handles.axes_raw_yaxis,'Label'); -0078 switch nmrproc.T1T2 -0079 case 'T1' -0080 switch logliny -0081 case 'y-axis -> lin' % log axes -0082 ticks = floor(min(log10(nmrraw.s(nmrraw.s>0))))-1:1:ceil(log10(nmrraw.s(end))); -0083 set(ax,'YScale','log','YLim',[10^(ticks(1)) 10^(ticks(end))],.... -0084 'YTick',10.^ticks); -0085 case 'y-axis -> log' % lin axes -0086 set(ax,'YScale','lin','YLim',[-0.05 max(real(nmrraw.s))*1.05],... -0087 'YTickMode','auto'); -0088 end -0089 case 'T2' -0090 ymin = min([min(real(nmrraw.s)) min(imag(nmrraw.s))]); -0091 ymax = max(real(nmrraw.s)); -0092 if isfield(data.results,'invstd') -0093 ymax = max([ymax max(data.results.invstd.fit_s)]); -0094 end -0095 switch logliny -0096 case 'y-axis -> lin' % log axes -0097 ticks = floor(log10(ymin))-1 :1: ceil(log10(ymax)); -0098 set(ax,'YScale','log','YLim',[10^(ticks(1)) ymax*1.05],... -0099 'YTick',10.^ticks); -0100 case 'y-axis -> log' % lin axes -0101 set(ax,'YScale','lin','YLim',[ymin ymax*1.05],... -0102 'YTickMode','auto'); -0103 end -0104 end -0105 -0106 % labels -0107 if strcmp(data.process.timescale,'s') -0108 set(get(ax,'XLabel'),'String','time [s]'); -0109 else -0110 set(get(ax,'XLabel'),'String','time [ms]'); -0111 end -0112 if strcmp(nmrproc.T1T2,'T2') && ~isreal(nmrraw.s) -0113 set(get(ax,'YLabel'),'String','\Reeal'); -0114 else -0115 set(get(ax,'YLabel'),'String','amplitude [a.u.]'); -0116 end -0117 -0118 % imag part -0119 if ~isreal(nmrraw.s) -0120 xlims = get(ax,'XLim'); -0121 line(xlims,[0 0],'LineStyle','--','LineWidth',1,'Color','k','Parent',axI); -0122 imag_mean = mean(imag(nmrraw.s)); -0123 imag_std = std(imag(nmrraw.s)); -0124 % yticks = linspace(min(imag(nmrraw.s)),max(imag(nmrraw.s)),3); +0043 if isfield(data,'results') && isfield(data.results,'nmrraw') &&... +0044 isfield(data.results,'nmrproc') +0045 % get NMR data +0046 nmrraw = data.results.nmrraw; +0047 nmrproc = data.results.nmrproc; +0048 if isfield(data.results,'invstd') +0049 invstd = data.results.invstd; +0050 end +0051 %% RAW data axis +0052 ax = gui.axes_handles.raw; +0053 axI = gui.axes_handles.imag; +0054 clearSingleAxis(ax); +0055 clearSingleAxis(axI); +0056 hold(ax,'on'); +0057 hold(axI,'on'); +0058 +0059 % data +0060 if isreal(nmrraw.s) +0061 plot(nmrraw.t,real(nmrraw.s),'Color',col.RE,'Parent',ax); +0062 else +0063 plot(nmrraw.t,real(nmrraw.s),'Color',col.RE,'Parent',ax); +0064 plot(nmrraw.t,imag(nmrraw.s),'Color',col.IM,'LineWidth',1,'Parent',axI); +0065 end +0066 +0067 % limits & ticks +0068 loglinx = get(gui.cm_handles.axes_raw_xaxis,'Label'); +0069 switch loglinx +0070 case 'x-axis -> lin' % log axes +0071 ticks = floor(min(log10(nmrraw.t(nmrraw.t>0)))):1:ceil(log10(nmrraw.t(end))); +0072 set(ax,'XScale','log','XLim',[10^(ticks(1)) nmrraw.t(end)],... +0073 'XTick',10.^ticks); +0074 case 'x-axis -> log' % lin axes +0075 set(ax,'XScale','lin','XLim',[nmrproc.echotime nmrraw.t(end)],... +0076 'XTickMode','auto'); +0077 end +0078 logliny = get(gui.cm_handles.axes_raw_yaxis,'Label'); +0079 switch nmrproc.T1T2 +0080 case 'T1' +0081 switch logliny +0082 case 'y-axis -> lin' % log axes +0083 ticks = floor(min(log10(nmrraw.s(nmrraw.s>0))))-1:1:ceil(log10(nmrraw.s(end))); +0084 set(ax,'YScale','log','YLim',[10^(ticks(1)) 10^(ticks(end))],.... +0085 'YTick',10.^ticks); +0086 case 'y-axis -> log' % lin axes +0087 set(ax,'YScale','lin','YLim',[-0.05 max(real(nmrraw.s))*1.05],... +0088 'YTickMode','auto'); +0089 end +0090 case 'T2' +0091 ymin = min([min(real(nmrraw.s)) min(imag(nmrraw.s))]); +0092 ymax = max(real(nmrraw.s)); +0093 if isfield(data.results,'invstd') +0094 ymax = max([ymax max(data.results.invstd.fit_s)]); +0095 end +0096 switch logliny +0097 case 'y-axis -> lin' % log axes +0098 ticks = floor(log10(ymin))-1 :1: ceil(log10(ymax)); +0099 set(ax,'YScale','log','YLim',[10^(ticks(1)) ymax*1.05],... +0100 'YTick',10.^ticks); +0101 case 'y-axis -> log' % lin axes +0102 set(ax,'YScale','lin','YLim',[ymin ymax*1.05],... +0103 'YTickMode','auto'); +0104 end +0105 end +0106 +0107 % labels +0108 if strcmp(data.process.timescale,'s') +0109 set(get(ax,'XLabel'),'String','time [s]'); +0110 else +0111 set(get(ax,'XLabel'),'String','time [ms]'); +0112 end +0113 if strcmp(nmrproc.T1T2,'T2') && ~isreal(nmrraw.s) +0114 set(get(ax,'YLabel'),'String','\Reeal'); +0115 else +0116 set(get(ax,'YLabel'),'String','amplitude [a.u.]'); +0117 end +0118 +0119 % imag part +0120 if ~isreal(nmrraw.s) +0121 xlims = get(ax,'XLim'); +0122 line(xlims,[0 0],'LineStyle','--','LineWidth',1,'Color','k','Parent',axI); +0123 imag_mean = mean(imag(nmrraw.s)); +0124 imag_std = std(imag(nmrraw.s)); 0125 yticks = [imag_mean-imag_std*2 0 imag_mean+imag_std*2]; 0126 ylim = [imag_mean-imag_std*3 imag_mean+imag_std*3]; 0127 set(axI,'XTickLabel','','YLim',ylim,'YTick',yticks,'YTickLabelMode','auto'); @@ -217,298 +217,348 @@

    SOURCE CODE ^% data 0149 switch data.invstd.invtype -0150 case {'MUMO'} -0151 if isfield(data.results,'invstd') && isfield(data.results.invstd,'uncert') -0152 % uncertainty patch created from min max of uncertainty -0153 % data -0154 s_min = data.results.invstd.uncert.interp_s_min; -0155 s_max = data.results.invstd.uncert.interp_s_max; -0156 t = data.results.invstd.uncert.interp_t; -0157 verts = [t(t>0) s_min(t>0); flipud(t(t>0)) flipud(s_max(t>0))]; -0158 faces = 1:1:size(verts,1); -0159 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -0160 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); -0161 end -0162 -0163 if isfield(data.results,'invstd') -0164 plot(nmrproc.t,nmrproc.s,'-','Color',col.RE,'LineWidth',1,'Parent',ax); -0165 plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,'Parent',ax); -0166 if nmrproc.noise > 0 -0167 plot(nmrproc.t,invstd.residual./nmrproc.e,'Color',col.IM,... -0168 'LineWidth',1,'Parent',axE); -0169 else -0170 plot(nmrproc.t,invstd.residual,'Color',col.IM,... -0171 'LineWidth',1,'Parent',axE); -0172 end -0173 else -0174 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,'Parent',ax); -0175 end -0176 otherwise -0177 if isfield(data.results,'invstd') -0178 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,'Parent',ax); -0179 plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,'Parent',ax); -0180 if nmrproc.noise > 0 -0181 plot(nmrproc.t,invstd.residual./nmrproc.e,'Color',col.IM,... -0182 'LineWidth',1,'Parent',axE); -0183 else -0184 plot(nmrproc.t,invstd.residual,'Color',col.IM,... -0185 'LineWidth',1,'Parent',axE); -0186 end -0187 else -0188 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,'Parent',ax); -0189 end -0190 end -0191 -0192 % limits & ticks -0193 xlimraw = get(gui.axes_handles.raw,'XLim'); -0194 loglinx = get(gui.cm_handles.axes_proc_xaxis,'Label'); -0195 switch loglinx -0196 case 'x-axis -> lin' % log axes -0197 ticks = floor(min(log10(nmrproc.t(nmrproc.t>0)))):1:ceil(log10(nmrproc.t(end))); -0198 set(ax,'XScale','log','XLim',xlimraw,'XTick',10.^ticks); -0199 case 'x-axis -> log' % lin axes -0200 set(ax,'XScale','lin','XLim',xlimraw,'XTickMode','auto'); -0201 end -0202 logliny = get(gui.cm_handles.axes_proc_yaxis,'Label'); -0203 switch nmrproc.T1T2 -0204 case 'T1' -0205 ymin = min(real(nmrproc.s)); -0206 ymax = max(real(nmrproc.s)); -0207 if isfield(data.results,'invstd') -0208 ymin = min([ymin min(invstd.residual)]); -0209 ymax = max([ymax max(data.results.invstd.fit_s)]); -0210 end -0211 if ymin>0 -0212 ymin = ymin*0.8; -0213 else -0214 ymin = ymin*1.2; -0215 end -0216 switch logliny -0217 case 'y-axis -> lin' % log axes -0218 ticks = floor(min(log10(nmrproc.s(nmrproc.s>0))))-1:1:ceil(log10(nmrproc.s(end))); -0219 set(ax,'YScale','log','YLim',[10^(ticks(1)) 10^(ticks(end))],... -0220 'YTick',10.^ticks); -0221 case 'y-axis -> log' % lin axes -0222 set(ax,'YScale','lin','YLim',[ymin ymax*1.05],... -0223 'YTickMode','auto'); -0224 end -0225 case 'T2' -0226 ymin = min([min(real(nmrraw.s)) min(imag(nmrraw.s))]); -0227 ymax = max(real(nmrraw.s)); -0228 if isfield(data.results,'invstd') -0229 ymin = min([ymin min(invstd.residual)]); -0230 ymax = max([ymax max(data.results.invstd.fit_s)]); +0150 case {'LU','NNLS','MUMO'} +0151 if isfield(data.results,'invstd') +0152 if isfield(data.results.invstd,'uncert') +0153 uncert = data.results.invstd.uncert; +0154 t = uncert.interp_t; +0155 SDIST = uncert.interp_s; +0156 switch data.info.RTDuncert +0157 case 'lines' +0158 plot(t,SDIST(:,1),'-','Color',[0.5 0.5 0.5],... +0159 'LineWidth',1,... +0160 'DisplayName','uncert models','Parent',ax); +0161 plot(t,SDIST(:,2:end),'-','Color',[0.5 0.5 0.5],... +0162 'LineWidth',1,'HandleVisibility','off',... +0163 'Tag','infolines','Parent',ax); +0164 case 'patch' +0165 % uncertainty patch created from min max of uncertainty +0166 % data +0167 s_min = data.results.invstd.uncert.interp_s_min; +0168 s_max = data.results.invstd.uncert.interp_s_max; +0169 t = data.results.invstd.uncert.interp_t; +0170 verts = [t(t>0) s_min(t>0); flipud(t(t>0)) flipud(s_max(t>0))]; +0171 faces = 1:1:size(verts,1); +0172 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... +0173 'FaceAlpha',0.75,'EdgeColor','none',... +0174 'DisplayName','uncert','Parent',ax); +0175 end +0176 +0177 end +0178 if nmrproc.isgated +0179 plot(data.results.nmrraw.t,data.results.nmrraw.s,'o',... +0180 'Color',[0.64 0.64 0.64],'LineWidth',0.75,... +0181 'DisplayName','signal_{raw}','Parent',ax); +0182 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... +0183 'DisplayName','signal_{gated}','Parent',ax); +0184 else +0185 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... +0186 'DisplayName','signal','Parent',ax); +0187 end +0188 plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,... +0189 'DisplayName','fit','Parent',ax); +0190 if nmrproc.noise > 0 +0191 plot(nmrproc.t,invstd.residual./nmrproc.e,'Color',col.IM,... +0192 'LineWidth',1,'Parent',axE); +0193 else +0194 plot(nmrproc.t,invstd.residual,'Color',col.IM,... +0195 'LineWidth',1,'Parent',axE); +0196 end +0197 else +0198 if nmrproc.isgated +0199 plot(data.results.nmrraw.t,data.results.nmrraw.s,'o',... +0200 'Color',[0.64 0.64 0.64],'LineWidth',0.75,... +0201 'DisplayName','signal_{raw}','Parent',ax); +0202 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... +0203 'DisplayName','signal_{gated}','Parent',ax); +0204 else +0205 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... +0206 'DisplayName','signal','Parent',ax); +0207 end +0208 end +0209 +0210 otherwise % mono & free +0211 if nmrproc.isgated +0212 plot(data.results.nmrraw.t,data.results.nmrraw.s,'o',... +0213 'Color',[0.64 0.64 0.64],'LineWidth',0.75,... +0214 'DisplayName','signal_{raw}','Parent',ax); +0215 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,... +0216 'DisplayName','signal_{gated}','Parent',ax); +0217 else +0218 plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,... +0219 'DisplayName','signal','Parent',ax); +0220 end +0221 if isfield(data.results,'invstd') +0222 plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,... +0223 'DisplayName','fit','Parent',ax); +0224 if nmrproc.noise > 0 +0225 plot(nmrproc.t,invstd.residual./nmrproc.e,'Color',col.IM,... +0226 'LineWidth',1,'Parent',axE); +0227 else +0228 plot(nmrproc.t,invstd.residual,'Color',col.IM,... +0229 'LineWidth',1,'Parent',axE); +0230 end 0231 end -0232 switch logliny -0233 case 'y-axis -> lin' % log axes -0234 ticks = floor(log10(ymin))-1 :1: ceil(log10(ymax)); -0235 set(ax,'YScale','log','YLim',[10^(ticks(1)) ymax*1.1],... -0236 'YTick',10.^ticks); -0237 case 'y-axis -> log' % lin axes -0238 set(ax,'YScale','lin','YLim',[ymin ymax*1.1],... -0239 'YTickMode','auto'); -0240 end -0241 end -0242 if isfield(data.results,'invstd') -0243 ylims = get(ax,'YLim'); -0244 set(gui.axes_handles.raw,'YLim',ylims); -0245 end -0246 -0247 % labels -0248 if strcmp(data.process.timescale,'s') -0249 set(get(ax,'XLabel'),'String','time [s]'); -0250 else -0251 set(get(ax,'XLabel'),'String','time [ms]'); -0252 end -0253 set(get(ax,'YLabel'),'String','amplitude [a.u.]'); -0254 -0255 % legend -0256 if isfield(data.results,'invstd') -0257 if isfield(data.results,'invstd') && isfield(data.results.invstd,'uncert') -0258 lgdstr = {'uncert','signal','fit'}; -0259 else -0260 lgdstr = {'signal','fit'}; -0261 end -0262 % switch data.invstd.invtype -0263 % case {'MUMO','NNLS'} -0264 % otherwise -0265 % end -0266 switch nmrproc.T1T2 -0267 case 'T1' -0268 lgh = legend(ax,lgdstr,'Location','NorthWest',... -0269 'Tag','fitlegend','FontSize',10); -0270 case 'T2' -0271 lgh = legend(ax,lgdstr,'Location','NorthEast',... -0272 'Tag','fitlegend','FontSize',10); -0273 end -0274 set(lgh,'TextColor',gui.myui.colors.panelFG); -0275 end -0276 -0277 % grid -0278 grid(ax,'on'); -0279 -0280 %% residual plot -0281 if isfield(data.results,'invstd') -0282 col = gui.myui.colors.axisL; -0283 xlims = get(ax,'XLim'); -0284 line(xlims,[0 0],'LineStyle','--','LineWidth',1,'Color',col,'Parent',axE); -0285 if nmrproc.noise > 0 -0286 err_mean = mean(invstd.residual./nmrproc.e); -0287 err_std = std(invstd.residual./nmrproc.e); -0288 line(xlims,[err_mean-err_std err_mean-err_std],... -0289 'LineStyle','--','LineWidth',1,'Color','r','Parent',axE); -0290 line(xlims,[err_mean+err_std err_mean+err_std],... -0291 'LineStyle','--','LineWidth',1,'Color','r','Parent',axE); -0292 line(xlims,[-1 -1],'LineStyle','-.','LineWidth',1,... -0293 'Color',col,'Parent',axE); -0294 line(xlims,[1 1],'LineStyle','-.','LineWidth',1,... -0295 'Color',col,'Parent',axE); -0296 set(axE,'XTickLabel',''); -0297 set(axE,'YLim',[-2 2]); -0298 set(axE,'YTick',[-1 0 1],'YTickLabelMode','auto'); -0299 set(get(axE,'YLabel'),'String',{'noise';'weighted';'residuals'},... -0300 'FontWeight','normal'); -0301 else -0302 err_mean = mean(invstd.residual); -0303 err_std = std(invstd.residual); -0304 line(xlims,[err_mean-1*err_std err_mean-1*err_std],... -0305 'LineStyle','-.','LineWidth',1,'Color',col,'Parent',axE); -0306 line(xlims,[err_mean+1*err_std err_mean+1*err_std],... -0307 'LineStyle','-.','LineWidth',1,'Color',col,'Parent',axE); -0308 set(axE,'XTickLabel',''); -0309 set(axE,'YLim',[err_mean-3*err_std err_mean+3*err_std]); -0310 set(axE,'YTick',[err_mean-3*err_std 0 err_mean+3*err_std],... -0311 'YTickLabelMode','auto') -0312 set(get(axE,'YLabel'),'String','residuals',... -0313 'FontWeight','normal'); -0314 end -0315 -0316 switch loglinx -0317 case 'x-axis -> lin' % log axes -0318 set(axE,'XScale','log','XLim',xlims); -0319 case 'x-axis -> log' % lin axes -0320 set(axE,'XScale','lin','XLim',xlims); -0321 end -0322 end -0323 % finalize -0324 beautifyAxes(fig); -0325 end -0326 -0327 %% if joint inversion is activated all NMR signals are plotted into the -0328 % "ALL (joint)" panel - this is just a rough overview if no joint inversion -0329 % result is yet availabe -0330 if isjoint && ~isfield(data.results,'invjoint') && ... -0331 ~strcmp(data.invstd.regtype,'lcurve') -0332 -0333 ax = gui.axes_handles.all; -0334 clearSingleAxis(ax); -0335 -0336 INVdata = getappdata(fig,'INVdata'); -0337 -0338 nINV = size(INVdata,1); -0339 E0 = zeros(nINV,1); -0340 c = 0; -0341 invlevels = 0; -0342 for i = 1:nINV -0343 if isstruct(INVdata{i}) -0344 c = c + 1; -0345 invlevels(c) = i; %#ok<AGROW> -0346 E0(i,1) = sum(INVdata{i}.results.invstd.E0); -0347 end -0348 end -0349 -0350 % the pressure / saturation data -0351 table = data.pressure.table; -0352 -0353 if size(table,1) == 1 & invlevels ~= 0 %#ok<AND2> -0354 % apparently no CPS data was loaded but joint inversion is -0355 % activated ... so just plot the data -0356 if invlevels == 0 -0357 levels = []; -0358 else -0359 levels = invlevels; -0360 S = E0(invlevels)./max(E0(invlevels)); -0361 end -0362 else -0363 uselevel = cell2mat(table(:,1)); -0364 tablelevels = 1:size(table,1); -0365 tablelevels = tablelevels(uselevel); -0366 S = cell2mat(table(:,3)); -0367 % if numel(S)~=nINV -0368 % % S() -0369 % end -0370 [isin,levels] = ismember(invlevels,tablelevels); -0371 levels = tablelevels(levels(isin)); +0232 end +0233 +0234 % limits & ticks +0235 xlimraw = get(gui.axes_handles.raw,'XLim'); +0236 loglinx = get(gui.cm_handles.axes_proc_xaxis,'Label'); +0237 switch loglinx +0238 case 'x-axis -> lin' % log axes +0239 ticks = floor(min(log10(nmrproc.t(nmrproc.t>0)))):1:ceil(log10(nmrproc.t(end))); +0240 set(ax,'XScale','log','XLim',xlimraw,'XTick',10.^ticks); +0241 case 'x-axis -> log' % lin axes +0242 set(ax,'XScale','lin','XLim',xlimraw,'XTickMode','auto'); +0243 end +0244 xlims = xlimraw; +0245 switch nmrproc.T1T2 +0246 case 'T1' +0247 if isfield(data.results,'invstd') && isfield(data.results.invstd,'uncert') +0248 xlims(2) = max([xlimraw(2) max(data.results.invstd.uncert.interp_t)/2]); +0249 end +0250 set(ax,'XLim',xlims); +0251 set(gui.axes_handles.raw,'XLim',xlims); +0252 set(gui.axes_handles.imag,'XLim',xlims); +0253 case 'T2' +0254 end +0255 logliny = get(gui.cm_handles.axes_proc_yaxis,'Label'); +0256 switch nmrproc.T1T2 +0257 case 'T1' +0258 ymin = min(real(nmrproc.s)); +0259 ymax = max(real(nmrproc.s)); +0260 if isfield(data.results,'invstd') +0261 ymin = min([ymin min(invstd.residual)]); +0262 ymax = max([ymax max(data.results.invstd.fit_s)]); +0263 if isfield(data.results.invstd,'uncert') +0264 ymax = max([ymax max(data.results.invstd.uncert.interp_s(:))]); +0265 end +0266 end +0267 if ymin>0 +0268 ymin = ymin*0.8; +0269 else +0270 ymin = ymin*1.2; +0271 end +0272 switch logliny +0273 case 'y-axis -> lin' % log axes +0274 ticks = floor(min(log10(nmrproc.s(nmrproc.s>0))))-1:1:ceil(log10(nmrproc.s(end))); +0275 set(ax,'YScale','log','YLim',[10^(ticks(1)) 10^(ticks(end))],... +0276 'YTick',10.^ticks); +0277 case 'y-axis -> log' % lin axes +0278 set(ax,'YScale','lin','YLim',[ymin ymax*1.05],... +0279 'YTickMode','auto'); +0280 end +0281 case 'T2' +0282 ymin = min([min(real(nmrraw.s)) min(imag(nmrraw.s))]); +0283 ymax = max(real(nmrraw.s)); +0284 if isfield(data.results,'invstd') +0285 ymin = min([ymin min(invstd.residual)]); +0286 ymax = max([ymax max(data.results.invstd.fit_s)]); +0287 if isfield(data.results.invstd,'uncert') +0288 ymax = max([ymax max(data.results.invstd.uncert.interp_s(:))]); +0289 end +0290 end +0291 switch logliny +0292 case 'y-axis -> lin' % log axes +0293 ticks = floor(log10(ymin))-1 :1: ceil(log10(ymax)); +0294 set(ax,'YScale','log','YLim',[10^(ticks(1)) ymax*1.1],... +0295 'YTick',10.^ticks); +0296 case 'y-axis -> log' % lin axes +0297 set(ax,'YScale','lin','YLim',[ymin ymax*1.1],... +0298 'YTickMode','auto'); +0299 end +0300 end +0301 if isfield(data.results,'invstd') +0302 ylims = get(ax,'YLim'); +0303 set(gui.axes_handles.raw,'YLim',ylims); +0304 end +0305 +0306 % labels +0307 if strcmp(data.process.timescale,'s') +0308 set(get(ax,'XLabel'),'String','time [s]'); +0309 else +0310 set(get(ax,'XLabel'),'String','time [ms]'); +0311 end +0312 set(get(ax,'YLabel'),'String','amplitude [a.u.]'); +0313 +0314 % legend +0315 if isfield(data.results,'invstd') +0316 switch nmrproc.T1T2 +0317 case 'T1' +0318 lgh = legend(ax,'Location','NorthWest',... +0319 'Tag','fitlegend','FontSize',10); +0320 case 'T2' +0321 lgh = legend(ax,'Location','NorthEast',... +0322 'Tag','fitlegend','FontSize',10); +0323 end +0324 set(lgh,'TextColor',gui.myui.colors.panelFG); +0325 end +0326 +0327 % grid +0328 grid(ax,'on'); +0329 +0330 %% residual plot +0331 if isfield(data.results,'invstd') +0332 col = gui.myui.colors.axisL; +0333 xlims = get(ax,'XLim'); +0334 line(xlims,[0 0],'LineStyle','--','LineWidth',1,'Color',col,'Parent',axE); +0335 if nmrproc.noise > 0 +0336 err_mean = mean(invstd.residual./nmrproc.e); +0337 err_std = std(invstd.residual./nmrproc.e); +0338 line(xlims,[err_mean-err_std err_mean-err_std],... +0339 'LineStyle','--','LineWidth',1,'Color','r','Parent',axE); +0340 line(xlims,[err_mean+err_std err_mean+err_std],... +0341 'LineStyle','--','LineWidth',1,'Color','r','Parent',axE); +0342 line(xlims,[-1 -1],'LineStyle','-.','LineWidth',1,... +0343 'Color',col,'Parent',axE); +0344 line(xlims,[1 1],'LineStyle','-.','LineWidth',1,... +0345 'Color',col,'Parent',axE); +0346 set(axE,'XTickLabel',''); +0347 set(axE,'YLim',[-2 2]); +0348 set(axE,'YTick',[-1 0 1],'YTickLabelMode','auto'); +0349 set(get(axE,'YLabel'),'String',{'noise';'weighted';'residuals'},... +0350 'FontWeight','normal'); +0351 else +0352 err_mean = mean(invstd.residual); +0353 err_std = std(invstd.residual); +0354 line(xlims,[err_mean-1*err_std err_mean-1*err_std],... +0355 'LineStyle','-.','LineWidth',1,'Color',col,'Parent',axE); +0356 line(xlims,[err_mean+1*err_std err_mean+1*err_std],... +0357 'LineStyle','-.','LineWidth',1,'Color',col,'Parent',axE); +0358 set(axE,'XTickLabel',''); +0359 set(axE,'YLim',[err_mean-3*err_std err_mean+3*err_std]); +0360 set(axE,'YTick',[err_mean-3*err_std 0 err_mean+3*err_std],... +0361 'YTickLabelMode','auto') +0362 set(get(axE,'YLabel'),'String','residuals',... +0363 'FontWeight','normal'); +0364 end +0365 +0366 switch loglinx +0367 case 'x-axis -> lin' % log axes +0368 set(axE,'XScale','log','XLim',xlims); +0369 case 'x-axis -> log' % lin axes +0370 set(axE,'XScale','lin','XLim',xlims); +0371 end 0372 end -0373 -0374 if ~isempty(levels) && levels(1) > 0 && c > 0 -0375 hold(ax,'on'); -0376 -0377 mycol = flipud(parula(128)); -0378 for i = 1:numel(levels) -0379 t = INVdata{levels(i)}.results.invstd.fit_t; -0380 s = INVdata{levels(i)}.results.invstd.fit_s; -0381 s = S(levels(i)).*(s./sum(INVdata{levels(i)}.results.invstd.E0)); -0382 if i == 1 -0383 xlims = [min(t) max(t)]; -0384 ylims = [min(s) max(s)]; -0385 else -0386 xlims = [min([xlims(1) min(t)]) max([xlims(2) max(t)])]; -0387 ylims = [min([ylims(1) min(s)]) max([ylims(2) max(s)])]; -0388 end -0389 colind = getColorIndex(S(levels(i)),128); -0390 plot(t,s,'LineStyle','-','Color',mycol(colind,:),'Parent',ax); -0391 end -0392 set(ax,'YLim',ylims); -0393 -0394 loglinx = get(gui.cm_handles.axes_all_xaxis,'Label'); -0395 switch loglinx -0396 case 'x-axis -> lin' % log axes -0397 ticks = floor(min(log10(nmrproc.t(nmrproc.t>0)))):1:ceil(log10(nmrproc.t(end))); -0398 set(ax,'XScale','log','XLim',xlims,'XTick',10.^ticks); -0399 case 'x-axis -> log' % lin axes -0400 set(ax,'XScale','lin','XLim',xlims,'XTickMode','auto'); -0401 end -0402 logliny = get(gui.cm_handles.axes_all_yaxis,'Label'); -0403 switch logliny -0404 case 'y-axis -> lin' % log axes -0405 set(ax,'YScale','log'); -0406 case 'y-axis -> log' % lin axes -0407 set(ax,'YScale','lin'); -0408 end -0409 end -0410 end -0411 -0412 % update GUI data -0413 setappdata(fig,'data',data); -0414 setappdata(fig,'gui',gui); -0415 -0416 end -0417 -0418 %------------- END OF CODE -------------- -0419 -0420 %% License: -0421 % MIT License -0422 % -0423 % Copyright (c) 2018 Thomas Hiller -0424 % -0425 % Permission is hereby granted, free of charge, to any person obtaining a copy -0426 % of this software and associated documentation files (the "Software"), to deal -0427 % in the Software without restriction, including without limitation the rights -0428 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0429 % copies of the Software, and to permit persons to whom the Software is -0430 % furnished to do so, subject to the following conditions: -0431 % -0432 % The above copyright notice and this permission notice shall be included in all -0433 % copies or substantial portions of the Software. -0434 % -0435 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0436 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0437 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0438 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0439 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0440 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0441 % SOFTWARE. +0373 % finalize +0374 beautifyAxes(fig); +0375 end +0376 +0377 %% if joint inversion is activated all NMR signals are plotted into the +0378 % "ALL (joint)" panel - this is just a rough overview if no joint inversion +0379 % result is yet availabe +0380 if isjoint && ~isfield(data.results,'invjoint') && ... +0381 ~strcmp(data.invstd.regtype,'lcurve') +0382 +0383 ax = gui.axes_handles.all; +0384 clearSingleAxis(ax); +0385 +0386 INVdata = getappdata(fig,'INVdata'); +0387 +0388 nINV = size(INVdata,1); +0389 E0 = zeros(nINV,1); +0390 c = 0; +0391 invlevels = 0; +0392 for i = 1:nINV +0393 if isstruct(INVdata{i}) +0394 c = c + 1; +0395 invlevels(c) = i; %#ok<AGROW> +0396 E0(i,1) = sum(INVdata{i}.results.invstd.E0); +0397 end +0398 end +0399 +0400 % the pressure / saturation data +0401 table = data.pressure.table; +0402 +0403 if size(table,1) == 1 & invlevels ~= 0 %#ok<AND2> +0404 % apparently no CPS data was loaded but joint inversion is +0405 % activated ... so just plot the data +0406 if invlevels == 0 +0407 levels = []; +0408 else +0409 levels = invlevels; +0410 S = E0(invlevels)./max(E0(invlevels)); +0411 end +0412 else +0413 uselevel = cell2mat(table(:,1)); +0414 tablelevels = 1:size(table,1); +0415 tablelevels = tablelevels(uselevel); +0416 S = cell2mat(table(:,3)); +0417 % if numel(S)~=nINV +0418 % % S() +0419 % end +0420 [isin,levels] = ismember(invlevels,tablelevels); +0421 levels = tablelevels(levels(isin)); +0422 end +0423 +0424 if ~isempty(levels) && levels(1) > 0 && c > 0 +0425 hold(ax,'on'); +0426 +0427 mycol = flipud(parula(128)); +0428 for i = 1:numel(levels) +0429 t = INVdata{levels(i)}.results.invstd.fit_t; +0430 s = INVdata{levels(i)}.results.invstd.fit_s; +0431 s = S(levels(i)).*(s./sum(INVdata{levels(i)}.results.invstd.E0)); +0432 if i == 1 +0433 xlims = [min(t) max(t)]; +0434 ylims = [min(s) max(s)]; +0435 else +0436 xlims = [min([xlims(1) min(t)]) max([xlims(2) max(t)])]; +0437 ylims = [min([ylims(1) min(s)]) max([ylims(2) max(s)])]; +0438 end +0439 colind = getColorIndex(S(levels(i)),128); +0440 plot(t,s,'LineStyle','-','Color',mycol(colind,:),'Parent',ax); +0441 end +0442 set(ax,'YLim',ylims); +0443 +0444 loglinx = get(gui.cm_handles.axes_all_xaxis,'Label'); +0445 switch loglinx +0446 case 'x-axis -> lin' % log axes +0447 ticks = floor(min(log10(nmrproc.t(nmrproc.t>0)))):1:ceil(log10(nmrproc.t(end))); +0448 set(ax,'XScale','log','XLim',xlims,'XTick',10.^ticks); +0449 case 'x-axis -> log' % lin axes +0450 set(ax,'XScale','lin','XLim',xlims,'XTickMode','auto'); +0451 end +0452 logliny = get(gui.cm_handles.axes_all_yaxis,'Label'); +0453 switch logliny +0454 case 'y-axis -> lin' % log axes +0455 set(ax,'YScale','log'); +0456 case 'y-axis -> log' % lin axes +0457 set(ax,'YScale','lin'); +0458 end +0459 end +0460 end +0461 +0462 % update GUI data +0463 setappdata(fig,'data',data); +0464 setappdata(fig,'gui',gui); +0465 +0466 end +0467 +0468 %------------- END OF CODE -------------- +0469 +0470 %% License: +0471 % MIT License +0472 % +0473 % Copyright (c) 2018 Thomas Hiller +0474 % +0475 % Permission is hereby granted, free of charge, to any person obtaining a copy +0476 % of this software and associated documentation files (the "Software"), to deal +0477 % in the Software without restriction, including without limitation the rights +0478 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0479 % copies of the Software, and to permit persons to whom the Software is +0480 % furnished to do so, subject to the following conditions: +0481 % +0482 % The above copyright notice and this permission notice shall be included in all +0483 % copies or substantial portions of the Software. +0484 % +0485 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0486 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0487 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0488 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0489 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0490 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0491 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/createKernelMatrix.html b/doc/nucleus/functions/inversion/createKernelMatrix.html index fa9799a..8f8f6cd 100644 --- a/doc/nucleus/functions/inversion/createKernelMatrix.html +++ b/doc/nucleus/functions/inversion/createKernelMatrix.html @@ -67,7 +67,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • fcn_fitMultiModal is the objective function for N free distribution
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • +
  • UncertView is an extra subGUI to show results of the uncertainty
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • fcn_fitMultiModal is the objective function for N free distribution
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • diff --git a/doc/nucleus/functions/inversion/estimateJacobian.html b/doc/nucleus/functions/inversion/estimateJacobian.html index 0e2f4e0..b63d44c 100644 --- a/doc/nucleus/functions/inversion/estimateJacobian.html +++ b/doc/nucleus/functions/inversion/estimateJacobian.html @@ -63,7 +63,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • +
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • diff --git a/doc/nucleus/functions/inversion/estimateUncertainty.html b/doc/nucleus/functions/inversion/estimateUncertainty.html index 31fd8b2..1d4ba31 100644 --- a/doc/nucleus/functions/inversion/estimateUncertainty.html +++ b/doc/nucleus/functions/inversion/estimateUncertainty.html @@ -34,18 +34,17 @@

    DESCRIPTION ^DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • displayStatusText shows status information either in the GUI or on the
  • createKernelMatrix creates a Kernel matrix from signal time vector "t"
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • getFitErrors calculates all relevant fitting errors for the NMR inversion
  • getTLogMean calculates the T logmean value out of a relaxation time
  • addNoiseToSignal adds noise with mean 'mu' and standard deviation 'sigma' to
  • This function is called by: +
  • UncertView is an extra subGUI to show results of the uncertainty
  • runUncertaintyCalculation caluclates inverison statistics in some kind of
  • @@ -94,62 +93,62 @@

    SOURCE CODE ^% 0008 % Inputs: 0009 % invtype - string indicating the inversion method of the optimal -0010 % fit ('NNLS' or 'MUMO') +0010 % fit ('LU','NNLS' or 'MUMO') 0011 % invstd - struct holding inversion results of the optimal fit 0012 % iparam - struct holding original inversion settings 0013 % parameter - struct that holds settings: -0014 % uncertMethod : which calculation method to use for +0014 % uncert.Method : which calculation method to use for 0015 % 'MUMO' the options are 'thresh' and 'ci' for 0016 % 'NNLS' the options are 'RTD_var', 'Lambda', 0017 % 'RMS_bound' and 'RMS_free' -0018 % uncertThresh : threshold for uncertainty search range -0019 % uncertChi2 : stop criteria for the chi2 deviation -0020 % uncertN : number of models to calculate -0021 % uncertMax : total number of unsuccessful attempts -0022 % after which the calculation is stopped -0023 % -0024 % Outputs: -0025 % invstd - same as input struct -0026 % uncert - uncertainty data -0027 % -0028 % Example: -0029 % [invstd] = estimateUncertainty('MUMO',invstd,iparam,uparam) -0030 % -0031 % Other m-files required: -0032 % createKernelMatrix -0033 % displayStatusText -0034 % fitDataLSQ -0035 % getFitErrors -0036 % -0037 % Subfunctions: -0038 % none -0039 % -0040 % MAT-files required: -0041 % none -0042 % -0043 % See also: -0044 % Author: see AUTHORS.md -0045 % email: see AUTHORS.md -0046 % License: MIT License (at end) -0047 -0048 %------------- BEGIN CODE -------------- -0049 -0050 %% get GUI handle and data -0051 fig = findobj('Tag','INV'); -0052 if ~isempty(fig) -0053 gui = getappdata(fig,'gui'); -0054 else -0055 % this routine will sill call 'displayStatusText' but then the output -0056 % is displayed at the command line -0057 gui = 0; -0058 end -0059 -0060 % get the main parameters -0061 uncertMethod = parameter.uncertMethod; -0062 uncertChi2 = parameter.uncertChi2; -0063 uncertThresh = parameter.uncertThresh; -0064 uncertN = parameter.uncertN; -0065 uncertMax = parameter.uncertMax; +0018 % uncert.Thresh : threshold for uncertainty search range +0019 % uncert.N : number of models to calculate +0020 % uncert.Max : total number of unsuccessful attempts +0021 % after which the calculation is stopped +0022 % +0023 % Outputs: +0024 % invstd - same as input struct +0025 % uncert - uncertainty data +0026 % +0027 % Example: +0028 % [invstd] = estimateUncertainty('MUMO',invstd,iparam,uparam) +0029 % +0030 % Other m-files required: +0031 % createKernelMatrix +0032 % displayStatusText +0033 % fitDataLSQ +0034 % getFitErrors +0035 % +0036 % Subfunctions: +0037 % none +0038 % +0039 % MAT-files required: +0040 % none +0041 % +0042 % See also: +0043 % Author: see AUTHORS.md +0044 % email: see AUTHORS.md +0045 % License: MIT License (at end) +0046 +0047 %------------- BEGIN CODE -------------- +0048 +0049 %% get GUI handle and data +0050 fig = findobj('Tag','INV'); +0051 if ~isempty(fig) +0052 gui = getappdata(fig,'gui'); +0053 else +0054 % this routine will still call 'displayStatusText' but then the output +0055 % is displayed at the command line +0056 gui = 0; +0057 end +0058 +0059 % get the main parameters +0060 uncertMethod = parameter.uncert.Method; +0061 chi2_range = parameter.uncert.chi2_range; +0062 mnorm_range = parameter.uncert.mnorm_range; +0063 uncertThresh = parameter.uncert.Thresh; +0064 uncertN = parameter.uncert.N; +0065 uncertMax = parameter.uncert.Max; 0066 0067 % original data that was fitted 0068 time = parameter.time; @@ -162,453 +161,333 @@

    SOURCE CODE ^case 'T1' 0076 K0 = createKernelMatrix(10*time(end),invstd.T1T2me',... 0077 iparam.Tb,iparam.Td,'T1',iparam.T1IRfac); -0078 +0078 0079 time0 = [time' 2*time(end) 5*time(end) 10*time(end)]; 0080 K0f = createKernelMatrix(time0,invstd.T1T2me',... 0081 iparam.Tb,iparam.Td,'T1',iparam.T1IRfac); 0082 case 'T2' 0083 K0 = createKernelMatrix(0,invstd.T1T2me',iparam.Tb,... 0084 iparam.Td,'T2',iparam.T1IRfac); -0085 +0085 0086 time0 = [0 1e-6 time(1)/10 time(1)/5 time(1)/3 time(1)/2 time']; 0087 K0f = createKernelMatrix(time0,invstd.T1T2me',iparam.Tb,... 0088 iparam.Td,'T2',iparam.T1IRfac); 0089 end 0090 -0091 % switch depending on inversion method -0092 switch invtype -0093 case 'MUMO' -0094 % data needed from the optimal fit -0095 T = invstd.T; -0096 S = invstd.S; -0097 E = invstd.E; -0098 x = invstd.x; -0099 lb = invstd.lb; -0100 ub = invstd.ub; -0101 ci = invstd.ci; -0102 -0103 % kernel for the original fit needed for comparison of the uncertainty models -0104 K = createKernelMatrix(time,invstd.T1T2me',iparam.Tb,iparam.Td,... -0105 iparam.T1T2,iparam.T1IRfac); -0106 -0107 % counter -0108 count = 0; -0109 countm = 0; -0110 -0111 % initialize variables -0112 TDIST = zeros(uncertN,numel(invstd.T1T2me)); -0113 SINTERP = zeros(numel(time0),uncertN); -0114 E0INTERP = zeros(uncertN,1); -0115 % calculate uncertainty models -0116 while count < uncertN -0117 switch uncertMethod -0118 case 'thresh' -0119 % randomly vary all parameters +- thresh -0120 a = 1-uncertThresh; -0121 b = 1+uncertThresh; -0122 rr = (b-a).*rand(1,length(ci)) + a; -0123 Ti = log(T).*rr(1:3:end); % do it on log-scale -0124 Si = S.*rr(2:3:end); -0125 Ei = E.*rr(3:3:end); -0126 -0127 xi = zeros(size(x)); -0128 xi(1:3:end) = Ti; -0129 xi(2:3:end) = Si; -0130 xi(3:3:end) = Ei; -0131 case 'ci' -0132 % randomly vary parameters within confidence interval -0133 rr = 2.*rand(1,length(ci))-1; -0134 xi = zeros(size(x)); -0135 xi(1:3:end) = log(T); -0136 xi(2:3:end) = S; -0137 xi(3:3:end) = E; -0138 xi = xi+ci'.*rr; -0139 end -0140 -0141 % adjust for bounds if necessary -0142 xi(xi<lb) = lb(xi<lb); -0143 xi(xi>ub) = lb(xi>ub); -0144 -0145 % temporary values -0146 Ti = exp(xi(1:3:end)); % transform back to lin-scale -0147 Si = xi(2:3:end); -0148 Ei = xi(3:3:end); -0149 -0150 % create a temporary distribution with the new parameters -0151 TdistI = 0; -0152 for i = 1:numel(T) -0153 tmp = 1./( Si(i)*sqrt(2*pi)).*exp(-((log(invstd.T1T2me') - log(Ti(i)))/ sqrt(2)/Si(i)).^2); -0154 % scale to amplitude -0155 if sum(tmp)>0 -0156 tmp = (tmp/sum(tmp)) * Ei(i); -0157 end -0158 % add the tmp per mu to Tdist -0159 TdistI = TdistI + tmp; -0160 end -0161 % calculate temporary signal(s) -0162 s_interp = K*TdistI'; -0163 s0_interp = K0f*TdistI'; -0164 -0165 % get residuals and error measures -0166 if isfield(iparam,'W') -0167 % when signal gating was used the error estimates need to be adjusted -0168 outI = getFitErrors(signal,s_interp,iparam.noise,iparam.W); -0169 else -0170 outI = getFitErrors(signal,s_interp,iparam.noise); -0171 end -0172 -0173 % check if the temporary chi2 is within the desired limit -0174 if abs(1-outI.chi2/invstd.chi2) <= uncertChi2 -0175 % if YES then keep it -0176 count = count + 1; -0177 % save RTD -0178 TDIST(count,:) = TdistI; -0179 % save signal -0180 SINTERP(:,count) = s0_interp; -0181 % save E0 -0182 E0INTERP(count,1) = K0*TdistI'; -0183 % status bar info -0184 infostring = ['Calculating uncertainty models: ',... -0185 num2str(count),' / ',num2str(uncertN)]; -0186 displayStatusText(gui,infostring); -0187 % reset max counter -0188 countm = 0; -0189 else -0190 % as long as we did not find a model keep counting -0191 if count < 1 -0192 countm = countm + 1; -0193 infostring = ['Trying to find uncertainty model: ',... -0194 num2str(countm),' / ',num2str(uncertMax)]; -0195 displayStatusText(gui,infostring); -0196 end -0197 end -0198 % after to many unsuccessful attempts STOP -0199 if countm > uncertMax -0200 infostring = ['No uncertainty model found: ',... -0201 num2str(countm),' / ',num2str(uncertMax)]; -0202 displayStatusText(gui,infostring); -0203 break; -0204 end -0205 end -0206 -0207 % output data -0208 if sum(E0INTERP) > 0 -0209 % E0 from uncertainy calculation -0210 invstd.E0 = mean(E0INTERP); -0211 % simple E0 confidence interval -0212 invstd.ciE0 = 2*std(E0INTERP); -0213 end -0214 -0215 % uncertainty calculation results -0216 uncert.interp_t = time0(:); -0217 uncert.interp_E0 = E0INTERP; -0218 uncert.interp_f = TDIST; -0219 uncert.interp_s = SINTERP; -0220 -0221 % uncertainty patch for fitted signal -> mean +-2*std -0222 meantmp = mean(SINTERP,2); -0223 stdtmp = std(SINTERP,0,2); -0224 uncert.interp_s_min = meantmp-2*stdtmp; -0225 uncert.interp_s_max = meantmp+2*stdtmp; -0226 -0227 % uncertainty patch for fitted RTD -> mean +-2*std -0228 meantmp = mean(TDIST); -0229 stdtmp = std(TDIST); -0230 uncert.interp_f_min = meantmp-2*stdtmp; -0231 uncert.interp_f_max = meantmp+2*stdtmp; -0232 -0233 invstd.uncert = uncert; -0234 -0235 case 'NNLS' -0236 -0237 % 'RTD_var' | 'Lambda' | 'RMS_bound' | 'RMS_free' -0238 % uncertMethod = 'RMS_bound'; -0239 -0240 switch uncertMethod -0241 case 'RTD_var' -0242 % find uncertainty models by varying the optimal RTD bins -0243 % individually -0244 -0245 % uncertN = 5; -0246 % uncertThresh = 0.1; -0247 % uncertChi2 = 0.05; -0248 f_final = invstd.T1T2f; -0249 -0250 % initialize variables -0251 % NOTE: we save 'uncertN' models for each RTD bin -0252 TDIST = zeros(uncertN*numel(invstd.T1T2me),numel(invstd.T1T2me)); -0253 SINTERP = zeros(numel(time0),uncertN*numel(invstd.T1T2me)); -0254 E0INTERP = zeros(uncertN*numel(invstd.T1T2me),1); -0255 % loop over all RTD bins -0256 for i1 = 1:numel(f_final) -0257 count = 0; -0258 while count < uncertN -0259 % start RTD is always the optimal one -0260 x0 = f_final; -0261 % global bounds -0262 lb = zeros(size(x0)); -0263 ub = max(f_final).*3.*ones(size(x0)); -0264 % now draw a random value for the current RTD bin -0265 a = 1-uncertThresh; -0266 b = 1+uncertThresh; -0267 rr = (b-a).*rand(1,1) + a; -0268 % adjust the initial model and bounds accordingly -0269 x0(i1) = f_final(i1)*rr; -0270 lb(i1) = x0(i1); -0271 ub(i1) = x0(i1); -0272 -0273 % save bounds for the LSQ inversion -0274 iparam.bounds.lb = lb; -0275 iparam.bounds.ub = ub; -0276 iparam.bounds.f0 = x0; -0277 -0278 % calculate solution -0279 invtmp = fitDataLSQ(time,signal,iparam); -0280 s0_interp = K0f*invtmp.T1T2f; -0281 -0282 % check if the temporary chi2 and model norm are -0283 % within the desired limits -0284 if abs(1-invtmp.chi2/invstd.chi2) <= uncertChi2 && ... -0285 abs(1-invtmp.xn/invstd.xn) <= uncertChi2/2 -0286 % if YES then keep it -0287 count = count + 1; -0288 % save RTD -0289 TDIST(i1*uncertN-(uncertN-count),:) = invtmp.T1T2f; -0290 % save signal -0291 SINTERP(:,i1*uncertN-(uncertN-count)) = s0_interp; -0292 % save E0 -0293 E0INTERP(i1*uncertN-(uncertN-count),1) = invtmp.E0; -0294 % status bar info -0295 infostring = ['Calculating uncertainty models: ',... -0296 num2str(count),' / ',num2str(uncertN),... -0297 ' for RTD bin: ',num2str(i1),' / ',num2str(numel(f_final))]; -0298 displayStatusText(gui,infostring); -0299 end -0300 end -0301 end -0302 -0303 case 'Lambda' -0304 % find uncertainty models by varying the optimal -0305 % regularization parameter lambda -0306 -0307 % set regularization to 'manual' just in case -0308 iparam.regMethod = 'manual'; -0309 -0310 % lambda search range -0311 a = log10(invstd.lambda_out/100); -0312 b = log10(invstd.lambda_out*10); -0313 -0314 % counter -0315 count = 0; -0316 countm = 0; -0317 -0318 % initialize variables -0319 TDIST = zeros(uncertN,numel(invstd.T1T2me)); -0320 SINTERP = zeros(numel(time0),uncertN); -0321 E0INTERP = zeros(uncertN,1); -0322 % calculate uncertainty models -0323 while count < uncertN -0324 % draw a random lambda value -0325 rr = (b-a).*rand(1,1) + a; -0326 iparam.lambda = 10^(rr); -0327 % calculate solution -0328 invtmp = fitDataLSQ(time,signal,iparam); -0329 s0_interp = K0f*invtmp.T1T2f; -0330 -0331 % check if temporary chi2 and model norm are within the -0332 % desired limits -0333 if abs(1-invtmp.chi2/invstd.chi2) <= uncertChi2 &&... -0334 abs(1-invtmp.xn/invstd.xn) <= uncertChi2*10 -0335 % if YES then keep it -0336 count = count + 1; -0337 % save RTD -0338 TDIST(count,:) = invtmp.T1T2f; -0339 % save signal -0340 SINTERP(:,count) = s0_interp; -0341 % save E0 -0342 E0INTERP(count,1) = invtmp.E0; -0343 % status bar info -0344 infostring = ['Calculating uncertainty models: ',... -0345 num2str(count),' / ',num2str(uncertN)]; -0346 displayStatusText(gui,infostring); -0347 % reset max counter -0348 countm = 0; -0349 else -0350 % % update the lambda search range -0351 % if invtmp.xn > invstd.xn % lambda was too small -0352 % % new lower lambda search bound -0353 % a = rr; -0354 % end -0355 % if invtmp.chi2 > invstd.chi2 % lambda was too big -0356 % % new upper lambda search bound -0357 % b = rr; -0358 % end -0359 % as long as we did not find a model keep counting -0360 if count < 1 -0361 countm = countm + 1; -0362 infostring = ['Trying to find uncertainty model: ',... -0363 num2str(countm),' / ',num2str(uncertMax)]; -0364 displayStatusText(gui,infostring); -0365 end -0366 end -0367 % after to many unsuccessful attempts STOP -0368 if countm > uncertMax -0369 infostring = ['No uncertainty model found: ',... -0370 num2str(countm),' / ',num2str(uncertMax)]; -0371 displayStatusText(gui,infostring); -0372 break; -0373 end -0374 end -0375 -0376 case 'RMS_bound' -0377 % find uncertainty models by adding random noise (based on -0378 % fit RMS) on the optimal fit to create new "raw data" and -0379 % invert them with the original optimal inversion settings -0380 % select models based on chi2 and model norm bounds -0381 -0382 % set regularization to 'manual' just in case -0383 iparam.regMethod = 'manual'; -0384 -0385 % counter -0386 count = 0; -0387 countm = 0; -0388 -0389 % initialize variables -0390 TDIST = zeros(uncertN,numel(invstd.T1T2me)); -0391 SINTERP = zeros(numel(time0),uncertN); -0392 E0INTERP = zeros(uncertN,1); -0393 % calculate uncertainty models -0394 while count < uncertN -0395 % the original fit -0396 sig1 = invstd.fit_s; -0397 % create some random noise based on original fit RMS -0398 [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); -0399 % calculate solution -0400 invtmp = fitDataLSQ(time,signalN,iparam); -0401 s0_interp = K0f*invtmp.T1T2f; -0402 -0403 % check if temporary chi2 and model norm are within the -0404 % desired limits -0405 if abs(1-invtmp.chi2/invstd.chi2) <= uncertChi2 &&... -0406 abs(1-invtmp.xn/invstd.xn) <= uncertChi2*10 -0407 % if YES then keep it -0408 count = count + 1; -0409 % save RTD -0410 TDIST(count,:) = invtmp.T1T2f; -0411 % save signal -0412 SINTERP(:,count) = s0_interp; -0413 % save E0 -0414 E0INTERP(count,1) = invtmp.E0; -0415 % status bar info -0416 infostring = ['Calculating uncertainty models: ',... -0417 num2str(count),' / ',num2str(uncertN)]; -0418 displayStatusText(gui,infostring); -0419 % reset max counter -0420 countm = 0; -0421 else -0422 % as long as we did not find a model keep counting -0423 if count < 1 -0424 countm = countm + 1; -0425 infostring = ['Trying to find uncertainty model: ',... -0426 num2str(countm),' / ',num2str(uncertMax)]; -0427 displayStatusText(gui,infostring); -0428 end -0429 end -0430 % after to many unsuccessful attempts STOP -0431 if countm > uncertMax -0432 infostring = ['No uncertainty model found: ',... -0433 num2str(countm),' / ',num2str(uncertMax)]; -0434 displayStatusText(gui,infostring); -0435 break; -0436 end -0437 end -0438 -0439 case 'RMS_free' -0440 % find uncertainty models by adding random noise (based on -0441 % fit RMS) on the optimal fit to create new "raw data" and -0442 % invert them with the original optimal inversion settings -0443 -0444 % set regularization to 'manual' just in case -0445 iparam.regMethod = 'manual'; -0446 -0447 % initialize variables -0448 TDIST = zeros(uncertN,numel(invstd.T1T2me)); -0449 SINTERP = zeros(numel(time0),uncertN); -0450 E0INTERP = zeros(uncertN,1); -0451 % calculate uncertainty models -0452 for count = 1:uncertN -0453 % the original fit -0454 sig1 = invstd.fit_s; -0455 % create some random noise based on original fit RMS -0456 [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); -0457 -0458 % calculate solution -0459 invtmp = fitDataLSQ(time,signalN,iparam); -0460 s0_interp = K0f*invtmp.T1T2f; -0461 % save RTD -0462 TDIST(count,:) = invtmp.T1T2f; -0463 % save signal -0464 SINTERP(:,count) = s0_interp; -0465 % save E0 -0466 E0INTERP(count,1) = invtmp.E0; -0467 % status bar info -0468 infostring = ['Calculating uncertainty models: ',... -0469 num2str(count),' / ',num2str(uncertN)]; -0470 displayStatusText(gui,infostring); -0471 end -0472 end -0473 -0474 % output data -0475 % simple E0 confidence interval -0476 invstd.ciE0 = 2*std(E0INTERP); -0477 -0478 % uncertainty calculation results -0479 uncert.interp_t = time0(:); -0480 uncert.interp_E0 = E0INTERP; -0481 uncert.interp_f = TDIST; -0482 uncert.interp_s = SINTERP; -0483 -0484 % uncertainty patch for fitted signal -0485 uncert.interp_s_min = min(SINTERP,[],2); -0486 uncert.interp_s_max = max(SINTERP,[],2); -0487 -0488 % uncertainty patch for fitted RTD -0489 uncert.interp_f_min = min(TDIST); -0490 uncert.interp_f_max = max(TDIST); -0491 -0492 invstd.uncert = uncert; -0493 -0494 otherwise -0495 % nothing to do -0496 uncert = []; -0497 end -0498 -0499 return -0500 -0501 %------------- END OF CODE -------------- -0502 -0503 %% License: -0504 % MIT License -0505 % -0506 % Copyright (c) 2022 Thomas Hiller -0507 % -0508 % Permission is hereby granted, free of charge, to any person obtaining a copy -0509 % of this software and associated documentation files (the "Software"), to deal -0510 % in the Software without restriction, including without limitation the rights -0511 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0512 % copies of the Software, and to permit persons to whom the Software is -0513 % furnished to do so, subject to the following conditions: -0514 % -0515 % The above copyright notice and this permission notice shall be included in all -0516 % copies or substantial portions of the Software. -0517 % -0518 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0519 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0520 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0521 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0522 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0523 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0524 % SOFTWARE. +0091 %% there are four different methods implemented +0092 switch uncertMethod +0093 case 'RMS_free' +0094 %% +0095 % find uncertainty models by adding random noise (based on +0096 % fit RMS) on the optimal fit to create new "raw data" and +0097 % invert them with the original optimal inversion settings +0098 +0099 % initialize variables +0100 TDIST = zeros(uncertN,numel(invstd.T1T2me)); +0101 SINTERP = zeros(numel(time0),uncertN); +0102 E0INTERP = zeros(uncertN,1); +0103 TLGMINTERP = zeros(uncertN,1); +0104 mnorm_all = zeros(uncertN,1); +0105 rnorm_all = zeros(uncertN,1); +0106 chi2_all = zeros(uncertN,1); +0107 % calculate uncertainty models +0108 for count = 1:uncertN +0109 % the original fit +0110 sig1 = invstd.fit_s; +0111 % create some random noise based on original fit RMS +0112 [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); +0113 +0114 % calculate solution +0115 switch invtype +0116 case 'LU' +0117 invtmp = fitDataLUdecomp(time,signalN,iparam); +0118 case 'MUMO' +0119 invtmp = fitDataMultiModal(time,signalN,iparam); +0120 case 'NNLS' +0121 invtmp = fitDataLSQ(time,signalN,iparam); +0122 end +0123 % new signal +0124 s0_interp = K0f*invtmp.T1T2f; +0125 % save RTD +0126 TDIST(count,:) = invtmp.T1T2f; +0127 % save signal +0128 SINTERP(:,count) = s0_interp; +0129 % save E0 +0130 E0INTERP(count,1) = invtmp.E0; +0131 % save TLGM +0132 TLGMINTERP(count,1) = invtmp.Tlgm; +0133 mnorm_all(count,1) = invtmp.xn; +0134 rnorm_all(count,1) = invtmp.rn; +0135 chi2_all(count,1) = invtmp.chi2; +0136 % status bar info +0137 infostring = ['Calculating uncertainty models: ',... +0138 num2str(count),' / ',num2str(uncertN)]; +0139 displayStatusText(gui,infostring); +0140 end +0141 case 'RMS_bound' +0142 %% +0143 % find uncertainty models by adding random noise (based on +0144 % fit RMS) on the optimal fit to create new "raw data" and +0145 % invert them with the original optimal inversion settings +0146 % select models based on chi2 and model norm bounds +0147 +0148 % counter +0149 count = 0; +0150 countm = 0; +0151 +0152 % initialize variables +0153 TDIST = zeros(uncertN,numel(invstd.T1T2me)); +0154 SINTERP = zeros(numel(time0),uncertN); +0155 E0INTERP = zeros(uncertN,1); +0156 TLGMINTERP = zeros(uncertN,1); +0157 mnorm_all = zeros(uncertN,1); +0158 rnorm_all = zeros(uncertN,1); +0159 chi2_all = zeros(uncertN,1); +0160 % calculate uncertainty models +0161 while count < uncertN +0162 % the original fit +0163 sig1 = invstd.fit_s; +0164 % create some random noise based on original fit RMS +0165 [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); +0166 % calculate solution +0167 switch invtype +0168 case 'LU' +0169 invtmp = fitDataLUdecomp(time,signalN,iparam); +0170 case 'MUMO' +0171 invtmp = fitDataMultiModal(time,signalN,iparam); +0172 case 'NNLS' +0173 invtmp = fitDataLSQ(time,signalN,iparam); +0174 end +0175 % new signal +0176 s0_interp = K0f*invtmp.T1T2f; +0177 +0178 % check if temporary chi2 and model norm are within the +0179 % desired limits +0180 if invtmp.chi2 >= chi2_range(1) && invtmp.chi2 <= chi2_range(2) && ... +0181 invtmp.xn >= mnorm_range(1) && invtmp.xn <= mnorm_range(2) +0182 % if YES then keep it +0183 count = count + 1; +0184 % save RTD +0185 TDIST(count,:) = invtmp.T1T2f; +0186 % save signal +0187 SINTERP(:,count) = s0_interp; +0188 % save E0 +0189 E0INTERP(count,1) = invtmp.E0; +0190 % save TLGM +0191 TLGMINTERP(count,1) = invtmp.Tlgm; +0192 mnorm_all(count,1) = invtmp.xn; +0193 rnorm_all(count,1) = invtmp.rn; +0194 chi2_all(count,1) = invtmp.chi2; +0195 % status bar info +0196 infostring = ['Calculating uncertainty models: ',... +0197 num2str(count),' / ',num2str(uncertN)]; +0198 displayStatusText(gui,infostring); +0199 % reset max counter +0200 countm = 0; +0201 else +0202 % as long as we did not find a model keep counting +0203 if count < 1 +0204 countm = countm + 1; +0205 infostring = ['Trying to find uncertainty model: ',... +0206 num2str(countm),' / ',num2str(uncertMax)]; +0207 displayStatusText(gui,infostring); +0208 end +0209 end +0210 % after to many unsuccessful attempts STOP +0211 if countm > uncertMax +0212 infostring = ['No uncertainty model found: ',... +0213 num2str(countm),' / ',num2str(uncertMax)]; +0214 displayStatusText(gui,infostring); +0215 break; +0216 end +0217 end +0218 otherwise % 'thresh' and 'ci' +0219 %% +0220 % data needed from the optimal fit +0221 T = invstd.T; +0222 S = invstd.S; +0223 E = invstd.E; +0224 x = invstd.x; +0225 lb = invstd.lb; +0226 ub = invstd.ub; +0227 ci = invstd.ci; +0228 +0229 % kernel for the original fit needed for comparison to the +0230 % uncertainty models +0231 K = createKernelMatrix(time,invstd.T1T2me',iparam.Tb,iparam.Td,... +0232 iparam.T1T2,iparam.T1IRfac); +0233 +0234 % counter +0235 count = 0; +0236 countm = 0; +0237 +0238 % initialize variables +0239 TDIST = zeros(uncertN,numel(invstd.T1T2me)); +0240 SINTERP = zeros(numel(time0),uncertN); +0241 E0INTERP = zeros(uncertN,1); +0242 TLGMINTERP = zeros(uncertN,1); +0243 mnorm_all = zeros(uncertN,1); +0244 rnorm_all = zeros(uncertN,1); +0245 chi2_all = zeros(uncertN,1); +0246 % calculate uncertainty models +0247 while count < uncertN +0248 switch uncertMethod +0249 case 'thresh' +0250 % randomly vary all parameters +- thresh +0251 a = 1-uncertThresh; +0252 b = 1+uncertThresh; +0253 rr = (b-a).*rand(1,length(ci)) + a; +0254 Ti = log(T).*rr(1:3:end); % do it on log-scale +0255 Si = S.*rr(2:3:end); +0256 Ei = E.*rr(3:3:end); +0257 +0258 xi = zeros(size(x)); +0259 xi(1:3:end) = Ti; +0260 xi(2:3:end) = Si; +0261 xi(3:3:end) = Ei; +0262 case 'ci' +0263 % randomly vary parameters within confidence interval +0264 rr = 2.*rand(1,length(ci))-1; +0265 xi = zeros(size(x)); +0266 xi(1:3:end) = log(T); +0267 xi(2:3:end) = S; +0268 xi(3:3:end) = E; +0269 xi = xi+ci'.*rr; +0270 end +0271 +0272 % adjust for bounds if necessary +0273 xi(xi<lb) = lb(xi<lb); +0274 xi(xi>ub) = lb(xi>ub); +0275 +0276 % temporary values +0277 Ti = exp(xi(1:3:end)); % transform back to lin-scale +0278 Si = xi(2:3:end); +0279 Ei = xi(3:3:end); +0280 +0281 % create a temporary distribution with the new random RTD parameters +0282 TdistI = 0; +0283 for i = 1:numel(T) +0284 tmp = 1./( Si(i)*sqrt(2*pi)).*exp(-((log(invstd.T1T2me') -... +0285 log(Ti(i)))/ sqrt(2)/Si(i)).^2); +0286 % scale to amplitude +0287 if sum(tmp)>0 +0288 tmp = (tmp/sum(tmp)) * Ei(i); +0289 end +0290 % add the tmp per mu to Tdist +0291 TdistI = TdistI + tmp; +0292 end +0293 % calculate temporary signal(s) +0294 s_interp = K*TdistI'; +0295 s0_interp = K0f*TdistI'; +0296 +0297 % get residuals and error measures +0298 if isfield(iparam,'W') +0299 % when signal gating was used the error estimates need to be adjusted +0300 outI = getFitErrors(signal,s_interp,iparam.noise,iparam.W); +0301 else +0302 outI = getFitErrors(signal,s_interp,iparam.noise); +0303 end +0304 +0305 chi2 = outI.chi2; +0306 xn = norm(TdistI,2); +0307 rn = norm(outI.residual,2); +0308 +0309 % check if the temporary chi2 and xn are within the desired +0310 % limits +0311 if chi2 >= chi2_range(1) && chi2 <= chi2_range(2) && ... +0312 xn >= mnorm_range(1) && xn <= mnorm_range(2) +0313 % if YES then keep it +0314 count = count + 1; +0315 % save RTD +0316 TDIST(count,:) = TdistI; +0317 % save signal +0318 SINTERP(:,count) = s0_interp; +0319 % save E0 +0320 E0INTERP(count,1) = K0*TdistI'; +0321 % save TLGM +0322 TLGMINTERP(count,1) = getTLogMean(invstd.T1T2me,TdistI); +0323 mnorm_all(count,1) = xn; +0324 rnorm_all(count,1) = rn; +0325 chi2_all(count,1) = chi2; +0326 % status bar info +0327 infostring = ['Calculating uncertainty models: ',... +0328 num2str(count),' / ',num2str(uncertN)]; +0329 displayStatusText(gui,infostring); +0330 % reset max counter +0331 countm = 0; +0332 else +0333 % as long as we did not find a model keep counting +0334 if count < 1 +0335 countm = countm + 1; +0336 infostring = ['Trying to find uncertainty model: ',... +0337 num2str(countm),' / ',num2str(uncertMax)]; +0338 displayStatusText(gui,infostring); +0339 end +0340 end +0341 % after to many unsuccessful attempts STOP +0342 if countm > uncertMax +0343 infostring = ['No uncertainty model found: ',... +0344 num2str(countm),' / ',num2str(uncertMax)]; +0345 displayStatusText(gui,infostring); +0346 break; +0347 end +0348 end +0349 end +0350 +0351 % output data +0352 % simple E0 confidence interval +0353 invstd.ciE0 = 2*std(E0INTERP); +0354 +0355 % mean E0 +0356 uncert.E0 = [mean(E0INTERP) std(E0INTERP)]; +0357 % mean TLGM +0358 uncert.Tlgm = [mean(TLGMINTERP) std(TLGMINTERP)]; +0359 +0360 % uncertainty calculation results +0361 uncert.interp_t = time0(:); +0362 uncert.interp_E0 = E0INTERP; +0363 uncert.interp_Tlgm = TLGMINTERP; +0364 uncert.mnorm_all = mnorm_all; +0365 uncert.rnorm_all = rnorm_all; +0366 uncert.chi2_all = chi2_all; +0367 uncert.interp_f = TDIST; +0368 uncert.interp_s = SINTERP; +0369 +0370 % uncertainty patch for fitted signal +0371 uncert.interp_s_min = min(SINTERP,[],2); +0372 uncert.interp_s_max = max(SINTERP,[],2); +0373 +0374 % uncertainty patch for fitted RTD +0375 uncert.interp_f_min = min(TDIST); +0376 uncert.interp_f_max = max(TDIST); +0377 +0378 invstd.uncert = uncert; +0379 +0380 end +0381 %------------- END OF CODE -------------- +0382 +0383 %% License: +0384 % MIT License +0385 % +0386 % Copyright (c) 2022 Thomas Hiller +0387 % +0388 % Permission is hereby granted, free of charge, to any person obtaining a copy +0389 % of this software and associated documentation files (the "Software"), to deal +0390 % in the Software without restriction, including without limitation the rights +0391 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0392 % copies of the Software, and to permit persons to whom the Software is +0393 % furnished to do so, subject to the following conditions: +0394 % +0395 % The above copyright notice and this permission notice shall be included in all +0396 % copies or substantial portions of the Software. +0397 % +0398 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0399 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0400 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0401 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0402 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0403 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0404 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/fcn_fitMultiModal.html b/doc/nucleus/functions/inversion/fcn_fitMultiModal.html index a624621..1e8ae69 100644 --- a/doc/nucleus/functions/inversion/fcn_fitMultiModal.html +++ b/doc/nucleus/functions/inversion/fcn_fitMultiModal.html @@ -70,7 +70,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=createKernelMatrix creates a Kernel matrix from signal time vector "t" This function is called by: +
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • diff --git a/doc/nucleus/functions/inversion/fitDataFree.html b/doc/nucleus/functions/inversion/fitDataFree.html index f4a69e7..8517544 100644 --- a/doc/nucleus/functions/inversion/fitDataFree.html +++ b/doc/nucleus/functions/inversion/fitDataFree.html @@ -92,7 +92,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=fcn_fitFreeT1 is the objective function for T1 mono- and free exponential
  • fcn_fitFreeT1_fmin is the objective function for T1 mono- and free exponential
  • fcn_fitFreeT2 is the objective function for T2 mono- and free exponential
  • fcn_fitFreeT2_fmin is the objective function for T2 mono- and free exponential
  • fcn_fitFreeT2w is the objective function for T2 mono- and free exponential
  • getConfInterval calculates the confidence interval for the inversion
  • getFitErrors calculates all relevant fitting errors for the NMR inversion
  • getFitFreeJacobian calculates the Jacobi matrix for the NMR inversion
  • This function is called by: +
  • LoadNMRData_driver loads NMR raw data from different file formats
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • runInversionBatch batch processes the inversion using for all NMR signals
  • runInversionStd controls the standard inversion process to invert a
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • diff --git a/doc/nucleus/functions/inversion/fitDataLSQ.html b/doc/nucleus/functions/inversion/fitDataLSQ.html index 6f1f33a..573309c 100644 --- a/doc/nucleus/functions/inversion/fitDataLSQ.html +++ b/doc/nucleus/functions/inversion/fitDataLSQ.html @@ -102,7 +102,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • applyRegularization applies regularization procedures from the
  • createKernelMatrix creates a Kernel matrix from signal time vector "t"
  • getFitErrors calculates all relevant fitting errors for the NMR inversion
  • getTLogMean calculates the T logmean value out of a relaxation time
  • This function is called by: @@ -263,102 +263,105 @@

    SOURCE CODE ^case 'lsqlin' 0151 options = optimoptions('lsqlin'); 0152 options.Display = parameter.info; -0153 options.OptimalityTolerance = 1e-18; -0154 options.StepTolerance = 1e-18; -0155 if isfield(parameter,'bounds') -0156 [f,~,~,~,~,~] = lsqlin(KK,gg,[],[],[],[],... -0157 f0_lb,f0_ub,f0,options); -0158 else -0159 [f,~,~,~,~,~] = lsqlin(KK,gg,[],[],[],[],... -0160 f0_lb,f0_ub,[],options); -0161 end -0162 case 'lsqnonneg' -0163 options = optimset('Display',parameter.info,'TolX',1e-12); -0164 [f,~,~,~,~,~] = lsqnonneg(KK,gg,options); -0165 end -0166 -0167 % rescale f so that the sum(f) = unscaled E0 -0168 f = (f.*maxS); -0169 -0170 % the 'inverted' signal -0171 gg_fit = KK*f; -0172 % cut off the end which was needed for regularization -0173 s_fit = gg_fit(1:length(t),1); -0174 -0175 % get residuals and error measures -0176 if isfield(parameter,'W') -0177 % normalize the fit because the signal was error weighted for the -0178 % inversion -0179 e = diag(W); -0180 einv = 1./e; -0181 Winv = diag(einv); -0182 s_fit = Winv * s_fit; -0183 -0184 % because signal and s_fit are unscaled the initial values for noise -0185 % and W are used to get the error estimates -0186 out = getFitErrors(signal,s_fit,parameter.noise,parameter.W); -0187 else -0188 out = getFitErrors(signal,s_fit,parameter.noise); -0189 end -0190 -0191 % L-curve parameter -0192 % model norm |L*x|_2 -0193 xn = norm(L*f,2); -0194 % residual norm |A*x-b|_2 -0195 rn = norm(out.residual,2); -0196 -0197 % get "initial" value E0 -0198 if strcmp(flag,'T1') -0199 K0 = createKernelMatrix(10*time(end),T1T2me,Tb,Td,flag,T1IRfac); -0200 elseif strcmp(flag,'T2') -0201 K0 = createKernelMatrix(0,T1T2me,Tb,Td,flag,T1IRfac); -0202 end -0203 E0 = K0*f; -0204 -0205 % output struct -0206 fitdata.fit_t = time(:); -0207 fitdata.fit_s = s_fit(:); -0208 fitdata.T1T2me = T1T2me(:); -0209 fitdata.T1T2f = f(:); -0210 fitdata.Tlgm = getTLogMean(T1T2me,f); -0211 fitdata.E0 = E0; -0212 fitdata.ciE0 = NaN; -0213 fitdata.resnorm = out.resnorm; -0214 fitdata.residual = out.residual; -0215 fitdata.chi2 = out.chi2; -0216 fitdata.rms = out.rms; -0217 fitdata.lambda_out = lambda_out; -0218 fitdata.KK = KK; -0219 fitdata.L = L; -0220 fitdata.xn = xn; -0221 fitdata.rn = rn; -0222 -0223 return -0224 -0225 %------------- END OF CODE -------------- -0226 -0227 %% License: -0228 % MIT License -0229 % -0230 % Copyright (c) 2018 Thomas Hiller -0231 % -0232 % Permission is hereby granted, free of charge, to any person obtaining a copy -0233 % of this software and associated documentation files (the "Software"), to deal -0234 % in the Software without restriction, including without limitation the rights -0235 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0236 % copies of the Software, and to permit persons to whom the Software is -0237 % furnished to do so, subject to the following conditions: -0238 % -0239 % The above copyright notice and this permission notice shall be included in all -0240 % copies or substantial portions of the Software. +0153 options.OptimalityTolerance = 1e-16; +0154 options.StepTolerance = 1e-16; +0155 % options.MaxIterations = 2000; +0156 if isfield(parameter,'bounds') +0157 [f,~,~,~,~,~] = lsqlin(KK,gg,[],[],[],[],... +0158 f0_lb,f0_ub,f0,options); +0159 else +0160 [f,~,~,~,~,~] = lsqlin(KK,gg,[],[],[],[],... +0161 f0_lb,f0_ub,[],options); +0162 end +0163 case 'lsqnonneg' +0164 options = optimset('Display',parameter.info,'TolX',1e-12); +0165 [f,~,~,~,~,~] = lsqnonneg(KK,gg,options); +0166 end +0167 +0168 % rescale f so that the sum(f) = unscaled E0 +0169 f = (f.*maxS); +0170 +0171 % the 'inverted' signal +0172 gg_fit = KK*f; +0173 % cut off the end which was needed for regularization +0174 s_fit = gg_fit(1:length(t),1); +0175 +0176 % get residuals and error measures +0177 if isfield(parameter,'W') +0178 % normalize the fit because the signal was error weighted for the +0179 % inversion +0180 e = diag(W); +0181 einv = 1./e; +0182 Winv = diag(einv); +0183 s_fit = Winv * s_fit; +0184 +0185 % because signal and s_fit are unscaled the initial values for noise +0186 % and W are used to get the error estimates +0187 out = getFitErrors(signal,s_fit,parameter.noise,parameter.W); +0188 else +0189 out = getFitErrors(signal,s_fit,parameter.noise); +0190 end +0191 +0192 % L-curve parameter +0193 % model norm |L*x|_2 +0194 xn = norm(L*f,2); +0195 % residual norm |A*x-b|_2 +0196 rn = norm(out.residual,2); +0197 +0198 % get "initial" value E0 +0199 if strcmp(flag,'T1') +0200 K0 = createKernelMatrix(10*time(end),T1T2me,Tb,Td,flag,T1IRfac); +0201 elseif strcmp(flag,'T2') +0202 K0 = createKernelMatrix(0,T1T2me,Tb,Td,flag,T1IRfac); +0203 end +0204 E0 = K0*f; +0205 +0206 % output struct +0207 fitdata.fit_t = time(:); +0208 fitdata.fit_s = s_fit(:); +0209 fitdata.T1T2me = T1T2me(:); +0210 fitdata.T1T2f = f(:); +0211 fitdata.Tlgm = getTLogMean(T1T2me,f); +0212 fitdata.E0 = E0; +0213 fitdata.ciE0 = NaN; +0214 fitdata.resnorm = out.resnorm; +0215 fitdata.residual = out.residual; +0216 fitdata.chi2 = out.chi2; +0217 fitdata.rms = out.rms; +0218 fitdata.lambda_out = lambda_out; +0219 fitdata.KK = KK; +0220 fitdata.L = L; +0221 fitdata.xn = xn; +0222 fitdata.rn = rn; +0223 fitdata.invtype = 'NNLS'; +0224 fitdata.invparams = parameter; +0225 +0226 return +0227 +0228 %------------- END OF CODE -------------- +0229 +0230 %% License: +0231 % MIT License +0232 % +0233 % Copyright (c) 2018 Thomas Hiller +0234 % +0235 % Permission is hereby granted, free of charge, to any person obtaining a copy +0236 % of this software and associated documentation files (the "Software"), to deal +0237 % in the Software without restriction, including without limitation the rights +0238 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0239 % copies of the Software, and to permit persons to whom the Software is +0240 % furnished to do so, subject to the following conditions: 0241 % -0242 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0243 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0244 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0245 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0246 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0247 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0248 % SOFTWARE. +0242 % The above copyright notice and this permission notice shall be included in all +0243 % copies or substantial portions of the Software. +0244 % +0245 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0246 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0247 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0248 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0249 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0250 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0251 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/fitDataLUdecomp.html b/doc/nucleus/functions/inversion/fitDataLUdecomp.html index e19f71b..d750fd2 100644 --- a/doc/nucleus/functions/inversion/fitDataLUdecomp.html +++ b/doc/nucleus/functions/inversion/fitDataLUdecomp.html @@ -91,10 +91,10 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls:
      -
    • createKernelMatrix creates a Kernel matrix from signal time vector "t"
    • getFitErrors calculates all relevant fitting errors for the NMR inversion
    • getTLogMean calculates the T logmean value out of a relaxation time
    +
  • createKernelMatrix creates a Kernel matrix from signal time vector "t"
  • getFitErrors calculates all relevant fitting errors for the NMR inversion
  • getTLogMean calculates the T logmean value out of a relaxation time
  • This function is called by: +
  • runInversionBatch batch processes the inversion using for all NMR signals
  • runInversionStd controls the standard inversion process to invert a
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • @@ -281,7 +281,7 @@

    SOURCE CODE ^getTLogMean(T1T2me,f); +0182 fitdata.Tlgm = getTLogMean(T1T2me,f); 0183 fitdata.E0 = E0; 0184 fitdata.residual = out.residual; 0185 fitdata.chi2 = out.chi2; @@ -291,10 +291,12 @@

    SOURCE CODE ^return +0192 fitdata.invtype = 'LU'; +0193 fitdata.invparams = parameter; 0194 -0195 %------------- END OF CODE -------------- +0195 return +0196 +0197 %------------- END OF CODE --------------
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/fitDataMultiModal.html b/doc/nucleus/functions/inversion/fitDataMultiModal.html index 500034f..f468560 100644 --- a/doc/nucleus/functions/inversion/fitDataMultiModal.html +++ b/doc/nucleus/functions/inversion/fitDataMultiModal.html @@ -23,7 +23,7 @@

    PURPOSE ^ is a control routine that uses either 'lsqnonlin' or

    SYNOPSIS ^

    -
    function [fitdata] = fitDataMultiModal(time,signal,parameter,nModes)
    +
    function [fitdata] = fitDataMultiModal(time,signal,parameter)

    DESCRIPTION ^

    fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
    @@ -37,6 +37,7 @@ 

    DESCRIPTION ^DESCRIPTION ^DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • createKernelMatrix creates a Kernel matrix from signal time vector "t"
  • estimateJacobian numerically estimates (in a very simple manner) a
  • fcn_fitMultiModal is the objective function for N free distribution
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • getConfInterval calculates the confidence interval for the inversion
  • getFitErrors calculates all relevant fitting errors for the NMR inversion
  • getTLogMean calculates the T logmean value out of a relaxation time
  • This function is called by: +
  • runInversionBatch batch processes the inversion using for all NMR signals
  • runInversionStd controls the standard inversion process to invert a
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • SOURCE CODE ^

    -
    0001 function [fitdata] = fitDataMultiModal(time,signal,parameter,nModes)
    +
    0001 function [fitdata] = fitDataMultiModal(time,signal,parameter)
     0002 %fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
     0003 %'fminsearchbnd' to fit NMR data with 'nModes' multi modal relaxation time
     0004 %distributions (T1 or T2)
    @@ -123,16 +123,16 @@ 

    SOURCE CODE ^% time - time vector 0011 % signal - NMR signal vector (no complex data allowed!) 0012 % parameter - struct that holds additional settings: -0013 % T1T2 : flag between 'T1' or 'T2' inversion -0014 % T1IRfac : either '1' or '2' depending on T1 method -0015 % Tb : bulk relaxation time -0016 % Td : diffusion relaxation time -0017 % Tint : relaxation times [log10(tmin) log10(tmax) Ndec] -0018 % noise : noise level needed for 'discrep' discrepancy -0019 % principle -0020 % optim : 'on' or 'off' (Optimization Toolbox) -0021 % W : error weighting matrix (optional) -0022 % nModes - No. of free distributions +0013 % nModes : No. of free distributions +0014 % T1T2 : flag between 'T1' or 'T2' inversion +0015 % T1IRfac : either '1' or '2' depending on T1 method +0016 % Tb : bulk relaxation time +0017 % Td : diffusion relaxation time +0018 % Tint : relaxation times [log10(tmin) log10(tmax) Ndec] +0019 % noise : noise level needed for 'discrep' discrepancy +0020 % principle +0021 % optim : 'on' or 'off' (Optimization Toolbox) +0022 % W : error weighting matrix (optional) 0023 % 0024 % Outputs: 0025 % fitdata - struct that holds the inversion results: @@ -197,221 +197,233 @@

    SOURCE CODE ^end 0085 0086 % get the input parameters -0087 % T1/T2 switch -0088 flag = parameter.T1T2; -0089 % T1 Sat/Inv Recovery factor -0090 T1IRfac = parameter.T1IRfac; -0091 % bulk relaxation time -0092 Tb = parameter.Tb; -0093 % diffusion relaxation time -0094 Td = parameter.Td; -0095 % smallest value in RTD (log10 value) -0096 tstart = parameter.Tint(1); -0097 % largest value in RTD (log10 value) -0098 tend = parameter.Tint(2); -0099 % N per decade in RTD -0100 N = parameter.Tint(3); -0101 -0102 % get boundary values for mu, sigma and amp by first applying a free -0103 % exponential fit -0104 param0.T1IRfac = T1IRfac; -0105 param0.noise = parameter.noise; -0106 param0.optim = parameter.optim; -0107 param0.Tfixed_bool = [0 0 0 0 0]; -0108 param0.Tfixed_val = [0 0 0 0 0]; -0109 if isfield(parameter,'W') -0110 param0.W = parameter.W; -0111 end -0112 % free exponential fit to get some reasonable start values -0113 invstd0 = fitDataFree(t,s,flag,param0,nModes); -0114 -0115 % start values for E and T -0116 x0 = zeros(1,3*nModes); -0117 lb = zeros(1,3*nModes); -0118 ub = zeros(1,3*nModes); -0119 for i = 1:nModes -0120 % initial values for T, sigma and E -0121 x0(3*i-2) = log(invstd0.x(2*i)); -0122 x0(3*i-1) = 1; -0123 x0(3*i) = invstd0.x(2*i-1); -0124 -0125 % lower bounds for T, sigma and E -0126 lb(3*i-2) = log(1e-6);%log(invstd0.x(2*i)*0.8);%log(invstd0.x(2*i) - 10*invstd0.ci(2*i)); -0127 lb(3*i-1) = 0.01; -0128 lb(3*i) = invstd0.x(2*i-1)*0.8;%invstd0.x(2*i-1) - 10*invstd0.ci(2*i-1); -0129 -0130 % upper bounds for T, sigma and E -0131 ub(3*i-2) = log(10);%log(invstd0.x(2*i) + 50*invstd0.ci(2*i)); -0132 ub(3*i-1) = 3.5; -0133 ub(3*i) = max(invstd0.E0)*1.1;%invstd0.x(2*i-1) + 50*invstd0.ci(2*i-1); -0134 end -0135 -0136 % switch off output if no option is given via 'parameter' -0137 if ~isfield(parameter,'info') -0138 parameter.info = 'off'; -0139 end -0140 -0141 % create the relaxation time vector -0142 T1T2me = logspace(tstart,tend,(tend-tstart)*N); +0087 nModes = parameter.nModes; +0088 % T1/T2 switch +0089 flag = parameter.T1T2; +0090 % T1 Sat/Inv Recovery factor +0091 T1IRfac = parameter.T1IRfac; +0092 % bulk relaxation time +0093 Tb = parameter.Tb; +0094 % diffusion relaxation time +0095 Td = parameter.Td; +0096 % smallest value in RTD (log10 value) +0097 tstart = parameter.Tint(1); +0098 % largest value in RTD (log10 value) +0099 tend = parameter.Tint(2); +0100 % N per decade in RTD +0101 N = parameter.Tint(3); +0102 +0103 % get boundary values for mu, sigma and amp by first applying a free +0104 % exponential fit +0105 param0.T1IRfac = T1IRfac; +0106 param0.noise = parameter.noise; +0107 param0.optim = parameter.optim; +0108 param0.Tfixed_bool = [0 0 0 0 0]; +0109 param0.Tfixed_val = [0 0 0 0 0]; +0110 if isfield(parameter,'W') +0111 param0.W = parameter.W; +0112 end +0113 % free exponential fit to get some reasonable start values +0114 invstd0 = fitDataFree(t,s,flag,param0,nModes); +0115 +0116 % start values for E and T +0117 x0 = zeros(1,3*nModes); +0118 lb = zeros(1,3*nModes); +0119 ub = zeros(1,3*nModes); +0120 for i = 1:nModes +0121 % initial values for T, sigma and E +0122 x0(3*i-2) = log(invstd0.x(2*i)); +0123 x0(3*i-1) = 1; +0124 x0(3*i) = invstd0.x(2*i-1); +0125 +0126 % lower bounds for T, sigma and E +0127 %lb(3*i-2) = log(1e-6);%log(invstd0.x(2*i)*0.8);%log(invstd0.x(2*i) - 10*invstd0.ci(2*i)); +0128 lb(3*i-2) = log(invstd0.x(2*i)/100);%log(invstd0.x(2*i) - 10*invstd0.ci(2*i)); +0129 lb(3*i-1) = 0.01; +0130 lb(3*i) = invstd0.x(2*i-1)*0.8;%invstd0.x(2*i-1) - 10*invstd0.ci(2*i-1); +0131 +0132 % upper bounds for T, sigma and E +0133 %ub(3*i-2) = log(10);%log(invstd0.x(2*i) + 50*invstd0.ci(2*i)); +0134 ub(3*i-2) = log(invstd0.x(2*i)*100);%log(invstd0.x(2*i) + 50*invstd0.ci(2*i)); +0135 ub(3*i-1) = 3.5; +0136 ub(3*i) = max(invstd0.E0)*1.1;%invstd0.x(2*i-1) + 50*invstd0.ci(2*i-1); +0137 end +0138 +0139 % switch off output if no option is given via 'parameter' +0140 if ~isfield(parameter,'info') +0141 parameter.info = 'off'; +0142 end 0143 -0144 % just needed for debugging the Optimization Toolbox availability -0145 % parameter.optim = 'off'; +0144 % create the relaxation time vector +0145 T1T2me = logspace(tstart,tend,(tend-tstart)*N); 0146 -0147 switch parameter.optim -0148 case 'on' -0149 % solver options -0150 options = optimoptions('lsqnonlin'); -0151 options.Algorithm = 'levenberg-marquardt'; -0152 options.Display = parameter.info; -0153 options.OptimalityTolerance = 1e-12; -0154 options.StepTolerance = 1e-12; -0155 -0156 iparam.optim = parameter.optim; -0157 iparam.flag = flag; -0158 iparam.T1IRfac = T1IRfac; -0159 iparam.nModes = nModes; -0160 iparam.t = t; -0161 iparam.s = s; -0162 iparam.T = T1T2me; -0163 iparam.Tb = Tb; -0164 iparam.Td = Td; -0165 [x,~,~,~,output,~,jacobian] = lsqnonlin(@(x)fcn_fitMultiModal(x,iparam),... -0166 x0,lb,ub,options); -0167 -0168 case 'off' -0169 % solver options -0170 options = optimset('Display',parameter.info,'MaxFunEvals',10^6,... -0171 'MaxIter',5000,'TolFun',1e-12,'TolX',1e-12); -0172 -0173 iparam.optim = parameter.optim; -0174 iparam.flag = flag; -0175 iparam.T1IRfac = T1IRfac; -0176 iparam.nModes = nModes; -0177 iparam.t = t; -0178 iparam.s = s; -0179 iparam.T = T1T2me; -0180 iparam.Tb = Tb; -0181 iparam.Td = Td; -0182 [x,~,~,output] = fminsearchbnd(@(x) fcn_fitMultiModal(x,iparam),... -0183 x0,lb,ub,options); -0184 -0185 % get Jacobian -0186 % therefore we need to switch the 'optim' on to get the correct -0187 % output of 'fcn_fitMultiModal' -0188 iparam.optim = 'on'; -0189 jacobian = estimateJacobian(@(x)fcn_fitMultiModal(x,iparam),x); -0190 end -0191 -0192 % assemble the final RTD -0193 Tdist = 0; -0194 for i = 1:length(x)/3 -0195 mu = exp(x(3*i-2)); % T -0196 sigma = x(3*i-1); % S -0197 amp = x(3*i); % E -0198 -0199 tmp = 1./( sigma*sqrt(2*pi)).*exp(-((log(T1T2me) - log(mu))/ sqrt(2)/sigma).^2); -0200 -0201 % scale to amplitude -0202 tmp = (tmp/sum(tmp)) * amp; -0203 % add the tmp per mu to Tdist -0204 Tdist = Tdist + tmp; -0205 end -0206 f = Tdist; -0207 % the fitted signal -0208 K = createKernelMatrix(t,T1T2me,Tb,Td,flag,1); -0209 si = K*f'; -0210 -0211 % get the fit -0212 fit_t = t; -0213 fit_s = si; -0214 -0215 % get residuals and error measures -0216 if isfield(parameter,'W') -0217 % when signal gating was used the error estimates need to be adjusted -0218 out = getFitErrors(signal,fit_s,parameter.noise,parameter.W); -0219 else -0220 out = getFitErrors(signal,fit_s,parameter.noise); -0221 end -0222 -0223 % confidence interval -0224 ci = getConfInterval(out.resnorm,jacobian,0.05); +0147 % just needed for debugging the Optimization Toolbox availability +0148 % parameter.optim = 'off'; +0149 +0150 switch parameter.optim +0151 case 'on' +0152 % solver options +0153 options = optimoptions('lsqnonlin'); +0154 options.Algorithm = 'levenberg-marquardt'; +0155 options.Display = parameter.info; +0156 options.OptimalityTolerance = 1e-12; +0157 options.StepTolerance = 1e-12; +0158 +0159 iparam.optim = parameter.optim; +0160 iparam.flag = flag; +0161 iparam.T1IRfac = T1IRfac; +0162 iparam.nModes = nModes; +0163 iparam.t = t; +0164 iparam.s = s; +0165 iparam.T = T1T2me; +0166 iparam.Tb = Tb; +0167 iparam.Td = Td; +0168 [x,~,~,~,output,~,jacobian] = lsqnonlin(@(x)fcn_fitMultiModal(x,iparam),... +0169 x0,lb,ub,options); +0170 +0171 case 'off' +0172 % solver options +0173 options = optimset('Display',parameter.info,'MaxFunEvals',10^6,... +0174 'MaxIter',5000,'TolFun',1e-12,'TolX',1e-12); +0175 +0176 iparam.optim = parameter.optim; +0177 iparam.flag = flag; +0178 iparam.T1IRfac = T1IRfac; +0179 iparam.nModes = nModes; +0180 iparam.t = t; +0181 iparam.s = s; +0182 iparam.T = T1T2me; +0183 iparam.Tb = Tb; +0184 iparam.Td = Td; +0185 [x,~,~,output] = fminsearchbnd(@(x) fcn_fitMultiModal(x,iparam),... +0186 x0,lb,ub,options); +0187 +0188 % get Jacobian +0189 % therefore we need to switch the 'optim' on to get the correct +0190 % output of 'fcn_fitMultiModal' +0191 iparam.optim = 'on'; +0192 jacobian = estimateJacobian(@(x)fcn_fitMultiModal(x,iparam),x); +0193 end +0194 +0195 % assemble the final RTD +0196 Tdist = 0; +0197 for i = 1:length(x)/3 +0198 mu = exp(x(3*i-2)); % T +0199 sigma = x(3*i-1); % S +0200 amp = x(3*i); % E +0201 +0202 tmp = 1./( sigma*sqrt(2*pi)).*exp(-((log(T1T2me) - log(mu))/ sqrt(2)/sigma).^2); +0203 +0204 % scale to amplitude +0205 tmp = (tmp/sum(tmp)) * amp; +0206 % add the tmp per mu to Tdist +0207 Tdist = Tdist + tmp; +0208 end +0209 f = Tdist; +0210 % the fitted signal +0211 K = createKernelMatrix(t,T1T2me,Tb,Td,flag,1); +0212 si = K*f'; +0213 +0214 % get the fit +0215 fit_t = t; +0216 fit_s = si; +0217 +0218 % get residuals and error measures +0219 if isfield(parameter,'W') +0220 % when signal gating was used the error estimates need to be adjusted +0221 out = getFitErrors(signal,fit_s,parameter.noise,parameter.W); +0222 else +0223 out = getFitErrors(signal,fit_s,parameter.noise); +0224 end 0225 -0226 % sort the relaxation times in ascending order and adjust the confidence -0227 % interval accordingly -0228 T = exp(x(1:3:end)); -0229 S = x(2:3:end); -0230 E = x(3:3:end); -0231 [T,idx] = sort(T); -0232 S = S(idx); -0233 E = E(idx); -0234 ciT = ci(1:3:end); -0235 ciS = ci(2:3:end); -0236 ciE = ci(3:3:end); -0237 ciT = ciT(idx); -0238 ciS = ciS(idx); -0239 ciE = ciE(idx); -0240 ci(1:3:end) = ciT; -0241 ci(2:3:end) = ciS; -0242 ci(3:3:end) = ciE; -0243 -0244 % get "initial" value E0 -0245 switch flag -0246 case 'T1' -0247 K0 = createKernelMatrix(10*time(end),T1T2me,Tb,Td,flag,T1IRfac); -0248 case 'T2' -0249 K0 = createKernelMatrix(0,T1T2me,Tb,Td,flag,T1IRfac); -0250 end -0251 E0 = K0*f'; -0252 -0253 % output struct -0254 fitdata.fit_t = fit_t; -0255 fitdata.fit_s = fit_s; -0256 fitdata.T1T2me = T1T2me(:); -0257 fitdata.T1T2f = f(:); -0258 fitdata.Tlgm = getTLogMean(T1T2me,f); -0259 fitdata.E0 = E0; -0260 fitdata.ciE0 = NaN; -0261 fitdata.resnorm = out.resnorm; -0262 fitdata.residual = out.residual; -0263 fitdata.errornorm = out.errnorm1; -0264 fitdata.lambda_out = 0; -0265 fitdata.rms = out.rms; -0266 fitdata.chi2 = out.chi2; -0267 fitdata.ci = ci; -0268 fitdata.T = T; -0269 fitdata.S = S; -0270 fitdata.E = E; -0271 fitdata.x = x; -0272 fitdata.lb = lb; -0273 fitdata.ub = ub; -0274 fitdata.output = output; -0275 -0276 return -0277 -0278 %------------- END OF CODE -------------- -0279 -0280 %% License: -0281 % MIT License -0282 % -0283 % Copyright (c) 2022 Thomas Hiller -0284 % -0285 % Permission is hereby granted, free of charge, to any person obtaining a copy -0286 % of this software and associated documentation files (the "Software"), to deal -0287 % in the Software without restriction, including without limitation the rights -0288 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0289 % copies of the Software, and to permit persons to whom the Software is -0290 % furnished to do so, subject to the following conditions: -0291 % -0292 % The above copyright notice and this permission notice shall be included in all -0293 % copies or substantial portions of the Software. +0226 % confidence interval +0227 ci = getConfInterval(out.resnorm,jacobian,0.05); +0228 +0229 % sort the relaxation times in ascending order and adjust the confidence +0230 % interval accordingly +0231 T = exp(x(1:3:end)); +0232 S = x(2:3:end); +0233 E = x(3:3:end); +0234 [T,idx] = sort(T); +0235 S = S(idx); +0236 E = E(idx); +0237 ciT = ci(1:3:end); +0238 ciS = ci(2:3:end); +0239 ciE = ci(3:3:end); +0240 ciT = ciT(idx); +0241 ciS = ciS(idx); +0242 ciE = ciE(idx); +0243 ci(1:3:end) = ciT; +0244 ci(2:3:end) = ciS; +0245 ci(3:3:end) = ciE; +0246 +0247 % get "initial" value E0 +0248 switch flag +0249 case 'T1' +0250 K0 = createKernelMatrix(10*time(end),T1T2me,Tb,Td,flag,T1IRfac); +0251 case 'T2' +0252 K0 = createKernelMatrix(0,T1T2me,Tb,Td,flag,T1IRfac); +0253 end +0254 E0 = K0*f'; +0255 +0256 % model norm |L*x|_2 +0257 xn = norm(f,2); +0258 % residual norm |A*x-b|_2 +0259 rn = norm(out.residual,2); +0260 +0261 % output struct +0262 fitdata.fit_t = fit_t; +0263 fitdata.fit_s = fit_s; +0264 fitdata.T1T2me = T1T2me(:); +0265 fitdata.T1T2f = f(:); +0266 fitdata.Tlgm = getTLogMean(T1T2me,f); +0267 fitdata.E0 = E0; +0268 fitdata.ciE0 = NaN; +0269 fitdata.resnorm = out.resnorm; +0270 fitdata.residual = out.residual; +0271 fitdata.errornorm = out.errnorm1; +0272 fitdata.lambda_out = 0; +0273 fitdata.rms = out.rms; +0274 fitdata.chi2 = out.chi2; +0275 fitdata.xn = xn; +0276 fitdata.rn = rn; +0277 fitdata.ci = ci; +0278 fitdata.T = T; +0279 fitdata.S = S; +0280 fitdata.E = E; +0281 fitdata.x = x; +0282 fitdata.lb = lb; +0283 fitdata.ub = ub; +0284 fitdata.output = output; +0285 fitdata.invtype = 'MUMO'; +0286 fitdata.invparams = parameter; +0287 +0288 return +0289 +0290 %------------- END OF CODE -------------- +0291 +0292 %% License: +0293 % MIT License 0294 % -0295 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0296 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0297 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0298 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0299 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0300 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0301 % SOFTWARE.

    +0295 % Copyright (c) 2022 Thomas Hiller +0296 % +0297 % Permission is hereby granted, free of charge, to any person obtaining a copy +0298 % of this software and associated documentation files (the "Software"), to deal +0299 % in the Software without restriction, including without limitation the rights +0300 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0301 % copies of the Software, and to permit persons to whom the Software is +0302 % furnished to do so, subject to the following conditions: +0303 % +0304 % The above copyright notice and this permission notice shall be included in all +0305 % copies or substantial portions of the Software. +0306 % +0307 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0308 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0309 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0310 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0311 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0312 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0313 % SOFTWARE.

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/getAAD.html b/doc/nucleus/functions/inversion/getAAD.html new file mode 100644 index 0000000..b1f88dd --- /dev/null +++ b/doc/nucleus/functions/inversion/getAAD.html @@ -0,0 +1,176 @@ + + + + Description of getAAD + + + + + + + + + + + +

    getAAD +

    + +

    PURPOSE ^

    +
    gets the average absolute deviation from the values in x
    + +

    SYNOPSIS ^

    +
    function aad = getAAD(x,flag,dim)
    + +

    DESCRIPTION ^

    +
    getAAD gets the average absolute deviation from the values in x
    +
    + Syntax:
    +       getAAD(x,flag)
    +
    + Inputs:
    +       x - values
    +       flag - '0' (mean) or '1' (median)
    +       dim - to calculate aad on
    +
    + Outputs:
    +       aad - average absolute deviation
    +
    + Example:
    +       aad = getAAD(TLGMvals,1)
    +
    + Other m-files required:
    +       none
    +
    + Subfunctions:
    +       none
    +
    + MAT-files required:
    +       none
    +
    + See also:
    + Author: see AUTHORS.md
    + email: see AUTHORS.md
    + License: MIT License (at end)
    + + +

    CROSS-REFERENCE INFORMATION ^

    +This function calls: +
      +
    +This function is called by: +
      +
    • UncertView is an extra subGUI to show results of the uncertainty
    + + + + +

    SOURCE CODE ^

    +
    0001 function aad = getAAD(x,flag,dim)
    +0002 %getAAD gets the average absolute deviation from the values in x
    +0003 %
    +0004 % Syntax:
    +0005 %       getAAD(x,flag)
    +0006 %
    +0007 % Inputs:
    +0008 %       x - values
    +0009 %       flag - '0' (mean) or '1' (median)
    +0010 %       dim - to calculate aad on
    +0011 %
    +0012 % Outputs:
    +0013 %       aad - average absolute deviation
    +0014 %
    +0015 % Example:
    +0016 %       aad = getAAD(TLGMvals,1)
    +0017 %
    +0018 % Other m-files required:
    +0019 %       none
    +0020 %
    +0021 % Subfunctions:
    +0022 %       none
    +0023 %
    +0024 % MAT-files required:
    +0025 %       none
    +0026 %
    +0027 % See also:
    +0028 % Author: see AUTHORS.md
    +0029 % email: see AUTHORS.md
    +0030 % License: MIT License (at end)
    +0031 
    +0032 %------------- BEGIN CODE --------------
    +0033 
    +0034 %% check for Statistics Toolbox
    +0035 Mver = ver;
    +0036 hasStatBox = false;
    +0037 for i = 1:size(Mver,2)
    +0038     if strfind(Mver(i).Name,'Statistics')
    +0039         hasStatBox = true;
    +0040         break
    +0041     end
    +0042 end
    +0043 
    +0044 % check flag
    +0045 if nargin < 2 || isempty(flag)
    +0046     flag = 0;
    +0047 end
    +0048 
    +0049 % check dim
    +0050 if nargin < 3 || isempty(dim)
    +0051     % get dimension
    +0052     dim = find(size(x)~=1,1);
    +0053     if isempty(dim)
    +0054         dim = 1;
    +0055     end
    +0056 end
    +0057 
    +0058 %% calculate AAD
    +0059 if hasStatBox
    +0060     % use Statistics Toolbox built-in function 'mad'
    +0061     aad = mad(x,flag,dim);
    +0062 else
    +0063     % get rid of NaNs and Infs
    +0064     x(isnan(x)) = [];
    +0065     x(isinf(x)) = [];
    +0066     if flag == 0
    +0067         % get AAD from mean
    +0068         aad = mean(abs(x-mean(x,dim)),dim);
    +0069     elseif flag == 1
    +0070         % get AAD from median
    +0071         aad = median(abs(x-median(x,dim)),dim);
    +0072     else
    +0073         error('getAAD: flag must be 0 or 1');
    +0074     end
    +0075 end
    +0076 
    +0077 return
    +0078 
    +0079 %------------- END OF CODE --------------
    +0080 
    +0081 %% License:
    +0082 % MIT License
    +0083 %
    +0084 % Copyright (c) 2024 Thomas Hiller
    +0085 %
    +0086 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +0087 % of this software and associated documentation files (the "Software"), to deal
    +0088 % in the Software without restriction, including without limitation the rights
    +0089 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +0090 % copies of the Software, and to permit persons to whom the Software is
    +0091 % furnished to do so, subject to the following conditions:
    +0092 %
    +0093 % The above copyright notice and this permission notice shall be included in all
    +0094 % copies or substantial portions of the Software.
    +0095 %
    +0096 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +0097 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +0098 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +0099 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +0100 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +0101 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +0102 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/getConfInterval.html b/doc/nucleus/functions/inversion/getConfInterval.html index eecfcef..8f274f2 100644 --- a/doc/nucleus/functions/inversion/getConfInterval.html +++ b/doc/nucleus/functions/inversion/getConfInterval.html @@ -69,7 +69,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=getStudentInvCDF calculates the inverse of Student's t CDF using the This function is called by:
      -
    • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
    • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
    +
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • diff --git a/doc/nucleus/functions/inversion/getFitErrors.html b/doc/nucleus/functions/inversion/getFitErrors.html index 864b29b..419b52b 100644 --- a/doc/nucleus/functions/inversion/getFitErrors.html +++ b/doc/nucleus/functions/inversion/getFitErrors.html @@ -72,7 +72,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=getChi2 the chi2 of a NMR fit (noise weighted error quality) This function is called by: +
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • diff --git a/doc/nucleus/functions/inversion/getTLogMean.html b/doc/nucleus/functions/inversion/getTLogMean.html index 1c1783d..5687637 100644 --- a/doc/nucleus/functions/inversion/getTLogMean.html +++ b/doc/nucleus/functions/inversion/getTLogMean.html @@ -23,7 +23,7 @@

    PURPOSE ^ calculates the T logmean value out of a relaxation time

    SYNOPSIS ^

    -
    function [TLGM,index] = getTLogMean(T,f)
    +
    function [TLGM,index] = getTLogMean(T,f,varargin)

    DESCRIPTION ^

    getTLogMean calculates the T logmean value out of a relaxation time
    @@ -64,13 +64,13 @@ 

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • +
  • UncertView is an extra subGUI to show results of the uncertainty
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • fitDataLSQ is a control routine that fits NMR data multi-exponentially;
  • fitDataLUdecomp is a control routine that uses a LU decomposition and the
  • fitDataMultiModal is a control routine that uses either 'lsqnonlin' or
  • SOURCE CODE ^

    -
    0001 function [TLGM,index] = getTLogMean(T,f)
    +
    0001 function [TLGM,index] = getTLogMean(T,f,varargin)
     0002 %getTLogMean calculates the T logmean value out of a relaxation time
     0003 %distribution
     0004 %
    @@ -105,44 +105,52 @@ 

    SOURCE CODE ^%------------- BEGIN CODE -------------- 0034 0035 %% calculate TLGM -0036 % make everything a column vector -0037 T = T(:); -0038 f = f(:); -0039 -0040 % get TLGM -0041 TLGM = 10.^(sum(f.*log10(T))./sum(f)); +0036 % check input +0037 if nargin > 2 +0038 mask = varargin{1}; +0039 else +0040 mask = true(size(T)); +0041 end 0042 -0043 % if desired get the closest T -0044 if nargout == 2 -0045 index = find(abs(T-TLGM)==min(abs(T-TLGM))); -0046 end +0043 % make everything a column vector +0044 T = T(:); +0045 f = f(:); +0046 mask = mask(:); 0047 -0048 return -0049 -0050 %------------- END OF CODE -------------- -0051 -0052 %% License: -0053 % MIT License -0054 % -0055 % Copyright (c) 2018 Thomas Hiller -0056 % -0057 % Permission is hereby granted, free of charge, to any person obtaining a copy -0058 % of this software and associated documentation files (the "Software"), to deal -0059 % in the Software without restriction, including without limitation the rights -0060 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0061 % copies of the Software, and to permit persons to whom the Software is -0062 % furnished to do so, subject to the following conditions: -0063 % -0064 % The above copyright notice and this permission notice shall be included in all -0065 % copies or substantial portions of the Software. -0066 % -0067 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0068 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0069 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0070 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0071 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0072 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0073 % SOFTWARE.

    +0048 % get TLGM +0049 TLGM = 10.^(sum(f(mask).*log10(T(mask)))./sum(f(mask))); +0050 +0051 % if desired get the closest T +0052 if nargout == 2 +0053 index = find(abs(T(mask)-TLGM)==min(abs(T(mask)-TLGM))); +0054 end +0055 +0056 return +0057 +0058 %------------- END OF CODE -------------- +0059 +0060 %% License: +0061 % MIT License +0062 % +0063 % Copyright (c) 2018 Thomas Hiller +0064 % +0065 % Permission is hereby granted, free of charge, to any person obtaining a copy +0066 % of this software and associated documentation files (the "Software"), to deal +0067 % in the Software without restriction, including without limitation the rights +0068 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0069 % copies of the Software, and to permit persons to whom the Software is +0070 % furnished to do so, subject to the following conditions: +0071 % +0072 % The above copyright notice and this permission notice shall be included in all +0073 % copies or substantial portions of the Software. +0074 % +0075 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0076 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0077 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0078 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0079 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0080 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0081 % SOFTWARE.

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/menu.html b/doc/nucleus/functions/inversion/menu.html index da2396f..5eaa6c2 100644 --- a/doc/nucleus/functions/inversion/menu.html +++ b/doc/nucleus/functions/inversion/menu.html @@ -18,7 +18,7 @@

    Index for nucleus\functions\inversion

    Matlab files in this directory:

    +
  • applyGatesToSignal
  • applyRegularization
  • createKernelMatrix
  • estimateJacobian
  • estimateUncertainty
  • fcn_JointInvfixed
  • fcn_JointInvfree
  • fcn_JointInvshape
  • fcn_fitFreeT1
  • fcn_fitFreeT1_fmin
  • fcn_fitFreeT2
  • fcn_fitFreeT2_fmin
  • fcn_fitFreeT2w
  • fcn_fitMultiModal
  • fitDataFree
  • fitDataLSQ
  • fitDataLUdecomp
  • fitDataMultiModal
  • getAAD
  • getChi2
  • getConfInterval
  • getFitErrors
  • getFitFreeJacobian
  • getLambdaFromLCurve
  • getLambdaFromRMS
  • getStudentInvCDF
  • getTLogMean
  • runUncertaintyCalculation
  • diff --git a/doc/nucleus/functions/inversion/runUncertaintyCalculation.html b/doc/nucleus/functions/inversion/runUncertaintyCalculation.html new file mode 100644 index 0000000..9ad7a38 --- /dev/null +++ b/doc/nucleus/functions/inversion/runUncertaintyCalculation.html @@ -0,0 +1,188 @@ + + + + Description of runUncertaintyCalculation + + + + + + + + + + + +

    runUncertaintyCalculation +

    + +

    PURPOSE ^

    +
    caluclates inverison statistics in some kind of
    + +

    SYNOPSIS ^

    +
    function runUncertaintyCalculation
    + +

    DESCRIPTION ^

    +
    runUncertaintyCalculation caluclates inverison statistics in some kind of
    +bootstrapping manner
    +
    + Syntax:
    +       runUncertaintyCalculation
    +
    + Inputs:
    +       none
    +
    + Outputs:
    +       none
    +
    + Example:
    +       runUncertaintyCalculation
    +
    + Other m-files required:
    +       estimateUncertainty.m
    +
    + Subfunctions:
    +       none
    +
    + MAT-files required:
    +       none
    +
    + See also: NUCLEUSinv
    + Author: see AUTHORS.md
    + email: see AUTHORS.md
    + License: MIT License (at end)
    + + +

    CROSS-REFERENCE INFORMATION ^

    +This function calls: + +This function is called by: +
      +
    • onPushRun handles the callbacks to all RUN push buttons in both GUIs and
    + + + + +

    SOURCE CODE ^

    +
    0001 function runUncertaintyCalculation
    +0002 %runUncertaintyCalculation caluclates inverison statistics in some kind of
    +0003 %bootstrapping manner
    +0004 %
    +0005 % Syntax:
    +0006 %       runUncertaintyCalculation
    +0007 %
    +0008 % Inputs:
    +0009 %       none
    +0010 %
    +0011 % Outputs:
    +0012 %       none
    +0013 %
    +0014 % Example:
    +0015 %       runUncertaintyCalculation
    +0016 %
    +0017 % Other m-files required:
    +0018 %       estimateUncertainty.m
    +0019 %
    +0020 % Subfunctions:
    +0021 %       none
    +0022 %
    +0023 % MAT-files required:
    +0024 %       none
    +0025 %
    +0026 % See also: NUCLEUSinv
    +0027 % Author: see AUTHORS.md
    +0028 % email: see AUTHORS.md
    +0029 % License: MIT License (at end)
    +0030 
    +0031 %------------- BEGIN CODE --------------
    +0032 
    +0033 %% get GUI handle and data
    +0034 fig = findobj('Tag','INV');
    +0035 gui = getappdata(fig,'gui');
    +0036 data = getappdata(fig,'data');
    +0037 INVdata = getappdata(fig,'INVdata');
    +0038 
    +0039 % id of the chosen NMR signal
    +0040 id = get(gui.listbox_handles.signal,'Value');
    +0041 
    +0042 if ~isempty(id) && ~isempty(INVdata) && isstruct(INVdata{id})
    +0043     % get original inversion data
    +0044     INVdata0 = INVdata{id};
    +0045     invstd = INVdata0.results.invstd; % results from original inversion
    +0046     invtype = INVdata0.invstd.invtype;
    +0047 
    +0048     % original fit parameter
    +0049     iparam = invstd.invparams;
    +0050 
    +0051     % uncertainty parameter
    +0052     uparam.id = id;
    +0053     uparam.time = INVdata0.results.nmrproc.t;
    +0054     uparam.signal = INVdata0.results.nmrproc.s;
    +0055     % can be set when switching the inversion method
    +0056     switch invtype
    +0057         case {'LU','NNLS'}
    +0058             uparam.uncert.Method = 'RMS_bound';
    +0059         case 'MUMO'
    +0060             uparam.uncert.Method = 'RMS_free';
    +0061     end
    +0062     uparam.uncert.Thresh = data.uncert.Thresh;
    +0063     uparam.uncert.chi2_range = [0 100];
    +0064     uparam.uncert.mnorm_range = [0 1.5*invstd.xn];
    +0065     uparam.uncert.N = data.uncert.N;
    +0066     uparam.uncert.Max = data.uncert.Max;
    +0067     invstd = estimateUncertainty(invtype,invstd,iparam,uparam);
    +0068 
    +0069     % save updated inversion results
    +0070     invstd.uncert.params = uparam;
    +0071     data.results.invstd = invstd;
    +0072     INVdata0.results.invstd = invstd;
    +0073 
    +0074     % update INVdata
    +0075     INVdata{id} = INVdata0;
    +0076     % update GUI data
    +0077     setappdata(fig,'data',data);
    +0078     % update GUI INVdata
    +0079     setappdata(fig,'INVdata',INVdata);
    +0080 
    +0081     % update plots and INFO fields
    +0082     updatePlotsSignal;
    +0083     updatePlotsDistribution;
    +0084     updateInfo(gui.plots.SignalPanel);
    +0085 else
    +0086     helpdlg('Cannot start calculation because there is no suitable data!',...
    +0087         'Perform inversion first.');
    +0088 end
    +0089 
    +0090 end
    +0091 
    +0092 %------------- END OF CODE --------------
    +0093 
    +0094 %% License:
    +0095 % MIT License
    +0096 %
    +0097 % Copyright (c) 2023 Thomas Hiller
    +0098 %
    +0099 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +0100 % of this software and associated documentation files (the "Software"), to deal
    +0101 % in the Software without restriction, including without limitation the rights
    +0102 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +0103 % copies of the Software, and to permit persons to whom the Software is
    +0104 % furnished to do so, subject to the following conditions:
    +0105 %
    +0106 % The above copyright notice and this permission notice shall be included in all
    +0107 % copies or substantial portions of the Software.
    +0108 %
    +0109 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +0110 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +0111 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +0112 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +0113 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +0114 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +0115 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/externals/kde/kde.m b/externals/kde/kde.m new file mode 100644 index 0000000..7d9acab --- /dev/null +++ b/externals/kde/kde.m @@ -0,0 +1,145 @@ +function [bandwidth,density,xmesh,cdf]=kde(data,n,MIN,MAX) +% Reliable and extremely fast kernel density estimator for one-dimensional data; +% Gaussian kernel is assumed and the bandwidth is chosen automatically; +% Unlike many other implementations, this one is immune to problems +% caused by multimodal densities with widely separated modes (see example). The +% estimation does not deteriorate for multimodal densities, because we never assume +% a parametric model for the data. +% INPUTS: +% data - a vector of data from which the density estimate is constructed; +% n - the number of mesh points used in the uniform discretization of the +% interval [MIN, MAX]; n has to be a power of two; if n is not a power of two, then +% n is rounded up to the next power of two, i.e., n is set to n=2^ceil(log2(n)); +% the default value of n is n=2^12; +% MIN, MAX - defines the interval [MIN,MAX] on which the density estimate is constructed; +% the default values of MIN and MAX are: +% MIN=min(data)-Range/10 and MAX=max(data)+Range/10, where Range=max(data)-min(data); +% OUTPUTS: +% bandwidth - the optimal bandwidth (Gaussian kernel assumed); +% density - column vector of length 'n' with the values of the density +% estimate at the grid points; +% xmesh - the grid over which the density estimate is computed; +% - If no output is requested, then the code automatically plots a graph of +% the density estimate. +% cdf - column vector of length 'n' with the values of the cdf +% Reference: +% Kernel density estimation via diffusion +% Z. I. Botev, J. F. Grotowski, and D. P. Kroese (2010) +% Annals of Statistics, Volume 38, Number 5, pages 2916-2957. + +% +% Example: +% data=[randn(100,1);randn(100,1)*2+35 ;randn(100,1)+55]; +% kde(data,2^14,min(data)-5,max(data)+5); + +data=data(:); %make data a column vector +if nargin<2 % if n is not supplied switch to the default + n=2^14; +end +n=2^ceil(log2(n)); % round up n to the next power of 2; +if nargin<4 %define the default interval [MIN,MAX] + minimum=min(data); maximum=max(data); + Range=maximum-minimum; + MIN=minimum-Range/2; MAX=maximum+Range/2; +end +% set up the grid over which the density estimate is computed; +R=MAX-MIN; dx=R/(n-1); xmesh=MIN+[0:dx:R]; N=length(unique(data)); +%bin the data uniformly using the grid defined above; +initial_data=histc(data,xmesh)/N; initial_data=initial_data/sum(initial_data); +a=dct1d(initial_data); % discrete cosine transform of initial data +% now compute the optimal bandwidth^2 using the referenced method +I=[1:n-1]'.^2; a2=(a(2:end)/2).^2; +% use fzero to solve the equation t=zeta*gamma^[5](t) +t_star=root(@(t)fixed_point(t,N,I,a2),N); +% smooth the discrete cosine transform of initial data using t_star +a_t=a.*exp(-[0:n-1]'.^2*pi^2*t_star/2); +% now apply the inverse discrete cosine transform +if (nargout>1)|(nargout==0) + density=idct1d(a_t)/R; +end +% take the rescaling of the data into account +bandwidth=sqrt(t_star)*R; +density(density<0)=eps; % remove negatives due to round-off error +if nargout==0 + figure(1), plot(xmesh,density) +end +% for cdf estimation +if nargout>3 + f=2*pi^2*sum(I.*a2.*exp(-I*pi^2*t_star)); + t_cdf=(sqrt(pi)*f*N)^(-2/3); + % now get values of cdf on grid points using IDCT and cumsum function + a_cdf=a.*exp(-[0:n-1]'.^2*pi^2*t_cdf/2); + cdf=cumsum(idct1d(a_cdf))*(dx/R); + % take the rescaling into account if the bandwidth value is required + bandwidth_cdf=sqrt(t_cdf)*R; +end + +end +%################################################################ +function out=fixed_point(t,N,I,a2) +% this implements the function t-zeta*gamma^[l](t) +l=7; +f=2*pi^(2*l)*sum(I.^l.*a2.*exp(-I*pi^2*t)); +for s=l-1:-1:2 + K0=prod([1:2:2*s-1])/sqrt(2*pi); const=(1+(1/2)^(s+1/2))/3; + time=(2*const*K0/N/f)^(2/(3+2*s)); + f=2*pi^(2*s)*sum(I.^s.*a2.*exp(-I*pi^2*time)); +end +out=t-(2*N*sqrt(pi)*f)^(-2/5); +end + + + +%############################################################## +function out = idct1d(data) + +% computes the inverse discrete cosine transform +[nrows,ncols]=size(data); +% Compute weights +weights = nrows*exp(i*(0:nrows-1)*pi/(2*nrows)).'; +% Compute x tilde using equation (5.93) in Jain +data = real(ifft(weights.*data)); +% Re-order elements of each column according to equations (5.93) and +% (5.94) in Jain +out = zeros(nrows,1); +out(1:2:nrows) = data(1:nrows/2); +out(2:2:nrows) = data(nrows:-1:nrows/2+1); +% Reference: +% A. K. Jain, "Fundamentals of Digital Image +% Processing", pp. 150-153. +end +%############################################################## + +function data=dct1d(data) +% computes the discrete cosine transform of the column vector data +[nrows,ncols]= size(data); +% Compute weights to multiply DFT coefficients +weight = [1;2*(exp(-i*(1:nrows-1)*pi/(2*nrows))).']; +% Re-order the elements of the columns of x +data = [ data(1:2:end,:); data(end:-2:2,:) ]; +% Multiply FFT by weights: +data= real(weight.* fft(data)); +end + +function t=root(f,N) +% try to find smallest root whenever there is more than one +N=50*(N<=50)+1050*(N>=1050)+N*((N<1050)&(N>50)); +tol=10^-12+0.01*(N-50)/1000; +flag=0; +while flag==0 + try + t=fzero(f,[0,tol]); + flag=1; + catch + tol=min(tol*2,.1); % double search interval + end + if tol==.1 % if all else fails + t=fminbnd(@(x)abs(f(x)),0,.1); flag=1; + end +end +end + + + + + diff --git a/externals/kde/license.txt b/externals/kde/license.txt new file mode 100644 index 0000000..ea31ce6 --- /dev/null +++ b/externals/kde/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2015, Zdravko Botev +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution + * Neither the name of the The University of New South Wales nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/functions/interface/UncertView.m b/functions/interface/UncertView.m new file mode 100644 index 0000000..182ff9f --- /dev/null +++ b/functions/interface/UncertView.m @@ -0,0 +1,1497 @@ +function UncertView(src,~) +%UncertView is an extra subGUI to show results of the uncertainty +%calculation +% +% Syntax: +% UncertView +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% UncertView(src,~) +% +% Other m-files required: +% beautifyAxes +% clearAllAxes +% estimateUncertainty +% createKernelMatrix +% updatePlotsSignal +% updatePlotsDistribution +% updateInfo +% +% Subfunctions: +% uv_closeme +% uv_onEditValue +% uv_updateMASK +% uv_onPushRun +% uv_onPushUpdate +% uv_onPushReset +% uv_updateInformation +% uv_updatePlots +% +% MAT-files required: +% none +% +% See also: NUCLEUSinv +% Author: see AUTHORS.md +% email: see AUTHORS.md +% License: MIT License (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI handle and data +figh_nucleus = ancestor(src,'figure','toplevel'); +nucleus.data = getappdata(figh_nucleus,'data'); +nucleus.gui = getappdata(figh_nucleus,'gui'); +myui = nucleus.gui.myui; +colors = myui.colors; + +%% proceed only if there is already uncertainty data +if isfield(nucleus.data.results.invstd,'uncert') + nucleus_data = nucleus.data; + + % check if the figure is already open + fig_uncert = findobj('Tag','UNCERTVIEW'); + % if not, create it + if isempty(fig_uncert) + % draw the figure on top of NUCLEUSinv + fig_uncert = figure('Name','NUCLEUSinv - RTD Uncertainty',... + 'NumberTitle','off','Resize','on','ToolBar','none',... + 'CloseRequestFcn',@uv_closeme,... + 'MenuBar','figure','Tag','UNCERTVIEW'); + pos0 = get(figh_nucleus,'Position'); + cent(1) = (pos0(1)+pos0(3)/2); + cent(2) = (pos0(2)+pos0(4)/2); + posf = [cent(1)-pos0(3)/3 pos0(2)+22 pos0(3)/1.5 pos0(4)-22]; + % posf = [cent(1)-pos0(3)/6 pos0(2)+pos0(4)-140 350 145]; + set(fig_uncert,'Position',posf); + + % create the main layout + gui.main = uix.HBox('Parent',fig_uncert,'BackGroundColor',colors.panelBG,... + 'Spacing',5,'Padding',5,'Visible','off'); + gui.left = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,... + 'Spacing',5,'Padding',0); % controls + gui.right = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,... + 'Spacing',5,'Padding',0); % plots + + set(gui.main,'Widths',[300 -1 ]); + + % waitbar indicating the loading of the GUI + steps = 5; + hwb = waitbar(0,'loading ...','Name','UncertView initialization','Visible','off'); + set(hwb,'Units','Pixel') + posw = get(hwb,'Position'); + set(hwb,'Position',[posf(1)+posf(3)/2-posw(3)/2 posf(2)+posf(4)/2-posw(4)/2 posw(3:4)]); + set(hwb,'Visible','on'); + + % --- control panel --- + waitbar(1/steps,hwb,'loading GUI elements - control'); + gui.panels.control.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Recalculate RTD Uncertainty','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle); + gui.panels.control.VBox = uix.VBox('Parent',gui.panels.control.main,... + 'Spacing',3,'Padding',3); + % uncertainty method + gui.panels.control.HBox1 = uix.HBox('Parent',gui.panels.control.VBox,... + 'Spacing',3); + gui.text_handles.uncertMethod = uicontrol('Parent',gui.panels.control.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','Method'); + tstr = ['Choose the uncertainty calculation method.

    ',... + 'Available options:
    ',... + 'Multi exp. (LSQ) | Multi exp. (LU decomp.):
    ',... + '',... + 'RMS - unbounded Keep all uncert models.
    ',... + 'RMS - bounded Only keep models within Lm and chi2 bounds.
    ',... + 'Multi modal:
    ',... + '',... + 'RMS - unbounded Keep all uncert models.
    ',... + 'RMS - bounded Only keep models within Lm and chi2 bounds.
    ',... + 'Threshold Vary fit parameter by threshold.
    ',... + 'Conf. Interval Vary fit parameter randomly within confidence interval.

    ',... + 'Default value:
    ',... + 'RMS - bounded
    ']; + gui.popup_handles.uncertMethod = uicontrol('Parent',gui.panels.control.HBox1,... + 'Style','popup','String',{'RMS - unbounded','RMS - bounded'},... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'FontSize',myui.fontsize,'Tag','control','Callback',@uv_onPopupMethod); + set(gui.panels.control.HBox1,'Widths',[150 -1]); + % number of uncertainty models + gui.panels.control.HBox2 = uix.HBox('Parent',gui.panels.control.VBox,... + 'Spacing',3); + gui.text_handles.uncertN = uicontrol('Parent',gui.panels.control.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','#models'); + uix.Empty('Parent',gui.panels.control.HBox2); + tstr = 'Number of uncertainty models to calculate.'; + gui.edit_handles.uncertN = uicontrol('Parent',gui.panels.control.HBox2,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','uncertN',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onEditValue); + set(gui.panels.control.HBox2,'Widths',[150 -1 -1]); + % bound1: chi2 range + gui.panels.control.HBox3 = uix.HBox('Parent',gui.panels.control.VBox,... + 'Spacing',3); + gui.text_handles.uncertchi2 = uicontrol('Parent',gui.panels.control.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',[char(hex2dec('03A7')),char(hex2dec('00B2')),... + ' range min | max']); + tstr = 'Lower bound of chi2 range.'; + gui.edit_handles.uncertchi2_min = uicontrol('Parent',gui.panels.control.HBox3,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@uv_onEditValue); + tstr = 'Upper bound of chi2 range.'; + gui.edit_handles.uncertchi2_max = uicontrol('Parent',gui.panels.control.HBox3,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@uv_onEditValue); + set(gui.panels.control.HBox3,'Widths',[150 -1 -1]); + % bound2: model norm range + gui.panels.control.HBox4 = uix.HBox('Parent',gui.panels.control.VBox,... + 'Spacing',3); + gui.text_handles.uncertmnorm = uicontrol('Parent',gui.panels.control.HBox4,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',['|Lm|',char(hex2dec('2082')),' range min | max']); + tstr = 'Lower bound of model norm range.'; + gui.edit_handles.uncertmnorm_min = uicontrol('Parent',gui.panels.control.HBox4,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@uv_onEditValue); + tstr = 'Upper bound of model norm range.'; + gui.edit_handles.uncertmnorm_max = uicontrol('Parent',gui.panels.control.HBox4,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','control',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@uv_onEditValue); + set(gui.panels.control.HBox4,'Widths',[150 -1 -1]); + % bound3: threshold + gui.panels.control.HBox5 = uix.HBox('Parent',gui.panels.control.VBox,... + 'Spacing',3); + gui.text_handles.uncertThresh = uicontrol('Parent',gui.panels.control.HBox5,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','Threshold'); + uix.Empty('Parent',gui.panels.control.HBox5); + tstr = 'Threshold value (0.05 = 5%).'; + gui.edit_handles.uncertThresh = uicontrol('Parent',gui.panels.control.HBox5,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','uncertThresh',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@uv_onEditValue); + set(gui.panels.control.HBox5,'Widths',[150 -1 -1]); + % max tries + gui.panels.control.HBox6 = uix.HBox('Parent',gui.panels.control.VBox,... + 'Spacing',3); + gui.text_handles.uncertMax = uicontrol('Parent',gui.panels.control.HBox6,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','Max. #tries'); + uix.Empty('Parent',gui.panels.control.HBox6); + tstr = 'Maximum number of unsuccesful tries.'; + gui.edit_handles.uncertMax = uicontrol('Parent',gui.panels.control.HBox6,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','uncertMax',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@uv_onEditValue); + set(gui.panels.control.HBox6,'Widths',[150 -1 -1]); + % RUN button + gui.panels.control.HBox7 = uix.HBox('Parent',gui.panels.control.VBox,... + 'Spacing',3); + uix.Empty('Parent',gui.panels.control.HBox7); + uix.Empty('Parent',gui.panels.control.HBox7); + tstr = ['RUN uncertainty calculation.
    ',... + 'Regularization is the same as in main NUCLEUSinv GUI.']; + gui.push_handles.reset = uicontrol('Parent',gui.panels.control.HBox7,... + 'String','RUN','FontSize',myui.fontsize,'Tag','process',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackGroundColor','g','Callback',@uv_onPushRun); + set(gui.panels.control.HBox7,'Widths',[150 -1 -1]); + + % --- process panel --- + waitbar(2/steps,hwb,'loading GUI elements - process'); + gui.panels.process.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Process Uncertainty Runs','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle); + gui.panels.process.VBox = uix.VBox('Parent',gui.panels.process.main,... + 'Spacing',3,'Padding',3); + % chi2 range + gui.panels.process.HBox1 = uix.HBox('Parent',gui.panels.process.VBox,... + 'Spacing',3); + gui.text_handles.chi2 = uicontrol('Parent',gui.panels.process.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',[char(hex2dec('03A7')),char(hex2dec('00B2')),... + ' range min | max']); + tstr = 'Lower bound of chi2 range.'; + gui.edit_handles.chi2_min = uicontrol('Parent',gui.panels.process.HBox1,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','process',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onEditValue); + tstr = 'Upper bound of chi2 range.'; + gui.edit_handles.chi2_max = uicontrol('Parent',gui.panels.process.HBox1,... + 'Style','edit','String','2','FontSize',myui.fontsize,'Tag','process',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onEditValue); + set(gui.panels.process.HBox1,'Widths',[150 -1 -1]); + % model norm range + gui.panels.process.HBox2 = uix.HBox('Parent',gui.panels.process.VBox,... + 'Spacing',3); + gui.text_handles.mnorm = uicontrol('Parent',gui.panels.process.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',['|Lm|',char(hex2dec('2082')),' range min | max']); + tstr = 'Lower bound of model norm range.'; + gui.edit_handles.mnorm_min = uicontrol('Parent',gui.panels.process.HBox2,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','process',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onEditValue); + tstr = 'Upper bound of model norm range.'; + gui.edit_handles.mnorm_max = uicontrol('Parent',gui.panels.process.HBox2,... + 'Style','edit','String','2','FontSize',myui.fontsize,'Tag','process',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onEditValue); + set(gui.panels.process.HBox2,'Widths',[150 -1 -1]); + % RESET button + gui.panels.process.HBox3 = uix.HBox('Parent',gui.panels.process.VBox,... + 'Spacing',3); + uix.Empty('Parent',gui.panels.process.HBox3); + tstr = 'SEND bounds to recaluclation panel above.'; + gui.push_handles.send = uicontrol('Parent',gui.panels.process.HBox3,... + 'String','SEND','FontSize',myui.fontsize,'Tag','process',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onPushSend); + tstr = 'RESET processing bounds and plots.'; + gui.push_handles.reset = uicontrol('Parent',gui.panels.process.HBox3,... + 'String','RESET','FontSize',myui.fontsize,'Tag','process',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onPushReset); + set(gui.panels.process.HBox3,'Widths',[150 -1 -1]); + + % --- RTD panel --- + waitbar(3/steps,hwb,'loading GUI elements - RTD bounds'); + gui.panels.rtd.main = uix.BoxPanel('Parent',gui.left,... + 'Title','RTD Calculation Bounds','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle); + gui.panels.rtd.VBox = uix.VBox('Parent',gui.panels.rtd.main,... + 'Spacing',3,'Padding',3); + % RTD range + gui.panels.rtd.HBox1 = uix.HBox('Parent',gui.panels.rtd.VBox,... + 'Spacing',3); + gui.text_handles.rtd = uicontrol('Parent',gui.panels.rtd.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','RTD range min | max'); + tstr = ['Minimum relaxation time in RTDs used
    ',... + 'for calculating statistics on E0 & TLGM.']; + gui.edit_handles.rtd_min = uicontrol('Parent',gui.panels.rtd.HBox1,... + 'Style','edit','String','0','FontSize',myui.fontsize,'Tag','rtd',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onEditValue); + tstr = ['Maximum relaxation time in RTDs used
    ',... + 'for calculating statistics on E0 & TLGM.']; + gui.edit_handles.rtd_max = uicontrol('Parent',gui.panels.rtd.HBox1,... + 'Style','edit','String','2','FontSize',myui.fontsize,'Tag','rtd',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onEditValue); + set(gui.panels.rtd.HBox1,'Widths',[150 -1 -1]); + % RESET button + gui.panels.rtd.HBox3 = uix.HBox('Parent',gui.panels.rtd.VBox,... + 'Spacing',3); + uix.Empty('Parent',gui.panels.rtd.HBox3); + uix.Empty('Parent',gui.panels.rtd.HBox3); + tstr = 'RESET RTDs calculation bounds.'; + gui.push_handles.reset_rtd = uicontrol('Parent',gui.panels.rtd.HBox3,... + 'String','RESET','FontSize',myui.fontsize,'Tag','rtd',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onPushReset); + set(gui.panels.rtd.HBox3,'Widths',[150 -1 -1]); + + % --- Statistics panel --- + waitbar(4/steps,hwb,'loading GUI elements - statistics'); + gui.panels.info.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Uncertainty Statistics','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle); + gui.panels.info.VBox = uix.VBox('Parent',gui.panels.info.main,... + 'Spacing',3,'Padding',3); + % mean TLGM + gui.panels.info.HBox1 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.TLGM = uicontrol('Parent',gui.panels.info.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','TLGM mean | std'); + tstr = 'MEAN of all TLGM values.'; + gui.edit_handles.TLGM_mean = uicontrol('Parent',gui.panels.info.HBox1,... + 'Style','edit','String','0','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxPRC); + tstr = 'STD of all TLGM values.'; + gui.edit_handles.TLGM_std = uicontrol('Parent',gui.panels.info.HBox1,... + 'Style','edit','String','2','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxPRC); + set(gui.panels.info.HBox1,'Widths',[150 -1 -1]); + % aad TLGM + gui.panels.info.HBox2 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.TLGM_aad = uicontrol('Parent',gui.panels.info.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','TLGM aad(mean)'); + uix.Empty('Parent',gui.panels.info.HBox2); + tstr = 'AAD (average absolute deviation from mean) of all TLGM values.'; + gui.edit_handles.TLGM_aad = uicontrol('Parent',gui.panels.info.HBox2,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Style','edit','String','2','FontSize',myui.fontsize); + set(gui.panels.info.HBox2,'Widths',[150 -1 -1]); + % median TLGM + gui.panels.info.HBox3 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.TLGM_med = uicontrol('Parent',gui.panels.info.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','TLGM median | aad(med)'); + tstr = 'MEDIAN of all TLGM values.'; + gui.edit_handles.TLGM_med = uicontrol('Parent',gui.panels.info.HBox3,... + 'Style','edit','String','0','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxCPS); + tstr = 'AAD (average absolute deviation from median) of all TLGM values.'; + gui.edit_handles.TLGM_aadmed = uicontrol('Parent',gui.panels.info.HBox3,... + 'Style','edit','String','2','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxCPS); + set(gui.panels.info.HBox3,'Widths',[150 -1 -1]); + % mean E0 + gui.panels.info.HBox4 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.E0 = uicontrol('Parent',gui.panels.info.HBox4,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','E0 mean | std'); + tstr = 'MEAN of all E0 values.'; + gui.edit_handles.E0_mean = uicontrol('Parent',gui.panels.info.HBox4,... + 'Style','edit','String','0','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxPRC); + tstr = 'STD of all E0 values.'; + gui.edit_handles.E0_std = uicontrol('Parent',gui.panels.info.HBox4,... + 'Style','edit','String','2','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxPRC); + set(gui.panels.info.HBox4,'Widths',[150 -1 -1]); + % aad E0 + gui.panels.info.HBox5 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.E0_aad = uicontrol('Parent',gui.panels.info.HBox5,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','E0 aad(mean)'); + uix.Empty('Parent',gui.panels.info.HBox5); + tstr = 'AAD (average absolute deviation from mean) of all E0 values.'; + gui.edit_handles.E0_aad = uicontrol('Parent',gui.panels.info.HBox5,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Style','edit','String','2','FontSize',myui.fontsize); + set(gui.panels.info.HBox5,'Widths',[150 -1 -1]); + % median E0 + gui.panels.info.HBox6 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.E0_med = uicontrol('Parent',gui.panels.info.HBox6,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','E0 median | aad(med)'); + tstr = 'MEDIAN of all E0 values.'; + gui.edit_handles.E0_med = uicontrol('Parent',gui.panels.info.HBox6,... + 'Style','edit','String','0','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxCPS); + tstr = 'AAD (average absolute deviation from median) of all E0 values.'; + gui.edit_handles.E0_aadmed = uicontrol('Parent',gui.panels.info.HBox6,... + 'Style','edit','String','2','FontSize',myui.fontsize,... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackgroundColor',colors.BoxCPS); + set(gui.panels.info.HBox6,'Widths',[150 -1 -1]); + + % --- update MAIN GUI button --- + tstr = 'UPDATE uncertainty data in main NUCLEUSinv GUI.'; + gui.push_handles.update = uicontrol('Parent',gui.left,... + 'String','UPDATE MAIN GUI','FontSize',myui.fontsize,'Tag','update',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onPushUpdate); + + % fix text vertical alignment + jh = findjobj(gui.text_handles.uncertMethod); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.uncertN); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.uncertchi2); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.uncertmnorm); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.uncertThresh); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.uncertMax); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.chi2); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.mnorm); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.rtd); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.TLGM); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.TLGM_aad); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.TLGM_med); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.E0); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.E0_aad); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.E0_med); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + + % empty space at bottom of left side + uix.Empty('Parent',gui.left); + % adjust the heights of all left-column-panels + heights = [22 22 22 22 28 -1; 22+7*24+9*3 22+3*24+5*3 22+2*24+4*4 22+6*24+8*3 28 -1]; + % panel header is always 22 high + set(gui.left,'Heights',heights(2,:),... + 'MinimumHeights',[22 22 22 22 28 0]); + + % --- plot boxes --- + waitbar(5/steps,hwb,'loading GUI elements - graphics'); + gui.rightPanel = uix.TabPanel('Parent',gui.right,... + 'BackGroundColor',colors.panelBG); + % -- tab1 + gui.righttop1 = uix.HBox('Parent',gui.rightPanel,... + 'BackGroundColor',colors.panelBG,'Spacing',5); + gui.pbox11 = uicontainer('Parent',gui.righttop1,... + 'BackGroundColor',colors.panelBG); + gui.pbox12 = uicontainer('Parent',gui.righttop1,... + 'BackGroundColor',colors.panelBG); + set(gui.righttop1,'Widths',[-1 -1 ]); + gui.rightbot = uix.HBox('Parent',gui.right,... + 'BackGroundColor',colors.panelBG,'Spacing',5); + gui.pbox2 = uicontainer('Parent',gui.rightbot,... + 'BackGroundColor',colors.panelBG); + + % -- tab2 + gui.righttop2 = uix.HBox('Parent',gui.rightPanel,... + 'BackGroundColor',colors.panelBG,'Spacing',5); + gui.pbox21 = uicontainer('Parent',gui.righttop2,... + 'BackGroundColor',colors.panelBG); + gui.pbox22 = uicontainer('Parent',gui.righttop2,... + 'BackGroundColor',colors.panelBG); + set(gui.righttop2,'Widths',[-1 -1 ]); + + gui.rightPanel.TabTitles = {'Statistics','Histograms'}; + gui.rightPanel.TabWidth = 75; + gui.rightPanel.TabEnables = {'on','on'}; + + % -- plot axes -- + gui.axes11 = axes('Parent',gui.pbox12,'Box','on'); + gui.axes12 = axes('Parent',gui.pbox11,'Box','on'); + gui.axes2 = axes('Parent',gui.pbox2,'Box','on'); + gui.axes21 = axes('Parent',gui.pbox21,'Box','on'); + gui.axes22 = axes('Parent',gui.pbox22,'Box','on'); + + % the chi2 vs. xn plot has a context menu + gui.cm_handles.axes_chi2 = uicontextmenu(fig_uncert); + gui.cm_handles.axes_color = uimenu(gui.cm_handles.axes_chi2,... + 'Label','color by'); + gui.cm_handles.axes_color_none = uimenu(gui.cm_handles.axes_color,... + 'Label','none','Tag','none','Checked','on',... + 'Callback',@uv_onContextPlotsColor); + gui.cm_handles.axes_color_chi2 = uimenu(gui.cm_handles.axes_color,... + 'Label','chi2','Tag','chi2','Callback',@uv_onContextPlotsColor); + gui.cm_handles.axes_color_mnorm = uimenu(gui.cm_handles.axes_color,... + 'Label','xn','Tag','xn','Callback',@uv_onContextPlotsColor); + set(gui.axes12,'UIContextMenu',gui.cm_handles.axes_chi2); + + % the RTD plot has a context menu + gui.cm_handles.axes_rtd = uicontextmenu(fig_uncert); + gui.cm_handles.axes_rtd_lines = uimenu(gui.cm_handles.axes_rtd,... + 'Label','lines','Tag','lines','Checked','on',... + 'Callback',@uv_onContextPlotsRTD); + gui.cm_handles.axes_rtd_patch = uimenu(gui.cm_handles.axes_rtd,... + 'Label','patch'); + gui.cm_handles.axes_rtd_patch_mean = uimenu(gui.cm_handles.axes_rtd_patch,... + 'Label','mean / std','Tag','patchmean',... + 'Callback',@uv_onContextPlotsRTD); + gui.cm_handles.axes_rtd_patch_median = uimenu(gui.cm_handles.axes_rtd_patch,... + 'Label','median / aad','Tag','patchmedian',... + 'Callback',@uv_onContextPlotsRTD); + set(gui.axes2,'UIContextMenu',gui.cm_handles.axes_rtd); + + % --- store main GUI settings --- + gui.myui = nucleus.gui.myui; + gui.myui.heights = heights; + gui.figh_nucleus = figh_nucleus; + + % --- save gui data to GUI --- + setappdata(fig_uncert,'gui',gui); + + % make GUI visible + delete(hwb); + set(gui.main,'Visible','on'); + + % initialize color style + uv.colorstyle = 'none'; + % initialize RTD plot style + uv.rtd_plotstyle = 'lines'; + else + data = getappdata(fig_uncert,'data'); + uv = data.uv; + end + % if the figure is already open load the GUI data + gui = getappdata(fig_uncert,'gui'); + % update new NUCLEUSinv data + setappdata(fig_uncert,'data',nucleus_data); + data = getappdata(fig_uncert,'data'); + % clear axes + clearAllAxes(fig_uncert); + + % round all chi2 and xn values to 6 digits + chi2_all = data.results.invstd.uncert.chi2_all; + chi2_all = round(1e6.*chi2_all)./1e6; + data.results.invstd.uncert.chi2_all = chi2_all; + mnorm_all = data.results.invstd.uncert.mnorm_all; + mnorm_all = round(1e6.*mnorm_all)./1e6; + data.results.invstd.uncert.mnorm_all = mnorm_all; + + % create logical mask + uv.touse = ones(nucleus_data.uncert.N,1); + % --- fill the edit fields --- + invstd = data.results.invstd; + uncert = invstd.uncert; + % 1.) control + uv.uncertMethod = uncert.params.uncert.Method; + uv.uncertN = uncert.params.uncert.N; + set(gui.edit_handles.uncertN,'String',num2str(uv.uncertN)); + uv.uncertThresh = uncert.params.uncert.Thresh; + set(gui.edit_handles.uncertThresh,'String',num2str(uv.uncertThresh)); + uv.uncertMax = uncert.params.uncert.Max; + set(gui.edit_handles.uncertMax,'String',num2str(uv.uncertMax)); + uv.chi2_range_calc = [min(uncert.chi2_all) max(uncert.chi2_all)]; + uv.mnorm_range_calc = [min(uncert.mnorm_all) max(uncert.mnorm_all)]; + % set popup menu + switch invstd.invtype + case {'LU','NNLS'} + set(gui.popup_handles.uncertMethod,... + 'String',{'RMS - unbounded','RMS - bounded'}) + switch uncert.params.uncert.Method + case 'RMS_free' + set(gui.popup_handles.uncertMethod,'Value',1); + case 'RMS_bound' + set(gui.popup_handles.uncertMethod,'Value',2); + end + case 'MUMO' + set(gui.popup_handles.uncertMethod,... + 'String',{'RMS - unbounded','RMS - bounded','Threshold','Conf. Interval'}) + switch uncert.params.uncert.Method + case 'RMS_free' + set(gui.popup_handles.uncertMethod,'Value',1); + case 'RMS_bound' + set(gui.popup_handles.uncertMethod,'Value',2); + case 'thresh' + set(gui.popup_handles.uncertMethod,'Value',3); + case 'ci' + set(gui.popup_handles.uncertMethod,'Value',4); + end + end + set(gui.edit_handles.uncertN,'String',num2str(uncert.params.uncert.N)); + % 2.) process + chi2_range = uv.chi2_range_calc; + mnorm_range = uv.mnorm_range_calc; + set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',chi2_range(1,1))); + set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',chi2_range(1,2))); + set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',mnorm_range(1,1))); + set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',mnorm_range(1,2))); + % 3.) RTD range + rtd_range = data.invstd.time; + set(gui.edit_handles.rtd_min,'String',num2str(rtd_range(1,1))); + set(gui.edit_handles.rtd_max,'String',num2str(rtd_range(1,2))); + uv.chi2_range = chi2_range; + uv.mnorm_range = mnorm_range; + uv.rtd_range = rtd_range; + + % update data + data.uv = uv; + setappdata(fig_uncert,'data',data); + uv_onPopupMethod(gui.popup_handles.uncertMethod); + + % plot all uncertainty data + uv_updateInformation(fig_uncert); + beautifyAxes(fig_uncert); +else + helpdlg({'function: UNCERTVIEW',... + 'Cannot continue because there is no data!'},... + 'No uncertainty data.'); +end + +end + +%% subfunction to update the edit fields +function uv_onEditValue(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +uv = data.uv; + +% get the edit field value +val = str2double(get(src,'String')); + +switch get(src,'Tag') + case 'uncertN' + if val < 10 + uncertN = 10; + else + uncertN = round(val); + end + set(src,'String',num2str(uncertN)); + uv.uncertN = uncertN; + data.uv = uv; + case 'uncertThresh' + case 'uncertMax' + case 'control' + % set the value with the desired layout + set(src,'String',sprintf('%7.6f',val)); + chi2_range_calc(1,1) = str2double(get(gui.edit_handles.uncertchi2_min,'String')); + chi2_range_calc(1,2) = str2double(get(gui.edit_handles.uncertchi2_max,'String')); + mnorm_range_calc(1,1) = str2double(get(gui.edit_handles.uncertmnorm_min,'String')); + mnorm_range_calc(1,2) = str2double(get(gui.edit_handles.uncertmnorm_max,'String')); + % update data + uv.chi2_range_calc = chi2_range_calc; + uv.mnorm_range_calc = mnorm_range_calc; + data.uv = uv; + case 'process' + % set the value with the desired layout + set(src,'String',sprintf('%7.6f',val)); + % get all range values + chi2_range(1,1) = str2double(get(gui.edit_handles.chi2_min,'String')); + chi2_range(1,2) = str2double(get(gui.edit_handles.chi2_max,'String')); + mnorm_range(1,1) = str2double(get(gui.edit_handles.mnorm_min,'String')); + mnorm_range(1,2) = str2double(get(gui.edit_handles.mnorm_max,'String')); + % fix wrong user input + if chi2_range(2) <= chi2_range(1) + warndlg({'function: UNCERTVIEW',... + 'Lower bound is larger than upper bound!'},... + 'Resetting.'); + chi2_range(1) = min(data.results.invstd.uncert.chi2_all); + chi2_range(2) = max(data.results.invstd.uncert.chi2_all); + set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',chi2_range(1))); + set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',chi2_range(2))); + end + if mnorm_range(2) <= mnorm_range(1) + warndlg({'function: UNCERTVIEW',... + 'Lower bound is larger than upper bound!'},... + 'Resetting.'); + mnorm_range(1) = min(data.results.invstd.uncert.mnorm_all); + mnorm_range(2) = max(data.results.invstd.uncert.mnorm_all); + set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',mnorm_range(1))); + set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',mnorm_range(2))); + end + % update data + uv.chi2_range = chi2_range; + uv.mnorm_range = mnorm_range; + data.uv = uv; + % update logical mask for plotting + data = uv_updateMASK(data); + case 'rtd' + % set the value with the desired layout + set(src,'String',num2str(val)); + % get all range values + rtd_range(1,1) = str2double(get(gui.edit_handles.rtd_min,'String')); + rtd_range(1,2) = str2double(get(gui.edit_handles.rtd_max,'String')); + % update data + uv.rtd_range = rtd_range; + data.uv = uv; +end + +% update GUI data +setappdata(figh,'data',data); +% update information +uv_updateInformation(figh); +end + +%% subfunction to copy the chi2 and xn range to the control panel +function uv_onPushSend(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +uv = data.uv; + +% get all data +chi2_range(1,1) = str2double(get(gui.edit_handles.chi2_min,'String')); +chi2_range(1,2) = str2double(get(gui.edit_handles.chi2_max,'String')); +mnorm_range(1,1) = str2double(get(gui.edit_handles.mnorm_min,'String')); +mnorm_range(1,2) = str2double(get(gui.edit_handles.mnorm_max,'String')); + +% copy data to calc +uv.chi2_range_calc = chi2_range; +uv.mnorm_range_calc = mnorm_range; +data.uv = uv; + +% write values to edit field +set(gui.edit_handles.uncertchi2_min,... + 'String',sprintf('%7.6f',uv.chi2_range_calc(1))); +set(gui.edit_handles.uncertchi2_max,... + 'String',sprintf('%7.6f',uv.chi2_range_calc(2))); +set(gui.edit_handles.uncertmnorm_min,... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(1))); +set(gui.edit_handles.uncertmnorm_max,... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(2))); + +% update GUI data +setappdata(figh,'data',data); +end + +%% subfunction to control the line color +function uv_onContextPlotsColor(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +uv = data.uv; + +% switch through different plot options +switch get(src,'Tag') + case 'none' + set(gui.cm_handles.axes_color_none,'Checked','on'); + set(gui.cm_handles.axes_color_chi2,'Checked','off'); + set(gui.cm_handles.axes_color_mnorm,'Checked','off'); + case 'chi2' + set(gui.cm_handles.axes_color_none,'Checked','off'); + set(gui.cm_handles.axes_color_chi2,'Checked','on'); + set(gui.cm_handles.axes_color_mnorm,'Checked','off'); + case 'xn' + set(gui.cm_handles.axes_color_none,'Checked','off'); + set(gui.cm_handles.axes_color_chi2,'Checked','off'); + set(gui.cm_handles.axes_color_mnorm,'Checked','on'); +end +uv.colorstyle = get(src,'Tag'); + +% update GUI data +data.uv = uv; +setappdata(figh,'data',data); +% update information and plots +uv_updateInformation(figh); +end + +%% subfunction to control RTD axes context menu +function uv_onContextPlotsRTD(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +uv = data.uv; + +% switch through different plot options +switch get(src,'Tag') + case 'lines' + set(gui.cm_handles.axes_rtd_lines,'Checked','on'); + set(gui.cm_handles.axes_rtd_patch_mean,'Checked','off'); + set(gui.cm_handles.axes_rtd_patch_median,'Checked','off'); + case 'patchmean' + set(gui.cm_handles.axes_rtd_lines,'Checked','off'); + set(gui.cm_handles.axes_rtd_patch_mean,'Checked','on'); + set(gui.cm_handles.axes_rtd_patch_median,'Checked','off'); + case 'patchmedian' + set(gui.cm_handles.axes_rtd_lines,'Checked','off'); + set(gui.cm_handles.axes_rtd_patch_mean,'Checked','off'); + set(gui.cm_handles.axes_rtd_patch_median,'Checked','on'); +end +uv.rtd_plotstyle = get(src,'Tag'); + +% update GUI data +data.uv = uv; +setappdata(figh,'data',data); +% update information and plots +uv_updateInformation(figh); +end + +%% subfunction to update the logical mask +function data = uv_updateMASK(data) +uncert = data.results.invstd.uncert; +uv = data.uv; + +mask1 = uncert.chi2_all >= uv.chi2_range(1) & uncert.chi2_all <= uv.chi2_range(2); +mask2 = uncert.mnorm_all >= uv.mnorm_range(1) & uncert.mnorm_all <= uv.mnorm_range(2); +uv.touse = mask1 & mask2; + +data.uv = uv; +end + +%% subfunction to update control panel based on uncertainty method +function uv_onPopupMethod(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +uv = data.uv; +invstd = data.results.invstd; + +val = get(gui.popup_handles.uncertMethod,'Value'); + +switch invstd.invtype + case {'LU','NNLS'} + switch val + case 1 % RMS_free + uv.uncertMethod = 'RMS_free'; + set(gui.edit_handles.uncertchi2_min,'Enable','off'); + set(gui.edit_handles.uncertchi2_max,'Enable','off'); + set(gui.edit_handles.uncertmnorm_min,'Enable','off'); + set(gui.edit_handles.uncertmnorm_max,'Enable','off'); + set(gui.edit_handles.uncertThresh,'Enable','off'); + set(gui.edit_handles.uncertMax,'Enable','off'); + case 2 % RMS_bound + uv.uncertMethod = 'RMS_bound'; + set(gui.edit_handles.uncertchi2_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(1))); + set(gui.edit_handles.uncertchi2_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(2))); + set(gui.edit_handles.uncertmnorm_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(1))); + set(gui.edit_handles.uncertmnorm_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(2))); + set(gui.edit_handles.uncertThresh,'Enable','off'); + set(gui.edit_handles.uncertMax,'Enable','on',... + 'String',num2str(uv.uncertMax)); + end + case 'MUMO' + switch val + case 1 % RMS_free + uv.uncertMethod = 'RMS_free'; + set(gui.edit_handles.uncertchi2_min,'Enable','off'); + set(gui.edit_handles.uncertchi2_max,'Enable','off'); + set(gui.edit_handles.uncertmnorm_min,'Enable','off'); + set(gui.edit_handles.uncertmnorm_max,'Enable','off'); + set(gui.edit_handles.uncertThresh,'Enable','off'); + set(gui.edit_handles.uncertMax,'Enable','off'); + case 2 % RMS_bound + uv.uncertMethod = 'RMS_bound'; + set(gui.edit_handles.uncertchi2_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(1))); + set(gui.edit_handles.uncertchi2_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(2))); + set(gui.edit_handles.uncertmnorm_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(1))); + set(gui.edit_handles.uncertmnorm_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(2))); + set(gui.edit_handles.uncertThresh,'Enable','off'); + set(gui.edit_handles.uncertMax,'Enable','on',... + 'String',num2str(uv.uncertMax)); + case 3 % threshold + uv.uncertMethod = 'thresh'; + uv.chi2_range_calc = [0 10]; + uv.mnorm_range_calc = [0 10]; + set(gui.edit_handles.uncertchi2_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(1))); + set(gui.edit_handles.uncertchi2_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(2))); + set(gui.edit_handles.uncertmnorm_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(1))); + set(gui.edit_handles.uncertmnorm_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(2))); + set(gui.edit_handles.uncertThresh,'Enable','on'); + set(gui.edit_handles.uncertMax,'Enable','on',... + 'String',num2str(uv.uncertMax)); + case 4 % ci - confidence intrval + uv.uncertMethod = 'ci'; + uv.chi2_range_calc = [0 10]; + uv.mnorm_range_calc = [0 10]; + set(gui.edit_handles.uncertchi2_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(1))); + set(gui.edit_handles.uncertchi2_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.chi2_range_calc(2))); + set(gui.edit_handles.uncertmnorm_min,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(1))); + set(gui.edit_handles.uncertmnorm_max,'Enable','on',... + 'String',sprintf('%7.6f',uv.mnorm_range_calc(2))); + set(gui.edit_handles.uncertThresh,'Enable','off'); + set(gui.edit_handles.uncertMax,'Enable','on',... + 'String',num2str(uv.uncertMax)); + end +end + +% update GUI data +data.uv = uv; +setappdata(figh,'data',data); +end + +%% subfunction to start a new uncertainty calculation +function uv_onPushRun(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +uv = data.uv; +invstd = data.results.invstd; +uncert = invstd.uncert; + +% original fit parameter +iparam = invstd.invparams; +% original uncertainty parameter +uparam = uncert.params; +% new uncertainty parameter from GUI +uparam.uncert.Method = uv.uncertMethod; +uparam.uncert.Thresh = uv.uncertThresh; +uparam.uncert.chi2_range = uv.chi2_range_calc; +uparam.uncert.mnorm_range = uv.mnorm_range_calc; +uparam.uncert.N = uv.uncertN; +uparam.uncert.Max = uv.uncertMax; +invstd = estimateUncertainty(invstd.invtype,invstd,iparam,uparam); + +% save updated inversion results +invstd.uncert.params = uparam; +data.results.invstd = invstd; + +% update GUI data +% round all chi2 and xn values to 6 digits +chi2_all = data.results.invstd.uncert.chi2_all; +chi2_all = round(1e6.*chi2_all)./1e6; +data.results.invstd.uncert.chi2_all = chi2_all; +mnorm_all = data.results.invstd.uncert.mnorm_all; +mnorm_all = round(1e6.*mnorm_all)./1e6; +data.results.invstd.uncert.mnorm_all = mnorm_all; + +% create logical mask +uv.touse = ones(uv.uncertN,1); + +% 1.) control +uv.chi2_range_calc = [min(chi2_all) max(chi2_all)]; +uv.mnorm_range_calc = [min(mnorm_all) max(mnorm_all)]; + +% 2.) process +uv.chi2_range = uv.chi2_range_calc; +uv.mnorm_range = uv.mnorm_range_calc; +set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',uv.chi2_range(1,1))); +set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',uv.chi2_range(1,2))); +set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',uv.mnorm_range(1,1))); +set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',uv.mnorm_range(1,2))); + +% update data +data.uv = uv; +setappdata(figh,'data',data); + +% plot all uncertainty data +uv_updateInformation(figh); +beautifyAxes(figh); +end + +%% subfunction to update the main NUCLEUSinv GUI +function uv_onPushUpdate(src,~) +figh = ancestor(src,'figure','toplevel'); +% local GUI data +uvgui = getappdata(figh,'gui'); +uvdata = getappdata(figh,'data'); +% NUCLEUSinv data +gui = getappdata(uvgui.figh_nucleus,'gui'); +data = getappdata(uvgui.figh_nucleus,'data'); +INVdata = getappdata(uvgui.figh_nucleus,'INVdata'); + +% get signal id +id = data.results.invstd.uncert.params.id; +% get data +INVdata0 = INVdata{id}; + +% --- update data --- +% -- general settings -- +data.uncert.N = uvdata.uv.uncertN; +data.uncert.Method = uvdata.uv.uncertMethod; +data.uncert.Thresh = uvdata.uv.uncertThresh; +data.uncert.Max = uvdata.uv.uncertMax; + +% -- check if data was excluded -- +if sum(uvdata.uv.touse == 0) > 0 + % if yes, proceed + in = uvdata.uv.touse == 1; + data.uncert.N = sum(in); + uvdata.results.invstd.uncert.params.uncert.N = sum(in); + uvdata.results.invstd.uncert.chi2_all = uvdata.results.invstd.uncert.chi2_all(in); + uvdata.results.invstd.uncert.mnorm_all = uvdata.results.invstd.uncert.mnorm_all(in); + uvdata.results.invstd.uncert.rnorm_all = uvdata.results.invstd.uncert.rnorm_all(in); + uvdata.results.invstd.uncert.interp_f = uvdata.results.invstd.uncert.interp_f(in,:); + uvdata.results.invstd.uncert.interp_s = uvdata.results.invstd.uncert.interp_s(:,in'); + uvdata.results.invstd.uncert.interp_E0 = uvdata.results.invstd.uncert.interp_E0(in); + uvdata.results.invstd.uncert.E0 = [mean(uvdata.results.invstd.uncert.interp_E0) std(uvdata.results.invstd.uncert.interp_E0)]; + uvdata.results.invstd.uncert.interp_Tlgm = uvdata.results.invstd.uncert.interp_Tlgm(in); + uvdata.results.invstd.uncert.Tlgm = [mean(uvdata.results.invstd.uncert.interp_Tlgm) std(uvdata.results.invstd.uncert.interp_Tlgm)]; +end + +% update data structs +data.results.invstd.uncert = uvdata.results.invstd.uncert; +INVdata0.results.invstd = uvdata.results.invstd; + +% update INVdata +INVdata{id} = INVdata0; +% update GUI data +setappdata(uvgui.figh_nucleus,'data',data); +% update GUI INVdata +setappdata(uvgui.figh_nucleus,'INVdata',INVdata); + +% update relevant GUI elements +set(gui.edit_handles.uncert_N,'String',num2str(data.results.invstd.uncert.params.uncert.N)) + +% update plots and INFO fields in main NUCLEUS GUI +updatePlotsSignal; +updatePlotsDistribution; +updateInfo(gui.plots.SignalPanel); + +end + +%% subfunction to reset chi2 and model norm bounds +function uv_onPushReset(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +uv = data.uv; +invstd = data.results.invstd; +uncert = invstd.uncert; + +switch get(src,'Tag') + case 'process' + % reset to original values + chi2_range = [min(uncert.chi2_all) max(uncert.chi2_all)]; + mnorm_range = [min(uncert.mnorm_all) max(uncert.mnorm_all)]; + % update edit fields + set(gui.edit_handles.chi2_min,'String',sprintf('%7.6f',chi2_range(1,1))); + set(gui.edit_handles.chi2_max,'String',sprintf('%7.6f',chi2_range(1,2))); + set(gui.edit_handles.mnorm_min,'String',sprintf('%7.6f',mnorm_range(1,1))); + set(gui.edit_handles.mnorm_max,'String',sprintf('%7.6f',mnorm_range(1,2))); + % update data + uv.chi2_range = chi2_range; + uv.mnorm_range = mnorm_range; + data.uv = uv; + % update logical mask for plotting + data = uv_updateMASK(data); + case 'rtd' + % reset to original values + rtd_range = data.invstd.time; + % update edit fields + set(gui.edit_handles.rtd_min,'String',num2str(rtd_range(1,1))); + set(gui.edit_handles.rtd_max,'String',num2str(rtd_range(1,2))); + % update data + uv.rtd_range = rtd_range; + data.uv = uv; +end + +setappdata(figh,'data',data); +% update information +uv_updateInformation(figh); +end + +%% subfunction to update the information output +function uv_updateInformation(figh) +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +invstd = data.results.invstd; +uncert = invstd.uncert; +uv = data.uv; + +% which models to use +in = data.uv.touse == 1; +% RTD time vector +T = data.results.invstd.T1T2me; +% RTD mask +mask = T >= uv.rtd_range(1) & T <= uv.rtd_range(2); + +% kernel matrices for pure (single) E0 estimation +iparam = invstd.invparams; +switch iparam.T1T2 + case 'T1' + K0 = createKernelMatrix(10*data.results.nmrproc.t(end),T',... + iparam.Tb,iparam.Td,'T1',iparam.T1IRfac); + case 'T2' + K0 = createKernelMatrix(0,T',iparam.Tb,... + iparam.Td,'T2',iparam.T1IRfac); +end + +TLGM_tmp = zeros(sum(in),1); +E0_tmp = zeros(sum(in),1); +c = 0; +for i = 1:size(uncert.interp_f,1) + if in(i) + F = uncert.interp_f(i,:); + c = c + 1; + TLGM_tmp(c,1) = getTLogMean(T,F,mask); + E0_tmp(c,1) = K0(mask')*F(mask')'; + end +end + +% TLGM +uv.Tlgm = [mean(TLGM_tmp) std(TLGM_tmp)]; +set(gui.edit_handles.TLGM_mean,'String',sprintf('%5.4f',uv.Tlgm(1))); +set(gui.edit_handles.TLGM_std,'String',sprintf('%5.4f',2*uv.Tlgm(2))); +% aad - mean +uv.Tlgm_aad = getAAD(TLGM_tmp,0); +set(gui.edit_handles.TLGM_aad,'String',sprintf('%5.4f',2*uv.Tlgm_aad)); +% aad - median +uv.Tlgm_aadmed = [median(TLGM_tmp) getAAD(TLGM_tmp,1)]; +set(gui.edit_handles.TLGM_med,'String',sprintf('%5.4f',uv.Tlgm_aadmed(1))); +set(gui.edit_handles.TLGM_aadmed,'String',sprintf('%5.4f',2*uv.Tlgm_aadmed(2))); +% E0 +uv.E0 = [mean(E0_tmp) std(E0_tmp)]; +set(gui.edit_handles.E0_mean,'String',sprintf('%5.4f',uv.E0(1))); +set(gui.edit_handles.E0_std,'String',sprintf('%5.4f',2*uv.E0(2))); +% aad - mean +uv.E0_aad = getAAD(E0_tmp,0); +set(gui.edit_handles.E0_aad,'String',sprintf('%5.4f',2*uv.E0_aad)); +% aad - median +uv.E0_aadmed = [median(E0_tmp) getAAD(E0_tmp,1)]; +set(gui.edit_handles.E0_med,'String',sprintf('%5.4f',uv.E0_aadmed(1))); +set(gui.edit_handles.E0_aadmed,'String',sprintf('%5.4f',2*uv.E0_aadmed(2))); + +% update GUI data +data.uv = uv; +setappdata(figh,'data',data); +% update plots +uv_updatePlots(figh); + +end + +%% subfunction to update all plots +function uv_updatePlots(figh) +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); + +% clear axes +clearAllAxes(figh); +hold(gui.axes11,'on'); +hold(gui.axes12,'on'); +hold(gui.axes2,'on'); +hold(gui.axes21,'on'); +hold(gui.axes22,'on'); + +% get relevant data +uv = data.uv; +invstd = data.results.invstd; +uncert = invstd.uncert; +col = gui.myui.colors; + +% get indices for models to use and not to use +in = data.uv.touse == 1; +out = data.uv.touse == 0; + +switch uv.colorstyle + case 'none' + % default gray + lcolors = [0.5 0.5 0.5]; + tmpchi2 = uncert.chi2_all(in); + tmpmnorm = uncert.mnorm_all(in); + tmpE0 = uncert.interp_E0(in); + tmpTlgm = uncert.interp_Tlgm(in); + clims = [0 1]; + case 'chi2' + tmp = uncert.chi2_all(in); + [tmpchi2,idx] = sort(tmp); + lcolors = tmpchi2; + tmpmnorm = uncert.mnorm_all(in); + tmpmnorm = tmpmnorm(idx); + tmpE0 = uncert.interp_E0(in); + tmpE0 = tmpE0(idx); + tmpTlgm = uncert.interp_Tlgm(in); + tmpTlgm = tmpTlgm(idx); + clims = [min(uncert.chi2_all) max(uncert.chi2_all)]; + case 'xn' + tmp = uncert.mnorm_all(in); + [tmpmnorm,idx] = sort(tmp); + lcolors = tmpmnorm; + tmpchi2 = uncert.chi2_all(in); + tmpchi2 = tmpchi2(idx); + tmpE0 = uncert.interp_E0(in); + tmpE0 = tmpE0(idx); + tmpTlgm = uncert.interp_Tlgm(in); + tmpTlgm = tmpTlgm(idx); + clims = [min(uncert.mnorm_all) max(uncert.mnorm_all)]; +end + +% --- chi2 vs model norm --- +scatter(uncert.chi2_all(out),uncert.mnorm_all(out),[],'red',... + 'LineWidth',1,'Parent',gui.axes12); +scatter(gui.axes12,tmpchi2,tmpmnorm,[],lcolors,... + 'LineWidth',1); +plot(invstd.chi2,invstd.xn,'+','MarkerSize',10,'Color',col.FIT,'Parent',gui.axes12); +% axis limits +xlims = [min([uncert.chi2_all(in); invstd.chi2]) max([uncert.chi2_all(in); invstd.chi2])]; +dx = xlims(2)-xlims(1); +xlims = [xlims(1)-dx/5 xlims(2)+dx/5]; +ylims = [min([uncert.mnorm_all(in); invstd.xn]) max([uncert.mnorm_all(in); invstd.xn])]; +dy = ylims(2)-ylims(1); +ylims = [ylims(1)-dy/5 ylims(2)+dy/5]; +% -- lines indicating TLGM and E0 bounds -- +line([min(uncert.chi2_all(in)) min(uncert.chi2_all(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines'); +line([max(uncert.chi2_all(in)) max(uncert.chi2_all(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines'); +line([xlims(1) xlims(2)],[min(uncert.mnorm_all(in)) min(uncert.mnorm_all(in))],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines'); +line([xlims(1) xlims(2)],[max(uncert.mnorm_all(in)) max(uncert.mnorm_all(in))],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'Parent',gui.axes12,'Tag','infolines'); +% axis setings +set(gui.axes12,'XScale','lin','XLim',xlims); +set(gui.axes12,'YScale','log','YLim',ylims); +set(gui.axes12,'CLim',clims); +set(get(gui.axes12,'XLabel'),'String','X² (error weighted residuals)'); +set(get(gui.axes12,'YLabel'),'String','model norm |Lm|_{2}'); + +% --- TLGM vs E0 --- +scatter(uncert.interp_Tlgm(out),uncert.interp_E0(out),[],'red',... + 'LineWidth',1,'DisplayName','runs (out)','Parent',gui.axes11); +scatter(tmpTlgm,tmpE0,[],lcolors,... + 'LineWidth',1,'DisplayName','runs (in)','Parent',gui.axes11); +plot(invstd.Tlgm,invstd.E0,'+','MarkerSize',10,'Color',col.FIT,... + 'DisplayName','init','Parent',gui.axes11); +errorbar(uv.Tlgm(1),uv.E0(1),2*uv.E0(2),2*uv.E0(2),2*uv.Tlgm(2),2*uv.Tlgm(2),... + 'Color',col.BoxPRC,'LineWidth',2,'DisplayName','mean (2*std)','Parent',gui.axes11); +errorbar(uv.Tlgm_aadmed(1),uv.E0_aadmed(1),2*uv.E0_aadmed(2),2*uv.E0_aadmed(2),2*uv.Tlgm_aadmed(2),2*uv.Tlgm_aadmed(2),... + 'Color',col.BoxCPS,'LineWidth',2,'DisplayName','median (2*aad)','Parent',gui.axes11); +% axis limits +% xlims = [min([uncert.interp_Tlgm; invstd.Tlgm; uv.Tlgm(1)])*0.95 ... +% max([uncert.interp_Tlgm; invstd.Tlgm; uv.Tlgm(1)])*1.05]; +% ylims = [min([uncert.interp_E0; invstd.E0; uv.E0(1)])*0.95 ... +% max([uncert.interp_E0; invstd.E0; uv.E0(1)])*1.05]; +xlims = [min([uncert.interp_Tlgm(in); invstd.Tlgm; uv.Tlgm(1)])*0.975 ... + max([uncert.interp_Tlgm(in); invstd.Tlgm; uv.Tlgm(1)])*1.025]; +ylims = [min([uncert.interp_E0(in); invstd.E0; uv.E0(1)])*0.975 ... + max([uncert.interp_E0(in); invstd.E0; uv.E0(1)])*1.025]; +% -- lines indicating TLGM and E0 bounds -- +line([min(uncert.interp_Tlgm(in)) min(uncert.interp_Tlgm(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines'); +line([max(uncert.interp_Tlgm(in)) max(uncert.interp_Tlgm(in))],[ylims(1) ylims(2)],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines'); +line([xlims(1) xlims(2)],[min(uncert.interp_E0(in)) min(uncert.interp_E0(in))],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines'); +line([xlims(1) xlims(2)],[max(uncert.interp_E0(in)) max(uncert.interp_E0(in))],'Color',[0.25 0.25 0.25],... + 'LineStyle',':','LineWidth',0.75,'HandleVisibility','off','Parent',gui.axes11,'Tag','infolines'); +legend(gui.axes11,'Location','NorthEast'); +% axis settings +set(gui.axes11,'XScale','lin','XLim',xlims); +set(gui.axes11,'YScale','lin','YLim',ylims); +set(gui.axes11,'CLim',clims); +set(get(gui.axes11,'XLabel'),'String','TLGM'); +set(get(gui.axes11,'YLabel'),'String','initial amplitude E0'); + +% --- RTDs --- +plotmethod = 1; +switch uv.rtd_plotstyle + case 'patchmean' + plotmethod = 2; + case 'patchmedian' + plotmethod = 3; + otherwise + % nothing to do because 'lines' is default +end + +% the 'init' RTD +F0 = invstd.T1T2f; +% normalize all curves to the median of all E0 values +E0norm = uv.E0_aadmed(1); +if sum(F0)>0 + F = (data.invstd.porosity*100).*F0./E0norm; + ylims = [0 max(F)*1.05]; +else + ylims = [-1 1]; +end +% the uncertainty runs +% only the selected ones within the chi2 and xn bounds +FDIST = uncert.interp_f(in,:); +% scaling +FDIST = (data.invstd.porosity*100).*FDIST./E0norm; + +% if selected plot lines +if plotmethod == 1 + % find maximum for axis limts + f_max = max([ylims(2) max(FDIST(:))]); + switch uv.colorstyle + case {'chi2','xn'} + % get colormap from chi2 vs xn axis + cmap = get(gui.axes12,'Colormap'); + % make vector of values to sort + idc = linspace(clims(1),clims(2),size(cmap,1)); + for i1 = 1:sum(in) + % find closest value (need for coloring) + idc1 = find(abs(idc-tmp(idx(i1)))==min(abs(idc-tmp(idx(i1))))); + % idc1 = abs(idc-tmp(idx(i1)))==min(abs(idc-tmp(idx(i1)))); + % plot line with correct color + plot(invstd.T1T2me,FDIST(idx(i1),:),'-','Color',cmap(idc1(1),:),... + 'LineWidth',1,'Displayname',num2str(tmp(idx(i1))),'Parent',gui.axes2); + end + % adjust color limits + set(gui.axes2,'CLim',clims); + otherwise + % need to plot transpose of FDIST because 'x' is a column vector + % otherwise plot goes bananas if numel(x) = #models + plot(invstd.T1T2me,FDIST','-','Color',[0.5 0.5 0.5],... + 'LineWidth',1,'Parent',gui.axes2); + end +end + +% if selcted plot patch +if plotmethod > 1 + % what kind of patch is created + if plotmethod == 2 % mean +- std + mean_f = mean(FDIST); + std_f = std(FDIST); + else % median +- mad + mean_f = median(FDIST); + std_f = getAAD(FDIST,1); + end + + % patch lower and upper bounds + patch_f_std1 = [mean_f+std_f;mean_f-std_f]; + patch_f_std2 = [mean_f+2*std_f;mean_f-2*std_f]; + patch_f_std3 = [mean_f+3*std_f;mean_f-3*std_f]; + patch_f_std1(patch_f_std1<0) = 0; + patch_f_std2(patch_f_std2<0) = 0; + patch_f_std3(patch_f_std3<0) = 0; + f_max = max([ylims(2) max(patch_f_std1) max(patch_f_std2) max(patch_f_std3)]); + + % draw all three patches on top of each other + verts = [invstd.T1T2me patch_f_std3(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std3(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,'FaceColor',[0.6 0.6 0.6],... + 'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2); + verts = [invstd.T1T2me patch_f_std2(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std2(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,'FaceColor',[0.4 0.4 0.4],... + 'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2); + verts = [invstd.T1T2me patch_f_std1(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std1(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,'FaceColor',[0.2 0.2 0.2],... + 'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2); +end + +% adjust y-limits +ylims(2) = max([ylims(2) max(f_max)*1.05]); + +% plot original solution +plot(invstd.T1T2me,F,'-','Color',col.FIT,'Parent',gui.axes2); + +% -- RTD bounds -- +uv = data.uv; +line([uv.rtd_range(1) uv.rtd_range(1)],[0 ylims(2)],'Color',[0.25 0.25 0.25],... + 'LineStyle','-.','LineWidth',2,'Parent',gui.axes2,'Tag','infolines'); +line([uv.rtd_range(2) uv.rtd_range(2)],[0 ylims(2)],'Color',[0.25 0.25 0.25],... + 'LineStyle','-.','LineWidth',2,'Parent',gui.axes2,'Tag','infolines'); + +% axes properties: +ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me))); +set(gui.axes2,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); +set(gui.axes2,'YScale','lin','YLim',ylims); +set(get(gui.axes2,'XLabel'),'String','relaxation time'); +set(get(gui.axes2,'YLabel'),'String','amplitude'); +grid(gui.axes2,'on'); + +% --- Histograms --- +hasStatBox = strcmp(data.info.stat,'off'); +% get the kernel density estimate (more precise compared to a simple histogram) +if hasStatBox + % Statistics ToolBox + [f1,xi1] = ksdensity(uncert.interp_E0(in)); + [f2,xi2] = ksdensity(uncert.interp_Tlgm(in)); +else + % FEX contribution + [~,f1,xi1] = kde(uncert.interp_E0(in),numel(uncert.interp_E0(in))); + [~,f2,xi2] = kde(uncert.interp_Tlgm(in),numel(uncert.interp_Tlgm(in))); +end + +% plot the KDEs +plot(xi1,f1,'Color',[0.5 0.5 0.5],'DisplayName','KDE','Parent',gui.axes21); +plot(xi2,f2,'Color',[0.5 0.5 0.5],'DisplayName','KDE','Parent',gui.axes22); + +% "init" E0 +line([invstd.E0 invstd.E0],[0 max(f1)],'Color',col.FIT,... + 'LineStyle',':','LineWidth',2,'Parent',gui.axes21,'DisplayName','init',... + 'Tag','infolines'); +% "init" TLGM +line([invstd.Tlgm invstd.Tlgm],[0 max(f2)],'Color',col.FIT,... + 'LineStyle',':','LineWidth',2,'Parent',gui.axes22,'DisplayName','init',... + 'Tag','infolines'); + +% mean E0 +line([uv.E0(1) uv.E0(1)],[0 max(f1)],'Color',col.BoxPRC,... + 'LineStyle','-','LineWidth',2,'Parent',gui.axes21,'DisplayName','mean'); +line([uv.E0(1)+2*uv.E0(2) uv.E0(1)+2*uv.E0(2)],[0 max(f1)],'Color',col.BoxPRC,... + 'LineStyle','--','LineWidth',1,'Parent',gui.axes21,'DisplayName','2*std'); +line([uv.E0(1)-2*uv.E0(2) uv.E0(1)-2*uv.E0(2)],[0 max(f1)],'Color',col.BoxPRC,... + 'LineStyle','--','LineWidth',1,'Parent',gui.axes21,'DisplayName','2*std',... + 'HandleVisibility','off','Tag','infolines'); + +% mean TLGM +line([uv.Tlgm(1) uv.Tlgm(1)],[0 max(f2)],'Color',col.BoxPRC,... + 'LineStyle','-','LineWidth',2,'Parent',gui.axes22,'DisplayName','mean'); +line([uv.Tlgm(1)+2*uv.Tlgm(2) uv.Tlgm(1)+2*uv.Tlgm(2)],[0 max(f2)],'Color',col.BoxPRC,... + 'LineStyle','--','LineWidth',1,'Parent',gui.axes22,'DisplayName','2*std'); +line([uv.Tlgm(1)-2*uv.Tlgm(2) uv.Tlgm(1)-2*uv.Tlgm(2)],[0 max(f2)],'Color',col.BoxPRC,... + 'LineStyle','--','LineWidth',1,'Parent',gui.axes22,'DisplayName','2*std',... + 'HandleVisibility','off','Tag','infolines'); + +% median E0 +line([uv.E0_aadmed(1) uv.E0_aadmed(1)],[0 max(f1)],'Color',col.BoxCPS,... + 'LineStyle','-','LineWidth',2,'Parent',gui.axes21,'DisplayName','median'); +line([uv.E0_aadmed(1)+2*uv.E0_aadmed(2) uv.E0_aadmed(1)+2*uv.E0_aadmed(2)],... + [0 max(f1)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... + 'Parent',gui.axes21,'DisplayName','2*aad'); +line([uv.E0_aadmed(1)-2*uv.E0_aadmed(2) uv.E0_aadmed(1)-2*uv.E0_aadmed(2)],... + [0 max(f1)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... + 'Parent',gui.axes21,'DisplayName','2*aad','HandleVisibility','off',... + 'Tag','infolines'); + +% median TLGM +line([uv.Tlgm_aadmed(1) uv.Tlgm_aadmed(1)],[0 max(f2)],'Color',col.BoxCPS,... + 'LineStyle','-','LineWidth',2,'Parent',gui.axes22,'DisplayName','median'); +line([uv.Tlgm_aadmed(1)+2*uv.Tlgm_aadmed(2) uv.Tlgm_aadmed(1)+2*uv.Tlgm_aadmed(2)],... + [0 max(f2)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... + 'Parent',gui.axes22,'DisplayName','2*aad'); +line([uv.Tlgm_aadmed(1)-2*uv.Tlgm_aadmed(2) uv.Tlgm_aadmed(1)-2*uv.Tlgm_aadmed(2)],... + [0 max(f2)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... + 'Parent',gui.axes22,'DisplayName','2*aad','HandleVisibility','off',... + 'Tag','infolines'); + +legend(gui.axes22,'Location','NorthWest'); + +% axes properties +set(get(gui.axes21,'XLabel'),'String','E0'); +set(get(gui.axes21,'YLabel'),'String','kernel denisty estimate'); +set(get(gui.axes22,'XLabel'),'String','TLGM'); +set(get(gui.axes22,'YLabel'),'String','kernel density estimate'); + +% hold off all axes +hold(gui.axes11,'off'); +hold(gui.axes12,'off'); +hold(gui.axes2,'off'); +hold(gui.axes21,'off'); +hold(gui.axes22,'off'); +end + +%% close function +function uv_closeme(src,~) +figh = ancestor(src,'figure','toplevel'); +% try to close the sub GUI in a clean manner +try + % NOTE: maybe needed at some later point + % gui = getappdata(figh,'gui'); + % data = getappdata(gui.figh_nucleus,'data'); + % % update NUCLEUSinv + % setappdata(gui.figh_nucleus,'data',data); + delete(figh); +catch + % if this is not working: just close it + delete(figh); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% MIT License +% +% Copyright (c) 2024 Thomas Hiller +% +% Permission is hereby granted, free of charge, to any person obtaining a copy +% of this software and associated documentation files (the "Software"), to deal +% in the Software without restriction, including without limitation the rights +% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +% copies of the Software, and to permit persons to whom the Software is +% furnished to do so, subject to the following conditions: +% +% The above copyright notice and this permission notice shall be included in all +% copies or substantial portions of the Software. +% +% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +% SOFTWARE. \ No newline at end of file diff --git a/functions/interface/clearInversion.m b/functions/interface/clearInversion.m index 68ff173..31461f1 100644 --- a/functions/interface/clearInversion.m +++ b/functions/interface/clearInversion.m @@ -65,6 +65,8 @@ function clearInversion(id) % clear inversion axes clearSingleAxis(gui.axes_handles.rtd); clearSingleAxis(gui.axes_handles.psd); + % switch-off uncert context menu + set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); % clear the info fields set(gui.listbox_handles.info_signal,'String',' '); set(gui.listbox_handles.info_dist,'String',' '); @@ -102,6 +104,8 @@ function clearInversion(id) % clear inversion axes clearSingleAxis(gui.axes_handles.rtd); clearSingleAxis(gui.axes_handles.psd); + % switch-off uncert context menu + set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); % clear the info fields set(gui.listbox_handles.info_signal,'String',' '); set(gui.listbox_handles.info_dist,'String',' '); diff --git a/functions/interface/clearSingleAxis.m b/functions/interface/clearSingleAxis.m index e49489e..23c4f0d 100644 --- a/functions/interface/clearSingleAxis.m +++ b/functions/interface/clearSingleAxis.m @@ -43,6 +43,9 @@ function clearSingleAxis(axh) ph = findall(axh,'Tag','fits'); if ~isempty(ph); set(ph,'HandleVisibility','on'); end +ph = findall(axh,'Tag','infolines'); +if ~isempty(ph); set(ph,'HandleVisibility','on'); end + %% clear the axis itself cla(axh); diff --git a/functions/interface/enableGUIelements.m b/functions/interface/enableGUIelements.m index f588368..f22f88d 100644 --- a/functions/interface/enableGUIelements.m +++ b/functions/interface/enableGUIelements.m @@ -40,16 +40,7 @@ function enableGUIelements(importtype) case {'ASCII','EXCEL','MOD'} % process panel data.process.end = 0; - data.process.gatetype = 'raw'; - data.process.norm = 0; - data.process.timescale = 's'; - data.process.timefac = 1; - % invstd panel - data.invstd.invtype = 'NNLS'; - data.invstd.regtype = 'manual'; - data.invstd.lambda = 1; - data.invstd.Lorder = 1; - set(gui.push_handles.invstd_run,'Enable','on'); + data.process.gatetype = 'raw'; case 'NMR' % process panel data.process.end = 0; @@ -59,17 +50,20 @@ function enableGUIelements(importtype) otherwise data.process.gatetype = 'log'; end - data.process.norm = 0; - data.process.timescale = 's'; - data.process.timefac = 1; - % invstd panel - data.invstd.invtype = 'NNLS'; - data.invstd.regtype = 'manual'; - data.invstd.lambda = 1; - data.invstd.Lorder = 1; - set(gui.push_handles.invstd_run,'Enable','on'); end +% process panel - contd +data.process.norm = 0; +data.process.timescale = 's'; +data.process.timefac = 1; + +% invstd panel +data.invstd.invtype = 'NNLS'; +data.invstd.regtype = 'manual'; +data.invstd.lambda = 1; +data.invstd.Lorder = 1; +set(gui.push_handles.invstd_run,'Enable','on'); + % petro panel data.param.calibVol = 1; data.param.calibAmp = 1; diff --git a/functions/interface/getVersionNoFromString.m b/functions/interface/getVersionNoFromString.m index 17933a3..546f790 100644 --- a/functions/interface/getVersionNoFromString.m +++ b/functions/interface/getVersionNoFromString.m @@ -29,10 +29,11 @@ %------------- BEGIN CODE -------------- -% remove points -version_str = strrep(version_str,'.',''); +% find first point +idx = strfind(version_str,'.'); +version_str = version_str(idx(1)+1:end); % convert string to numeric value -version = str2double(version_str); +version = str2double(version_str)*100; end diff --git a/functions/interface/importASCIIdata.m b/functions/interface/importASCIIdata.m index 1c58c6f..aec58bb 100644 --- a/functions/interface/importASCIIdata.m +++ b/functions/interface/importASCIIdata.m @@ -41,7 +41,7 @@ function importASCIIdata(src) T1T2 = get(src,'Label'); % get file name -ASCIIpath = -1; +ASCIIpath = -1; %#ok<*NASGU> ASCIIfile = -1; if isfield(data.import,'path') [ASCIIfile,ASCIIpath] = uigetfile(fullfile(data.import.path,'*.*'),... @@ -122,26 +122,68 @@ function importASCIIdata(src) % the NMR data data.import.NMR.data{c}.flag = T1T2; data.import.NMR.data{c}.time = tmp_data(:,1); - if size(tmp_data,2)>2 - tmp_signal = complex(tmp_data(:,2),tmp_data(:,3)); - [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); - data.import.NMR.data{c}.signal = tmp_signal; - data.import.NMR.data{c}.phase = tmp_phase; - else - data.import.NMR.data{c}.signal = tmp_data(:,2); - data.import.NMR.data{c}.phase = 0; - - param.T1IRfac = 1; - param.noise = 0; - param.optim = 'off'; - invstd = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... - 'T2',param,5); - data.import.NMR.data{c}.noise = invstd.rms; + % switch between T1 and T2 data + switch T1T2 + case 'T1' + data.import.NMR.data{c}.signal = tmp_data(:,2); + data.import.NMR.data{c}.phase = 0; + + % try saturation recovery first + param.T1IRfac = 1; + param.noise = 0; + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd1 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... + data.import.NMR.data{c}.flag,param,5); + + % now inversion recovery + param.T1IRfac = 2; + param.noise = 0; + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd2 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... + data.import.NMR.data{c}.flag,param,5); + + % compare the residuals + if invstd1.resnorm < invstd2.resnorm + % data is possibly saturation recovery + invstd = invstd1; + T1IRfac = 1; + else + % data is possibly inversion recovery + invstd = invstd2; + T1IRfac = 2; + end + % save the "dummy" RMS as noise estimate + data.import.NMR.data{c}.noise = invstd.rms; + case 'T2' + T1IRfac = 1; + if size(tmp_data,2)>2 + tmp_signal = complex(tmp_data(:,2),tmp_data(:,3)); + [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); + data.import.NMR.data{c}.signal = tmp_signal; + data.import.NMR.data{c}.phase = tmp_phase; + else + data.import.NMR.data{c}.signal = tmp_data(:,2); + data.import.NMR.data{c}.phase = 0; + + % noise estimate + param.T1IRfac = 1; + param.noise = 0; + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... + data.import.NMR.data{c}.flag,param,5); + % save the "dummy" RMS as noise estimate + data.import.NMR.data{c}.noise = invstd.rms; + end end - data.import.NMR.data{c}.T1IRfac = 1; + data.import.NMR.data{c}.T1IRfac = T1IRfac; data.import.NMR.data{c}.raw.time = data.import.NMR.data{c}.time; data.import.NMR.data{c}.raw.signal = data.import.NMR.data{c}.signal; - data.import.NMR.data{c}.phase = 0; % dummy parameter data data.import.NMR.para{c} = 0; diff --git a/functions/interface/importEXCELdata.m b/functions/interface/importEXCELdata.m index b9d09ec..1494978 100644 --- a/functions/interface/importEXCELdata.m +++ b/functions/interface/importEXCELdata.m @@ -155,18 +155,70 @@ function importEXCELdata(src) % the NMR data data.import.NMR.data{c}.flag = T1T2; data.import.NMR.data{c}.time = num(:,1); - if size(num,2)>2 - tmp_signal = complex(num(:,2),num(:,3)); - [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); - data.import.NMR.data{c}.signal = tmp_signal; - data.import.NMR.data{c}.phase = tmp_phase; - else - data.import.NMR.data{c}.signal = num(:,2); + % switch between T1 and T2 data + switch T1T2 + case 'T1' + data.import.NMR.data{c}.signal = num(:,2); + data.import.NMR.data{c}.phase = 0; + + % try saturation recovery first + param.T1IRfac = 1; + param.noise = 0; + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd1 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... + data.import.NMR.data{c}.flag,param,5); + + % now inversion recovery + param.T1IRfac = 2; + param.noise = 0; + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd2 = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... + data.import.NMR.data{c}.flag,param,5); + + % compare the residuals + if invstd1.resnorm < invstd2.resnorm + % data is possibly saturation recovery + invstd = invstd1; + T1IRfac = 1; + else + % data is possibly inversion recovery + invstd = invstd2; + T1IRfac = 2; + end + % save the "dummy" RMS as noise estimate + data.import.NMR.data{c}.noise = invstd.rms; + case 'T2' + T1IRfac = 1; + if size(num,2)>2 + tmp_signal = complex(num(:,2),num(:,3)); + [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); + data.import.NMR.data{c}.signal = tmp_signal; + data.import.NMR.data{c}.phase = tmp_phase; + else + data.import.NMR.data{c}.signal = num(:,2); + data.import.NMR.data{c}.phase = 0; + + % noise estimate + param.T1IRfac = 1; + param.noise = 0; + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd = fitDataFree(data.import.NMR.data{c}.time,data.import.NMR.data{c}.signal,... + data.import.NMR.data{c}.flag,param,5); + % save the "dummy" RMS as noise estimate + data.import.NMR.data{c}.noise = invstd.rms; + end + end - data.import.NMR.data{c}.T1IRfac = 1; + data.import.NMR.data{c}.T1IRfac = T1IRfac; data.import.NMR.data{c}.raw.time = data.import.NMR.data{c}.time; data.import.NMR.data{c}.raw.signal = data.import.NMR.data{c}.signal; - + % dummy parameter data data.import.NMR.para{c} = 0; end diff --git a/functions/interface/importINV2INV.m b/functions/interface/importINV2INV.m index eb70abb..de3b36e 100644 --- a/functions/interface/importINV2INV.m +++ b/functions/interface/importINV2INV.m @@ -37,10 +37,11 @@ function importINV2INV(src) fig = findobj('Tag','INV'); gui = getappdata(fig,'gui'); data = getappdata(fig,'data'); +data0 = data; % get the file name -Sessionpath = -1; -Sessionfile = -1; +% Sessionpath = -1; +% Sessionfile = -1; % if there is already a data folder present start from there if isfield(data.import,'path') [Sessionfile,Sessionpath] = uigetfile(data.import.path,... @@ -103,11 +104,111 @@ function importINV2INV(src) savedata.data.invstd.Tfixed_val = data.invstd.Tfixed_val; for i = 1:numel(savedata.INVdata) if isstruct(savedata.INVdata{i}) + if strcmp(savedata.INVdata{i}.invstd.invtype,'mono') || .... + strcmp(savedata.INVdata{i}.invstd.invtype,'free') + switch savedata.INVdata{i}.results.nmrproc.T1T2 + case 'T1' + savedata.INVdata{i}.results.invstd.T = ... + savedata.INVdata{i}.results.invstd.T1; + case 'T2' + savedata.INVdata{i}.results.invstd.T = ... + savedata.INVdata{i}.results.invstd.T2; + end + end savedata.INVdata{i}.invstd.Tfixed_bool = data.invstd.Tfixed_bool; savedata.INVdata{i}.invstd.Tfixed_val = data.invstd.Tfixed_val; end end end + if version_in < 200 % changes introduced with v.0.2.0 + % new 'RTDuncert' info flag + savedata.data.info.RTDuncert = data.info.RTDuncert; + % new 'isgated' field + savedata.data.process.isgated = data.process.isgated; + % clean-up possible old 'uncert' fields that were not used + % prior to version 0.2.0 + if isfield(savedata.data.invstd,'useUncert') + savedata.data.invstd = rmfield(savedata.data.invstd,'useUncert'); + savedata.data.invstd = rmfield(savedata.data.invstd,'uncertMethod'); + savedata.data.invstd = rmfield(savedata.data.invstd,'uncertThresh'); + savedata.data.invstd = rmfield(savedata.data.invstd,'uncertChi2'); + savedata.data.invstd = rmfield(savedata.data.invstd,'uncertN'); + savedata.data.invstd = rmfield(savedata.data.invstd,'uncertMax'); + end + % now create the new 'uncert' struct + savedata.data.uncert = data.uncert; + + for i = 1:numel(savedata.INVdata) + if isstruct(savedata.INVdata{i}) + savedata.INVdata{i}.info.RTDuncert = data.info.RTDuncert; + if strcmp(savedata.INVdata{i}.process.gatetype,'raw') + savedata.INVdata{i}.process.isgated = false; + savedata.INVdata{i}.results.nmrproc.isgated = false; + else + savedata.INVdata{i}.process.isgated = true; + savedata.INVdata{i}.results.nmrproc.isgated = true; + end + + % clean-up possible old 'uncert' fields that were + % not used prior to version 0.2.0 + if isfield(savedata.INVdata{i}.invstd,'useUncert') + savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'useUncert'); + savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertMethod'); + savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertThresh'); + savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertChi2'); + savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertN'); + savedata.INVdata{i}.invstd = rmfield(savedata.INVdata{i}.invstd,'uncertMax'); + end + % now create the new 'uncert' struct + savedata.INVdata{i}.uncert = data.uncert; + + % now invtype is also stored in the results data + savedata.INVdata{i}.results.invstd.invtype = savedata.INVdata{i}.invstd.invtype; + + % new 'invparams' field + invparams.info = 'off'; + switch savedata.INVdata{i}.invstd.invtype + case {'mono','free'} + invparams.T1IRfac = savedata.INVdata{i}.results.nmrproc.T1IRfac; + invparams.noise = savedata.INVdata{i}.results.nmrproc.noise; + invparams.optim = data.info.has_optim; + invparams.Tfixed_bool = savedata.INVdata{i}.invstd.Tfixed_bool; + invparams.Tfixed_val = savedata.INVdata{i}.invstd.Tfixed_val; + if isfield(savedata.INVdata{i}.results.nmrproc,'W') + invparams.W = savedata.INVdata{i}.results.nmrproc.W; + end + invparams.t_raw = savedata.INVdata{i}.results.nmrraw.t; + invparams.s_raw = savedata.INVdata{i}.results.nmrraw.s; + + otherwise + invparams.T1T2 = savedata.INVdata{i}.results.nmrproc.T1T2; + invparams.T1IRfac = savedata.INVdata{i}.results.nmrproc.T1IRfac; + invparams.Tb = savedata.INVdata{i}.invstd.Tbulk; + invparams.Td = savedata.INVdata{i}.invstd.Tdiff; + invparams.Tint = [log10(savedata.INVdata{i}.invstd.time) savedata.INVdata{i}.invstd.Ntime]; + invparams.noise = savedata.INVdata{i}.results.nmrproc.noise; + if isfield(savedata.INVdata{i}.results.nmrproc,'W') + invparams.W = savedata.INVdata{i}.results.nmrproc.W; + end + switch savedata.INVdata{i}.invstd.invtype + case 'LU' + invparams.Lorder = savedata.INVdata{i}.invstd.Lorder; + invparams.lambda = savedata.INVdata{i}.invstd.lambda; + case 'NNLS' + invparams.regMethod = savedata.INVdata{i}.invstd.regtype; + invparams.Lorder = savedata.INVdata{i}.invstd.Lorder; + invparams.lambda = savedata.INVdata{i}.invstd.lambda; + invparams.solver = savedata.data.info.solver; + case 'MUMO' + invparams.nModes = savedata.INVdata{i}.invstd.freeDT; + invparams.optim = data.info.has_optim; + end + end + % add the new field to the inversion results + savedata.INVdata{i}.results.invstd.invparams = invparams; + end + end + end end % update GUI data from session mat-file @@ -179,6 +280,27 @@ function importINV2INV(src) set(gui.menu.extra_expert,'Checked','on'); end onMenuExpert(gui.menu.extra_expert); + + % adjust menu entry for LSQ solver + % first check if we have the optimization toolbox + switch data0.info.has_optim + case 'on' + % if yes, set the solver accordingly + switch savedata.data.info.solver + case 'lsqlin' + set(gui.menu.extra_solver_lsqlin,'Checked','on'); + onMenuSolver(gui.menu.extra_solver_lsqlin); + case 'lsqnonneg' + set(gui.menu.extra_solver_lsqnonneg,'Checked','on'); + onMenuSolver(gui.menu.extra_solver_lsqnonneg); + end + case 'off' + % if not set solver to LSQNONNEG + data.info.has_optim = 'off'; + set(gui.menu.extra_solver_lsqnonneg,'Checked','on'); + onMenuSolver(gui.menu.extra_solver_lsqnonneg); + set(gui.menu.extra_solver,'Enable','off'); + end % adjust menu entry for joint inversion switch savedata.data.info.JointInv diff --git a/functions/interface/minimizePanel.m b/functions/interface/minimizePanel.m index d594f96..2fb5b7b 100644 --- a/functions/interface/minimizePanel.m +++ b/functions/interface/minimizePanel.m @@ -48,14 +48,14 @@ function minimizePanel(src,~) def_heights = gui.myui.heights; % switch depending on figure tag -switch fig_tag - case 'INV' +switch fig_tag + case 'INV' panel_1 = 'Simple Processing'; panel_2 = 'Petro Parameter'; panel_3 = 'Standard Inversion'; panel_4 = 'Joint Inversion'; panel_5 = 'CPS (joint)'; - + switch paneltitle case panel_1 id = 2; @@ -64,12 +64,12 @@ function minimizePanel(src,~) case panel_3 id = 4; case panel_4 - id = 5; + id = 5; otherwise helpdlg({'function: minimizePanel',... 'Something is utterly wrong.'},'Info'); end - + switch paneltitle case {panel_1,panel_2,panel_3,panel_4} % all heights of the left panels @@ -107,15 +107,15 @@ function minimizePanel(src,~) helpdlg({'function: minimizePanel',... 'Something is utterly wrong.'},'Info'); end - - case 'MOD' + + case 'MOD' panel_1 = 'Geometry'; panel_2 = 'Pressure / Saturation'; panel_3 = 'NMR'; panel_4 = 'Pore Size Distribution'; panel_5 = 'Capillary Pressure Saturation Curve'; panel_6 = 'NMR Signals'; - + switch paneltitle case {panel_1,panel_4} id = 1; @@ -127,7 +127,7 @@ function minimizePanel(src,~) helpdlg({'function: minimizePanel',... 'Something is utterly wrong.'},'Info'); end - + switch paneltitle case {panel_1,panel_2,panel_3} % all heights of the left panels @@ -163,6 +163,46 @@ function minimizePanel(src,~) helpdlg({'function: minimizePanel',... 'Something is utterly wrong.'},'Info'); end + + case 'UNCERTVIEW' + panel_1 = 'Recalculate RTD Uncertainty'; + panel_2 = 'Process Uncertainty Runs'; + panel_3 = 'RTD Calculation Bounds'; + panel_4 = 'Uncertainty Statistics'; + + switch paneltitle + case panel_1 + id = 1; + case panel_2 + id = 2; + case panel_3 + id = 3; + case panel_4 + id = 4; + otherwise + helpdlg({'function: minimizePanel',... + 'Something is utterly wrong.'},'Info'); + end + + switch paneltitle + case {panel_1,panel_2,panel_3,panel_4} + % all heights of the left panels + heights = get(gui.left,'Heights'); + % default height of this panel + pheight = def_heights(2,id); + if isminimized % maximize panel + heights(id) = pheight; + set(gui.left,'Heights',heights); + set(panel,'Minimized',false); + else % minimize panel + heights(id) = pheightmin; + set(gui.left,'Heights',heights); + set(panel,'Minimized',true) + end + otherwise + helpdlg({'function: minimizePanel',... + 'Something is utterly wrong.'},'Info'); + end end % update GUI data setappdata(fig,'gui',gui); diff --git a/functions/interface/processNMRDataControl.m b/functions/interface/processNMRDataControl.m index cd18a8a..10df8e4 100644 --- a/functions/interface/processNMRDataControl.m +++ b/functions/interface/processNMRDataControl.m @@ -57,6 +57,7 @@ function processNMRDataControl(fig,id) nmrproc.start = data.process.start; nmrproc.end = data.process.end; nmrproc.norm = data.process.norm; +nmrproc.isgated = data.process.isgated; nmrproc.gatetype = data.process.gatetype; nmrproc.Nechoes = data.process.Nechoes; diff --git a/functions/interface/runInversionBatch.m b/functions/interface/runInversionBatch.m index 92141cc..cb8ea1c 100644 --- a/functions/interface/runInversionBatch.m +++ b/functions/interface/runInversionBatch.m @@ -191,19 +191,18 @@ data.results.nmrproc.s,param,data.invstd.freeDT); % estimate uncertainty - if data.invstd.useUncert - % original fit parameter - iparam = param; - % uncertainty parameter - uparam.time = data.results.nmrproc.t; - uparam.signal = data.results.nmrproc.s; - uparam.uncertMethod = data.invstd.uncertMethod; - uparam.uncertThresh = data.invstd.uncertThresh; - uparam.uncertChi2 = data.invstd.uncertChi2; - uparam.uncertN = data.invstd.uncertN; - uparam.uncertMax = data.invstd.uncertMax; - invstd = estimateUncertainty(data.invstd.invtype,invstd,iparam,uparam); - end +% if data.invstd.useUncert +% % original fit parameter +% iparam = param; +% % uncertainty parameter +% uparam.time = data.results.nmrproc.t; +% uparam.signal = data.results.nmrproc.s; +% uparam.uncertMethod = data.invstd.uncertMethod; +% uparam.uncertThresh = data.invstd.uncertThresh; +% uparam.uncertN = data.invstd.uncertN; +% uparam.uncertMax = data.invstd.uncertMax; +% invstd = estimateUncertainty(data.invstd.invtype,invstd,iparam,uparam); +% end end % save inversion results diff --git a/functions/interface/runInversionStd.m b/functions/interface/runInversionStd.m index 702e0f1..4666a32 100644 --- a/functions/interface/runInversionStd.m +++ b/functions/interface/runInversionStd.m @@ -211,6 +211,8 @@ infostring = 'Inversion using ''fminsearchbnd'' ... '; end displayStatusText(gui,infostring); + param.t_raw = data.results.nmrraw.t; + param.s_raw = data.results.nmrraw.s; invstd = fitDataFree(data.results.nmrproc.t,... data.results.nmrproc.s,flag,param,1); data.invstd.Tfixed_val = [invstd.T zeros(1,4)]; @@ -285,6 +287,7 @@ data.results.nmrproc.s,param); case 'MUMO' % N free distribution inversion + param.nModes = data.invstd.freeDT; param.T1T2 = data.results.nmrproc.T1T2; param.T1IRfac = data.results.nmrproc.T1IRfac; param.Tb = data.invstd.Tbulk; @@ -305,22 +308,7 @@ end displayStatusText(gui,infostring); invstd = fitDataMultiModal(data.results.nmrproc.t,... - data.results.nmrproc.s,param,data.invstd.freeDT); - - % estimate uncertainty - if data.invstd.useUncert - % original fit parameter - iparam = param; - % uncertainty parameter - uparam.time = data.results.nmrproc.t; - uparam.signal = data.results.nmrproc.s; - uparam.uncertMethod = data.invstd.uncertMethod; - uparam.uncertThresh = data.invstd.uncertThresh; - uparam.uncertChi2 = data.invstd.uncertChi2; - uparam.uncertN = data.invstd.uncertN; - uparam.uncertMax = data.invstd.uncertMax; - invstd = estimateUncertainty(data.invstd.invtype,invstd,iparam,uparam); - end + data.results.nmrproc.s,param); end % normalize to 1 if data.process.norm == 1 @@ -400,7 +388,7 @@ calibratePorosity; end end - % --- + % --- else % STOP was pressed (because "UserData" is 0) % reset "UserData" set(gui.push_handles.invstd_run,'UserData',1); diff --git a/functions/interface/switchToolTips.m b/functions/interface/switchToolTips.m index 25f4ef9..01a1d68 100644 --- a/functions/interface/switchToolTips.m +++ b/functions/interface/switchToolTips.m @@ -60,7 +60,7 @@ function switchToolTips(gui,onoff) eval(['ud = get(gui.',h{i},'.',fnames{j},... ',''UserData'');']); if isfield(ud,'Tooltipstr') - tstr = ud.Tooltipstr; + % tstr = ud.Tooltipstr; eval(['set(gui.',h{i},'.',fnames{j},... ',''ToolTipString'','''');']); end diff --git a/functions/interface/updateInfo.m b/functions/interface/updateInfo.m index d15d8be..9200d47 100644 --- a/functions/interface/updateInfo.m +++ b/functions/interface/updateInfo.m @@ -98,13 +98,18 @@ function updateInfo(src,~) %#ok end end - info{end+1,1} = ['noise = ',sprintf('%4.2e',nmrproc.noise),'']; + info{end+1,1} = ['noise = ',sprintf('%4.3f',nmrproc.noise),'']; info{end+1,1} = ' '; % possible inversion results/statistics if isfield(data.results,'invstd') invstd = data.results.invstd; invtype = data.invstd.invtype; + hasUncert = false; + if isfield(invstd,'uncert') + hasUncert = true; + uncert = invstd.uncert; + end switch invtype case 'mono' @@ -112,21 +117,21 @@ function updateInfo(src,~) %#ok switch nmrproc.T1T2 case 'T1' info{end+1,1} = ['E&infin = ',... - sprintf('%4.2e',sum(invstd.E0)),... - ' ∓ (',sprintf('%4.2e',ciE0),')','']; + sprintf('%5.3f',sum(invstd.E0)),... + ' ∓ (',sprintf('%5.3f',ciE0),')','']; case 'T2' info{end+1,1} = ['E0 = ',... - sprintf('%4.2e',sum(invstd.E0)),... - ' ∓ (',sprintf('%4.2e',ciE0),')','']; + sprintf('%5.3f',sum(invstd.E0)),... + ' ∓ (',sprintf('%5.3f',ciE0),')','']; end info{end+1,1} = ' '; if isfield(invstd,'chi2') if ~isnan(invstd.chi2) - str = ['&Chi2 = ',sprintf('%4.2f',invstd.chi2)]; + str = ['&Chi2 = ',sprintf('%5.3f',invstd.chi2)]; info{end+1,1} = ['',str,'']; end end - str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; + str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; info{end+1,1} = ['',str,'']; % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 if nmrproc.noise ~= 0 @@ -139,24 +144,23 @@ function updateInfo(src,~) %#ok switch nmrproc.T1T2 case 'T1' info{end+1,1} = ['E&infin = ',... - sprintf('%4.2e',sum(E0)),... - ' ∓ (',sprintf('%4.2e',ciE0s),')','']; + sprintf('%5.3f',sum(E0)),... + ' ∓ (',sprintf('%5.3f',ciE0s),')','']; case 'T2' info{end+1,1} = ['E0 = ',... - sprintf('%4.2e',sum(E0)),... - ' ∓ (',sprintf('%4.2e',ciE0s),')','']; + sprintf('%5.3f',sum(E0)),... + ' ∓ (',sprintf('%5.3f',ciE0s),')','']; end info{end+1,1} = ' '; if isfield(invstd,'chi2') if ~isnan(invstd.chi2) - str = ['&Chi2 = ',sprintf('%4.2f',invstd.chi2)]; + str = ['&Chi2 = ',sprintf('%5.3f',invstd.chi2)]; info{end+1,1} = ['',str,'']; end end - str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; + str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; info{end+1,1} = ['',str,'']; -% if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 if nmrproc.noise ~= 0 info{end+1,1} = ['S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'']; end @@ -164,52 +168,77 @@ function updateInfo(src,~) %#ok case {'LU','NNLS'} switch nmrproc.T1T2 case 'T1' - info{end+1,1} = ['E&infin = ',... - sprintf('%4.2e',sum(invstd.E0)),'']; + info{end+1,1} = ['E&infin = ',... + sprintf('%5.3f',sum(invstd.E0)),'']; case 'T2' - info{end+1,1} = ['E0 = ',... - sprintf('%4.2e',sum(invstd.E0)),'']; + info{end+1,1} = ['E0 = ',... + sprintf('%5.3f',sum(invstd.E0)),'']; + end + if hasUncert + switch nmrproc.T1T2 + case 'T1' + info{end+1,1} = ['E&infin = ',... + sprintf('%5.3f',uncert.E0(1)),... + ' ∓ (',sprintf('%5.3f',2*uncert.E0(2)),')','']; + case 'T2' + info{end+1,1} = ['E0 = ',... + sprintf('%5.3f',uncert.E0(1)),... + ' ∓ (',sprintf('%5.3f',2*uncert.E0(2)),')','']; + end end info{end+1,1} = ' '; if isfield(invstd,'chi2') if ~isnan(invstd.chi2) - str = ['&Chi2 = ',sprintf('%4.2f',invstd.chi2)]; + str = ['&Chi2 = ',sprintf('%5.3f',invstd.chi2)]; info{end+1,1} = ['',str,'']; end end - str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; + str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; info{end+1,1} = ['',str,'']; - % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 if nmrproc.noise ~= 0 info{end+1,1} = ['S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'']; end - info{end+1,1} = ['&lambda = ',sprintf('%6.5f',invstd.lambda_out),'']; + info{end+1,1} = ['&lambda = ',sprintf('%5.3f',invstd.lambda_out),'']; info{end+1,1} = ' '; case {'MUMO'} switch nmrproc.T1T2 case 'T1' - info{end+1,1} = ['E&infin = ',... - sprintf('%4.2e',sum(invstd.E0)),... - ' ∓ (',sprintf('%4.2e',invstd.ciE0),')','']; + info{end+1,1} = ['E&infin = ',... + sprintf('%5.3f',sum(invstd.E0)),'']; case 'T2' - info{end+1,1} = ['E0 = ',... - sprintf('%4.2e',sum(invstd.E0)),... - ' ∓ (',sprintf('%4.2e',invstd.ciE0),')','']; + info{end+1,1} = ['E0 = ',... + sprintf('%5.3f',sum(invstd.E0)),'']; + end + if hasUncert + switch nmrproc.T1T2 + case 'T1' + info{end+1,1} = ['E&infin = ',... + sprintf('%5.3f',uncert.E0(1)),... + ' ∓ (',sprintf('%5.3f',2*uncert.E0(2)),')','']; + case 'T2' + info{end+1,1} = ['E0 = ',... + sprintf('%5.3f',uncert.E0(1)),... + ' ∓ (',sprintf('%5.3f',2*uncert.E0(2)),')','']; + end end info{end+1,1} = ' '; if isfield(invstd,'chi2') if ~isnan(invstd.chi2) - str = ['&Chi2 = ',sprintf('%4.2f',invstd.chi2)]; + str = ['&Chi2 = ',sprintf('%5.3f',invstd.chi2)]; info{end+1,1} = ['',str,'']; end end - str = ['RMS = ',sprintf('%4.2e',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; + str = ['RMS = ',sprintf('%5.3f',invstd.rms),' (',sprintf('%4.2f',invstd.rms*100./sum(invstd.E0)),'%)']; info{end+1,1} = ['',str,'']; - % if strcmp(nmrproc.T1T2,'T2') && nmrproc.noise ~= 0 + if nmrproc.noise ~= 0 info{end+1,1} = ['S/N = ',sprintf('%4d',floor(sum(invstd.E0)/nmrproc.noise)),'']; end @@ -226,9 +255,9 @@ function updateInfo(src,~) %#ok info{end+1,1} = data.import.NMR.data{id}.date; info{end+1,1} = ' '; info{end+1,1} = ['t_min  = ',... - sprintf('%4.3e',data.results.nmrraw.t(1)),'']; + sprintf('%5.3e',data.results.nmrraw.t(1)),'']; info{end+1,1} = ['t_max  = ',... - sprintf('%4.3e',data.results.nmrraw.t(end)),'']; + sprintf('%5.3e',data.results.nmrraw.t(end)),'']; switch data.results.nmrproc.T1T2 case 'T1' info{end+1,1} = ' '; @@ -237,9 +266,9 @@ function updateInfo(src,~) %#ok '']; case 'T2' info{end+1,1} = ['t_echo = ',... - sprintf('%4.3e',data.results.nmrproc.echotime),'']; + sprintf('%5.3e',data.results.nmrproc.echotime),'']; info{end+1,1} = ['t_dead = ',... - sprintf('%4.3e',data.results.nmrproc.dead),'']; + sprintf('%5.3e',data.results.nmrproc.dead),'']; info{end+1,1} = ' '; info{end+1,1} = ['Echos  = ',... sprintf('%d',length(data.results.nmrraw.t)),... @@ -278,19 +307,19 @@ function updateInfo(src,~) %#ok levels = invjoint.levels; % global fit error - info{end+1,1} = ['ErrNorm: ',sprintf('%4.3e',invjoint.errnorm)]; - info{end+1,1} = ['RMS: ',sprintf('%4.3e',invjoint.rms)]; + info{end+1,1} = ['ErrNorm: ',sprintf('%5.3f',invjoint.errnorm)]; + info{end+1,1} = ['RMS: ',sprintf('%5.3f',invjoint.rms)]; info{end+1,1} = ['&Chi2: ',... - sprintf('%5.4f',invjoint.chi2),'']; + sprintf('%5.3f',invjoint.chi2),'']; info{end+1,1} = ' '; info{end+1,1} = '-----'; info{end+1,1} = ' '; for i = 1:numel(levels) info{end+1,1} = nmr{levels(i)}.name; - info{end+1,1} = ['RMS: ',sprintf('%4.3e',nmr{levels(i)}.rms)]; + info{end+1,1} = ['RMS: ',sprintf('%5.3f',nmr{levels(i)}.rms)]; info{end+1,1} = ['&Chi2: ',... - sprintf('%5.4f',nmr{levels(i)}.chi2),'']; + sprintf('%5.3f',nmr{levels(i)}.chi2),'']; info{end+1,1} = ' '; end end @@ -309,6 +338,11 @@ function updateInfo(src,~) %#ok nmrproc = data.results.nmrproc; invstd = data.results.invstd; invtype = data.invstd.invtype; + hasUncert = false; + if isfield(invstd,'uncert') + hasUncert = true; + uncert = invstd.uncert; + end switch invtype case 'mono' @@ -326,13 +360,13 @@ function updateInfo(src,~) %#ok case 'T1' info{end+1,1} = ['T1 = ',... - sprintf('%5.4f',invstd.T1),... - ' ∓ (',sprintf('%5.4f',ciT),')','']; + sprintf('%5.3f',invstd.T1),... + ' ∓ (',sprintf('%5.3f',ciT),')','']; case 'T2' info{end+1,1} = ['T2 = ',... - sprintf('%5.4f',invstd.T2),... - ' ∓ (',sprintf('%5.4f',ciT),')','']; + sprintf('%5.3f',invstd.T2),... + ' ∓ (',sprintf('%5.3f',ciT),')','']; end info{end+1,1} = ' '; @@ -361,10 +395,10 @@ function updateInfo(src,~) %#ok end info{end+1,1} = ['T(',num2str(i),') = ',sprintf('%5.4f',T(i)),... - ' ∓ (',sprintf('%5.4f',ciT(i)),')','']; %#ok<*AGROW> - info{end+1,1} = ['E(',num2str(i),') = ',sprintf('%5.4f',E0(i)),... - ' ∓ (',sprintf('%5.4f',ciE0(i)),')','']; + sprintf('%d,%d,%d',col),')">T(',num2str(i),') = ',sprintf('%5.3f',T(i)),... + ' ∓ (',sprintf('%5.3f',ciT(i)),')','']; %#ok<*AGROW> + info{end+1,1} = ['E(',num2str(i),') = ',sprintf('%5.3f',E0(i)),... + ' ∓ (',sprintf('%5.3f',ciE0(i)),')','']; info{end+1,1} = ' '; end @@ -375,7 +409,12 @@ function updateInfo(src,~) %#ok info{end+1,1} = ' '; % TLGM - info{end+1,1} = ['TLGM = ',sprintf('%5.4f',invstd.Tlgm),'']; + info{end+1,1} = ['TLGM = ',sprintf('%5.3f',invstd.Tlgm),'']; + if hasUncert + info{end+1,1} = ['TLGM = ',sprintf('%5.3f',uncert.Tlgm(1)),... + ' ∓ (',sprintf('%5.3f',2*uncert.Tlgm(2)),')','']; + end info{end+1,1} = ' '; % clay-bound water CBW < tcut ms @@ -408,7 +447,12 @@ function updateInfo(src,~) %#ok info{end+1,1} = ' '; % TLGM - info{end+1,1} = ['TLGM = ',sprintf('%5.4f',invstd.Tlgm),'']; + info{end+1,1} = ['TLGM = ',sprintf('%5.3f',invstd.Tlgm),'']; + if hasUncert + info{end+1,1} = ['TLGM = ',sprintf('%5.3f',uncert.Tlgm(1)),... + ' ∓ (',sprintf('%5.3f',2*uncert.Tlgm(2)),')','']; + end info{end+1,1} = ' '; % clay-bound water CBW < tcut ms @@ -443,12 +487,12 @@ function updateInfo(src,~) %#ok ciT = T - exp(tmpT); for i = 1:length(T) - info{end+1,1} = ['T(',num2str(i),') = ',sprintf('%5.4f',T(i)),... - ' ∓ (',sprintf('%5.4f',ciT(i)),')','']; %#ok<*AGROW> - info{end+1,1} = ['S(',num2str(i),') = ',sprintf('%5.4f',S(i)),... - ' ∓ (',sprintf('%5.4f',ciS(i)),')','']; - info{end+1,1} = ['E(',num2str(i),') = ',sprintf('%5.4f',E(i)),... - ' ∓ (',sprintf('%5.4f',ciE(i)),')','']; + info{end+1,1} = ['T(',num2str(i),') = ',sprintf('%5.3f',T(i)),... + ' ∓ (',sprintf('%5.3f',ciT(i)),')','']; %#ok<*AGROW> + info{end+1,1} = ['S(',num2str(i),') = ',sprintf('%5.3f',S(i)),... + ' ∓ (',sprintf('%5.3f',ciS(i)),')','']; + info{end+1,1} = ['E(',num2str(i),') = ',sprintf('%5.3f',E(i)),... + ' ∓ (',sprintf('%5.3f',ciE(i)),')','']; info{end+1,1} = ' '; end end @@ -469,17 +513,17 @@ function updateInfo(src,~) %#ok switch data.invjoint.geometry_type case 'cyl' info{end+1,1} = ['Shape: ',data.invjoint.geometry_type]; - info{end+1,1} = ['Geom.: ',sprintf('%4.2f',invjoint.iGEOM.a)]; + info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; case 'ang' info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,' ',... num2str(invjoint.iGEOM.angles(1)),' ',... num2str(invjoint.iGEOM.angles(2)),' ',... num2str(invjoint.iGEOM.angles(3))]; - info{end+1,1} = ['Geom.: ',sprintf('%4.2f',invjoint.iGEOM.a)]; + info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; case 'poly' info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,... ' ',num2str(data.invjoint.polyN),' sides']; - info{end+1,1} = ['Geom.: ',sprintf('%4.2f',invjoint.iGEOM.a)]; + info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; end info{end+1,1} = ' '; info{end+1,1} = ['rho (INV): ',sprintf('%5.3f',invjoint.irho*1e6),' [µm/s]']; @@ -508,18 +552,18 @@ function updateInfo(src,~) %#ok for i = 1:numel(levels) info{end+1,1} = nmr{levels(i)}.name; info{end+1,1} = ['press. : ',... - sprintf('%5.4f',invjoint.p0(levels(i))*data.pressure.unitfac),... + sprintf('%5.3f',invjoint.p0(levels(i))*data.pressure.unitfac),... ' [',data.pressure.unit,']']; switch invjoint.T1T2 case 'T1' info{end+1,1} = ['sat. (INV) : ',... - sprintf('%4.2f',invjoint.idata.nmr{levels(i)}.fit_g(end))]; + sprintf('%5.3f',invjoint.idata.nmr{levels(i)}.fit_g(end))]; case 'T2' info{end+1,1} = ['sat. (INV) : ',... - sprintf('%4.2f',invjoint.idata.nmr{levels(i)}.fit_g(1))]; + sprintf('%5.3f',invjoint.idata.nmr{levels(i)}.fit_g(1))]; end info{end+1,1} = ['sat. (MOD) : ',... - sprintf('%4.2f',invjoint.S0(levels(i)))]; + sprintf('%5.3f',invjoint.S0(levels(i)))]; info{end+1,1} = ' '; end end diff --git a/functions/interface/updatePlotsDistribution.m b/functions/interface/updatePlotsDistribution.m index 6a119d8..231f1db 100644 --- a/functions/interface/updatePlotsDistribution.m +++ b/functions/interface/updatePlotsDistribution.m @@ -35,10 +35,22 @@ data = getappdata(fig,'data'); col = gui.myui.colors; -nmrproc = data.results.nmrproc; +% assume there is no uncertainty data +hasUncert = false; +set(gui.cm_handles.axes_rtd_uncert,'Enable','off'); + +if isfield(data,'results') && isfield(data.results,'nmrproc') + nmrproc = data.results.nmrproc; +end % only continue if there is actual data to show -if isfield(data.results,'invstd') +if isfield(data,'results') && isfield(data.results,'invstd') invstd = data.results.invstd; + + if isfield(invstd,'uncert') + hasUncert = true; + uncert = invstd.uncert; + set(gui.cm_handles.axes_rtd_uncert,'Enable','on'); + end %% RTD % RTD axis @@ -103,73 +115,11 @@ % grid grid(ax,'on'); - case {'LU'} - % scale distribution by porosity - F = invstd.T1T2f; - if sum(F)>0 - F = (data.invstd.porosity*100).*F./sum(F); - ylims = [0 max(F)*1.05]; - else - ylims = [-1 1]; - end - if data.invstd.porosity == 1 - ylab1 = 'amplitudes [-]'; - ylab2 = 'cumulative amplitudes [-]'; - else - ylab1 = 'water content [vol. %]'; - ylab2 = 'cumulative water content [vol. %]'; - end - % F = data.invstd.porosity.*F./trapz(T,F); - - switch data.info.RTDflag - case 'freq' - plot(invstd.T1T2me,F,'o-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); - % find approx. TLGM amplitude - amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); - stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... - 'LineWidth',2,'Tag','TLGM','Parent',ax); - - % y-limits - set(ax,'YScale','lin','YLim',ylims); - % y-label - set(get(ax,'YLabel'),'String',ylab1); - - case 'cum' - plot(invstd.T1T2me,cumsum(F),'o-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); - % find approx. TLGM amplitude - amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); - stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... - 'LineWidth',2,'Tag','TLGM','Parent',ax); - - % y-limits - set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); - % y-label - set(get(ax,'YLabel'),'String',ylab2); - end - - % x-limits - ticks = round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me))); - set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); - % x-label - set(get(ax,'XLabel'),'String',xlstring); - % grid - grid(ax,'on'); - - case {'NNLS'} + case {'LU','NNLS'} % scale distribution by porosity - F = invstd.T1T2f; - if sum(F)>0 - % apply same scaling to the uncertainty patch - if isfield(data.results.invstd,'uncert') - f_min = data.results.invstd.uncert.interp_f_min; - f_max = data.results.invstd.uncert.interp_f_max; - f_min = (data.invstd.porosity*100).*f_min./sum(F); - f_max = (data.invstd.porosity*100).*f_max./sum(F); - end - F = (data.invstd.porosity*100).*F./sum(F); - + F0 = invstd.T1T2f; + if sum(F0)>0 + F = (data.invstd.porosity*100).*F0./sum(F0); ylims = [0 max(F)*1.05]; else ylims = [-1 1]; @@ -185,45 +135,97 @@ switch data.info.RTDflag case 'freq' - if isfield(data.results.invstd,'uncert') - % plot uncertainty - for i = 1:size(invstd.uncert.interp_f,1) - plot(invstd.T1T2me,(data.invstd.porosity*100).*invstd.uncert.interp_f(i,:)./sum(invstd.T1T2f),... - '-','Color',[0.5 0.5 0.5],'LineWidth',1,'Parent',ax); - end -% verts = [invstd.T1T2me f_min'; flipud(invstd.T1T2me) flipud(f_max')]; -% faces = 1:1:size(verts,1); -% patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... -% 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); + % check if there is uncertainty data + if hasUncert + % plot uncertainty models + f_max = 0; + FDIST = uncert.interp_f; + % scaling + FDIST = (data.invstd.porosity*100).*FDIST./sum(F0); + + switch data.info.RTDuncert + case 'lines' + f_max = max([ylims(2) max(FDIST(:))]); + % need to plot transpose of FDIST because 'x' + % is a column vector otherwise plot goes + % bananas if numel(x) = #models + plot(invstd.T1T2me,FDIST(1,:)','-','Color',[0.5 0.5 0.5],... + 'LineWidth',1,... + 'DisplayName','uncert models','Parent',ax); + plot(invstd.T1T2me,FDIST(2:end,:)','-','Color',[0.5 0.5 0.5],... + 'LineWidth',1,'HandleVisibility','off',... + 'Tag','infolines','Parent',ax); + case 'patch' + % get mean and std of all uncert models + mean_f = mean(FDIST); + std_f = std(FDIST); + + % patch lower and upper bounds + patch_f_std1 = [mean_f+std_f;mean_f-std_f]; + patch_f_std2 = [mean_f+2*std_f;mean_f-2*std_f]; + patch_f_std3 = [mean_f+3*std_f;mean_f-3*std_f]; + patch_f_std1(patch_f_std1<0) = 0; + patch_f_std2(patch_f_std2<0) = 0; + patch_f_std3(patch_f_std3<0) = 0; + f_max = max([ylims(2) max(patch_f_std1)... + max(patch_f_std2) max(patch_f_std3)]); + + % draw all three patches on top of each other + verts = [invstd.T1T2me patch_f_std3(2,:)';.... + flipud(invstd.T1T2me) flipud(patch_f_std3(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,... + 'FaceColor',[0.6 0.6 0.6],... + 'FaceAlpha',0.75,'EdgeColor','none',... + 'DisplayName','mean (3*std)','Parent',ax); + verts = [invstd.T1T2me patch_f_std2(2,:)';... + flipud(invstd.T1T2me) flipud(patch_f_std2(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,... + 'FaceColor',[0.4 0.4 0.4],... + 'FaceAlpha',0.75,'EdgeColor','none',... + 'DisplayName','mean (2*std)','Parent',ax); + verts = [invstd.T1T2me patch_f_std1(2,:)';... + flipud(invstd.T1T2me) flipud(patch_f_std1(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,... + 'FaceColor',[0.2 0.2 0.2],... + 'FaceAlpha',0.75,'EdgeColor','none',... + 'DisplayName','mean (std)','Parent',ax); + end % adjust y-limits ylims(2) = max([ylims(2) max(f_max)*1.05]); - end + + % plot original solution + plot(invstd.T1T2me,F,'-','Color',col.FIT,... + 'DisplayName','fit','LineWidth',2,'Parent',ax); + else + plot(invstd.T1T2me,F,'o-','Color',col.FIT,... + 'DisplayName','fit','LineWidth',2,'Parent',ax); + end - plot(invstd.T1T2me,F,'o-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); % find approx. TLGM amplitude amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); - stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... - 'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... + 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',ylims); % y-label set(get(ax,'YLabel'),'String',ylab1); + % legend + legend(ax,'Location','NorthEast'); case 'cum' - if isfield(data.results.invstd,'uncert') - verts = [invstd.T1T2me cumsum(F)-f_min'; flipud(invstd.T1T2me) flipud(cumsum(F)+f_max')]; - faces = 1:1:size(verts,1); - patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... - 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); - end + % in the case of the cumulative plot, no uncertainty is + % shown plot(invstd.T1T2me,cumsum(F),'o-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); + 'DisplayName','fit','LineWidth',2,'Parent',ax); + % find approx. TLGM amplitude amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); - stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... - 'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... + 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); @@ -253,20 +255,15 @@ dist(i,:) = (tmp/sum(tmp)) * amp; end - % scale distribution by porosity - F = invstd.T1T2f; - if sum(F)>0 + % scale RTD(s) by porosity + F0 = invstd.T1T2f; + if sum(F0)>0 + % individual RTDs for i = 1:length(invstd.x)/3 - dist(i,:) = (data.invstd.porosity*100).*dist(i,:)./sum(F); + dist(i,:) = (data.invstd.porosity*100).*dist(i,:)./sum(F0); end - % apply same scaling to the uncertainty patch - if isfield(data.results.invstd,'uncert') - f_min = data.results.invstd.uncert.interp_f_min; - f_max = data.results.invstd.uncert.interp_f_max; - f_min = (data.invstd.porosity*100).*f_min./sum(F); - f_max = (data.invstd.porosity*100).*f_max./sum(F); - end - F = (data.invstd.porosity*100).*F./sum(F); + % combined (total) RTD + F = (data.invstd.porosity*100).*F0./sum(F0); ylims = [0 max(F)*1.05]; else @@ -286,66 +283,100 @@ switch data.info.RTDflag case 'freq' - if isfield(data.results.invstd,'uncert') - % plot uncertainty - % lines - % for i = 1:size(invstd.TDIST,1) - % plot(invstd.T1T2me,(data.invstd.porosity*100).*invstd.TDIST(i,:)./sum(invstd.T1T2f),... - % '-','Color',[0.5 0.5 0.5],'LineWidth',1,'Parent',ax); - % end - % patch -% TDIST = invstd.TDIST; -% for i = 1:size(invstd.TDIST,1) -% TDIST(i,:) = (data.invstd.porosity*100).*invstd.TDIST(i,:)./sum(invstd.T1T2f); -% end -% TDISTmin = min(TDIST); -% TDISTmax = max(TDIST); -% verts = [nmrproc.t(nmrproc.t>0) s_min; flipud(nmrproc.t(nmrproc.t>0)) flipud(s_max)]; -% faces = 1:1:size(verts,1); -% - verts = [invstd.T1T2me f_min'; flipud(invstd.T1T2me) flipud(f_max')]; - faces = 1:1:size(verts,1); - patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... - 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); + if hasUncert + % plot uncertainty models + f_max = 0; + FDIST = uncert.interp_f; + % scaling + FDIST = (data.invstd.porosity*100).*FDIST./sum(F0); + + switch data.info.RTDuncert + case 'lines' + f_max = max([ylims(2) max(FDIST(:))]); + % need to plot transpose of FDIST because 'x' + % is a column vector otherwise plot goes + % bananas if numel(x) = #models + plot(invstd.T1T2me,FDIST(1,:)','-','Color',[0.5 0.5 0.5],... + 'LineWidth',1,'DisplayName','uncert models',... + 'Parent',ax); + plot(invstd.T1T2me,FDIST(2:end,:)','-','Color',[0.5 0.5 0.5],... + 'LineWidth',1,'HandleVisibility','off',... + 'Tag','infolines','Parent',ax); + case 'patch' + % get mean and std of all uncert models + mean_f = mean(FDIST); + std_f = std(FDIST); + + % patch lower and upper bounds + patch_f_std1 = [mean_f+std_f;mean_f-std_f]; + patch_f_std2 = [mean_f+2*std_f;mean_f-2*std_f]; + patch_f_std3 = [mean_f+3*std_f;mean_f-3*std_f]; + patch_f_std1(patch_f_std1<0) = 0; + patch_f_std2(patch_f_std2<0) = 0; + patch_f_std3(patch_f_std3<0) = 0; + f_max = max([ylims(2) max(patch_f_std1)... + max(patch_f_std2) max(patch_f_std3)]); + + % draw all three patches on top of each other + verts = [invstd.T1T2me patch_f_std3(2,:)';.... + flipud(invstd.T1T2me) flipud(patch_f_std3(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,... + 'FaceColor',[0.6 0.6 0.6],... + 'FaceAlpha',0.75,'EdgeColor','none',... + 'DisplayName','mean (3*std)','Parent',ax); + verts = [invstd.T1T2me patch_f_std2(2,:)';... + flipud(invstd.T1T2me) flipud(patch_f_std2(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,... + 'FaceColor',[0.4 0.4 0.4],... + 'FaceAlpha',0.75,'EdgeColor','none',... + 'DisplayName','mean (2*std)','Parent',ax); + verts = [invstd.T1T2me patch_f_std1(2,:)';... + flipud(invstd.T1T2me) flipud(patch_f_std1(1,:)')]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,... + 'FaceColor',[0.2 0.2 0.2],... + 'FaceAlpha',0.75,'EdgeColor','none',... + 'DisplayName','mean (std)','Parent',ax); + end % adjust y-limits ylims(2) = max([ylims(2) max(f_max)*1.05]); end % plot total RTD plot(invstd.T1T2me,F,'-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); + 'DisplayName','fit','LineWidth',2,'Parent',ax); % plot individual RTDs for i = 1:length(invstd.x)/3 plot(invstd.T1T2me,dist(i,:),'--','Color',mycols(i,:),... - 'LineWidth',2,'Parent',ax); + 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); end % find approx. TLGM amplitude amp = findApproxTlgmAmplitude(invstd.T1T2me,F,invstd.Tlgm); - stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... - 'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... + 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',ylims); % y-label set(get(ax,'YLabel'),'String',ylab1); + % legend + legend(ax,'Location','NorthEast'); case 'cum' - if isfield(data.results.invstd,'uncert') - verts = [invstd.T1T2me cumsum(F)-f_min'; flipud(invstd.T1T2me) flipud(cumsum(F)+f_max')]; - faces = 1:1:size(verts,1); - patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... - 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); - end + % in the case of the cumulative plot, no uncertainty is + % shown plot(invstd.T1T2me,cumsum(F),'-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); + 'DisplayName','fit','LineWidth',2,'Parent',ax); for i = 1:length(invstd.x)/3 plot(invstd.T1T2me,cumsum(dist(i,:)),'--','Color',mycols(i,:),... - 'LineWidth',2,'Parent',ax); + 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); end % find approx. TLGM amplitude amp = findApproxTlgmAmplitude(invstd.T1T2me,cumsum(F),invstd.Tlgm); - stem(invstd.Tlgm,amp,'x-','Color',col.axisL,... - 'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(invstd.Tlgm,amp,'x-','Color',col.FIT,'LineStyle','--',... + 'LineWidth',2,'DisplayName','TLGM','Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); @@ -436,10 +467,10 @@ switch data.info.PSDflag case 'freq' plot(requiv,F,'o-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); + 'DisplayName','fit','LineWidth',2,'Parent',ax); % find approx. RLGM amplitude amp = findApproxTlgmAmplitude(requiv,F,Rlgm); - stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',ylims); @@ -448,10 +479,10 @@ case 'cum' plot(requiv,cumsum(F),'o-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); + 'DisplayName','fit','LineWidth',2,'Parent',ax); % find approx. RLGM amplitude amp = findApproxTlgmAmplitude(requiv,cumsum(F),Rlgm); - stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); @@ -461,7 +492,7 @@ % x-limits ticks = floor(log10(min(requiv))) :1: ceil(log10(max(requiv))); - % set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); + % set(ax,'XScale','log','XLim',[10^(ticks(1)) 10^(ticks(end))],'XTick',10.^ticks); set(ax,'XScale','log','XLim',[min(requiv) max(requiv)],'XTick',10.^ticks); % x-label set(get(ax,'XLabel'),'String',xlstring); @@ -475,22 +506,15 @@ switch data.info.PSDflag case 'freq' - if isfield(data.results.invstd,'uncert') - verts = [requiv f_min'; flipud(requiv) flipud(f_max')]; - patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... - 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); - % adjust y-limits - ylims(2) = max([ylims(2) max(f_max)*1.05]); - end plot(requiv,F,'-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); + 'DisplayName','fit','LineWidth',2,'Parent',ax); for i = 1:length(invstd.x)/3 plot(requiv,dist(i,:),'--','Color',mycols(i,:),... - 'LineWidth',2,'Parent',ax); + 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); end % find approx. RLGM amplitude amp = findApproxTlgmAmplitude(requiv,F,Rlgm); - stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',ylims); @@ -498,20 +522,15 @@ set(get(ax,'YLabel'),'String',ylab1); case 'cum' - if isfield(data.results.invstd,'uncert') - verts = [requiv cumsum(F)-f_min'; flipud(requiv) flipud(cumsum(F)+f_max')]; - patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... - 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); - end plot(requiv,cumsum(F),'-','Color',col.FIT,... - 'LineWidth',2,'Parent',ax); + 'DisplayName','fit','LineWidth',2,'Parent',ax); for i = 1:length(invstd.x)/3 plot(requiv,cumsum(dist(i,:)),'--','Color',mycols(i,:),... - 'LineWidth',2,'Parent',ax); + 'DisplayName',['fit',num2str(i)],'LineWidth',2,'Parent',ax); end % find approx. RLGM amplitude amp = findApproxTlgmAmplitude(requiv,cumsum(F),Rlgm); - stem(Rlgm,amp,'x-','Color',col.axisL,'LineWidth',2,'Tag','TLGM','Parent',ax); + stem(Rlgm,amp,'x--','Color',col.FIT,'LineWidth',2,'Tag','TLGM','Parent',ax); % y-limits set(ax,'YScale','lin','YLim',[0 sum(F)*1.05]); diff --git a/functions/interface/updatePlotsDistributionInfo.m b/functions/interface/updatePlotsDistributionInfo.m index 2e843b2..aac50ef 100644 --- a/functions/interface/updatePlotsDistributionInfo.m +++ b/functions/interface/updatePlotsDistributionInfo.m @@ -55,9 +55,9 @@ xx = get(ax,'XLim'); yy = get(ax,'YLim'); line([CBW CBW],[yy(1) yy(2)],'Color',col,'LineStyle','--',... - 'LineWidth',2,'Parent',ax,'Tag','infolines'); + 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); line([BVI BVI],[yy(1) yy(2)],'Color',col,'LineStyle','--',... - 'LineWidth',2,'Parent',ax,'Tag','infolines'); + 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); if CBW > xx(1) xx1 = mean([log10(xx(1)) log10(CBW)]); @@ -103,9 +103,9 @@ xx = get(ax,'XLim'); yy = get(ax,'YLim'); line([fast fast],[yy(1) yy(2)],'Color',col,'LineStyle','--',... - 'LineWidth',2,'Parent',ax,'Tag','infolines'); + 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); line([slow slow],[yy(1) yy(2)],'Color',col,'LineStyle','--',... - 'LineWidth',2,'Parent',ax,'Tag','infolines'); + 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); if fast > xx(1) xx2 = mean([log10(xx(1)) log10(fast)]); diff --git a/functions/interface/updatePlotsJointInversion.m b/functions/interface/updatePlotsJointInversion.m index dca69df..27269c3 100644 --- a/functions/interface/updatePlotsJointInversion.m +++ b/functions/interface/updatePlotsJointInversion.m @@ -40,7 +40,7 @@ col = gui.myui.colors; % proceed only if there is data -if isfield(data.results,'invjoint') +if isfield(data,'results') && isfield(data.results,'invjoint') % get al relevant data invjoint = data.results.invjoint; nmr = invjoint.idata.nmr; diff --git a/functions/interface/updatePlotsSignal.m b/functions/interface/updatePlotsSignal.m index e98779d..78c3987 100644 --- a/functions/interface/updatePlotsSignal.m +++ b/functions/interface/updatePlotsSignal.m @@ -40,7 +40,8 @@ isjoint = strcmp(get(gui.menu.extra_joint,'Checked'),'on'); % proceed if there is data -if isfield(data.results,'nmrraw') && isfield(data.results,'nmrproc') +if isfield(data,'results') && isfield(data.results,'nmrraw') &&... + isfield(data.results,'nmrproc') % get NMR data nmrraw = data.results.nmrraw; nmrproc = data.results.nmrproc; @@ -121,7 +122,6 @@ line(xlims,[0 0],'LineStyle','--','LineWidth',1,'Color','k','Parent',axI); imag_mean = mean(imag(nmrraw.s)); imag_std = std(imag(nmrraw.s)); -% yticks = linspace(min(imag(nmrraw.s)),max(imag(nmrraw.s)),3); yticks = [imag_mean-imag_std*2 0 imag_mean+imag_std*2]; ylim = [imag_mean-imag_std*3 imag_mean+imag_std*3]; set(axI,'XTickLabel','','YLim',ylim,'YTick',yticks,'YTickLabelMode','auto'); @@ -147,22 +147,46 @@ % data switch data.invstd.invtype - case {'MUMO'} - if isfield(data.results,'invstd') && isfield(data.results.invstd,'uncert') - % uncertainty patch created from min max of uncertainty - % data - s_min = data.results.invstd.uncert.interp_s_min; - s_max = data.results.invstd.uncert.interp_s_max; - t = data.results.invstd.uncert.interp_t; - verts = [t(t>0) s_min(t>0); flipud(t(t>0)) flipud(s_max(t>0))]; - faces = 1:1:size(verts,1); - patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... - 'FaceAlpha',0.75,'EdgeColor','none','Parent',ax); - end - + case {'LU','NNLS','MUMO'} if isfield(data.results,'invstd') - plot(nmrproc.t,nmrproc.s,'-','Color',col.RE,'LineWidth',1,'Parent',ax); - plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,'Parent',ax); + if isfield(data.results.invstd,'uncert') + uncert = data.results.invstd.uncert; + t = uncert.interp_t; + SDIST = uncert.interp_s; + switch data.info.RTDuncert + case 'lines' + plot(t,SDIST(:,1),'-','Color',[0.5 0.5 0.5],... + 'LineWidth',1,... + 'DisplayName','uncert models','Parent',ax); + plot(t,SDIST(:,2:end),'-','Color',[0.5 0.5 0.5],... + 'LineWidth',1,'HandleVisibility','off',... + 'Tag','infolines','Parent',ax); + case 'patch' + % uncertainty patch created from min max of uncertainty + % data + s_min = data.results.invstd.uncert.interp_s_min; + s_max = data.results.invstd.uncert.interp_s_max; + t = data.results.invstd.uncert.interp_t; + verts = [t(t>0) s_min(t>0); flipud(t(t>0)) flipud(s_max(t>0))]; + faces = 1:1:size(verts,1); + patch('Faces',faces,'Vertices',verts,'FaceColor',[0.64 0.64 0.64],... + 'FaceAlpha',0.75,'EdgeColor','none',... + 'DisplayName','uncert','Parent',ax); + end + + end + if nmrproc.isgated + plot(data.results.nmrraw.t,data.results.nmrraw.s,'o',... + 'Color',[0.64 0.64 0.64],'LineWidth',0.75,... + 'DisplayName','signal_{raw}','Parent',ax); + plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... + 'DisplayName','signal_{gated}','Parent',ax); + else + plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... + 'DisplayName','signal','Parent',ax); + end + plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,... + 'DisplayName','fit','Parent',ax); if nmrproc.noise > 0 plot(nmrproc.t,invstd.residual./nmrproc.e,'Color',col.IM,... 'LineWidth',1,'Parent',axE); @@ -171,21 +195,39 @@ 'LineWidth',1,'Parent',axE); end else - plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,'Parent',ax); + if nmrproc.isgated + plot(data.results.nmrraw.t,data.results.nmrraw.s,'o',... + 'Color',[0.64 0.64 0.64],'LineWidth',0.75,... + 'DisplayName','signal_{raw}','Parent',ax); + plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... + 'DisplayName','signal_{gated}','Parent',ax); + else + plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',0.75,... + 'DisplayName','signal','Parent',ax); + end + end + + otherwise % mono & free + if nmrproc.isgated + plot(data.results.nmrraw.t,data.results.nmrraw.s,'o',... + 'Color',[0.64 0.64 0.64],'LineWidth',0.75,... + 'DisplayName','signal_{raw}','Parent',ax); + plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,... + 'DisplayName','signal_{gated}','Parent',ax); + else + plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,... + 'DisplayName','signal','Parent',ax); end - otherwise if isfield(data.results,'invstd') - plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,'Parent',ax); - plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,'Parent',ax); + plot(invstd.fit_t,invstd.fit_s,'Color',col.FIT,'LineWidth',2,... + 'DisplayName','fit','Parent',ax); if nmrproc.noise > 0 plot(nmrproc.t,invstd.residual./nmrproc.e,'Color',col.IM,... 'LineWidth',1,'Parent',axE); else plot(nmrproc.t,invstd.residual,'Color',col.IM,... 'LineWidth',1,'Parent',axE); - end - else - plot(nmrproc.t,nmrproc.s,'o','Color',col.RE,'LineWidth',1,'Parent',ax); + end end end @@ -199,6 +241,17 @@ case 'x-axis -> log' % lin axes set(ax,'XScale','lin','XLim',xlimraw,'XTickMode','auto'); end + xlims = xlimraw; + switch nmrproc.T1T2 + case 'T1' + if isfield(data.results,'invstd') && isfield(data.results.invstd,'uncert') + xlims(2) = max([xlimraw(2) max(data.results.invstd.uncert.interp_t)/2]); + end + set(ax,'XLim',xlims); + set(gui.axes_handles.raw,'XLim',xlims); + set(gui.axes_handles.imag,'XLim',xlims); + case 'T2' + end logliny = get(gui.cm_handles.axes_proc_yaxis,'Label'); switch nmrproc.T1T2 case 'T1' @@ -207,6 +260,9 @@ if isfield(data.results,'invstd') ymin = min([ymin min(invstd.residual)]); ymax = max([ymax max(data.results.invstd.fit_s)]); + if isfield(data.results.invstd,'uncert') + ymax = max([ymax max(data.results.invstd.uncert.interp_s(:))]); + end end if ymin>0 ymin = ymin*0.8; @@ -228,6 +284,9 @@ if isfield(data.results,'invstd') ymin = min([ymin min(invstd.residual)]); ymax = max([ymax max(data.results.invstd.fit_s)]); + if isfield(data.results.invstd,'uncert') + ymax = max([ymax max(data.results.invstd.uncert.interp_s(:))]); + end end switch logliny case 'y-axis -> lin' % log axes @@ -254,21 +313,12 @@ % legend if isfield(data.results,'invstd') - if isfield(data.results,'invstd') && isfield(data.results.invstd,'uncert') - lgdstr = {'uncert','signal','fit'}; - else - lgdstr = {'signal','fit'}; - end -% switch data.invstd.invtype -% case {'MUMO','NNLS'} -% otherwise -% end switch nmrproc.T1T2 case 'T1' - lgh = legend(ax,lgdstr,'Location','NorthWest',... + lgh = legend(ax,'Location','NorthWest',... 'Tag','fitlegend','FontSize',10); case 'T2' - lgh = legend(ax,lgdstr,'Location','NorthEast',... + lgh = legend(ax,'Location','NorthEast',... 'Tag','fitlegend','FontSize',10); end set(lgh,'TextColor',gui.myui.colors.panelFG); diff --git a/functions/inversion/estimateUncertainty.m b/functions/inversion/estimateUncertainty.m index f688d67..a4db939 100644 --- a/functions/inversion/estimateUncertainty.m +++ b/functions/inversion/estimateUncertainty.m @@ -7,18 +7,17 @@ % % Inputs: % invtype - string indicating the inversion method of the optimal -% fit ('NNLS' or 'MUMO') +% fit ('LU','NNLS' or 'MUMO') % invstd - struct holding inversion results of the optimal fit % iparam - struct holding original inversion settings % parameter - struct that holds settings: -% uncertMethod : which calculation method to use for +% uncert.Method : which calculation method to use for % 'MUMO' the options are 'thresh' and 'ci' for % 'NNLS' the options are 'RTD_var', 'Lambda', % 'RMS_bound' and 'RMS_free' -% uncertThresh : threshold for uncertainty search range -% uncertChi2 : stop criteria for the chi2 deviation -% uncertN : number of models to calculate -% uncertMax : total number of unsuccessful attempts +% uncert.Thresh : threshold for uncertainty search range +% uncert.N : number of models to calculate +% uncert.Max : total number of unsuccessful attempts % after which the calculation is stopped % % Outputs: @@ -52,17 +51,18 @@ if ~isempty(fig) gui = getappdata(fig,'gui'); else - % this routine will sill call 'displayStatusText' but then the output + % this routine will still call 'displayStatusText' but then the output % is displayed at the command line gui = 0; end % get the main parameters -uncertMethod = parameter.uncertMethod; -uncertChi2 = parameter.uncertChi2; -uncertThresh = parameter.uncertThresh; -uncertN = parameter.uncertN; -uncertMax = parameter.uncertMax; +uncertMethod = parameter.uncert.Method; +chi2_range = parameter.uncert.chi2_range; +mnorm_range = parameter.uncert.mnorm_range; +uncertThresh = parameter.uncert.Thresh; +uncertN = parameter.uncert.N; +uncertMax = parameter.uncert.Max; % original data that was fitted time = parameter.time; @@ -75,22 +75,148 @@ case 'T1' K0 = createKernelMatrix(10*time(end),invstd.T1T2me',... iparam.Tb,iparam.Td,'T1',iparam.T1IRfac); - + time0 = [time' 2*time(end) 5*time(end) 10*time(end)]; K0f = createKernelMatrix(time0,invstd.T1T2me',... iparam.Tb,iparam.Td,'T1',iparam.T1IRfac); case 'T2' K0 = createKernelMatrix(0,invstd.T1T2me',iparam.Tb,... iparam.Td,'T2',iparam.T1IRfac); - + time0 = [0 1e-6 time(1)/10 time(1)/5 time(1)/3 time(1)/2 time']; K0f = createKernelMatrix(time0,invstd.T1T2me',iparam.Tb,... iparam.Td,'T2',iparam.T1IRfac); end -% switch depending on inversion method -switch invtype - case 'MUMO' +%% there are four different methods implemented +switch uncertMethod + case 'RMS_free' + %% + % find uncertainty models by adding random noise (based on + % fit RMS) on the optimal fit to create new "raw data" and + % invert them with the original optimal inversion settings + + % initialize variables + TDIST = zeros(uncertN,numel(invstd.T1T2me)); + SINTERP = zeros(numel(time0),uncertN); + E0INTERP = zeros(uncertN,1); + TLGMINTERP = zeros(uncertN,1); + mnorm_all = zeros(uncertN,1); + rnorm_all = zeros(uncertN,1); + chi2_all = zeros(uncertN,1); + % calculate uncertainty models + for count = 1:uncertN + % the original fit + sig1 = invstd.fit_s; + % create some random noise based on original fit RMS + [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); + + % calculate solution + switch invtype + case 'LU' + invtmp = fitDataLUdecomp(time,signalN,iparam); + case 'MUMO' + invtmp = fitDataMultiModal(time,signalN,iparam); + case 'NNLS' + invtmp = fitDataLSQ(time,signalN,iparam); + end + % new signal + s0_interp = K0f*invtmp.T1T2f; + % save RTD + TDIST(count,:) = invtmp.T1T2f; + % save signal + SINTERP(:,count) = s0_interp; + % save E0 + E0INTERP(count,1) = invtmp.E0; + % save TLGM + TLGMINTERP(count,1) = invtmp.Tlgm; + mnorm_all(count,1) = invtmp.xn; + rnorm_all(count,1) = invtmp.rn; + chi2_all(count,1) = invtmp.chi2; + % status bar info + infostring = ['Calculating uncertainty models: ',... + num2str(count),' / ',num2str(uncertN)]; + displayStatusText(gui,infostring); + end + case 'RMS_bound' + %% + % find uncertainty models by adding random noise (based on + % fit RMS) on the optimal fit to create new "raw data" and + % invert them with the original optimal inversion settings + % select models based on chi2 and model norm bounds + + % counter + count = 0; + countm = 0; + + % initialize variables + TDIST = zeros(uncertN,numel(invstd.T1T2me)); + SINTERP = zeros(numel(time0),uncertN); + E0INTERP = zeros(uncertN,1); + TLGMINTERP = zeros(uncertN,1); + mnorm_all = zeros(uncertN,1); + rnorm_all = zeros(uncertN,1); + chi2_all = zeros(uncertN,1); + % calculate uncertainty models + while count < uncertN + % the original fit + sig1 = invstd.fit_s; + % create some random noise based on original fit RMS + [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); + % calculate solution + switch invtype + case 'LU' + invtmp = fitDataLUdecomp(time,signalN,iparam); + case 'MUMO' + invtmp = fitDataMultiModal(time,signalN,iparam); + case 'NNLS' + invtmp = fitDataLSQ(time,signalN,iparam); + end + % new signal + s0_interp = K0f*invtmp.T1T2f; + + % check if temporary chi2 and model norm are within the + % desired limits + if invtmp.chi2 >= chi2_range(1) && invtmp.chi2 <= chi2_range(2) && ... + invtmp.xn >= mnorm_range(1) && invtmp.xn <= mnorm_range(2) + % if YES then keep it + count = count + 1; + % save RTD + TDIST(count,:) = invtmp.T1T2f; + % save signal + SINTERP(:,count) = s0_interp; + % save E0 + E0INTERP(count,1) = invtmp.E0; + % save TLGM + TLGMINTERP(count,1) = invtmp.Tlgm; + mnorm_all(count,1) = invtmp.xn; + rnorm_all(count,1) = invtmp.rn; + chi2_all(count,1) = invtmp.chi2; + % status bar info + infostring = ['Calculating uncertainty models: ',... + num2str(count),' / ',num2str(uncertN)]; + displayStatusText(gui,infostring); + % reset max counter + countm = 0; + else + % as long as we did not find a model keep counting + if count < 1 + countm = countm + 1; + infostring = ['Trying to find uncertainty model: ',... + num2str(countm),' / ',num2str(uncertMax)]; + displayStatusText(gui,infostring); + end + end + % after to many unsuccessful attempts STOP + if countm > uncertMax + infostring = ['No uncertainty model found: ',... + num2str(countm),' / ',num2str(uncertMax)]; + displayStatusText(gui,infostring); + break; + end + end + otherwise % 'thresh' and 'ci' + %% % data needed from the optimal fit T = invstd.T; S = invstd.S; @@ -99,19 +225,24 @@ lb = invstd.lb; ub = invstd.ub; ci = invstd.ci; - - % kernel for the original fit needed for comparison of the uncertainty models + + % kernel for the original fit needed for comparison to the + % uncertainty models K = createKernelMatrix(time,invstd.T1T2me',iparam.Tb,iparam.Td,... iparam.T1T2,iparam.T1IRfac); - + % counter count = 0; countm = 0; - + % initialize variables TDIST = zeros(uncertN,numel(invstd.T1T2me)); SINTERP = zeros(numel(time0),uncertN); E0INTERP = zeros(uncertN,1); + TLGMINTERP = zeros(uncertN,1); + mnorm_all = zeros(uncertN,1); + rnorm_all = zeros(uncertN,1); + chi2_all = zeros(uncertN,1); % calculate uncertainty models while count < uncertN switch uncertMethod @@ -123,7 +254,7 @@ Ti = log(T).*rr(1:3:end); % do it on log-scale Si = S.*rr(2:3:end); Ei = E.*rr(3:3:end); - + xi = zeros(size(x)); xi(1:3:end) = Ti; xi(2:3:end) = Si; @@ -137,20 +268,21 @@ xi(3:3:end) = E; xi = xi+ci'.*rr; end - + % adjust for bounds if necessary xi(xiub) = lb(xi>ub); - + % temporary values Ti = exp(xi(1:3:end)); % transform back to lin-scale Si = xi(2:3:end); Ei = xi(3:3:end); - - % create a temporary distribution with the new parameters + + % create a temporary distribution with the new random RTD parameters TdistI = 0; for i = 1:numel(T) - tmp = 1./( Si(i)*sqrt(2*pi)).*exp(-((log(invstd.T1T2me') - log(Ti(i)))/ sqrt(2)/Si(i)).^2); + tmp = 1./( Si(i)*sqrt(2*pi)).*exp(-((log(invstd.T1T2me') -... + log(Ti(i)))/ sqrt(2)/Si(i)).^2); % scale to amplitude if sum(tmp)>0 tmp = (tmp/sum(tmp)) * Ei(i); @@ -161,7 +293,7 @@ % calculate temporary signal(s) s_interp = K*TdistI'; s0_interp = K0f*TdistI'; - + % get residuals and error measures if isfield(iparam,'W') % when signal gating was used the error estimates need to be adjusted @@ -169,9 +301,15 @@ else outI = getFitErrors(signal,s_interp,iparam.noise); end - - % check if the temporary chi2 is within the desired limit - if abs(1-outI.chi2/invstd.chi2) <= uncertChi2 + + chi2 = outI.chi2; + xn = norm(TdistI,2); + rn = norm(outI.residual,2); + + % check if the temporary chi2 and xn are within the desired + % limits + if chi2 >= chi2_range(1) && chi2 <= chi2_range(2) && ... + xn >= mnorm_range(1) && xn <= mnorm_range(2) % if YES then keep it count = count + 1; % save RTD @@ -180,6 +318,11 @@ SINTERP(:,count) = s0_interp; % save E0 E0INTERP(count,1) = K0*TdistI'; + % save TLGM + TLGMINTERP(count,1) = getTLogMean(invstd.T1T2me,TdistI); + mnorm_all(count,1) = xn; + rnorm_all(count,1) = rn; + chi2_all(count,1) = chi2; % status bar info infostring = ['Calculating uncertainty models: ',... num2str(count),' / ',num2str(uncertN)]; @@ -203,301 +346,38 @@ break; end end - - % output data - if sum(E0INTERP) > 0 - % E0 from uncertainy calculation - invstd.E0 = mean(E0INTERP); - % simple E0 confidence interval - invstd.ciE0 = 2*std(E0INTERP); - end - - % uncertainty calculation results - uncert.interp_t = time0(:); - uncert.interp_E0 = E0INTERP; - uncert.interp_f = TDIST; - uncert.interp_s = SINTERP; - - % uncertainty patch for fitted signal -> mean +-2*std - meantmp = mean(SINTERP,2); - stdtmp = std(SINTERP,0,2); - uncert.interp_s_min = meantmp-2*stdtmp; - uncert.interp_s_max = meantmp+2*stdtmp; - - % uncertainty patch for fitted RTD -> mean +-2*std - meantmp = mean(TDIST); - stdtmp = std(TDIST); - uncert.interp_f_min = meantmp-2*stdtmp; - uncert.interp_f_max = meantmp+2*stdtmp; - - invstd.uncert = uncert; - - case 'NNLS' - - % 'RTD_var' | 'Lambda' | 'RMS_bound' | 'RMS_free' - % uncertMethod = 'RMS_bound'; - - switch uncertMethod - case 'RTD_var' - % find uncertainty models by varying the optimal RTD bins - % individually - - % uncertN = 5; - % uncertThresh = 0.1; - % uncertChi2 = 0.05; - f_final = invstd.T1T2f; - - % initialize variables - % NOTE: we save 'uncertN' models for each RTD bin - TDIST = zeros(uncertN*numel(invstd.T1T2me),numel(invstd.T1T2me)); - SINTERP = zeros(numel(time0),uncertN*numel(invstd.T1T2me)); - E0INTERP = zeros(uncertN*numel(invstd.T1T2me),1); - % loop over all RTD bins - for i1 = 1:numel(f_final) - count = 0; - while count < uncertN - % start RTD is always the optimal one - x0 = f_final; - % global bounds - lb = zeros(size(x0)); - ub = max(f_final).*3.*ones(size(x0)); - % now draw a random value for the current RTD bin - a = 1-uncertThresh; - b = 1+uncertThresh; - rr = (b-a).*rand(1,1) + a; - % adjust the initial model and bounds accordingly - x0(i1) = f_final(i1)*rr; - lb(i1) = x0(i1); - ub(i1) = x0(i1); - - % save bounds for the LSQ inversion - iparam.bounds.lb = lb; - iparam.bounds.ub = ub; - iparam.bounds.f0 = x0; - - % calculate solution - invtmp = fitDataLSQ(time,signal,iparam); - s0_interp = K0f*invtmp.T1T2f; - - % check if the temporary chi2 and model norm are - % within the desired limits - if abs(1-invtmp.chi2/invstd.chi2) <= uncertChi2 && ... - abs(1-invtmp.xn/invstd.xn) <= uncertChi2/2 - % if YES then keep it - count = count + 1; - % save RTD - TDIST(i1*uncertN-(uncertN-count),:) = invtmp.T1T2f; - % save signal - SINTERP(:,i1*uncertN-(uncertN-count)) = s0_interp; - % save E0 - E0INTERP(i1*uncertN-(uncertN-count),1) = invtmp.E0; - % status bar info - infostring = ['Calculating uncertainty models: ',... - num2str(count),' / ',num2str(uncertN),... - ' for RTD bin: ',num2str(i1),' / ',num2str(numel(f_final))]; - displayStatusText(gui,infostring); - end - end - end - - case 'Lambda' - % find uncertainty models by varying the optimal - % regularization parameter lambda - - % set regularization to 'manual' just in case - iparam.regMethod = 'manual'; - - % lambda search range - a = log10(invstd.lambda_out/100); - b = log10(invstd.lambda_out*10); - - % counter - count = 0; - countm = 0; - - % initialize variables - TDIST = zeros(uncertN,numel(invstd.T1T2me)); - SINTERP = zeros(numel(time0),uncertN); - E0INTERP = zeros(uncertN,1); - % calculate uncertainty models - while count < uncertN - % draw a random lambda value - rr = (b-a).*rand(1,1) + a; - iparam.lambda = 10^(rr); - % calculate solution - invtmp = fitDataLSQ(time,signal,iparam); - s0_interp = K0f*invtmp.T1T2f; - - % check if temporary chi2 and model norm are within the - % desired limits - if abs(1-invtmp.chi2/invstd.chi2) <= uncertChi2 &&... - abs(1-invtmp.xn/invstd.xn) <= uncertChi2*10 - % if YES then keep it - count = count + 1; - % save RTD - TDIST(count,:) = invtmp.T1T2f; - % save signal - SINTERP(:,count) = s0_interp; - % save E0 - E0INTERP(count,1) = invtmp.E0; - % status bar info - infostring = ['Calculating uncertainty models: ',... - num2str(count),' / ',num2str(uncertN)]; - displayStatusText(gui,infostring); - % reset max counter - countm = 0; - else -% % update the lambda search range -% if invtmp.xn > invstd.xn % lambda was too small -% % new lower lambda search bound -% a = rr; -% end -% if invtmp.chi2 > invstd.chi2 % lambda was too big -% % new upper lambda search bound -% b = rr; -% end - % as long as we did not find a model keep counting - if count < 1 - countm = countm + 1; - infostring = ['Trying to find uncertainty model: ',... - num2str(countm),' / ',num2str(uncertMax)]; - displayStatusText(gui,infostring); - end - end - % after to many unsuccessful attempts STOP - if countm > uncertMax - infostring = ['No uncertainty model found: ',... - num2str(countm),' / ',num2str(uncertMax)]; - displayStatusText(gui,infostring); - break; - end - end - - case 'RMS_bound' - % find uncertainty models by adding random noise (based on - % fit RMS) on the optimal fit to create new "raw data" and - % invert them with the original optimal inversion settings - % select models based on chi2 and model norm bounds - - % set regularization to 'manual' just in case - iparam.regMethod = 'manual'; - - % counter - count = 0; - countm = 0; - - % initialize variables - TDIST = zeros(uncertN,numel(invstd.T1T2me)); - SINTERP = zeros(numel(time0),uncertN); - E0INTERP = zeros(uncertN,1); - % calculate uncertainty models - while count < uncertN - % the original fit - sig1 = invstd.fit_s; - % create some random noise based on original fit RMS - [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); - % calculate solution - invtmp = fitDataLSQ(time,signalN,iparam); - s0_interp = K0f*invtmp.T1T2f; - - % check if temporary chi2 and model norm are within the - % desired limits - if abs(1-invtmp.chi2/invstd.chi2) <= uncertChi2 &&... - abs(1-invtmp.xn/invstd.xn) <= uncertChi2*10 - % if YES then keep it - count = count + 1; - % save RTD - TDIST(count,:) = invtmp.T1T2f; - % save signal - SINTERP(:,count) = s0_interp; - % save E0 - E0INTERP(count,1) = invtmp.E0; - % status bar info - infostring = ['Calculating uncertainty models: ',... - num2str(count),' / ',num2str(uncertN)]; - displayStatusText(gui,infostring); - % reset max counter - countm = 0; - else - % as long as we did not find a model keep counting - if count < 1 - countm = countm + 1; - infostring = ['Trying to find uncertainty model: ',... - num2str(countm),' / ',num2str(uncertMax)]; - displayStatusText(gui,infostring); - end - end - % after to many unsuccessful attempts STOP - if countm > uncertMax - infostring = ['No uncertainty model found: ',... - num2str(countm),' / ',num2str(uncertMax)]; - displayStatusText(gui,infostring); - break; - end - end - - case 'RMS_free' - % find uncertainty models by adding random noise (based on - % fit RMS) on the optimal fit to create new "raw data" and - % invert them with the original optimal inversion settings - - % set regularization to 'manual' just in case - iparam.regMethod = 'manual'; - - % initialize variables - TDIST = zeros(uncertN,numel(invstd.T1T2me)); - SINTERP = zeros(numel(time0),uncertN); - E0INTERP = zeros(uncertN,1); - % calculate uncertainty models - for count = 1:uncertN - % the original fit - sig1 = invstd.fit_s; - % create some random noise based on original fit RMS - [signalN,~] = addNoiseToSignal(sig1,0,invstd.rms); - - % calculate solution - invtmp = fitDataLSQ(time,signalN,iparam); - s0_interp = K0f*invtmp.T1T2f; - % save RTD - TDIST(count,:) = invtmp.T1T2f; - % save signal - SINTERP(:,count) = s0_interp; - % save E0 - E0INTERP(count,1) = invtmp.E0; - % status bar info - infostring = ['Calculating uncertainty models: ',... - num2str(count),' / ',num2str(uncertN)]; - displayStatusText(gui,infostring); - end - end - - % output data - % simple E0 confidence interval - invstd.ciE0 = 2*std(E0INTERP); - - % uncertainty calculation results - uncert.interp_t = time0(:); - uncert.interp_E0 = E0INTERP; - uncert.interp_f = TDIST; - uncert.interp_s = SINTERP; - - % uncertainty patch for fitted signal - uncert.interp_s_min = min(SINTERP,[],2); - uncert.interp_s_max = max(SINTERP,[],2); - - % uncertainty patch for fitted RTD - uncert.interp_f_min = min(TDIST); - uncert.interp_f_max = max(TDIST); - - invstd.uncert = uncert; - - otherwise - % nothing to do - uncert = []; end -return +% output data +% simple E0 confidence interval +invstd.ciE0 = 2*std(E0INTERP); + +% mean E0 +uncert.E0 = [mean(E0INTERP) std(E0INTERP)]; +% mean TLGM +uncert.Tlgm = [mean(TLGMINTERP) std(TLGMINTERP)]; +% uncertainty calculation results +uncert.interp_t = time0(:); +uncert.interp_E0 = E0INTERP; +uncert.interp_Tlgm = TLGMINTERP; +uncert.mnorm_all = mnorm_all; +uncert.rnorm_all = rnorm_all; +uncert.chi2_all = chi2_all; +uncert.interp_f = TDIST; +uncert.interp_s = SINTERP; + +% uncertainty patch for fitted signal +uncert.interp_s_min = min(SINTERP,[],2); +uncert.interp_s_max = max(SINTERP,[],2); + +% uncertainty patch for fitted RTD +uncert.interp_f_min = min(TDIST); +uncert.interp_f_max = max(TDIST); + +invstd.uncert = uncert; + +end %------------- END OF CODE -------------- %% License: diff --git a/functions/inversion/fitDataLSQ.m b/functions/inversion/fitDataLSQ.m index 5f8f5c9..c72d6bc 100644 --- a/functions/inversion/fitDataLSQ.m +++ b/functions/inversion/fitDataLSQ.m @@ -150,8 +150,9 @@ case 'lsqlin' options = optimoptions('lsqlin'); options.Display = parameter.info; - options.OptimalityTolerance = 1e-18; - options.StepTolerance = 1e-18; + options.OptimalityTolerance = 1e-16; + options.StepTolerance = 1e-16; +% options.MaxIterations = 2000; if isfield(parameter,'bounds') [f,~,~,~,~,~] = lsqlin(KK,gg,[],[],[],[],... f0_lb,f0_ub,f0,options); @@ -219,6 +220,8 @@ fitdata.L = L; fitdata.xn = xn; fitdata.rn = rn; +fitdata.invtype = 'NNLS'; +fitdata.invparams = parameter; return diff --git a/functions/inversion/fitDataLUdecomp.m b/functions/inversion/fitDataLUdecomp.m index 579111d..701c78c 100644 --- a/functions/inversion/fitDataLUdecomp.m +++ b/functions/inversion/fitDataLUdecomp.m @@ -189,6 +189,8 @@ fitdata.L = L; fitdata.xn = xn; fitdata.rn = rn; +fitdata.invtype = 'LU'; +fitdata.invparams = parameter; return diff --git a/functions/inversion/fitDataMultiModal.m b/functions/inversion/fitDataMultiModal.m index 4027ebc..9588b77 100644 --- a/functions/inversion/fitDataMultiModal.m +++ b/functions/inversion/fitDataMultiModal.m @@ -1,4 +1,4 @@ -function [fitdata] = fitDataMultiModal(time,signal,parameter,nModes) +function [fitdata] = fitDataMultiModal(time,signal,parameter) %fitDataMultiModal is a control routine that uses either 'lsqnonlin' or %'fminsearchbnd' to fit NMR data with 'nModes' multi modal relaxation time %distributions (T1 or T2) @@ -10,6 +10,7 @@ % time - time vector % signal - NMR signal vector (no complex data allowed!) % parameter - struct that holds additional settings: +% nModes : No. of free distributions % T1T2 : flag between 'T1' or 'T2' inversion % T1IRfac : either '1' or '2' depending on T1 method % Tb : bulk relaxation time @@ -19,7 +20,6 @@ % principle % optim : 'on' or 'off' (Optimization Toolbox) % W : error weighting matrix (optional) -% nModes - No. of free distributions % % Outputs: % fitdata - struct that holds the inversion results: @@ -84,6 +84,7 @@ end % get the input parameters +nModes = parameter.nModes; % T1/T2 switch flag = parameter.T1T2; % T1 Sat/Inv Recovery factor @@ -123,12 +124,14 @@ x0(3*i) = invstd0.x(2*i-1); % lower bounds for T, sigma and E - lb(3*i-2) = log(1e-6);%log(invstd0.x(2*i)*0.8);%log(invstd0.x(2*i) - 10*invstd0.ci(2*i)); + %lb(3*i-2) = log(1e-6);%log(invstd0.x(2*i)*0.8);%log(invstd0.x(2*i) - 10*invstd0.ci(2*i)); + lb(3*i-2) = log(invstd0.x(2*i)/100);%log(invstd0.x(2*i) - 10*invstd0.ci(2*i)); lb(3*i-1) = 0.01; lb(3*i) = invstd0.x(2*i-1)*0.8;%invstd0.x(2*i-1) - 10*invstd0.ci(2*i-1); % upper bounds for T, sigma and E - ub(3*i-2) = log(10);%log(invstd0.x(2*i) + 50*invstd0.ci(2*i)); + %ub(3*i-2) = log(10);%log(invstd0.x(2*i) + 50*invstd0.ci(2*i)); + ub(3*i-2) = log(invstd0.x(2*i)*100);%log(invstd0.x(2*i) + 50*invstd0.ci(2*i)); ub(3*i-1) = 3.5; ub(3*i) = max(invstd0.E0)*1.1;%invstd0.x(2*i-1) + 50*invstd0.ci(2*i-1); end @@ -250,6 +253,11 @@ end E0 = K0*f'; +% model norm |L*x|_2 +xn = norm(f,2); +% residual norm |A*x-b|_2 +rn = norm(out.residual,2); + % output struct fitdata.fit_t = fit_t; fitdata.fit_s = fit_s; @@ -264,6 +272,8 @@ fitdata.lambda_out = 0; fitdata.rms = out.rms; fitdata.chi2 = out.chi2; +fitdata.xn = xn; +fitdata.rn = rn; fitdata.ci = ci; fitdata.T = T; fitdata.S = S; @@ -272,6 +282,8 @@ fitdata.lb = lb; fitdata.ub = ub; fitdata.output = output; +fitdata.invtype = 'MUMO'; +fitdata.invparams = parameter; return diff --git a/functions/inversion/getAAD.m b/functions/inversion/getAAD.m new file mode 100644 index 0000000..03788f5 --- /dev/null +++ b/functions/inversion/getAAD.m @@ -0,0 +1,102 @@ +function aad = getAAD(x,flag,dim) +%getAAD gets the average absolute deviation from the values in x +% +% Syntax: +% getAAD(x,flag) +% +% Inputs: +% x - values +% flag - '0' (mean) or '1' (median) +% dim - to calculate aad on +% +% Outputs: +% aad - average absolute deviation +% +% Example: +% aad = getAAD(TLGMvals,1) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also: +% Author: see AUTHORS.md +% email: see AUTHORS.md +% License: MIT License (at end) + +%------------- BEGIN CODE -------------- + +%% check for Statistics Toolbox +Mver = ver; +hasStatBox = false; +for i = 1:size(Mver,2) + if strfind(Mver(i).Name,'Statistics') + hasStatBox = true; + break + end +end + +% check flag +if nargin < 2 || isempty(flag) + flag = 0; +end + +% check dim +if nargin < 3 || isempty(dim) + % get dimension + dim = find(size(x)~=1,1); + if isempty(dim) + dim = 1; + end +end + +%% calculate AAD +if hasStatBox + % use Statistics Toolbox built-in function 'mad' + aad = mad(x,flag,dim); +else + % get rid of NaNs and Infs + x(isnan(x)) = []; + x(isinf(x)) = []; + if flag == 0 + % get AAD from mean + aad = mean(abs(x-mean(x,dim)),dim); + elseif flag == 1 + % get AAD from median + aad = median(abs(x-median(x,dim)),dim); + else + error('getAAD: flag must be 0 or 1'); + end +end + +return + +%------------- END OF CODE -------------- + +%% License: +% MIT License +% +% Copyright (c) 2024 Thomas Hiller +% +% Permission is hereby granted, free of charge, to any person obtaining a copy +% of this software and associated documentation files (the "Software"), to deal +% in the Software without restriction, including without limitation the rights +% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +% copies of the Software, and to permit persons to whom the Software is +% furnished to do so, subject to the following conditions: +% +% The above copyright notice and this permission notice shall be included in all +% copies or substantial portions of the Software. +% +% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +% SOFTWARE. \ No newline at end of file diff --git a/functions/inversion/getTLogMean.m b/functions/inversion/getTLogMean.m index dc772c5..8cec4a0 100644 --- a/functions/inversion/getTLogMean.m +++ b/functions/inversion/getTLogMean.m @@ -1,4 +1,4 @@ -function [TLGM,index] = getTLogMean(T,f) +function [TLGM,index] = getTLogMean(T,f,varargin) %getTLogMean calculates the T logmean value out of a relaxation time %distribution % @@ -33,16 +33,24 @@ %------------- BEGIN CODE -------------- %% calculate TLGM +% check input +if nargin > 2 + mask = varargin{1}; +else + mask = true(size(T)); +end + % make everything a column vector T = T(:); f = f(:); +mask = mask(:); % get TLGM -TLGM = 10.^(sum(f.*log10(T))./sum(f)); +TLGM = 10.^(sum(f(mask).*log10(T(mask)))./sum(f(mask))); % if desired get the closest T if nargout == 2 - index = find(abs(T-TLGM)==min(abs(T-TLGM))); + index = find(abs(T(mask)-TLGM)==min(abs(T(mask)-TLGM))); end return diff --git a/functions/inversion/runUncertaintyCalculation.m b/functions/inversion/runUncertaintyCalculation.m new file mode 100644 index 0000000..6ad6868 --- /dev/null +++ b/functions/inversion/runUncertaintyCalculation.m @@ -0,0 +1,115 @@ +function runUncertaintyCalculation +%runUncertaintyCalculation caluclates inverison statistics in some kind of +%bootstrapping manner +% +% Syntax: +% runUncertaintyCalculation +% +% Inputs: +% none +% +% Outputs: +% none +% +% Example: +% runUncertaintyCalculation +% +% Other m-files required: +% estimateUncertainty.m +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also: NUCLEUSinv +% Author: see AUTHORS.md +% email: see AUTHORS.md +% License: MIT License (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI handle and data +fig = findobj('Tag','INV'); +gui = getappdata(fig,'gui'); +data = getappdata(fig,'data'); +INVdata = getappdata(fig,'INVdata'); + +% id of the chosen NMR signal +id = get(gui.listbox_handles.signal,'Value'); + +if ~isempty(id) && ~isempty(INVdata) && isstruct(INVdata{id}) + % get original inversion data + INVdata0 = INVdata{id}; + invstd = INVdata0.results.invstd; % results from original inversion + invtype = INVdata0.invstd.invtype; + + % original fit parameter + iparam = invstd.invparams; + + % uncertainty parameter + uparam.id = id; + uparam.time = INVdata0.results.nmrproc.t; + uparam.signal = INVdata0.results.nmrproc.s; + % can be set when switching the inversion method + switch invtype + case {'LU','NNLS'} + uparam.uncert.Method = 'RMS_bound'; + case 'MUMO' + uparam.uncert.Method = 'RMS_free'; + end + uparam.uncert.Thresh = data.uncert.Thresh; + uparam.uncert.chi2_range = [0 100]; + uparam.uncert.mnorm_range = [0 1.5*invstd.xn]; + uparam.uncert.N = data.uncert.N; + uparam.uncert.Max = data.uncert.Max; + invstd = estimateUncertainty(invtype,invstd,iparam,uparam); + + % save updated inversion results + invstd.uncert.params = uparam; + data.results.invstd = invstd; + INVdata0.results.invstd = invstd; + + % update INVdata + INVdata{id} = INVdata0; + % update GUI data + setappdata(fig,'data',data); + % update GUI INVdata + setappdata(fig,'INVdata',INVdata); + + % update plots and INFO fields + updatePlotsSignal; + updatePlotsDistribution; + updateInfo(gui.plots.SignalPanel); +else + helpdlg('Cannot start calculation because there is no suitable data!',... + 'Perform inversion first.'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% MIT License +% +% Copyright (c) 2023 Thomas Hiller +% +% Permission is hereby granted, free of charge, to any person obtaining a copy +% of this software and associated documentation files (the "Software"), to deal +% in the Software without restriction, including without limitation the rights +% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +% copies of the Software, and to permit persons to whom the Software is +% furnished to do so, subject to the following conditions: +% +% The above copyright notice and this permission notice shall be included in all +% copies or substantial portions of the Software. +% +% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +% SOFTWARE. \ No newline at end of file diff --git a/nucleusinv_gui.png b/nucleusinv_gui.png index f773e1987692e94547085dbd38e63f0b67bc4353..39f22aafef14fb4420b98321505b4c55fd83fb5f 100644 GIT binary patch literal 129764 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 Iu{VDI1ERtboB#j- literal 124974 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 LMW$Tpb-@1vq)y9G diff --git a/nucleusmod_gui.png b/nucleusmod_gui.png index 024b3024f6feff1f66d410197b32427d2e29b4eb..d20828330f1eefe420d7e4e70a5272f3d052dbb7 100644 GIT binary patch literal 98228 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 literal 129420 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 diff --git a/uncertview_gui.png b/uncertview_gui.png new file mode 100644 index 0000000000000000000000000000000000000000..f55326addae4b0d60f66d6afd54f450b6a8cd262 GIT binary patch literal 89408 zcmb4r1yohr|0gPm%&d+ zD@*9XKbP#3B}LE*dq`KoH|Vd0<%QAEN`h~m>R$!l->{a_utP(`ZbJRN)Mk}!h=z8N zAuT4X>ZJ4Y4C@U+TkPh|GIe!zOLcW)=V8Od#qh}Z=ydA5c!rP}0-3 z8eHj@C3VJr6r$(7z4+*pG&Z^y)~y&CY@6$(ex!GuZ&Ba9DeC8Y>w^-%Ka&Lqu~zG+ zPd1m)_d>T1o%lW6&(8Cb*2c?g@?1UbHz!?x?P`^a4XF$bk-IwnvLY&X4c6-8PsXED zNO)p1*ZdKDp+ut(>&9}1|NCdNv(M!=*<5^)5_>PF8no&L9q~`n>@}f!0f5 z8g!*aOyk&{5-9tiV?N9Exx3}hPJ)8*h8l-SV^}Mx>2d=bH*u(}A`3fv;gbw2LFbRd z2j?fzNtL|=Z>boPP99p3q#r(SP)1H&3~}K{3)pl_YQ5{IdkpVk-e)=M#xstW_1u-$ zq7#J4?J+OjTK~P{Mv*h(g?^EG%Fv~0gqfC(p=2AV`pY=QofH&%oh0Jx& zJ8;U)bn9)0+7PVT)nbeZ{!)3n+_L%}tyEn}P6Mw7#>5iRR-Valg{?8~8Rl!o)Rk3# zk+)scP8Ov%fzMUFMU*M)d}|*3v*9`DbhhGeFth#Xt0t+JxON4 z>OGxOskzwoF`ukBJ>Iy`$~&;~IDs>!PovCjj7&ZEn;&orBE@_vs?ZgPTCx%P%e>CM ztOm^tBAzNFx0TqQC&~++vA>mB#hPfjtnxoUx#P|6Pi8S~VtH8}$~JoNK9D5C_-4vD zQk!-7Vq~+|vUc6+EUQRBu;d~SPv`8!QW-hIT32GYsys3`K7bH*9BRISgjn9$`4e8t zSRknXgsUyq%4ye>U%j_5ooz~9Dqp?v+I+1wcaZS$oT)R-<}&8vP-^=9)eN9w2 zE_Khs^~|v$Ao29#tl?s_NcST8LlCyY#inF^-y?PQOQo5^(tGxDOk$y<4wZt<$F zE9C(J7pJ}20X6q~l2RA&X9FB+?8~$KXdgsJ35x4{%rWq108%|@%iP%GPRFMrudlY{8~a-mH%7&dtFO*)_>Ol8#(2dZZ@1j zELZdMV&e5P=f(~^bt}mDs!qn9Z;YM{XxH@gOdkgvc}{$BKfPEckEea9s*n9`Fo#^Me12b^oi8IWF1VHEowJsa8ZH%?FPRiZ#Zvz3O{n^Winj zJkD{g3#+%HT)149$8)y#d|hN@ZZ%3mw2C)uBaXpwFX&L2t!5|Sa6eY&*BRC;kAdXQ z^s$VFBigf}E)3dVrBhBWQ`OEMu+@5VO=X5?a(R~K8t0nkI+gLG;Qy?0A^w#S%mN~^ zl6~~R+k9leuKZ$O_riW_u~Efym%E|f{u{}3?UCa{tKC|yn zocaOV-sCDmM~%1${uHWLYsKtO7&NpKV?c5F_kv{ptGOHD9Hk zK@b7iuV41%^M;BvcB7XRM^87#_eYXrezAIL+aE0BVDsQf>F|%>43QmXMK^3?ZCXiZ zY7t{GXHk74A}Hj!(b@GN7gIaK`V)_@LF}+#V3egNXGP!lE|0xyZ@+iERNpW*E9*Yz z%xPWiusSIqiCug4vBr6#xivm8qdu>)EGmLyJ?a32A8!jOHum4^3bzUin+?db`J98^ zU|Dv|dj9RSTx#?{RzUK6c15=ivnwiBK7ITd^4#+@t7zK2!rVq7GENUhj0yfzk`e}# zG2nBnyyx+`1>^_IYDl8q{W6H|!N*vd)eEA=zr(4yBMOv^k)_@bqOW5u8{84#QUuW^ zm@;M#n18PZFY7I6T>okma}kdJqp>w3y8pT2M-|nNQ2gI1{}C@M`wqhw1UY5M%j8&7gJui;in$U_rlc!YU#aJ zxfSIdqbb%4I!hLC!#R9%vFllXVP(Xg$n8zraK4YTG&+~z>ktmb>)*}1tOv#g1|5cU z$b1MRmzU26?`9jJY)37=p{G*MN?*S;LIRm3Ss59AtXB@@?u3;HOFuhV#kI7533exD z=N;JfET;?;h)+8x!@TRArDUy=mzE@qGU+^zq`_YlWlNQO?p{Zm$EMC4cdrdWV z$|iSN&xHFD%mp^1stKIDO0Du61XjXF8Z#e~>*T{}a`zrjidEaXsBMN%KYhV8H=?)D zLAW|=;{DcyiX<+;Pi^V)F|92E8dnm*EK;34!9iAP$ChlF=zqt5jzv$EOK)iWMK{1t z^QKyywvsEmfmY6F=TotwI|vBertOD6wF_P93R@ zl~CxX`k{xaipoLx&iLp-BY{kF#(5@Z2(6s(gBA&)sq44J*Sf9E>sS)E3puD?MCifB zci%HOqDDFY=Zszuo=jx<;z_j1RRq4%}m!!UxB2}MR zhB5S2jU&i5qhvd?H#);{k)e+2jKjEoD{9{m-H&dmY#1VtuN@R~!W^%+L^q_BQ;g75 zSDVVL4^F>nsp}|OWLNaeU{JxC!g7#A=VsCN2=BzSJYCxOBG`@9?oq~``4-7)7|o-m z?B9bZR}83Co#8NuvJ*%!MlA|Cjd!y>sreJWQux%@1Zk1h4Q-#DF=}wfQP72nZw#|Y zcLa4j*2{y0sFE?nPZ{-2ljG_)tu@M>*WQZX__LFAeDLtpjon>8(*p)qXkV?D$>sX! z%y0|0Is_Cv83o_di$d`Q^@X=DKGHOoK(nprEesU9CL)|JhhwG! zuY(*dw0_Yr4w|tSM)2Z1wTSllodXjc-H1@KGmYR+&EgF>_; zzth$NR`ZP*{#d0veydL4+%?dTm+ck95N*N3&Pr@-hp}=@J6yE~_!ARG3P#a;%k-P; z?FcCCpiB&bBo0&WPfI!YQwdHxdJscMiKjAg#PyLB*%={GJ51&_D_@Ld1O_c&B{@eN zs*SO?U#3)F=&Aea!GdtC=A*6l%H7<^#hDk_zSLvJbP1gtAA5~`mNN`tE~OKVwG!l9 z`af6Kw}468>~nI*mj}}F-5d}LgE?0Qc$gDYk zs7p~+mF_8+M!kPV%r31eE8s5TD9h~ba+_^!42>iGGn`%fGdB0s0v?hR`!tE$6!PVs z3sTd!&XxJ#0n{`BiwZn3cSLGpz)^X5)eMjdkJ<}N1f){_F1PUI4-Xl+S#<@?sy@p* znbvuKmGP=Et^rZqgR`(SlN=G{#C^1+)A8ih#KNdtEsA=1lkBW5+m9RXj`zmi{xBZp zy6ap4Wj$-P$W*=Zdi%!#A7j2(ZsIu6$op70y<)o5{7aV(%;j)Tz+`_}HRmG)iy^ao zAd!2^%)5eNW(^iHb;cy>uadiaH~m`(E{%9f@)0YgL|-1 z6$dO*brcaU-igp1n|jpKGM6=&n~*lQ+G5(cx2O$?isnDat-m^&^B!50EkZF?q5AJP zGBzS4lc!Z#KNT&`tYl+SK5;2-!P^r(2vL*8tMUg8cNw8-DqVr(2qxf?7i7pKCaxWl zkmFELlidvx^B?;&I51c-wj$QoGg$L(dwug^Fs{%aEFME#<)vbWE4X7EZj9kmmitKx zq?f+>vtIqqc>fY)lzjY}emx@x7X~gNB?9@Tv;vv6&7Bb~f)E#Drm`)}u%j3XcFp*< z{Gcb!=uJsNQy6CMepZX^ipmBSW%cl^Do44&L6k-+|M8r7f;{8v8O+kZc3YVT;eOlG z_gKc2kc^3XJWJf?Hf}n7bZV5sEoQ^EAMBx}X6ac`GV#(Pm(+YcNgE$NNVz=CLwyNkUBYs&NT`8mUuMnzI z4S@nYBTm9B_-s;av+wXQj8+e?3co;TsxxQUdI(oN(|{d_8KU2O$GcFzJ)F}iBPj0^ zhFQz$5p%Xu+x{dz#4H3M^PpiP=4I!twc2*4<2O+uql6>E=3V(pWJp{~5Zr&CG-C&% zr6ELDObTJoFQ4zrB0I_DO|=>0vZdV9V0`d;j?qm;MeL(X8QAe-Y(G>HifZPVg<%vjoLT! zfH9&9jKl{th!)P_D2;Uf@pnFO?)clkLOQau6dIWJHoNS|xMBF?@*Q@Q?yRfjE?Ept zSH}=Pq!+^_BCnfaDYl6BL?|ltG>VHCNl3Dp=l`frQyu&Jl8|bIpbzGH z`&vtlGS2x&i;ko)d&;?O~S4e~1`iPD|rls=p@`YKzx=eS6 zLi>ll$Fh?U6RW1a$PT=25WFJ+2}@U8$`15%V&A$m@2h?l$L!|LI7T@Qj1aqz-|@wC zP?g2S1o<@5Ab9-c)J*%c`1nbTk&zK@PR<-JtTq3Cea0PgxN@O?mJz+$^8J7sWwSo} z;WHD=F$_(@Vkmk`oN0l8=|*j%65a-eij@T{NAp+d3Vi|V6zg5OUnt_&AwZ2C-}pg9 zrJZXA`e-D~Gk#EF(5BjR&B{A9mGY$nFCU+p1}KCN|4)~ZgR$4sZg7h{PxW*C`@<(N zn6$q0*}SlT5zyL?oLs#ocxI(PJ)BOlezX2$3G9W{RBdP|u7C6dVt$LI^TyOn_65D@f;pa0g7pz{t5 z!Rwv`=aoLn&h_w!lqNQ4oTKxR+;`{0*$=_@`7$wAL(1oo+TZOGKorl3_xIGld-sl7 zGHCDMAh+~d1BSc1yI(S|y-ehTsf$k%3mV?C(JVRscW=c%mV5MuorN0KDKqYVk3}-m ziTcpDb`CuWJh>s*iJ#GvbLAeS{*GZe5r&?zk>TOtzP@6&BioneTvk*0X&4?@!-d)b z*XQKrV1m`GoCO0PoEeV&IxQK}BH=$j zobQTa)&lPUgs4r}T!I?GduaYyM8Dyc_Z`=RA$GYQe&>~(PAM}_f7=5r9Gv-{@sW`a zr+t0T0^#|9FwU(*?$jhCA1kbU?a9GGgR|b1+1c3}c(mUWc*(RAauEI%swcFe`H!vl6Pg4+Ui?i(IP zSkH>6g@}%r59cdgmA3ZY*x2X@r`w#U3irQsaj!t5#sTU6YcdPdjr#Q~#n8=W{n@b9 zt2YT}!pj(?YQ3j>1y7h9c6<0X6F5u<5D=^yp*Y}{>WF=xH*;ZSM5K-%L$wQaWR2k7 z5)%`b?i0Pjs#Cuz{nQ&U5kH28$}1{Va9>=oS2r|F*LD}_)VZ|y6Xf1L3rtvs=q`Co zIedPhsGL-hi0iT}=4fMJOEt5Y!U$Sf2POi^fA`+KcXH$cF8D|F_4R=0(5bY(U!7 z^QNPH&h>DjORU$_N}$)iQ5Mi-ZW`JsqAS4K;$$_;S0w&&BJE(1p_aFPh#bta_rCd2 zs1k_6TeIODLMw^k7dGCn=c&6ZZ8n3+lRKM(L74+dAwf_&Q_*n7d|nTfi}fvrG(YrO zQq>kj;-%GQvNi7gpi|A2E!xx2r=NVu^J+EKC2!>^?2injLGX(JHj6<-p!`<39j%#2 z33L^9D48MQ!L##s``zr8uGQJ?2w6U|P${CErf-$2l$4Ojl#5Nn9NP{JcJpETHSKu; zf|@}W{jv^r?kl(lbGBw6b@uBsJzUDjsQHP`NCwt#5qQEwFN_AgT6a40)gCcR1o(xl zNe)x>;@?9cZGEg3FJ9u z-Say~Q&T$kv-mkHJ!sLz8Zb|YswX;du?qkTNwAc6Hm53#P=`-5U@iHelh+Q-Rqu4 zef@@_(JEKXW$EatbL}#HK$oRfnr?RnCp)tYN&4^8EIPyYQXLhNh$^B8Lu+S>m-#MT z3E~5?n3iSL;%@TADM*?6y$sgXCySv~M@#V}BqT&EFQ0gv9tM(d1Jy`2`S?dx6svB% zUgKrMDVKF-O)w@2A|V+Gxh2Qp-Zwm&MK248Foy{UM*+;DNW*@Wo7sM)L! zcm+DZ*RO9a?(qB-MsE#A0+Xcg=)tD13cTjXYoPcS1TTfn_5Br95m4tFMoX;sPhUZ> z3$9_zz_;lzbX1A-qK*Qwq^w03NMTaG#q@T^W6PWT^lZ~p(K!!FZ;ZF9|H!`~xV7Vc za?l;iE{SkysH;nC*4#Z_FY??=C(m%x(uz+~ww?Xvi{ri`+7?XytMKyEaQZ77^(U73 zA_P>lf0FUL)EL3s!&{@&eICxiEL{%<@h84OL&^p?nClMLV&`thLO07Y!+H*{-lU5~ zARSRF6sgevis*iAQrH(y*E>HvL~ty3hkmo0dpdtt9j@PQC9&U{C%-t1eE8h5dNniH z{ii{9cXz{K3v0HF-Otg-&?u<#=RJ<~qRv|%JP$vB0j0|Xo<1I~h+@&s#l*$?U5Olw zeGX+F(ypruOMW=pDJ{o)!!&lw-@y=GnsZtG^2x;bz?)yiFs%$?Gm~!BOQjh`P`g~F zXu`h?(i(w0z1~;zePvV3Y*xZ}oFjCn#b^}N+|Q@|>5}D8Q!#_d66hf{_Ur0?hwrXj zqZj$wP+kuX`}F)|GmHOlMN+8RZdqZI5zR6-;?gt7E=TIdpEzXKES;@eXr?k@EY;O9 zyphpm3?^7wVwg~PwVzQAcPQ}tx=cEGX1k9moIxFnNLO!y0_ORV*WX^sSFNn+uM#?zx+czm3mobyk}vCFCdP6|-b@umJ# z=@o?Au)a+WJy^1)COBQ^%7naYHmc1}54Y{@?bnA3cFU0KBSq=L1_txXLKn`b;-O}o z6%)1r=W+9n^}F|(ybAl61qPaHFyDFzp3dSlfIMmUoWo0Y0;xey_TL|kYMKiF`s9RQ znD36-)-tkU`oR1kJo(fRIbNPikt{doV)@aYfCF(hVb{A_q(}JfPf5Q=`w&!J-1<=V z$64);b9cYdnR@i`Wt9e#?74JCFig>1F>ca!oK*YLcJbfuaHp=&LBII{^w4)JOVDlw z&ATB4YU8b&YugHTR*=Z<)oA!5xX%g%B3DG|PlbusF9oy!X(~z8w0MZV%+1O7fJ{zK ztrD>!6SRE%r*WY=ualV(O}WsGGRWgH1)ivr1%OY>l5eLTx6u97oTceIN}zhm$0ZqH z(YJXVe#Uej&5X=|0i~$^IF}KWP}aSk*?B^|Kjqjs#^)PC`w71lpP7WDWKDIob;5_e zUTggO9#e>D2u8>!@~RP79CEI#ujdsO3feCCF`guR1}~@H>tQ&Zd#@t57<2jWTet(r z89ciKBwS%RS$+RbXSP3P8d$}*DyQwa&d7)6=H_P>d?}6P<|A=&am8ioFzpW;eYST7 zYBMcZ$&}qHx5&-au7>jsM;kPHUB$nKLMoL@n9)|sCr!JEE<6Ns=PDW6l|Iq&^z`%v zbk+R3E5MrS>N>H?$Fg0G1;E3~eO(KG?=o&%jVytT&;H^}2}ElbmFvve2@;3wyQ$B!FGS?#4Ciq!fP3)8b23ZqxPd*_b*}*B=)xL(3)kokt7X zh|j-X-y7q?)q{QV8Z%_0jlaj(Y)tSh6d)ioOhNT+FkpnV#+iZsEkl~ZM3(szacV{AuhSstA(3wZ*U1FQS0EU$vIp=JHi zQfq6g?@c0rsXXRe16k|#2C@YAa~8Xz=f$43p2UZ8PdUw7d7fw)7XNG$Ja}w{^W)Z! zA3yMSqp9ouOhesbmthBf=@e+$T@>@?MBNNlpXBAsjo6`~00Wb9s6Bexw?93-h^i`J z6gOop#OPahC8bqN;s;nYk%Qc&7Pd1l{tYj#MI%rkU3yaf#Y3ywBT(mq%6Ffpz# zxqArv3LQ4$oS*+{$f_Me^v{5{B}V2*?!=>`>$VqGFlA+BMOQLhdw#r5ezqdX5NycTzRrlQ;`LF?C8E?>3y?76G1Ztt`5(O@92^`# zDIDzYQw9gP%FAQ9JIc(Dq-14fRaYO+wFHz7jpl2VS$j(w09O&1v7gv2eHZhXJT z=K0ogQc?mX=`LY^I#TDS)-QkR7_ssCi^iyR6&F{V{$iobFm5%(H)h_)b7qtFH#e-? zku`rlMX~?UC?uLUmyk$b@j{1f9N`#9J1kIYsr*!S{ZcAp9Uqm~+t*iWn;Q`Te|}%@ z340*xfE>@jywiXI@HtT2Qz)Lgf$lIGz+<0)DX*+)HJAgt528a9T<@?0fw<4w@%Zj7Q(c^MxroDVej3A;g@DV{Q z(??(Eq%xhh@?CZWroS8Zw>2^GXKiAS3hac~MiEe;s`x^&^l+5mS;N32QUm?!ukiwK zURqjOM65dbm^=M?PYG!5kt7Itl07d3qXcyWKytacxpl6;sHS09>-lrX(?gpvnG}d* zgwN%=US&czNM_a_f=82raf)74Ib4d=4AfL{72O7~4+2WKPc!jEGE+YOJ%0~A8F1cA z@gL@OMz(|OSR!CrbRDAK%pcSF_ zePOncfJclisfa&Vs&F6E@WH+Xldh`3ej3K%zJr0CGD*TXYe| ze6uW-S)!Lkyo8`7qnC_m|G|{&W=3tk^3A-of`<*~Io}ex<;qEh+}0_inSUVM587Xc zPcWYm($$*x+6T)R!4L%9Bw|s$%JT+HImBuq=-ewC8%g}mr5(cjoYQ;8Z z$NR&>>T2}&Q4@R1I3nXa&#P!Q;V=PFK0~aRN(&iexwY+`neXv=_bG&z-7=F`G!KG%zpDd&NrG-XtN{NfCv5BI}9#9tnhpr3DTn*1^DmuI9c zJ{c)M?@PdgZZw_t&LU@+h2*n~gHj4~WsDXI&W|^QR*7f^h5ZbuA#$o)xSq@SbMO82k@+~Iof&T&s`H;^y>lWCfE`KO20UW+W8D2f z{`p!c^YUM8Mh4(xFM$Bs3V`?N&i%s}*_~1IpPCy)5_hdC{nnQtFLk+w2DIB zpDx&E3@S?mMm?ZQ$I3cr8MR<9>gYu*Hf(suc9MU|mzuX%LBsMPkGqGbg4c~Pu9zeB zqGkufRO5|*ZTm;d1s6jJj;E^m?7KQX<&p>Tr4?V$IWwW<3dsjwfTUuzFdRV96hY|r zt@)%Z1^}~H*S{4A*JlO5BKMtsROXXYOzrDwg~L-JigpAgy(fPP4K zIwfzy2g<--^h3h+F2pqqjQafos~izt;~~(!aXVG-{!aFOL_qMD);l%!pI<Ql5dyNl1N`pP1Wng4Oe= z3ovGiOe(^t6pVZcN6jO8oDg@@m~%f70tW9C$l{J^fH-Cdp_=|^a6S3+k?>{$e-ON> zD0r!2_(m?UOl0!cb4UvnD#U`}vI>!$~dsZ>7?Uy3$9HWT>oDjDP^=X-suV{rNp< zq~e2(|4V!n93r%x!x6%Nru$pr&j9K?MSn{Berptnx;?>YbzL8+U{cHu{kN-opCPyFB{T=AvnT+!C^$k^I{gZrk41aN{)uK;DHlBJ+_m1GLTe5A0& zl0~<^HYdk)W1{MLkxs^w-v>(wv)zs2rC{k1wxlcrk_e9;zCIIK(q(F@N^ZFQ9C1=+N zde}i5{T?lL#C!$K2zZ}<(|a%gAB`c(8)s%_0LQATZ(-39_CO0^fl`*xle5OW4b<9k zNe+=;lh|ErSDzDkWN1qD{p?syepCK9JkR}ANj)h(@QuVu>A^vC9bcf3UjhsFxv z*hQ?8YKtt27bKIMo8#M)$_;DG>VPA(xSo_B(Jh9JLY?{0dX3ZAr3xKDo`3_Qm?(xi z%dDScEIvWVqqlR+j?4gxZFCGwM0us#Yp9*yY_)%@%?fXCzaU+lADc%*t8M{<@x zcz-c)pd!#x14 z8rn@zG)JiN+`r3y#IeKDJFJ%f z2yOw^X=G?915>VfYZp;hX-Is){^UtE=AGx>fN~ih9}fx&GRJOeYEm`&hX(C#VIGai zQK!RCb~~3=BNBqi?%j)JGs0v;ap_=b5-->+4FRO80@xdu-+Bh^w5Fs4w`KZl!_oEz zH~CS!q-xJ>bi?Ulbp76gPM~v~(J3Z_e##*sYEe;LQ4s&BKi-~hj=2r%J&3PafX&->SN!F*0$23gYQpfG4&Wef9@~Cq zy!&&sgqrulz+d_=*baoi6}n^GLJYtpwpqsUAI^BIs%_Aj=KS7td6F_t)80(O0&$7` zMI3$<;Ztk7DC6qNC-{=mYYv=1p>Bf$7MfsW>H*+%R2G3w1HAGSHP;0Jb4IUB_X7Q< zgQKGg310hNu;;0PVR1VMKL)=H!L4^V6uTQWo509^o6rOB>A7BZ=?`m3rk$7Xcw*=@NcCJ;J*9!-91$5zGwUY>X3mM*b*ZpKP%)dk|<;+z-Or*@NvowB?4xQK+ZgXwH)S-%- zlqSKS6=j{k*^{b<=;&Sm|IZAHw; zZZ-M|QKH9pL6v}`e0+_^k7~`MgI?S~AgzD-eS7uz!zWk6IdJQ25EwdM$Zd7@i;9Cp zxTY#pU)eP)%-={dVz4bx6%)WSpQm}s`S~=KPmJX&+4C1JYP`!u3-JaD?o*L`!Bsm z?dk_W13itFp4Oh>z0s28213o0*Mh{e-{W|1wRGu>{Cw*}CNvEMZReMISAJ`O3YZxc zP&}V9L1@*x>x|ryN!59L5U$#7=khN>RVQv4HL#lb0|2Do6n0E}9iy&dn9?k-ZHEt} z41OQCt1yQmTJt1Tyff@HDHUf*#`R{5?-lY|+^YB%QL!0OEQ)>~<@(c`rQS|eQJ4<5 z{&fFJ9+s?F6NQDA<^~un<#Vk&ouY+CgiCX#0hx{ zVm*paq$rZi|7g$_)c+ako|&PrIF}SU4rR=`g4?i~883KH63ofXeKAMWkU}wb0LYnr zLNF`^WJ1*SZ&sDn+T&0;(AkSndxLi_^^Em0BP)sFuuO@RyKKMP~@k9l@FcHDHvT@aU-5a|+;05In1cS@DTZ z5J{^W$ho|4C!5KF?!;It5`<`l2`EOb88B*S;(oWzznxP~l%Ag@C6NsxQpdB^eDhIF zC-)_!)kzjYE9H!vnNW7P5?38Ug1~;hW~Yn4zXcL>+-|b3$gn>7}gFmyIpMtU* zp|4aRIjau|Lf*MS<WTy7>8ngK!b%I&3 zn%BlcIr9EO=>S_GhUxt-nXHUYyyZ)CX+@9PYs*| zDqm|Bue4;;W>=$06r+W3;km|#oaO~$ui>=T!KCX`PG?28atUpDeC=g99+V*ec&TPE z^E$~+iNQ!o>9O{ML5+;WJ4w*odUfDI0|o9iSdeMiEYItm`PX=9+TR;!t)Q$7WtU+j zVZ}=9h$P7?7w#@%)Yxxy z`MK@q=_YbPgov)bPfk<3eD=EzfK=Ak)`&?+gf5PH=UM%) zQ+X2rQ9u^ez=0mESe^;}Egq^;n!jZIa6|3ESHua|8PVhF#3^Z)-qP&Qa}$m}=j|fu z=o~`RuFH$*sVO6K(IXdYpRzf3;%Xr+W6qp9yfdDrDIF$Dvll69c4x#=kL5X|x__i^ zaHNf|Wxjh@Zuwps1I9KDe)*Ye>P0hMHYV7*DrMG|3M2x7c>n%AN}i31xMe@Z=REu2SMY6dHxln3v0?aI5D zNOPTnkZddvCMcZ;@@Qt;g(=8q?L-?j0Z;<%5?IxjeAX8qrJ^Xzj1r_$TX{Zhi55~BZh&P2XEO6)jPm7Nx6m`6M!SvbDr7S_U(Nyrk*4CrF zilQQ%qtw(?AR7V~of5(9|3-qZnAQVY7X~JvtDM6WfF$s#-6J5W6`Yc$#{bkao3=Dv zRIeZ%89Si?43AUcPM(Cj3KmzbdbGg*xYY8FiePItO;l_K;4UudUh(Y+btCB?3os(HS6X=jSk z`e_qvbhXY?q#?g08JKd87Z3WXJkDIq&GQ%+q);=DQ*xf8Tk`@0o5oNvX=(1{vYOAA@Ei-s5Y zHx+_EhWNEP9qd~5e)BK?gvL~4JZ z(Z~m#BCWwaODpym-no_3jFw*kk&gl2>`TT?OM_w@{L7&{+aUZ(r>ORFpP$2_$_Y(r z`T%7r!CaODjC7_Dq+RP&0@f|;tId`0Zwn$T*lD0;nABoz1Cdj}_27l~D{1K`+_pHM zN5H`AGQ}0Bb1m4qsj6S_X=j(8*qFoBUbxi-OmOL#WPm*XzDX+Svrp6QJjJCTz?7Dy zn=X}$j3f7|d??i&GBd{U4OxEhLgcp)=6NyDP+)m~Ka*PELblxL;_RaTsHjlWiVdcV zMa?ik=6dc0b=l~=<|lc`kXB0w&?{LnbgdYe8D9zm=O4~}-p?Wi26(h`&v>M@v`FG| zyhy8ogEo*+%8TU9e*kAf53q%9)@%x@SzBMFE=AfS7)CgH3NRzFgP{-N0Ohb0JM5lv zRyiPvxqbrCE|>IPYU1Z-hIiSql+529T+WanxWSEOKSsqtX39A&*mKkW1UzGjaxenU%^^X$JC8o^9dfP-KxFXX8eNi88UUfd zqW~TgP*YP27C5-uqK%jw8{@HGQ&kJ`!v5cUlY75@4LUyf2r6{Zi;{1|s=g)`BuQAX z`qe8F@s0~S-ke5Qu)_<$D*c>m52b!_0<;$w05gE&8FQ|-)zr6aGl*{^Me4JUTi8Ih z!`1~wsP+11H7zCqpEB1re}a>RH>?XbI(gMGfGVpEjwb_;rO7$7i?qx%13KWhckho{ zeWMFuRfFVmLNK;p*hpBlS6Yz#vTEN0Mx)Tp_4Rnr7rSo@01!Jfqxba68yzhzxWC_~ zTi?m4vZ8|MVcNAAAhgt{rp_L2&ks}Vh~Xmy)^?jXK0L^MX7e<^8-0itc6i_+BVCBP z6QhgsvnQLySZK?vMqg2SZh+s%Iht-X1sxg_4u1IV1?>>wbk5V49%-530!g6vBv=HI z_{4;PA=!X7@0>jGVr}PV0kQ!{hf7SyWiwl!jzOh#xdwO10ekZW&a=+NW${ijh~(|1GFTv6zUrr zyK%+x58Zt(w2nf`mrQ>%-sz&@*T~&&Z%@`ZHht^A>$!gm&pgC$MIuO+`D1xf1(sI> zy~gm@ROur2O#d%P%%qBf#;gg@a%NT5Z?e{I?R2r$)W5}L7!K!Hc7`=BOS3iH{@Bp! zZ>^kH#G3xjjzzR_{>W1ucodiBGTk*J2U9iKDR+Lcp2cgdS6KL+?f|x6AiAF8(W4Yk zLOL9Y-&RSl@0*?%Cx8pVwfzK70L%p(avN8!VLz=0rohk(;Kqsq`4xsQ%fj%Rtp6;~Jj(dDnat@e{ zvfYv8BdQve-*M5Eiw3jM7#YAJ{a_q-9{*zMdGOlv0A&^g*1;s|qr)~K z1w5XR|Dpq>2c$0agyOG-c@G>{xELN`;aKlt{Eu@( zn*-ohv2sA^E_gTpX;%l<0O+Qpn05SB8sB?Q4QM+Hs%rg#8F zHW;JbJ0KxAn&oXSFLy>zm}m)m9z}aP|C)5v<#qx(T*^$JhS~7opeS<(Vp~wy3WZ>R zi9VQ2K<3K#CB|CBSpYEF09U5E@2_bg_hSy?KBy<4+|#PB#y8^HGw4U|W#GK@@mX#ojAQd(L` zNl6uuoOFYrv~;61NOvw;N?J-JCk>LKvckLo z_>9f|?|QzHiQ2%#dp~uI*L$J@kg6oEieojKGk~E0M5&~-^r(90HKyzX#ihaRRl;iN zrl!^ViVC$R!jGA#HquD#XAggtS+`7Jw{v9d1;3PEEq`28CDD$E_}ob-f#=(@gMder z2!(xrH7(Fc_;~*#EgeH(VPTD)6oZ8hj8*_}{dCfO_SS2ISWwmaa97fD~5_6<}8iG}B zj1Iz)opnr=uKe^i$2Ru~fkBerdctO^Vre8x+6O^1(k7~iO7nhq9YW)r-4}`JKn!Tt zqDGR@2(o|Cv`JH{n|NEKkmll5jl=fkcGa6^q;S7zaTmY^AA#kgD0&E-OmAg1>2d!f z%BX6)dcYm)>0Y)-gA$!X3pKimeJIj>*cZwKAA=j)p|UO5%Yd7&KBQplmj6!9-L!2$ zRyt&!xV^Y}@;UrqChB{gmCVJ~8QAqmt>znXMX8vfv0KB0eYBnj8;qEbC$vlBTrHTA z1+yy=^6VYMa&lN49zYLkltq{Zw7dh}S1k}a##_)U0-c&ioGDyZSlA9dA?wF^#Td1W z{Tfe$j`=oBkOT}zeh`&a$GYWl{oxQlVrSg?=KOJd{|rLP&W`)s(aRY~5?g9(waBOq zxUt$zV7$2diijP>IF=T@c;f_In#P!>GGJf2z47uhV(^Y-*@y_1?|Y%wlN~=HrCP9E zZEZnPcX2eTBd++4cz`yZ!1NP%eJS&FRhrLQk!pcLl)S zgp&h^O9h9%!}s^ifrUy-s>1}Pe^`BES}$Q;;c`@2vp9PofOU9ZP+l(Kv2UvSpy)yOzg(Mq=;OTSw7}q0 zME4w4x$ZUe-DCB=JmB}@K$Qx%;C&guR9>%Po1nBt6R!I-S0xGlRzROMb{F(xykcDU z5}sFexG0Q#@}~0(Fb=8u;e{4uv$o0aU2v?W3B8Vqi2)7ftmk%VzG}vgogFckt@xsl zTZo;0e+WkZxdTjA31%>nAvU{a#m8J(B{5>oTrARVzXxlqRke44Fusn7?D5eYpq7*# zJ%<^p)s@!>YX(;N*{+Vx4Gg@P7noN(H7{`cK1B>0XLE_4oJjScr$==9 z;qBtMIUgW41@Io(!a$VP{gRK5Z;{)E>L!*c!gj8x=))%~Sk$hmL@^$c018!b*lS== z*}zYqCzom5u;SQ%=$&gcK)1(y35saGrV5_9cip@<&WoWFmNtjU0>~P({MHp>qW#tDkIsw(Yfp3GDL#OO2}UEjB0qpdF&mOpZ)*X047SEU5c`+f%K+=gYBvi|6?I4`djsk zh(}~hQ=;gVX+^1;yX|O5l1@nII=NH7GB{U#fZWxf*`1gIa1TI12+o7}D1yH)DFAp} zl+Inqc0xJ!St3;*FR_e#tt;lsaLrz8wSk$l>0kka=^NI{D)>0`5-^u>s6FEy2}WNr z?~{99$vx1uTnZ~28D9yg1?KqO9H5?>7?Eeu3Q2!Ab)2IZx6wo~g8;Umis#_fBpwli z*X&UN$WLHz+Wb_OJ*4kn)qr6+_wjKqa1w9N@ZB_rx!41z1YUDUXAOqq+M&@;MY`f* z+^jO(7@$dnkf6i7Iqs+E0=rdkU9|vdnzB=uC63PBHJbnw3!^IbTO-~iS_2R7zosj-t8t`cxE4=0bFD+KBbKH1JCW;?VVO{~{&&+%& zA>%>pFg(eG2HGuuMNQJ72j(@`qEhSssZjQ;AbMB>r7K>u5V$r3D(*}R8g(vlAN^&) zk`z{Z-R4W&=dYv~nOP9{pysP&M$$YNMoq5DCF{DAhO}X;0jUY@OzJNrsy@XT8ABcxOQ*tKPUv_*%xjW%sTac}8 z#MdbxFBn24Xwg$Sd1x6BD#Y96z4YP;UGkog(A3=ADSh!43UWGz#5{ z??*T=V11a8RWzFs5bt0<3G20iS&-)}fVWuc@sq%39->R$LKeI~l8dBpws8`PYzUc1 zSRzUt`}jgyDs*|K5UWd@2}3Tz#Ul=OT-EpFxP41|5Qmc$gA z^aM+Ck8WLU!NGgN(LnYAiUxbM;}5_9TN}nBTOZS@ZCFj*|F9NSoc@`$Ry#_Q23M0B zYWxI(Unp%8`!&mn%&Vg=L;&8uZqc>VX?PGhwkWMbRswR-%pN={|lG@ zf2_wn-2e$r=fCG0^}#~WF*!obNV-GF_9P$^2NN{oZ8AzqHcfeXYaM~OMT;o#nsMD8 zhBkg@o;t+J|CFDhxBi^~r{#g-6haxPX2Du4Oo;h<5r6m{crL6hEOY^Rz$FPPR&8~( zR-|M@7JV--FAunczqG*sna~56$F@C?Ra)U?e~js@&?(W)!uf`&?CJ38VdgWLvG{>_ zCQ&;t(4ZlWx~|*c6F8q%p|8`CF?M;zCbl<2A+_6M{K|}bKC5}ZnG_k+5rYRHUILq8 zW!eoCwVf8#^!cb2OH0p%9E^=`Bb~AQ{QN+5@PWOfTuN0{)y0MX{3G8xers)O>$|-F zBDsb@$NY_8@J+ihwK-)v_lNiQ5~P%DsFX6qY4jN+Dkm5;baZ-#;bV+z_?50ad`x}- z?d9bBvB`{tkihwJUn#rK{hvyG)fA?op;>b=2Wk-Dt9^p;*4V$jy&br+)QIRlnhlVf z0^`Ie01k`~``>(wA>IGdlOxqpx+Kgbi*%#7t1h2E1%CE>NF)y2)G8U`VxWr${h8_$ z7lZz5thFxno-=%IshG`2ldN&5FakSmO;)4_glw=F#czFwTYWFV64aCu|807-HC{y5 zH-!QqBpn@{Ux$alCae1H-gB^HfzVy}t?;w~pY(qfrY>OXALpbm1QuB*m3bs!$CxOP9xw=yAk~xE%n%a$WIF zOj4F6+~Xw6Eu*P?TSy<1NM_rl00E)WyLah&AA!^t_{7M$3;+$X;W?PhUqpv(J2E#X z=CQvDEEGkK55VGT0TBT}xl;lPON@+@fNi-UUHS&TBTvl>0yEygl*l0AKpOc@hS>_P zjT?nz)OUYjqXAOsj6S^q0$jeVcQ?=(rxZn!6hld8Ax54|rn4Lkxw)xsrr0ne&_?yz$jy^5 zQ}_B|A3hEFlq%jcSl~JQ@*VXvm>>)^SpNgQ6WjO&@RY+dN*{cC-15@WosEsxSVTa{ zQvX3mOKTKOX(&TtVPpikd!OvoT`qHLk5BsUU7kqz?8^Jb2V*khyXUy&q2q6K@M;P3 zn7Z&~&M2^`F*lDnQY?m-LTEPce9)uA02KHB_FLsYvlVhhjB%^j=_Y7qX3%PiP(%&)E{{WS;70N~W6dEgx4hfB^e z^5N^ml|F@kV6`3Vwv6|$A9EGR##`bxW<_EGO1}b#RJ5z-+!KY0VRVd z<=O#aEHdbb2IDeF*i0E5d<&g`hyqClrA7FQ3!o|d)bO$v@rQcE|R`lf@l$*AiX&iyu>{2jpn5f*IHB+bSr%Zt&joSW_5iIoPlS3s;MER)`zL4Z%4nrWR`LaqB?bQFaQemen-^nDheXZ&+;imJx%>j0ONLPI5A3@}xR>^VsYk zTNB1_n{ou73`KjSdUD>tqPE9*_HjhISj~57sqvYm34VN#LW`dF_y46kVOPDp@b)}< zAwnrDTVQeUBn;PY9DxSjsN2tZ@aIAE&A$QWtlQ+uiGl3v9BruXB%cbcH$UG^l$OCb zpEooEeQlPiJuuhadkVy1QCBt=q=BV~6{+z2S+(mY41TVf%(pqNW2_Z8bx=-2^Yhhy zT>PY<FYXD@z%GgJUDM_b=tj9!b`^=)ZyzpttYsvn{r&3 zpY0|5F-LbeMf(B0;vrzWJB91cG|hB_lrEO?lkz=hRy{pE`;urKb$n%(r*$gfQp=^X zUDS7|#|G(g!K8WZ*l*H6nUG^ zz#7Eu}ct!dm~te zF`dF2%}(|&QOVdkhp9Ym^u1g=dJq6e5;Sc|$-ylinR<8cMLzrLt9<{I^QY^= zRFtz9#5x#g$yG`|C>Cm|fg%`(tP6s=mJrqFbg>lgo4(3v2yQ*+vcjmQC*{NQK25iF^9b$C#A{SLB3g@5ZKe=&tlKV3 zx-z}t_*B{lk3tgtLqhr;tR9AZm%0)CYgy@$;(DvMNo0RtZD=hpj8JfLs$QIW6&~d! zDtk1HX3U_lJaDXqvUzQ&>J%q0d6RIN8)BrT9qt}A+IZ7>9d9{qNmPwVso^yUj}Yj! zr1mAm!U8-XAt!anAqnE{Jv>pVaQkT_!y4%pAIdV0I8qE4E)#0lNI^AsP+3B+N%Q}P zfxPn(ROaDNua{Suv%xCV*IQ&&w1guctM{K2B7#n3Fk6bsQZLe)t3$tfYDFe8a3)ci z*yQ6e49m#GLR3lEvr<}FB_o2411;VP7ml#|dR>ww(9mV(uQfxdiH8vnW@Wz3-OnRD zY;%19f3{=_7)O*!wbHVa9Dok$nqn7Hj{o8&w}NvwE`QjKV(8A22Q2h<_ajLW=j|Vn z*+s0rK-CNs=H@kX%f_)U*}9M4(^^(N=G3ctVzf2;^sT|{hVk0mUJd3MwP>He%*i zwqH*+nL=lnr;}W9|Di`ARrg$t9Zna2^#FlNVbg|A2#VdW98W;oUEe;Aoe$5qcnm*f zXSpi>cUT5(14lq^R-9qXBr7MmL)J%%*`z;H%IA4TPTe71hMs6j)HH$*@QnC1gy^Rb zS-lU8o)P^{1;9&7t2e6seeH1`Ir#Y6WL%elu|;QEcy|MCo82>^^!r@9J{>`*HuU=^ z+edcS9zhW%=9Tg6_dL}1D|dw25NQ;iGT8V;BMa^#f>$pxC4LSktaQOyE#hImez|4i zrbmsN%rxQjm(546Tz)E-J|6ciWcA$C(DLkoKLy2DuJ7{=+RtFWds$d0eCx+Qi%7LK z7fcSxDh3ZmVE?d!b@f%1~=` zCyAUd=>;5_u4bbjsp{ohotOCxxqFX}j!u{AzXhJl%`YEV`;IwYSh^|Xr`PQWR$tSm zT<3Xa@YqiRFB27LE9TXC)0b4*_p!Ma~ByX8DE5)53Q8c^x#{SRz>DAp8d>^X7JVSpO}wi6G@?f^i>a)HU>A z^42f3Ayzk;kK^J;7aLd4MU^^XhrphHS}c(31wwV|b=xY9+?OzpZhs~LK+t!=eXieR zijzWo=Wfs;4Va%`bSeztDvx=$5k-X;=jBJT(blaGkiM85Ro&f5Lmb|S%!?>JN*0NaG3{Vv>hnsWw6t7Y+#BJg!27ad)a*z?zi~=KE>Uy z$P_L|;WKc_d<1$Dt!Qc?`%IzB0RuWqLC4saNs4Gr_o(W4(gd?o3`8?2mUi`oxGrK> ziW;+}Rad$NMm|%_(5`B^Jdd{0usg(1&Vmz|XOaEP=-8P5AZTS^k3N9K+WUd~;Jpt& zd4Vf2^1v`i%A8rVlwG;zd7=OLpAJGM?tEHDLj!G89Rq7NJnZI$HsLdQj^U)1#gBPN)BTAOG?vc=91Xjgm0&0Mw{5EvPN-9t(V0(elM~9 z6()%xVW)3$&QinjrCdfIS&ihs*^bgFIS;~o@lRuiM=GO&*hwph80Y~~HZA(HoVi|0 z8(8FfXiB1hC9k6nRV&8hH(Di%_FC-}m_c-MP%htb2@dAeyN=+x^9RARN%kBP&M#iT z%mDmR!f9lsSmzy_o2j!k)Oq}Pi&`FY9rsVl1tWoMC>`0W>#6^2z)@4*V*omrWMxT3 znHo2_LO@*sOewi9QXLk09d1)*T)ZYOH(FT>5P0C%Z9$a6!}QahJCoS>k1Va5@hWP3 z(uLgmY=zNen*ebrQIq&XixH=#w4UITDIk0Q)$DPwMhUu_Yyi}uIb%DPDLDJBd=+Xo z>G_yQzS?z1zcCUxlm>1pi%4Z(FEfniDR(6P7v+)6S8k{Vn%`Op;q+G^IIiO;8-Z{I z$yL3&8PABM4?N@oL*+$6j8_ z-KqDy9H2{MG3-s5Crl85!YgzqOil5HYAQ`gYYD9Xos`gi42V{bLv&OLw7 zuAX!E-D=4?AF&qG>{`QH*-#fvQe<(E^1K7xPV;*4fiMrv z!|+i=X*!DTg(Tm%7A<_8IHm1uEhkHNeXPrKPzC*D|mj_$6rv?fb*$?fva- zBdF)|;%?N&q;vcW3%(Y#dI6oiy^|jOC|Zu<($VX^bWnsBJ1SN#)tzNlPrK}TEXFb% z;@2s4^RzaA9$~;!AlM+q;AJhsL7S1fHaK$Ygg=rBxvd=*+fWNGcXun;ZxSPRz7yNo z3^#bYcHuN1>;>hwqR0U>k`l7hiD;W|;TujFBJP)Qj=aLl0d%n#k*o^?Gp8E#9BQ*JCSk+O_Y-~*y<41CiavP^z;s`3&R*h0x7^{mSR|V;1muML3pAz_3Q- zz%G8e@c|T-wFE#_oG(-{-+PzpiIT&w1c_~h`NA!Bf+zTCqaU2zi%othDrZN(B?7@0 zE2Kw@i<#``j^NY+GKpoG>KUZcwa7k*fv~Q)urP~Ti;-YFXmCK=1Uy4g=MAE7r0%ig z*IJ4nL0l^_+ZId|`vYwd5G zqWgy+OPDK{pkT%p&(4c#J=R_rL^G7OZlw;^F`e7CQ2wv@hj@??B(@JkAW?`Niu*4m zZ`hyh4RNefd6-GBc$?DZ%monPvN5<1%hQu)sl|#^-WFP^pa5*2PDT!mW-aONl z!8lT9dKF4}i^^;94VHGfQN-t!D2Yhbu3nHGLVUYoZ#0b(<$)r$xZ(j?KFa*TiM99| z;ZN^W8lz9ssQf)*&;PiuI{Z*OBYF+Lhg=a}{sC zfPR=ss!H1fIUd31O( znzLiqU&9vUduXm86is~DLaXzFA7sz^Am;uJ&CJLEc29r2p?-b4mIOZ(2T6|yiVmz` zE$u(NUT1HK!AI#Etf!YbS79}aDwi9!&EAg}ktDHCCIF7}hxuUqQKu=!d_mw0La}X? zs2pPC@6E1r;3_-;5p&z)|E4VL52c9|UMDt2*ihIWJOi2vz@Qw9cO!$tz@d}Dz8fKG zY`-qg)Ztc+`vV8BUsSs8(#CHu9FBQb)CT@Yg^{Rv!}M>kp9 zw}3(w$>w-74ihwrk@i~aWArA4IguU;OZj?nTzu+5IJ}~|b*l|q7Fai+xkjyV5Buq3 zz;JBDumD$U$Om$d!_3>Xp5Qy5o}NZV60Gh;TG`lqHSS-HZ%ru6JAK8a$s) z+s8w;fB^fH;^$!fHb}f#o)1sq<4L`^>qcaotoQ|_erRdQs`3l_UU&oQh$jO@7c_RjxPrzNH`E?x`-}w9W!3`Zx;rr-85l$2_uQ)k_ z-M*`tOs#acSN9<-J>OP1nRcWr#R6*birZL>piG7srP7YvZV!r*WO}fa^cPGk}PzIUT-k^_;;bu7%|B`E-i!z1n%( zU99PXYEjA37o?nR9$G+7pvzsP`35`X-IT!B-&w)59p-wb_Esx;g1#4jdT70rwB!{V zGII9(0=)j5j8fT7(fc-^f8VJK!wso{ZXpm5PmAeKBNr!07R`T~C9tCIK~&fyZntBi zN70owxqeIu7&89pUBiCOEWgnErv7^Z71wzn`ARoM=vg*tl5U)@^hd4fH{r%)@6_6R zR34-Nt;K0;0`eeNEf4kpRMtSh#dDZ|;=17XhFn?fIvyUpXz21F>C)c{eSu9>9Hxi|#ZJ$n$A5%b+jLyK{E zMk9&j^wRreIq*H!1|$%TZO3j3+`YgU!m0}*$iis9eej1w*jGP)udb~PwrhQr@#mXs zW)Gq(*fn{0=g&{=5K=%6{Uu3v<&=}5l<@Fyo9U`=6Z&>yuTGuq?0$lVSyQ%o6hSk( za%mqHYCC`Y{4M*fMVG@!$@PE*dw$Pjf>ixn3H5;cb}1}FU-+K(JG*q5+nj+Q-cMai zK&XDczju7X5rHT09c;cLSyNqP?Hk-VG9uyoTY^rioK32>4-q3X9_!hE={$g$x+Zka zIZ3YT9(gnM-^RI}ioX&O;dPIT93LP51Q+i1>qQqWrxVw;Tm5#;h#Qc?^=#y^(}hxdggiy(Gf@iv7euKlzrLhn>i_L7_TwD}vsMk|rHtl4_^Jp2!a&t&;n-5)j22ft7J^gIWx2L!^&d)L~bLHi!g~)Pnzk$H>~z;>1~Q=Vf-F90+4G`gS=` z4e4|%QkvUiwB@4El|w09#3zp-zIso(vJ2^M+*b>9r2n=oD5|A+UoTeOkAX9F#S_)a z%4*{$vS|Q)l;HmA?7-$rZ2q2nM&R489|*m?`SQ_q;ZSnhX6ms#`l{2YOWkykGzZ>X zc3{&_>%u!I%j{B$h;5qB~| zyLDxuVHndLdy!R*+`PA9br{G?>~e*MX~6st;FAjhtH06b&vmIwG|WECH6g+IvJbVj zhMb%sD=VkZQ!#35JF53EyNxaCF6rF17zmB6cRMfTUCJ?F0z zj*`~a+B)TL`}=4QFsB@PH5S08yHak%V^P$PTyj+hjlZ}pWB=#-U~ z23R`@NLKL+>)v3D`fhF6&Wz#PRacq|-Trv)x-{+eYikL50y!bbfY9PoFOYh$k!@+> z<&>30rq@Bd&pQH;4bnq{x2JNnbsli$!0#Qi*=wkU0=z}ZeQ6_W5FGLrQcZhsguKe+ ztxZqQ&cN77zW-ciZ?6)Rb204P4Fr!jjZ*`)fM4IU6JKqI=B{?g(oPwd8NAX>V^rC} z|Atc?VMvQqo4l0(q7smztcHO#db8)FH2`4Xx?&o6M#BY2Z4!9qL6^S)^)9%yjQhy-JcH@(}?G@JP8f6Q~l|(UG&< z`VxVCdc{-yu2f!GSy{Nx9HtBqSOu{KoPzn)HI1Ldd1M z3c%!gU8Qu<-vromG(cEiRAi#mVYeD>bFdw|wn$1!3Q+pLT-N>e@n?T$PH4llw6t<$ z?;p(j{HtHG2ZeE79?N%|ROk$Z$;c`KNv-nj_HpTpyS$HTW4fdA%byU?^YZb{%=;W4 z!=tp5@4++zb0#iCsX*}acTX}^x+MP_H-7Cq$FkPuV$T==G2Vah!1MU~(^B-q^GaoeP1%awSdi(Js5mZd^L~Ztje@67Fb#fJEo>ikAUT9+HqLy z7pOnfdUBn=3sXisl zap+c{*jYBWgn2|_O}nmF+JWfu!rr$-;x6o%PXNGdqH(p!#8B0YPCM=l0qw1?iG zOL%~BwjmZt+1v*X_f`6U9`fVZ%!3+}tRQsk@+r{(yO_&CVx zj@8Q5Ev*%D7i4!CiVBDDfIRTJ#RV=5^G6Ea>59C7grDTrU8+6|!2a0!?3+3K?}&%W zN-Yx85g5Qb7TRw!pcSTw&T9V}$mvmThOd`?j{uYD=XybgFT<@Z&XclW)&&_e$MT~x z%!JsFXP?|$PJI!7B(`X7^B@NwcilC!LxLkfW_K^6E`q9P!7b-Spa)};+m{^4F$K-` z*K2VF*EFnlkwLwMHfNxFcVhkzfgT(jtTpBg^t`2|5I~fR=z0)WjcqDb5-|q`sI8H{ z@bgb3=P|l8@lVhc{h*t7N-aec`^dO|$si(H%iN#lUo+-Fj*lcsuBwCXSx<1x5(ClS z9pKab3`U2P8#H8Zy$DC_07W|x!&@Z%*;7bPR9>0pvqT?KhWISnH0oBQsk;$CN~@fY zeUS{*b+3?lKrvYVbg%d9P6T=X3AznW*cz(jDiI4pl*+Sycs%pSaF18PQSt!Jeniqq<>rk|Z@ zP^@B89lTDt8)=Kph_vK$N5_%30(_oe% zyH!GApR3#faBFKj*EwdF6p5+=*K6{a+5b# zYg8X!*IRLTgiLZKjZ-O`EcYUIzI#{{cpxdHThpI8_}V zYiwPa{KHOu+u5YnWvjNg8utAlhnveVG)&gSgt6=DixK+e3^f?;0>-_ZAe)ux zwj(MR6d26;P$oowtyNrwMj^mk;AbS=GpdC3URPZYo**303%_Ya&gLMZh~*=)Ta4S< zVXPHNvSXjx&#V;+Sx?WY@pCav4~om0!3}N+gAA7XxFXzL>!d1XX~4Mx1WBjmOBL5I zYK0g72M%g*@CJK+p#aUHDJB>fAIxPzJ)GfR9Q*{z7+2b1m>{iRT+yFLUTJ{ieJ89E z5L9g3~WvZZA_=-m0^5 zaIzxC>BD5WrhI2r_vd|8L0=6HuFTwK;4E;t-6 zN&WO2Rr--v8Tyrcp6}ZmZYq&5ty^eQp16f4BS}5{P_+Kz6wU|47n}^6@NIi^AuUtS zmu^mXV-K`P*}RZ!L9F%XdLlnxhyVniZ*IO(HEwoSN01oLe!cX7&LbXVUd0OpDp~?c zWbu22*fVsgbRH50;z8I*E!6m92)#BKv)#P&;vqp&a9aYcunE%9TR#(WX%t6VuAXx# zH+Cj_St$@2#w1qI1ndwqawg{+wmEw%CgLV3yIz(3cJqkBC_V%y-&cw%vf3xmkx-d% z=3Nf*bgRS6?_)fg)4E(g-qNYEL1?Mor=DX1D1+XUcN2LL25zzxa|z+Sb4td64IxD& zq2cMH^vrW|t7*!-+RvvD#ZH%uZH4=>7xrc!Jy^lHg+)O9n&LzZmqX|8x4lJ8E$Xn0 zj)A(2OiXJ&65K+W>wU{=(^NAe7;SJM&Dv`m7%rh#D>eG#6Do)#X=rUV9;9~#FTyo~A?u@K`z8@t=Q ztd2(~fUS=f4iuCc{Z)ud}%rHHJ7^JH;-dYl~lfgLJO7&(ZwShOcYu%W0 z3<&R=o53#}riD}c__rCyOUF|9Eo3y;3%kVRUuy(1{}xbK^27zNtzPNtAeFz^YNaB;sO7~M1-B$gY*+cb^gD|TG27TvFJo8%A`k@x=D-GF0GtR3VG1NF zUvjd7-n4pY<5{BJLh$f!*g%|yB}4N*XBN=TMktx#*|Ahp@JOCgcY{;*td0KE^Twj& zL~LgMm+1=CH)s{_ixmh8J+SGd$`Xy8&az#r9k-d-o_E}8k8v!Vt7<6$1K%B8v;-US zz3X+Pu!Ou#Srb0lm8C>QIrMgZ;kFurS9a#Ynz+ z2XHWAUWpgn1nCj2002tkl{Pf|5G7h=H`n-zZ#ZW*ps9Hs(r0`~$~;eRMR}i`n7)cc znw3mNXFf!wuq%zdytF9O%G|iT;oFlW*y{ir{w<;U3>i`;sH@Dq=T}n(6}CB&p5nL z5so8-#YFY!4PN}i3z^=9i}u?<84XYu;vY`IRl%xX`WemO3iEq>Ol2HEHFZ}T(2{6R zCTlGDip2PQM0uCd_b!f=-;;{KYo^M1%wP!S3-DNhr_rHu>f@`X)3td2q9Ni|ZRun^$7F|~;ve%HD-BxXD7r|O-(iU4yG z%=?jP(L)fH77ep^tTwIXeZ|#70iGZ+D7k({XiTBTUi#CXdWQIMn8!TXuLVjl&@=jL zbc6XbFmSm;;}|hFH5C#T820d^l-YT0L%4)|9mxKuwGI9Yd?I!X-e`GsQQ}1Ee_+4& zoL;^v&?x_)J740Q@b-m$A0%? z%dzN5wE14#rM%(XZvwfW2(L;Y2khaWk}6!G9Nuq!eN7CvdH=fk zyuh^UgOh;Y{t~Aj1jSFpDP-+R0-DmDWwES`mYMUz?@DK_L0zqe5@3Aq2EoCG^1KQyI+aQ&w z_1s^AH38b*WQgB;ILH9FXQiicFJbc~SY-F&cESrzCC^zQ1J?lE$HaH&rq@WDx_&dr ze=O{*3PO%^mdOVx9{x_!y>+2klfFtH!;I|+Wz zdJlsCwDLN%KdoFY`Ex00;9(I!m0DU#mLZ$3Osa|&Kg2mRaOZu4;<~NPv-WDgLY(lI)1^qCLkbnc?d2o)?HL)x?Q; zHeU%8Ti937SW}6^v;Y@xg?VG|$On{|cC0fnkb_a;5gHu7x^h_{wH4NNV!*z#my^2o z&n#CcWpvT?dY0)hm$(g#{EN6?%=(VS{cD|=%j!&yAl8X!o9l*R?YDaZY(hkrxH1lW zc}gBb_9h^Ab+u1gRZH&4nZ{c$G_txjv$a#2GJyTr~7}8N$gqygEW7u*F!5fj2~Go z8(nlJH}C})^;S=R@*9K%Z9ILmACqilEBHhw$+O~BA+S#{0Ig0suy){5^R;@w!GvLz zR0jyDOH~{Uoo`dGOTQE;KhxN}^ww(l@)k^AV-+{uk&G|3xUckR=4(1Ju+n)A=(RQ(2s>KQq8b3ZiyL-dKlLvzj z1WOlR^S7<4*iky)@NAK9qx}3_q?)i1ygh8AKn%W@B{+L1FCs+VyWJ8AO3}+38LSVt z@%l@y3psB9_YHE~!KjtV+AH~IN9 zMUx}ueMCsey1Yd>9$NiS9{F+Tuvaizgb#wVhwX}P>$GnE9#v=Mc z-Zik@+$n0y3{*m-6=u|Aj!pf22YL!65ZZ%l&)?i_vR>xrI-K?$iy_y<2)@N$()h;X zhwAdBhsmGXA;&E5R_4wB2{33yBZnA>G`%`=)r#EnmE`fzsE5!j2@9Y44x^{=+6#1V~7E@xK6w4*;tH_8uUloNsW-XMYUD z(qIBpvKq+V4N4ho;S~2)Q7vVIvD99U6cvh-~Jq(iv)hpuL zd|*`;F`K6pKAHQ%@bdljtQ#*1W1Lhhgs8>Tl?EQTutq0*t*-P|Kl&O*xi|?&3@SqQ zR;{17&c0`MTfr1(Hz83h4FO{Aw*@X>JT&F+`oil)E6(He*v6Yh**XJr*I?&K7yUvOfL|^!UBgCoVHTCNDOJ9LoCa-p68^9x(~Z z_-xKw2?-jHxAf#>1;~_))ngQ)y6Rf?@;W7`ek?`RSFx9VI9d=CXq$KBziN&|Nj z`=5+Gz9yjM%hYBJ0;);FXNW(A>uZu zfBmPeO%j~R^71|W!N8?i$pliLNB|Lrs0&+gpS-D``V{crcC9p%UjVsGbcZIw%9=*r z=uYZu=cBv>VkrE82dBRck&AbFnkolpv5P1?ji0dKi}tWAP(h9YNYit27}a4L(O*eY z-3jZhcT;m-qWjfFRdcx6Z~gg07G+HiL1vQZ9G|S7e~qlv8_MLP#DHfoTM547!qDz< z2qa=>KeSZ!gJvO63{9(-z!?LK1-^H9Zsh+9Pqgi%K$`;50xs5bnbx79A<*XhmkaH` z(viD>?;JQvcTIHpZKxIxBqZew;*P?JIVZ}lGk>y7)xV&jlrZwH5kT(zE!JOmrG@%EcqDRCHRd@G@w9pb`0rzPg|2sck`jUTJRb}1JJGY2tB z_;w=kg-~$F74KoD45EO8i{)W>X_^mvWn>u`w_ce@TmVMDSsaf?wE7{6wcZx0z zSkFA*5z$^6vrLy8H7`zcKi_5h+F6;7$xwbbEs@u%hC`SF5~}6yewpH-?1SLEbh-Um z^CHtsmNF#;hnb1+>wD)X{qN@6mZK)haPU0)Ou?p;nrf1tc*cJF#Rx7)j9IMd9H+SH z>3(a!UTMXXW__AYsj@wd%FVePs_V_zvIimQKbXuO$*v;sdy57S!o(Mrn;CcHjP7`U zl6@5QGcJ}>T!9dOiP8swAn*DUAo5NZlmOv*>rWM}zgyhjXL$S&60qN&sUW_=qxZSc z)kUAA1k+~isC6wb*+V%U0g1hy?`&X*|~OFbpt^a7&{E(~@WSY*Xe_9yf|`TsebAu1)2;^~y@doX4@ z@`q960n=geeGU3W+Nh>_a$B*QH6f|r;&DteQ;54!FQx?AurYFjps}ZGEd-B)RUSJ( z>Og!`K#(|agtQib;F^p-4E1`VOuO?y^Og=zxyHmy=)S0n1U4Ia9Atca9@5Y+2$-9M zM^eME>yPFB>X>jZVdNY^#5Nw#vzRHz*oZK$jqo>9zs2*KtuF&~P>lJu0PpArmBrb^ zTIz9Cx&)Avpb+zanch$X1z!Nxx{sXlO=s!c{g>S)a2v9nA-xIb4L7ciZLZ8puk>^l z$tX}7HbRB@vCNMV<8@2jaJKp4nX=pCs4um5Q!_^jjEp#5MPKj z*Z6{%`@#$Oy=cq5&bTjKSu>BybxJm@EFHv(WsVZLL68iXvD$+qP~VdMZ2}xBcd`x_ zYNh;~q}#u}6T}ugO!grUe(kDp-zl}J&2H`A0{qbn7_`6gk<^}N`ou^g)burc2msE^nl-k$xFy77)>Q_!yvR|Iloq~w1sfK z8`K?h%(o|%wK;U0bm?tdnmO(y@pCYvov z6N>S@Iz2=RKu-hj($)TV)~kxcvzD0qO5V?|dXA77sI%0P5_=kv-dCFD^>e;668aez zB}hLWVhpzACuF6K6BX4Q`X zbz^aDE!m*+E^u+C-FtqGT*?PnG@9IgCgRUsCC2=H#5`4yWOW^zR1^KIB#ihl`KSSRi0NPPuxg*E1v{|{SzBDiYy9Z}Z1kG4TZaWC){e*iw=wO7C) zT{ONyB}~u#3Xc@v>$i-)7GJF3m$7Q->B@0Rso1mV z6aoy=L(My&XOylwnza=Yl-1OEDw*#wI^=*{95-c!&i)-0{vTB)7$g*qFL}k1B4Ix= zz_|d`75w!p`eoj705<7MpzH&IIi}jBda{Gp8)Hb-XNN$)N)lo*kI;tN5IYaVz(1do za>JNRvwR3;>6t^!583O}zMh);c#eRWu5sfg%bIzXk-8-oAkK^wvA?4WwLh*!Ah?X0 zb;-KBGdsAbhNh4M9O@OIg^z{_->74OYO4ffP69`6J?KLQxLcb|`$+!Cl2QJ(;Rowo zgW&r4J;u8Cx*+=qcnfdeo4{L87R%O3! zfrgGhIGEJ{*BkS>uBMN(2qdM&y^B&2iEpor2XDR(aLi?h%E z_CC+O_wgSeV)4Gem^tPcH`-j@r=E(x$HOz+*XI*F&(4OqGbL5g%2nbE_|GI+Zv#r| zKTX|()azKTCS(trz&4t$BvCGF1G=;e`d`NtK3NI3A9-);}H-sdtZ| z`ieMGTINK`xKlc1JGdIFkHlIJfrCQ_lX`mgb?s(nvy2w4ZoWTlto z&{lwKW=b;>4^$d;Yhdl6&&~rN?^7UHn23{-gV&#{9oic4$qS#~e+z`Z0J;OLkd}Ks zpXH{3yYfMM*NIkzE9J@v%!rT36?tnC!x*n-`ULuLwfc*LHu%tG+#csgiy`xpgGJI*9v zGrsE*$#1J2adOxJ_&t~%?7%;r@P3u9IvmM4U2?^dTmM?=<|pT*sWmVFHM?xGNH>s^ zc=bf*Xmhc=)dP#g*fVpciBi^o?P|)EoH5~)o_=)qw4G%IY6uzq9;485rU;?&HL3jd zgBZ1$WbfuE{B+c2^+Yrj$ zm$TU}35P=iP>utVwb|=h`FiVNq78RSagYcaA=i=hR||O4)SyLAK!U{PF%n78$`+a? zLslp0;dYJ93*^akbknH9#;>s-ANY`*F)GW2He3+cO^j(6c1XcTr-2fM7_?pK+RkMn z+^xcOvnLSZOC5oz1t60A07o5$8fuVd>`mU-rtMjv1KA|eZ$GzazaF7YkOJm(@c?R# zD-JKHH!7(+dOK>7qA=YaY|iap-VYpPh9Zgvep(u@7~jt0%ZA|x^-254Nf7sv!h?Ru zE_zH6_2R|T9YQRsq#uZ@pW?ft9#JJD&^$8rRtqBi)4Rwtkz0O=uMLJB2rMTbBUS{0 zc^xKlOHLM=u?-1wPQw%aovuzg521`rtcU(FGeB2f26N_**2@?5_yaC_8rN4)j3iZ3 zji?o4p&jJ>JrVUM+6mNi35Urpvm`Wjt2N7cb+z;xt8vZ+rAK^1BI43@&0ivgmh|5D z6PO15$UQrZ*3V^IW7pI!~%Wf@MP8YiiSdqJK7lK z4DuF&_YJhdTtXWN%M>@s6P$%{K}my~F#(l>E9FB7Qcf=~plS9jcAq5d#`25Lb|i#W zvs=Zio}3LRXs$1;?qvrd%&~nBxvv!M-8r)dE7#BFN0CWyyRFuuDXSfq>MzncIjh(d1+i!64= zh2u#&oBB%^Nr_YW?aq?OqLJ@qf>N1uwE1=u@qUL&gFj;|%fu5>fO#wJ+ytMjgR|2n zC$b_1!Mo&sKVVI+ z4=q~5jxK|ipgUh;8$}Z$&Z*m@6}M z)nxEj(NLXm3X+MF!mZtO!R=B9zlj&rm-SA89(Kwr9KLcwqwotC7VSUFAHO>5E0?wO z@cUMY&3fehFh4Vxyr-tOLM#0;ZY?j8<8f?_`0(gTjDjIfX?BrRvY^_>0t{9Cqny%` zZ;a5sc+FlAwE1_zG^R$J&YF>fg zEYM}5rtO~gD@Sz(*W1Q=Vz%+(LU{;U@4x~?9g*eEB>DaXBK@?liC7GF#YJPZTgRfo`UFq4ZMrPh1hsItR2+^SFkyubqg7UNOQdrm9Jmz?}P9Z4!l(}$spdTII zt60cu9z$+pLj6<29N%o+tq7l$mx-X!bD}rlELTH(@#g1+^|yR6-e?K}AbKuAs&v=P ztA2g;u*J{~p{~rsWY}v$$^)7sRx$acMq2vUE=fD=m*YQTc-C1!S@$(f=**`R_Dw#i zp4K1jPM!L?YBG^2Ga!wY2vcl*bI%#l$NtYfdF*+MVKqsg`hOMTKLu5*wZijnE{7N8 zBN&y?MlEk!iV!3Zre>`G_a?X(TfRbfpQVp_zfh0TB8Dc+zp~>Z6egkHc35z0du$+Mgw~i;zNpCFj1V{#z<=SVS z-$D?4AOsQXCXXXJpQAr$HXeub#>91`sI3`DJvz)_FtJmg<1Nxi(>fE+=rmzoI z)-~FMb7GzPNL}{E*Z*=_)R z0Zh)hRv8;W3zMGk@xDrgheLsfnOX$6zlSo%pnD;H17<<_ka)iL0@2ij{{6?;i+W5D=-4yn;kP#)*IJh-&E}hWPLBEu*P1ZwavC z!;&lL{7rEw{Ca=S=5d#;$U*=$H?sYwElvEN{g$Ia%&z08a+S{|BSZ>=*MN@z?wr&Z z%*Inej}MbE9)Y~m8X#v4X&C-@?Z4+z{ptUyayZ63drgxMybfi#iKO)VNwfZ z0Oa*-ZF>f^TsG16({ip0#tiY-9JYo#wB#jw-F8*Y&KOWD8tQShhVuacvsll?HPb`> zN9O0E-QBWmoB7ml?V&Iz{U;*R25T5Il1a987sD<@>CbuhZhIW>PZ)nV&A;CH02rgS zOKop5oAEl#Cq{X1h94XL2nd@i0W4N&5OAdy;aBK)cxNRp6?) zTEOxkhRW66a=Dc>WgUtoYsCviIf{&%7U4mB z4hhYJHPkeio{k3a-2+T&ue0;9v~-BM)bJl{a}E#xZ0o$8n}Fe99vD2nC4}d3ME!OL zCJg@~ee*QnbH;$i_|Km|PZ^3|KY07$%j=}18JU?$rvSF>U2$y^(-+i1(@5B2G{9fX zBh-hjhfA`fnvcb#WLiBde`Ib~Bi9WjUpY!5^!Y(*Y4>s&0}CC(i|EB~-|pn{N=Drp zDmH(O(d?MG8qH%Mj1 z_IH2YRx1*N95d>+c9qSvh=FzdRK#*k&9T*i51L+KQ1KPvn2abo4kL!YA5OzUor@|( z_7&c9YDLA#>wWh*H<`cO9S$byLJD7HP#n6ULr#*cE*8^D(?m zqM@r?4~*O276XJB(p`Ok%o3gKkBFQ_yuKSyu;76)5bZ=>^9b@z1AL#!IO-(JZevw{ zVNHTiukSAzj0Nc+>Hgl_%z*zn{%iiOw_^wvAoKoEjMmrBqQ>y)9j4c||1-Tl#c4aA z5lD6*&V;Em@P0GWU`EERj5G`>Yin1-*@FhhRAfrPu!7IIM;(~Ns#cc*6Dom(C2@U? z6^_ne%CG@C(%pViIa8RDeig<|Gb>9pRJmV8$N;kx1LIR&&Y^{`;(wURp8s`&rYk);YMHH2I>L0 z31xtm=(f>7AW?ge)-0$!Z}&NW$Rl{Vd!Qg%UGi_LO6( zDUFxxX#(1Uo}(D33T%8wX>GrA(EKT5ahbfnog8HiD$?v+z}=y#sRk5C3(Q)s$U zyMWwlscFlbZmDN6c8c%tS6+#et}uVm6c)iPLdX&^Dh6IJqHz`|3E17AjyT|6ZQ_gi4CgAsb3M};pokA@8c*fE5{ue&-MbH921)(r02R4lS*DDqPwGz&)9 z+zW~!1x;VlZcJZu<`i$Q7ioJY`rhzExs0Uqz-15f&~WR`IdW&Z0qHUm-)=>U23@wT z$0oQ#*dx99x9F$qE`0eBDTC0m;p3f^G#Fk1o@?SgaMwxC5xkbvok-JFy84DI6|#Nm9L~$)E!3WeG~od- zvxoUEsju#38g7WEft9!f!h<{K>hBN(CC-!w`W3I4%oT;ASXmd!$-+?G%f7k{KqUqh zKi5qb_$jHIm>*wx-oXza;hO;huE4vwJoFLs39m5zzu_$ZZUyLbU*Wb*L7|ji-Gg!0 zcY@EJRWpQ!02JX~%x4V$g(kCiiJ9^qu(tK`E3XbxACK{Ll935zm=*K?!LMHJslg4Asj%w=FQh2Ry*<-+|&I`x_vK#^|07f>e_E9T=d2^!u^mrg!;w(d%wS znVAy8=H?(6@o3=*WwrG2zd1=G>5?Bz3x7V^AM+BA?N-N{Vc1KL;MU+@lm&s`;6bMz z2thq&MEO-R?GhgU({;K>-$91X3aX%hyCx?kl_k!n_+z9;iVy5h9*f3$*mW|p%!~{h zJXz3;opuM3VSheL{Spx>Aw{xg4Pey=F<(V)ULoy`0>f5^r7`K1y=IpP>m|?8?&knt z7UEAQSnM27uX`{_Vk{xt^qO$uoEpRgZ(p?_*T%#uCRf~hND_dh5Q?U9{ARd(dEmb4 zKc0xaAzZjn!Fl}}R7U9J2a#7xXl+#&FMA5;wZ(^u6fVMmFu@?QU^UhY(`~z`ZHbTTR&jBJU>*Eg# z3R0@qVxGdJ1yMV^%tU(pQ!@+!{{>~txJ$roX3nQa^Z-zZrcH1y$jA@}e{F50lCS5( zAjV-eHqzalgj;%HF%v4&lX1ZJ5Xoj%fK(=T`dBqLdS>x^S% z>OCS-?Yn8s2Cnp2(&xCIuA5|7@J5ErFD-q<`CL)W6~^deu?B$^fcituJ$jim2G#8M_Gq@TH2n`tG;n(9A$C%(ann{Y!ePwoSv<0Z1vJO@c?xF#!V7`k`I10*bWh zxWFDh!>M>5}*I77O%xHwvFv#XJ(Qwzi`^znF; zA5cYplv|4Wfig|6<>ZCX%&t@`N(Xf$Re6WFi1-TBHe5Fh8-VJS#v<5jr~RD`VAI&r z2|c1C&~(>66+i@cU3W?n!Z~0-Rup{U(8+mT8lKTQB%af13@(n%(B0de0A~gc;V94- zOUVMp?FCSLNyk-<_(^kbqgNgTGe}^8Gw`xG)2(ns%El+ zAM3srIH4Ru&rhl?5z?9;C{97{Jk=0@;ilSjP-MR3Y{j;|a}CE;>(bbbhJk?06LU(Dm-R&&WSuvSHq z6$wfz(lI+*&HUx6arU+E$zE*n^sy#E(1^nVC9A<8wpTDF=7yPthPccruUtgd>`Rt& z^0>Vj&COW&r&WJ@)+ce$`APgJdfjE7WuyaBgY~)XT3gXPHM}3);hOd`!RWMOAM~X} z^w)i>okNMgREh)iqLH#_0;tmz*v;!StxWNKv}5UsVd*IE;|AS#C&y^aY2Zp-b6pk$ z9Y3GzgL=ap%`RREFykNl*>TL7_R5qh)Ftgi_RTP)+ z@bSg=4E(aCY*0*2m>4Udu9i+JCSfhQH1(AJa;JLK3`*SHCe7P>)!qMX!Jrt4A*$Wk zY8je%xTRIXxM&XAM=KIA4OYM&d-&TC{hz;SfIONQF<$I_a{F&i|@U6kGK4l){|oDRUQ@oZ99!VM+R-)J~OZyonGBd4W!$t5$4r<9IWXN zU9L(f#}bAQA`2(MIf1_1%0(HzcP%hl>V6W#gzvh&3Y!nABIPpty+e{uo)l^;j?`R> zV{s2@4AS-jWd|6=dqiA-UHK(n;h1}ja&sUnvkOSnbU&yfP21wz9MpFTda4T1BV0C7 zfjf($03v}|$h1dsJf__#puIIeTr8;=9HMJuXNwUAb#MYf%N!dTB?Dvh3ncFAyHaKL zDq5(J{~*+zMD6=z(@htENh|@*cLh(~z*Y<)>~~KX9hj~h?(P;6)(8VpJD{fL zn$b|jg(fg(R zm-cKGFZu-IaSSl8e!k4T8g;FLe0olv$zEPDqG+KP$-Qqa;dC^z@m#Y&Y8(ecq!82wbpeWggZ8+or#Nk;=r{sqNE#;N=3zMavGS#V?E(R)F0}uGd4azdC#yBRD6@`Ze-AK{x zyob+@EpJYYzFFs&Cm2f4L(HCb8fc~W6o0m}`l}iT?XVfk>u3pv5C7hJCmd21SnPZH z?@%a55ReY#-=QOx296r@7f-b+pV|Z0GSD|;rc=S$U!(WSoI?Ht+o21IR*7L*;Nxv8 zkko>>t|-#MQJD?*IYdI&xU4-^JNS2Rz13~aC;{iQ(=p}2^e%rAghk=_G?PwIpKzN}?D_ckwz(#ir@k#*oXq3(k)f(3p27#Wo}+mB0XzJppb$Zy;62v~#oX|&(#Cf^Z-*?@Rg2U8 zA`#Di(o|}ZS^jkRq8Zd|j^aR$Cm9-^%z0pLn zn5ZaD_H%a&RV(9~Kn=#!Dez|e%C|sfAZVig4FA{-e&E|D-^vNAk$c}){^?F5tqZ!! z_6x2WHaVLG`O-36*dL#$AzFplfoq(NxivBtrW%Vq%$QE+ElfmHGx!Tz)Hit|wuItV$40a{}sOW3&+O(G1%@GRU z@L{}C^xPa!6dQ;D@3y@%YHHiv&4uP0Rr(*#;~p;@92yFsd>9dUOtLmT%!VlyAO+OO zm%k1$r}yO}GFxBHo`bVER%aIbRp{AwAc|2qJD0+Bw=;R`8?JDL&r3hE9=CgmPyBCZ zeoH={7^Q^n-~BQ`9#wbgd;N3GWGrs>CI{@?=C%_IQ>PkdDRWw1T8##?)|81HUywBq zJYP=~J&%a_z_7ka^WrKmHj3sO8`}_v+V@Y?GJGoyUq#{&4B^B2rGrKuz5UbK=*pOba!hC+HYhUb{}7 z)m8z%^~?*j#y8uhAS^mxozAxcg{4l;XbnkI9e23J-+|QL5?nC>DG|Z5Z}0p}>}%DZ zmu~*?A|W}BK~U8aZ5+6jBY1`1HfCaX^PZ6}Kefu}Yg*q_ zr*vjA+vHaN*@oBW<)1TFY9zTN@_#BcR2F)2lRY+8&8H8Uk?{~;p#16m0?Xhm8RHD{ ztXSjl_o*IFj&a+p((vp;OmyvC)%XXRW6dqM{yNBvX zp)tOtOC+rnn&UOAYL)9Ys(K%>9!gHlPVnIjZ!7@RL21>@3w8461V+Zs8SQX?R_jcY zAJ!7{n_c2ga=v5Nfy#bjT*X^t#MI@vvcaZI{TiJXEDdOC*Nf7>jh0BB?v*mmHt($g zw(DrZ@E#z2z5(QIk573SwnjyRo*Kxt5;UB7&L-Qz2^<65(J-Y#`=}9UUQ}7RxJ-GYe{l80=xB_WqMwF3Rx2A^iY0X~HP2*<$S~c-GBx+3a zj+c97B?dUM?+#SD>(SmwS|{P=X@rb3*~|lCem^J2=u7W{$I0%hjPL;|h5^*=p7JMh z3x}u_7zDH;S3X^g50S|$32vsD3I-?v_t7+WKEk-Zxw#om42#RA#oOxBAG9iQeGyk(gea+oJWepc8dlHj0nv4p1bzr^!rai!X_&zfSgimnSm9< zWHL_o+2XIet;-T^DAU3gIhwPVfSQ}lldG36dl+(Xa>{FPUZ@nav*}6_W@2K3Y#H}k zY$hnZ@y`<>FYx*>z#a-#k3EX#J5#V3Ez{FJ;Y?=GuTc_w=s?F`)pHjr#&$P=6;tq}KcLbB=ay`7zT<^#+XRxld=d>BHf zBpiP(G7~g5R5EfhGCZy22@r!w{qskGtQ|0kgstd8PF6BhqLG=Njx?YNPZWlv2QkwXke=Qm#FPog~WhRYoBK3CUcbht8@(KLzAPkBJ zLV5E= zrR%0}J7m~!b9CK1axwGiIT13K67J{<$;)4CCo;~yrBTwkmwU`t_f0oOdg9DN`4B1$Oz$0%bj(-n^8Q|b;CDyZ%|Nvczo%h7238u81L+$ z50KCq9lqgB9P~9eclpZ47b2p(l9Q2K?+>(ge`>7kNOxpaF0tIg4aH1YS_Ov2VuWs#-W`osHiE4SqWTXQHlB1cyN#Ws$ zlk$c8`3T;%F1o|Y5$1fXUO`7Whi;PMRS4?Q*@CFW6x)@+*M^dx}}$>dLC(mn)|S%9tT#~#8VcK&4Eh2XU&sq^?_(*XcL=-bidJzaMV*yaxQ1Y z;OW52OkWks%kZvdVZ}J_=avF;BO)E4jvtwwN|kLJKN{L19VE$OQCGvBwyubf*zWA_ghSSmW*|7DZnWeKTaHQ{OIF8`>Rpqe(FIQHVw(x zCpN_M`Yt>*We4~oX6p0s#9y)CMT!*$cjjQ)-(9sZ^@yo^!rsc!E2E?I%Rf6IFE=s8 z=lQ}w0Vu^|p5dH4b0nzTnK26woj*by{9!O8NYNY-Kv4hZ#}gwL4F3L^pkI0EU%rj? zhY+^^e=PqWp0{wgXm6ZqjjtbGB7iIaYuR5WE{5La{3`)78EV%}=V*avzewPB-gv)T z#QK7d=8)g4QMw%kz*^GUyFc0TXJ`Uol(ya*M_UWiZ4d#79N#dqTIEhJ{^KwA7333| zFqK@IjGP=r3Y=nt;9*WA?pArO(++k^SBWA(6+g;`|w!lUkfteUf)tk~sT5SEpufvOn%xFTo`hRCJ)s zyb;7O`-#N=J6-t)1^I)f%;BEvWI zvFaqo{KWB38Ck(0`(!H9V~M0Tecz|Rcg?M`LWGscaB@KH`KQ6bT+h3UxJIfe=P=!x z)5wKD7}j0&iIBId4LM;}sYps?)OA~%i+khJ$Y5?i*-vaufc4K}QuZ$A& z6F0c+U*+d(pD-UGXQ%q0rfGl{0Vk`gcM|Q;crghvZa<(YpC$z?Nav~b^{cV_OBgRd zW?!=#IAb{OIrK#2IXO=6(=1kzwxsCW<)f&kN@2rA>S*c*aB<0@QT`03* zuG%ad&|1ql{wODF$6O#{f19~Dx0Nh+ce5~wQ(zFuMks^sXA_5nE=`Ew#Mkkd*LvuH%sKgXYiOX^Q#`#VQ|cibVlZW};Bo~KfFNKZmWpC{bFD*Q zd~_7FA+Cs7>m$$t`*Sji&9!BThi?vj$%Bzue!uDh#dmM+8B>?o+|NNV=wn{G0PO~= zXeW$Wi@rr;i@AZCqjfj=`e4MZ5FKn_F@N}_cK<9T$jtzW;GcaA>ThpWgs_*oD0U2!mMi&!cWY`DBSypx*^UI|B^eaqksmQ8APj( z9`VG~VQ#bcSl1cfGFTP=U) z99<5hDuwcd{M5q}d$`v4Hb2`f*~0&JhznK1$`cI34*%jKeYC+Col_PoC3)*@Wg|6) zbjzW`lLFJ^?*FeoT@zqhhjtJWBw3>A-tRv`vD9wGq$;M~ib0fPRFEkEe-?D?XrU5j z5tvh40e;(a8m;OoDaVoQPiL$a2;y}lNW>FP5h z|L3K^m?b_0Ip(d7j-@P@$3NRVAqQ=lfqo|hxeBdy3|go0Pb1srxAi?{)abYUgxe%kF&#x!vFp6V&#v~pXkwz)3)j#A^}8<_cIkfhr@Vuh6U0B~haTYN@f5%DD#cUU zJM>75dY9T={d22^5F$sG%f-v6K`|=`CN<#By*WKu*a5K%T^&|iJR9K%S7N{VD;CVJ z3@uds_B(B}mAl^r1J~sR4z@c!<#^g6fXFRJ-EnzB(Cq6|u7Lmgr!Y*b=jtDxPH@u_ zDq6TO8BHzh;V2L~%6VP*cq$DF`CQG+m$Oif>k%B3*=XuNe;8wyC_dF;IsIH4bbDW@ zVA5)bxNYJUwX*ktx_T#I)D4p!CHZvl-=-Kw{t#gH`oq&=6ScdRIBFEm2A||S|Nh@x zyzPam3k&J-!-dA7gl3;0V+3l=t&QAgZonoyzSYF3(0h4|gEr#L|LJ7t6^Ml^4rJGF3ck&K!wQ$vO_PvOQFCkF zC*W@ebEWTJysUq6kRHE;%|5wvkjCi)>GM@ZD+;O5d!N3!HL(aog_e{jc>(5+a?C_-*)IEV76(gdN zDU^gz4{;HLPH?V>uq{^Lxzrj=pjNVS``NZ+*;PxJo%{2Zt}iaf|FiMZa6DN0wYYTt z8s8RlGs4WCt;LKhB*pP(?!(UZf8MF)soHt=UF=7o5jTxHW)MOixBB*RO}ymv*CbWp?)2&aA)zca;5po3yF;YE}n^wGhsm z5cKx$9l{QRL+;&>J%vQ{OONf}N=y&C!sql-VV8V-%h&chDO-`*fyJgY!;Hsi#e1b+ ztMzOuvJ@RzZhXq+M>|kjsJrqQT~4!mFVDhKghIt2DVnY z%`(TN0uep&Z0F<&do$i#h6=wD&=7QWdGamhLb>oOuu+<#YYuY(jD_<5k2bexclAlx z)8*^;bYi~6uZgdk${`XNuBLvAbA^RXmYB=`8Lfw@y5!#jLvi4keJxqWI_3^GWfWjYJ0lj#X=1HfY zg(Gei%$rS1)69kBDuqayac12;H^$cjrC;J1~3ivrM_|1LHH zsOblC4+V@cH?v>bZP9M_aDY(F(T|dqa5--axF_#K8^^PtY6Jh9ttL*oP< zVp72N|3_D6T)O+glv*uq<6?0&_Y+*AJunnI&mv%Qvzu{5tvz9TP8$gJoPX9ejEG(Q zBZ0vGH#Qmp-W8UJ0EpbcJN*$rCA2Tb^oXthq|zNU=&)Y2a-Alpo+8V&{xO6$uHNu@ zBQ^R6ZU&n;rc66Uq^pPCgfxlyy!fT_HRbTTJ%tAV2f_*I9}n%7AyZxHGc_1wuBemN zpFG$K`3^1ZK6~*=Wr6(igokK%qo0wPF=<8o`_jr)HS29X+NP^>EmlleL2u@w@f4@8 zyya+aKdWL z-YW&kK$G#l`nG})jf%`Un#hBQJzmS$`5eG^6zFiotQIDu&2mKn`$FR-D4TBxn`b3zM23mm%^$77W>vaW< zgrJZ2q0^WH!Nh1s$!^|74R#ZwBUSS3S5Bs4f4xO^Dc;x7wx>h7I>w-=0bK zX(c<$zi!Bq@qjsXIK}>uFY|P{eNLUmL&Y;asdJP(`v+*3-P>82j7zVplb)42+KGhH z&e3R@oTf2+Y>}{ul|qqpLyh=4UgvQ7$2UC9)H4$E$*2uKNuE(kIW9rr zU#B>>PMIbj(uBN1>Z{`M>#_cN^X-l}myY6rXyeL7p5o7~{4VZI*Y3S z+dYWpuiQ+iAPdkC>9#qD`<4#q*LT@jSy?~;@XO~7nPu7280OI^zw`(A;d;IHva%); z(;lJxas5H4K_#7D`!I%<_fpO`q388{BltK9&CHSbHG@+An#)x4^>kZw*W${Ij_ODd zXI_nqde?=xD^r7~WgmokE+TD`%jq6etfX0d%6)$Pi}9OLjL$k#kYc z56!Xo-v32p6BZth4&NQ}MZJ&j`DYa20osbKjvhtdYIpg;>D^;Zc zSkR%N*$h6b6LCVPr18#>GBeHgv+HFGK%+Bd#2$<|E}}_7?32cRe(M`Kew**#UZlPZ zG3`0DdZauUyAAST0cXA; zPt-ArGaN%LSzgcG_j^IQ!0O?k%1mWyWfj_1e8#k7&iLjRz3|N2hX;aD+;$eJ8&qi; z%wFE@MWdwRpTxXUZu?O$^jf3SQ<*L0>;V3Y^zHez2-@XTOMpHv?VAU?gD z`5JCGKIOZ9yi(eb#F@HcMXApB=u`|MW_zrUjZ~GpIh9)9rmDS5eICZ#-vu+%gpqu| z=CnI7Wt9048lnzpXFK%W64}=sSWp!D@ci z*!{h(4ye!|qz!36#b&~K%a3cn=)aZto_zNMdD9jPwU?bzaeksy8sA^NI}t~m<$KwC zI`&kX8qtJDKN{6781H;96C*ZMNUMNr;IP4I(=uYG7sEMLQ1$0uMwb+H9_<-%S6DY! z;^eVl9HV;8`OAHN6}Zx-v89_KWy}olzj;fbD7dc09BF>=PPWOAx`izKo(mvb)*&3b zfG9he+s7nh)tZVvSm|V%iuw=df=>EJ!G0utIbzIdI;Y~VO=J_TaU8i-x4=6rK&ov@ z9$WzLT;O{$d%Lsq<>1=EUP5iHAj^FvE5?MviaUdDyBnM(9NP#+{k}&uf_3XHg_A903&_w2`;fz& zFK0y)1`vhluOXacEhT@h%YWRFA{i0{W2@L$)vU`65gHzBSg>zx{_GnxS`s8xPi~!+ocl;-@Ay5er`Qo&&hcA8orhG({+H z3+rh-5F#ZbtIJp}3}0=bF0tGF8ASe2^KLU(Q%3PYNW|ntwuaK>V=T*AXNE9`KF7`J zU5zk$H93UVc>iV@Vtcz8#(HEIPRc|~!`16X%#9wnn%?hKyyCw81kGQLph3^Ofk^V; zLxGJ!0)bt--!}E=Sur+Bcid*KO>3m_g{)h1R%c{WwE6h^A4y5@Kjh|I5`z8XvA5G> z+ng;Oq72&D;>KyseQ2E?o4HNMPEl=J>am?$g5qd}zYJ54X{A#T;uL%#BPqDMh#4&t zU4S+!z$+<3Rw1*kdSm*vMfc`=GNe)MKahyzotMh*=tI~Bs$>U*h2ejQg;rs7llg&g z)Aq)|!RXh z>anbMn>HsEg;a||K9@ND3fbBg%bQMOzx!B^yHXO-?3A>J*KDb317&hOJ)V+ zv1QDsJM&2MC;F%bnnd*Z)49|ca0GhwdQq0>Fn`&Q z2Uj-gH~P0j)J-kX=&<~n5!rXPy{IU@z@*CzRS)ET@949go`kCHujFA{)+D?mNE=aM zyA<~G=3M_^Of4*`b8|aNOw^gF^4<8moh*p>hr;RnmF^vim#NwbYn+~R*- zn~;TiNpG93%^&8AeiVbsy{4Vfh?;W?3kw($)Kv6V2=@-oO@ut@QS8Jukt~zGF~x)= zzHG0V63EIRuO(hLi|k?~nNJLt=#;DX5YuN1@#Vc{X5#NyFM9*&|DM!B&s}T@ne%hc zf7D^#_u^|)ZdG#iS=sToD-WjM$9gVmU8pT>vb=jKd99(Ir&9AdyhUV{hZ2MO$N(zX z(ccA5P#VW5hYmQ(z;9xvS30ea*%{sbccD?Gn_CyMVsreRvO~?wm9?3Uf;}@HvIQ7-5)M*!Jpl7mx1j2i~$EFBa2FPmFK00*Dj{mi4?xbIDmjMD*adAw|) zjbQmIXOQ)-#O_WKV%ujSaXRaxSj|#<*jj6cHd(c7!N_kfDN0Av@on2ehx`3@We*k9w}*q4!cOyU{-K;51;#zzeY^vrI(^cL33g9#<#-sH0VXd%eoA9 z=s2z(ljBCk&3}2rfE@0RzN&6Nf}E%0M}^Q%f8mK1W()6QjpA*n%tvF#1JK|6L#dH# z-Ma^V4aYFXejce`5roWd!;Txm>YX3VPcAKW28g2dMXqXFRlFphS?b!AmA?sBPMYmUz$DguBZ)SVILlw* zhv{xhl9>nd@U?AL!jtzZD_$|UKXZXV8ScKN`iB3dR=W9wX8m)Poc&X?t2^{@@8ezntAm6aOY z6;#Cumu_Yw&ZwWUB-Lpj%6mZ?w*LvLL+!LDf$crqp6fb5TDvK>iPs^8z)$&Tbrsr(bXmTf` z_qV~Lyy9SB97O-~uDH&cgTbvkj?@A_Gp=%%FLal{jLWyK6L zhsNa`bD~mNo3x#%@pRkWtgWVWJhHeLf8~op!>|y}uaGPe+_<5j@2Y+d_{HJ5}?$xNFM7HudAd!U$G9WKLhAJ=^epvBJW><^2e)FFK zhg4Hdq?P34hDJrf#X$s#a|0LC@th~@DZ!sw9bb~_y?&$8G!<>`N6Cf=(HFf+an+jr zt=MQ1XEzmQjqr%l2ELNuyc|)h-`SuNKxwvulP-?}%cw(i>9*Fn10h$)fT5UaZ)Z1g z;l?PEYl)zzx0m{J;5k1p9Q@~op3j6A8#G5$ z=ycY9%FJxv4a1X!|eiD zU*Xk_0XVrB2@|nFMB(Vn=5zw5lZ}a~si~Qn5GsV`a&FN*z$KKQ6x6aWFS{Puc2qy% zh|q;k`PyW;+ZN3>pz)*~riO1|h{T}+u#M|++3)T@+0EgqJ*^lR9q~A!^r7f#`;^z` zd2BP#jRR5yBfiiVa1&W968;wH@Z^wK<>%DA|3Rr3DI2{?eC%&=vnPqRtIgil3TF6x z4?Q-<+zWZLi;m8*kqTEE$7yBx$5d5#HblO5aj=yQttL_!bhvf-s71@?|m&q8=+uym2}cL0aM=TFM`~?{LKIY zEwTYKRq|xUAKZQ?A+4K}e(gvT-Y=|#9pL zDyOsix-+;pgl`5#P5M*>TTdR^;bJF(@mY!8H1k(`H1dDtn1jE7jGdR4_lqdCqv;V++cJ9P7sk&U;V`byf|R&^meNkJRVR-IL`De2+2dd){c9^DYc4;h?0e z2e37*N=Xn@FtrO2y3YDW&@rWBzw>q93??XWd3so?Z`Y@iA6`+$B&t-KK}U^$U$kIh zci&kz)!@syHOyb?(3N)yaRQ8EfvvT59#ldF=mJQDYFonx)BYdEzB``k{{7!5QmIJx zC@C{5p%fan$_izZJK`K8dsFs`h*F4*hESYikE~D$ksNyzag5@S`Mcf+t-Jg4{XHJ{ zpLfoCyxy8@j?Tay2;#jZ*%!irr^(mNOta&d;`0Z;tahw^QHl6H;WTi@v4*|An)`%D$# zw^rciW@e6mdwuxp{^+mD9`mQvN&5n(V4bzz*;Bm57^zsW_l>Zgv*QaC{Reoc#|YV0 zj7PE;zg$pPC~(VnPvi-;(Dl|HF@2m;8g2Sb>mt|0mb>(L+19V@JRHrQQrUW3NB5TE zR^D*-`7xwX2T?ug^#uv6Vm ztU8%TN)AN5mwMDKuG?2ls=$7c(ai6WkHzMEi@Ap{b?-0}Z~uRw-Hcwf6{u{(Qf3BJ zW8>6)LstbVbi&*50PTjI$_;uPUCY=0N5!cVor60!jLA-UASfNn58aTF$1{nqL3=MW zL~E0L!8|Yn_kg5!4ob51Gh z)lyBsuGS7M&X$An#TBa-^bcf*I<@lUtvyl&&#>>8>vV~VpOMST5lMIU`;19Z7Ezuf z%OM+FNGC%}iNAX&?P-1$U@k!QV`cP<>=?c&)8hUlDh4MeCJ-qFh z-&mm^2*Q?{4qjfrb7~?U6xeWOtZoJB-eY>jqF_&yI>X)grR)nKWtUAuEpxf(^KqQ9 z4TieDcAmF7Q3_>@Z*sQNZQmSqy}juI!+XCfah-JkZcM_DgV+_#aeRV+$5o=vCrPt) zIbEP9o&_LS>cb41EAd^UkzMI;LM@JC_S2bNaR`)s%5a>+?ey|Pf%#KfsmzU97r4J- zh{=YZDJ`}k&+)t)HeB#ndSCuYPWFq3ZWf-|UM(mk zKaR>$r37>`e-y(u224)Cek^`&b{6yp)LjUkTZxLaZ6+v!v~YZ4LR*lGr?x=}cH5O0 zu3}W%?m9~vi~Fhj%vBAqUB6WI>bQK5db8EmPDKwsX=&wKjC;84p*0xba%hRa*T7I0 z!TfpG=NGq>MoEKC43IG^6o;~nCH5EKJJ+5B@pStu2_qU1=Lg#^gd&l2i+6UlJj)9w zzPtulX`v*EMxIzZzQMC2M1&d;yFcn!Vl~d|!*sj+ModDr^$XnF?fJK6S^8vLb@)@)EW+a29WMpk9W>kUe$#V-9 zC}y<2a{9Qg^nXSm9~ce3ALxWNsD9|hG6YY!utA-AN5qVx0J_Gk&bdxC@HR3nlik$c zbhF#(B7o;eZ7jN08*eN`uG~M_z$qJ$*trPU;+muJ^|xx|<~~I*)u*6j3)LxWmDQ%6 zbB$nx1d^V@$)LVL%KpZEG{hjM4oITHre2)qPR6aYCas7G3-2}R>V`7{jVnmyJf^`M zn4j?X4r*69q08?$^(wW{i9jluIk50`Oq>>Li22h$fTsdm?QD*!}<2 zL2a*!VE_Vbqmtd5gs%#%fDz9S+rCA+SRU%e>({SC+CB^|$m%$N{kBxK#z8U3f4^+# zB+=I4=?c29uHnlD82)ve?aR;K}x>mlW(cHJ1i~h{vg&<^i zwv#_YSGG4^?9G(ODu>={4s54hU+cL!5h}Uqt~PzAEdzAWf1WySBkvx-u5?5~Vo-t0 z?jwaYa`Ui0D|7);5>nw5D)d~*zi%o~S&;f4A7?hQqSiQ)HY{S~Z)iO)bHee)O?7UhS%D*#f%JVh@Ddvzkj(~%Kx9?KvKk4R>F{iwZg=s|F9d*$<1qq|ZKkJO+2i{5l?j54 zOl_*1%#RAiL|VIT>cV7ZvQH&cfNHbt_!U0(HgCtLG~~m+-t)ggVm{CcUqAo`?K-r3 zLkut2>itQq#R^bcVBWBp+sufI+Hf#;qRYZ)2DB6~GaMe&uoZ{>^KlV{XtAqH^M@zayVW)$pg zHSLSlvaYYb?OcVS^V7rTV5vU!*s5%#T2=%&)gZ_ z06gZvj!&5We8!18H1_Q?N7+FwvJ&$U^*c8$>d)~wOAiYS2vRX5(pX&W^}gKxiUCF5 z5PmG@0-TK`6s7Hvr(b7@Rru$_R+4427ONR?jnrorwmK!y_Pi~#iJH{}_ zbmR-=hh-H``6D~*-uDXRzqRR7zJ}|G2-_SnsO9Dy)RPs_?F6wUjA)m}GgxYyea_vE zaVyLV0C-mDx!Al0TeUd4%LR}E5&HKiDADoPJvLW7kHQib7ZxD&p#LJdwjMzHSKfG% z?_V@bQ0p^SVns^{z*fF<40Bk)Yn@&j{=ez9@Eb1w6ih#v#^09qK7KyF>Q>+lUe>sh zYx1YmGrkr1Us83maci7Sl{Y9)pjdF~y;i(>(Cz(=!m#l4sn%S4gu~O5Nyn}bb~=bW z6DXJxTjLuI`=nv^PlqnQv*H5WskrT2w{z9lL1A>4*t!vnF|)aky$E4B{iW^bp+$j zCHTv!P?K|pzY%k5aLIhIuZLQ}w}U4o{oIjLbXIzz=Jq)AyY$?0_oG`9YM+Trzqx%Y zKi83cmf=Iwk%$JSk%`ST_r{D)98m~rW*RoR-y>Lwa+eaNmy9^fzCe1v&NHw8yWoU_ zi6k;5O63r}2bg5k&2gXpx7EtDKT79uDZ#(t&Z;nSc>DQPNIQW!A@Uqis;nqbKHLu9 zwJdBc$#>EQg^Dew+HN4ZkHYl7K8(BV=8Fho2k3jEyu8h!s946QLedXd3Qyl8`+iP2 zyckt*I7aI6<&iw4Om@^Io2x`F?x>3Mb!tb~>5dGITgq>qbParOoWyvtec$%VuJ-Jk z(zF8SIkthGFHNY`w}F|5qxSqoJy1CV+tk!d9q`@CxXBY9i_jY8THhE6G^tXjDnE*a zkvYA*f@Je=^ona_!+!41e^Q}P9~8gZ4PrK>m>~7MJ9gp1&ubq&l!#oBX>y|kFBC{tUxb!-zX`|QDS#ywtIfI`4jG4}l7KIHj*R0NTyKkn7f-IJ8 z7b35*ZXrZ1q6i*s{*0EKNwWoOLo<)^ znPo-UBO#qy(&{n~T^{>|{b+*uS{pv9WoT8Pww<^%%sT3#%vi!3G<_*F#neFQ#f2VJ zE3jD8d8Ln>acl3#=v)V+AwlZlkVNk4bfmX_fo*@t9)97optSQ~-mzB)Uv&-nRzRCS zvp?GNyv%kP%ajxf5-dzN{@(P>J1lT+_{Gi;U(uWEMMQHA6-&lL#UTd2zTG!HyJlBez=Uvp2WZUxC~pkpJJZ&V@|nq2foI?T&iDvtSjka_XHEq z9_xN7h*VYhw$@t|xBJobkV8)$|Ebe9!Dg|3KJf zLS)MvMxzxqcKrY_W4ZnSFlB9rUPV27_6))_`>={Flli_z+8Zk_IPSnj$faTLsrd5I zbZ_l{S1O?9Fc>-$OD7WA!gw%MeHT?S_ahUb2b}}+-pXQT4{Id$=sd=<1k1TIDaZ)~ ze^!^1O={qg_w!Ojnr3txJwp?fZiYW&#U?YQOE${m={V_5`BHRo-iywH*a7&2K5mT} z3~SUHNx3%HZI1iWfr@02n1E_%j}ln{%7t=|($>Ggr@nol(Smo<(&EPv71L|=0>H2a z?Bug?Jbp74Rk9`dKR+L&?(?5JoW6zmbj_F1XF5FHrleRiJ~dRXYc?mtlWsKKnGicM z+VE@gv3D)*EAPIwn%^)af2*3l)il`d66;I24P~3H30_B!4{Bddzty(?RNXNBbPCG+ zfKo|Z4(5RMfdW)V3ESxAi9s=DtJINhxFZMzKYRb!o*p5QGhJc5rrM%G zYSRnc%o%b%-MddW#Fyky+}TG62|g*1$Rx6G?oh-D)QxyP+Elxkc7E>YQQw-3cC#Z) zX9;_9tH)um_nqoY$*66CFg&n%)!Zn;!3Z?+)Uom@PhGjF-$N4axQ}|zCQUh$ofVp1EzdF%X=+Nv0LZ=Iz z&N?YLbfQ_o&@c7YRknXidoW@Sn%n)Etp_Va(-#8wJNk&oN17XU_Wu`I({cLb#o}m?a64| zQWa5)dAOg-%T4N%p6Rh%>Kxp&H&C-+3dWsYeope1w&^K>sc@nF4)4=(pUx|3``pX( z25$X3jS~DxJmz+%15Vb)X7URqeZL*@Cz0iUUI}!1YuY#Xq{cjE+jOQx`Jx@5F>2rt zgr3#48}mn53K`#7Sy?b&3M}u?i0mwVJ_z;o1j}Lg3_DXT z|3CI5q!)cAE#7?ogp<~lrm{#eaDmDE^O{lQUIYMhdrP7pk_|mr_Vp!oX&(#4oP7F` z(Eq`wyF$Xj1e&h*3_kDdP=jRo~EOx>|5}p$-dn zQk4FK<6vdAwz2V^uDdm5F?s+?9v!IAdomGs1z{CkAHBGeH1BZPPc2YM7Mr!y-x5yL zauY$#zgA`smBGdY#*>7Egj9Z16J02#*vJEIY@B=v@6Hb;!Sa)Vy$dNFPuif<~Wx4>=?$==M)>uzg?`t%!mTg^LkN*PzLBziQh=x7amMl&f3H*Tiz-LoB+ioB-6%y<_ z1g4eEcDkPn$&2tr+DB~;KbV4yg@R}yHNc}%^Sh)=w;10MEHs#lEF(8u6C?J0>0Ic1 zUZ!qy$(yb1%?leCt~L_gZ`ANcqPGi}>W~&v_goyk>)XslLVw1V#IJzA!OjuZZode{ zxWL>2?AS`Pa|I&LU8CBy74cvq^Yq|r zz2!pGbZL~+8G~d0xyhd~2lFAE%0nr5yxt{uH@BPuWKHMx0SeGtI>IrPGyOkS*xFNl zZCg5en+@w}^`59N9mzo*T^d1s2n*q*v%a``Iz~Qxp&cbfD{_}BHr}594T@!FJo;0_ z)`3i$L$2>H@JbbZ!YG{mCWTqJhMT`+iF^_%f^2}2lLCpQgMg@4zyIqcrL@2#M0A2+ zXHS`@yA8}#(m~b&eaY7bezv*ZdbA#xPQYXGgH6cJPBiHCxt$W^+O3l9k{kwtB$`eFL!y_kfT$LcUroiyCv`xg{F9H=_f zpKP&f$P&Y5apXK_+Lj{e)RZSxN-K3rirw+@-QL``BwVdcgu~u1EdZikiSU^$xcD#v z2Tc*IC^*F?msn2T*!T3&G@+95#J4_=<6rId?TaHgmc@n&f&U-DWJT;MVc*{3qXZlR z%AF2$j~$yL7uv%(n43^_pF~C4qo^-fT_$C747E3!)b_)j^RCFNaIyZ>V9VAP2UBn4li+n4W6ZXyl9+rMJ<`xVvn*DZY%6pFaw|!{(~6cqN{Cu zE|YZRkABive*lU!1Br==cpMfkWjF1d3nOM?NTBTX@$-(xvo~tU~|&O%XK> z#khl~4RLXMY*DXEW~a_?pJAZlJa;wu;~C|NJAM?^u??!Wlg4S)h>o+_Kp8Fgy*u4@ z@f+DQF5fp65_=3p;-+`W(iJw`DY%*%Z~x>TF2Z{^=r})7R%cVzHt-}{nVq?350%OC zbR9=k=s%}VSB1s1pbJP__A5jL^*g|)Skg=Ohf1Hb8Ym;u5f;-DhDl2BHKW&w2r(U*dV8Mx6=r@Ag16ruXMeBYJd^qS38UfD>YCNc}AD&Af%*kNmmoD9D)|RBOP*paIG9g@~)lD+1`dqv}SQIx@l2>-PeqMLs0Q)Ye9g+#SNf@|^ zrB1l{QawA;OZjUTQNVwdb@luMuS>MJ{>zbwF~3ScWa~vil(Z@wCCteuO&*tLb#y7BYFV-4<=^%-GkHc z7NLe}PQl+XZ6>rkMpm^Z5qFa`0f^quEEyss2~jg{l)0F{mYcXyOmN$^81qmEv>slJ z{#G$(p`JyWt57KJcJ(tUKAyXL@cime8*|0r0^Zo}DY-nWNLLjxL>|?tOnV*KPd35B z@TzF|N5CikDHl!MBOQ%x=bX7Xq zU=0;(ksx(RGLUH=tUYlDqo}GCw7>8kTJKVm1<%(w#RnuZdl@x%4JzGydDI#{E#mgx zfm82qy_bAYCHGD2H0NYcl;^~Yw_SvXO1JvtTICzE3yDs)F$}+~0Y*kra?AN^gDI%_ z2efh``MqA=-m8SRou=D*OY-$HeKQ*sWDcz3DlD?tz_&s)PZNbsGqPdm8=s|-3wE8Q z9xKij{kUInZ*KJn#`on+=h6U4w4Rl2x%7A;7)jPTpIjU}J%mGyj*cGnUMYD63QWYs z=J>J9uGy(>+1XD~hLh^O*Wy${75|vF>9$ItLW4M1nDD=KqYe*OeFC}`fs+B)gF43A z+PWl^j(C`B>+|6wj8pX9b5(VtiqSC-P!q`tR_n6yl@iFK?)m_-{|8~6Q_dK*vMy0#LiVFdD>-`8kOYSFPZR&Y3LPS*@eJm!a5=%$Q?dXSv#GABWA4)f za;l`Gm_2={f)Kf${4~Q^>0Y8oW7!JzmBV zv`)~XGRRTgu~>z$ZE2?_myrRmXWgI+T5z9fy#}Hy57&a6+$c8>;A~BXvn)sE!laFIV8Cqx0d!To<|crJ-{baW-&AkgWnPs&pgo{l6-7DRW*K@8~m% zlCopqkoI8g-2t<~I3I3W*LV_U*#CtT^Rb_B%PTHkj8b6#Ugy13M^xt~>6UHsYP!Lk zMl9egNm=`SU2o+?^*SsUm!(Q4AeJ&x-0xndNBWrdJ!(*tThl#}#un~nk)c$}XN1S(vn{6s!h6yB# zsgAg*O_L)d6_JV!a=5-sfDv+i)+)3^&^F4<+wK>)cbgNMWt;s-hZt&qFQeCswvx^& zD>xSdOd90i*ZYQ_KX}leh3z?ZA&l|d{8ZIWBbWZoQ69^)5VWrIRCix=@`lpVv0d75 z5yYCMX=r!4Ot5Z;#4EIAt)CGl`xPFaR&(4~jwOoUD|oZE6_lOthdXWVft*r!3T zsR6Ai;0}bjxzK84WYDw1Ps~eK>(9$9JAek*R;F(ks0kCY0T=%A)YC<yBkgv+*AJ&VXM%r_;X9@;vtNkwE&MBQQL?A^2Kd1T*6l9*y;SvIqepxGK#S$ zu9tdDeWU!32brk~s%0SQ(*xABWv)2yh5-aGvJr2q7%Z``CL(}?jAQsGu_V8{F*R;n zkyz5EA{6DS3ph;N_ug-4xi~*PSio@q0n!`9`bjuXRyzSd_jEF|DV=D;CH&2R`F>ZQ z=Jdt8mT)wmzbi&%D7HsFlKoIXD^Xs60E2Es$yM7z(~cVR9?M&kPZL$d^AX$rr9@M(gFb6&oZ?9-fN8FH8AXt> zo{V#EW_sLKhSlID!7hW!(L~|rRs7~_{#_<&br0b%;c*^3caP_{$H|e{2@mwqBdTyq z=rs0i_B1w@rP~9~m6DQj_yBg*qrOXp>V0dfj6U?3C7<9EkH6&G?G%2kidq5=Gs7|u zCO;U)u%$<`@+!=lI=emNdbg7_HKm#a{(4eC2F!$H>9F!_CV){nlm8$;zG^y2zj#Z+ zR+oBwk?V{K5ZpxdF>u_HW_1w|fO~!)jO=L-6)M|8Dme*5u&S?Hu4zTypIw}4B|DGG zwQ&E(q}d5()kzPBUrzJ1#g#T?Ri&4?T4B``RJ)Ha93Y|vRquCI+2K|T%?C0efs!V~ zuXHc-z7&B?2hrcpt9iXpd`QKU@i3wr+4TFCY5fd}o!-QYkkV&{I@mUgJYj(t5Bu4xb0zB3V@)CMBolOs!h#@v zl>zZ<;l5H_#FDLbym@jTPf)2?)Lw}zzFNX0^iTWy*W zbsKFtpdLl$go~Zi^Z8v4p$O{jN^xJ@%7-M?(>iX(JzTc9DGv@t#$@+q;z2O$*J@K1 z;dvjFThCJspZ@39+F|+R7DXi0b+K36?@@Jj{$6txdbCQ?ig-*V8FxlP?Cv%)_mg6x zQG5@zuFM-2gBcUXY8+IJ&#@m?4uWtB5d2Brjo!fW-YYC31?Wc^S)ERZhX9x|dFPHD zA;-eE=lAZc_S{@DsEloOCJrGXnqY)qEv&vHXzv!O>4+qv-QWh20q2_Rf(rxwd+DGBO2Ee7D1; z!DhBDu>YN(0u7cU(KIQfU$85Spn~;cXaNnuDG|DNr53~@%dHYnRYUtlnNN|L|FyV? z2^rM`>Oq^I9>#_f7>Ys$c+Tv^(+o=S(uYpm`h_U`sg^zZ;5B+tB6Q087;}xib0*hB z(U})-(74mTpzQ^hytaXT_b19`04s(BOPxqHo)3MRQ`4cF6CJtaURSO&7cqoCLAEF% zMrP(?U}_vc_fcI)8xlYy{{!Uw<^tf0wQ|T;?+aoVP0Yqi$+xx2$C}1WY&PCp>ze!& zU2L3|C0=ClSmO=s7CV0c@n4cX_2vCSG0tz8BE4p=tcvZ_c!%n>x_&ux8No<)urEj5 z{7m?W`rM4F^Hj>Li#=n?b!L?zUuZQ_&W`fqz`#+`F;xADXmuL$am=Azde-7KS5MkJ z%(N)pQ;1KwED6$OaPlW0vbJLu;O5ww_#SM@UM9u*d8kE07A`$}QV-^Kw-b*GViDxD zQFyQer+)j;fP8d%SjO!)wRg1-VkDKUMGoDrPI1zEsPSOyb<>Qf%;H{<(+@r`v+C}jk z8AKgO&C|Fe&i&9CXK~AH>up9Zd+|=Sy*%PA>Iai!Yi?0fg6zEmrPE_W`YWZCJ>r5d zhn4DADlKe7d$+l6vT%=vt$N@NwwI#oi=jn#YViekZsn>AI_;+Ej46^FK>mAY%m)&L zaZKe~CfUHi9$}gO>Dg zuU57BweY-ARLmWs`jipWr|&-%{*){~?N2`JZujfTmji4LM5t&qTAq8M<@KbXe!&!U zPvhg`$DPI*Z#S=hthIiiWCkptCid_Rx>N>!$O&Qnqd(hFUcAl;ZjuPS)-+6Eqr~+c z(UTfu*@oB{{`}>~gQC$eajD3{y=`U^wk%T^d$cAn@Z4Ao#ugSMUD4&&*<*zYn*VnE zY~Y)ybUMCkKu2jrzu1iQvby+^*9xWwz0_w#W1}7uCAie_@YU=7zRZYO06Gt zmi)4SLA)~ikGDz0|4puL0oCbVViExulkT87JjjpVpYHS?IcaqFy8-MR-QCnOGAVD* zed?UFVYt8YJ$mfe0B`+Fs>~_mt3sSf#2O9_X(C+GtThqWa6ZHY0nr_3$)VSlKlUW1 zE4iMJs;)7S*mNW5LML_3uCBmTo$3A2<;!@R(FuEaLb=H2A`2l!(Kxrqf6tYg?NmB>fdi-47?$1(y6S-XFeojP^Z}-ghVDuVn$Ub0fXW7D)a0_eUn=I1g!o z&+YN$yqf7}GK!>*RiIkCN3F$(Xn@|yO4OvFM`if`IIn++H+hJ_K*Rfs@r^>(-k&PJ zTgV0$Td=&+U+i7dkr9{5SytK??lUgEupc-eDEZbTv7nZQ!tQ1>!H$WFq^HPvCEP+5 z0!Jq2I``hO^0u&0EWqzFvc1);AhU&N#9DL9{j`()dfIW!zOvwklUFnvrcwfw!+6YN zUby@ITlql*56#U2Tm^2>V)JGLBB+Sc$nT4FDo_2a>1+ zLS3E4-*>6V1<+6T1&4)#E27+C%()VEy0fQe$LYzkMZsTw+2?Ej^6Kt|Qeo$?o2oTy z_5I%~>szRbwnH6mN5@!Z(`P@dWwoql4qVRjbfG8j%NosJg{=pWUg^5ln>7UQ)frA} zS9ns2Y0>bQ=v>iBKx?7a9Hd021R@}M-T^^by|_7#omrn_cr}4%iQ$OaB>HiM!0nF{ zEE{s7x}3YLHbqp<|0Tc#`->UuB*0f-J8p@K5-=(&$ z>EpbukYF@;NFp`|mg_*OkWgWFZx81~je66?2YrYhWR0B$n{&nE3s3s;XDcZ=?m-t} z03tvriA8oTbP-^L(CSQvOmJ85PY(BKzc70|^{-8>jKjz~STHcyMq5{2^zbG5=P&|3 zX?gq#P+u{>Ji!&@T$|ozH4&Afv0f|Bn%VaKu*Poa3li$Zt7g-Q@=cMe6Nj3p`Hor7 zop4?#DrerK$x~o6s*kWeM4aoouHjmbRP~0d}3yK)R;g>HA$3 z<6qjH^qW@X`Ql)RRXYoWS?^reM0qg#*%uO}!wc%E&w9^Z@3_A878?!?`A$dl z&%oIo)IxW8rg^pL)9AZ-|3b5Xwx{RhaXVkGDW73zFesm4R9S4^LVHZAgP&WlD*eD8*I1*v7y zvCUCwD^EBS51iYt!#26+eiOxKl-1$kT6Dr!P@*GPY>%m2VgbsZ#inHX#beHHLblf| z|GrpKTNX$k-GM-$QCWn_eF)x&WDU4j<#i&-Qo8usT6s0uKy~%I5n+&>i;-EVU%j@n z zd%$72cIgaylT`#6m$BrV%ABcq%9CDO+@Z{YH!$DjL?ehj8{pTWpSxmqVre(|H3h$* zTg(Ly&L~HOAmYx4bq5vxE$$o;+}dHO!E1Vd20~gAf*s;NxNK4Ey6SOo{`S18_+Fi( zw+2iS-YXZO=JWf7{z<~HUFnb8dL^MJyjz@X^63WyX9IV4(3e8YlZtTH;r(YWg5$v8 zwGK(%h53-nkKL_zeNV9 zE$*tiO^YNziuVvIp02atWYkdsG!HzkJI1bGEwRY z%g_`D0{tHo@8MLmdCM!eU z7X(;K3NGlWMmC%{R84Y_kssuuDpgzCHT8z|d0xDp?BV-_u_-iU&GNdJ+a{58+vDM#N9dPwu$&q)o!iq5*K+|d)E&qXrJ454fklLF1@NNJ>8z; zE^gX-;}h1%wR#N%bNA)Peud2HU=gH0dht&B_%&ZZ$leL%lVTBQ&=%onfn%aedsIJ? zy82m#+-2uI{bEJM15wR{>lJGP<83+$4+5IhZznpiYn8^DG9+**nX__HJ_?slv3r}T zu{%rC()4S&_MI+^=nm6M0wU)^PsbZS-PM4qN;eV`GCUb2d9Fj`=!b2aF9-X#JxuRa zw#DU)Qa-hg@Z&tpR^$Jo)BalCC=N2fdN(0qRFszFsdx~OBS?2> zD*N$%`g#FN`el;Mje62|=R~=st*zQ$0RvHDhQI|JH|Z_P>tc*lUOScL)u7^W7FAiiX;(vAR4!;e-o9EOSVfOA_R>v3)$oX0pj_HEzp4*f{oV%5XE+(3e*7 zruH|f$3B2QQ{)uV@viAJxytq!h@CY@nqNUy4SN-PKBIe&TOU4GOBL3K*t(58m!C;j zm(!LZD#7Iw27}>iRQ&YzzTVdq)ZXIA6@bQVx%K0vp z}Chx5u+vLrKzKNG|B>$@*rIMd&#Wi=*E)va`#N@z#=`AdJbHXlP%?sPafC3|d zFU|{?kP)qhp&v!g!xiuqOh1$CY)=1cbB?4SZdlSFwh!)RO`F_l<85oZEAa&hqt#4Y zPJb|}gkS`INndD}Ku%_Z)>XeWDeHveIJ%x>^0T_fH{85ZMGB-bAnq1SN*+gOjc@$; zhm;)X8%ByZj;XG_AE2=g;(VSwi99=_8Ob(HG$az^@BjuQ zUKDm2M8$oOi%Jzn*6`ac3w9ISw|Tihs85(`>*(u;2|bG{^$wU+@j1jMn>|_ zuP)5lG1WsfQU%J{$?4QdX$C=1n>2}gW(Q3vA-bD1-G@+m25DXs7&o2d~+&k1@TqlWfJ}G0(l|1QKr1`&K-K%HGf3pZM znljJDhdkip;3ao(_~E0DO=cPJsGk`fQANEofCfHMc_vk*SQl0O-4 z(CLHb8(bXdh#JCB?4u)XeW;VVP!TK<~^DgXOXKR4-vA~e@6w7fqHOjYl*!Y zFYpSXiiY0HcPKxnw%vw!yuz?eyV}yCXNk`f;($&u@3?5=eS@gwLk46bk&8%#PyWZU zB@LGED7;FBL8Nwqmp_-_ekQ7m-ZSMMgp(!S;LcN-&$DR9aZr_@rG(In7XnNk-*BN7 zrCL`pL6YeYAV5C>NeuvYAs>TDL5Kl*b;unzIap(=EbZjb%4BDST;Eoa*#W zGay8)-|FHQN|gcuCFFuVHnMiRF*}GBqhtzPVBLx5otGiV`85RXk_EBJ%eHfPy4K@A zc)2as_Zw{&8N)|{EPu^D4nGPz6Vb^B|Fljh-x7tA<8bZ6*rc{mKo3HJE-o!)+bUlM z7{LNy1Y`y7%`!6t!qy{4etFh03=o;VPV@Z)0{#$l7qoZQH7Ssl>)TTRZ zy?1rFx45VX?l9=rFHOw>(*C*+ulO?<%F?JcAo=CL1Mxr7bs5u3a&YZbP;`Ua3REwM zlA|$}3lh@kf0W(82{ZocWrj2xi(p)qnLY zrWrw6uxvRrzvPBdtj0X_`YopmahVez1cY>TJ8jO)CrnopURZIQesWfZBe+rVl)>W8 zN7s?%S`4`-iIe9~v*j6yB63h-Uh z95_CiD}6~`jz--4Qsqk@a_h3$W(VU|#>&r}i;+|-AWWO7r%7)jFDM==H(bbl8mUob zU6KF9%lv)l4k|?_A?f$?;##@$PNZr3-7@VJhi+W9_w7>YO>^=3W_>hpEz^B1^b4VE zdob&i?cJ*!8n!JUrTvQQgd#ainTi(Rv-^Z$bBvTu*LA{lnqE17HvznO z6<4p*C}6X?Zg>?VfFzOj$&&p57>&eAYvk}8mfsvnHvjX)g?HrS1s5owxS)1fVOt2# zy9N?-BTv5lx`g?`4;trpVwsf6aIq2(&YPAvK24R_#B=MN0qg1QkS+=F2W#2E`K{8& zyNvV0d)s&P1)~`KnKS7Y!{U#*%)pO33oTI2pSY|G32c=3xa~-I@O`6zVYY42COpTQ z1U}gGNp8wa3F2A&qRB*KK4s&uU)|0l^l@(Ob~3l(uLq+^R(2ON+H~_M&!|5taDIIl zzUwuWU4CoXpePQ=S~)D+{e>OVd!nO}Uz8&;TAF@HAP`Ktk2=2ds)w+KwI3X&vaV9& ztg)+f<$hq|6@69rLsEtJ<$vg+KU!n?t+t*l5n}VxP2o5!*DIG~v|X4Ae&`31KWwP< zb!Bl9+&aqyZ21Y#1+lL7oO4?{)zI(5e-h_Uds7a(KdAXCii358Pzythwm5qxDmn*8 z$5Dv~z0ZE0x58gsB1>IA9Qk@Z`mc+Kcrtyj`OLP5R_MuOtfIQ=eRRwgHg!TSbly&blmfg3r>`r6r-VBc zfQ&gJnu(RQ+T9D+P-BrlYL0<1V?k&ZE8;%n58Z~LJxdn>ip9PRolM@$NP^12COpK( z9BDZd!WzSgvnE7P)KR%#WWDl~4t{a$|&RyifTnc$+#y9U3Biw4QZ51`A5>N?j9^DxIXR^)R;`XA2@s~U`w*`<- zTrH?VB}G1jqdfQg-Y-=)^(yG5`%>5!FErP#<~qWdygkylr&-_>tDcgH7+a4zQ;NG> z6y^&vo~QOp*(fXDp-}WGDaAT`19R)yI_`>my}Ac4!A)u*s+fukdC7CmHFEe~R}pH2 zEvyk#RBUKH(w>08ZIXi^i$5K>1AyydM)_&{u6ws{LfQdeO0-`Zcp4T}gi1Hnx`C2g z6c}SS5Owz(1?_QjcSk}J1}1pzoFD$Ej>Qm-aJ<31#4~2z1ry1Nf!?K05-v6}v+p%6 zm`oC2Hri@P;n=fc?b-^nO-BGMkyuaFA<7UyyXW=Tk+;X@jq^FMn6WIq<6GN*P?Xly z8)O(M?R2vrulD~m>iU_>Ewr{2!LS4P;7dJCzw$}#O;ET69tx^YGrrhJI{OR#_r&UA0GNJqij zx98>=95=h99)skIx3_6sQ-2{8uYYv=eBZgx=)FS3y`$7>uFy4=JTcN2r970nvL}GyZjG@pG7gPn%XO3>G zglJhX%|_pB@Sa7KUC zPMKu59_;>7Bm56zaUG zkHV@jLK$bTZ;Ve7qqux28=s-nY)j-O^>c87PjK3TlEdpkFk4QZx4$Dp;sFLv7H-x*sZ@UYzNAl+t>OCePNg8ZWbB z;soT=9j}WO{cjx$V%7tMZU8f!s})y$M)tk60) zf_8LD9paBpKA~p0gi6lMrRf&;(km{>xxbNiw$|`4Ix0eVQ5ce@V?Q&Zeo1~V<=+Q> zFS=?iDG6QN#jkWqB$}V3K}FJ?={Any%eY3D3I0<~#p3SQV#_Ov{rMTH7a^&rz?P)( zrQtt%8a0F}(SpU#E*#HFzTKXIBV7U?M`A>JbG^)SD(nXOa?ZQe+z-uK1Fd&YsUFgL z^X#CeejqnCI$CL7x#g_+aeXXx0kv}`fpqQY;T!DpQjyudpL@{Cx+*mXMtx!@zq22! zsntWDdUB{-<|~-S>K5;LWtVL%f~)yEUHD-f#qxPd=K;@xCCqAYZ!Z+H2wDGoF{^sL z_}3XaN<`VLq5T9V{D%Wp#ZbxbT!bKlx(4&$9ullgFS|}!%|8W*o%)BeowePj`3_s3 z5qsYXWoj#-LO(CK;q!g~Po(9cmi5_q4UhBIu8XY&p);KaL8<0rWDF{Cg~k!XKY^5= zo%@B8$EohzaI?oz?qm;J&S^wVLW2tf91#HtgtJ<`Cf#-YtfiGzmH$h_umD_ll;4k{ zqkzw8_tm}~H|k8=9$%pRboNw&Vz~@0`?j1;5Xa5CG@EnPCcGntNj+(i?t?D})=00^ z40BKTluG02ohS03KluAPK{`gHd6!4}eT|nzs7ZU2ZA)K9>XEHfFRkj(dSn>rpbW;% zGIq4vLg1C9j}-Of2^WFBXY!FQ&}MB*WlQR)RX8a)N#lOow*hM;J#?ZFMq|#`h`wpT zyIu7zAhOfY&+bV>cMzu$`6W2l` z%u%p|k%XH&MUvhSH-w=P_Md1{dx>vonktmi`1#ER&gwb*vtKyGnK|CFV6{oyi?SOd z+^L!Fqgh?NjI6}K^G6k|Ha`ECc$E^^%u^!HLFObI@M>(f`97 zAtbmMx_`N~^2~wlI8*)yl5_|!s?hAT$R<4imo|YRom4^#cUf#jj>;cPP+zH-_ruMK zL9)3oLUCQb6F0r2?E!Cf2^_3)9(lJf_nP0vDpbatp9X?9>{tlL($dKinYdnpj84`i z2=EZR_?Iog@=_c=LlyZjsBP!Ps?mHl2!bcCem~hJ78I&V2qKGv&co7IoDZ z*h{zzA$s}RRA1#@{D!cQn3uiP;8{3Fga@Kap`HbCQcUIPLYrP`&mS>@v6e=4fNTkW z;qkJa+1rzbl3~U=jB3n(m$~+7`=N?bi{FJ-7OJg%{7SZ$qNLUx3+Wq=BnPdxs+U3S zY}eq3YpM5@xy7%vS5}2O*>|^+62B51YXD26$?D3o<++9;ob!5Q_71c}Y?Z7mo%6e~ z>_JZ+8ID58a?k7hS}opFYI`0D8e7oX_%Qif%OU_hGJc;H`Y^9cofdHJh<1wDUAScZM0rR=c6;5Vq3)^TcXmH7 zYxp(ocM{TqfXkp;k1ewW5O@SL8jLcAN`FD?$40g_&!(FA@HArL4%`7I>DGB^q_#8|d;WN>TP^A@vsB~LUQqM>vg@t`SsrqS4op@=rvlT_&bK!ujk&)5eZMhes za-1{+FQE#Gr=GP6EoEePr1x5AN;hSIM_Y$GYd{*!M)z&}?w*LBy-oe@|YUixUO+!RAuQ*+^ zookvdGdPA{5bL$mguk|K#(;GQ8~>HF{M%3nfScJUWT^n&H(!-A@31D@M;-;eD#ClO zeD;obqU@VEG{IN4b)TG(?f|-XBg!9<`kmf;OsGt9`-$8WN97I8^b$J)jLwZ{(XB^^ z$7Op;^eBVLI4%X^sG}`+!~5(3$bI=`%%AV`ht3Y}Qh9ef1b;Q0f*_E&B0Q7@uNoss z`aZvtZG7=Q!r}YZ;XXOQhp)hU@?3D3@qloKJ2d2`nwqW9=GfN7B!7;GLoqxHO-a5t zGNPrND?$Y(y~s7K2?6_p-<{gF zZ9%pk^;c$jMoOSD;~|_UbwRuOwNtoEbQTIY>lRbVT15nYs^K_)N{UCvy0JJev4j3v zY*HUyCr-wQxuSTk0@WLkWH@hmqwZALoy-@6z|F+yKjH0~>Y~o*ML->A=tLKex)ClZ zRbJ@@&34NLGZLO$YGFa+*5OW5N|#hPI-T6n$LsOGyt!Ttc827vtg~H54jpQ|edx5% z7M89jwn<3%8pqx#f8CvP+t11UoGX}vZ@tq^EHmzhlpA%CI8VYNqjH{v`4kZS8%y@b z?#|pA(?rz41w7(0=@x&sjjnLFbFKq!VHUHKRdR2ff{IMwIfmp>L{D?~?mOH*w=T)q z^aHI2G0PUL)(Br>ZLDouHIsIy*Wk$VB0##61}1(ITV+*0Tx0nN1}_M{LgA$*Sl1?c zkuJ9<6NbNsv;{2g$`bEta%mE}_V}(kO&HqZ zAV~R=?4Q76gIEEsePaOO9uZ>LJbW&f$GXHBMW?P+JR551+|sG5YOWNfG$3zFxdO)fm5Q}t< zy(fG===I$r+a~!l!zLp?R8j_ws9-yp+%E}q5__`(iNUi*Fl|5bwC)l}*YgKfZp|4{d}o3e=aO}+ zvlBpKb~tI)M7=_Nr5eTuy)81ksUky7^FP16zisY8N!^rStkIR$_Vxg&W2z?KGi8c- zg;e|+9s3l{3HpC{R8DAx3VyAO_{pS?jbSQr4-St(R}XT4ySEN>Zh5G3Tc9$ZQ?|sK zi>%};P)z*Y>}ccX%_gBKmxY8zO7`Hw6IsH%@*=q8S#ME|7XH7!t~?&f_UjL0N!Ch? zEMv=(vXm%GC`&5Qt_V?47)zEBW(HXzq@+Z&i2M>I*}{x{X;C6-#!jVdGh`jS=Qj29 zJiq6CUw`=Ae++Zq_jRsw&UMcBe82Z%-uA^@2-CQxSR&~k$C_qIn0W#SWiJ{Jq$t)e z&aZXHE;UGx5erBFEF;O3JvcqzblLsl)!)7k@<8CJU-o`kvcMS5JggQ&?*9TxD)}Ul ze`iC#9|OsTlsJVRY;kpU-IW)SByjJTB%8GLX7~H~!W;+HgJKVPT)Tlm6(74ed3~^_ zq%FPw+868RH_e)H@l1vat|aN-Z;Q}fIfgBspyyU^mAB$D z<)%h<=hT$(OiC;NFP5evyKoml7WN){2|dat_7jjI3}R@%JAHpszJuPLCX5)&UUfcL z*>*4adQar|yG9wRJmQciE{J zv;}If;)y+1_kJDhX6rEu@d1?zYgBp69hIN@BRXsgM@I~A;;PF>toI#++)NRvU7ba~ z@)Vq}>Z58RA6Vzg2LPp+v`J)^TDu)WCaYsS{i$b)vL@yffA5REzSI@3E!&eQY?M=^ zuekH)uXT6zQNEM_4`2|$y~?zOC+FWhhW2LlR*Aas&z{Wt*Ewt-^HUb2v7Cno&b+!e zn1-Q7$_*NA04XuhWo_D4+cQ|jRAyzn zdw&5Cs4qhsP4-=f{y6Jh{gTcr#X-2Nv+U{h<}@tTx$AX4VK96Xn!_s5eY=ZD>w<&OD6d#duJ(WYzy8PSZzTNC!~Sh;#IQLFGn zM@LjFnz5>K4VB>^50Tc*6Pjj@Q;y$^4*sTJ|A=e(<;+j6g8MIS?&bD?6BhJ4EC0RB zO^GZ-GkEeBV}o{&3w`n`~2YP9;0406!2_(%|MvVThucPYn5PMQ4w|!O~|4Cxn~>z4}du$o|6}z2n^u&!ITc zPNl}gWDIrYipN2BR&#Fw+d`05A)3tFXvY0H>(z_FdP6!&BEG`C^|z+tf{3BBU;lD7 z;pC;6Dn{dsP)~pU>Beg?A=!I%qd-Rmflq+Np372BWnnY^IwK%BgexbYRH=W2kBVR) z6g=eb8gUrgalv`dm*UsohQ6_;OWs>HqGQHYGPA+&@N9H&z}*MD8%JMz4Pb9 zr#fFb;aO^J%gn`QM{SV0#WbFnAYJmMZsjchuBE3m-d_+r@28PuRX-94f}yOn-{V>2 zZhPFN`sl{aDPX`VV!X9^r_;kl$i1}wvnj4(_Nj4hR=?Bdshve@zMpO$$o(WwXWFv^)KPnz)Of#h4 zEO<#g>;{Cj2$eWymo8|BIZ@JsfLMoRv$;_W9n#ERWv1{Gd$L{EgtbIju!ouOpS`^M zAvJCLg-k26D}Si`%9ZuL{d$z&q!7h0cGfN6&ven8q75(9Ttzt%aVw9}LL)mDj zZ|g2UHjTbjG((YZy;8-cVV7yeCmJ?^l2zQ7zGGpE>fzz$X3Q%9?SABx;q%G7Y{mMW z=9NElPrO*UaoddB)7E(XsSc>kf*zQgt?IS9({cs6_*;+KxF|mW_+=)6wg0mxA8P20 zvJsmzw!B;p7Nx598Q6&j_TxRzDA){`I#1Q{jfOXGkJ0hoalKRN{|{Uv=G0`HS*_OjWy#I+F=qScJ}rCF+?YojOGfj?jn2KC7O^5lN?lw*cpqve;dnfP zzC!Hd;Xgy{oB98_ZjLZi4a+7E@E9or0uv5{(u>2-o9kl5{UPg+VDH&F9XGZR&rO*0 zhf>iM&oJ{A%QGrc*81YX;uVsM9}<6DdcK$9&uciKv2(-JO;TF)?igQ6a47#BU4PXy z8Ii?jx7KP{q0TsH!f3>y zNotgfETd%K8{qQx8^}FIrYUfVDefPoYJ@Hq(04L{E_Y*8Ut3kSFb|18&us(a0AKT8%gaH%sconbg<<7#OW4U)MO5L9d+~`fR z!6oYl`Z+ntS=Rvr2a%(Fn=K^)y)j-=rw$ya53R;k#lFHk(w7-6cXg!o=6Uxx}lqKR@>{{K9Pox@gg2;J9=)| zmvNuQA`Fd((_zQJD1f0ny<{XQNhCoXO2_+>04k!s@8@>!fd+nUn)J0iGS^rBMH>(X zSLeHaW?5`I7-5gWy(}sc?SmvER#JBgcyeoHB2Hl<8Z{A5n#~g@v3;{wUkzxK1y)_+ z$*Y+Aj}_zz7=?aB>Oq0(1~f^)xVqXr4NtEXrT=i48tYce(4$xJs`cFL)B{3-olRn3 z^pI%J0adMW8d^YN8%l7lHT%$odENj4tdDtSIs^HtMs;Y2AsP_az+sJquMxm|ISrJF z;o6)tZQVT7bo z?F7c-Q@+XUf0p#d0qH(HHKnDgIZ%%Wz|dYhjIfj!zRxKY>pgRKZ~kK9GP~u`<51s$ zwmd+ZyuTH$8pp!0lxVqDK-UcHa0QFolf9AHXg%kFCcHi!Fmgp6^_aAuB@54*v#3d@ zCzY3pP)@MrJdbkR0oZyFX9(aD1+_VOC5mEtP(E>qp!vzSzc8|G#|AhBhm}Jl{!-LU z5Wg{eaOb?JnjOTA@1vbBHQs2hFA!|KPG@wX$2Gf4E-2Ok%Xaz5-tR5$S#Aa|Edvl! zY2`@K_Qw=Ou)QYe{3c2+lG+F$jG#dnE%{pL_9@g$ z@@i(V`9jG^;)wGc>p?e6K%*e+xP$?rEU2;^*cLL1MP^|%R$LoLo1OUTwVQFK3KB2S z*$O}g&aQ6VGfp!;7RI57`8a^w4hzPBnTI48AyzS$Z=-$N8k-G1RL zkYjo^w!`ah2LPqUTg~-MRO@x>{%*oYmW^d^-n3~Gh(H7b*XtnfXb76SCw#3F%59KW ztxS4#Y)+oM@{#W(Kr6wk2`otfmUao{#jiGPg`vGCf@*W9WWN#uPU_LahbHpAD~p;(oKmZ&*cRD(rZjTf|NKkf*=xX% zMD6iBBIb9hMlQ@_zCH~m5mCj#SAM(zW<QJOO1em=l`=y`u({=XMtD?E3@IBA!rK<6Z%vq!- zkC#t$+8=Q$;@4LyhXaI}_SC2Do>F}(Uo{`d03jaq5XZJwn4p^g$8>u~@Ej5#hFTuN zuG)WF^Bj0eUQtyhaBV-`S31(YFzOGoy{B8U6jMv!!UbZi zr74dkuA%!TG1B@lbYDCGQDZz0cO&DmN88OE7vGu1 zOD({lAZh=zH#}?|(-5yh1pKgHDsLmiI$u7Ki3Y75|Gd*H0Bu}Usq48c!rV+x%`_|W8>=X-I%SDb`$pFv= zGLy%?5fH2gFTZhr)mI)k9fviLazg!(Jh_E$i!Bm(Av&*e(0q83i>wP3-#fJp;bK-( z^#+S{2zYli&$WaJ?&#?1A`EwElm^1|a|U8)@S-k9Kd|$!dm6ZF7kb0)Gql17u3)CT ztev6E{`yhDD{cV^QljeR2pMLMOcFQ)SD^b$CoXP}vn#_N7$ty(17O0>*B991j}VMo z4&>?f1BUy<87V`^t1!3~Pf;d@=IbApxSO?usROW;W$GA<0y2v5XqBE)S}I}TXZtDP z_GAaK;v?!c#WiAXbl?eihVm-|!Au#>1t663RFXG8`RztVJ81w^cLY_CPA;K8XF9YX&H6~4-- literal 0 HcmV?d00001