diff --git a/CHANGELOG.md b/CHANGELOG.md index 676b4b7..125d4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [0.3.0] - 2024-11-27 + +### Added +- New sub GUI *2DInv* in **NUCLEUSinv** for 2D T1-T2 inversion (works so far for HELIOS, DART and JAVELIN (Vista Clara) and RockCoreAnalyzer (Magritek) data) +- New import routines in **NUCLEUSinv** for the NMR Dart Logging tool +- New *Extra* menu entry in **NUCLEUSinv** to find duplicate NMR signals in the file list +- New fitting options in the *PhaseView* sub GUI of **NUCLEUSinv** + +### Changed +- Unified the appearance along several sub GUIs for consistency +- Updated the wait bar increments for very long batch runs +- When *HELIOS* data is imported, the user can now decide if several files should be stacked together + +### Fixed +- Fixed a bug when importing data and the Statistics Toolbox is not available + ## [0.2.1] - 2024-02-11 ### Added @@ -215,6 +231,7 @@ Initial Version +[0.3.0]: https://github.com/ThoHiller/nmr-nucleus/compare/v.0.2.1...v.0.3.0 [0.2.1]: https://github.com/ThoHiller/nmr-nucleus/compare/v.0.2.0...v.0.2.1 [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 diff --git a/NUCLEUSinv/NUCLEUSinv.m b/NUCLEUSinv/NUCLEUSinv.m index 3e75c63..674a4cc 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.2.1'; -myui.date = '11.02.2024'; +myui.version = '0.3.0'; +myui.date = '27.11.2024'; myui.author = {'Stephan Costabel','Thomas Hiller'}; myui.email = 'thomas.hiller[at]bgr.de'; myui.fontsize = 10; @@ -68,6 +68,7 @@ data.uncert = defaults.uncert; data.calib = defaults.calib; data.invjoint = defaults.invjoint; +data.inv2D = defaults.inv2D; data.pressure = defaults.pressure; gui.myui = myui; diff --git a/NUCLEUSinv/NUCLEUSinv_createMenus.m b/NUCLEUSinv/NUCLEUSinv_createMenus.m index 465e9a4..7a3658e 100644 --- a/NUCLEUSinv/NUCLEUSinv_createMenus.m +++ b/NUCLEUSinv/NUCLEUSinv_createMenus.m @@ -48,88 +48,108 @@ gui.menu.file_import_lab = uimenu(gui.menu.file_import,... 'Label','Lab'); -% 1.1.1.1 BAM +% 1.1.1.1 AARHUS +gui.menu.file_import_lab_aarhus = uimenu(gui.menu.file_import_lab,... + 'Label','AARHUS'); +% 1.1.1.1.1 AARHUS Dart T1T2 +gui.menu.file_import_lab_aarhus_dartT1T2 = uimenu(gui.menu.file_import_lab_aarhus,... + 'Label','Dart T1T2','Tag','Lab','Callback',@onMenuImport); +% 1.1.1.1.2 AARHUS Dart T2 logging +gui.menu.file_import_lab_aarhus_dartT2 = uimenu(gui.menu.file_import_lab_aarhus,... + 'Label','Dart T2 logging','Tag','Lab','Callback',@onMenuImport); + +% 1.1.1.2 BAM gui.menu.file_import_lab_bam = uimenu(gui.menu.file_import_lab,... 'Label','BAM'); -% 1.1.1.1.1 BAM TOM +% 1.1.1.2.1 BAM TOM gui.menu.file_import_lab_bam_tom = uimenu(gui.menu.file_import_lab_bam,... 'Label','BAM TOM','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.2 BGR +% 1.1.1.3 BGR gui.menu.file_import_lab_bgr = uimenu(gui.menu.file_import_lab,... 'Label','BGR'); -% 1.1.1.2.1 BGR std +% 1.1.1.3.1 BGR std gui.menu.file_import_lab_bgr_std = uimenu(gui.menu.file_import_lab_bgr,... 'Label','BGR std','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.2.2 BGR mat +% 1.1.1.3.2 BGR mat gui.menu.file_import_lab_bgr_mat = uimenu(gui.menu.file_import_lab_bgr,... 'Label','BGR mat','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.2.3 Mouse CPMG data, single data subfolders from CPMG +% 1.1.1.3.3 Mouse CPMG data, single data subfolders from CPMG gui.menu.file_import_lab_bgr_mouse_cpmg = uimenu(gui.menu.file_import_lab_bgr,... 'Label','MouseCPMG','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.2.4 Mouse plus Lift, all data subfolders from t1test,... +% 1.1.1.3.4 Mouse plus Lift, all data subfolders from t1test,... % cpmgfastautotest, or (old Prospa Versions) cpmgfastauto gui.menu.file_import_lab_bgr_mouse_lift = uimenu(gui.menu.file_import_lab_bgr,... 'Label','MouseLift','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.2.5 Helios CPMG standard data, single subfolders with individual data files +% 1.1.1.3.5 Helios CPMG standard data, single subfolders with individual data files gui.menu.file_import_lab_bgr_helios_cpmg = uimenu(gui.menu.file_import_lab_bgr,... 'Label','HeliosCPMG','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.2.6 Helios series of CPMG data, several files of a series in the target +% 1.1.1.3.6 Helios series of CPMG data, several files of a series in the target % folder, as used e.g. for T1 measurements gui.menu.file_import_lab_bgr_helios_series = uimenu(gui.menu.file_import_lab_bgr,... 'Label','HeliosSeries','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.3 LIAG +% 1.1.1.4 LIAG gui.menu.file_import_lab_liag = uimenu(gui.menu.file_import_lab,... 'Label','LIAG'); -% 1.1.1.3.1 LIAG +% 1.1.1.4.1 LIAG gui.menu.file_import_lab_liag_single = uimenu(gui.menu.file_import_lab_liag,... 'Label','LIAG single','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.3.2 LIAG +% 1.1.1.4.2 LIAG gui.menu.file_import_lab_liag_project = uimenu(gui.menu.file_import_lab_liag,... 'Label','LIAG from project','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.3.3 LIAG +% 1.1.1.4.3 LIAG gui.menu.file_import_lab_liag_core = uimenu(gui.menu.file_import_lab_liag,... 'Label','LIAG core','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.4 RWTH +% 1.1.1.5 RUTGERS +gui.menu.file_import_lab_rutgers = uimenu(gui.menu.file_import_lab,... + 'Label','RUTGERS'); +% 1.1.1.5.1 RUTGERS +gui.menu.file_import_lab_rutgers_T1T2 = uimenu(gui.menu.file_import_lab_rutgers,... + 'Label','RoCA T1T2','Tag','Lab','Callback',@onMenuImport); + +% 1.1.1.6 RWTH gui.menu.file_import_lab_rwth = uimenu(gui.menu.file_import_lab,... 'Label','RWTH'); -% 1.1.1.4.1 IBAC +% 1.1.1.6.1 IBAC gui.menu.file_import_lab_ibac = uimenu(gui.menu.file_import_lab_rwth,... 'Label','IBAC'); -% 1.1.1.4.1.1 IBAC +% 1.1.1.6.1.1 IBAC gui.menu.file_import_lab_ibac_pm5 = uimenu(gui.menu.file_import_lab_ibac,... 'Label','PM5','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.4.1.2 IBAC +% 1.1.1.6.1.2 IBAC gui.menu.file_import_lab_ibac_pm25 = uimenu(gui.menu.file_import_lab_ibac,... 'Label','PM25','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.4.2 GGE +% 1.1.1.6.2 GGE gui.menu.file_import_lab_gge = uimenu(gui.menu.file_import_lab_rwth,... 'Label','GGE'); -% 1.1.1.4.2.1 GGE ascii +% 1.1.1.6.2.1 GGE ascii gui.menu.file_import_lab_gge_ascii = uimenu(gui.menu.file_import_lab_gge,... 'Label','GGE ascii','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.4.2.2 GGE field +% 1.1.1.6.2.2 GGE field gui.menu.file_import_lab_gge_field = uimenu(gui.menu.file_import_lab_gge,... 'Label','GGE field','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.4.2.3 GGE Dart +% 1.1.1.6.2.3 GGE Dart gui.menu.file_import_lab_gge_dart = uimenu(gui.menu.file_import_lab_gge,... 'Label','GGE Dart','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.5 OTHER +% 1.1.1.7 OTHER gui.menu.file_import_lab_other = uimenu(gui.menu.file_import_lab,... 'Label','OTHER'); -% 1.1.1.5.1 CoreLab ascii +% 1.1.1.7.1 CoreLab ascii gui.menu.file_import_lab_corelab = uimenu(gui.menu.file_import_lab_other,... 'Label','CoreLab ascii','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.5.2 MOUSE +% 1.1.1.7.2 MOUSE gui.menu.file_import_lab_mouse = uimenu(gui.menu.file_import_lab_other,... 'Label','MOUSE','Tag','Lab','Callback',@onMenuImport); -% 1.1.1.5.3 DART (University of Vienna) +% 1.1.1.7.3 DART (University of Vienna) gui.menu.file_import_lab_dart = uimenu(gui.menu.file_import_lab_other,... 'Label','DART','Tag','Lab','Callback',@onMenuImport); +% 1.1.1.7.4 DART (incl. Burst echoes) +gui.menu.file_import_lab_dartburst = uimenu(gui.menu.file_import_lab_other,... + 'Label','DART (+Burst)','Tag','Lab','Callback',@onMenuImport); % 1.1.2 Ascii gui.menu.file_import_ascii = uimenu(gui.menu.file_import,... @@ -167,6 +187,9 @@ % 1.1.5.2 NUCLEUSmod from GUI gui.menu.file_import_nmrmod_gui = uimenu(gui.menu.file_import_nmrmod,.... 'Label','GUI','Tag','NUCLEUSmod','Callback',@onMenuImport); +% 1.1.5.3 NUCLEUSmod from 2D GUI +gui.menu.file_import_nmrmod_gui2d = uimenu(gui.menu.file_import_nmrmod,.... + 'Label','2D GUI','Tag','NUCLEUSmod2d','Callback',@onMenuImport); % 1.2 Export gui.menu.file_export = uimenu(gui.menu.file,... @@ -318,6 +341,9 @@ % 2.9 UncertaintyVIEW GUI gui.menu.extra_uncert = uimenu(gui.menu.view,... 'Label','UncertView GUI','Enable','off','Callback',@onMenuSubGUIs); +% 2.9 2DInv GUI +gui.menu.extra_T1T2map = uimenu(gui.menu.view,... + 'Label','2DInv GUI','Enable','off','Callback',@onMenuSubGUIs); %% 3. Extras gui.menu.extra = uimenu(gui.figh,... @@ -374,6 +400,11 @@ 'Label','Surface relaxivity bounds','Enable','off',... 'Callback',@onMenuExtraRhoBounds); +% 3.6 find duplicate data +gui.menu.extra_find_duplicates = uimenu(gui.menu.extra,... + 'Label','Find duplicate signals','Enable','on',... + 'Callback',@onMenuExtraFindDuplicates); + %% 4. Color theme gui.menu.color_theme = uimenu(gui.figh,... diff --git a/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m b/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m index ce5aab7..966a819 100644 --- a/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m +++ b/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.m @@ -184,7 +184,7 @@ 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]); +set(gui.panels.invstd.HBox7,'Widths',[200 -1 -2]); %% Java Hack to adjust vertical alignment of text fields jh = findjobj(gui.text_handles.invstd_InvType); diff --git a/NUCLEUSinv/NUCLEUSinv_loadDefaults.m b/NUCLEUSinv/NUCLEUSinv_loadDefaults.m index 4c53dc3..a3b8047 100644 --- a/NUCLEUSinv/NUCLEUSinv_loadDefaults.m +++ b/NUCLEUSinv/NUCLEUSinv_loadDefaults.m @@ -195,6 +195,65 @@ % corresponding scale factors - 1 | 1e-3 | 1e-6 | 1e-5 out.pressure.unitfac = 1; +%% 2D inversion GUI settings +% system / fluid properties +% diffusion coefficient [m²/s] +out.inv2D.prop.D = 2.025e-9; +% gradient [T/m] +out.inv2D.prop.G0 = 0; +% echo time [s] +out.inv2D.prop.te = 200e-6; +% start echo +out.inv2D.prop.first = 1; +% last echo +out.inv2D.prop.last = 1; + +% inversion settings +% IR/SR factor +out.inv2D.inv.T1IRfac = 2; +% IR kernel type (1 or 2) +out.inv2D.inv.IRtype = 1; +% T1 range minimum [s] +out.inv2D.inv.T1min = 1e-4; +% T1 range maximum [s] +out.inv2D.inv.T1max = 10; +% T1 number of points in range +out.inv2D.inv.T1N = 51; +% T2 range minimum [s] +out.inv2D.inv.T2min = 1e-4; +% T2 range maximum [s] +out.inv2D.inv.T2max = 10; +% T2 number of points in range +out.inv2D.inv.T2N = 51; +% T1 regularization parameter lambda +out.inv2D.inv.T1lambda = 5; +% T1 order of smoothness constraint +out.inv2D.inv.T1order = 1; +% T2 regularization parameter lambda +out.inv2D.inv.T2lambda = 2; +% T2 order of smoothness constraint +out.inv2D.inv.T2order = 1; + +% information settings / properties +% T1 minimum [s] +out.inv2D.info.T1min = 1e-3; +% T1 maximum [s] +out.inv2D.info.T1max = 1; +% T2 minimum [s] +out.inv2D.info.T2min = 1e-3; +% T2 minimum [s] +out.inv2D.info.T2max = 1; +% initial amplitude E0 [a.u.] +out.inv2D.info.E0 = 0; +% T1 log mean time +out.inv2D.info.T1tlgm = 0; +% T2 log mean time +out.inv2D.info.T2tlgm = 0; +% T1 maximum time +out.inv2D.info.T1tmax = 0; +% T2 maximum time +out.inv2D.info.T2tmax = 0; + return %------------- END OF CODE -------------- diff --git a/NUCLEUSmod/NUCLEUSmod.m b/NUCLEUSmod/NUCLEUSmod.m index 02e53b5..ccab327 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.2.1'; -myui.date = '11.02.2024'; +myui.version = '0.3.0'; +myui.date = '27.11.2024'; myui.author = {'Stephan Costabel','Thomas Hiller'}; myui.email = 'thomas.hiller[at]bgr.de'; myui.fontsize = 10; @@ -65,6 +65,7 @@ data.geometry = defaults.geometry; data.pressure = defaults.pressure; data.nmr = defaults.nmr; +data.mod2D = defaults.mod2D; gui.myui = myui; % save the data struct within the GUI diff --git a/NUCLEUSmod/NUCLEUSmod_createMenus.m b/NUCLEUSmod/NUCLEUSmod_createMenus.m index 34b7dd8..f20907a 100644 --- a/NUCLEUSmod/NUCLEUSmod_createMenus.m +++ b/NUCLEUSmod/NUCLEUSmod_createMenus.m @@ -99,9 +99,13 @@ % 2.2 Figure Toolbar gui.menu.view_toolbar = uimenu(gui.menu.view,... 'Label','Figure Toolbar','Callback',@onMenuView); -% 2.3 hydraulic conductivity +% 2.3 2D modelling GUI +gui.menu.view_2dmod = uimenu(gui.menu.view,... + 'Label','2DMod GUI','Separator','on','Enable','on',... + 'Callback',@onMenuSubGUIs); +% 2.4 hydraulic conductivity gui.menu.view_conduct = uimenu(gui.menu.view,... - 'Label','ConductView GUI','Separator','on','Enable','off',... + 'Label','ConductView GUI','Enable','off',... 'Callback',@onMenuSubGUIs); %% 3. Color theme diff --git a/NUCLEUSmod/NUCLEUSmod_createPanelNMR.m b/NUCLEUSmod/NUCLEUSmod_createPanelNMR.m index 4c707ad..95b2d2a 100644 --- a/NUCLEUSmod/NUCLEUSmod_createPanelNMR.m +++ b/NUCLEUSmod/NUCLEUSmod_createPanelNMR.m @@ -114,7 +114,6 @@ set(gui.panels.nmr.HBox3,'Widths',[200 -1]); %% noise & porosity - tstr = ['NMR data noise method.

',... 'A noise level will be used globally for all NMR signals.
',... 'A signal-to-ratio will be used individually on every single NMR signal.

',... diff --git a/NUCLEUSmod/NUCLEUSmod_loadDefaults.m b/NUCLEUSmod/NUCLEUSmod_loadDefaults.m index 28050d7..eab5cb5 100644 --- a/NUCLEUSmod/NUCLEUSmod_loadDefaults.m +++ b/NUCLEUSmod/NUCLEUSmod_loadDefaults.m @@ -92,6 +92,57 @@ % use linear y-axes as default (log=1, lin=2) out.nmr.logliny = 2; +%% 2D settings +% system / fluid properties +% diffusion coefficient [m²/s] +out.mod2D.prop.D = 2.025e-9; +% gradient [T/m] +out.mod2D.prop.G0 = 0; +% echo time [s] +out.mod2D.prop.te = 0; +% bulk relaxation [s] +out.mod2D.prop.Tbulk = 1e6; + +% model space settings +% 2D type +out.mod2D.mod.type = 'T1T2'; +% T1 range minimum [s] +out.mod2D.mod.T1min = 1e-4; +% T1 range maximum [s] +out.mod2D.mod.T1max = 10; +% T1 number of points in range +out.mod2D.mod.T1N = 151; +% T2 range minimum [s] +out.mod2D.mod.T2min = 1e-4; +% T2 range maximum [s] +out.mod2D.mod.T2max = 10; +% T2 number of points in range +out.mod2D.mod.T2N = 151; + +% number of 2D distribution +out.mod2D.mod.Ndist = 3; +% center point of 2D distribution +out.mod2D.mod.mu = [1 1;0.01 0.03;0.5 0.005]; +% covariance matrix of 2D distribution +out.mod2D.mod.sigma{1} = [0.1 0;0 0.1]; +out.mod2D.mod.sigma{2} = [0.2 0.3;0 0.2]; +out.mod2D.mod.sigma{3} = [0.3 0;0 0.01]; +% amplitude of 2D distribution +out.mod2D.mod.amp = [1 1 1]; + +% NMR data +out.mod2D.nmr.T1IRfac = 2; +out.mod2D.nmr.IRtype = 1; +out.mod2D.nmr.T1trmin = 1e-3; +out.mod2D.nmr.T1trmax = 1; +out.mod2D.nmr.T1trN = 21; +out.mod2D.nmr.T2te = 200e-6; +out.mod2D.nmr.T2teN = 500; +% noise creation type 'level' or 'SNR' +out.mod2D.nmr.noisetype = 'level'; +% noise level [0:1] or SNR [-] +out.mod2D.nmr.noise = 0; + return %------------- END OF CODE -------------- diff --git a/README.md b/README.md index 0b71eaa..100aae5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # NUCLEUS -BLOCHUS icon +NUCLEUS logo modeling and i**N**version of n**UCL**ear magnetic r**E**sonance data with ang**U**lar pore**S** @@ -31,20 +31,30 @@ modeling and i**N**version of n**UCL**ear magnetic r**E**sonance data with ang** 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 3. Based on the different saturation levels along the CPSC, calculate the corresponding geometry-dependent forward NMR signals +4. 2D forward modeling of T1-T2 data + +|
![nucleusmod](images/nucleusmod_gui.png)
|
![nucleusmod2d](images/2dmod_gui.png)
| +|:-------------------------------------------------------------------:|:-------------------------------------------------------------:| +| NUCLEUSmod | NUCLEUSmod - 2D (T1-T2) | -NUCLEUSmod ### 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) +3. Simple pre-processing of NMR signals (cutting, gating, normalizing, phasing) 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) +7. 2D inversion of T1-T2 data + +|
![nucleusinv](images/nucleusinv_gui.png)
|
![nucleusinv2d](images/2dinv_gui.png)
| +|:-------------------------------------------------------------------:|:--------------------------------------------------------------:| +| NUCLEUSinv | NUCLEUSinv - 2D (T1-T2) | +|
![uncert](images/uncertview_gui.png)
|
![phaseview](images/phaseview_gui.png)
| +| NUCLEUSinv - RTD Uncertainty View | NUCLEUSinv - Phase View | -NUCLEUSinv UncertView - - - @@ -53,7 +63,7 @@ modeling and i**N**version of n**UCL**ear magnetic r**E**sonance data with ang** 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) +1. The [Mathworks](https://www.mathworks.com) MATLABTM software development environment (tested with R2016b and newer) - 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) @@ -62,6 +72,7 @@ In order to work properly you need to meet the following requirements: 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; not needed for R2023b and newer) +8. `imagescnan` (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/20516-imagescnan-m-v2-1-aug-2009)) (optional; only needed for the 2D inversion) 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. @@ -123,17 +134,20 @@ In no particular order and without guarantee that it will ever happen :-) : ## Cite as If you use NUCLEUS for your research, please cite it as: -Thomas Hiller. (2024, Feb 11). ThoHiller/nmr-nucleus: v0.2.1 (Version v0.2.1). Zenodo. [https://doi.org/10.5281/zenodo.4022195] +Thomas Hiller. (2024, Nov 27). ThoHiller/nmr-nucleus: v0.3.0 (Version v0.3.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 -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) -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) +1. Lorenzoni,R., Cunningham, P., Fritsch, T., Schmidt, W., Kruschwitz, S. and Bruno, G. "Microstructure analysis of cement-biochar composites", *Materials and Structures*, **57**, 2024, 175, [DOI](https://doi.org/10.1617/s11527-024-02452-5) +2. Kruschwitz, S., Munsch, S., Telong, M., Schmidt, W., Bintz, T., Fladt, M. and Stelzner, L., "The NMR core analyzing tomograph: a multi-functional tool for non-destructive testing of building materials", *Magnetic Resonance Letters*. **3**(3), 2023, 207-219, [DOI](https://doi.org/10.1016/j.mrl.2023.03.004) +3. 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) +4. 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) +5. Munsch, S., Bintz, T., Heyn, R., Hirsch, H., Grunewald, J. and Kruschwitz, S., "Detailed investigation of capillary active insulation materials by 1H nuclear magnetic resonance (NMR) and thermogravimetric drying", International Symposium on Non-Destructive Testing in Civil Engineering (NDT-CE 2022), 16-18 August 2022, Zurich, Switzerland, *e-Journal of Nondestructive Testing*, **27**(9), [DOI](https://doi.org/10.58286/27205) +6. 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) +7. 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) +8. 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) - - - diff --git a/callbacks/contextmenus/onContextAxisLogLin.m b/callbacks/contextmenus/onContextAxisLogLin.m index 5911082..c7f170a 100644 --- a/callbacks/contextmenus/onContextAxisLogLin.m +++ b/callbacks/contextmenus/onContextAxisLogLin.m @@ -38,11 +38,9 @@ function onContextAxisLogLin(src,~) % get the label of the context menu label = get(src,'Label'); -% get the tag of the context menu -tag = get(src,'Tag'); % change the label depending on the current status -if ~isempty(strfind(label,'log')) % current axis is lin -> switch to log +if contains(label,'log') % current axis is lin -> switch to log label = strrep(label,'log','lin'); else % current axis is log -> switch to lin label = strrep(label,'lin','log'); diff --git a/callbacks/listboxes/onListboxData.m b/callbacks/listboxes/onListboxData.m index d2cad8d..061f8a5 100644 --- a/callbacks/listboxes/onListboxData.m +++ b/callbacks/listboxes/onListboxData.m @@ -192,6 +192,8 @@ function onListboxData(src,~) % reset all RUN buttons set(gui.push_handles.invstd_run,'String','RUN',... 'BackgroundColor','g','Enable','on','Callback',@onPushRun); + set(gui.push_handles.uncert,'String','CALC.',... + 'BackgroundColor','g','Enable','on','Callback',@onPushRun); set(gui.push_handles.invjoint_run,'String','RUN',... 'BackgroundColor','g','Enable','on','Callback',@onPushRun); diff --git a/callbacks/menus/onMenuExpert.m b/callbacks/menus/onMenuExpert.m index 53273b3..0b9b80e 100644 --- a/callbacks/menus/onMenuExpert.m +++ b/callbacks/menus/onMenuExpert.m @@ -72,6 +72,12 @@ function onMenuExpert(src,~) delete(fig_uncert); end set(gui.menu.extra_uncert,'Enable','off'); + % check if the figure is already open + fig_T1T2map = findobj('Tag','T1T2MAP'); + if ~isempty(fig_T1T2map) + delete(fig_T1T2map); + end + set(gui.menu.extra_T1T2map,'Enable','off'); % deactivate solver menu and set to default onMenuSolver(gui.menu.extra_solver_lsqnonneg); @@ -109,6 +115,8 @@ function onMenuExpert(src,~) set(gui.menu.extra_fixedtime,'Enable','on'); % activate Uncertainty View GUI set(gui.menu.extra_uncert,'Enable','on'); + % activate T1T2map GUI + set(gui.menu.extra_T1T2map,'Enable','on'); % activate solver menu if optimization toolbox is available switch data.info.has_optim diff --git a/callbacks/menus/onMenuExtraFindDuplicates.m b/callbacks/menus/onMenuExtraFindDuplicates.m new file mode 100644 index 0000000..64a204a --- /dev/null +++ b/callbacks/menus/onMenuExtraFindDuplicates.m @@ -0,0 +1,158 @@ +function onMenuExtraFindDuplicates(src,~) +%onMenuExtraFindDuplicates finds duplicate NMR signals (mostly a HELIOS issue) +% +% Syntax: +% onMenuExtraFindDuplicates(src,~) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onMenuExtraFindDuplicates(src) +% +% Other m-files required: +% none +% +% 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 = ancestor(src,'figure','toplevel'); +gui = getappdata(fig,'gui'); +data = getappdata(fig,'data'); +INVdata = getappdata(fig,'INVdata'); + +hasData = false; +if isfield(data.import,'NMR') + hasData = true; +end + +if hasData + + %% 1. before we do anything, sort the data by date (time) + time = zeros(numel(data.import.NMR.filesShort),1); + timestamp = zeros(numel(data.import.NMR.filesShort),1); + for i = 1:numel(data.import.NMR.filesShort) + time(i,1) = data.import.NMR.data{i}.datenum; + timestamp(i,1) = data.import.NMR.para{i}.timestamp; + end + [~,ix] = sort(time); + % now apply changes - resort the imported data + data.import.NMR.data = {data.import.NMR.data{ix'}}; %#ok<*CCAT1> + data.import.NMR.para = {data.import.NMR.para{ix'}}; + data.import.NMR.files = data.import.NMR.files(ix); + data.import.NMR.filesShort = {data.import.NMR.filesShort{ix'}}; + % the timestamps can also indicate duplicate signals + timestamp = timestamp(ix); + dts = [0; diff(timestamp)]; + % and resort possible already stored inversion data + INVdata = {INVdata{ix(:)}}'; + % update the listbox entries + shownames = get(gui.listbox_handles.signal,'String'); + set(gui.listbox_handles.signal,'String',{shownames{ix}}); + set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); + + %% 2. checking starts at the second signal + dup_ids = zeros(1,1); + keep_ids = 1:1:numel(data.import.NMR.data); + keep_ids = keep_ids(:); + c = 0; + for i1 = 2:numel(data.import.NMR.data) + + s0 = data.import.NMR.data{i1-1}.signal; + s1 = data.import.NMR.data{i1}.signal; + + if s0==s1 + c = c + 1; + dup_ids(c,1) = i1; + keep_ids(keep_ids == i1) = []; + end + end + % if we found something, ask what to do + if sum(dup_ids) > 0 + answer = questdlg('What to do with the duplicate signals?',... + 'Duplicates Found',... + 'Keep & Mark','Delete','Nothing','Delete'); + switch answer + case 'Keep & Mark' + shownames = data.import.NMR.filesShort; + for i1 = 1:numel(dup_ids) + shownames{dup_ids(i1)} = [shownames{dup_ids(i1)},'_dup']; + end + data.import.NMR.filesShort = shownames; + set(gui.listbox_handles.signal,'String',shownames); + set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); + + msgbox([num2str(numel(dup_ids)),... + ' signals have been marked as duplicate.']); + + case 'Delete' + ix = keep_ids; + data.import.NMR.data = {data.import.NMR.data{ix'}}; %#ok<*CCAT1> + data.import.NMR.para = {data.import.NMR.para{ix'}}; + data.import.NMR.files = data.import.NMR.files(ix); + data.import.NMR.filesShort = {data.import.NMR.filesShort{ix'}}; + % and resort possible already stored inversion data + INVdata = {INVdata{ix(:)}}'; + + % update the listbox entries + shownames = get(gui.listbox_handles.signal,'String'); + set(gui.listbox_handles.signal,'String',{shownames{ix}}); + set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); + + msgbox([num2str(numel(dup_ids)),' signals have been deleted.']); + + case 'Nothing' + end + else + msgbox('No duplicate signals have been found.'); + end + + % update the GUI data + setappdata(fig,'data',data); + setappdata(fig,'INVdata',INVdata); + +else + helpdlg('Nothing to do because there is no data loaded!',... + 'onMenuExtraFindDuplicates: Load NMR data first.'); +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/callbacks/menus/onMenuImport.m b/callbacks/menus/onMenuImport.m index 4114d12..8ba8276 100644 --- a/callbacks/menus/onMenuImport.m +++ b/callbacks/menus/onMenuImport.m @@ -54,7 +54,9 @@ function onMenuImport(src,~) case 'NUCLEUSinv' importINV2INV(src); case 'NUCLEUSmod' - importMOD2INV(src); + importMOD2INV(src); + case 'NUCLEUSmod2d' + importMOD2D2INV(src); case 'Excel' importEXCELdata(src); case 'Ascii' diff --git a/callbacks/menus/onMenuSubGUIs.m b/callbacks/menus/onMenuSubGUIs.m index f4bfd9a..edbd2d9 100644 --- a/callbacks/menus/onMenuSubGUIs.m +++ b/callbacks/menus/onMenuSubGUIs.m @@ -84,6 +84,16 @@ function onMenuSubGUIs(src,~) 'Cannot continue because there is no data!'},... 'No inversion data.'); end + case '2DInv GUI' + if isfield(data.import,'T1T2map') + Inv2DView(src); + else + helpdlg({'function: Inv2DView',... + 'Cannot continue because there is no data!'},... + 'No T1T2 data.'); + end + case '2DMod GUI' + Mod2DView(src); end end diff --git a/callbacks/menus/onMenuView.m b/callbacks/menus/onMenuView.m index 74e949e..80e7341 100644 --- a/callbacks/menus/onMenuView.m +++ b/callbacks/menus/onMenuView.m @@ -43,7 +43,7 @@ function onMenuView(src,~) onoff = lower(get(src,'Checked')); switch fig_tag - + case 'INV' switch label case 'Tooltips' @@ -60,7 +60,7 @@ function onMenuView(src,~) % update ini-file gui.myui.inidata.tooltips = data.info.ToolTips; gui = makeINIfile(gui,'update'); - + case 'Figure Toolbar' % switch on/off the default Figure Toolbar switch onoff case 'on' % it it's on, switch it off @@ -70,7 +70,7 @@ function onMenuView(src,~) set(gui.menu.view_toolbar,'Checked','on'); viewmenufcn('FigureToolbar'); end - + case 'INFO fields' switch onoff case 'on' % it it's on, switch it off @@ -79,7 +79,7 @@ function onMenuView(src,~) set(gui.push_handles.info,'String','<'); end onPushShowHide(gui.push_handles.info); - + case 'CLI Inv. Info' switch onoff case 'on' % it it's on, switch it off @@ -93,7 +93,20 @@ function onMenuView(src,~) gui.myui.inidata.invinfo = data.info.InvInfo; gui = makeINIfile(gui,'update'); end - + + case {'2DINV','PHASEVIEW','UNCERTVIEW','CONDUCT'} + switch label + case 'Figure Toolbar' % switch on/off the default Figure Toolbar + switch onoff + case 'on' % it it's on, switch it off + set(gui.menu.view_toolbar,'Checked','off'); + viewmenufcn('FigureToolbar'); + case 'off' + set(gui.menu.view_toolbar,'Checked','on'); + viewmenufcn('FigureToolbar'); + end + end + case 'MOD' switch label case 'Tooltips' @@ -117,6 +130,18 @@ function onMenuView(src,~) viewmenufcn('FigureToolbar'); end end + case '2DMOD' + switch label + case 'Figure Toolbar' % switch on/off the default Figure Toolbar + switch onoff + case 'on' % it it's on, switch it off + set(gui.menu.view_toolbar,'Checked','off'); + viewmenufcn('FigureToolbar'); + case 'off' + set(gui.menu.view_toolbar,'Checked','on'); + viewmenufcn('FigureToolbar'); + end + end end % update GUI data diff --git a/doc/menu.html b/doc/menu.html index 51000b8..a03b14a 100644 --- a/doc/menu.html +++ b/doc/menu.html @@ -16,7 +16,7 @@

Matlab Index

Matlab Directories

- +
Generated by m2html © 2005
diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv.html index ed81de1..5890d3d 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.2.1'; -0042 myui.date = '11.02.2024'; +0041 myui.version = '0.3.0'; +0042 myui.date = '27.11.2024'; 0043 myui.author = {'Stephan Costabel','Thomas Hiller'}; 0044 myui.email = 'thomas.hiller[at]bgr.de'; 0045 myui.fontsize = 10; @@ -141,55 +141,56 @@

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

    SOURCE CODE ^... 0049 'Label','Lab'); 0050 -0051 % 1.1.1.1 BAM -0052 gui.menu.file_import_lab_bam = uimenu(gui.menu.file_import_lab,... -0053 'Label','BAM'); -0054 % 1.1.1.1.1 BAM TOM -0055 gui.menu.file_import_lab_bam_tom = uimenu(gui.menu.file_import_lab_bam,... -0056 'Label','BAM TOM','Tag','Lab','Callback',@onMenuImport); -0057 -0058 % 1.1.1.2 BGR -0059 gui.menu.file_import_lab_bgr = uimenu(gui.menu.file_import_lab,... -0060 'Label','BGR'); -0061 % 1.1.1.2.1 BGR std -0062 gui.menu.file_import_lab_bgr_std = uimenu(gui.menu.file_import_lab_bgr,... -0063 'Label','BGR std','Tag','Lab','Callback',@onMenuImport); -0064 % 1.1.1.2.2 BGR mat -0065 gui.menu.file_import_lab_bgr_mat = uimenu(gui.menu.file_import_lab_bgr,... -0066 'Label','BGR mat','Tag','Lab','Callback',@onMenuImport); -0067 % 1.1.1.2.3 Mouse CPMG data, single data subfolders from CPMG -0068 gui.menu.file_import_lab_bgr_mouse_cpmg = uimenu(gui.menu.file_import_lab_bgr,... -0069 'Label','MouseCPMG','Tag','Lab','Callback',@onMenuImport); -0070 % 1.1.1.2.4 Mouse plus Lift, all data subfolders from t1test,... -0071 % cpmgfastautotest, or (old Prospa Versions) cpmgfastauto -0072 gui.menu.file_import_lab_bgr_mouse_lift = uimenu(gui.menu.file_import_lab_bgr,... -0073 'Label','MouseLift','Tag','Lab','Callback',@onMenuImport); -0074 % 1.1.1.2.5 Helios CPMG standard data, single subfolders with individual data files -0075 gui.menu.file_import_lab_bgr_helios_cpmg = uimenu(gui.menu.file_import_lab_bgr,... -0076 'Label','HeliosCPMG','Tag','Lab','Callback',@onMenuImport); -0077 % 1.1.1.2.6 Helios series of CPMG data, several files of a series in the target -0078 % folder, as used e.g. for T1 measurements -0079 gui.menu.file_import_lab_bgr_helios_series = uimenu(gui.menu.file_import_lab_bgr,... -0080 'Label','HeliosSeries','Tag','Lab','Callback',@onMenuImport); -0081 -0082 % 1.1.1.3 LIAG -0083 gui.menu.file_import_lab_liag = uimenu(gui.menu.file_import_lab,... -0084 'Label','LIAG'); -0085 % 1.1.1.3.1 LIAG -0086 gui.menu.file_import_lab_liag_single = uimenu(gui.menu.file_import_lab_liag,... -0087 'Label','LIAG single','Tag','Lab','Callback',@onMenuImport); -0088 % 1.1.1.3.2 LIAG -0089 gui.menu.file_import_lab_liag_project = uimenu(gui.menu.file_import_lab_liag,... -0090 'Label','LIAG from project','Tag','Lab','Callback',@onMenuImport); -0091 % 1.1.1.3.3 LIAG -0092 gui.menu.file_import_lab_liag_core = uimenu(gui.menu.file_import_lab_liag,... -0093 'Label','LIAG core','Tag','Lab','Callback',@onMenuImport); -0094 -0095 % 1.1.1.4 RWTH -0096 gui.menu.file_import_lab_rwth = uimenu(gui.menu.file_import_lab,... -0097 'Label','RWTH'); -0098 % 1.1.1.4.1 IBAC -0099 gui.menu.file_import_lab_ibac = uimenu(gui.menu.file_import_lab_rwth,... -0100 'Label','IBAC'); -0101 % 1.1.1.4.1.1 IBAC -0102 gui.menu.file_import_lab_ibac_pm5 = uimenu(gui.menu.file_import_lab_ibac,... -0103 'Label','PM5','Tag','Lab','Callback',@onMenuImport); -0104 % 1.1.1.4.1.2 IBAC -0105 gui.menu.file_import_lab_ibac_pm25 = uimenu(gui.menu.file_import_lab_ibac,... -0106 'Label','PM25','Tag','Lab','Callback',@onMenuImport); -0107 -0108 % 1.1.1.4.2 GGE -0109 gui.menu.file_import_lab_gge = uimenu(gui.menu.file_import_lab_rwth,... -0110 'Label','GGE'); -0111 % 1.1.1.4.2.1 GGE ascii -0112 gui.menu.file_import_lab_gge_ascii = uimenu(gui.menu.file_import_lab_gge,... -0113 'Label','GGE ascii','Tag','Lab','Callback',@onMenuImport); -0114 % 1.1.1.4.2.2 GGE field -0115 gui.menu.file_import_lab_gge_field = uimenu(gui.menu.file_import_lab_gge,... -0116 'Label','GGE field','Tag','Lab','Callback',@onMenuImport); -0117 % 1.1.1.4.2.3 GGE Dart -0118 gui.menu.file_import_lab_gge_dart = uimenu(gui.menu.file_import_lab_gge,... -0119 'Label','GGE Dart','Tag','Lab','Callback',@onMenuImport); -0120 -0121 % 1.1.1.5 OTHER -0122 gui.menu.file_import_lab_other = uimenu(gui.menu.file_import_lab,... -0123 'Label','OTHER'); -0124 % 1.1.1.5.1 CoreLab ascii -0125 gui.menu.file_import_lab_corelab = uimenu(gui.menu.file_import_lab_other,... -0126 'Label','CoreLab ascii','Tag','Lab','Callback',@onMenuImport); -0127 % 1.1.1.5.2 MOUSE -0128 gui.menu.file_import_lab_mouse = uimenu(gui.menu.file_import_lab_other,... -0129 'Label','MOUSE','Tag','Lab','Callback',@onMenuImport); -0130 % 1.1.1.5.3 DART (University of Vienna) -0131 gui.menu.file_import_lab_dart = uimenu(gui.menu.file_import_lab_other,... -0132 'Label','DART','Tag','Lab','Callback',@onMenuImport); -0133 -0134 % 1.1.2 Ascii -0135 gui.menu.file_import_ascii = uimenu(gui.menu.file_import,... -0136 'Label','Ascii'); -0137 % 1.1.2.1 T1 -0138 gui.menu.file_import_lab_ascii_T1 = uimenu(gui.menu.file_import_ascii,... -0139 'Label','T1','Tag','Ascii','Callback',@onMenuImport); -0140 % 1.1.2.2 T2 -0141 gui.menu.file_import_lab_ascii_T2 = uimenu(gui.menu.file_import_ascii,... -0142 'Label','T2','Tag','Ascii','Callback',@onMenuImport); -0143 -0144 % 1.1.3 Excel -0145 gui.menu.file_import_excel = uimenu(gui.menu.file_import,... -0146 'Label','Excel'); -0147 % 1.1.3.1 T1 -0148 gui.menu.file_import_lab_excel_T1 = uimenu(gui.menu.file_import_excel,... -0149 'Label','T1','Tag','Excel','Callback',@onMenuImport); -0150 % 1.1.3.2 T2 -0151 gui.menu.file_import_lab_excel_T2 = uimenu(gui.menu.file_import_excel,... -0152 'Label','T2','Tag','Excel','Callback',@onMenuImport); +0051 % 1.1.1.1 AARHUS +0052 gui.menu.file_import_lab_aarhus = uimenu(gui.menu.file_import_lab,... +0053 'Label','AARHUS'); +0054 % 1.1.1.1.1 AARHUS Dart T1T2 +0055 gui.menu.file_import_lab_aarhus_dartT1T2 = uimenu(gui.menu.file_import_lab_aarhus,... +0056 'Label','Dart T1T2','Tag','Lab','Callback',@onMenuImport); +0057 % 1.1.1.1.2 AARHUS Dart T2 logging +0058 gui.menu.file_import_lab_aarhus_dartT2 = uimenu(gui.menu.file_import_lab_aarhus,... +0059 'Label','Dart T2 logging','Tag','Lab','Callback',@onMenuImport); +0060 +0061 % 1.1.1.2 BAM +0062 gui.menu.file_import_lab_bam = uimenu(gui.menu.file_import_lab,... +0063 'Label','BAM'); +0064 % 1.1.1.2.1 BAM TOM +0065 gui.menu.file_import_lab_bam_tom = uimenu(gui.menu.file_import_lab_bam,... +0066 'Label','BAM TOM','Tag','Lab','Callback',@onMenuImport); +0067 +0068 % 1.1.1.3 BGR +0069 gui.menu.file_import_lab_bgr = uimenu(gui.menu.file_import_lab,... +0070 'Label','BGR'); +0071 % 1.1.1.3.1 BGR std +0072 gui.menu.file_import_lab_bgr_std = uimenu(gui.menu.file_import_lab_bgr,... +0073 'Label','BGR std','Tag','Lab','Callback',@onMenuImport); +0074 % 1.1.1.3.2 BGR mat +0075 gui.menu.file_import_lab_bgr_mat = uimenu(gui.menu.file_import_lab_bgr,... +0076 'Label','BGR mat','Tag','Lab','Callback',@onMenuImport); +0077 % 1.1.1.3.3 Mouse CPMG data, single data subfolders from CPMG +0078 gui.menu.file_import_lab_bgr_mouse_cpmg = uimenu(gui.menu.file_import_lab_bgr,... +0079 'Label','MouseCPMG','Tag','Lab','Callback',@onMenuImport); +0080 % 1.1.1.3.4 Mouse plus Lift, all data subfolders from t1test,... +0081 % cpmgfastautotest, or (old Prospa Versions) cpmgfastauto +0082 gui.menu.file_import_lab_bgr_mouse_lift = uimenu(gui.menu.file_import_lab_bgr,... +0083 'Label','MouseLift','Tag','Lab','Callback',@onMenuImport); +0084 % 1.1.1.3.5 Helios CPMG standard data, single subfolders with individual data files +0085 gui.menu.file_import_lab_bgr_helios_cpmg = uimenu(gui.menu.file_import_lab_bgr,... +0086 'Label','HeliosCPMG','Tag','Lab','Callback',@onMenuImport); +0087 % 1.1.1.3.6 Helios series of CPMG data, several files of a series in the target +0088 % folder, as used e.g. for T1 measurements +0089 gui.menu.file_import_lab_bgr_helios_series = uimenu(gui.menu.file_import_lab_bgr,... +0090 'Label','HeliosSeries','Tag','Lab','Callback',@onMenuImport); +0091 +0092 % 1.1.1.4 LIAG +0093 gui.menu.file_import_lab_liag = uimenu(gui.menu.file_import_lab,... +0094 'Label','LIAG'); +0095 % 1.1.1.4.1 LIAG +0096 gui.menu.file_import_lab_liag_single = uimenu(gui.menu.file_import_lab_liag,... +0097 'Label','LIAG single','Tag','Lab','Callback',@onMenuImport); +0098 % 1.1.1.4.2 LIAG +0099 gui.menu.file_import_lab_liag_project = uimenu(gui.menu.file_import_lab_liag,... +0100 'Label','LIAG from project','Tag','Lab','Callback',@onMenuImport); +0101 % 1.1.1.4.3 LIAG +0102 gui.menu.file_import_lab_liag_core = uimenu(gui.menu.file_import_lab_liag,... +0103 'Label','LIAG core','Tag','Lab','Callback',@onMenuImport); +0104 +0105 % 1.1.1.5 RUTGERS +0106 gui.menu.file_import_lab_rutgers = uimenu(gui.menu.file_import_lab,... +0107 'Label','RUTGERS'); +0108 % 1.1.1.5.1 RUTGERS +0109 gui.menu.file_import_lab_rutgers_T1T2 = uimenu(gui.menu.file_import_lab_rutgers,... +0110 'Label','RoCA T1T2','Tag','Lab','Callback',@onMenuImport); +0111 +0112 % 1.1.1.6 RWTH +0113 gui.menu.file_import_lab_rwth = uimenu(gui.menu.file_import_lab,... +0114 'Label','RWTH'); +0115 % 1.1.1.6.1 IBAC +0116 gui.menu.file_import_lab_ibac = uimenu(gui.menu.file_import_lab_rwth,... +0117 'Label','IBAC'); +0118 % 1.1.1.6.1.1 IBAC +0119 gui.menu.file_import_lab_ibac_pm5 = uimenu(gui.menu.file_import_lab_ibac,... +0120 'Label','PM5','Tag','Lab','Callback',@onMenuImport); +0121 % 1.1.1.6.1.2 IBAC +0122 gui.menu.file_import_lab_ibac_pm25 = uimenu(gui.menu.file_import_lab_ibac,... +0123 'Label','PM25','Tag','Lab','Callback',@onMenuImport); +0124 +0125 % 1.1.1.6.2 GGE +0126 gui.menu.file_import_lab_gge = uimenu(gui.menu.file_import_lab_rwth,... +0127 'Label','GGE'); +0128 % 1.1.1.6.2.1 GGE ascii +0129 gui.menu.file_import_lab_gge_ascii = uimenu(gui.menu.file_import_lab_gge,... +0130 'Label','GGE ascii','Tag','Lab','Callback',@onMenuImport); +0131 % 1.1.1.6.2.2 GGE field +0132 gui.menu.file_import_lab_gge_field = uimenu(gui.menu.file_import_lab_gge,... +0133 'Label','GGE field','Tag','Lab','Callback',@onMenuImport); +0134 % 1.1.1.6.2.3 GGE Dart +0135 gui.menu.file_import_lab_gge_dart = uimenu(gui.menu.file_import_lab_gge,... +0136 'Label','GGE Dart','Tag','Lab','Callback',@onMenuImport); +0137 +0138 % 1.1.1.7 OTHER +0139 gui.menu.file_import_lab_other = uimenu(gui.menu.file_import_lab,... +0140 'Label','OTHER'); +0141 % 1.1.1.7.1 CoreLab ascii +0142 gui.menu.file_import_lab_corelab = uimenu(gui.menu.file_import_lab_other,... +0143 'Label','CoreLab ascii','Tag','Lab','Callback',@onMenuImport); +0144 % 1.1.1.7.2 MOUSE +0145 gui.menu.file_import_lab_mouse = uimenu(gui.menu.file_import_lab_other,... +0146 'Label','MOUSE','Tag','Lab','Callback',@onMenuImport); +0147 % 1.1.1.7.3 DART (University of Vienna) +0148 gui.menu.file_import_lab_dart = uimenu(gui.menu.file_import_lab_other,... +0149 'Label','DART','Tag','Lab','Callback',@onMenuImport); +0150 % 1.1.1.7.4 DART (incl. Burst echoes) +0151 gui.menu.file_import_lab_dartburst = uimenu(gui.menu.file_import_lab_other,... +0152 'Label','DART (+Burst)','Tag','Lab','Callback',@onMenuImport); 0153 -0154 % 1.1.4 NUCLEUSinv -0155 gui.menu.file_import_nmrinv = uimenu(gui.menu.file_import,... -0156 'Label','NUCLEUSinv','Separator','on'); -0157 % 1.1.4.1 NUCLEUSinv session file -0158 gui.menu.file_import_nmrinv_file = uimenu(gui.menu.file_import_nmrinv,... -0159 'Label','Session','Tag','NUCLEUSinv','Callback',@onMenuImport); -0160 -0161 % 1.1.5 NUCLEUSmod -0162 gui.menu.file_import_nmrmod = uimenu(gui.menu.file_import,... -0163 'Label','NUCLEUSmod'); -0164 % 1.1.5.1 NUCLEUSmod from file -0165 gui.menu.file_import_nmrmod_file = uimenu(gui.menu.file_import_nmrmod,... -0166 'Label','File','Tag','NUCLEUSmod','Callback',@onMenuImport); -0167 % 1.1.5.2 NUCLEUSmod from GUI -0168 gui.menu.file_import_nmrmod_gui = uimenu(gui.menu.file_import_nmrmod,.... -0169 'Label','GUI','Tag','NUCLEUSmod','Callback',@onMenuImport); -0170 -0171 % 1.2 Export -0172 gui.menu.file_export = uimenu(gui.menu.file,... -0173 'Label','Export'); -0174 % 1.2.0 Last export -0175 lastexport = gui.myui.inidata.lastexport; -0176 gui.menu.file_export_lastexport = uimenu(gui.menu.file_export,... -0177 'Label',lastexport,'Callback',@onMenuExportData); -0178 % 1.2.1 Data -0179 gui.menu.file_export_data = uimenu(gui.menu.file_export,... -0180 'Label','Data'); -0181 % 1.2.1.1 GUI raw data mat-file -0182 gui.menu.file_export_data_GUImat = uimenu(gui.menu.file_export_data,... -0183 'Label','NUCLEUSinv (raw)','Callback',@onMenuExportData); -0184 % 1.2.1.2 GUI session mat-file -0185 gui.menu.file_export_data_GUImat = uimenu(gui.menu.file_export_data,... -0186 'Label','NUCLEUSinv (session)','Callback',@onMenuExportData); -0187 % 1.2.1.3 Inversion results single xls -0188 gui.menu.file_export_data_invstd_excel = uimenu(gui.menu.file_export_data,... -0189 'Label','EXCEL single (std)','Separator','on','Callback',@onMenuExportData); -0190 % 1.2.1.4 Inversion results single mat-file -0191 gui.menu.file_export_data_invstd_mat_single = uimenu(gui.menu.file_export_data,... -0192 'Label','MAT single (std)','Callback',@onMenuExportData); -0193 % 1.2.1.5 Inversion results all mat-file -0194 gui.menu.file_export_data_invstd_mat_all = uimenu(gui.menu.file_export_data,... -0195 'Label','MAT all (std)','Callback',@onMenuExportData); -0196 % 1.2.1.6 Joint Inversion results xls -0197 gui.menu.file_export_data_invjoint_excel = uimenu(gui.menu.file_export_data,... -0198 'Label','EXCEL all (joint)','Separator','on','Enable','off',... -0199 'Callback',@onMenuExportData); -0200 % 1.2.1.7 Joint Inversion results mat-file -0201 gui.menu.file_export_data_invjoint_mat = uimenu(gui.menu.file_export_data,... -0202 'Label','MAT all (joint)','Enable','off','Callback',@onMenuExportData); -0203 % 1.2.1.8 LIAG archive -0204 gui.menu.file_export_data_liag_archive = uimenu(gui.menu.file_export_data,... -0205 'Label','LIAG archive','Separator','on','Callback',@onMenuExportData); -0206 % 1.2.1.9 LIAG CSV T2 -0207 gui.menu.file_export_data_liag_csvT2 = uimenu(gui.menu.file_export_data,... -0208 'Label','LIAG CSV T2','Callback',@onMenuExportData); -0209 % 1.2.1.10 BGR data repository ascii -0210 gui.menu.file_export_data_bgr_repo = uimenu(gui.menu.file_export_data,... -0211 'Label','BGR repository','Callback',@onMenuExportData); -0212 -0213 % 1.2.2 Graphics -0214 gui.menu.file_export_graphics = uimenu(gui.menu.file_export,... -0215 'Label','Graphics'); -0216 % 1.2.2.1 Layout -0217 gui.menu.file_export_graphics_layout = uimenu(gui.menu.file_export_graphics,... -0218 'Label','Layout'); -0219 % 1.2.2.1.1 Layout vertical -0220 gui.menu.file_export_graphics_layout_vert = uimenu(gui.menu.file_export_graphics_layout,... -0221 'Label','vert','Checked','on','Callback',@onMenuExportGraphics); -0222 % 1.2.2.1.2 Layout horizontal -0223 gui.menu.file_export_graphics_layout_horz = uimenu(gui.menu.file_export_graphics_layout,... -0224 'Label','horz','Callback',@onMenuExportGraphics); -0225 % 1.2.2.2 fig -0226 gui.menu.file_export_graphics_fig = uimenu(gui.menu.file_export_graphics,... -0227 'Label','FIG','Callback',@onMenuExportGraphics); -0228 % 1.2.2.3 png -0229 gui.menu.file_export_graphicspng = uimenu(gui.menu.file_export_graphics,... -0230 'Label','PNG','Callback',@onMenuExportGraphics); -0231 % 1.2.2.4 tiff -0232 gui.menu.file_export_graphicstiff = uimenu(gui.menu.file_export_graphics,... -0233 'Label','TIFF','Callback',@onMenuExportGraphics); -0234 % 1.2.2.5 eps -0235 gui.menu.file_export_graphicseps = uimenu(gui.menu.file_export_graphics,... -0236 'Label','EPS','Callback',@onMenuExportGraphics); -0237 -0238 % 1.3 Restart -0239 gui.menu.file_restart = uimenu(gui.menu.file,... -0240 'Label','Restart','Separator','on','Callback',@onMenuRestartQuit); -0241 -0242 % 1.4 Quit -0243 gui.menu.file_quit = uimenu(gui.menu.file,... -0244 'Label','Quit','Callback',@onMenuRestartQuit); -0245 -0246 %% 2. View -0247 gui.menu.view = uimenu(gui.figh,... -0248 'Label','View','Enable','off'); -0249 -0250 % 2.1 tooltips (on/off) -0251 gui.menu.view_tooltips = uimenu(gui.menu.view,... -0252 'Label','Tooltips','Checked','off','Callback',@onMenuView); -0253 switch gui.myui.inidata.tooltips -0254 case 'on' -0255 set(gui.menu.view_tooltips,'Checked','on'); -0256 case 'off' -0257 set(gui.menu.view_tooltips,'Checked','off'); -0258 end -0259 % 2.2 Figure Toolbar -0260 gui.menu.view_toolbar = uimenu(gui.menu.view,... -0261 'Label','Figure Toolbar','Callback',@onMenuView); -0262 -0263 % 2.3 INFO fields in plot panels (on/off) -0264 gui.menu.view_infofields = uimenu(gui.menu.view,... -0265 'Label','INFO fields','Separator','on','Callback',@onMenuView); -0266 -0267 % 2.4 inversion info on command line (on/off) -0268 gui.menu.view_invinfo = uimenu(gui.menu.view,... -0269 'Label','CLI Inv. Info','Callback',@onMenuView); -0270 switch gui.myui.inidata.invinfo -0271 case 'on' -0272 set(gui.menu.view_invinfo,'Checked','on'); -0273 case 'off' -0274 set(gui.menu.view_invinfo,'Checked','off'); -0275 end -0276 -0277 % 2.5 figures -0278 gui.menu.extra_graphics = uimenu(gui.menu.view,... -0279 'Label','Figures','Separator','on'); -0280 % 2.5.1 parameter file info -0281 gui.menu.extra_graphics_parinfo = uimenu(gui.menu.extra_graphics,... -0282 'Label','Parameter Info','Callback',@onMenuViewFigures); -0283 % 2.5.2 fit statistics -0284 gui.menu.extra_graphics_stats = uimenu(gui.menu.extra_graphics,... -0285 'Label','Fit statistics','Callback',@onMenuViewFigures); -0286 switch gui.myui.inidata.expertmode -0287 case 'on' -0288 % 2.5.3 amplitude over time -0289 gui.menu.extra_graphics_amp = uimenu(gui.menu.extra_graphics,... -0290 'Label','AMP-TLGM-SNR','Callback',@onMenuViewFigures); -0291 % 2.5.4 amplitude vs tlgm -0292 gui.menu.extra_graphics_amp2 = uimenu(gui.menu.extra_graphics,... -0293 'Label','AMP vs TLGM','Callback',@onMenuViewFigures); -0294 % 2.5.5 relaxation time distribution over time -0295 gui.menu.extra_graphics_rtd = uimenu(gui.menu.extra_graphics,... -0296 'Label','RTD','Callback',@onMenuViewFigures); -0297 case 'off' -0298 % 2.5.3 amplitude over time -0299 gui.menu.extra_graphics_amp = uimenu(gui.menu.extra_graphics,... -0300 'Label','AMP-TLGM-SNR','Enable','off','Callback',@onMenuViewFigures); -0301 % 2.5.4 amplitude vs tlgm -0302 gui.menu.extra_graphics_amp2 = uimenu(gui.menu.extra_graphics,... -0303 'Label','AMP vs TLGM','Enable','off','Callback',@onMenuViewFigures); -0304 % 2.5.5 relaxation time distribution over time -0305 gui.menu.extra_graphics_rtd = uimenu(gui.menu.extra_graphics,... -0306 'Label','RTD','Enable','off','Callback',@onMenuViewFigures); -0307 end -0308 -0309 % 2.6 PhaseView GUI -0310 gui.menu.extra_phaseview = uimenu(gui.menu.view,... -0311 'Label','PhaseView GUI','Enable','off','Separator','on','Callback',@onMenuSubGUIs); -0312 % 2.7 ConductVew GUI -> hydraulic conductivity -0313 gui.menu.extra_conduct = uimenu(gui.menu.view,... -0314 'Label','ConductView GUI','Enable','off','Callback',@onMenuSubGUIs); -0315 % 2.8 FixedTimeView GUI -0316 gui.menu.extra_fixedtime = uimenu(gui.menu.view,... -0317 'Label','FixedTimeView GUI','Enable','off','Callback',@onMenuSubGUIs); -0318 % 2.9 UncertaintyVIEW GUI -0319 gui.menu.extra_uncert = uimenu(gui.menu.view,... -0320 'Label','UncertView GUI','Enable','off','Callback',@onMenuSubGUIs); -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','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 flag for LSQLIN option to set RTs smaller than min(TE)/5 to 0 -0357 gui.menu.extra_lsqlin_echoflag = uimenu(gui.menu.extra,... -0358 'Label','RTD<TE/5=0','Enable','off',... -0359 'Callback',@onMenuExtraEchoFlag); -0360 -0361 % 3.4 joint inversion (on/off) -0362 gui.menu.extra_joint = uimenu(gui.menu.extra,... -0363 'Label','Joint Inversion','Checked','off','Separator','on',... -0364 'Callback',@onMenuJointInversion); -0365 switch gui.myui.inidata.expertmode -0366 case 'on' -0367 set(gui.menu.extra_joint,'Enable','on'); -0368 case 'off' -0369 set(gui.menu.extra_joint,'Enable','off'); -0370 end -0371 -0372 % 3.5 set inversion bounds for surface relaxivity rho -0373 gui.menu.extra_joint_rhobounds = uimenu(gui.menu.extra,... -0374 'Label','Surface relaxivity bounds','Enable','off',... -0375 'Callback',@onMenuExtraRhoBounds); -0376 -0377 -0378 %% 4. Color theme -0379 gui.menu.color_theme = uimenu(gui.figh,... -0380 'Label','Color Theme','Enable','off'); +0154 % 1.1.2 Ascii +0155 gui.menu.file_import_ascii = uimenu(gui.menu.file_import,... +0156 'Label','Ascii'); +0157 % 1.1.2.1 T1 +0158 gui.menu.file_import_lab_ascii_T1 = uimenu(gui.menu.file_import_ascii,... +0159 'Label','T1','Tag','Ascii','Callback',@onMenuImport); +0160 % 1.1.2.2 T2 +0161 gui.menu.file_import_lab_ascii_T2 = uimenu(gui.menu.file_import_ascii,... +0162 'Label','T2','Tag','Ascii','Callback',@onMenuImport); +0163 +0164 % 1.1.3 Excel +0165 gui.menu.file_import_excel = uimenu(gui.menu.file_import,... +0166 'Label','Excel'); +0167 % 1.1.3.1 T1 +0168 gui.menu.file_import_lab_excel_T1 = uimenu(gui.menu.file_import_excel,... +0169 'Label','T1','Tag','Excel','Callback',@onMenuImport); +0170 % 1.1.3.2 T2 +0171 gui.menu.file_import_lab_excel_T2 = uimenu(gui.menu.file_import_excel,... +0172 'Label','T2','Tag','Excel','Callback',@onMenuImport); +0173 +0174 % 1.1.4 NUCLEUSinv +0175 gui.menu.file_import_nmrinv = uimenu(gui.menu.file_import,... +0176 'Label','NUCLEUSinv','Separator','on'); +0177 % 1.1.4.1 NUCLEUSinv session file +0178 gui.menu.file_import_nmrinv_file = uimenu(gui.menu.file_import_nmrinv,... +0179 'Label','Session','Tag','NUCLEUSinv','Callback',@onMenuImport); +0180 +0181 % 1.1.5 NUCLEUSmod +0182 gui.menu.file_import_nmrmod = uimenu(gui.menu.file_import,... +0183 'Label','NUCLEUSmod'); +0184 % 1.1.5.1 NUCLEUSmod from file +0185 gui.menu.file_import_nmrmod_file = uimenu(gui.menu.file_import_nmrmod,... +0186 'Label','File','Tag','NUCLEUSmod','Callback',@onMenuImport); +0187 % 1.1.5.2 NUCLEUSmod from GUI +0188 gui.menu.file_import_nmrmod_gui = uimenu(gui.menu.file_import_nmrmod,.... +0189 'Label','GUI','Tag','NUCLEUSmod','Callback',@onMenuImport); +0190 % 1.1.5.3 NUCLEUSmod from 2D GUI +0191 gui.menu.file_import_nmrmod_gui2d = uimenu(gui.menu.file_import_nmrmod,.... +0192 'Label','2D GUI','Tag','NUCLEUSmod2d','Callback',@onMenuImport); +0193 +0194 % 1.2 Export +0195 gui.menu.file_export = uimenu(gui.menu.file,... +0196 'Label','Export'); +0197 % 1.2.0 Last export +0198 lastexport = gui.myui.inidata.lastexport; +0199 gui.menu.file_export_lastexport = uimenu(gui.menu.file_export,... +0200 'Label',lastexport,'Callback',@onMenuExportData); +0201 % 1.2.1 Data +0202 gui.menu.file_export_data = uimenu(gui.menu.file_export,... +0203 'Label','Data'); +0204 % 1.2.1.1 GUI raw data mat-file +0205 gui.menu.file_export_data_GUImat = uimenu(gui.menu.file_export_data,... +0206 'Label','NUCLEUSinv (raw)','Callback',@onMenuExportData); +0207 % 1.2.1.2 GUI session mat-file +0208 gui.menu.file_export_data_GUImat = uimenu(gui.menu.file_export_data,... +0209 'Label','NUCLEUSinv (session)','Callback',@onMenuExportData); +0210 % 1.2.1.3 Inversion results single xls +0211 gui.menu.file_export_data_invstd_excel = uimenu(gui.menu.file_export_data,... +0212 'Label','EXCEL single (std)','Separator','on','Callback',@onMenuExportData); +0213 % 1.2.1.4 Inversion results single mat-file +0214 gui.menu.file_export_data_invstd_mat_single = uimenu(gui.menu.file_export_data,... +0215 'Label','MAT single (std)','Callback',@onMenuExportData); +0216 % 1.2.1.5 Inversion results all mat-file +0217 gui.menu.file_export_data_invstd_mat_all = uimenu(gui.menu.file_export_data,... +0218 'Label','MAT all (std)','Callback',@onMenuExportData); +0219 % 1.2.1.6 Joint Inversion results xls +0220 gui.menu.file_export_data_invjoint_excel = uimenu(gui.menu.file_export_data,... +0221 'Label','EXCEL all (joint)','Separator','on','Enable','off',... +0222 'Callback',@onMenuExportData); +0223 % 1.2.1.7 Joint Inversion results mat-file +0224 gui.menu.file_export_data_invjoint_mat = uimenu(gui.menu.file_export_data,... +0225 'Label','MAT all (joint)','Enable','off','Callback',@onMenuExportData); +0226 % 1.2.1.8 LIAG archive +0227 gui.menu.file_export_data_liag_archive = uimenu(gui.menu.file_export_data,... +0228 'Label','LIAG archive','Separator','on','Callback',@onMenuExportData); +0229 % 1.2.1.9 LIAG CSV T2 +0230 gui.menu.file_export_data_liag_csvT2 = uimenu(gui.menu.file_export_data,... +0231 'Label','LIAG CSV T2','Callback',@onMenuExportData); +0232 % 1.2.1.10 BGR data repository ascii +0233 gui.menu.file_export_data_bgr_repo = uimenu(gui.menu.file_export_data,... +0234 'Label','BGR repository','Callback',@onMenuExportData); +0235 +0236 % 1.2.2 Graphics +0237 gui.menu.file_export_graphics = uimenu(gui.menu.file_export,... +0238 'Label','Graphics'); +0239 % 1.2.2.1 Layout +0240 gui.menu.file_export_graphics_layout = uimenu(gui.menu.file_export_graphics,... +0241 'Label','Layout'); +0242 % 1.2.2.1.1 Layout vertical +0243 gui.menu.file_export_graphics_layout_vert = uimenu(gui.menu.file_export_graphics_layout,... +0244 'Label','vert','Checked','on','Callback',@onMenuExportGraphics); +0245 % 1.2.2.1.2 Layout horizontal +0246 gui.menu.file_export_graphics_layout_horz = uimenu(gui.menu.file_export_graphics_layout,... +0247 'Label','horz','Callback',@onMenuExportGraphics); +0248 % 1.2.2.2 fig +0249 gui.menu.file_export_graphics_fig = uimenu(gui.menu.file_export_graphics,... +0250 'Label','FIG','Callback',@onMenuExportGraphics); +0251 % 1.2.2.3 png +0252 gui.menu.file_export_graphicspng = uimenu(gui.menu.file_export_graphics,... +0253 'Label','PNG','Callback',@onMenuExportGraphics); +0254 % 1.2.2.4 tiff +0255 gui.menu.file_export_graphicstiff = uimenu(gui.menu.file_export_graphics,... +0256 'Label','TIFF','Callback',@onMenuExportGraphics); +0257 % 1.2.2.5 eps +0258 gui.menu.file_export_graphicseps = uimenu(gui.menu.file_export_graphics,... +0259 'Label','EPS','Callback',@onMenuExportGraphics); +0260 +0261 % 1.3 Restart +0262 gui.menu.file_restart = uimenu(gui.menu.file,... +0263 'Label','Restart','Separator','on','Callback',@onMenuRestartQuit); +0264 +0265 % 1.4 Quit +0266 gui.menu.file_quit = uimenu(gui.menu.file,... +0267 'Label','Quit','Callback',@onMenuRestartQuit); +0268 +0269 %% 2. View +0270 gui.menu.view = uimenu(gui.figh,... +0271 'Label','View','Enable','off'); +0272 +0273 % 2.1 tooltips (on/off) +0274 gui.menu.view_tooltips = uimenu(gui.menu.view,... +0275 'Label','Tooltips','Checked','off','Callback',@onMenuView); +0276 switch gui.myui.inidata.tooltips +0277 case 'on' +0278 set(gui.menu.view_tooltips,'Checked','on'); +0279 case 'off' +0280 set(gui.menu.view_tooltips,'Checked','off'); +0281 end +0282 % 2.2 Figure Toolbar +0283 gui.menu.view_toolbar = uimenu(gui.menu.view,... +0284 'Label','Figure Toolbar','Callback',@onMenuView); +0285 +0286 % 2.3 INFO fields in plot panels (on/off) +0287 gui.menu.view_infofields = uimenu(gui.menu.view,... +0288 'Label','INFO fields','Separator','on','Callback',@onMenuView); +0289 +0290 % 2.4 inversion info on command line (on/off) +0291 gui.menu.view_invinfo = uimenu(gui.menu.view,... +0292 'Label','CLI Inv. Info','Callback',@onMenuView); +0293 switch gui.myui.inidata.invinfo +0294 case 'on' +0295 set(gui.menu.view_invinfo,'Checked','on'); +0296 case 'off' +0297 set(gui.menu.view_invinfo,'Checked','off'); +0298 end +0299 +0300 % 2.5 figures +0301 gui.menu.extra_graphics = uimenu(gui.menu.view,... +0302 'Label','Figures','Separator','on'); +0303 % 2.5.1 parameter file info +0304 gui.menu.extra_graphics_parinfo = uimenu(gui.menu.extra_graphics,... +0305 'Label','Parameter Info','Callback',@onMenuViewFigures); +0306 % 2.5.2 fit statistics +0307 gui.menu.extra_graphics_stats = uimenu(gui.menu.extra_graphics,... +0308 'Label','Fit statistics','Callback',@onMenuViewFigures); +0309 switch gui.myui.inidata.expertmode +0310 case 'on' +0311 % 2.5.3 amplitude over time +0312 gui.menu.extra_graphics_amp = uimenu(gui.menu.extra_graphics,... +0313 'Label','AMP-TLGM-SNR','Callback',@onMenuViewFigures); +0314 % 2.5.4 amplitude vs tlgm +0315 gui.menu.extra_graphics_amp2 = uimenu(gui.menu.extra_graphics,... +0316 'Label','AMP vs TLGM','Callback',@onMenuViewFigures); +0317 % 2.5.5 relaxation time distribution over time +0318 gui.menu.extra_graphics_rtd = uimenu(gui.menu.extra_graphics,... +0319 'Label','RTD','Callback',@onMenuViewFigures); +0320 case 'off' +0321 % 2.5.3 amplitude over time +0322 gui.menu.extra_graphics_amp = uimenu(gui.menu.extra_graphics,... +0323 'Label','AMP-TLGM-SNR','Enable','off','Callback',@onMenuViewFigures); +0324 % 2.5.4 amplitude vs tlgm +0325 gui.menu.extra_graphics_amp2 = uimenu(gui.menu.extra_graphics,... +0326 'Label','AMP vs TLGM','Enable','off','Callback',@onMenuViewFigures); +0327 % 2.5.5 relaxation time distribution over time +0328 gui.menu.extra_graphics_rtd = uimenu(gui.menu.extra_graphics,... +0329 'Label','RTD','Enable','off','Callback',@onMenuViewFigures); +0330 end +0331 +0332 % 2.6 PhaseView GUI +0333 gui.menu.extra_phaseview = uimenu(gui.menu.view,... +0334 'Label','PhaseView GUI','Enable','off','Separator','on','Callback',@onMenuSubGUIs); +0335 % 2.7 ConductVew GUI -> hydraulic conductivity +0336 gui.menu.extra_conduct = uimenu(gui.menu.view,... +0337 'Label','ConductView GUI','Enable','off','Callback',@onMenuSubGUIs); +0338 % 2.8 FixedTimeView GUI +0339 gui.menu.extra_fixedtime = uimenu(gui.menu.view,... +0340 'Label','FixedTimeView GUI','Enable','off','Callback',@onMenuSubGUIs); +0341 % 2.9 UncertaintyVIEW GUI +0342 gui.menu.extra_uncert = uimenu(gui.menu.view,... +0343 'Label','UncertView GUI','Enable','off','Callback',@onMenuSubGUIs); +0344 % 2.9 2DInv GUI +0345 gui.menu.extra_T1T2map = uimenu(gui.menu.view,... +0346 'Label','2DInv GUI','Enable','off','Callback',@onMenuSubGUIs); +0347 +0348 %% 3. Extras +0349 gui.menu.extra = uimenu(gui.figh,... +0350 'Label','Extra','Enable','off'); +0351 +0352 % 3.1 expert mode (on/off) +0353 gui.menu.extra_expert = uimenu(gui.menu.extra,... +0354 'Label','Expert Mode','Callback',@onMenuExpert); +0355 switch gui.myui.inidata.expertmode +0356 case 'on' +0357 set(gui.menu.extra_expert,'Checked','on'); +0358 case 'off' +0359 set(gui.menu.extra_expert,'Checked','of'); +0360 end +0361 +0362 % 3.2 optimization toolbox (on/off) +0363 switch gui.myui.inidata.expertmode +0364 case 'on' +0365 switch data.info.has_optim +0366 case 'on' +0367 gui.menu.extra_solver = uimenu(gui.menu.extra,... +0368 'Label','LSQ Solver','Enable','on'); +0369 case 'off' +0370 gui.menu.extra_solver = uimenu(gui.menu.extra,... +0371 'Label','LSQ Solver','Enable','off'); +0372 end +0373 case 'off' +0374 gui.menu.extra_solver = uimenu(gui.menu.extra,... +0375 'Label','LSQ Solver','Enable','off'); +0376 end +0377 gui.menu.extra_solver_lsqlin = uimenu(gui.menu.extra_solver,... +0378 'Label','LSQLIN (Optim. TB)','Callback',@onMenuSolver); +0379 gui.menu.extra_solver_lsqnonneg = uimenu(gui.menu.extra_solver,... +0380 'Label','LSQNONNEG (default)','Checked','on','Callback',@onMenuSolver); 0381 -0382 % 4.1 default color theme -0383 gui.menu.color_theme_standard = uimenu(gui.menu.color_theme,... -0384 'Label','standard','Callback',@onMenuExtraColor); -0385 % 4.2 basic color theme -0386 gui.menu.color_theme_basic = uimenu(gui.menu.color_theme,... -0387 'Label','basic','Callback',@onMenuExtraColor); -0388 % 4.3 dark color theme -0389 gui.menu.color_theme_dark = uimenu(gui.menu.color_theme,... -0390 'Label','dark','Callback',@onMenuExtraColor); -0391 % 4.4 black color theme -0392 gui.menu.color_theme_black = uimenu(gui.menu.color_theme,... -0393 'Label','black','Callback',@onMenuExtraColor); -0394 switch gui.myui.inidata.colortheme -0395 case 'standard' -0396 set(gui.menu.color_theme_standard,'Checked','on'); -0397 case 'basic' -0398 set(gui.menu.color_theme_basic,'Checked','on'); -0399 case 'dark' -0400 set(gui.menu.color_theme_dark,'Checked','on'); -0401 case 'black' -0402 set(gui.menu.color_theme_black,'Checked','on'); -0403 end -0404 -0405 %% 5. Help -0406 gui.menu.help = uimenu(gui.figh,... -0407 'Label','Help','Enable','off'); +0382 % 3.3 flag for LSQLIN option to set RTs smaller than min(TE)/5 to 0 +0383 gui.menu.extra_lsqlin_echoflag = uimenu(gui.menu.extra,... +0384 'Label','RTD<TE/5=0','Enable','off',... +0385 'Callback',@onMenuExtraEchoFlag); +0386 +0387 % 3.4 joint inversion (on/off) +0388 gui.menu.extra_joint = uimenu(gui.menu.extra,... +0389 'Label','Joint Inversion','Checked','off','Separator','on',... +0390 'Callback',@onMenuJointInversion); +0391 switch gui.myui.inidata.expertmode +0392 case 'on' +0393 set(gui.menu.extra_joint,'Enable','on'); +0394 case 'off' +0395 set(gui.menu.extra_joint,'Enable','off'); +0396 end +0397 +0398 % 3.5 set inversion bounds for surface relaxivity rho +0399 gui.menu.extra_joint_rhobounds = uimenu(gui.menu.extra,... +0400 'Label','Surface relaxivity bounds','Enable','off',... +0401 'Callback',@onMenuExtraRhoBounds); +0402 +0403 % 3.6 find duplicate data +0404 gui.menu.extra_find_duplicates = uimenu(gui.menu.extra,... +0405 'Label','Find duplicate signals','Enable','on',... +0406 'Callback',@onMenuExtraFindDuplicates); +0407 0408 -0409 % 5.1 About -0410 gui.menu.help_about = uimenu(gui.menu.help,... -0411 'Label','About','Callback',@onMenuHelp); +0409 %% 4. Color theme +0410 gui.menu.color_theme = uimenu(gui.figh,... +0411 'Label','Color Theme','Enable','off'); 0412 -0413 return -0414 -0415 %------------- END OF CODE -------------- -0416 -0417 %% License: -0418 % MIT License -0419 % -0420 % Copyright (c) 2018 Thomas Hiller -0421 % -0422 % Permission is hereby granted, free of charge, to any person obtaining a copy -0423 % of this software and associated documentation files (the "Software"), to deal -0424 % in the Software without restriction, including without limitation the rights -0425 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0426 % copies of the Software, and to permit persons to whom the Software is -0427 % furnished to do so, subject to the following conditions: -0428 % -0429 % The above copyright notice and this permission notice shall be included in all -0430 % copies or substantial portions of the Software. -0431 % -0432 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0433 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0434 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0435 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0436 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0437 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0438 % SOFTWARE. +0413 % 4.1 default color theme +0414 gui.menu.color_theme_standard = uimenu(gui.menu.color_theme,... +0415 'Label','standard','Callback',@onMenuExtraColor); +0416 % 4.2 basic color theme +0417 gui.menu.color_theme_basic = uimenu(gui.menu.color_theme,... +0418 'Label','basic','Callback',@onMenuExtraColor); +0419 % 4.3 dark color theme +0420 gui.menu.color_theme_dark = uimenu(gui.menu.color_theme,... +0421 'Label','dark','Callback',@onMenuExtraColor); +0422 % 4.4 black color theme +0423 gui.menu.color_theme_black = uimenu(gui.menu.color_theme,... +0424 'Label','black','Callback',@onMenuExtraColor); +0425 switch gui.myui.inidata.colortheme +0426 case 'standard' +0427 set(gui.menu.color_theme_standard,'Checked','on'); +0428 case 'basic' +0429 set(gui.menu.color_theme_basic,'Checked','on'); +0430 case 'dark' +0431 set(gui.menu.color_theme_dark,'Checked','on'); +0432 case 'black' +0433 set(gui.menu.color_theme_black,'Checked','on'); +0434 end +0435 +0436 %% 5. Help +0437 gui.menu.help = uimenu(gui.figh,... +0438 'Label','Help','Enable','off'); +0439 +0440 % 5.1 About +0441 gui.menu.help_about = uimenu(gui.menu.help,... +0442 'Label','About','Callback',@onMenuHelp); +0443 +0444 return +0445 +0446 %------------- END OF CODE -------------- +0447 +0448 %% License: +0449 % MIT License +0450 % +0451 % Copyright (c) 2018 Thomas Hiller +0452 % +0453 % Permission is hereby granted, free of charge, to any person obtaining a copy +0454 % of this software and associated documentation files (the "Software"), to deal +0455 % in the Software without restriction, including without limitation the rights +0456 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0457 % copies of the Software, and to permit persons to whom the Software is +0458 % furnished to do so, subject to the following conditions: +0459 % +0460 % The above copyright notice and this permission notice shall be included in all +0461 % copies or substantial portions of the Software. +0462 % +0463 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0464 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0465 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0466 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0467 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0468 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0469 % 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 9614092..778fff3 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_createPanelInversionStd.html @@ -256,7 +256,7 @@

    SOURCE CODE ^'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]); +0187 set(gui.panels.invstd.HBox7,'Widths',[200 -1 -2]); 0188 0189 %% Java Hack to adjust vertical alignment of text fields 0190 jh = findjobj(gui.text_handles.invstd_InvType); diff --git a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html index c05d4ec..0ce8b72 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_loadDefaults.html @@ -264,32 +264,91 @@

    SOURCE CODE ^% corresponding scale factors - 1 | 1e-3 | 1e-6 | 1e-5 0196 out.pressure.unitfac = 1; 0197 -0198 return -0199 -0200 %------------- END OF CODE -------------- -0201 -0202 %% License: -0203 % MIT License -0204 % -0205 % Copyright (c) 2018 Thomas Hiller -0206 % -0207 % Permission is hereby granted, free of charge, to any person obtaining a copy -0208 % of this software and associated documentation files (the "Software"), to deal -0209 % in the Software without restriction, including without limitation the rights -0210 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0211 % copies of the Software, and to permit persons to whom the Software is -0212 % furnished to do so, subject to the following conditions: -0213 % -0214 % The above copyright notice and this permission notice shall be included in all -0215 % copies or substantial portions of the Software. -0216 % -0217 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0218 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0219 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0220 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0221 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0222 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0223 % SOFTWARE. +0198 %% 2D inversion GUI settings +0199 % system / fluid properties +0200 % diffusion coefficient [m²/s] +0201 out.inv2D.prop.D = 2.025e-9; +0202 % gradient [T/m] +0203 out.inv2D.prop.G0 = 0; +0204 % echo time [s] +0205 out.inv2D.prop.te = 200e-6; +0206 % start echo +0207 out.inv2D.prop.first = 1; +0208 % last echo +0209 out.inv2D.prop.last = 1; +0210 +0211 % inversion settings +0212 % IR/SR factor +0213 out.inv2D.inv.T1IRfac = 2; +0214 % IR kernel type (1 or 2) +0215 out.inv2D.inv.IRtype = 1; +0216 % T1 range minimum [s] +0217 out.inv2D.inv.T1min = 1e-4; +0218 % T1 range maximum [s] +0219 out.inv2D.inv.T1max = 10; +0220 % T1 number of points in range +0221 out.inv2D.inv.T1N = 51; +0222 % T2 range minimum [s] +0223 out.inv2D.inv.T2min = 1e-4; +0224 % T2 range maximum [s] +0225 out.inv2D.inv.T2max = 10; +0226 % T2 number of points in range +0227 out.inv2D.inv.T2N = 51; +0228 % T1 regularization parameter lambda +0229 out.inv2D.inv.T1lambda = 5; +0230 % T1 order of smoothness constraint +0231 out.inv2D.inv.T1order = 1; +0232 % T2 regularization parameter lambda +0233 out.inv2D.inv.T2lambda = 2; +0234 % T2 order of smoothness constraint +0235 out.inv2D.inv.T2order = 1; +0236 +0237 % information settings / properties +0238 % T1 minimum [s] +0239 out.inv2D.info.T1min = 1e-3; +0240 % T1 maximum [s] +0241 out.inv2D.info.T1max = 1; +0242 % T2 minimum [s] +0243 out.inv2D.info.T2min = 1e-3; +0244 % T2 minimum [s] +0245 out.inv2D.info.T2max = 1; +0246 % initial amplitude E0 [a.u.] +0247 out.inv2D.info.E0 = 0; +0248 % T1 log mean time +0249 out.inv2D.info.T1tlgm = 0; +0250 % T2 log mean time +0251 out.inv2D.info.T2tlgm = 0; +0252 % T1 maximum time +0253 out.inv2D.info.T1tmax = 0; +0254 % T2 maximum time +0255 out.inv2D.info.T2tmax = 0; +0256 +0257 return +0258 +0259 %------------- END OF CODE -------------- +0260 +0261 %% License: +0262 % MIT License +0263 % +0264 % Copyright (c) 2018 Thomas Hiller +0265 % +0266 % Permission is hereby granted, free of charge, to any person obtaining a copy +0267 % of this software and associated documentation files (the "Software"), to deal +0268 % in the Software without restriction, including without limitation the rights +0269 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0270 % copies of the Software, and to permit persons to whom the Software is +0271 % furnished to do so, subject to the following conditions: +0272 % +0273 % The above copyright notice and this permission notice shall be included in all +0274 % copies or substantial portions of the Software. +0275 % +0276 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0277 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0278 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0279 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0280 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0281 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0282 % 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 7e71ab5..61e8460 100644 --- a/doc/nucleus/NUCLEUSinv/NUCLEUSinv_updateInterface.html +++ b/doc/nucleus/NUCLEUSinv/NUCLEUSinv_updateInterface.html @@ -70,7 +70,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • onEditValue updates all edit field values, checks for wrong inputs and
  • onListboxData handles the calls from the context menu of the data
  • onMenuExpert handles the call from the menu that activates / deactivates
  • onMenuExtraEchoFlag handles the call from the menu that swicth the "EchoFlag"
  • onMenuJointInversion handles the call from the menu that activates / deactivates
  • onMenuSolver handles the call from the menu that allows to choose the LSQ
  • onPopupInvjointGeometryType selects the joint inversion geometry (dependent
  • onPopupInvjointPolyN handles the call from the popup menu to select the
  • onPopupInvjointType selects the joint inversion method ("free", "fixed" or
  • onPopupInvjointTypeOptional select regularization option for the joint
  • onPopupInvstdType selects the inversion method for the standard inversion
  • onPopupInvstdTypeOptional select regularization option for the standard
  • onPopupPressureUnits select pressure unit ("Pa", "kPa", "MPa" or "bar")
  • onRadioGates selects the re-sampling / gating method ("log", "lin" or "none")
  • onRadioLorder selects the smoothness constraint for the multi-exponential
  • onRadioNormalize selects whether to normalize a NMR signal to 1
  • onRadioTimescale selects whether the time scale should be "s" or "ms"
  • calibratePorosity determines a sample's porosity from a calibration
  • clearInversion removes inversion results from the internal data structure
  • importASCIIdata imports NMR data from ASCII files
  • importCPSdata imports CPS data from an ASCII dat-file. See the "examples"
  • importCalibrationData
  • importEXCELdata imports NMR data from Excel files
  • importINV2INV imports a previously saved NUCLEUSinv session
  • 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
  • +
  • onEditValue updates all edit field values, checks for wrong inputs and
  • onListboxData handles the calls from the context menu of the data
  • onMenuExpert handles the call from the menu that activates / deactivates
  • onMenuExtraEchoFlag handles the call from the menu that swicth the "EchoFlag"
  • onMenuJointInversion handles the call from the menu that activates / deactivates
  • onMenuSolver handles the call from the menu that allows to choose the LSQ
  • onPopupInvjointGeometryType selects the joint inversion geometry (dependent
  • onPopupInvjointPolyN handles the call from the popup menu to select the
  • onPopupInvjointType selects the joint inversion method ("free", "fixed" or
  • onPopupInvjointTypeOptional select regularization option for the joint
  • onPopupInvstdType selects the inversion method for the standard inversion
  • onPopupInvstdTypeOptional select regularization option for the standard
  • onPopupPressureUnits select pressure unit ("Pa", "kPa", "MPa" or "bar")
  • onRadioGates selects the re-sampling / gating method ("log", "lin" or "none")
  • onRadioLorder selects the smoothness constraint for the multi-exponential
  • onRadioNormalize selects whether to normalize a NMR signal to 1
  • onRadioTimescale selects whether the time scale should be "s" or "ms"
  • calibratePorosity determines a sample's porosity from a calibration
  • clearInversion removes inversion results from the internal data structure
  • importASCIIdata imports NMR data from ASCII files
  • importCPSdata imports CPS data from an ASCII dat-file. See the "examples"
  • importCalibrationData
  • importEXCELdata imports NMR data from Excel files
  • importINV2INV imports a previously saved NUCLEUSinv session
  • importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
  • importMOD2INV imports data directly from the NUCLEUSmod GUI or and
  • 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
  • SUBFUNCTIONS ^

    diff --git a/doc/nucleus/NUCLEUSmod/NUCLEUSmod.html b/doc/nucleus/NUCLEUSmod/NUCLEUSmod.html index f6c2583..43de30a 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.2.1'; -0045 myui.date = '11.02.2024'; +0044 myui.version = '0.3.0'; +0045 myui.date = '27.11.2024'; 0046 myui.author = {'Stephan Costabel','Thomas Hiller'}; 0047 myui.email = 'thomas.hiller[at]bgr.de'; 0048 myui.fontsize = 10; @@ -141,43 +141,44 @@

    SOURCE CODE ^% save the data struct within the GUI -0071 setappdata(gui.figh,'data',data); -0072 setappdata(gui.figh,'gui',gui); -0073 -0074 %% Create GUI elements -0075 NUCLEUSmod_createGUI(gui.figh,1); -0076 -0077 %% Calculate Initial Geometry -0078 calculateGeometry; -0079 end -0080 -0081 %------------- END OF CODE -------------- -0082 -0083 %% License: -0084 % MIT License -0085 % -0086 % Copyright (c) 2018 Thomas Hiller -0087 % -0088 % Permission is hereby granted, free of charge, to any person obtaining a copy -0089 % of this software and associated documentation files (the "Software"), to deal -0090 % in the Software without restriction, including without limitation the rights -0091 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0092 % copies of the Software, and to permit persons to whom the Software is -0093 % furnished to do so, subject to the following conditions: -0094 % -0095 % The above copyright notice and this permission notice shall be included in all -0096 % copies or substantial portions of the Software. -0097 % -0098 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0099 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0100 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0101 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0102 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0103 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0104 % SOFTWARE. +0068 data.mod2D = defaults.mod2D; +0069 gui.myui = myui; +0070 +0071 % save the data struct within the GUI +0072 setappdata(gui.figh,'data',data); +0073 setappdata(gui.figh,'gui',gui); +0074 +0075 %% Create GUI elements +0076 NUCLEUSmod_createGUI(gui.figh,1); +0077 +0078 %% Calculate Initial Geometry +0079 calculateGeometry; +0080 end +0081 +0082 %------------- END OF CODE -------------- +0083 +0084 %% License: +0085 % MIT License +0086 % +0087 % Copyright (c) 2018 Thomas Hiller +0088 % +0089 % Permission is hereby granted, free of charge, to any person obtaining a copy +0090 % of this software and associated documentation files (the "Software"), to deal +0091 % in the Software without restriction, including without limitation the rights +0092 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0093 % copies of the Software, and to permit persons to whom the Software is +0094 % furnished to do so, subject to the following conditions: +0095 % +0096 % The above copyright notice and this permission notice shall be included in all +0097 % copies or substantial portions of the Software. +0098 % +0099 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0100 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0101 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0102 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0103 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0104 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0105 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createMenus.html b/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createMenus.html index 4c2d53f..e7e6d11 100644 --- a/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createMenus.html +++ b/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createMenus.html @@ -168,61 +168,65 @@

    SOURCE CODE ^% 2.2 Figure Toolbar 0100 gui.menu.view_toolbar = uimenu(gui.menu.view,... 0101 'Label','Figure Toolbar','Callback',@onMenuView); -0102 % 2.3 hydraulic conductivity -0103 gui.menu.view_conduct = uimenu(gui.menu.view,... -0104 'Label','ConductView GUI','Separator','on','Enable','off',... +0102 % 2.3 2D modelling GUI +0103 gui.menu.view_2dmod = uimenu(gui.menu.view,... +0104 'Label','2DMod GUI','Separator','on','Enable','on',... 0105 'Callback',@onMenuSubGUIs); -0106 -0107 %% 3. Color theme -0108 gui.menu.color_theme = uimenu(gui.figh,... -0109 'Label','Color Theme'); -0110 % 3.1 default color theme -0111 gui.menu.color_theme_standard = uimenu(gui.menu.color_theme,... -0112 'Label','standard','Checked','on','Callback',@onMenuExtraColor); -0113 % 3.2 basic color theme -0114 gui.menu.color_theme_basic = uimenu(gui.menu.color_theme,... -0115 'Label','basic','Callback',@onMenuExtraColor); -0116 % 3.3 dark color theme -0117 gui.menu.color_theme_dark = uimenu(gui.menu.color_theme,... -0118 'Label','dark','Callback',@onMenuExtraColor); -0119 % 3.4 black color theme -0120 gui.menu.color_theme_black = uimenu(gui.menu.color_theme,... -0121 'Label','black','Callback',@onMenuExtraColor); -0122 -0123 %% 4. Help -0124 gui.menu.help = uimenu(gui.figh,... -0125 'Label','Help'); +0106 % 2.4 hydraulic conductivity +0107 gui.menu.view_conduct = uimenu(gui.menu.view,... +0108 'Label','ConductView GUI','Enable','off',... +0109 'Callback',@onMenuSubGUIs); +0110 +0111 %% 3. Color theme +0112 gui.menu.color_theme = uimenu(gui.figh,... +0113 'Label','Color Theme'); +0114 % 3.1 default color theme +0115 gui.menu.color_theme_standard = uimenu(gui.menu.color_theme,... +0116 'Label','standard','Checked','on','Callback',@onMenuExtraColor); +0117 % 3.2 basic color theme +0118 gui.menu.color_theme_basic = uimenu(gui.menu.color_theme,... +0119 'Label','basic','Callback',@onMenuExtraColor); +0120 % 3.3 dark color theme +0121 gui.menu.color_theme_dark = uimenu(gui.menu.color_theme,... +0122 'Label','dark','Callback',@onMenuExtraColor); +0123 % 3.4 black color theme +0124 gui.menu.color_theme_black = uimenu(gui.menu.color_theme,... +0125 'Label','black','Callback',@onMenuExtraColor); 0126 -0127 % 4.1 About -0128 gui.menu.help_about = uimenu(gui.menu.help,... -0129 'Label','About','Callback',@onMenuHelp); +0127 %% 4. Help +0128 gui.menu.help = uimenu(gui.figh,... +0129 'Label','Help'); 0130 -0131 return -0132 -0133 %------------- END OF CODE -------------- +0131 % 4.1 About +0132 gui.menu.help_about = uimenu(gui.menu.help,... +0133 'Label','About','Callback',@onMenuHelp); 0134 -0135 %% License: -0136 % MIT License -0137 % -0138 % Copyright (c) 2018 Thomas Hiller -0139 % -0140 % Permission is hereby granted, free of charge, to any person obtaining a copy -0141 % of this software and associated documentation files (the "Software"), to deal -0142 % in the Software without restriction, including without limitation the rights -0143 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0144 % copies of the Software, and to permit persons to whom the Software is -0145 % furnished to do so, subject to the following conditions: -0146 % -0147 % The above copyright notice and this permission notice shall be included in all -0148 % copies or substantial portions of the Software. -0149 % -0150 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0151 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0152 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0153 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0154 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0155 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0156 % SOFTWARE. +0135 return +0136 +0137 %------------- END OF CODE -------------- +0138 +0139 %% License: +0140 % MIT License +0141 % +0142 % Copyright (c) 2018 Thomas Hiller +0143 % +0144 % Permission is hereby granted, free of charge, to any person obtaining a copy +0145 % of this software and associated documentation files (the "Software"), to deal +0146 % in the Software without restriction, including without limitation the rights +0147 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0148 % copies of the Software, and to permit persons to whom the Software is +0149 % furnished to do so, subject to the following conditions: +0150 % +0151 % The above copyright notice and this permission notice shall be included in all +0152 % copies or substantial portions of the Software. +0153 % +0154 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0155 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0156 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0157 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0158 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0159 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0160 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createPanelNMR.html b/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createPanelNMR.html index c28af29..25c9e1c 100644 --- a/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createPanelNMR.html +++ b/doc/nucleus/NUCLEUSmod/NUCLEUSmod_createPanelNMR.html @@ -184,78 +184,77 @@

    SOURCE CODE ^'Widths',[200 -1]); 0115 0116 %% noise & porosity -0117 -0118 tstr = ['<HTML>NMR data noise method.<br><br>',... -0119 'A noise level will be used globally for all NMR signals.<br>',... -0120 'A signal-to-ratio will be used individually on every single NMR signal.<br><br>',... -0121 '<u>Available options:</u><br>',... -0122 '<b>noise level</b> or <b>SNR</b> <br><br>',... -0123 '<u>Default value:</u><br>',... -0124 '<b>noise level</b> <br>']; -0125 gui.popup_handles.noisetype = uicontrol('Parent',gui.panels.nmr.HBox4,... -0126 'Style','popup','String',{'noise level','SNR'},... -0127 'Value',1,'FontSize',myui.fontsize,'UserData',struct('Tooltipstr',tstr),... -0128 'Callback',@onPopupNMRNoiseType); -0129 tstr = ['<HTML>NMR data noise.<br><br>',... -0130 '<u>Hint:</u><br>',... -0131 'You do not need to press RUN to add noise to the NMR signals.<br>',... -0132 'The raw NMR signals are stored internally and the noise is<br>',... -0133 'applied instantaneously.<br><br>',... -0134 '<u>Default value:</u><br>',... -0135 '<b>0</b><br>']; -0136 gui.edit_handles.noise = uicontrol('Parent',gui.panels.nmr.HBox4,... -0137 'Style','edit','String',num2str(data.nmr.noise),'FontSize',myui.fontsize,... -0138 'UserData',struct('Tooltipstr',tstr,'defaults',[data.nmr.noise 1 1]),... -0139 'Tag','nmr_noise','Enable','on','Callback',@onEditValue); -0140 gui.text_handles.porosity = uicontrol('Parent',gui.panels.nmr.HBox4,... -0141 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... -0142 'String','porosity'); -0143 tstr = ['<HTML>Porosity value in the range [0, 1].<br><br>',... -0144 '<u>Note:</u><br>',... -0145 'This value is applied only as a scaling factor to the NMR amplitudes.<br>',... -0146 'Hence, saturation becomes water content.']; -0147 gui.edit_handles.porosity = uicontrol('Parent',gui.panels.nmr.HBox4,... -0148 'Style','edit','String',num2str(data.nmr.porosity),'FontSize',myui.fontsize,... -0149 'UserData',struct('Tooltipstr',tstr,'defaults',[data.nmr.porosity 1 1]),... -0150 'Tag','nmr_porosity','Enable','on','Callback',@onEditValue); -0151 set(gui.panels.nmr.HBox4,'Widths',[100 -1 100 -1]); -0152 -0153 %% Java Hack to adjust vertical alignment of text fields -0154 jh = findjobj(gui.text_handles.Tbulk); -0155 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0156 jh = findjobj(gui.text_handles.rho); -0157 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0158 jh = findjobj(gui.text_handles.nmr_RUN); -0159 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0160 jh = findjobj(gui.text_handles.porosity); -0161 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0162 -0163 return -0164 -0165 %------------- END OF CODE -------------- -0166 -0167 %% License: -0168 % MIT License -0169 % -0170 % Copyright (c) 2018 Thomas Hiller -0171 % -0172 % Permission is hereby granted, free of charge, to any person obtaining a copy -0173 % of this software and associated documentation files (the "Software"), to deal -0174 % in the Software without restriction, including without limitation the rights -0175 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0176 % copies of the Software, and to permit persons to whom the Software is -0177 % furnished to do so, subject to the following conditions: -0178 % -0179 % The above copyright notice and this permission notice shall be included in all -0180 % copies or substantial portions of the Software. -0181 % -0182 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0183 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0184 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0185 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0186 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0187 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0188 % SOFTWARE. +0117 tstr = ['<HTML>NMR data noise method.<br><br>',... +0118 'A noise level will be used globally for all NMR signals.<br>',... +0119 'A signal-to-ratio will be used individually on every single NMR signal.<br><br>',... +0120 '<u>Available options:</u><br>',... +0121 '<b>noise level</b> or <b>SNR</b> <br><br>',... +0122 '<u>Default value:</u><br>',... +0123 '<b>noise level</b> <br>']; +0124 gui.popup_handles.noisetype = uicontrol('Parent',gui.panels.nmr.HBox4,... +0125 'Style','popup','String',{'noise level','SNR'},... +0126 'Value',1,'FontSize',myui.fontsize,'UserData',struct('Tooltipstr',tstr),... +0127 'Callback',@onPopupNMRNoiseType); +0128 tstr = ['<HTML>NMR data noise.<br><br>',... +0129 '<u>Hint:</u><br>',... +0130 'You do not need to press RUN to add noise to the NMR signals.<br>',... +0131 'The raw NMR signals are stored internally and the noise is<br>',... +0132 'applied instantaneously.<br><br>',... +0133 '<u>Default value:</u><br>',... +0134 '<b>0</b><br>']; +0135 gui.edit_handles.noise = uicontrol('Parent',gui.panels.nmr.HBox4,... +0136 'Style','edit','String',num2str(data.nmr.noise),'FontSize',myui.fontsize,... +0137 'UserData',struct('Tooltipstr',tstr,'defaults',[data.nmr.noise 1 1]),... +0138 'Tag','nmr_noise','Enable','on','Callback',@onEditValue); +0139 gui.text_handles.porosity = uicontrol('Parent',gui.panels.nmr.HBox4,... +0140 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0141 'String','porosity'); +0142 tstr = ['<HTML>Porosity value in the range [0, 1].<br><br>',... +0143 '<u>Note:</u><br>',... +0144 'This value is applied only as a scaling factor to the NMR amplitudes.<br>',... +0145 'Hence, saturation becomes water content.']; +0146 gui.edit_handles.porosity = uicontrol('Parent',gui.panels.nmr.HBox4,... +0147 'Style','edit','String',num2str(data.nmr.porosity),'FontSize',myui.fontsize,... +0148 'UserData',struct('Tooltipstr',tstr,'defaults',[data.nmr.porosity 1 1]),... +0149 'Tag','nmr_porosity','Enable','on','Callback',@onEditValue); +0150 set(gui.panels.nmr.HBox4,'Widths',[100 -1 100 -1]); +0151 +0152 %% Java Hack to adjust vertical alignment of text fields +0153 jh = findjobj(gui.text_handles.Tbulk); +0154 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0155 jh = findjobj(gui.text_handles.rho); +0156 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0157 jh = findjobj(gui.text_handles.nmr_RUN); +0158 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0159 jh = findjobj(gui.text_handles.porosity); +0160 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0161 +0162 return +0163 +0164 %------------- END OF CODE -------------- +0165 +0166 %% License: +0167 % MIT License +0168 % +0169 % Copyright (c) 2018 Thomas Hiller +0170 % +0171 % Permission is hereby granted, free of charge, to any person obtaining a copy +0172 % of this software and associated documentation files (the "Software"), to deal +0173 % in the Software without restriction, including without limitation the rights +0174 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0175 % copies of the Software, and to permit persons to whom the Software is +0176 % furnished to do so, subject to the following conditions: +0177 % +0178 % The above copyright notice and this permission notice shall be included in all +0179 % copies or substantial portions of the Software. +0180 % +0181 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0182 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0183 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0184 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0185 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0186 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0187 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/NUCLEUSmod/NUCLEUSmod_loadDefaults.html b/doc/nucleus/NUCLEUSmod/NUCLEUSmod_loadDefaults.html index 88457eb..f657817 100644 --- a/doc/nucleus/NUCLEUSmod/NUCLEUSmod_loadDefaults.html +++ b/doc/nucleus/NUCLEUSmod/NUCLEUSmod_loadDefaults.html @@ -159,32 +159,83 @@

    SOURCE CODE ^% use linear y-axes as default (log=1, lin=2) 0093 out.nmr.logliny = 2; 0094 -0095 return -0096 -0097 %------------- END OF CODE -------------- -0098 -0099 %% License: -0100 % MIT License -0101 % -0102 % Copyright (c) 2018 Thomas Hiller -0103 % -0104 % Permission is hereby granted, free of charge, to any person obtaining a copy -0105 % of this software and associated documentation files (the "Software"), to deal -0106 % in the Software without restriction, including without limitation the rights -0107 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0108 % copies of the Software, and to permit persons to whom the Software is -0109 % furnished to do so, subject to the following conditions: -0110 % -0111 % The above copyright notice and this permission notice shall be included in all -0112 % copies or substantial portions of the Software. -0113 % -0114 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0115 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0116 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0117 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0118 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0119 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0120 % SOFTWARE. +0095 %% 2D settings +0096 % system / fluid properties +0097 % diffusion coefficient [m²/s] +0098 out.mod2D.prop.D = 2.025e-9; +0099 % gradient [T/m] +0100 out.mod2D.prop.G0 = 0; +0101 % echo time [s] +0102 out.mod2D.prop.te = 0; +0103 % bulk relaxation [s] +0104 out.mod2D.prop.Tbulk = 1e6; +0105 +0106 % model space settings +0107 % 2D type +0108 out.mod2D.mod.type = 'T1T2'; +0109 % T1 range minimum [s] +0110 out.mod2D.mod.T1min = 1e-4; +0111 % T1 range maximum [s] +0112 out.mod2D.mod.T1max = 10; +0113 % T1 number of points in range +0114 out.mod2D.mod.T1N = 151; +0115 % T2 range minimum [s] +0116 out.mod2D.mod.T2min = 1e-4; +0117 % T2 range maximum [s] +0118 out.mod2D.mod.T2max = 10; +0119 % T2 number of points in range +0120 out.mod2D.mod.T2N = 151; +0121 +0122 % number of 2D distribution +0123 out.mod2D.mod.Ndist = 3; +0124 % center point of 2D distribution +0125 out.mod2D.mod.mu = [1 1;0.01 0.03;0.5 0.005]; +0126 % covariance matrix of 2D distribution +0127 out.mod2D.mod.sigma{1} = [0.1 0;0 0.1]; +0128 out.mod2D.mod.sigma{2} = [0.2 0.3;0 0.2]; +0129 out.mod2D.mod.sigma{3} = [0.3 0;0 0.01]; +0130 % amplitude of 2D distribution +0131 out.mod2D.mod.amp = [1 1 1]; +0132 +0133 % NMR data +0134 out.mod2D.nmr.T1IRfac = 2; +0135 out.mod2D.nmr.IRtype = 1; +0136 out.mod2D.nmr.T1trmin = 1e-3; +0137 out.mod2D.nmr.T1trmax = 1; +0138 out.mod2D.nmr.T1trN = 21; +0139 out.mod2D.nmr.T2te = 200e-6; +0140 out.mod2D.nmr.T2teN = 500; +0141 % noise creation type 'level' or 'SNR' +0142 out.mod2D.nmr.noisetype = 'level'; +0143 % noise level [0:1] or SNR [-] +0144 out.mod2D.nmr.noise = 0; +0145 +0146 return +0147 +0148 %------------- END OF CODE -------------- +0149 +0150 %% License: +0151 % MIT License +0152 % +0153 % Copyright (c) 2018 Thomas Hiller +0154 % +0155 % Permission is hereby granted, free of charge, to any person obtaining a copy +0156 % of this software and associated documentation files (the "Software"), to deal +0157 % in the Software without restriction, including without limitation the rights +0158 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0159 % copies of the Software, and to permit persons to whom the Software is +0160 % furnished to do so, subject to the following conditions: +0161 % +0162 % The above copyright notice and this permission notice shall be included in all +0163 % copies or substantial portions of the Software. +0164 % +0165 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0166 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0167 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0168 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0169 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0170 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0171 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/contextmenus/onContextAxisLogLin.html b/doc/nucleus/callbacks/contextmenus/onContextAxisLogLin.html index 22e1853..4fa46a6 100644 --- a/doc/nucleus/callbacks/contextmenus/onContextAxisLogLin.html +++ b/doc/nucleus/callbacks/contextmenus/onContextAxisLogLin.html @@ -110,52 +110,50 @@

    SOURCE CODE ^% get the label of the context menu 0040 label = get(src,'Label'); -0041 % get the tag of the context menu -0042 tag = get(src,'Tag'); -0043 -0044 % change the label depending on the current status -0045 if ~isempty(strfind(label,'log')) % current axis is lin -> switch to log -0046 label = strrep(label,'log','lin'); -0047 else % current axis is log -> switch to lin -0048 label = strrep(label,'lin','log'); -0049 end -0050 set(src,'Label',label); -0051 -0052 % call the respective functions that update the plot axes -0053 switch fig_tag -0054 case 'INV' -0055 updatePlotsSignal; -0056 updatePlotsJointInversion; -0057 case 'MOD' -0058 updatePlotsNMR; +0041 +0042 % change the label depending on the current status +0043 if contains(label,'log') % current axis is lin -> switch to log +0044 label = strrep(label,'log','lin'); +0045 else % current axis is log -> switch to lin +0046 label = strrep(label,'lin','log'); +0047 end +0048 set(src,'Label',label); +0049 +0050 % call the respective functions that update the plot axes +0051 switch fig_tag +0052 case 'INV' +0053 updatePlotsSignal; +0054 updatePlotsJointInversion; +0055 case 'MOD' +0056 updatePlotsNMR; +0057 end +0058 0059 end 0060 -0061 end +0061 %------------- END OF CODE -------------- 0062 -0063 %------------- END OF CODE -------------- -0064 -0065 %% License: -0066 % MIT License +0063 %% License: +0064 % MIT License +0065 % +0066 % Copyright (c) 2018 Thomas Hiller 0067 % -0068 % Copyright (c) 2018 Thomas Hiller -0069 % -0070 % Permission is hereby granted, free of charge, to any person obtaining a copy -0071 % of this software and associated documentation files (the "Software"), to deal -0072 % in the Software without restriction, including without limitation the rights -0073 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0074 % copies of the Software, and to permit persons to whom the Software is -0075 % furnished to do so, subject to the following conditions: -0076 % -0077 % The above copyright notice and this permission notice shall be included in all -0078 % copies or substantial portions of the Software. -0079 % -0080 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0081 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0082 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0083 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0084 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0085 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0086 % SOFTWARE. +0068 % Permission is hereby granted, free of charge, to any person obtaining a copy +0069 % of this software and associated documentation files (the "Software"), to deal +0070 % in the Software without restriction, including without limitation the rights +0071 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0072 % copies of the Software, and to permit persons to whom the Software is +0073 % furnished to do so, subject to the following conditions: +0074 % +0075 % The above copyright notice and this permission notice shall be included in all +0076 % copies or substantial portions of the Software. +0077 % +0078 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0079 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0080 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0081 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0082 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0083 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0084 % 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 c9565c6..b6eb234 100644 --- a/doc/nucleus/callbacks/listboxes/onListboxData.html +++ b/doc/nucleus/callbacks/listboxes/onListboxData.html @@ -67,10 +67,10 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • NUCLEUSinv_updateInterface updates all GUI elements
  • onPopupInvstdType selects the inversion method for the standard inversion
  • onPushRun handles the callbacks to all RUN push buttons in both GUIs and
  • FixedTimeView is an extra subGUI to fix certain relaxation times during
  • PhaseView is an extra subGUI to manipulate the phase of a T2 signal
  • UncertView is an extra subGUI to show results of the uncertainty
  • clearSingleAxis clears an individual axis
  • processNMRDataControl prepares simple NMR raw data processing
  • 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
  • updatePlotsJointInversion plots the joint-inversion results in NUCLEUSinv
  • updatePlotsLcurve plots the results of the L-curve calculation
  • updatePlotsSignal plots the raw and processed NMR signals in NUCLEUSinv
  • This function is called by: +
  • NUCLEUSinv_createPanelData creates data panel
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • PhaseView is an extra subGUI to manipulate the phase of a T2 signal
  • importINV2INV imports a previously saved NUCLEUSinv session
  • runInversionBatch batch processes the inversion using for all NMR signals
  • @@ -270,63 +270,65 @@

    SOURCE CODE ^% reset all RUN buttons 0193 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... 0194 'BackgroundColor','g','Enable','on','Callback',@onPushRun); -0195 set(gui.push_handles.invjoint_run,'String','<HTML><u>R</u>UN',... +0195 set(gui.push_handles.uncert,'String','CALC.',... 0196 'BackgroundColor','g','Enable','on','Callback',@onPushRun); -0197 -0198 % if the Fit Statistics window is open update it -0199 if ~isempty(findobj('Tag','FITSTATS')) -0200 showFitStatistics; -0201 end -0202 % if the PhaseView window is open update it -0203 if ~isempty(findobj('Tag','PHASEVIEW')) -0204 PhaseView(gui.menu.extra_phaseview); -0205 end -0206 % if the FixedTimeView window is open update it -0207 if ~isempty(findobj('Tag','FIXEDTIMEVIEW')) -0208 FixedTimeView(gui.menu.extra_fixedtime); -0209 end -0210 % if the UncertView window is open update it -0211 if ~isempty(findobj('Tag','UNCERTVIEW')) -0212 UncertView(gui.menu.extra_uncert); -0213 end -0214 else -0215 helpdlg({'onListboxData:','Only choose one data set at a time.'},... -0216 'too many data'); -0217 end -0218 else -0219 helpdlg('Nothing to do because there is no data loaded!',... -0220 'onListboxData: Load NMR data first.'); -0221 end -0222 -0223 % update the figure data -0224 setappdata(fig,'gui',gui); -0225 -0226 end +0197 set(gui.push_handles.invjoint_run,'String','<HTML><u>R</u>UN',... +0198 'BackgroundColor','g','Enable','on','Callback',@onPushRun); +0199 +0200 % if the Fit Statistics window is open update it +0201 if ~isempty(findobj('Tag','FITSTATS')) +0202 showFitStatistics; +0203 end +0204 % if the PhaseView window is open update it +0205 if ~isempty(findobj('Tag','PHASEVIEW')) +0206 PhaseView(gui.menu.extra_phaseview); +0207 end +0208 % if the FixedTimeView window is open update it +0209 if ~isempty(findobj('Tag','FIXEDTIMEVIEW')) +0210 FixedTimeView(gui.menu.extra_fixedtime); +0211 end +0212 % if the UncertView window is open update it +0213 if ~isempty(findobj('Tag','UNCERTVIEW')) +0214 UncertView(gui.menu.extra_uncert); +0215 end +0216 else +0217 helpdlg({'onListboxData:','Only choose one data set at a time.'},... +0218 'too many data'); +0219 end +0220 else +0221 helpdlg('Nothing to do because there is no data loaded!',... +0222 'onListboxData: Load NMR data first.'); +0223 end +0224 +0225 % update the figure data +0226 setappdata(fig,'gui',gui); 0227 -0228 %------------- END OF CODE -------------- +0228 end 0229 -0230 %% License: -0231 % MIT License -0232 % -0233 % Copyright (c) 2018 Thomas Hiller +0230 %------------- END OF CODE -------------- +0231 +0232 %% License: +0233 % MIT License 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 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. +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.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/menus/menu.html b/doc/nucleus/callbacks/menus/menu.html index feb0b62..d92387f 100644 --- a/doc/nucleus/callbacks/menus/menu.html +++ b/doc/nucleus/callbacks/menus/menu.html @@ -18,7 +18,7 @@

    Index for nucleus\callbacks\menus

    Matlab files in this directory:

    +
  • onMenuExpert
  • onMenuExportData
  • onMenuExportGraphics
  • onMenuExtraColor
  • onMenuExtraEchoFlag
  • onMenuExtraFindDuplicates
  • onMenuExtraGraphics
  • onMenuExtraRhoBounds
  • onMenuExtraShow
  • onMenuHelp
  • onMenuImport
  • onMenuJointInversion
  • onMenuRestartQuit
  • onMenuSolver
  • onMenuSubGUIs
  • onMenuView
  • onMenuViewFigures
  • diff --git a/doc/nucleus/callbacks/menus/onMenuExpert.html b/doc/nucleus/callbacks/menus/onMenuExpert.html index b12af7f..2fbdcf7 100644 --- a/doc/nucleus/callbacks/menus/onMenuExpert.html +++ b/doc/nucleus/callbacks/menus/onMenuExpert.html @@ -149,99 +149,107 @@

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

    onMenuExtraFindDuplicates +

    + +

    PURPOSE ^

    +
    finds duplicate NMR signals (mostly a HELIOS issue)
    + +

    SYNOPSIS ^

    +
    function onMenuExtraFindDuplicates(src,~)
    + +

    DESCRIPTION ^

    +
    onMenuExtraFindDuplicates finds duplicate NMR signals (mostly a HELIOS issue)
    +
    + Syntax:
    +       onMenuExtraFindDuplicates(src,~)
    +
    + Inputs:
    +       src - handle of the calling object
    +
    + Outputs:
    +       none
    +
    + Example:
    +       onMenuExtraFindDuplicates(src)
    +
    + Other m-files required:
    +       none
    +
    + 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: + + + + + +

    SOURCE CODE ^

    +
    0001 function onMenuExtraFindDuplicates(src,~)
    +0002 %onMenuExtraFindDuplicates finds duplicate NMR signals (mostly a HELIOS issue)
    +0003 %
    +0004 % Syntax:
    +0005 %       onMenuExtraFindDuplicates(src,~)
    +0006 %
    +0007 % Inputs:
    +0008 %       src - handle of the calling object
    +0009 %
    +0010 % Outputs:
    +0011 %       none
    +0012 %
    +0013 % Example:
    +0014 %       onMenuExtraFindDuplicates(src)
    +0015 %
    +0016 % Other m-files required:
    +0017 %       none
    +0018 %
    +0019 % Subfunctions:
    +0020 %       none
    +0021 %
    +0022 % MAT-files required:
    +0023 %       none
    +0024 %
    +0025 % See also: NUCLEUSinv
    +0026 % Author: see AUTHORS.md
    +0027 % email: see AUTHORS.md
    +0028 % License: MIT License (at end)
    +0029 
    +0030 %------------- BEGIN CODE --------------
    +0031 
    +0032 %% get GUI handle and data
    +0033 fig = ancestor(src,'figure','toplevel');
    +0034 gui = getappdata(fig,'gui');
    +0035 data = getappdata(fig,'data');
    +0036 INVdata = getappdata(fig,'INVdata');
    +0037 
    +0038 hasData = false;
    +0039 if isfield(data.import,'NMR')
    +0040     hasData = true;
    +0041 end
    +0042 
    +0043 if hasData
    +0044 
    +0045     %% 1. before we do anything, sort the data by date (time)
    +0046     time = zeros(numel(data.import.NMR.filesShort),1);
    +0047     timestamp = zeros(numel(data.import.NMR.filesShort),1);
    +0048     for i = 1:numel(data.import.NMR.filesShort)
    +0049         time(i,1) = data.import.NMR.data{i}.datenum;
    +0050         timestamp(i,1) = data.import.NMR.para{i}.timestamp;
    +0051     end
    +0052     [~,ix] = sort(time);
    +0053     % now apply changes - resort the imported data
    +0054     data.import.NMR.data = {data.import.NMR.data{ix'}}; %#ok<*CCAT1>
    +0055     data.import.NMR.para = {data.import.NMR.para{ix'}};
    +0056     data.import.NMR.files = data.import.NMR.files(ix);
    +0057     data.import.NMR.filesShort = {data.import.NMR.filesShort{ix'}};
    +0058     % the timestamps can also indicate duplicate signals
    +0059     timestamp = timestamp(ix);
    +0060     dts = [0; diff(timestamp)];
    +0061     % and resort possible already stored inversion data
    +0062     INVdata = {INVdata{ix(:)}}';
    +0063     % update the listbox entries
    +0064     shownames = get(gui.listbox_handles.signal,'String');
    +0065     set(gui.listbox_handles.signal,'String',{shownames{ix}});
    +0066     set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0);
    +0067 
    +0068     %% 2. checking starts at the second signal
    +0069     dup_ids = zeros(1,1);
    +0070     keep_ids = 1:1:numel(data.import.NMR.data);
    +0071     keep_ids = keep_ids(:);
    +0072     c = 0;
    +0073     for i1 = 2:numel(data.import.NMR.data)
    +0074 
    +0075         s0 = data.import.NMR.data{i1-1}.signal;
    +0076         s1 = data.import.NMR.data{i1}.signal;
    +0077 
    +0078         if s0==s1
    +0079             c = c + 1;
    +0080             dup_ids(c,1) = i1;
    +0081             keep_ids(keep_ids == i1) = [];
    +0082         end
    +0083     end
    +0084     % if we found something, ask what to do
    +0085     if sum(dup_ids) > 0
    +0086         answer = questdlg('What to do with the duplicate signals?',...
    +0087             'Duplicates Found',...
    +0088             'Keep & Mark','Delete','Nothing','Delete');
    +0089         switch answer
    +0090             case 'Keep & Mark'
    +0091                 shownames = data.import.NMR.filesShort;
    +0092                 for i1 = 1:numel(dup_ids)
    +0093                     shownames{dup_ids(i1)} = [shownames{dup_ids(i1)},'_dup'];
    +0094                 end
    +0095                 data.import.NMR.filesShort = shownames;
    +0096                 set(gui.listbox_handles.signal,'String',shownames);
    +0097                 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0);
    +0098 
    +0099                 msgbox([num2str(numel(dup_ids)),...
    +0100                     ' signals have been marked as duplicate.']);
    +0101 
    +0102             case 'Delete'
    +0103                 ix = keep_ids;
    +0104                 data.import.NMR.data = {data.import.NMR.data{ix'}}; %#ok<*CCAT1>
    +0105                 data.import.NMR.para = {data.import.NMR.para{ix'}};
    +0106                 data.import.NMR.files = data.import.NMR.files(ix);
    +0107                 data.import.NMR.filesShort = {data.import.NMR.filesShort{ix'}};
    +0108                 % and resort possible already stored inversion data
    +0109                 INVdata = {INVdata{ix(:)}}';
    +0110 
    +0111                 % update the listbox entries
    +0112                 shownames = get(gui.listbox_handles.signal,'String');
    +0113                 set(gui.listbox_handles.signal,'String',{shownames{ix}});
    +0114                 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0);
    +0115 
    +0116                 msgbox([num2str(numel(dup_ids)),' signals have been deleted.']);
    +0117 
    +0118             case 'Nothing'
    +0119         end
    +0120     else
    +0121         msgbox('No duplicate signals have been found.');
    +0122     end
    +0123 
    +0124     % update the GUI data
    +0125     setappdata(fig,'data',data);
    +0126     setappdata(fig,'INVdata',INVdata);
    +0127 
    +0128 else
    +0129     helpdlg('Nothing to do because there is no data loaded!',...
    +0130         'onMenuExtraFindDuplicates: Load NMR data first.');
    +0131 end
    +0132 
    +0133 end
    +0134 
    +0135 %------------- END OF CODE --------------
    +0136 
    +0137 %% License:
    +0138 % MIT License
    +0139 %
    +0140 % Copyright (c) 2024 Thomas Hiller
    +0141 %
    +0142 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +0143 % of this software and associated documentation files (the "Software"), to deal
    +0144 % in the Software without restriction, including without limitation the rights
    +0145 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +0146 % copies of the Software, and to permit persons to whom the Software is
    +0147 % furnished to do so, subject to the following conditions:
    +0148 %
    +0149 % The above copyright notice and this permission notice shall be included in all
    +0150 % copies or substantial portions of the Software.
    +0151 %
    +0152 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +0153 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +0154 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +0155 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +0156 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +0157 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +0158 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/callbacks/menus/onMenuImport.html b/doc/nucleus/callbacks/menus/onMenuImport.html index 0c8c71e..d616576 100644 --- a/doc/nucleus/callbacks/menus/onMenuImport.html +++ b/doc/nucleus/callbacks/menus/onMenuImport.html @@ -64,7 +64,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • onMenuImport handles the import menu entries
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importINV2INV imports a previously saved NUCLEUSinv session
  • importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
  • importMOD2INV imports data directly from the NUCLEUSmod GUI or and
  • importMOD2MOD imports previously saved NUCLEUSmod data back into the GUI
  • importNMRdata is the general import routine for NMR data
  • makeINIfile creates or updates the ini-File
  • uncheckImportMenus unchecks all import menus in NUCLEUSinv
  • This function is called by: @@ -129,71 +129,73 @@

    SOURCE CODE ^case 'NUCLEUSinv' 0055 importINV2INV(src); 0056 case 'NUCLEUSmod' -0057 importMOD2INV(src); -0058 case 'Excel' -0059 importEXCELdata(src); -0060 case 'Ascii' -0061 importASCIIdata(src); -0062 case 'Lab' -0063 importNMRdata(src); -0064 otherwise -0065 helpdlg({'function: onMenuImport','Menu tag not known.'},... -0066 'menu not known') -0067 end -0068 -0069 % activate the PhaseView GUI in case real data is imported -0070 switch menu_tag -0071 case 'NUCLEUSmod' -0072 set(gui.menu.extra_phaseview,'Enable','off'); -0073 otherwise -0074 set(gui.menu.extra_phaseview,'Enable','on'); -0075 end -0076 -0077 % get updated gui data -0078 gui = getappdata(fig,'gui'); -0079 % update the "last import" value within the ini-file -0080 gui.myui.inidata.lastimport = [menu_tag,'_',label]; -0081 setappdata(fig,'gui',gui); -0082 gui = makeINIfile(gui,'update'); -0083 % and the menu entry itself -0084 switch label -0085 case 'LIAG from project' -0086 label = 'LIAG last project'; -0087 set(gui.menu.file_import_lastimport,'Label',label,... -0088 'Tag',menu_tag,'Callback',@onMenuImport) -0089 otherwise -0090 set(gui.menu.file_import_lastimport,'Label',label,... -0091 'Tag',menu_tag,'Callback',@onMenuImport); -0092 end -0093 setappdata(fig,'gui',gui); -0094 end -0095 +0057 importMOD2INV(src); +0058 case 'NUCLEUSmod2d' +0059 importMOD2D2INV(src); +0060 case 'Excel' +0061 importEXCELdata(src); +0062 case 'Ascii' +0063 importASCIIdata(src); +0064 case 'Lab' +0065 importNMRdata(src); +0066 otherwise +0067 helpdlg({'function: onMenuImport','Menu tag not known.'},... +0068 'menu not known') +0069 end +0070 +0071 % activate the PhaseView GUI in case real data is imported +0072 switch menu_tag +0073 case 'NUCLEUSmod' +0074 set(gui.menu.extra_phaseview,'Enable','off'); +0075 otherwise +0076 set(gui.menu.extra_phaseview,'Enable','on'); +0077 end +0078 +0079 % get updated gui data +0080 gui = getappdata(fig,'gui'); +0081 % update the "last import" value within the ini-file +0082 gui.myui.inidata.lastimport = [menu_tag,'_',label]; +0083 setappdata(fig,'gui',gui); +0084 gui = makeINIfile(gui,'update'); +0085 % and the menu entry itself +0086 switch label +0087 case 'LIAG from project' +0088 label = 'LIAG last project'; +0089 set(gui.menu.file_import_lastimport,'Label',label,... +0090 'Tag',menu_tag,'Callback',@onMenuImport) +0091 otherwise +0092 set(gui.menu.file_import_lastimport,'Label',label,... +0093 'Tag',menu_tag,'Callback',@onMenuImport); +0094 end +0095 setappdata(fig,'gui',gui); 0096 end 0097 -0098 %------------- END OF CODE -------------- +0098 end 0099 -0100 %% License: -0101 % MIT License -0102 % -0103 % Copyright (c) 2018 Thomas Hiller +0100 %------------- END OF CODE -------------- +0101 +0102 %% License: +0103 % MIT License 0104 % -0105 % Permission is hereby granted, free of charge, to any person obtaining a copy -0106 % of this software and associated documentation files (the "Software"), to deal -0107 % in the Software without restriction, including without limitation the rights -0108 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0109 % copies of the Software, and to permit persons to whom the Software is -0110 % furnished to do so, subject to the following conditions: -0111 % -0112 % The above copyright notice and this permission notice shall be included in all -0113 % copies or substantial portions of the Software. -0114 % -0115 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0116 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0117 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0118 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0119 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0120 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0121 % SOFTWARE. +0105 % Copyright (c) 2018 Thomas Hiller +0106 % +0107 % Permission is hereby granted, free of charge, to any person obtaining a copy +0108 % of this software and associated documentation files (the "Software"), to deal +0109 % in the Software without restriction, including without limitation the rights +0110 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0111 % copies of the Software, and to permit persons to whom the Software is +0112 % furnished to do so, subject to the following conditions: +0113 % +0114 % The above copyright notice and this permission notice shall be included in all +0115 % copies or substantial portions of the Software. +0116 % +0117 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0118 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0119 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0120 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0121 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0122 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0123 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/menus/onMenuSubGUIs.html b/doc/nucleus/callbacks/menus/onMenuSubGUIs.html index ef67739..c9fa325 100644 --- a/doc/nucleus/callbacks/menus/onMenuSubGUIs.html +++ b/doc/nucleus/callbacks/menus/onMenuSubGUIs.html @@ -61,7 +61,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • ConductView is an extra subGUI to visualize hydraulic conductivity
  • FixedTimeView is an extra subGUI to fix certain relaxation times during
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • PhaseView is an extra subGUI to manipulate the phase of a T2 signal
  • UncertView is an extra subGUI to show results of the uncertainty
  • This function is called by: @@ -156,34 +156,44 @@

    SOURCE CODE ^'Cannot continue because there is no data!'},... 0085 'No inversion data.'); 0086 end -0087 end -0088 -0089 end -0090 -0091 %------------- END OF CODE -------------- -0092 -0093 %% License: -0094 % MIT License -0095 % -0096 % Copyright (c) 2024 Thomas Hiller -0097 % -0098 % Permission is hereby granted, free of charge, to any person obtaining a copy -0099 % of this software and associated documentation files (the "Software"), to deal -0100 % in the Software without restriction, including without limitation the rights -0101 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0102 % copies of the Software, and to permit persons to whom the Software is -0103 % furnished to do so, subject to the following conditions: -0104 % -0105 % The above copyright notice and this permission notice shall be included in all -0106 % copies or substantial portions of the Software. +0087 case '2DInv GUI' +0088 if isfield(data.import,'T1T2map') +0089 Inv2DView(src); +0090 else +0091 helpdlg({'function: Inv2DView',... +0092 'Cannot continue because there is no data!'},... +0093 'No T1T2 data.'); +0094 end +0095 case '2DMod GUI' +0096 Mod2DView(src); +0097 end +0098 +0099 end +0100 +0101 %------------- END OF CODE -------------- +0102 +0103 %% License: +0104 % MIT License +0105 % +0106 % Copyright (c) 2024 Thomas Hiller 0107 % -0108 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0109 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0110 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0111 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0112 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0113 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0114 % SOFTWARE. +0108 % Permission is hereby granted, free of charge, to any person obtaining a copy +0109 % of this software and associated documentation files (the "Software"), to deal +0110 % in the Software without restriction, including without limitation the rights +0111 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0112 % copies of the Software, and to permit persons to whom the Software is +0113 % furnished to do so, subject to the following conditions: +0114 % +0115 % The above copyright notice and this permission notice shall be included in all +0116 % copies or substantial portions of the Software. +0117 % +0118 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0119 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0120 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0121 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0122 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0123 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0124 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/menus/onMenuView.html b/doc/nucleus/callbacks/menus/onMenuView.html index 6bc9e96..4ea7fbb 100644 --- a/doc/nucleus/callbacks/menus/onMenuView.html +++ b/doc/nucleus/callbacks/menus/onMenuView.html @@ -62,7 +62,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=onPushShowHide shows/hides the INFO column on the right side of NUCLEUSinv
  • makeINIfile creates or updates the ini-File
  • switchToolTips switches GUI tool tips either "on" or "off"
  • updateStatusInformation updates all fields inside the bottom status bar
  • This function is called by: +
  • NUCLEUSinv_createMenus creates all GUI menus
  • NUCLEUSmod_createMenus creates all GUI menus
  • ConductView is an extra subGUI to visualize hydraulic conductivity
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • PhaseView is an extra subGUI to manipulate the phase of a T2 signal
  • UncertView is an extra subGUI to show results of the uncertainty
  • importINV2INV imports a previously saved NUCLEUSinv session
  • @@ -113,7 +113,7 @@

    SOURCE CODE ^'Checked')); 0044 0045 switch fig_tag -0046 +0046 0047 case 'INV' 0048 switch label 0049 case 'Tooltips' @@ -130,7 +130,7 @@

    SOURCE CODE ^% update ini-file 0061 gui.myui.inidata.tooltips = data.info.ToolTips; 0062 gui = makeINIfile(gui,'update'); -0063 +0063 0064 case 'Figure Toolbar' % switch on/off the default Figure Toolbar 0065 switch onoff 0066 case 'on' % it it's on, switch it off @@ -140,7 +140,7 @@

    SOURCE CODE ^'Checked','on'); 0071 viewmenufcn('FigureToolbar'); 0072 end -0073 +0073 0074 case 'INFO fields' 0075 switch onoff 0076 case 'on' % it it's on, switch it off @@ -149,7 +149,7 @@

    SOURCE CODE ^'String','<'); 0080 end 0081 onPushShowHide(gui.push_handles.info); -0082 +0082 0083 case 'CLI Inv. Info' 0084 switch onoff 0085 case 'on' % it it's on, switch it off @@ -163,65 +163,90 @@

    SOURCE CODE ^makeINIfile(gui,'update'); 0095 end -0096 -0097 case 'MOD' +0096 +0097 case {'2DINV','PHASEVIEW','UNCERTVIEW','CONDUCT'} 0098 switch label -0099 case 'Tooltips' +0099 case 'Figure Toolbar' % switch on/off the default Figure Toolbar 0100 switch onoff 0101 case 'on' % it it's on, switch it off -0102 set(gui.menu.view_tooltips,'Checked','off'); -0103 switchToolTips(gui,'off'); -0104 data.info.ToolTips = 'off'; -0105 case 'off' -0106 set(gui.menu.view_tooltips,'Checked','on'); -0107 switchToolTips(gui,'on'); -0108 data.info.ToolTips = 'on'; -0109 end -0110 case 'Figure Toolbar' -0111 switch onoff -0112 case 'on' % it it's on, switch it off -0113 set(gui.menu.view_toolbar,'Checked','off'); -0114 viewmenufcn('FigureToolbar'); -0115 case 'off' -0116 set(gui.menu.view_toolbar,'Checked','on'); -0117 viewmenufcn('FigureToolbar'); -0118 end -0119 end -0120 end -0121 -0122 % update GUI data -0123 setappdata(fig,'gui',gui); -0124 setappdata(fig,'data',data); -0125 % update status bar -0126 updateStatusInformation(fig); -0127 -0128 -0129 end -0130 -0131 %------------- END OF CODE -------------- -0132 -0133 %% License: -0134 % MIT License -0135 % -0136 % Copyright (c) 2020 Thomas Hiller -0137 % -0138 % Permission is hereby granted, free of charge, to any person obtaining a copy -0139 % of this software and associated documentation files (the "Software"), to deal -0140 % in the Software without restriction, including without limitation the rights -0141 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0142 % copies of the Software, and to permit persons to whom the Software is -0143 % furnished to do so, subject to the following conditions: -0144 % -0145 % The above copyright notice and this permission notice shall be included in all -0146 % copies or substantial portions of the Software. -0147 % -0148 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0149 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0150 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0151 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0152 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0153 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0154 % SOFTWARE. +0102 set(gui.menu.view_toolbar,'Checked','off'); +0103 viewmenufcn('FigureToolbar'); +0104 case 'off' +0105 set(gui.menu.view_toolbar,'Checked','on'); +0106 viewmenufcn('FigureToolbar'); +0107 end +0108 end +0109 +0110 case 'MOD' +0111 switch label +0112 case 'Tooltips' +0113 switch onoff +0114 case 'on' % it it's on, switch it off +0115 set(gui.menu.view_tooltips,'Checked','off'); +0116 switchToolTips(gui,'off'); +0117 data.info.ToolTips = 'off'; +0118 case 'off' +0119 set(gui.menu.view_tooltips,'Checked','on'); +0120 switchToolTips(gui,'on'); +0121 data.info.ToolTips = 'on'; +0122 end +0123 case 'Figure Toolbar' +0124 switch onoff +0125 case 'on' % it it's on, switch it off +0126 set(gui.menu.view_toolbar,'Checked','off'); +0127 viewmenufcn('FigureToolbar'); +0128 case 'off' +0129 set(gui.menu.view_toolbar,'Checked','on'); +0130 viewmenufcn('FigureToolbar'); +0131 end +0132 end +0133 case '2DMOD' +0134 switch label +0135 case 'Figure Toolbar' % switch on/off the default Figure Toolbar +0136 switch onoff +0137 case 'on' % it it's on, switch it off +0138 set(gui.menu.view_toolbar,'Checked','off'); +0139 viewmenufcn('FigureToolbar'); +0140 case 'off' +0141 set(gui.menu.view_toolbar,'Checked','on'); +0142 viewmenufcn('FigureToolbar'); +0143 end +0144 end +0145 end +0146 +0147 % update GUI data +0148 setappdata(fig,'gui',gui); +0149 setappdata(fig,'data',data); +0150 % update status bar +0151 updateStatusInformation(fig); +0152 +0153 +0154 end +0155 +0156 %------------- END OF CODE -------------- +0157 +0158 %% License: +0159 % MIT License +0160 % +0161 % Copyright (c) 2020 Thomas Hiller +0162 % +0163 % Permission is hereby granted, free of charge, to any person obtaining a copy +0164 % of this software and associated documentation files (the "Software"), to deal +0165 % in the Software without restriction, including without limitation the rights +0166 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0167 % copies of the Software, and to permit persons to whom the Software is +0168 % furnished to do so, subject to the following conditions: +0169 % +0170 % The above copyright notice and this permission notice shall be included in all +0171 % copies or substantial portions of the Software. +0172 % +0173 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0174 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0175 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0176 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0177 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0178 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0179 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/callbacks/push/onPushRun.html b/doc/nucleus/callbacks/push/onPushRun.html index e1078df..31513b9 100644 --- a/doc/nucleus/callbacks/push/onPushRun.html +++ b/doc/nucleus/callbacks/push/onPushRun.html @@ -65,7 +65,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=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: +
  • NUCLEUSinv_createPanelInversionJoint creates joint inversion panel
  • NUCLEUSinv_createPanelInversionStd creates standard inversion panel
  • NUCLEUSmod_createPanelCPS creates pressure panel
  • NUCLEUSmod_createPanelNMR creates NMR panel
  • onContextSignalList handles the calls from the context menu of the data
  • onListboxData handles the calls from the context menu of the data
  • onPushStop recognizes that a STOP push button was pressed and resets the
  • caluclatePressureSaturation calculates the geometry dependent pressure
  • runInversionBatch batch processes the inversion using for all NMR signals
  • 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
  • diff --git a/doc/nucleus/functions/import/LoadNMRData_bamtom.html b/doc/nucleus/functions/import/LoadNMRData_bamtom.html index 6f3150d..2a5183a 100644 --- a/doc/nucleus/functions/import/LoadNMRData_bamtom.html +++ b/doc/nucleus/functions/import/LoadNMRData_bamtom.html @@ -64,7 +64,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -184,7 +184,7 @@

    SOURCE CODE ^case 'T2' 0109 data.signal = complex(d.data(:,2),d.data(:,3)); -0110 [data.signal,data.phase] = rotateT2phase(data.signal); +0110 [data.signal,data.phase] = rotateT2phase(data.signal); 0111 end 0112 0113 % save raw data diff --git a/doc/nucleus/functions/import/LoadNMRData_bgr.html b/doc/nucleus/functions/import/LoadNMRData_bgr.html index 9286697..c28c2c9 100644 --- a/doc/nucleus/functions/import/LoadNMRData_bgr.html +++ b/doc/nucleus/functions/import/LoadNMRData_bgr.html @@ -64,7 +64,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -162,7 +162,7 @@

    SOURCE CODE ^case 'T2' 0087 data.signal = complex(d(:,2),d(:,3)); -0088 [data.signal,data.phase] = rotateT2phase(data.signal); +0088 [data.signal,data.phase] = rotateT2phase(data.signal); 0089 end 0090 else 0091 data.flag = '0'; diff --git a/doc/nucleus/functions/import/LoadNMRData_bgr2.html b/doc/nucleus/functions/import/LoadNMRData_bgr2.html index fd41330..8751718 100644 --- a/doc/nucleus/functions/import/LoadNMRData_bgr2.html +++ b/doc/nucleus/functions/import/LoadNMRData_bgr2.html @@ -66,7 +66,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -175,7 +175,7 @@

    SOURCE CODE ^case 'T2' 0098 data.signal = complex(d(:,2),d(:,3)); -0099 [data.signal,data.phase] = rotateT2phase(data.signal); +0099 [data.signal,data.phase] = rotateT2phase(data.signal); 0100 end 0101 else 0102 data.flag = '0'; diff --git a/doc/nucleus/functions/import/LoadNMRData_bgrmat.html b/doc/nucleus/functions/import/LoadNMRData_bgrmat.html index e8bb426..c21b2f5 100644 --- a/doc/nucleus/functions/import/LoadNMRData_bgrmat.html +++ b/doc/nucleus/functions/import/LoadNMRData_bgrmat.html @@ -64,7 +64,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -171,7 +171,7 @@

    SOURCE CODE ^if isfield(data.sig(i),'V_im') 0097 nmrData{i}.signal = complex(data.sig(i).V_re,data.sig(i).V_im); 0098 % if there is an imag part the signal gets phase corrected -0099 [nmrData{i}.signal,nmrData{i}.phase] = rotateT2phase(nmrData{i}.signal); +0099 [nmrData{i}.signal,nmrData{i}.phase] = rotateT2phase(nmrData{i}.signal); 0100 else 0101 nmrData{i}.signal = data.sig(i).V_re; 0102 end diff --git a/doc/nucleus/functions/import/LoadNMRData_corelab.html b/doc/nucleus/functions/import/LoadNMRData_corelab.html index 3696a9a..b69ce78 100644 --- a/doc/nucleus/functions/import/LoadNMRData_corelab.html +++ b/doc/nucleus/functions/import/LoadNMRData_corelab.html @@ -64,7 +64,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -168,7 +168,7 @@

    SOURCE CODE ^'T2'; 0092 data.time = d(:,1); 0093 data.signal = complex(d(:,2),d(:,3)); -0094 [data.signal,data.phase] = rotateT2phase(data.signal); +0094 [data.signal,data.phase] = rotateT2phase(data.signal); 0095 else 0096 data.flag = '0'; 0097 data.time = 0; diff --git a/doc/nucleus/functions/import/LoadNMRData_dart.html b/doc/nucleus/functions/import/LoadNMRData_dart.html index 014cd10..2722fdc 100644 --- a/doc/nucleus/functions/import/LoadNMRData_dart.html +++ b/doc/nucleus/functions/import/LoadNMRData_dart.html @@ -66,13 +66,15 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: - +

    SUBFUNCTIONS ^

    +

    SOURCE CODE ^

    0001 function out = LoadNMRData_dart(in)
    @@ -115,13 +117,13 @@ 

    SOURCE CODE ^%------------- BEGIN CODE -------------- 0039 0040 %% start processing the files -0041 % load the Matlab mat-file -0042 data = load(fullfile(in.path,in.name)); -0043 file = dir(fullfile(in.path,in.name)); -0044 -0045 switch in.version -0046 -0047 case 1 +0041 +0042 switch in.version +0043 case 1 +0044 % load the Matlab mat-file +0045 data = load(fullfile(in.path,in.name)); +0046 file = dir(fullfile(in.path,in.name)); +0047 0048 % init stuff 0049 parData = cell(1,1); 0050 tmp = cell(1,1); @@ -129,7 +131,7 @@

    SOURCE CODE ^if size(data.se_vector_wc,2) > 1 0053 % command line output 0054 disp([in.name,': importing NMR files ...']); -0055 +0055 0056 nmrData = cell(1,size(data.se_vector_wc,2)); 0057 for i = 1:size(data.se_vector_wc,2) 0058 % calculate amplitudes from water contents with the @@ -139,13 +141,13 @@

    SOURCE CODE ^elseif extras.freq(i) <= 4.4e+05 && data.extras.freq(i) >= 4.2e+05 % frequency 2 0063 se_vector_amp = data.se_vector_wc(:,i)./8.429; 0064 end -0065 +0065 0066 % get file statistics 0067 nmrData{i}.datfile = file.name; 0068 nmrData{i}.date = file.date; 0069 nmrData{i}.datenum = file.datenum; 0070 nmrData{i}.bytes = file.bytes; -0071 +0071 0072 % save the NMR data 0073 nmrData{i}.flag = 'T2'; 0074 nmrData{i}.T1IRfac = 1; @@ -154,14 +156,14 @@

    SOURCE CODE ^% create parameter data 0082 parData{i}.acq_params_Tr = data.acq_params.Tr; 0083 parData{i}.depth = data.depth(i); 0084 parData{i}.Qs = data.extras.Qs(i); 0085 parData{i}.DCbus = data.extras.DC_bus(i); 0086 parData{i}.freq = data.extras.freq(i); -0087 +0087 0088 fields = fieldnames(parData{i}); 0089 for j = 1:size(fields,1) 0090 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',... @@ -170,12 +172,12 @@

    SOURCE CODE ^% command line output 0098 disp([in.name,': importing NMR files ',sprintf('%03d',i),... 0099 ' / ',sprintf('%03d',size(data.se_vector_wc,2))]); 0100 end -0101 +0101 0102 else 0103 % calculate amplitudes from water contents with the 0104 % frequency-specific multiplication factors @@ -184,13 +186,13 @@

    SOURCE CODE ^elseif extras.freq <= 4.4e+05 && extras.freq >= 4.2e+05 % frequency 2 0108 se_vector_amp = data.se_vector_wc./8.429; 0109 end -0110 +0110 0111 % get file statistics 0112 nmrData{1}.datfile = file.name; 0113 nmrData{1}.date = file.date; 0114 nmrData{1}.datenum = file.datenum; 0115 nmrData{1}.bytes = file.bytes; -0116 +0116 0117 % save the NMR data 0118 nmrData{1}.flag = 'T2'; 0119 nmrData{1}.T1IRfac = 1; @@ -199,14 +201,14 @@

    SOURCE CODE ^% create parameter data 0127 parData{1}.acq_params_Tr = data.acq_params.Tr; 0128 parData{1}.depth = data.depth; 0129 parData{1}.Qs = data.extras.Qs; 0130 parData{1}.DCbus = data.extras.DC_bus; 0131 parData{1}.freq = data.extras.freq; -0132 +0132 0133 fields = fieldnames(parData{1}); 0134 for j = 1:size(fields,1) 0135 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',... @@ -215,158 +217,334 @@

    SOURCE CODE ^end -0141 +0141 0142 case 2 -0143 % init stuff -0144 parData = cell(1,size(data.jpd.stack.se,1)); -0145 tmp = cell(1,1); -0146 % check, if it is one or multiple depths -0147 if size(data.jpd.stack.se,1) > 1 -0148 % command line output -0149 disp([in.name,': importing NMR files ...']); -0150 -0151 nmrData = cell(1,size(data.jpd.stack.se,1)); -0152 for i = 1:size(data.jpd.stack.se,1) % loop over all depths -0153 % get file statistics -0154 nmrData{i}.datfile = file.name; -0155 nmrData{i}.date = datestr(data.jpd.acq_time(i)); -0156 nmrData{i}.datenum = data.jpd.acq_time(i); -0157 nmrData{i}.bytes = file.bytes; -0158 -0159 % save the NMR data -0160 nmrData{i}.flag = 'T2'; -0161 nmrData{i}.T1IRfac = 1; -0162 nmrData{i}.time = data.jpd.stack.time(1,1:end)'; -0163 nmrData{i}.signal = data.jpd.stack.se(i,1:end)'; -0164 nmrData{i}.raw.time = data.jpd.stack.time(1,1:end)'; -0165 nmrData{i}.raw.signal = data.jpd.stack.se(i,1:end)'; -0166 nmrData{i}.phase = 0; -0167 -0168 % create parameter data -0169 parData{i}.acq_params_Tr = 4; -0170 parData{i}.depth = data.jpd.depth_raw(i); -0171 -0172 fields = fieldnames(parData{i}); -0173 for j = 1:size(fields,1) -0174 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(i),'}.',fields{j}]))]; -0175 end -0176 d{1} = tmp; -0177 parData{i}.all = d; -0178 clear d tmp -0179 -0180 % command line output -0181 disp([in.name,': importing NMR files ',sprintf('%03d',i),... -0182 ' / ',sprintf('%03d',size(data.jpd.stack.se,1))]); -0183 end -0184 -0185 else -0186 % get file statistics -0187 nmrData{1}.datfile = file.name; -0188 nmrData{1}.date = file.date; -0189 nmrData{1}.datenum = file.datenum; -0190 nmrData{1}.bytes = file.bytes; -0191 -0192 % save the NMR data -0193 nmrData{1}.flag = 'T2'; -0194 nmrData{1}.T1IRfac = 1; -0195 nmrData{1}.time = data.jpd.stack.time(1,1:end)'; -0196 nmrData{1}.signal = data.jpd.stack.se(1,1:end)'; -0197 nmrData{1}.raw.time = data.jpd.stack.time(1,1:end)'; -0198 nmrData{1}.raw.signal = data.jpd.stack.se(1,1:end)'; -0199 nmrData{1}.phase = 0; -0200 -0201 % create parameter data -0202 parData{1}.acq_params_Tr = 4; -0203 parData{1}.depth = data.jpd.depth_raw(1); -0204 -0205 fields = fieldnames(parData{1}); -0206 for j = 1:size(fields,1) -0207 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(1),'}.',fields{j}]))]; -0208 end -0209 d{1} = tmp; -0210 parData{1}.all = d; -0211 end -0212 -0213 case 3 % University of Vienna -0214 -0215 disp([in.name,': importing NMR data ...']); +0143 % load the Matlab mat-file +0144 data = load(fullfile(in.path,in.name)); +0145 file = dir(fullfile(in.path,in.name)); +0146 +0147 % init stuff +0148 parData = cell(1,size(data.jpd.stack.se,1)); +0149 tmp = cell(1,1); +0150 % check, if it is one or multiple depths +0151 if size(data.jpd.stack.se,1) > 1 +0152 % command line output +0153 disp([in.name,': importing NMR files ...']); +0154 +0155 nmrData = cell(1,size(data.jpd.stack.se,1)); +0156 for i = 1:size(data.jpd.stack.se,1) % loop over all depths +0157 % get file statistics +0158 nmrData{i}.datfile = file.name; +0159 nmrData{i}.date = datestr(data.jpd.acq_time(i)); +0160 nmrData{i}.datenum = data.jpd.acq_time(i); +0161 nmrData{i}.bytes = file.bytes; +0162 +0163 % save the NMR data +0164 nmrData{i}.flag = 'T2'; +0165 nmrData{i}.T1IRfac = 1; +0166 nmrData{i}.time = data.jpd.stack.time(1,1:end)'; +0167 nmrData{i}.signal = data.jpd.stack.se(i,1:end)'; +0168 nmrData{i}.raw.time = data.jpd.stack.time(1,1:end)'; +0169 nmrData{i}.raw.signal = data.jpd.stack.se(i,1:end)'; +0170 nmrData{i}.phase = 0; +0171 +0172 % create parameter data +0173 parData{i}.acq_params_Tr = 4; +0174 parData{i}.depth = data.jpd.depth_raw(i); +0175 +0176 fields = fieldnames(parData{i}); +0177 for j = 1:size(fields,1) +0178 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(i),'}.',fields{j}]))]; +0179 end +0180 d{1} = tmp; +0181 parData{i}.all = d; +0182 clear d tmp +0183 +0184 % command line output +0185 disp([in.name,': importing NMR files ',sprintf('%03d',i),... +0186 ' / ',sprintf('%03d',size(data.jpd.stack.se,1))]); +0187 end +0188 +0189 else +0190 % get file statistics +0191 nmrData{1}.datfile = file.name; +0192 nmrData{1}.date = file.date; +0193 nmrData{1}.datenum = file.datenum; +0194 nmrData{1}.bytes = file.bytes; +0195 +0196 % save the NMR data +0197 nmrData{1}.flag = 'T2'; +0198 nmrData{1}.T1IRfac = 1; +0199 nmrData{1}.time = data.jpd.stack.time(1,1:end)'; +0200 nmrData{1}.signal = data.jpd.stack.se(1,1:end)'; +0201 nmrData{1}.raw.time = data.jpd.stack.time(1,1:end)'; +0202 nmrData{1}.raw.signal = data.jpd.stack.se(1,1:end)'; +0203 nmrData{1}.phase = 0; +0204 +0205 % create parameter data +0206 parData{1}.acq_params_Tr = 4; +0207 parData{1}.depth = data.jpd.depth_raw(1); +0208 +0209 fields = fieldnames(parData{1}); +0210 for j = 1:size(fields,1) +0211 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(1),'}.',fields{j}]))]; +0212 end +0213 d{1} = tmp; +0214 parData{1}.all = d; +0215 end 0216 -0217 % init stuff -0218 tmp = cell(1,1); -0219 nmrData = cell(1,numel(data.jpd.depth)); -0220 parData = cell(1,numel(data.jpd.depth)); -0221 -0222 for i = 1:numel(data.jpd.depth) % loop over all depths -0223 % get file statistics -0224 nmrData{i}.datfile = file.name; -0225 nmrData{i}.date = file.date; -0226 nmrData{i}.datenum = file.datenum; -0227 nmrData{i}.bytes = file.bytes; +0217 case 3 % University of Vienna +0218 % load the Matlab mat-file +0219 data = load(fullfile(in.path,in.name)); +0220 file = dir(fullfile(in.path,in.name)); +0221 +0222 disp([in.name,': importing NMR data ...']); +0223 +0224 % init stuff +0225 tmp = cell(1,1); +0226 nmrData = cell(1,numel(data.jpd.depth)); +0227 parData = cell(1,numel(data.jpd.depth)); 0228 -0229 % save the NMR data -0230 nmrData{i}.flag = 'T2'; -0231 nmrData{i}.T1IRfac = 1; -0232 nmrData{i}.time = data.jpd.freq_stack.time(1,1:end)'; -0233 nmrData{i}.signal = data.jpd.freq_stack.se(i,1:end)'; -0234 nmrData{i}.raw.time = data.jpd.freq_stack.time(1,1:end)'; -0235 nmrData{i}.raw.signal = data.jpd.freq_stack.se(i,1:end)'; -0236 nmrData{i}.phase = 0; -0237 -0238 % create parameter data -0239 parData{i}.depth = data.jpd.depth(i); -0240 parData{i}.depth_units = data.jpd.depth_units; -0241 parData{i}.depth_offset = data.state_proc.depth_offset; -0242 parData{i}.stack_method = data.state_proc.stack_method; -0243 parData{i}.phase_method = data.state_proc.phase_method; -0244 parData{i}.d_avg = data.state_proc.d_avg; -0245 parData{i}.reg_factor = data.state_proc.reg_factor; -0246 parData{i}.min_T2 = data.state_proc.min_T2; -0247 parData{i}.doDCscale = data.state_proc.doDCscale; -0248 -0249 fields = fieldnames(parData{i}); -0250 for j = 1:size(fields,1) -0251 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(i),'}.',fields{j}]))]; -0252 end -0253 d{1} = tmp; -0254 parData{i}.all = d; -0255 clear d tmp -0256 -0257 % command line output -0258 disp([in.name,': importing NMR data from depth: ',... -0259 sprintf('%3.2f',data.jpd.depth(i)),' ',data.jpd.depth_units]); -0260 end -0261 end -0262 -0263 % save data to output struct -0264 out.nmrData = nmrData; -0265 out.parData = parData; -0266 -0267 end +0229 for i = 1:numel(data.jpd.depth) % loop over all depths +0230 % get file statistics +0231 nmrData{i}.datfile = file.name; +0232 nmrData{i}.date = file.date; +0233 nmrData{i}.datenum = file.datenum; +0234 nmrData{i}.bytes = file.bytes; +0235 +0236 % save the NMR data +0237 nmrData{i}.flag = 'T2'; +0238 nmrData{i}.T1IRfac = 1; +0239 nmrData{i}.time = data.jpd.freq_stack.time(1,1:end)'; +0240 nmrData{i}.signal = data.jpd.freq_stack.se(i,1:end)'; +0241 nmrData{i}.raw.time = data.jpd.freq_stack.time(1,1:end)'; +0242 nmrData{i}.raw.signal = data.jpd.freq_stack.se(i,1:end)'; +0243 nmrData{i}.phase = 0; +0244 +0245 % create parameter data +0246 parData{i}.depth = data.jpd.depth(i); +0247 parData{i}.depth_units = data.jpd.depth_units; +0248 parData{i}.depth_offset = data.state_proc.depth_offset; +0249 parData{i}.stack_method = data.state_proc.stack_method; +0250 parData{i}.phase_method = data.state_proc.phase_method; +0251 parData{i}.d_avg = data.state_proc.d_avg; +0252 parData{i}.reg_factor = data.state_proc.reg_factor; +0253 parData{i}.min_T2 = data.state_proc.min_T2; +0254 parData{i}.doDCscale = data.state_proc.doDCscale; +0255 +0256 fields = fieldnames(parData{i}); +0257 for j = 1:size(fields,1) +0258 tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(i),'}.',fields{j}]))]; +0259 end +0260 d{1} = tmp; +0261 parData{i}.all = d; +0262 clear d tmp +0263 +0264 % command line output +0265 disp([in.name,': importing NMR data from depth: ',... +0266 sprintf('%3.2f',data.jpd.depth(i)),' ',data.jpd.depth_units]); +0267 end 0268 -0269 %------------- END OF CODE -------------- -0270 -0271 %% License: -0272 % MIT License -0273 % -0274 % Copyright (c) 2020 Thomas Hiller -0275 % -0276 % Permission is hereby granted, free of charge, to any person obtaining a copy -0277 % of this software and associated documentation files (the "Software"), to deal -0278 % in the Software without restriction, including without limitation the rights -0279 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0280 % copies of the Software, and to permit persons to whom the Software is -0281 % furnished to do so, subject to the following conditions: -0282 % -0283 % The above copyright notice and this permission notice shall be included in all -0284 % copies or substantial portions of the Software. -0285 % -0286 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0287 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0288 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0289 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0290 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0291 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0292 % SOFTWARE.

    +0269 case 4 % Aarhus T1T2 +0270 % read the data file +0271 datafile = dir(fullfile(in.path,in.name)); +0272 [data,parData] = LoadDataFile(in.path,in.name,in.T1T2); +0273 +0274 % get file statistics +0275 nmrData.datfile = datafile.name; +0276 nmrData.date = datafile.date; +0277 nmrData.datenum = datafile.datenum; +0278 nmrData.bytes = datafile.bytes; +0279 +0280 % save the NMR data +0281 nmrData.flag = data.flag; +0282 nmrData.T1IRfac = 1; +0283 nmrData.time = data.time; +0284 nmrData.signal = data.signal; +0285 nmrData.raw = data.raw; +0286 if strcmp(in.T1T2,'T2') +0287 nmrData.phase = data.phase; +0288 end +0289 +0290 case 5 % Dart T2 logging +0291 % read the data file +0292 datafile = dir(fullfile(in.path,in.name)); +0293 [data,parData] = LoadDataFileLogging(in.path,in.name,in.T1T2); +0294 +0295 nmrData = cell(1,1); +0296 for nn = 1:numel(data) +0297 % get file statistics +0298 nmrData{nn}.datfile = datafile.name; +0299 nmrData{nn}.date = datafile.date; +0300 nmrData{nn}.datenum = datafile.datenum; +0301 nmrData{nn}.bytes = datafile.bytes; +0302 +0303 % save the NMR data +0304 nmrData{nn}.flag = data{nn}.flag; +0305 nmrData{nn}.T1IRfac = 1; +0306 nmrData{nn}.time = data{nn}.time; +0307 nmrData{nn}.signal = data{nn}.signal; +0308 nmrData{nn}.raw = data{nn}.raw; +0309 if strcmp(in.T1T2,'T2') +0310 nmrData{nn}.phase = data{nn}.phase; +0311 end +0312 end +0313 end +0314 +0315 % save data to output struct +0316 out.nmrData = nmrData; +0317 out.parData = parData; +0318 +0319 end +0320 +0321 %% load NMR data file +0322 function [data,pardata] = LoadDataFile(datapath,fname,flag) +0323 +0324 % importdata is rather slow for row data +0325 % A = importdata(fullfile(datapath,fname),'\t'); +0326 +0327 % first read the file to get the number of echos +0328 fid = fopen(fullfile(datapath,fname)); +0329 A0 = textscan(fid,'%f','Delimiter','\n'); +0330 fclose(fid); +0331 % now read all three lines +0332 fid = fopen(fullfile(datapath,fname)); +0333 A1 = textscan(fid,'%f',A0{1}(3)); +0334 A2 = textscan(fid,'%f',A0{1}(3)); +0335 A3 = textscan(fid,'%f',A0{1}(3)); +0336 fclose(fid); +0337 % and stitch them together +0338 A = [A1{1}';A2{1}';A3{1}']; +0339 +0340 t_echo = A(1,2); +0341 n_echo = A(1,3); +0342 freq = A(1,4); +0343 Nscans = A(1,5); +0344 t_recov = A(1,57); % DART +0345 +0346 time = t_echo:t_echo:t_echo*n_echo; +0347 time = time(:); +0348 re = A(2,1:length(time)); +0349 im = A(3,1:length(time)); +0350 re = re(:); +0351 im = im(:); +0352 +0353 data.flag = flag; +0354 data.raw.time = time; +0355 data.raw.signal = complex(re,im); +0356 [data.signal,data.phase] = rotateT2phase(data.raw.signal); +0357 +0358 data.time = data.raw.time; +0359 +0360 pardata.t_echo = t_echo; +0361 pardata.n_echo = n_echo; +0362 pardata.t_recov = t_recov; +0363 pardata.freq = freq; +0364 pardata.Nscans = Nscans; +0365 d{1}{1,1} = ['t_echo = ',num2str(t_echo)]; +0366 d{1}{2,1} = ['n_echo = ',num2str(n_echo)]; +0367 d{1}{3,1} = ['t_recov = ',num2str(t_recov)]; +0368 d{1}{4,1} = ['freq = ',num2str(freq)]; +0369 d{1}{5,1} = ['Nscans = ',num2str(Nscans)]; +0370 pardata.all = d; +0371 +0372 end +0373 +0374 %% load NMR data file +0375 function [data,pardata] = LoadDataFileLogging(datapath,fname,flag) +0376 +0377 % importdata is rather slow for row data +0378 % A = importdata(fullfile(datapath,fname),'\t'); +0379 +0380 % first read the file to get the number of echos +0381 fid = fopen(fullfile(datapath,fname)); +0382 A0 = textscan(fid,'%f','Delimiter','\n'); +0383 fclose(fid); +0384 +0385 % get the number of Echos +0386 n_echo = A0{1}(3); +0387 N = numel(A0{1}); +0388 % reshape the data +0389 A1 = reshape(A0{1},[n_echo N/n_echo]); +0390 A2 = A1'; +0391 +0392 data = cell(1,1); +0393 pardata = cell(1,1); +0394 for nn = 1:size(A2,1)/3 +0395 t_echo = A2(3*nn-2,2); +0396 n_echo = A2(3*nn-2,3); +0397 freq = A2(3*nn-2,4); +0398 Nscans = A2(3*nn-2,5); +0399 depth = A2(3*nn-2,9); +0400 t_wait = A2(3*nn-2,14); +0401 time = t_echo:t_echo:t_echo*n_echo; +0402 re = A2(3*nn-1,1:length(time)); +0403 im = A2(3*nn,1:length(time)); +0404 time = time(:); +0405 re = re(:); +0406 im = im(:); +0407 data{nn}.flag = flag; +0408 data{nn}.raw.time = time; +0409 data{nn}.raw.signal = complex(re,im); +0410 data{nn}.time = data{nn}.raw.time; +0411 [data{nn}.signal,data{nn}.phase] = rotateT2phase(data{nn}.raw.signal); +0412 +0413 pardata{nn}.t_echo = t_echo; +0414 pardata{nn}.n_echo = n_echo; +0415 pardata{nn}.freq = freq; +0416 pardata{nn}.Nscans = Nscans; +0417 pardata{nn}.depth = depth; +0418 pardata{nn}.t_wait = t_wait; +0419 d{1}{1,1} = ['t_echo = ',num2str(t_echo)]; +0420 d{1}{2,1} = ['n_echo = ',num2str(n_echo)]; +0421 d{1}{3,1} = ['freq = ',num2str(freq)]; +0422 d{1}{4,1} = ['Nscans = ',num2str(Nscans)]; +0423 d{1}{5,1} = ['depth = ',num2str(depth)]; +0424 d{1}{6,1} = ['t_wait = ',num2str(t_wait)]; +0425 pardata{nn}.all = d; +0426 end +0427 +0428 +0429 % figure; +0430 % subplot(211); +0431 % plot(data{1}.time,real(data{1}.signal),'k'); hold on +0432 % plot(data{1}.time,imag(data{1}.signal),'k--','LineWidth',1); +0433 % plot(data{3}.time,real(data{3}.signal),'r'); +0434 % plot(data{3}.time,imag(data{3}.signal),'r--','LineWidth',1); +0435 % set(gca,'XScale','log','YScale','lin'); +0436 % subplot(212); +0437 % plot(data{2}.time,real(data{2}.signal),'k'); hold on +0438 % plot(data{2}.time,imag(data{2}.signal),'k--','LineWidth',1); +0439 % plot(data{4}.time,real(data{4}.signal),'r'); +0440 % plot(data{4}.time,imag(data{4}.signal),'r--','LineWidth',1); +0441 % set(gca,'XScale','log','YScale','lin'); +0442 +0443 end +0444 +0445 %------------- END OF CODE -------------- +0446 +0447 %% License: +0448 % MIT License +0449 % +0450 % Copyright (c) 2020 Thomas Hiller +0451 % +0452 % Permission is hereby granted, free of charge, to any person obtaining a copy +0453 % of this software and associated documentation files (the "Software"), to deal +0454 % in the Software without restriction, including without limitation the rights +0455 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0456 % copies of the Software, and to permit persons to whom the Software is +0457 % furnished to do so, subject to the following conditions: +0458 % +0459 % The above copyright notice and this permission notice shall be included in all +0460 % copies or substantial portions of the Software. +0461 % +0462 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0463 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0464 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0465 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0466 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0467 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0468 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/import/LoadNMRData_driver.html b/doc/nucleus/functions/import/LoadNMRData_driver.html index 6656f6c..4fd8486 100644 --- a/doc/nucleus/functions/import/LoadNMRData_driver.html +++ b/doc/nucleus/functions/import/LoadNMRData_driver.html @@ -36,6 +36,7 @@

    DESCRIPTION ^DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • LoadNMRData_bamtom loads BAM TOM data
  • LoadNMRData_bgr loads standard BGR NMR data
  • LoadNMRData_bgrmat loads already preprocessed BGR NMR data; check the
  • LoadNMRData_corelab loads NMR data as provided by Corelab
  • LoadNMRData_dart loads RWTH NMR data (recorded with the Dart device); the
  • LoadNMRData_field loads RWTH field NMR data (Blümich group bore-hole tool)
  • LoadNMRData_helios loads BGR NMR data from a typical folder structure
  • LoadNMRData_ibac imports NMR data from the PM5 and PM25
  • LoadNMRData_liag loads LIAG NMR data
  • LoadNMRData_mouse loads NMR data saved by the MOUSE
  • LoadNMRData_mousecpmg
  • LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as
  • LoadNMRData_rocaT1T2 loads T1T2 NMR data from a typical folder structure
  • LoadNMRData_rwth loads RWTH NMR data (saved by the old Prospa version)
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • This function is called by: @@ -94,120 +95,124 @@

    SOURCE CODE ^% in.path - data path 0010 % in.name - file name (optional) 0011 % in.fileformat - varying -0012 % -0013 % Outputs: -0014 % out - output structure -0015 % out.parData - parameter file data -0016 % out.nmrData - NMR data -0017 % -0018 % Example: -0019 % out = LoadNMRData_driver(in) -0020 % -0021 % Other m-files required: -0022 % LoadNMRData_rwth -0023 % LoadNMRData_field -0024 % LoadNMRData_dart -0025 % LoadNMRData_corelab -0026 % LoadNMRData_ibac -0027 % LoadNMRData_mouse -0028 % LoadNMRData_liag -0029 % LoadNMRData_bgr -0030 % LoadNMRData_mousecpmg -0031 % LoadNMRData_bgrmat -0032 % LoadNMRData_helios -0033 % LoadNMRData_bamtom -0034 % -0035 % Subfunctions: -0036 % none -0037 % -0038 % MAT-files required: -0039 % none -0040 % -0041 % See also: NUCLEUSinv -0042 % Author: see AUTHORS.md -0043 % email: see AUTHORS.md -0044 % License: MIT License (at end) -0045 -0046 %------------- BEGIN CODE -------------- -0047 -0048 %% select the routine depending on the file format -0049 switch in.fileformat -0050 case 'bamtom' -0051 out = LoadNMRData_bamtom(in); -0052 case 'bgr' -0053 out = LoadNMRData_bgr(in); -0054 case 'bgrmat' -0055 out = LoadNMRData_bgrmat(in); -0056 case 'corelab' -0057 out = LoadNMRData_corelab(in); -0058 case 'dart' -0059 out = LoadNMRData_dart(in); -0060 case 'field' -0061 out = LoadNMRData_field(in); -0062 case {'heliosCPMG','heliosSeries'} -0063 out = LoadNMRData_helios(in); -0064 case 'liag' -0065 out = LoadNMRData_liag(in); -0066 case 'mouse' -0067 out = LoadNMRData_mouse(in); -0068 case 'MouseCPMG' -0069 out = LoadNMRData_mousecpmg(in); -0070 case 'MouseLift' -0071 out = LoadNMRData_mouselift(in); -0072 case 'rwth' -0073 out = LoadNMRData_rwth(in); -0074 case 'pm5' -0075 out = LoadNMRData_ibac(in); -0076 case 'pm25' -0077 out = LoadNMRData_ibac(in); -0078 end -0079 -0080 % if an imported T2 signal has no imaginary part, the noise is estimated -0081 % from an exponential fit -0082 if ~strcmp(in.fileformat,'heliosCPMG') && ~strcmp(in.fileformat,'heliosSeries')... -0083 && (isfield(in,'T1T2') && ~strcmp(in.T1T2,'T1')) -0084 for i = 1:numel(out.nmrData) -0085 if isreal(out.nmrData{i}.signal) -0086 disp('NUCLUESinv import: Estimating noise from exponential fit ...'); -0087 param.T1IRfac = out.nmrData{i}.T1IRfac; -0088 param.noise = 0; -0089 param.optim = 'off'; -0090 param.Tfixed_bool = [0 0 0 0 0]; -0091 param.Tfixed_val = [0 0 0 0 0]; -0092 invstd = fitDataFree(out.nmrData{i}.time,out.nmrData{i}.signal,... -0093 out.nmrData{i}.flag,param,5); -0094 out.nmrData{i}.noise = invstd.rms; -0095 disp('NUCLUESinv import: done.') -0096 end -0097 end -0098 end -0099 -0100 return -0101 -0102 %------------- END OF CODE -------------- +0012 % in.version - varying (dependent on fileformat) +0013 % +0014 % Outputs: +0015 % out - output structure +0016 % out.parData - parameter file data +0017 % out.nmrData - NMR data +0018 % +0019 % Example: +0020 % out = LoadNMRData_driver(in) +0021 % +0022 % Other m-files required: +0023 % LoadNMRData_rwth +0024 % LoadNMRData_field +0025 % LoadNMRData_dart +0026 % LoadNMRData_corelab +0027 % LoadNMRData_ibac +0028 % LoadNMRData_mouse +0029 % LoadNMRData_liag +0030 % LoadNMRData_bgr +0031 % LoadNMRData_mousecpmg +0032 % LoadNMRData_bgrmat +0033 % LoadNMRData_helios +0034 % LoadNMRData_bamtom +0035 % +0036 % Subfunctions: +0037 % none +0038 % +0039 % MAT-files required: +0040 % none +0041 % +0042 % See also: NUCLEUSinv +0043 % Author: see AUTHORS.md +0044 % email: see AUTHORS.md +0045 % License: MIT License (at end) +0046 +0047 %------------- BEGIN CODE -------------- +0048 +0049 %% select the routine depending on the file format +0050 switch in.fileformat +0051 case 'bamtom' +0052 out = LoadNMRData_bamtom(in); +0053 case 'bgr' +0054 out = LoadNMRData_bgr(in); +0055 case 'bgrmat' +0056 out = LoadNMRData_bgrmat(in); +0057 case 'corelab' +0058 out = LoadNMRData_corelab(in); +0059 case {'dart','dartSeries','dartT2logging'} +0060 out = LoadNMRData_dart(in); +0061 case 'field' +0062 out = LoadNMRData_field(in); +0063 case {'heliosCPMG','heliosSeries'} +0064 out = LoadNMRData_helios(in); +0065 case 'liag' +0066 out = LoadNMRData_liag(in); +0067 case 'mouse' +0068 out = LoadNMRData_mouse(in); +0069 case 'MouseCPMG' +0070 out = LoadNMRData_mousecpmg(in); +0071 case 'MouseLift' +0072 out = LoadNMRData_mouselift(in); +0073 case 'rwth' +0074 out = LoadNMRData_rwth(in); +0075 case 'pm5' +0076 out = LoadNMRData_ibac(in); +0077 case 'pm25' +0078 out = LoadNMRData_ibac(in); +0079 case 'rocaT1T2' +0080 out = LoadNMRData_rocaT1T2(in); +0081 end +0082 +0083 % if an imported T2 signal has no imaginary part, the noise is estimated +0084 % from an exponential fit +0085 if ~strcmp(in.fileformat,'heliosCPMG') && ~strcmp(in.fileformat,'heliosSeries')... +0086 && ~strcmp(in.fileformat,'dartSeries') && ~strcmp(in.fileformat,'dartT2logging')... +0087 && (isfield(in,'T1T2') && ~strcmp(in.T1T2,'T1')) +0088 for i = 1:numel(out.nmrData) +0089 if isreal(out.nmrData{i}.signal) +0090 disp('NUCLUESinv import: Estimating noise from exponential fit ...'); +0091 param.T1IRfac = out.nmrData{i}.T1IRfac; +0092 param.noise = 0; +0093 param.optim = 'off'; +0094 param.Tfixed_bool = [0 0 0 0 0]; +0095 param.Tfixed_val = [0 0 0 0 0]; +0096 invstd = fitDataFree(out.nmrData{i}.time,out.nmrData{i}.signal,... +0097 out.nmrData{i}.flag,param,5); +0098 out.nmrData{i}.noise = invstd.rms; +0099 disp('NUCLUESinv import: done.') +0100 end +0101 end +0102 end 0103 -0104 %% License: -0105 % MIT License -0106 % -0107 % Copyright (c) 2018 Thomas Hiller -0108 % -0109 % Permission is hereby granted, free of charge, to any person obtaining a copy -0110 % of this software and associated documentation files (the "Software"), to deal -0111 % in the Software without restriction, including without limitation the rights -0112 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0113 % copies of the Software, and to permit persons to whom the Software is -0114 % furnished to do so, subject to the following conditions: -0115 % -0116 % The above copyright notice and this permission notice shall be included in all -0117 % copies or substantial portions of the Software. -0118 % -0119 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0120 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0121 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0122 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0123 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0124 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0125 % SOFTWARE. +0104 return +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 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/import/LoadNMRData_field.html b/doc/nucleus/functions/import/LoadNMRData_field.html index 792a6f9..da8ca1b 100644 --- a/doc/nucleus/functions/import/LoadNMRData_field.html +++ b/doc/nucleus/functions/import/LoadNMRData_field.html @@ -65,7 +65,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -218,7 +218,7 @@

    SOURCE CODE ^end 0142 data.signal = complex(d(:,2),d(:,3)); -0143 [data.signal,data.phase] = rotateT2phase(data.signal); +0143 [data.signal,data.phase] = rotateT2phase(data.signal); 0144 else 0145 data.flag = '0'; 0146 data.time = 0; diff --git a/doc/nucleus/functions/import/LoadNMRData_helios.html b/doc/nucleus/functions/import/LoadNMRData_helios.html index 0fedea1..567d25f 100644 --- a/doc/nucleus/functions/import/LoadNMRData_helios.html +++ b/doc/nucleus/functions/import/LoadNMRData_helios.html @@ -64,7 +64,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -163,56 +163,68 @@

    SOURCE CODE ^rotateT2phase(data.raw.signal); -0101 -0102 data.time = data.raw.time; -0103 -0104 pardata.t_echo = t_echo; -0105 pardata.n_echo = n_echo; -0106 pardata.freq = freq; -0107 pardata.Nscans = Nscans; -0108 d{1}{1,1} = ['t_echo = ',num2str(t_echo)]; -0109 d{1}{2,1} = ['n_echo = ',num2str(n_echo)]; -0110 d{1}{3,1} = ['freq = ',num2str(freq)]; -0111 d{1}{4,1} = ['Nscans = ',num2str(Nscans)]; -0112 pardata.all = d; -0113 -0114 end -0115 %------------- END OF CODE -------------- -0116 -0117 %% License: -0118 % MIT License -0119 % -0120 % Copyright (c) 2021 Stephan Costabel -0121 % -0122 % Permission is hereby granted, free of charge, to any person obtaining a copy -0123 % of this software and associated documentation files (the "Software"), to deal -0124 % in the Software without restriction, including without limitation the rights -0125 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0126 % copies of the Software, and to permit persons to whom the Software is -0127 % furnished to do so, subject to the following conditions: -0128 % -0129 % The above copyright notice and this permission notice shall be included in all -0130 % copies or substantial portions of the Software. +0089 t_recov = A(1,9); % HELIOS +0090 t_rep = A(1,14); % HELIOS +0091 timestamp = A(1,42); % HELIOS +0092 +0093 time = t_echo:t_echo:t_echo*n_echo; +0094 time = time(:); +0095 re = A(2,1:length(time)); +0096 im = A(3,1:length(time)); +0097 re = re(:); +0098 im = im(:); +0099 +0100 data.flag = flag; +0101 data.raw.time = time; +0102 data.raw.signal = complex(re,im); +0103 % the HELIOS phase is generally around 140°, hence we give a range for +0104 % finding the optimal phase angle +0105 [data.signal,data.phase] = rotateT2phase(data.raw.signal,'stdIm',... +0106 [deg2rad(140-25) deg2rad(140+25)]); +0107 +0108 data.time = data.raw.time; +0109 data.raw.signal = data.signal; +0110 +0111 pardata.t_echo = t_echo; +0112 pardata.n_echo = n_echo; +0113 pardata.t_recov = t_recov; +0114 pardata.t_rep = t_rep; +0115 pardata.freq = freq; +0116 pardata.Nscans = Nscans; +0117 pardata.timestamp = timestamp; +0118 d{1}{1,1} = ['t_echo = ',num2str(t_echo)]; +0119 d{1}{2,1} = ['n_echo = ',num2str(n_echo)]; +0120 d{1}{3,1} = ['t_recov = ',num2str(t_recov)]; +0121 d{1}{4,1} = ['t_rep = ',num2str(t_rep)]; +0122 d{1}{5,1} = ['freq = ',num2str(freq)]; +0123 d{1}{6,1} = ['Nscans = ',num2str(Nscans)]; +0124 pardata.all = d; +0125 +0126 end +0127 %------------- END OF CODE -------------- +0128 +0129 %% License: +0130 % MIT License 0131 % -0132 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0133 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0134 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0135 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0136 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0137 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0138 % SOFTWARE. +0132 % Copyright (c) 2021 Stephan Costabel +0133 % +0134 % Permission is hereby granted, free of charge, to any person obtaining a copy +0135 % of this software and associated documentation files (the "Software"), to deal +0136 % in the Software without restriction, including without limitation the rights +0137 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0138 % copies of the Software, and to permit persons to whom the Software is +0139 % furnished to do so, subject to the following conditions: +0140 % +0141 % The above copyright notice and this permission notice shall be included in all +0142 % copies or substantial portions of the Software. +0143 % +0144 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0145 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0146 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0147 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0148 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0149 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0150 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/import/LoadNMRData_ibac.html b/doc/nucleus/functions/import/LoadNMRData_ibac.html index 7835eeb..5b06fac 100644 --- a/doc/nucleus/functions/import/LoadNMRData_ibac.html +++ b/doc/nucleus/functions/import/LoadNMRData_ibac.html @@ -67,7 +67,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -195,7 +195,7 @@

    SOURCE CODE ^% save the complex signal 0116 nmrData{i}.signal = complex(sr,si); 0117 % rotate phase to minimize imag part -0118 [nmrData{i}.signal,nmrData{i}.phase] = rotateT2phase(nmrData{i}.signal); +0118 [nmrData{i}.signal,nmrData{i}.phase] = rotateT2phase(nmrData{i}.signal); 0119 nmrData{i}.raw.signal = nmrData{i}.signal; 0120 else 0121 nmrData{i}.signal = data.signal(data.depth==depths(i)); diff --git a/doc/nucleus/functions/import/LoadNMRData_liag.html b/doc/nucleus/functions/import/LoadNMRData_liag.html index e7182f1..da20333 100644 --- a/doc/nucleus/functions/import/LoadNMRData_liag.html +++ b/doc/nucleus/functions/import/LoadNMRData_liag.html @@ -63,7 +63,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -171,7 +171,7 @@

    SOURCE CODE ^case 'T2' 0097 data.signal = complex(d(:,2),d(:,3)); -0098 [data.signal,data.phase] = rotateT2phase(data.signal); +0098 [data.signal,data.phase] = rotateT2phase(data.signal); 0099 end 0100 else 0101 data.flag = '0'; diff --git a/doc/nucleus/functions/import/LoadNMRData_mouse.html b/doc/nucleus/functions/import/LoadNMRData_mouse.html index 7000acd..1f76d27 100644 --- a/doc/nucleus/functions/import/LoadNMRData_mouse.html +++ b/doc/nucleus/functions/import/LoadNMRData_mouse.html @@ -63,7 +63,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -175,7 +175,7 @@

    SOURCE CODE ^case 'T2' 0101 data.signal = complex(d(:,2),d(:,3)); -0102 [data.signal,data.phase] = rotateT2phase(data.signal); +0102 [data.signal,data.phase] = rotateT2phase(data.signal); 0103 end 0104 else 0105 data.flag = '0'; diff --git a/doc/nucleus/functions/import/LoadNMRData_mouselift.html b/doc/nucleus/functions/import/LoadNMRData_mouselift.html index 3736f33..92874fa 100644 --- a/doc/nucleus/functions/import/LoadNMRData_mouselift.html +++ b/doc/nucleus/functions/import/LoadNMRData_mouselift.html @@ -27,7 +27,7 @@

    SYNOPSIS ^DESCRIPTION ^

    LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as
    -generated by the NMR MOUSE when using it wogether with the lift
    +generated by the NMR MOUSE when using it together with the lift
     
      Syntax:
            out = LoadNMRData_mouselift(in)
    @@ -65,7 +65,7 @@ 

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • This function is called by: @@ -78,7 +78,7 @@

    SUBFUNCTIONS ^SOURCE CODE ^

    0001 function out = LoadNMRData_mouselift(in)
     0002 %LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as
    -0003 %generated by the NMR MOUSE when using it wogether with the lift
    +0003 %generated by the NMR MOUSE when using it together with the lift
     0004 %
     0005 % Syntax:
     0006 %       out = LoadNMRData_mouselift(in)
    @@ -173,7 +173,7 @@ 

    SOURCE CODE ^case 'T2' 0097 data.signal = complex(d(:,2),d(:,3)); -0098 [data.signal,data.phase] = rotateT2phase(data.signal); +0098 [data.signal,data.phase] = rotateT2phase(data.signal); 0099 end 0100 else 0101 data.flag = '0'; diff --git a/doc/nucleus/functions/import/LoadNMRData_rocaT1T2.html b/doc/nucleus/functions/import/LoadNMRData_rocaT1T2.html new file mode 100644 index 0000000..5752d48 --- /dev/null +++ b/doc/nucleus/functions/import/LoadNMRData_rocaT1T2.html @@ -0,0 +1,354 @@ + + + + Description of LoadNMRData_rocaT1T2 + + + + + + + + + + + +

    LoadNMRData_rocaT1T2 +

    + +

    PURPOSE ^

    +
    loads T1T2 NMR data from a typical folder structure
    + +

    SYNOPSIS ^

    +
    function out = LoadNMRData_rocaT1T2(in)
    + +

    DESCRIPTION ^

    +
    LoadNMRData_rocaT1T2 loads T1T2 NMR data from a typical folder structure
    +produced by the Magritek Rock Core Analyzer
    +
    + Syntax:
    +       out = LoadNMRData_rocaT1T2(in)
    +
    + Inputs:
    +       in - input structure
    +       in.path - data path
    +       in.T1T2 - T1 / T2 flag
    +       in.fileformat - 'rocaT1T2'
    +
    + Outputs:
    +       out - output structure
    +       out.parData - parameter file data
    +       out.nmrData - NMR data
    +
    + Example:
    +       out = LoadNMRData_helios(in)
    +
    + Other m-files required:
    +       fixParameterString
    +
    + Subfunctions:
    +       LoadDataFile
    +
    + 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: +
      +
    • fixParameterString cleans parameter file lines when the properties have a
    • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
    +This function is called by: + + + +

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function out = LoadNMRData_rocaT1T2(in)
    +0002 %LoadNMRData_rocaT1T2 loads T1T2 NMR data from a typical folder structure
    +0003 %produced by the Magritek Rock Core Analyzer
    +0004 %
    +0005 % Syntax:
    +0006 %       out = LoadNMRData_rocaT1T2(in)
    +0007 %
    +0008 % Inputs:
    +0009 %       in - input structure
    +0010 %       in.path - data path
    +0011 %       in.T1T2 - T1 / T2 flag
    +0012 %       in.fileformat - 'rocaT1T2'
    +0013 %
    +0014 % Outputs:
    +0015 %       out - output structure
    +0016 %       out.parData - parameter file data
    +0017 %       out.nmrData - NMR data
    +0018 %
    +0019 % Example:
    +0020 %       out = LoadNMRData_helios(in)
    +0021 %
    +0022 % Other m-files required:
    +0023 %       fixParameterString
    +0024 %
    +0025 % Subfunctions:
    +0026 %       LoadDataFile
    +0027 %
    +0028 % MAT-files required:
    +0029 %       none
    +0030 %
    +0031 % See also: NUCLEUSinv
    +0032 % Author: see AUTHORS.md
    +0033 % email: see AUTHORS.md
    +0034 % License: MIT License (at end)
    +0035 
    +0036 %------------- BEGIN CODE --------------
    +0037 
    +0038 %% start processing the files
    +0039 
    +0040 % read the data file
    +0041 datafile = dir(fullfile(in.path,in.name));
    +0042 % load Parameter file
    +0043 parData = LoadParameterFile(in.path,'acqu.par');
    +0044 data = LoadDataFile(in.path,in.name,in.T1T2,parData);
    +0045 
    +0046 nmrData = cell(1,1);
    +0047 for j1 = 1:numel(data)
    +0048     % get file statistics
    +0049     nmrData{j1}.datfile = datafile.name;
    +0050     nmrData{j1}.date = datafile.date;
    +0051     nmrData{j1}.datenum = datafile.datenum;
    +0052     nmrData{j1}.bytes = datafile.bytes;
    +0053 
    +0054     % save the NMR data
    +0055     nmrData{j1}.flag = data(j1).flag;
    +0056     nmrData{j1}.T1IRfac = 1;
    +0057     nmrData{j1}.time = data(j1).time;
    +0058     nmrData{j1}.signal = data(j1).signal;
    +0059     nmrData{j1}.raw = data(j1).raw;
    +0060     if strcmp(in.T1T2,'T2')
    +0061         nmrData{j1}.phase = data(j1).phase;
    +0062     end
    +0063 end
    +0064 
    +0065 % save data to output struct
    +0066 out.parData = parData;
    +0067 out.nmrData = nmrData;
    +0068 
    +0069 end
    +0070 
    +0071 %% load NMR data file
    +0072 function data = LoadDataFile(datapath,fname,flag,pardata)
    +0073 
    +0074 % first read the file
    +0075 d = importdata(fullfile(datapath,fname));
    +0076 
    +0077 % create echo time vector
    +0078 time = pardata.echoTime:pardata.echoTime:pardata.echoTime*pardata.nrEchoes;
    +0079 time = time(:)./1e6; % to [s]
    +0080 
    +0081 % swicth on/off debug plots
    +0082 do_debug = false;
    +0083 
    +0084 %% start of DEBUG part
    +0085 if do_debug
    +0086     figure; %#ok<*UNRCH>
    +0087     ax1 = subplot(131);
    +0088     ax2 = subplot(132);
    +0089     ax3 = subplot(133);
    +0090     hold([ax1 ax2 ax3],'on');
    +0091     id_last = size(d,1);
    +0092     id_test = round(linspace(1,id_last-1,8));
    +0093     for j1 = [id_test id_last]
    +0094         re = d(j1,1:2:end);
    +0095         im = d(j1,2:2:end);
    +0096 
    +0097         mag = abs(complex(re,im));
    +0098 
    +0099         if j1 < id_last
    +0100             LS = '-';
    +0101         else
    +0102             LS = '--';
    +0103         end
    +0104         plot(time,re','LineStyle',LS,'DisplayName',['row',sprintf('%d',j1)],'Parent',ax1);
    +0105         plot(time,im','LineStyle',LS,'DisplayName',['row',sprintf('%d',j1)],'Parent',ax2);
    +0106         plot(time,mag','LineStyle',LS,'DisplayName',['row',sprintf('%d',j1)],'Parent',ax3);
    +0107 
    +0108     end
    +0109     hold([ax1 ax2 ax3],'off');
    +0110     set([ax1 ax2 ax3],'XScale','log');
    +0111     set(get(ax1,'Xlabel'),'String','time [s]');
    +0112     set(get(ax2,'Xlabel'),'String','time [s]');
    +0113     set(get(ax3,'Xlabel'),'String','time [s]');
    +0114     set(get(ax1,'Ylabel'),'String','Real part');
    +0115     set(get(ax2,'Ylabel'),'String','Imag part');
    +0116     set(get(ax3,'Ylabel'),'String','Magntiude sqrt(Re^2+Im^2)');
    +0117 
    +0118     figure;
    +0119     ax1 = subplot(131);
    +0120     ax2 = subplot(132);
    +0121     ax3 = subplot(133);
    +0122     hold([ax1 ax2 ax3],'on');
    +0123     for j1 = id_test
    +0124         re = d(j1,1:2:end)-d(id_last,1:2:end);
    +0125         im = d(j1,2:2:end)-d(id_last,2:2:end);
    +0126 
    +0127         mag = abs(complex(re,im));
    +0128 
    +0129         plot(time,re','DisplayName',['row',sprintf('%d',j1)],'Parent',ax1);
    +0130         plot(time,im','DisplayName',['row',sprintf('%d',j1)],'Parent',ax2);
    +0131         plot(time,mag','DisplayName',['row',sprintf('%d',j1)],'Parent',ax3);
    +0132 
    +0133     end
    +0134     hold([ax1 ax2 ax3],'off');
    +0135     set([ax1 ax2 ax3],'XScale','log');
    +0136     set(get(ax1,'Xlabel'),'String','time [s]');
    +0137     set(get(ax2,'Xlabel'),'String','time [s]');
    +0138     set(get(ax3,'Xlabel'),'String','time [s]');
    +0139     set(get(ax1,'Ylabel'),'String','Real part');
    +0140     set(get(ax2,'Ylabel'),'String','Imag part');
    +0141     set(get(ax3,'Ylabel'),'String','Magntiude sqrt(Re^2+Im^2)');
    +0142 end
    +0143 % end of DEBUG part
    +0144 
    +0145 %
    +0146 % correction after Hürliman 2001, JMR 148
    +0147 % last row is the correction signal
    +0148 dref = d(end,:);
    +0149 % the data without the last row
    +0150 d = d(1:end-1,:);
    +0151 % subtract the correction signal from all other signals
    +0152 d = d - dref;
    +0153 
    +0154 % rotate the longest delay time (last row) and get its phase
    +0155 dlong = complex(d(end,1:2:end),d(end,2:2:end));
    +0156 [dlong_rot,dlong_phase] = rotateT2phase(dlong);
    +0157 
    +0158 if do_debug
    +0159     figure;
    +0160     subplot(121);
    +0161     plot(time,real(dlong)); hold on
    +0162     plot(time,imag(dlong));
    +0163     xlabel('time [s]');
    +0164     ylabel('amplitude');
    +0165     title('from file');
    +0166     subplot(122);
    +0167     plot(time,real(dlong_rot)); hold on
    +0168     plot(time,imag(dlong_rot));
    +0169     xlabel('time [s]');
    +0170     ylabel('amplitude');
    +0171     title('after rotation');
    +0172 
    +0173     plotphase = zeros(pardata.tauSteps,1);
    +0174 end
    +0175 
    +0176 data = struct;
    +0177 for j1 = 1:pardata.tauSteps
    +0178     re = d(j1,1:2:end);
    +0179     im = d(j1,2:2:end);
    +0180     re = re(:);
    +0181     im = im(:);
    +0182     data(j1).flag = flag;
    +0183     data(j1).raw.time = time;
    +0184     data(j1).time = time;
    +0185 
    +0186     tmp_s = complex(re,im);
    +0187 
    +0188     % rotate the signal with an angle within reference phase +- 5deg
    +0189     [tmp_s,tmp_phase] = rotateT2phase(tmp_s,'stdIm',...
    +0190         [dlong_phase-deg2rad(5) dlong_phase+deg2rad(5)]);
    +0191 
    +0192     % save the data
    +0193     data(j1).raw.signal = tmp_s;
    +0194     data(j1).signal = data(j1).raw.signal;
    +0195     data(j1).phase = tmp_phase;
    +0196     
    +0197     if do_debug
    +0198         plotphase(j1) = tmp_phase;
    +0199     end
    +0200 end
    +0201 if do_debug
    +0202     figure;
    +0203     plot(rad2deg(plotphase));
    +0204     xlabel('row number');
    +0205     ylabel('phase angle [deg]');
    +0206 
    +0207     figure;
    +0208     ax1 = subplot(131);
    +0209     ax2 = subplot(132);
    +0210     ax3 = subplot(133);
    +0211     hold([ax1 ax2 ax3],'on');
    +0212     for j1 = id_test
    +0213         re = real(data(j1).raw.signal);
    +0214         im = imag(data(j1).raw.signal);
    +0215 
    +0216         mag = abs(complex(re,im));
    +0217 
    +0218         plot(time,re','DisplayName',['row',sprintf('%d',j1)],'Parent',ax1);
    +0219         plot(time,im','DisplayName',['row',sprintf('%d',j1)],'Parent',ax2);
    +0220         plot(time,mag','DisplayName',['row',sprintf('%d',j1)],'Parent',ax3);
    +0221 
    +0222     end
    +0223     hold([ax1 ax2 ax3],'off');
    +0224     set([ax1 ax2 ax3],'XScale','log');
    +0225     set(get(ax1,'Xlabel'),'String','time [s]');
    +0226     set(get(ax2,'Xlabel'),'String','time [s]');
    +0227     set(get(ax3,'Xlabel'),'String','time [s]');
    +0228     set(get(ax1,'Ylabel'),'String','Real part');
    +0229     set(get(ax2,'Ylabel'),'String','Imag part');
    +0230     set(get(ax3,'Ylabel'),'String','Magntiude sqrt(Re^2+Im^2)');
    +0231 end
    +0232 
    +0233 end
    +0234 
    +0235 %% load parameter file
    +0236 function [data] = LoadParameterFile(datapath,fname)
    +0237 
    +0238 fid = fopen(fullfile(datapath,fname));
    +0239 d = textscan(fid,'%s','Delimiter','\n');
    +0240 fclose(fid);
    +0241 
    +0242 for i = 1:size(d{1},1)
    +0243     str = char(d{1}(i));
    +0244     str = fixParameterString(str);
    +0245     eval(['data.',str,';']); %#ok<EVLDOT>
    +0246 end
    +0247 data.all = d;
    +0248 
    +0249 end
    +0250 
    +0251 %------------- END OF CODE --------------
    +0252 
    +0253 %% License:
    +0254 % MIT License
    +0255 %
    +0256 % Copyright (c) 2024 Thomas Hiller
    +0257 %
    +0258 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +0259 % of this software and associated documentation files (the "Software"), to deal
    +0260 % in the Software without restriction, including without limitation the rights
    +0261 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +0262 % copies of the Software, and to permit persons to whom the Software is
    +0263 % furnished to do so, subject to the following conditions:
    +0264 %
    +0265 % The above copyright notice and this permission notice shall be included in all
    +0266 % copies or substantial portions of the Software.
    +0267 %
    +0268 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +0269 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +0270 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +0271 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +0272 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +0273 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +0274 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/import/LoadNMRData_rwth.html b/doc/nucleus/functions/import/LoadNMRData_rwth.html index 4c0fcd9..2d30b88 100644 --- a/doc/nucleus/functions/import/LoadNMRData_rwth.html +++ b/doc/nucleus/functions/import/LoadNMRData_rwth.html @@ -65,7 +65,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • fixParameterString cleans parameter file lines when the properties have a
  • rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
  • displayStatusText shows status information either in the GUI or on the
  • This function is called by: @@ -280,13 +280,13 @@

    SOURCE CODE ^'T2'; 0203 data.time = 0; 0204 data.signal = complex(d(:,1),d(:,2)); -0205 [data.signal,data.phase] = rotateT2phase(data.signal); +0205 [data.signal,data.phase] = rotateT2phase(data.signal); 0206 elseif size(d,2) == 4 0207 % a T2 measurement has four columns 0208 data.flag = 'T2'; 0209 data.time = d(:,1); 0210 data.signal = complex(d(:,2),d(:,3)); -0211 [data.signal,data.phase] = rotateT2phase(data.signal); +0211 [data.signal,data.phase] = rotateT2phase(data.signal); 0212 else 0213 data.flag = '0'; 0214 data.time = 0; diff --git a/doc/nucleus/functions/import/fixParameterString.html b/doc/nucleus/functions/import/fixParameterString.html index 6f3ebad..b006634 100644 --- a/doc/nucleus/functions/import/fixParameterString.html +++ b/doc/nucleus/functions/import/fixParameterString.html @@ -62,7 +62,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • LoadNMRData_bamtom loads BAM TOM data
  • LoadNMRData_bgr loads standard BGR NMR data
  • LoadNMRData_bgr2 loads BGR NMR data from an original folder structure as
  • LoadNMRData_field loads RWTH field NMR data (Blümich group bore-hole tool)
  • LoadNMRData_ibac imports NMR data from the PM5 and PM25
  • LoadNMRData_liag loads LIAG NMR data
  • LoadNMRData_mouse loads NMR data saved by the MOUSE
  • LoadNMRData_mousecpmg
  • LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as
  • LoadNMRData_rwth loads RWTH NMR data (saved by the old Prospa version)
  • importNMRdata is the general import routine for NMR data
  • +
  • LoadNMRData_bamtom loads BAM TOM data
  • LoadNMRData_bgr loads standard BGR NMR data
  • LoadNMRData_bgr2 loads BGR NMR data from an original folder structure as
  • LoadNMRData_field loads RWTH field NMR data (Blümich group bore-hole tool)
  • LoadNMRData_ibac imports NMR data from the PM5 and PM25
  • LoadNMRData_liag loads LIAG NMR data
  • LoadNMRData_mouse loads NMR data saved by the MOUSE
  • LoadNMRData_mousecpmg
  • LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as
  • LoadNMRData_rocaT1T2 loads T1T2 NMR data from a typical folder structure
  • LoadNMRData_rwth loads RWTH NMR data (saved by the old Prospa version)
  • importNMRdata is the general import routine for NMR data
  • diff --git a/doc/nucleus/functions/import/menu.html b/doc/nucleus/functions/import/menu.html index 9b2cf27..11953ac 100644 --- a/doc/nucleus/functions/import/menu.html +++ b/doc/nucleus/functions/import/menu.html @@ -18,7 +18,7 @@

    Index for nucleus\functions\import

    Matlab files in this directory:

    +
  • LoadNMRData_bamtom
  • LoadNMRData_bgr
  • LoadNMRData_bgr2
  • LoadNMRData_bgrmat
  • LoadNMRData_corelab
  • LoadNMRData_dart
  • LoadNMRData_driver
  • LoadNMRData_field
  • LoadNMRData_helios
  • LoadNMRData_ibac
  • LoadNMRData_liag
  • LoadNMRData_mouse
  • LoadNMRData_mousecpmg
  • LoadNMRData_mouselift
  • LoadNMRData_rocaT1T2
  • LoadNMRData_rwth
  • fixParameterString
  • rotateT2phase
  • diff --git a/doc/nucleus/functions/import/rotateT2phase.html b/doc/nucleus/functions/import/rotateT2phase.html index 1d37812..9896245 100644 --- a/doc/nucleus/functions/import/rotateT2phase.html +++ b/doc/nucleus/functions/import/rotateT2phase.html @@ -23,7 +23,7 @@

    PURPOSE ^ rotateT2phase rotates the complex NMR T2 signal so that the imaginary

    SYNOPSIS ^

    -
    function [s_rot,alpha] = rotateT2phase(s)
    +
    function [s_rot,alpha] = rotateT2phase(s,varargin)

    DESCRIPTION ^

    rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
    @@ -63,7 +63,7 @@ 

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • LoadNMRData_bamtom loads BAM TOM data
  • LoadNMRData_bgr loads standard BGR NMR data
  • LoadNMRData_bgr2 loads BGR NMR data from an original folder structure as
  • LoadNMRData_bgrmat loads already preprocessed BGR NMR data; check the
  • LoadNMRData_corelab loads NMR data as provided by Corelab
  • LoadNMRData_field loads RWTH field NMR data (Blümich group bore-hole tool)
  • LoadNMRData_helios loads BGR NMR data from a typical folder structure
  • LoadNMRData_ibac imports NMR data from the PM5 and PM25
  • LoadNMRData_liag loads LIAG NMR data
  • LoadNMRData_mouse loads NMR data saved by the MOUSE
  • LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as
  • LoadNMRData_rwth loads RWTH NMR data (saved by the old Prospa version)
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importNMRdata is the general import routine for NMR data
  • +
  • LoadNMRData_bamtom loads BAM TOM data
  • LoadNMRData_bgr loads standard BGR NMR data
  • LoadNMRData_bgr2 loads BGR NMR data from an original folder structure as
  • LoadNMRData_bgrmat loads already preprocessed BGR NMR data; check the
  • LoadNMRData_corelab loads NMR data as provided by Corelab
  • LoadNMRData_dart loads RWTH NMR data (recorded with the Dart device); the
  • LoadNMRData_field loads RWTH field NMR data (Blümich group bore-hole tool)
  • LoadNMRData_helios loads BGR NMR data from a typical folder structure
  • LoadNMRData_ibac imports NMR data from the PM5 and PM25
  • LoadNMRData_liag loads LIAG NMR data
  • LoadNMRData_mouse loads NMR data saved by the MOUSE
  • LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as
  • LoadNMRData_rocaT1T2 loads T1T2 NMR data from a typical folder structure
  • LoadNMRData_rwth loads RWTH NMR data (saved by the old Prospa version)
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importNMRdata is the general import routine for NMR data
  • SUBFUNCTIONS ^

    @@ -71,7 +71,7 @@

    SUBFUNCTIONS ^function sse = fun1(alpha,s,method)

    SOURCE CODE ^

    -
    0001 function [s_rot,alpha] = rotateT2phase(s)
    +
    0001 function [s_rot,alpha] = rotateT2phase(s,varargin)
     0002 %rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary
     0003 %part is zero.
     0004 %
    @@ -104,100 +104,115 @@ 

    SOURCE CODE ^%------------- BEGIN CODE -------------- 0033 -0034 %% only proceed if signal is complex -0035 if ~isreal(s) -0036 % fminsearch options -0037 options = optimset('MaxFunEvals',100,'MaxIter',100,'TolFun',1e-6,'TolX',1e-6); -0038 % let fminsearch minimize fun1 -0039 [alpha,~,~,~] = fminsearch(@(alpha) fun1(alpha,s,'minReIm'),pi/18,options); -0040 -0041 % s_rot is the rotated signal -0042 s_rot = s .* exp(1i*alpha); -0043 -0044 % if the real part is negative rotate by 180° -0045 if real(s_rot(1)) < 0 -0046 s_rot = s_rot .* exp(1i*pi); -0047 end -0048 else -0049 % do nothing -0050 s_rot = s; -0051 disp('Cannot ROTATE signal because it is not complex! rotateT2phase: Data is not complex.'); -0052 end -0053 -0054 return -0055 -0056 % minimization function -0057 function sse = fun1(alpha,s,method) -0058 % Inputs: -0059 % alpha - rotation phase angle in [rad] -0060 % s - NMR signal vector (has to be complex!) -0061 % method - "zero" or "minsd" -0062 % -0063 % Outputs: -0064 % sse - sum of squared residuals ("minReIm" or "minIm") or -0065 % standard deviation of imag. part ("stdIm") -0066 -0067 s = s(:); -0068 switch method -0069 case 'minReIm' -0070 % make a vector of zeros -0071 t0 = zeros(size(s,1),1); -0072 t0 = t0(:); -0073 % s_rot is the rotated signal -0074 s_rot = s .* exp(1i*alpha); -0075 % create residuals -0076 residuali = t0-imag(s_rot); -0077 residualr = t0-real(s_rot); -0078 % real part times -1 because we seek the maximum -0079 sse = sum(residuali.^2) + sum(residualr.^2)*-1; -0080 case 'minIm' -0081 % make a vector of zeros -0082 t0 = zeros(size(s,1),1); -0083 t0 = t0(:); -0084 % s_rot is the rotated signal -0085 s_rot = s .* exp(1i*alpha); -0086 % create residuals -0087 residuali = t0-imag(s_rot); -0088 % sse -0089 sse = sum(residuali.^2); -0090 case 'stdIm' -0091 % s_rot is the rotated signal -0092 s_rot = s .* exp(1i*alpha); -0093 % standard deviation of the imaginary part should be minimized -0094 sse = std(imag(s_rot)); -0095 case 'maxRe' -0096 % s_rot is the rotated signal -0097 s_rot = s .* exp(1i*alpha); -0098 % maximum of real part should be maximized -0099 sse = max(real(s_rot))*-1; -0100 end -0101 -0102 return -0103 -0104 %------------- END OF CODE -------------- -0105 -0106 %% License: -0107 % MIT License -0108 % -0109 % Copyright (c) 2018 Thomas Hiller -0110 % -0111 % Permission is hereby granted, free of charge, to any person obtaining a copy -0112 % of this software and associated documentation files (the "Software"), to deal -0113 % in the Software without restriction, including without limitation the rights -0114 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0115 % copies of the Software, and to permit persons to whom the Software is -0116 % furnished to do so, subject to the following conditions: -0117 % -0118 % The above copyright notice and this permission notice shall be included in all -0119 % copies or substantial portions of the Software. -0120 % -0121 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0122 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0123 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0124 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0125 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0126 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0127 % SOFTWARE.

    +0034 %% +0035 method = 'minReIm'; +0036 if nargin > 1 +0037 method = varargin{1}; +0038 end +0039 range = [-pi pi]; +0040 if nargin > 2 +0041 range = varargin{2}; +0042 end +0043 +0044 %% only proceed if signal is complex +0045 if ~isreal(s) +0046 % fminsearch options +0047 options = optimset('MaxFunEvals',100,'MaxIter',100,'TolFun',1e-6,'TolX',1e-6); +0048 % let fminsearch minimize fun1 +0049 % method = 'maxRe'; +0050 % [alpha,~,~,~] = fminsearch(@(alpha) fun1(alpha,s(1:end),method),pi/18,options); +0051 +0052 [alpha,~,~,~] = fminsearchbnd(@(alpha) fun1(alpha,s(1:end),method),... +0053 pi/18,range(1),range(2),options); +0054 +0055 % s_rot is the rotated signal +0056 s_rot = s .* exp(1i*alpha); +0057 +0058 % if the real part is negative rotate by 180° +0059 % if real(s_rot(1)) < 0 +0060 % s_rot = s_rot .* exp(1i*pi); +0061 % alpha = alpha + pi; +0062 % end +0063 else +0064 % do nothing +0065 s_rot = s; +0066 disp('Cannot ROTATE signal because it is not complex! rotateT2phase: Data is not complex.'); +0067 end +0068 +0069 return +0070 +0071 % minimization function +0072 function sse = fun1(alpha,s,method) +0073 % Inputs: +0074 % alpha - rotation phase angle in [rad] +0075 % s - NMR signal vector (has to be complex!) +0076 % method - "zero" or "minsd" +0077 % +0078 % Outputs: +0079 % sse - sum of squared residuals ("minReIm" or "minIm") or +0080 % standard deviation of imag. part ("stdIm") +0081 +0082 s = s(:); +0083 switch method +0084 case 'minReIm' +0085 % make a vector of zeros +0086 t0 = zeros(size(s,1),1); +0087 t0 = t0(:); +0088 % s_rot is the rotated signal +0089 s_rot = s .* exp(1i*alpha); +0090 % create residuals +0091 residuali = t0-imag(s_rot); +0092 residualr = t0-real(s_rot); +0093 % real part times -1 because we seek the maximum +0094 sse = sum(residuali.^2) + sum(residualr.^2)*-1; +0095 case 'minIm' +0096 % make a vector of zeros +0097 t0 = zeros(size(s,1),1); +0098 t0 = t0(:); +0099 % s_rot is the rotated signal +0100 s_rot = s .* exp(1i*alpha); +0101 % create residuals +0102 residuali = t0-imag(s_rot); +0103 % sse +0104 sse = sum(residuali.^2); +0105 case 'stdIm' +0106 % s_rot is the rotated signal +0107 s_rot = s .* exp(1i*alpha); +0108 % standard deviation of the imaginary part should be minimized +0109 sse = std(imag(s_rot)); +0110 case 'maxRe' +0111 % s_rot is the rotated signal +0112 s_rot = s .* exp(1i*alpha); +0113 % maximum of real part should be maximized +0114 sse = max(real(s_rot))*-1; +0115 end +0116 +0117 return +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.

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/ConductView.html b/doc/nucleus/functions/interface/ConductView.html index ce3c2df..3eb9c3a 100644 --- a/doc/nucleus/functions/interface/ConductView.html +++ b/doc/nucleus/functions/interface/ConductView.html @@ -62,7 +62,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • onMenuView handles the view menu entries
  • checkIfInversionExists checks if any inversion result is stored inside
  • clearAllAxes clears all axes of a given figure
  • getConstants provides some physical constants to the forward calculation
  • This function is called by:
    • onMenuSubGUIs handles the extra menu entries to open NUCLEUS sub GUIs
    @@ -163,638 +163,641 @@

    SOURCE CODE ^if isempty(fig_conduct) 0089 % draw the figure on top of NUCLEUS 0090 fig_conduct = figure('Name','NUCLEUS - ConductView',... -0091 'NumberTitle','off','ToolBar','none','Tag','CONDUCT'); +0091 'NumberTitle','off','ToolBar','none','Menubar','none','Tag','CONDUCT'); 0092 pos0 = get(fig,'Position'); -0093 pos1 = get(fig_conduct,'Position'); -0094 cent(1) = (pos0(1)+pos0(3)/2); -0095 cent(2) = (pos0(2)+pos0(4)/2); -0096 set(fig_conduct,'Position',[cent(1)-pos0(3)/3 pos0(2) pos0(3)/1.5 pos0(4)]); -0097 -0098 % create the layout -0099 gui.main = uix.HBox('Parent',fig_conduct,... -0100 'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); -0101 % control panel -0102 gui.col1 = uix.VBox('Parent',gui.main,... -0103 'BackGroundColor',colors.panelBG,'Spacing',5); -0104 % axes panel -0105 gui.col2 = uix.CardPanel('Parent',gui.main,... -0106 'BackGroundColor',colors.panelBG,'Visible','off'); -0107 set(gui.main,'Width',[200 -1]); -0108 -0109 % axes inside uicontainers -0110 for i = 1:6 -0111 gui.card(i) = uicontainer('Parent',gui.col2,... -0112 'BackGroundColor',colors.panelBG); -0113 gui.ax(i) = axes('Parent',gui.card(i),'Color',colors.axisBG,... -0114 'XColor',colors.axisFG,'YColor',colors.axisFG,... -0115 'FontSize',12); -0116 end -0117 -0118 % control boxes -0119 uix.Empty('Parent',gui.col1); -0120 gui.panels.method = uix.BoxPanel('Parent',gui.col1,'Title','Upscaling Method',... -0121 'TitleColor',colors.CPS,'ForegroundColor',colors.BoxTitle); -0122 gui.panels.type = uix.BoxPanel('Parent',gui.col1,'Title','Plot Type',... -0123 'TitleColor',colors.CPS,'ForegroundColor',colors.BoxTitle); -0124 gui.panels.prop = uix.BoxPanel('Parent',gui.col1,'Title','Properties',... -0125 'TitleColor',colors.CPS,'ForegroundColor',colors.BoxTitle); -0126 uix.Empty('Parent',gui.col1); -0127 set(gui.col1,'Heights',[-1 100 175 210 -1]); -0128 -0129 % vboxes inside panels -0130 gui.vbox1 = uix.VBox('Parent',gui.panels.method,... -0131 'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0132 gui.vbox2 = uix.VBox('Parent',gui.panels.type,... -0133 'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0134 gui.vbox3 = uix.VBox('Parent',gui.panels.prop,... -0135 'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0136 -0137 % radio buttons inside 1. box -0138 gui.radio.coord = [1 1]; -0139 % parallel connection -0140 gui.radio.pc = uicontrol('Parent',gui.vbox1,... -0141 'Style','radiobutton','String','parallel connection',... -0142 'Tag','method','FontSize',nucleus.gui.myui.fontsize,... -0143 'BackGroundColor',colors.panelBG,.... -0144 'ForeGroundColor',colors.panelFG,... -0145 'Enable','on','Value',1,'Callback',@cv_onRadioMethod); -0146 % effective capillary -0147 gui.radio.eff = uicontrol('Parent',gui.vbox1,... -0148 'Style','radiobutton','String','effective capillary',... -0149 'Tag','method','FontSize',nucleus.gui.myui.fontsize,... -0150 'BackGroundColor',colors.panelBG,.... -0151 'ForeGroundColor',colors.panelFG,... -0152 'Enable','on','Callback',@cv_onRadioMethod); -0153 -0154 % radio buttons inside 2. box -0155 % hydraulic conductivity -0156 gui.radio.cond = uicontrol('Parent',gui.vbox2,... -0157 'Style','radiobutton','String','hydraulic conductivity',... -0158 'Tag','type','FontSize',nucleus.gui.myui.fontsize,... -0159 'BackGroundColor',colors.panelBG,.... -0160 'ForeGroundColor',colors.panelFG,... -0161 'Enable','on','Value',1,'Callback',@cv_onRadioMethod); -0162 gui.hbox10 = uix.HBox('Parent',gui.vbox2,'BackGroundColor',colors.panelBG,'Spacing',4,'Padding',2); -0163 uix.Empty('Parent',gui.hbox10); -0164 gui.popup.cond = uicontrol('Parent',gui.hbox10,... -0165 'Style','popupmenu','String',{'m/s','cm/d'},... -0166 'Tag','cond','FontSize',nucleus.gui.myui.fontsize,... -0167 'BackGroundColor',colors.panelBG,.... -0168 'ForeGroundColor',colors.panelFG,... -0169 'Enable','on','Value',1,'Callback',@cv_onPopupUnit); -0170 gui.text.cond_unit = uicontrol('Parent',gui.hbox10,... -0171 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','left',... -0172 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0173 'String','unit'); -0174 uix.Empty('Parent',gui.hbox10); -0175 set(gui.hbox10,'Widths',[25 -3 -3 -1]); -0176 % permeability -0177 gui.radio.perm = uicontrol('Parent',gui.vbox2,... -0178 'Style','radiobutton','String','permeability',... -0179 'Tag','type','FontSize',nucleus.gui.myui.fontsize,... -0180 'BackGroundColor',colors.panelBG,.... -0181 'ForeGroundColor',colors.panelFG,... -0182 'Enable','on','Callback',@cv_onRadioMethod); -0183 gui.hbox11 = uix.HBox('Parent',gui.vbox2,'BackGroundColor',colors.panelBG,'Spacing',4,'Padding',2); -0184 uix.Empty('Parent',gui.hbox11); -0185 gui.popup.perm = uicontrol('Parent',gui.hbox11,... -0186 'Style','popupmenu','String',{'m²','D','mD'},... -0187 'Tag','perm','FontSize',nucleus.gui.myui.fontsize,... -0188 'BackGroundColor',colors.panelBG,.... -0189 'ForeGroundColor',colors.panelFG,... -0190 'Enable','on','Value',1,'Callback',@cv_onPopupUnit); -0191 gui.text.perm_unit = uicontrol('Parent',gui.hbox11,... -0192 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','left',... -0193 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0194 'String','unit'); -0195 uix.Empty('Parent',gui.hbox11); -0196 set(gui.hbox11,'Widths',[25 -3 -3 -1]); -0197 % relative cond / perm -0198 gui.radio.rel = uicontrol('Parent',gui.vbox2,... -0199 'Style','radiobutton','String','relative cond / perm [-]',... -0200 'Tag','type','FontSize',nucleus.gui.myui.fontsize,... -0201 'BackGroundColor',colors.panelBG,.... -0202 'ForeGroundColor',colors.panelFG,... -0203 'Enable','on','Callback',@cv_onRadioMethod); -0204 -0205 % horizontal boxes inside 3. box -0206 gui.hbox1 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0207 gui.hbox2 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0208 gui.hbox3 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0209 uix.Empty('Parent',gui.vbox3); -0210 gui.hbox4 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0211 gui.hbox5 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); -0212 set(gui.vbox3,'Heights',[-4 -4 -4 -1 -4 -4]); -0213 -0214 % gravitational acceleration [m/s²] -0215 gui.edit.gravity = uicontrol('Parent',gui.hbox1,... -0216 'Style','edit','String',num2str(constants.gravity),'FontSize',nucleus.gui.myui.fontsize,... -0217 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... -0218 'Tag','gravity','Enable','on','Callback',@cv_onEditProp); -0219 gui.text.gravity = uicontrol('Parent',gui.hbox1,... -0220 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... -0221 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0222 'String','grav. acc. [m/s²]'); -0223 % density [kg/m³] -0224 gui.edit.dens = uicontrol('Parent',gui.hbox2,... -0225 'Style','edit','String',num2str(constants.density),'FontSize',nucleus.gui.myui.fontsize,... -0226 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... -0227 'Tag','dens','Enable','on','Callback',@cv_onEditProp); -0228 gui.text.dens = uicontrol('Parent',gui.hbox2,... -0229 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... -0230 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0231 'String','density [kg/m³]'); -0232 % dynamic viscosity [Pa s] -0233 gui.edit.dyn = uicontrol('Parent',gui.hbox3,... -0234 'Style','edit','String',num2str(constants.dynvisc),'FontSize',nucleus.gui.myui.fontsize,... -0235 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... -0236 'Tag','dyn','Enable','on','Callback',@cv_onEditProp); -0237 gui.text.dyn = uicontrol('Parent',gui.hbox3,... -0238 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... -0239 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0240 'String','dyn. visc. [Pa s]'); -0241 % edit and text fields for different properties -0242 % porosity [-] -0243 gui.edit.poro = uicontrol('Parent',gui.hbox4,... -0244 'Style','edit','String',num2str(constants.porosity),'FontSize',nucleus.gui.myui.fontsize,... -0245 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... -0246 'Tag','poro','Enable','on','Callback',@cv_onEditProp); -0247 gui.text.poro = uicontrol('Parent',gui.hbox4,... -0248 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... -0249 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0250 'String','porosity [-]'); -0251 % edit and text fields for different properties -0252 % porosity [-] -0253 gui.edit.tort = uicontrol('Parent',gui.hbox5,... -0254 'Style','edit','String',num2str(constants.tortuosity),'FontSize',nucleus.gui.myui.fontsize,... -0255 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... -0256 'Tag','tort','Enable','on','Callback',@cv_onEditProp); -0257 gui.text.tort = uicontrol('Parent',gui.hbox5,... -0258 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... -0259 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0260 'String','tortuosity [-]'); -0261 % adjust the boxes -0262 set(gui.hbox1,'Width',[-1 -1.5]); -0263 set(gui.hbox2,'Width',[-1 -1.5]); -0264 set(gui.hbox3,'Width',[-1 -1.5]); -0265 set(gui.hbox4,'Width',[-1 -1.5]); -0266 set(gui.hbox5,'Width',[-1 -1.5]); -0267 % adjust the text fields -0268 jh = findjobj(gui.text.cond_unit); -0269 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0270 jh = findjobj(gui.text.perm_unit); -0271 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0272 jh = findjobj(gui.text.gravity); -0273 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0274 jh = findjobj(gui.text.dens); -0275 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0276 jh = findjobj(gui.text.dyn); -0277 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0278 jh = findjobj(gui.text.poro); -0279 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0280 h = findjobj(gui.text.tort); -0281 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0282 -0283 % store some main GUI settings -0284 gui.myui = nucleus.gui.myui; -0285 % save to GUI -0286 setappdata(fig_conduct,'gui',gui); -0287 else -0288 % if the figure is already open load the GUI data -0289 gui = getappdata(fig_conduct,'gui'); -0290 % clear all axes -0291 clearAllAxes(fig_conduct); -0292 % set default radio buttons -0293 gui.radio.coord = [1 1]; -0294 set(gui.radio.pc,'Value',1); -0295 set(gui.radio.cond,'Value',1); -0296 cv_onRadioMethod(gui.radio.pc); -0297 cv_onRadioMethod(gui.radio.cond); -0298 % set unit popup menus -0299 set(gui.popup.cond,'Value',1); -0300 set(gui.popup.perm,'Value',1); -0301 % set properties (may have changed) -0302 set(gui.edit.poro,'String',num2str(constants.porosity)); -0303 set(gui.edit.gravity,'String',num2str(constants.gravity)); -0304 set(gui.edit.dens,'String',num2str(constants.density)); -0305 set(gui.edit.dyn,'String',num2str(constants.dynvisc)); -0306 set(gui.edit.tort,'String',num2str(constants.tortuosity)); -0307 end -0308 % save to GUI -0309 setappdata(fig_conduct,'data',data); -0310 % plot the data -0311 cv_updateAxes(fig_conduct); -0312 % make the axes visible -0313 set(gui.col2,'Selection',1,'Visible','on'); -0314 else -0315 helpdlg({'function: showConduct',... -0316 'Cannot continue because there is no data.'},... -0317 'Not enough data to show'); -0318 end -0319 -0320 end -0321 -0322 %% -0323 function cv_onEditProp(src,~) -0324 fig_conduct = ancestor(src,'figure','toplevel'); -0325 gui = getappdata(fig_conduct,'gui'); -0326 data = getappdata(fig_conduct,'data'); -0327 -0328 val = str2double(get(src,'String')); -0329 -0330 switch get(src,'Tag') -0331 case 'poro' -0332 % check that porosity stays within limits -0333 if val <= 0 || val > 1 -0334 val = 1; -0335 set(src,'String',num2str(val)); -0336 end -0337 data.constants.porosity = val; -0338 case 'gravity' -0339 data.constants.gravity = val; -0340 case 'dens' -0341 data.constants.density = val; -0342 case 'dyn' -0343 data.constants.dynvisc = val; -0344 case 'tort' -0345 data.constants.tortuosity = val; -0346 end -0347 setappdata(fig_conduct,'data',data); -0348 cv_updateAxes(fig_conduct); -0349 -0350 end -0351 -0352 %% -0353 function cv_onPopupUnit(src,~) -0354 fig_conduct = ancestor(src,'figure','toplevel'); -0355 data = getappdata(fig_conduct,'data'); -0356 gui = getappdata(fig_conduct,'gui'); -0357 -0358 % check which popup menu was selected -0359 % and set the corresponding unit -0360 switch get(src,'Tag') -0361 case 'cond' -0362 data.cond_unit = get(src,'Value'); -0363 case 'perm' -0364 data.perm_unit = get(src,'Value'); -0365 end -0366 % update gui data -0367 setappdata(fig_conduct,'data',data); -0368 setappdata(fig_conduct,'gui',gui); -0369 -0370 % get the id of the current visible plot -0371 id = get(gui.col2,'Selection'); -0372 % update all plots -0373 cv_updateAxes(fig_conduct) -0374 % show the current visible plot again -0375 set(gui.col2,'Selection',id); -0376 -0377 end -0378 -0379 %% -0380 function cv_onRadioMethod(src,~) -0381 fig_conduct = ancestor(src,'figure','toplevel'); -0382 gui = getappdata(fig_conduct,'gui'); -0383 -0384 % check which radiobutton was selected -0385 switch get(src,'Tag') -0386 case 'method' -0387 switch get(src,'String') -0388 case 'parallel connection' -0389 gui.radio.coord(2) = 1; -0390 set(src,'Value',1); -0391 set(gui.radio.eff,'Value',0); -0392 case 'effective capillary' -0393 gui.radio.coord(2) = 2; -0394 set(src,'Value',1); -0395 set(gui.radio.pc,'Value',0); -0396 end -0397 case 'type' -0398 switch get(src,'String') -0399 case 'hydraulic conductivity' -0400 gui.radio.coord(1) = 1; -0401 set(src,'Value',1); -0402 set(gui.radio.perm,'Value',0); -0403 set(gui.radio.rel,'Value',0); -0404 case 'permeability' -0405 gui.radio.coord(1) = 2; -0406 set(src,'Value',1); -0407 set(gui.radio.cond,'Value',0); -0408 set(gui.radio.rel,'Value',0); -0409 case 'relative cond / perm [-]' -0410 gui.radio.coord(1) = 3; -0411 set(src,'Value',1); -0412 set(gui.radio.cond,'Value',0); -0413 set(gui.radio.perm,'Value',0); -0414 end -0415 end -0416 % update gui data -0417 setappdata(fig_conduct,'gui',gui); -0418 -0419 % activate selected card panel -0420 id = 3*(gui.radio.coord(2)-1)+gui.radio.coord(1); -0421 set(gui.col2,'Selection',id); -0422 -0423 end -0424 -0425 %% -0426 function cv_updateAxes(fig_conduct) -0427 gui = getappdata(fig_conduct,'gui'); -0428 data = getappdata(fig_conduct,'data'); -0429 colors = gui.myui.colors; -0430 -0431 % get unit for hydraulic conductivity -0432 if data.cond_unit == 1 -0433 unitfak_1 = 1; % [m/s] -0434 unitstr_1 = '[m/s]'; -0435 else -0436 unitfak_1 = 8.64e6; % [cm/d] -0437 unitstr_1 = '[cm/d]'; -0438 end -0439 ylstr_1 = ['hydraulic conductivity ',unitstr_1]; -0440 -0441 % get unit for permeability -0442 if data.perm_unit == 1 -0443 unitfak_2 = 1; % [m^2] -0444 unitstr_2 = '[m²]'; -0445 elseif data.perm_unit == 2 -0446 unitfak_2 = (1/9.86923e-13); % [D] Darcy -0447 unitstr_2 = '[D]'; -0448 else -0449 unitfak_2 = (1/9.86923e-16); % [mD] miili Darcy -0450 unitstr_2 = '[mD]'; -0451 end -0452 ylstr_2 = ['permeability ',unitstr_2]; -0453 -0454 % gather parameters -0455 tolKrel = data.tolKrel; -0456 constants = data.constants; -0457 permfak = constants.dynvisc / constants.density / constants.gravity; -0458 porofak = constants.porosity / constants.tortuosity; -0459 SAT = data.SAT; -0460 % "color brewer" colors -0461 coldrain = [0.2157 0.4941 0.7216]; % blue -0462 colimb = [0.8941 0.1020 0.1098]; % red -0463 -0464 % clear and hold all axes -0465 for i = 1:6 -0466 cla(gui.ax(i)) -0467 hold(gui.ax(i),'on'); -0468 end -0469 -0470 % plot data -0471 % pc - cond -0472 KSpc = max(unitfak_1*porofak*SAT.Kdfull(SAT.Sdfull==1)); -0473 if isempty(KSpc) -0474 KSpc = max(unitfak_1*porofak*SAT.Kdfull(SAT.Sdfull==max(SAT.Sdfull))); -0475 end -0476 switch data.geom_type -0477 case 'cyl' -0478 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kdfull,'Color',coldrain,... -0479 'DisplayName','drain','Parent',gui.ax(1)); -0480 plot(SAT.Sifull,unitfak_1*porofak*SAT.Kifull,'Color',colimb,... -0481 'LineStyle','--','DisplayName','imb','Parent',gui.ax(1)); -0482 otherwise -0483 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kdfull,'Color',coldrain,... -0484 'DisplayName','drain','Parent',gui.ax(1)); -0485 plot(SAT.Sifull,unitfak_1*porofak*SAT.Kifull,'Color',colimb,... -0486 'DisplayName','imb','Parent',gui.ax(1)); -0487 end -0488 ymin = min([unitfak_1*porofak*SAT.Kdfull;unitfak_1*porofak*SAT.Kifull]); -0489 ymax = max([unitfak_1*porofak*SAT.Kdfull;unitfak_1*porofak*SAT.Kifull]); -0490 ymin = 10^floor(log10(ymin)); -0491 ymax = 10^ceil(log10(ymax)); -0492 set(gui.ax(1),'YLim',[ymin ymax]); -0493 lgh = legend(gui.ax(1),'Location','SouthEast'); -0494 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0495 -0496 % pc - perm -0497 kSpc = max(unitfak_2*permfak*porofak*SAT.Kdfull(SAT.Sdfull==1)); -0498 if isempty(kSpc) -0499 kSpc = max(unitfak_2*permfak*porofak*SAT.Kdfull(SAT.Sdfull==max(SAT.Sdfull))); -0500 end -0501 switch data.geom_type -0502 case 'cyl' -0503 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kdfull.*permfak,'Color',coldrain,... -0504 'DisplayName','drain','Parent',gui.ax(2)); -0505 plot(SAT.Sifull,unitfak_2*porofak*SAT.Kifull.*permfak,'Color',colimb,... -0506 'LineStyle','--','DisplayName','imb','Parent',gui.ax(2)); -0507 otherwise -0508 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kdfull.*permfak,'Color',coldrain,... -0509 'DisplayName','drain','Parent',gui.ax(2)); -0510 plot(SAT.Sifull,unitfak_2*porofak*SAT.Kifull.*permfak,'Color',colimb,... -0511 'DisplayName','imb','Parent',gui.ax(2)); -0512 end -0513 ymin = min([unitfak_2*porofak*SAT.Kdfull.*permfak;unitfak_2*porofak*SAT.Kifull.*permfak]); -0514 ymax = max([unitfak_2*porofak*SAT.Kdfull.*permfak;unitfak_2*porofak*SAT.Kifull.*permfak]); -0515 ymin = 10^floor(log10(ymin)); -0516 ymax = 10^ceil(log10(ymax)); -0517 set(gui.ax(2),'YLim',[ymin ymax]); -0518 lgh = legend(gui.ax(2),'Location','SouthEast'); -0519 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0520 -0521 % pc - rel -0522 rel1 = SAT.Kdfull/SAT.Kdfull(find(SAT.Sdfull<tolKrel,1)); -0523 rel2 = SAT.Kifull/SAT.Kifull(find(SAT.Sifull<tolKrel,1)); -0524 switch data.geom_type -0525 case 'cyl' -0526 plot(SAT.Sdfull,rel1,'Color',coldrain,'DisplayName','drain','Parent',gui.ax(3)); -0527 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','imb','LineStyle','--','Parent',gui.ax(3)); -0528 otherwise +0093 cent(1) = (pos0(1)+pos0(3)/2); +0094 cent(2) = (pos0(2)+pos0(4)/2); +0095 set(fig_conduct,'Position',[cent(1)-pos0(3)/3 pos0(2)+22 pos0(3)/1.5 pos0(4)-22]); +0096 +0097 gui.menu.view = uimenu(fig_conduct,'Label','View'); +0098 gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',... +0099 'Callback',@onMenuView); +0100 +0101 % create the layout +0102 gui.main = uix.HBox('Parent',fig_conduct,... +0103 'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); +0104 % control panel +0105 gui.col1 = uix.VBox('Parent',gui.main,... +0106 'BackGroundColor',colors.panelBG,'Spacing',5); +0107 % axes panel +0108 gui.col2 = uix.CardPanel('Parent',gui.main,... +0109 'BackGroundColor',colors.panelBG,'Visible','off'); +0110 set(gui.main,'Width',[200 -1]); +0111 +0112 % axes inside uicontainers +0113 for i = 1:6 +0114 gui.card(i) = uicontainer('Parent',gui.col2,... +0115 'BackGroundColor',colors.panelBG); +0116 gui.ax(i) = axes('Parent',gui.card(i),'Color',colors.axisBG,... +0117 'XColor',colors.axisFG,'YColor',colors.axisFG,... +0118 'FontSize',12); +0119 end +0120 +0121 % control boxes +0122 uix.Empty('Parent',gui.col1); +0123 gui.panels.method = uix.BoxPanel('Parent',gui.col1,'Title','Upscaling Method',... +0124 'TitleColor',colors.CPS,'ForegroundColor',colors.BoxTitle); +0125 gui.panels.type = uix.BoxPanel('Parent',gui.col1,'Title','Plot Type',... +0126 'TitleColor',colors.CPS,'ForegroundColor',colors.BoxTitle); +0127 gui.panels.prop = uix.BoxPanel('Parent',gui.col1,'Title','Properties',... +0128 'TitleColor',colors.CPS,'ForegroundColor',colors.BoxTitle); +0129 uix.Empty('Parent',gui.col1); +0130 set(gui.col1,'Heights',[-1 100 175 210 -1]); +0131 +0132 % vboxes inside panels +0133 gui.vbox1 = uix.VBox('Parent',gui.panels.method,... +0134 'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0135 gui.vbox2 = uix.VBox('Parent',gui.panels.type,... +0136 'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0137 gui.vbox3 = uix.VBox('Parent',gui.panels.prop,... +0138 'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0139 +0140 % radio buttons inside 1. box +0141 gui.radio.coord = [1 1]; +0142 % parallel connection +0143 gui.radio.pc = uicontrol('Parent',gui.vbox1,... +0144 'Style','radiobutton','String','parallel connection',... +0145 'Tag','method','FontSize',nucleus.gui.myui.fontsize,... +0146 'BackGroundColor',colors.panelBG,.... +0147 'ForeGroundColor',colors.panelFG,... +0148 'Enable','on','Value',1,'Callback',@cv_onRadioMethod); +0149 % effective capillary +0150 gui.radio.eff = uicontrol('Parent',gui.vbox1,... +0151 'Style','radiobutton','String','effective capillary',... +0152 'Tag','method','FontSize',nucleus.gui.myui.fontsize,... +0153 'BackGroundColor',colors.panelBG,.... +0154 'ForeGroundColor',colors.panelFG,... +0155 'Enable','on','Callback',@cv_onRadioMethod); +0156 +0157 % radio buttons inside 2. box +0158 % hydraulic conductivity +0159 gui.radio.cond = uicontrol('Parent',gui.vbox2,... +0160 'Style','radiobutton','String','hydraulic conductivity',... +0161 'Tag','type','FontSize',nucleus.gui.myui.fontsize,... +0162 'BackGroundColor',colors.panelBG,.... +0163 'ForeGroundColor',colors.panelFG,... +0164 'Enable','on','Value',1,'Callback',@cv_onRadioMethod); +0165 gui.hbox10 = uix.HBox('Parent',gui.vbox2,'BackGroundColor',colors.panelBG,'Spacing',4,'Padding',2); +0166 uix.Empty('Parent',gui.hbox10); +0167 gui.popup.cond = uicontrol('Parent',gui.hbox10,... +0168 'Style','popupmenu','String',{'m/s','cm/d'},... +0169 'Tag','cond','FontSize',nucleus.gui.myui.fontsize,... +0170 'BackGroundColor',colors.panelBG,.... +0171 'ForeGroundColor',colors.panelFG,... +0172 'Enable','on','Value',1,'Callback',@cv_onPopupUnit); +0173 gui.text.cond_unit = uicontrol('Parent',gui.hbox10,... +0174 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','left',... +0175 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0176 'String','unit'); +0177 uix.Empty('Parent',gui.hbox10); +0178 set(gui.hbox10,'Widths',[25 -3 -3 -1]); +0179 % permeability +0180 gui.radio.perm = uicontrol('Parent',gui.vbox2,... +0181 'Style','radiobutton','String','permeability',... +0182 'Tag','type','FontSize',nucleus.gui.myui.fontsize,... +0183 'BackGroundColor',colors.panelBG,.... +0184 'ForeGroundColor',colors.panelFG,... +0185 'Enable','on','Callback',@cv_onRadioMethod); +0186 gui.hbox11 = uix.HBox('Parent',gui.vbox2,'BackGroundColor',colors.panelBG,'Spacing',4,'Padding',2); +0187 uix.Empty('Parent',gui.hbox11); +0188 gui.popup.perm = uicontrol('Parent',gui.hbox11,... +0189 'Style','popupmenu','String',{'m²','D','mD'},... +0190 'Tag','perm','FontSize',nucleus.gui.myui.fontsize,... +0191 'BackGroundColor',colors.panelBG,.... +0192 'ForeGroundColor',colors.panelFG,... +0193 'Enable','on','Value',1,'Callback',@cv_onPopupUnit); +0194 gui.text.perm_unit = uicontrol('Parent',gui.hbox11,... +0195 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','left',... +0196 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0197 'String','unit'); +0198 uix.Empty('Parent',gui.hbox11); +0199 set(gui.hbox11,'Widths',[25 -3 -3 -1]); +0200 % relative cond / perm +0201 gui.radio.rel = uicontrol('Parent',gui.vbox2,... +0202 'Style','radiobutton','String','relative cond / perm [-]',... +0203 'Tag','type','FontSize',nucleus.gui.myui.fontsize,... +0204 'BackGroundColor',colors.panelBG,.... +0205 'ForeGroundColor',colors.panelFG,... +0206 'Enable','on','Callback',@cv_onRadioMethod); +0207 +0208 % horizontal boxes inside 3. box +0209 gui.hbox1 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0210 gui.hbox2 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0211 gui.hbox3 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0212 uix.Empty('Parent',gui.vbox3); +0213 gui.hbox4 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0214 gui.hbox5 = uix.HBox('Parent',gui.vbox3,'BackGroundColor',colors.panelBG,'Spacing',2,'Padding',2); +0215 set(gui.vbox3,'Heights',[-4 -4 -4 -1 -4 -4]); +0216 +0217 % gravitational acceleration [m/s²] +0218 gui.edit.gravity = uicontrol('Parent',gui.hbox1,... +0219 'Style','edit','String',num2str(constants.gravity),'FontSize',nucleus.gui.myui.fontsize,... +0220 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... +0221 'Tag','gravity','Enable','on','Callback',@cv_onEditProp); +0222 gui.text.gravity = uicontrol('Parent',gui.hbox1,... +0223 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... +0224 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0225 'String','grav. acc. [m/s²]'); +0226 % density [kg/m³] +0227 gui.edit.dens = uicontrol('Parent',gui.hbox2,... +0228 'Style','edit','String',num2str(constants.density),'FontSize',nucleus.gui.myui.fontsize,... +0229 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... +0230 'Tag','dens','Enable','on','Callback',@cv_onEditProp); +0231 gui.text.dens = uicontrol('Parent',gui.hbox2,... +0232 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... +0233 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0234 'String','density [kg/m³]'); +0235 % dynamic viscosity [Pa s] +0236 gui.edit.dyn = uicontrol('Parent',gui.hbox3,... +0237 'Style','edit','String',num2str(constants.dynvisc),'FontSize',nucleus.gui.myui.fontsize,... +0238 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... +0239 'Tag','dyn','Enable','on','Callback',@cv_onEditProp); +0240 gui.text.dyn = uicontrol('Parent',gui.hbox3,... +0241 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... +0242 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0243 'String','dyn. visc. [Pa s]'); +0244 % edit and text fields for different properties +0245 % porosity [-] +0246 gui.edit.poro = uicontrol('Parent',gui.hbox4,... +0247 'Style','edit','String',num2str(constants.porosity),'FontSize',nucleus.gui.myui.fontsize,... +0248 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... +0249 'Tag','poro','Enable','on','Callback',@cv_onEditProp); +0250 gui.text.poro = uicontrol('Parent',gui.hbox4,... +0251 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... +0252 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0253 'String','porosity [-]'); +0254 % edit and text fields for different properties +0255 % porosity [-] +0256 gui.edit.tort = uicontrol('Parent',gui.hbox5,... +0257 'Style','edit','String',num2str(constants.tortuosity),'FontSize',nucleus.gui.myui.fontsize,... +0258 'BackGroundColor',colors.editBG,'ForeGroundColor',colors.panelFG,... +0259 'Tag','tort','Enable','on','Callback',@cv_onEditProp); +0260 gui.text.tort = uicontrol('Parent',gui.hbox5,... +0261 'Style','text','FontSize',nucleus.gui.myui.fontsize,'HorizontalAlignment','center',... +0262 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0263 'String','tortuosity [-]'); +0264 % adjust the boxes +0265 set(gui.hbox1,'Width',[-1 -1.5]); +0266 set(gui.hbox2,'Width',[-1 -1.5]); +0267 set(gui.hbox3,'Width',[-1 -1.5]); +0268 set(gui.hbox4,'Width',[-1 -1.5]); +0269 set(gui.hbox5,'Width',[-1 -1.5]); +0270 % adjust the text fields +0271 jh = findjobj(gui.text.cond_unit); +0272 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0273 jh = findjobj(gui.text.perm_unit); +0274 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0275 jh = findjobj(gui.text.gravity); +0276 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0277 jh = findjobj(gui.text.dens); +0278 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0279 jh = findjobj(gui.text.dyn); +0280 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0281 jh = findjobj(gui.text.poro); +0282 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0283 h = findjobj(gui.text.tort); +0284 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0285 +0286 % store some main GUI settings +0287 gui.myui = nucleus.gui.myui; +0288 % save to GUI +0289 setappdata(fig_conduct,'gui',gui); +0290 else +0291 % if the figure is already open load the GUI data +0292 gui = getappdata(fig_conduct,'gui'); +0293 % clear all axes +0294 clearAllAxes(fig_conduct); +0295 % set default radio buttons +0296 gui.radio.coord = [1 1]; +0297 set(gui.radio.pc,'Value',1); +0298 set(gui.radio.cond,'Value',1); +0299 cv_onRadioMethod(gui.radio.pc); +0300 cv_onRadioMethod(gui.radio.cond); +0301 % set unit popup menus +0302 set(gui.popup.cond,'Value',1); +0303 set(gui.popup.perm,'Value',1); +0304 % set properties (may have changed) +0305 set(gui.edit.poro,'String',num2str(constants.porosity)); +0306 set(gui.edit.gravity,'String',num2str(constants.gravity)); +0307 set(gui.edit.dens,'String',num2str(constants.density)); +0308 set(gui.edit.dyn,'String',num2str(constants.dynvisc)); +0309 set(gui.edit.tort,'String',num2str(constants.tortuosity)); +0310 end +0311 % save to GUI +0312 setappdata(fig_conduct,'data',data); +0313 % plot the data +0314 cv_updateAxes(fig_conduct); +0315 % make the axes visible +0316 set(gui.col2,'Selection',1,'Visible','on'); +0317 else +0318 helpdlg({'function: showConduct',... +0319 'Cannot continue because there is no data.'},... +0320 'Not enough data to show'); +0321 end +0322 +0323 end +0324 +0325 %% +0326 function cv_onEditProp(src,~) +0327 fig_conduct = ancestor(src,'figure','toplevel'); +0328 gui = getappdata(fig_conduct,'gui'); +0329 data = getappdata(fig_conduct,'data'); +0330 +0331 val = str2double(get(src,'String')); +0332 +0333 switch get(src,'Tag') +0334 case 'poro' +0335 % check that porosity stays within limits +0336 if val <= 0 || val > 1 +0337 val = 1; +0338 set(src,'String',num2str(val)); +0339 end +0340 data.constants.porosity = val; +0341 case 'gravity' +0342 data.constants.gravity = val; +0343 case 'dens' +0344 data.constants.density = val; +0345 case 'dyn' +0346 data.constants.dynvisc = val; +0347 case 'tort' +0348 data.constants.tortuosity = val; +0349 end +0350 setappdata(fig_conduct,'data',data); +0351 cv_updateAxes(fig_conduct); +0352 +0353 end +0354 +0355 %% +0356 function cv_onPopupUnit(src,~) +0357 fig_conduct = ancestor(src,'figure','toplevel'); +0358 data = getappdata(fig_conduct,'data'); +0359 gui = getappdata(fig_conduct,'gui'); +0360 +0361 % check which popup menu was selected +0362 % and set the corresponding unit +0363 switch get(src,'Tag') +0364 case 'cond' +0365 data.cond_unit = get(src,'Value'); +0366 case 'perm' +0367 data.perm_unit = get(src,'Value'); +0368 end +0369 % update gui data +0370 setappdata(fig_conduct,'data',data); +0371 setappdata(fig_conduct,'gui',gui); +0372 +0373 % get the id of the current visible plot +0374 id = get(gui.col2,'Selection'); +0375 % update all plots +0376 cv_updateAxes(fig_conduct) +0377 % show the current visible plot again +0378 set(gui.col2,'Selection',id); +0379 +0380 end +0381 +0382 %% +0383 function cv_onRadioMethod(src,~) +0384 fig_conduct = ancestor(src,'figure','toplevel'); +0385 gui = getappdata(fig_conduct,'gui'); +0386 +0387 % check which radiobutton was selected +0388 switch get(src,'Tag') +0389 case 'method' +0390 switch get(src,'String') +0391 case 'parallel connection' +0392 gui.radio.coord(2) = 1; +0393 set(src,'Value',1); +0394 set(gui.radio.eff,'Value',0); +0395 case 'effective capillary' +0396 gui.radio.coord(2) = 2; +0397 set(src,'Value',1); +0398 set(gui.radio.pc,'Value',0); +0399 end +0400 case 'type' +0401 switch get(src,'String') +0402 case 'hydraulic conductivity' +0403 gui.radio.coord(1) = 1; +0404 set(src,'Value',1); +0405 set(gui.radio.perm,'Value',0); +0406 set(gui.radio.rel,'Value',0); +0407 case 'permeability' +0408 gui.radio.coord(1) = 2; +0409 set(src,'Value',1); +0410 set(gui.radio.cond,'Value',0); +0411 set(gui.radio.rel,'Value',0); +0412 case 'relative cond / perm [-]' +0413 gui.radio.coord(1) = 3; +0414 set(src,'Value',1); +0415 set(gui.radio.cond,'Value',0); +0416 set(gui.radio.perm,'Value',0); +0417 end +0418 end +0419 % update gui data +0420 setappdata(fig_conduct,'gui',gui); +0421 +0422 % activate selected card panel +0423 id = 3*(gui.radio.coord(2)-1)+gui.radio.coord(1); +0424 set(gui.col2,'Selection',id); +0425 +0426 end +0427 +0428 %% +0429 function cv_updateAxes(fig_conduct) +0430 gui = getappdata(fig_conduct,'gui'); +0431 data = getappdata(fig_conduct,'data'); +0432 colors = gui.myui.colors; +0433 +0434 % get unit for hydraulic conductivity +0435 if data.cond_unit == 1 +0436 unitfak_1 = 1; % [m/s] +0437 unitstr_1 = '[m/s]'; +0438 else +0439 unitfak_1 = 8.64e6; % [cm/d] +0440 unitstr_1 = '[cm/d]'; +0441 end +0442 ylstr_1 = ['hydraulic conductivity ',unitstr_1]; +0443 +0444 % get unit for permeability +0445 if data.perm_unit == 1 +0446 unitfak_2 = 1; % [m^2] +0447 unitstr_2 = '[m²]'; +0448 elseif data.perm_unit == 2 +0449 unitfak_2 = (1/9.86923e-13); % [D] Darcy +0450 unitstr_2 = '[D]'; +0451 else +0452 unitfak_2 = (1/9.86923e-16); % [mD] miili Darcy +0453 unitstr_2 = '[mD]'; +0454 end +0455 ylstr_2 = ['permeability ',unitstr_2]; +0456 +0457 % gather parameters +0458 tolKrel = data.tolKrel; +0459 constants = data.constants; +0460 permfak = constants.dynvisc / constants.density / constants.gravity; +0461 porofak = constants.porosity / constants.tortuosity; +0462 SAT = data.SAT; +0463 % "color brewer" colors +0464 coldrain = [0.2157 0.4941 0.7216]; % blue +0465 colimb = [0.8941 0.1020 0.1098]; % red +0466 +0467 % clear and hold all axes +0468 for i = 1:6 +0469 cla(gui.ax(i)) +0470 hold(gui.ax(i),'on'); +0471 end +0472 +0473 % plot data +0474 % pc - cond +0475 KSpc = max(unitfak_1*porofak*SAT.Kdfull(SAT.Sdfull==1)); +0476 if isempty(KSpc) +0477 KSpc = max(unitfak_1*porofak*SAT.Kdfull(SAT.Sdfull==max(SAT.Sdfull))); +0478 end +0479 switch data.geom_type +0480 case 'cyl' +0481 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kdfull,'Color',coldrain,... +0482 'DisplayName','drain','Parent',gui.ax(1)); +0483 plot(SAT.Sifull,unitfak_1*porofak*SAT.Kifull,'Color',colimb,... +0484 'LineStyle','--','DisplayName','imb','Parent',gui.ax(1)); +0485 otherwise +0486 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kdfull,'Color',coldrain,... +0487 'DisplayName','drain','Parent',gui.ax(1)); +0488 plot(SAT.Sifull,unitfak_1*porofak*SAT.Kifull,'Color',colimb,... +0489 'DisplayName','imb','Parent',gui.ax(1)); +0490 end +0491 ymin = min([unitfak_1*porofak*SAT.Kdfull;unitfak_1*porofak*SAT.Kifull]); +0492 ymax = max([unitfak_1*porofak*SAT.Kdfull;unitfak_1*porofak*SAT.Kifull]); +0493 ymin = 10^floor(log10(ymin)); +0494 ymax = 10^ceil(log10(ymax)); +0495 set(gui.ax(1),'YLim',[ymin ymax]); +0496 lgh = legend(gui.ax(1),'Location','SouthEast'); +0497 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0498 +0499 % pc - perm +0500 kSpc = max(unitfak_2*permfak*porofak*SAT.Kdfull(SAT.Sdfull==1)); +0501 if isempty(kSpc) +0502 kSpc = max(unitfak_2*permfak*porofak*SAT.Kdfull(SAT.Sdfull==max(SAT.Sdfull))); +0503 end +0504 switch data.geom_type +0505 case 'cyl' +0506 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kdfull.*permfak,'Color',coldrain,... +0507 'DisplayName','drain','Parent',gui.ax(2)); +0508 plot(SAT.Sifull,unitfak_2*porofak*SAT.Kifull.*permfak,'Color',colimb,... +0509 'LineStyle','--','DisplayName','imb','Parent',gui.ax(2)); +0510 otherwise +0511 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kdfull.*permfak,'Color',coldrain,... +0512 'DisplayName','drain','Parent',gui.ax(2)); +0513 plot(SAT.Sifull,unitfak_2*porofak*SAT.Kifull.*permfak,'Color',colimb,... +0514 'DisplayName','imb','Parent',gui.ax(2)); +0515 end +0516 ymin = min([unitfak_2*porofak*SAT.Kdfull.*permfak;unitfak_2*porofak*SAT.Kifull.*permfak]); +0517 ymax = max([unitfak_2*porofak*SAT.Kdfull.*permfak;unitfak_2*porofak*SAT.Kifull.*permfak]); +0518 ymin = 10^floor(log10(ymin)); +0519 ymax = 10^ceil(log10(ymax)); +0520 set(gui.ax(2),'YLim',[ymin ymax]); +0521 lgh = legend(gui.ax(2),'Location','SouthEast'); +0522 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0523 +0524 % pc - rel +0525 rel1 = SAT.Kdfull/SAT.Kdfull(find(SAT.Sdfull<tolKrel,1)); +0526 rel2 = SAT.Kifull/SAT.Kifull(find(SAT.Sifull<tolKrel,1)); +0527 switch data.geom_type +0528 case 'cyl' 0529 plot(SAT.Sdfull,rel1,'Color',coldrain,'DisplayName','drain','Parent',gui.ax(3)); -0530 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','imb','Parent',gui.ax(3)); -0531 end -0532 ymin = min([rel1; rel2]); -0533 ymin = 10^floor(log10(ymin)); -0534 set(gui.ax(3),'YLim',[ymin 1]); -0535 lgh = legend(gui.ax(3),'Location','SouthEast'); -0536 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0537 -0538 % eff - cond -0539 KSeff = max(unitfak_1*porofak*SAT.Kd_eff(SAT.Sdfull==1)); -0540 if isempty(KSeff) -0541 KSeff = max(unitfak_1*porofak*SAT.Kd_eff(SAT.Sdfull==max(SAT.Sdfull))); -0542 end -0543 switch data.geom_type -0544 case 'cyl' -0545 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_eff,'Color',coldrain,... -0546 'DisplayName','drain','Parent',gui.ax(4)); -0547 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_eff,'Color',colimb,... -0548 'DisplayName','imb','LineStyle','--','Parent',gui.ax(4)); -0549 lgh = legend(gui.ax(4),'Location','SouthEast'); -0550 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0551 otherwise -0552 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_ducts,'Color',coldrain,'LineStyle','--',... -0553 'DisplayName','ducts','Parent',gui.ax(4)); -0554 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_corners,'Color',coldrain,'LineStyle',':',... -0555 'DisplayName','corners','Parent',gui.ax(4)); -0556 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_eff,'Color',coldrain,... -0557 'DisplayName','sum','Parent',gui.ax(4)); -0558 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_ducts,'Color',colimb,'LineStyle','--',... -0559 'DisplayName','ducts','Parent',gui.ax(4)); -0560 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_corners,'Color',colimb,'LineStyle',':',... -0561 'DisplayName','corners','Parent',gui.ax(4)); -0562 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_eff,'Color',colimb,... -0563 'DisplayName','sum','Parent',gui.ax(4)); -0564 lgh = legend(gui.ax(4),'Location','SouthEast'); -0565 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0566 lgh.NumColumns = 2; -0567 lgh.Title.String = 'drain imb'; -0568 end -0569 ymin = min([unitfak_1*porofak*SAT.Kd_eff';unitfak_1*porofak*SAT.Ki_eff']); -0570 ymax = max([unitfak_1*porofak*SAT.Kd_eff';unitfak_1*porofak*SAT.Ki_eff']); -0571 ymin = 10^floor(log10(ymin)); -0572 ymax = 10^ceil(log10(ymax)); -0573 set(gui.ax(4),'YLim',[ymin ymax]); -0574 -0575 -0576 % eff - perm -0577 kSeff = max(unitfak_2*permfak*porofak*SAT.Kd_eff(SAT.Sdfull==1)); -0578 if isempty(kSeff) -0579 kSeff = max(unitfak_2*permfak*porofak*SAT.Kd_eff(SAT.Sdfull==max(SAT.Sdfull))); -0580 end -0581 switch data.geom_type -0582 case 'cyl' -0583 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_eff.*permfak,'Color',coldrain,... -0584 'DisplayName','drain','Parent',gui.ax(5)); -0585 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_eff.*permfak,'Color',colimb,... -0586 'DisplayName','imb','LineStyle','--','Parent',gui.ax(5)); -0587 lgh = legend(gui.ax(5),'Location','SouthEast'); -0588 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0589 otherwise -0590 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_ducts.*permfak,'Color',coldrain,'LineStyle','--',... -0591 'DisplayName','ducts','Parent',gui.ax(5)); -0592 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_corners.*permfak,'Color',coldrain,'LineStyle',':',... -0593 'DisplayName','corners','Parent',gui.ax(5)); -0594 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_eff.*permfak,'Color',coldrain,... -0595 'DisplayName','sum','Parent',gui.ax(5)); -0596 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_ducts.*permfak,'Color',colimb,'LineStyle','--',... -0597 'DisplayName','ducts','Parent',gui.ax(5)); -0598 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_corners.*permfak,'Color',colimb,'LineStyle',':',... -0599 'DisplayName','corners','Parent',gui.ax(5)); -0600 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_eff.*permfak,'Color',colimb,... -0601 'DisplayName','sum','Parent',gui.ax(5)); -0602 lgh = legend(gui.ax(5),'Location','SouthEast'); -0603 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0604 lgh.NumColumns = 2; -0605 lgh.Title.String = 'drain imb'; -0606 end -0607 ymin = min([unitfak_2*porofak*SAT.Kd_eff'.*permfak;unitfak_2*porofak*SAT.Ki_eff'.*permfak]); -0608 ymax = max([unitfak_2*porofak*SAT.Kd_eff'.*permfak;unitfak_2*porofak*SAT.Ki_eff'.*permfak]); -0609 ymin = 10^floor(log10(ymin)); -0610 ymax = 10^ceil(log10(ymax)); -0611 set(gui.ax(5),'YLim',[ymin ymax]); -0612 -0613 % eff - rel -0614 rel1 = SAT.Kd_eff/SAT.Kd_eff(find(SAT.Sdfull<tolKrel,1)); -0615 rel2 = SAT.Ki_eff/SAT.Ki_eff(find(SAT.Sifull<tolKrel,1)); -0616 switch data.geom_type -0617 case 'cyl' -0618 plot(SAT.Sdfull,rel1,'Color',coldrain,'DisplayName','drain',... -0619 'Parent',gui.ax(6)); -0620 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','imb',... -0621 'LineStyle','--','Parent',gui.ax(6)); -0622 lgh = legend(gui.ax(6),'Location','SouthEast'); -0623 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0624 otherwise -0625 plot(SAT.Sdfull,SAT.Kd_ducts/SAT.Kd_eff(find(SAT.Sdfull<tolKrel,1)),... -0626 'Color',coldrain,'LineStyle','--','DisplayName','ducts','Parent',gui.ax(6)); -0627 plot(SAT.Sdfull,SAT.Kd_corners/SAT.Kd_eff(find(SAT.Sdfull<tolKrel,1)),... -0628 'Color',coldrain,'LineStyle',':','DisplayName','corners','Parent',gui.ax(6)); -0629 plot(SAT.Sdfull,rel1,'Color',coldrain,'DisplayName','sum','Parent',gui.ax(6)); -0630 plot(SAT.Sifull,SAT.Ki_ducts/SAT.Ki_eff(find(SAT.Sifull<tolKrel,1)),... -0631 'Color',colimb,'LineStyle','--','DisplayName','ducts','Parent',gui.ax(6)); -0632 plot(SAT.Sifull,SAT.Ki_corners/SAT.Ki_eff(find(SAT.Sifull<tolKrel,1)),... -0633 'Color',colimb,'LineStyle',':','DisplayName','corners','Parent',gui.ax(6)); -0634 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','sum','Parent',gui.ax(6)); -0635 lgh = legend(gui.ax(6),'Location','SouthEast'); -0636 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); -0637 lgh.NumColumns = 2; -0638 lgh.Title.String = 'drain imb'; -0639 end -0640 ymin = min([rel1(rel1>0)'; rel2(rel2>0)']); -0641 ymin = 10^floor(log10(ymin)); -0642 set(gui.ax(6),'YLim',[ymin 1]); -0643 -0644 % general axes settingd -0645 set(gui.ax,'YScale','log','XLim',[0 1]); -0646 for i = 1:6 -0647 grid(gui.ax(i),'on'); -0648 hold(gui.ax(i),'off'); -0649 set(get(gui.ax(i),'XLabel'),'String','saturation [-]'); -0650 end -0651 -0652 % set the individual axes titles with the full saturated values for "K" / "k" -0653 col = get(gui.ax(1),'XColor'); -0654 set(get(gui.ax(1),'Title'),'String',['K(S=1) = ',sprintf('%1.2e',KSpc),' ',unitstr_1],... -0655 'Color',col); -0656 set(get(gui.ax(2),'Title'),'String',['k(S=1) = ',sprintf('%1.2e',kSpc),' ',unitstr_2],... -0657 'Color',col); -0658 set(get(gui.ax(4),'Title'),'String',['K(S=1) = ',sprintf('%1.2e',KSeff),' ',unitstr_1],... -0659 'Color',col); -0660 set(get(gui.ax(5),'Title'),'String',['k(S=1) = ',sprintf('%1.2e',kSeff),' ',unitstr_2],... -0661 'Color',col); -0662 -0663 % some special axes settings -0664 for i = 1:3 -0665 % adjust the y-limits for similar axes -0666 ylim1 = get(gui.ax(i),'YLim'); -0667 ylim2 = get(gui.ax(i+3),'YLim'); -0668 -0669 if ylim1(1) == 0 -0670 ylim1(1) = ylim2(1); -0671 end -0672 if ylim2(1) == 0 -0673 ylim2(1) = ylim1(1); +0530 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','imb','LineStyle','--','Parent',gui.ax(3)); +0531 otherwise +0532 plot(SAT.Sdfull,rel1,'Color',coldrain,'DisplayName','drain','Parent',gui.ax(3)); +0533 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','imb','Parent',gui.ax(3)); +0534 end +0535 ymin = min([rel1; rel2]); +0536 ymin = 10^floor(log10(ymin)); +0537 set(gui.ax(3),'YLim',[ymin 1]); +0538 lgh = legend(gui.ax(3),'Location','SouthEast'); +0539 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0540 +0541 % eff - cond +0542 KSeff = max(unitfak_1*porofak*SAT.Kd_eff(SAT.Sdfull==1)); +0543 if isempty(KSeff) +0544 KSeff = max(unitfak_1*porofak*SAT.Kd_eff(SAT.Sdfull==max(SAT.Sdfull))); +0545 end +0546 switch data.geom_type +0547 case 'cyl' +0548 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_eff,'Color',coldrain,... +0549 'DisplayName','drain','Parent',gui.ax(4)); +0550 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_eff,'Color',colimb,... +0551 'DisplayName','imb','LineStyle','--','Parent',gui.ax(4)); +0552 lgh = legend(gui.ax(4),'Location','SouthEast'); +0553 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0554 otherwise +0555 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_ducts,'Color',coldrain,'LineStyle','--',... +0556 'DisplayName','ducts','Parent',gui.ax(4)); +0557 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_corners,'Color',coldrain,'LineStyle',':',... +0558 'DisplayName','corners','Parent',gui.ax(4)); +0559 plot(SAT.Sdfull,unitfak_1*porofak*SAT.Kd_eff,'Color',coldrain,... +0560 'DisplayName','sum','Parent',gui.ax(4)); +0561 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_ducts,'Color',colimb,'LineStyle','--',... +0562 'DisplayName','ducts','Parent',gui.ax(4)); +0563 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_corners,'Color',colimb,'LineStyle',':',... +0564 'DisplayName','corners','Parent',gui.ax(4)); +0565 plot(SAT.Sifull,unitfak_1*porofak*SAT.Ki_eff,'Color',colimb,... +0566 'DisplayName','sum','Parent',gui.ax(4)); +0567 lgh = legend(gui.ax(4),'Location','SouthEast'); +0568 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0569 lgh.NumColumns = 2; +0570 lgh.Title.String = 'drain imb'; +0571 end +0572 ymin = min([unitfak_1*porofak*SAT.Kd_eff';unitfak_1*porofak*SAT.Ki_eff']); +0573 ymax = max([unitfak_1*porofak*SAT.Kd_eff';unitfak_1*porofak*SAT.Ki_eff']); +0574 ymin = 10^floor(log10(ymin)); +0575 ymax = 10^ceil(log10(ymax)); +0576 set(gui.ax(4),'YLim',[ymin ymax]); +0577 +0578 +0579 % eff - perm +0580 kSeff = max(unitfak_2*permfak*porofak*SAT.Kd_eff(SAT.Sdfull==1)); +0581 if isempty(kSeff) +0582 kSeff = max(unitfak_2*permfak*porofak*SAT.Kd_eff(SAT.Sdfull==max(SAT.Sdfull))); +0583 end +0584 switch data.geom_type +0585 case 'cyl' +0586 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_eff.*permfak,'Color',coldrain,... +0587 'DisplayName','drain','Parent',gui.ax(5)); +0588 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_eff.*permfak,'Color',colimb,... +0589 'DisplayName','imb','LineStyle','--','Parent',gui.ax(5)); +0590 lgh = legend(gui.ax(5),'Location','SouthEast'); +0591 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0592 otherwise +0593 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_ducts.*permfak,'Color',coldrain,'LineStyle','--',... +0594 'DisplayName','ducts','Parent',gui.ax(5)); +0595 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_corners.*permfak,'Color',coldrain,'LineStyle',':',... +0596 'DisplayName','corners','Parent',gui.ax(5)); +0597 plot(SAT.Sdfull,unitfak_2*porofak*SAT.Kd_eff.*permfak,'Color',coldrain,... +0598 'DisplayName','sum','Parent',gui.ax(5)); +0599 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_ducts.*permfak,'Color',colimb,'LineStyle','--',... +0600 'DisplayName','ducts','Parent',gui.ax(5)); +0601 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_corners.*permfak,'Color',colimb,'LineStyle',':',... +0602 'DisplayName','corners','Parent',gui.ax(5)); +0603 plot(SAT.Sifull,unitfak_2*porofak*SAT.Ki_eff.*permfak,'Color',colimb,... +0604 'DisplayName','sum','Parent',gui.ax(5)); +0605 lgh = legend(gui.ax(5),'Location','SouthEast'); +0606 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0607 lgh.NumColumns = 2; +0608 lgh.Title.String = 'drain imb'; +0609 end +0610 ymin = min([unitfak_2*porofak*SAT.Kd_eff'.*permfak;unitfak_2*porofak*SAT.Ki_eff'.*permfak]); +0611 ymax = max([unitfak_2*porofak*SAT.Kd_eff'.*permfak;unitfak_2*porofak*SAT.Ki_eff'.*permfak]); +0612 ymin = 10^floor(log10(ymin)); +0613 ymax = 10^ceil(log10(ymax)); +0614 set(gui.ax(5),'YLim',[ymin ymax]); +0615 +0616 % eff - rel +0617 rel1 = SAT.Kd_eff/SAT.Kd_eff(find(SAT.Sdfull<tolKrel,1)); +0618 rel2 = SAT.Ki_eff/SAT.Ki_eff(find(SAT.Sifull<tolKrel,1)); +0619 switch data.geom_type +0620 case 'cyl' +0621 plot(SAT.Sdfull,rel1,'Color',coldrain,'DisplayName','drain',... +0622 'Parent',gui.ax(6)); +0623 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','imb',... +0624 'LineStyle','--','Parent',gui.ax(6)); +0625 lgh = legend(gui.ax(6),'Location','SouthEast'); +0626 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0627 otherwise +0628 plot(SAT.Sdfull,SAT.Kd_ducts/SAT.Kd_eff(find(SAT.Sdfull<tolKrel,1)),... +0629 'Color',coldrain,'LineStyle','--','DisplayName','ducts','Parent',gui.ax(6)); +0630 plot(SAT.Sdfull,SAT.Kd_corners/SAT.Kd_eff(find(SAT.Sdfull<tolKrel,1)),... +0631 'Color',coldrain,'LineStyle',':','DisplayName','corners','Parent',gui.ax(6)); +0632 plot(SAT.Sdfull,rel1,'Color',coldrain,'DisplayName','sum','Parent',gui.ax(6)); +0633 plot(SAT.Sifull,SAT.Ki_ducts/SAT.Ki_eff(find(SAT.Sifull<tolKrel,1)),... +0634 'Color',colimb,'LineStyle','--','DisplayName','ducts','Parent',gui.ax(6)); +0635 plot(SAT.Sifull,SAT.Ki_corners/SAT.Ki_eff(find(SAT.Sifull<tolKrel,1)),... +0636 'Color',colimb,'LineStyle',':','DisplayName','corners','Parent',gui.ax(6)); +0637 plot(SAT.Sifull,rel2,'Color',colimb,'DisplayName','sum','Parent',gui.ax(6)); +0638 lgh = legend(gui.ax(6),'Location','SouthEast'); +0639 set(lgh,'TextColor',colors.panelFG,'Color',colors.axisBG); +0640 lgh.NumColumns = 2; +0641 lgh.Title.String = 'drain imb'; +0642 end +0643 ymin = min([rel1(rel1>0)'; rel2(rel2>0)']); +0644 ymin = 10^floor(log10(ymin)); +0645 set(gui.ax(6),'YLim',[ymin 1]); +0646 +0647 % general axes settingd +0648 set(gui.ax,'YScale','log','XLim',[0 1]); +0649 for i = 1:6 +0650 grid(gui.ax(i),'on'); +0651 hold(gui.ax(i),'off'); +0652 set(get(gui.ax(i),'XLabel'),'String','saturation [-]'); +0653 end +0654 +0655 % set the individual axes titles with the full saturated values for "K" / "k" +0656 col = get(gui.ax(1),'XColor'); +0657 set(get(gui.ax(1),'Title'),'String',['K(S=1) = ',sprintf('%1.2e',KSpc),' ',unitstr_1],... +0658 'Color',col); +0659 set(get(gui.ax(2),'Title'),'String',['k(S=1) = ',sprintf('%1.2e',kSpc),' ',unitstr_2],... +0660 'Color',col); +0661 set(get(gui.ax(4),'Title'),'String',['K(S=1) = ',sprintf('%1.2e',KSeff),' ',unitstr_1],... +0662 'Color',col); +0663 set(get(gui.ax(5),'Title'),'String',['k(S=1) = ',sprintf('%1.2e',kSeff),' ',unitstr_2],... +0664 'Color',col); +0665 +0666 % some special axes settings +0667 for i = 1:3 +0668 % adjust the y-limits for similar axes +0669 ylim1 = get(gui.ax(i),'YLim'); +0670 ylim2 = get(gui.ax(i+3),'YLim'); +0671 +0672 if ylim1(1) == 0 +0673 ylim1(1) = ylim2(1); 0674 end -0675 -0676 if i<3 -0677 set(gui.ax(i),'YLim',[min([ylim1(1) ylim2(1)]) max([ylim1(2) ylim2(2)])]); -0678 set(gui.ax(i+3),'YLim',[min([ylim1(1) ylim2(1)]) max([ylim1(2) ylim2(2)])]); -0679 else -0680 set(gui.ax(i),'YLim',[min([ylim1(1) ylim2(1)]) 1]); -0681 set(gui.ax(i+3),'YLim',[min([ylim1(1) ylim2(1)]) 1]); -0682 end -0683 -0684 % axes labels -0685 if i == 1 -0686 set(get(gui.ax(i),'YLabel'),'String',ylstr_1); -0687 set(get(gui.ax(i+3),'YLabel'),'String',ylstr_1); -0688 elseif i == 2 -0689 set(get(gui.ax(i),'YLabel'),'String',ylstr_2); -0690 set(get(gui.ax(i+3),'YLabel'),'String',ylstr_2); -0691 else -0692 set(get(gui.ax(i),'YLabel'),'String','relative cond. / perm. [-]'); -0693 set(get(gui.ax(i+3),'YLabel'),'String','relative cond. / perm. [-]'); -0694 end -0695 end -0696 -0697 end -0698 -0699 %------------- END OF CODE -------------- -0700 -0701 %% License: -0702 % MIT License -0703 % -0704 % Copyright (c) 2018 Thomas Hiller -0705 % -0706 % Permission is hereby granted, free of charge, to any person obtaining a copy -0707 % of this software and associated documentation files (the "Software"), to deal -0708 % in the Software without restriction, including without limitation the rights -0709 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0710 % copies of the Software, and to permit persons to whom the Software is -0711 % furnished to do so, subject to the following conditions: -0712 % -0713 % The above copyright notice and this permission notice shall be included in all -0714 % copies or substantial portions of the Software. +0675 if ylim2(1) == 0 +0676 ylim2(1) = ylim1(1); +0677 end +0678 +0679 if i<3 +0680 set(gui.ax(i),'YLim',[min([ylim1(1) ylim2(1)]) max([ylim1(2) ylim2(2)])]); +0681 set(gui.ax(i+3),'YLim',[min([ylim1(1) ylim2(1)]) max([ylim1(2) ylim2(2)])]); +0682 else +0683 set(gui.ax(i),'YLim',[min([ylim1(1) ylim2(1)]) 1]); +0684 set(gui.ax(i+3),'YLim',[min([ylim1(1) ylim2(1)]) 1]); +0685 end +0686 +0687 % axes labels +0688 if i == 1 +0689 set(get(gui.ax(i),'YLabel'),'String',ylstr_1); +0690 set(get(gui.ax(i+3),'YLabel'),'String',ylstr_1); +0691 elseif i == 2 +0692 set(get(gui.ax(i),'YLabel'),'String',ylstr_2); +0693 set(get(gui.ax(i+3),'YLabel'),'String',ylstr_2); +0694 else +0695 set(get(gui.ax(i),'YLabel'),'String','relative cond. / perm. [-]'); +0696 set(get(gui.ax(i+3),'YLabel'),'String','relative cond. / perm. [-]'); +0697 end +0698 end +0699 +0700 end +0701 +0702 %------------- END OF CODE -------------- +0703 +0704 %% License: +0705 % MIT License +0706 % +0707 % Copyright (c) 2018 Thomas Hiller +0708 % +0709 % Permission is hereby granted, free of charge, to any person obtaining a copy +0710 % of this software and associated documentation files (the "Software"), to deal +0711 % in the Software without restriction, including without limitation the rights +0712 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0713 % copies of the Software, and to permit persons to whom the Software is +0714 % furnished to do so, subject to the following conditions: 0715 % -0716 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0717 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0718 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0719 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0720 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0721 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0722 % SOFTWARE.

    +0716 % The above copyright notice and this permission notice shall be included in all +0717 % copies or substantial portions of the Software. +0718 % +0719 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0720 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0721 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0722 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0723 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0724 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0725 % SOFTWARE.

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

    Inv2DView +

    + +

    PURPOSE ^

    +
    is an extra subGUI to calculate 2D inversion of T1-T2 data
    + +

    SYNOPSIS ^

    +
    function Inv2DView(src,~)
    + +

    DESCRIPTION ^

    +
    Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
    +
    + Syntax:
    +       Inv2DView
    +
    + Inputs:
    +       src - handle of the calling object
    +
    + Outputs:
    +       none
    +
    + Example:
    +       Inv2DView(src,~)
    +
    + Other m-files required:
    +       beautifyAxes
    +       clearAllAxes
    +       displayStatusText
    +       fitData2D
    +       imagescnan
    +       onListboxData
    +       onRadioGates
    +       updatePlotsSignal;
    +       updatePlotsDistribution;
    +       updateInfo;
    +
    + Subfunctions:
    +       findApproxTlgmAmplitude
    +       tv_closeme
    +       tv_estimateIRtype
    +       tv_getTLGM
    +       tv_onCheckDCM
    +       tv_onEditValue
    +       tv_onPopupIRType
    +       tv_onPopupT1Type
    +       tv_onPushRun
    +       tv_onPushSave
    +       tv_onPushView
    +       tv_onPushUpdate
    +       tv_onRadioLogLin
    +       tv_plotResults
    +       tv_plotRawData
    +       tv_prepareRawData
    +       tv_setAxesScaling
    +
    + 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 Inv2DView(src,~)
    +0002 %Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
    +0003 %
    +0004 % Syntax:
    +0005 %       Inv2DView
    +0006 %
    +0007 % Inputs:
    +0008 %       src - handle of the calling object
    +0009 %
    +0010 % Outputs:
    +0011 %       none
    +0012 %
    +0013 % Example:
    +0014 %       Inv2DView(src,~)
    +0015 %
    +0016 % Other m-files required:
    +0017 %       beautifyAxes
    +0018 %       clearAllAxes
    +0019 %       displayStatusText
    +0020 %       fitData2D
    +0021 %       imagescnan
    +0022 %       onListboxData
    +0023 %       onRadioGates
    +0024 %       updatePlotsSignal;
    +0025 %       updatePlotsDistribution;
    +0026 %       updateInfo;
    +0027 %
    +0028 % Subfunctions:
    +0029 %       findApproxTlgmAmplitude
    +0030 %       tv_closeme
    +0031 %       tv_estimateIRtype
    +0032 %       tv_getTLGM
    +0033 %       tv_onCheckDCM
    +0034 %       tv_onEditValue
    +0035 %       tv_onPopupIRType
    +0036 %       tv_onPopupT1Type
    +0037 %       tv_onPushRun
    +0038 %       tv_onPushSave
    +0039 %       tv_onPushView
    +0040 %       tv_onPushUpdate
    +0041 %       tv_onRadioLogLin
    +0042 %       tv_plotResults
    +0043 %       tv_plotRawData
    +0044 %       tv_prepareRawData
    +0045 %       tv_setAxesScaling
    +0046 %
    +0047 % MAT-files required:
    +0048 %       none
    +0049 %
    +0050 % See also: NUCLEUSinv
    +0051 % Author: see AUTHORS.md
    +0052 % email: see AUTHORS.md
    +0053 % License: MIT License (at end)
    +0054 
    +0055 %------------- BEGIN CODE --------------
    +0056 
    +0057 %% get GUI handle and data
    +0058 figh_nucleus = ancestor(src,'figure','toplevel');
    +0059 nucleus.data = getappdata(figh_nucleus,'data');
    +0060 nucleus.gui = getappdata(figh_nucleus,'gui');
    +0061 myui = nucleus.gui.myui;
    +0062 colors = myui.colors;
    +0063 
    +0064 %% get GUI data from NUCLEUS
    +0065 data = nucleus.data.inv2D;
    +0066 
    +0067 % check if the figure is already open
    +0068 fig_T1T2map = findobj('Tag','2DINV');
    +0069 % if not, create it
    +0070 if isempty(fig_T1T2map)
    +0071     % draw the figure on top of NUCLEUSinv
    +0072     fig_T1T2map = figure('Name','NUCLEUSinv - 2D Inversion',...
    +0073         'NumberTitle','off','Resize','on','ToolBar','none',...
    +0074         'Tag','2DINV','CloseRequestFcn',@tv_closeme,...
    +0075         'MenuBar','none');
    +0076     pos0 = get(figh_nucleus,'Position');
    +0077     cent(1) = (pos0(1)+pos0(3)/2);
    +0078     cent(2) = (pos0(2)+pos0(4)/2);
    +0079     posf = [cent(1)-pos0(3)/2.5 pos0(2)+22 pos0(3)/1.25 pos0(4)-22];
    +0080     % posf = pos0;
    +0081     set(fig_T1T2map,'Position',posf);
    +0082 
    +0083     gui.menu.view = uimenu(fig_T1T2map,'Label','View');
    +0084     gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',...
    +0085         'Callback',@onMenuView);
    +0086 
    +0087     cpanel_w = 175;
    +0088 
    +0089     % create the main layout
    +0090     gui.main = uix.HBox('Parent',fig_T1T2map,'BackGroundColor',colors.panelBG,...
    +0091         'Spacing',5,'Padding',5,'Visible','off');
    +0092     gui.left = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,...
    +0093         'Spacing',5,'Padding',0); % controls
    +0094     gui.right = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,...
    +0095         'Spacing',5,'Padding',0); % plots
    +0096 
    +0097     set(gui.main,'Widths',[350 -1 ]);
    +0098 
    +0099     % waitbar indicating the loading of the GUI
    +0100     steps = 4;
    +0101     hwb = waitbar(0,'loading ...','Name','T1T2 2DInv GUI initialization','Visible','off');
    +0102     set(hwb,'Units','Pixel')
    +0103     posw = get(hwb,'Position');
    +0104     set(hwb,'Position',[posf(1)+posf(3)/2-posw(3)/2 posf(2)+posf(4)/2-posw(4)/2 posw(3:4)]);
    +0105     set(hwb,'Visible','on');
    +0106 
    +0107     % --- properties panel ---
    +0108     waitbar(1/steps,hwb,'loading GUI elements - properties');
    +0109     gui.panels.prop.main = uix.BoxPanel('Parent',gui.left,...
    +0110         'Title','Properties','MinimizeFcn',@minimizePanel,...
    +0111         'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle);
    +0112     gui.panels.prop.VBox = uix.VBox('Parent',gui.panels.prop.main,...
    +0113         'Spacing',3,'Padding',3);
    +0114 
    +0115     % D coeff.
    +0116     gui.panels.prop.HBox1 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0117         'Spacing',3);
    +0118     gui.text_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,...
    +0119         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0120         'String',['Diffusion coeff. [10',char(hex2dec('207B')),...
    +0121         char(hex2dec('2079')),' m',char(hex2dec('00B2')),'/s]']);
    +0122     uix.Empty('Parent',gui.panels.prop.HBox1);
    +0123     tstr = 'Set diffusion coefficient.';
    +0124     gui.edit_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,...
    +0125         'Style','edit','String',sprintf('%4.3f',data.prop.D*1e9),...
    +0126         'FontSize',myui.fontsize,'Tag','diff',...
    +0127         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0128         'Callback',@tv_onEditValue);
    +0129     set(gui.panels.prop.HBox1,'Widths',[cpanel_w -1 -1]);
    +0130 
    +0131     % Gradient
    +0132     gui.panels.prop.HBox2 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0133         'Spacing',3);
    +0134     gui.text_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,...
    +0135         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0136         'String',"Gradient [T/m]");
    +0137     uix.Empty('Parent',gui.panels.prop.HBox2);
    +0138     tstr = 'Set device gradient.';
    +0139     gui.edit_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,...
    +0140         'Style','edit','String',sprintf('%d',data.prop.G0),...
    +0141         'FontSize',myui.fontsize,'Tag','gradient',...
    +0142         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0143         'Callback',@tv_onEditValue);
    +0144     set(gui.panels.prop.HBox2,'Widths',[cpanel_w -1 -1]);
    +0145 
    +0146     % echo time
    +0147     gui.panels.prop.HBox3 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0148         'Spacing',3);
    +0149     gui.text_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,...
    +0150         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0151         'String',"Echo time tE [µs]");
    +0152     uix.Empty('Parent',gui.panels.prop.HBox3);
    +0153     tstr = 'Set echo time tE.';
    +0154     gui.edit_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,...
    +0155         'Style','edit','String',sprintf('%d',data.prop.te*1e6),...
    +0156         'FontSize',myui.fontsize,'Tag','echo_time',...
    +0157         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0158         'Enable','off',...
    +0159         'Callback',@tv_onEditValue);
    +0160     set(gui.panels.prop.HBox3,'Widths',[cpanel_w -1 -1]);
    +0161 
    +0162     % first and last echo
    +0163     gui.panels.prop.HBox4 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0164         'Spacing',3);
    +0165     gui.text_handles.first = uicontrol('Parent',gui.panels.prop.HBox4,...
    +0166         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0167         'String',"T2 echoes - first | last");
    +0168     tstr = 'Set first / last echo of all T2 signals.';
    +0169     gui.edit_handles.first = uicontrol('Parent',gui.panels.prop.HBox4,...
    +0170         'Style','edit','String',sprintf('%d',data.prop.first),...
    +0171         'FontSize',myui.fontsize,'Tag','first',...
    +0172         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0173         'Callback',@tv_onEditValue);
    +0174     gui.edit_handles.last = uicontrol('Parent',gui.panels.prop.HBox4,...
    +0175         'Style','edit','String',sprintf('%d',data.prop.last),...
    +0176         'FontSize',myui.fontsize,'Tag','last',...
    +0177         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0178         'Callback',@tv_onEditValue);
    +0179     set(gui.panels.prop.HBox4,'Widths',[cpanel_w -1 -1]);
    +0180 
    +0181     % --- inversion panel ---
    +0182     waitbar(2/steps,hwb,'loading GUI elements - 2D inversion');
    +0183     gui.panels.inv.main = uix.BoxPanel('Parent',gui.left,...
    +0184         'Title','2D inversion settings','MinimizeFcn',@minimizePanel,...
    +0185         'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle);
    +0186     gui.panels.inv.VBox = uix.VBox('Parent',gui.panels.inv.main,...
    +0187         'Spacing',3,'Padding',3);
    +0188 
    +0189     % T1type
    +0190     gui.panels.inv.HBox0 = uix.HBox('Parent',gui.panels.inv.VBox,...
    +0191         'Spacing',3);
    +0192     gui.text_handles.T1type = uicontrol('Parent',gui.panels.inv.HBox0,...
    +0193         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0194         'String','T1 type (SR / IR)');
    +0195     tstr = 'Choose between Saturation and Inversion Recovery.';
    +0196     gui.popup_handles.T1type = uicontrol('Parent',gui.panels.inv.HBox0,...
    +0197         'Style','popup','String',{'Saturation Recovery','Inversion Recovery'},...
    +0198         'Value',data.inv.T1IRfac,'FontSize',myui.fontsize,...
    +0199         'UserData',struct('Tooltipstr',tstr),'Callback',@tv_onPopupT1Type);
    +0200     set(gui.panels.inv.HBox0,'Widths',[cpanel_w -1]);
    +0201 
    +0202     % IR kernel type
    +0203     gui.panels.inv.HBox01 = uix.HBox('Parent',gui.panels.inv.VBox,...
    +0204         'Spacing',3);
    +0205     gui.text_handles.IRtype = uicontrol('Parent',gui.panels.inv.HBox01,...
    +0206         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0207         'String','IR kernel type');
    +0208     tstr = 'Choose IR kernel type.';
    +0209     gui.popup_handles.IRtype = uicontrol('Parent',gui.panels.inv.HBox01,...
    +0210         'Style','popup','String',{'1-2exp(-t/T1)','-exp(-t/T1)'},...
    +0211         'Value',1,'FontSize',myui.fontsize,...
    +0212         'UserData',struct('Tooltipstr',tstr),'Callback',@tv_onPopupIRType);
    +0213     set(gui.panels.inv.HBox01,'Widths',[cpanel_w -1]);
    +0214 
    +0215     % RTD T1
    +0216     gui.panels.inv.HBox1 = uix.HBox('Parent',gui.panels.inv.VBox,...
    +0217         'Spacing',3);
    +0218     gui.text_handles.rtdT1 = uicontrol('Parent',gui.panels.inv.HBox1,...
    +0219         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0220         'String','RTD T1 -  min [s] | max [s] | #');
    +0221     tstr = "";
    +0222     gui.edit_handles.rtdT1min = uicontrol('Parent',gui.panels.inv.HBox1,...
    +0223         'Style','edit','String',sprintf('%5.4f',data.inv.T1min),...
    +0224         'FontSize',myui.fontsize,'Tag','rtdT1min',...
    +0225         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0226         'Callback',@tv_onEditValue);
    +0227     tstr = "";
    +0228     gui.edit_handles.rtdT1max = uicontrol('Parent',gui.panels.inv.HBox1,...
    +0229         'Style','edit','String',sprintf('%d',data.inv.T1max),...
    +0230         'FontSize',myui.fontsize,'Tag','rtdT1max',...
    +0231         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0232         'Callback',@tv_onEditValue);
    +0233     tstr = "";
    +0234     gui.edit_handles.rtdT1N = uicontrol('Parent',gui.panels.inv.HBox1,...
    +0235         'Style','edit','String',sprintf('%d',data.inv.T1N),...
    +0236         'FontSize',myui.fontsize,'Tag','rtdT1N',...
    +0237         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0238         'Callback',@tv_onEditValue);
    +0239     set(gui.panels.inv.HBox1,'Widths',[cpanel_w -1 -1 -1]);
    +0240 
    +0241     % RTD T2
    +0242     gui.panels.inv.HBox2 = uix.HBox('Parent',gui.panels.inv.VBox,...
    +0243         'Spacing',3);
    +0244     gui.text_handles.rtdT2 = uicontrol('Parent',gui.panels.inv.HBox2,...
    +0245         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0246         'String','RTD T2 - min [s] | max [s] | #');
    +0247     tstr = "";
    +0248     gui.edit_handles.rtdT2min = uicontrol('Parent',gui.panels.inv.HBox2,...
    +0249         'Style','edit','String',sprintf('%5.4f',data.inv.T2min),...
    +0250         'FontSize',myui.fontsize,'Tag','rtdT2min',...
    +0251         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0252         'Callback',@tv_onEditValue);
    +0253     tstr = "";
    +0254     gui.edit_handles.rtdT2max = uicontrol('Parent',gui.panels.inv.HBox2,...
    +0255         'Style','edit','String',sprintf('%d',data.inv.T2max),...
    +0256         'FontSize',myui.fontsize,'Tag','rtdT2max',...
    +0257         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0258         'Callback',@tv_onEditValue);
    +0259     tstr = "";
    +0260     gui.edit_handles.rtdT2N = uicontrol('Parent',gui.panels.inv.HBox2,...
    +0261         'Style','edit','String',sprintf('%d',data.inv.T2N),...
    +0262         'FontSize',myui.fontsize,'Tag','rtdT2N',...
    +0263         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0264         'Callback',@tv_onEditValue);
    +0265     set(gui.panels.inv.HBox2,'Widths',[cpanel_w -1 -1 -1]);
    +0266 
    +0267     % T1 lambda / order
    +0268     gui.panels.inv.HBox3 = uix.HBox('Parent',gui.panels.inv.VBox,...
    +0269         'Spacing',3);
    +0270     gui.text_handles.lambdaT1 = uicontrol('Parent',gui.panels.inv.HBox3,...
    +0271         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0272         'String','T1 - lambda | L-order');
    +0273     tstr = "";
    +0274     gui.edit_handles.lambdaT1 = uicontrol('Parent',gui.panels.inv.HBox3,...
    +0275         'Style','edit','String',sprintf('%d',data.inv.T1lambda),...
    +0276         'FontSize',myui.fontsize,'Tag','lambdaT1',...
    +0277         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0278         'Callback',@tv_onEditValue);
    +0279     tstr = "";
    +0280     gui.edit_handles.orderT1 = uicontrol('Parent',gui.panels.inv.HBox3,...
    +0281         'Style','edit','String',sprintf('%d',data.inv.T1order),...
    +0282         'FontSize',myui.fontsize,'Tag','orderT1',...
    +0283         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0284         'Callback',@tv_onEditValue);
    +0285     set(gui.panels.inv.HBox3,'Widths',[cpanel_w -1 -1]);
    +0286 
    +0287     % T2 lambda / order
    +0288     gui.panels.inv.HBox4 = uix.HBox('Parent',gui.panels.inv.VBox,...
    +0289         'Spacing',3);
    +0290     gui.text_handles.lambdaT2 = uicontrol('Parent',gui.panels.inv.HBox4,...
    +0291         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0292         'String','T2 - lambda | L-order');
    +0293     tstr = "";
    +0294     gui.edit_handles.lambdaT2 = uicontrol('Parent',gui.panels.inv.HBox4,...
    +0295         'Style','edit','String',sprintf('%d',data.inv.T2lambda),...
    +0296         'FontSize',myui.fontsize,'Tag','lambdaT2',...
    +0297         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0298         'Callback',@tv_onEditValue);
    +0299     tstr = "";
    +0300     gui.edit_handles.orderT2 = uicontrol('Parent',gui.panels.inv.HBox4,...
    +0301         'Style','edit','String',sprintf('%d',data.inv.T2order),...
    +0302         'FontSize',myui.fontsize,'Tag','orderT2',...
    +0303         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0304         'Enable','off','Callback',@tv_onEditValue);
    +0305     set(gui.panels.inv.HBox4,'Widths',[cpanel_w -1 -1]);
    +0306 
    +0307     % RUN button
    +0308     gui.panels.inv.HBox5 = uix.HBox('Parent',gui.panels.inv.VBox,...
    +0309         'Spacing',3);
    +0310     uix.Empty('Parent',gui.panels.inv.HBox5);
    +0311     tstr = 'RUN 2D inversion.';
    +0312     gui.push_handles.run_inv = uicontrol('Parent',gui.panels.inv.HBox5,...
    +0313         'String','RUN 2D INV','FontSize',myui.fontsize,'Tag','rtd',...
    +0314         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0315         'BackGroundColor','g','Callback',@tv_onPushRun);
    +0316     set(gui.panels.inv.HBox5,'Widths',[cpanel_w -1]);
    +0317 
    +0318     % --- information panel ---
    +0319     waitbar(3/steps,hwb,'loading GUI elements - information panel');
    +0320     gui.panels.info.main = uix.BoxPanel('Parent',gui.left,...
    +0321         'Title','Information','MinimizeFcn',@minimizePanel,...
    +0322         'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle);
    +0323     gui.panels.info.VBox = uix.VBox('Parent',gui.panels.info.main,...
    +0324         'Spacing',3,'Padding',3);
    +0325 
    +0326     % T1 range
    +0327     gui.panels.info.HBox1 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0328         'Spacing',3);
    +0329     gui.text_handles.rangeT1 = uicontrol('Parent',gui.panels.info.HBox1,...
    +0330         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0331         'String','T1 range - min [s] | max [s]');
    +0332     tstr = "";
    +0333     gui.edit_handles.T1min = uicontrol('Parent',gui.panels.info.HBox1,...
    +0334         'Style','edit','String',sprintf('%5.4f',data.info.T1min),...
    +0335         'FontSize',myui.fontsize,'Tag','T1min',...
    +0336         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0337         'Callback',@tv_onEditValue);
    +0338     tstr = "";
    +0339     gui.edit_handles.T1max = uicontrol('Parent',gui.panels.info.HBox1,...
    +0340         'Style','edit','String',sprintf('%d',data.info.T1max),...
    +0341         'FontSize',myui.fontsize,'Tag','T1max',...
    +0342         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0343         'Callback',@tv_onEditValue);
    +0344     set(gui.panels.info.HBox1,'Widths',[cpanel_w -1 -1]);
    +0345 
    +0346     % T2 range
    +0347     gui.panels.info.HBox2 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0348         'Spacing',3);
    +0349     gui.text_handles.rangeT2 = uicontrol('Parent',gui.panels.info.HBox2,...
    +0350         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0351         'String','T2 range - min [s] | max [s]');
    +0352     tstr = "";
    +0353     gui.edit_handles.T2min = uicontrol('Parent',gui.panels.info.HBox2,...
    +0354         'Style','edit','String',sprintf('%5.4f',data.info.T2min),...
    +0355         'FontSize',myui.fontsize,'Tag','T2min',...
    +0356         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0357         'Callback',@tv_onEditValue);
    +0358     tstr = "";
    +0359     gui.edit_handles.T2max = uicontrol('Parent',gui.panels.info.HBox2,...
    +0360         'Style','edit','String',sprintf('%d',data.info.T2max),...
    +0361         'FontSize',myui.fontsize,'Tag','T2max',...
    +0362         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0363         'Callback',@tv_onEditValue);
    +0364     set(gui.panels.info.HBox2,'Widths',[cpanel_w -1 -1]);
    +0365 
    +0366     % E0
    +0367     gui.panels.info.HBox0 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0368         'Spacing',3);
    +0369     gui.text_handles.E0 = uicontrol('Parent',gui.panels.info.HBox0,...
    +0370         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0371         'String','E0 [-]');
    +0372     uix.Empty('Parent',gui.panels.info.HBox0);
    +0373     tstr = "";
    +0374     gui.edit_handles.E0 = uicontrol('Parent',gui.panels.info.HBox0,...
    +0375         'Style','edit','String',sprintf('%4.3f',data.info.E0),...
    +0376         'FontSize',myui.fontsize,'Tag','E0',...
    +0377         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0378         'Enable','off');
    +0379     set(gui.panels.info.HBox0,'Widths',[cpanel_w -1 -1]);
    +0380 
    +0381     % TLGM
    +0382     gui.panels.info.HBox3 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0383         'Spacing',3);
    +0384     gui.text_handles.Tlgm = uicontrol('Parent',gui.panels.info.HBox3,...
    +0385         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0386         'String','TLGM [s] (T1,T2)');
    +0387     tstr = "";
    +0388     gui.edit_handles.T1tlgm = uicontrol('Parent',gui.panels.info.HBox3,...
    +0389         'Style','edit','String',sprintf('%4.3f',data.info.T1tlgm),...
    +0390         'FontSize',myui.fontsize,'Tag','T1tlgm',...
    +0391         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0392         'Enable','off');
    +0393     tstr = "";
    +0394     gui.edit_handles.T2tlgm = uicontrol('Parent',gui.panels.info.HBox3,...
    +0395         'Style','edit','String',sprintf('%4.3f',data.info.T2tlgm),...
    +0396         'FontSize',myui.fontsize,'Tag','T2tlgm',...
    +0397         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0398         'Enable','off');
    +0399     set(gui.panels.info.HBox3,'Widths',[cpanel_w -1 -1]);
    +0400 
    +0401     % TLGM ratio
    +0402     gui.panels.info.HBox4 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0403         'Spacing',3);
    +0404     gui.text_handles.Tlgm_ratio = uicontrol('Parent',gui.panels.info.HBox4,...
    +0405         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0406         'String','TLGM ratio T1/T2');
    +0407     uix.Empty('Parent',gui.panels.info.HBox4);
    +0408     tstr = "";
    +0409     gui.edit_handles.Tlgm_ratio = uicontrol('Parent',gui.panels.info.HBox4,...
    +0410         'Style','edit','String',sprintf('%4.3f',data.info.T1tlgm/data.info.T2tlgm),...
    +0411         'FontSize',myui.fontsize,'Tag','Tlgm_ratio',...
    +0412         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0413         'Enable','off');
    +0414     set(gui.panels.info.HBox4,'Widths',[cpanel_w -1 -1]);
    +0415 
    +0416     % Tmax
    +0417     gui.panels.info.HBox5 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0418         'Spacing',3);
    +0419     gui.text_handles.Tmax = uicontrol('Parent',gui.panels.info.HBox5,...
    +0420         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0421         'String','TMAX [s] (T1,T2)');
    +0422     tstr = "";
    +0423     gui.edit_handles.T1tmax = uicontrol('Parent',gui.panels.info.HBox5,...
    +0424         'Style','edit','String',sprintf('%4.3f',data.info.T1tmax),...
    +0425         'FontSize',myui.fontsize,'Tag','T1tmax',...
    +0426         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0427         'Enable','off');
    +0428     tstr = "";
    +0429     gui.edit_handles.T2tmax = uicontrol('Parent',gui.panels.info.HBox5,...
    +0430         'Style','edit','String',sprintf('%4.3f',data.info.T2tmax),...
    +0431         'FontSize',myui.fontsize,'Tag','T2tmax',...
    +0432         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0433         'Enable','off');
    +0434     set(gui.panels.info.HBox5,'Widths',[cpanel_w -1 -1]);
    +0435 
    +0436     % Tmax ratio
    +0437     gui.panels.info.HBox6 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0438         'Spacing',3);
    +0439     gui.text_handles.Tmax_ratio = uicontrol('Parent',gui.panels.info.HBox6,...
    +0440         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0441         'String','TMAX ratio T1/T2');
    +0442     uix.Empty('Parent',gui.panels.info.HBox6);
    +0443     tstr = "";
    +0444     gui.edit_handles.Tmax_ratio = uicontrol('Parent',gui.panels.info.HBox6,...
    +0445         'Style','edit','String',sprintf('%4.3f',data.info.T1tmax/data.info.T2tmax),...
    +0446         'FontSize',myui.fontsize,'Tag','Tmax_ratio',...
    +0447         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0448         'Enable','off');
    +0449     set(gui.panels.info.HBox6,'Widths',[cpanel_w -1 -1]);
    +0450 
    +0451     % log/lin axes
    +0452     gui.panels.info.HBox7 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0453         'Spacing',3);
    +0454     gui.text_handles.loglin_axes = uicontrol('Parent',gui.panels.info.HBox7,...
    +0455         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0456         'String','Echo time axes');
    +0457     tstr = "";
    +0458     gui.radio_handles.log = uicontrol('Parent',gui.panels.info.HBox7,...
    +0459         'Style','radiobutton','String','log','FontSize',myui.fontsize,'Tag','log',...
    +0460         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0461         'Enable','on','Value',1,'Callback',@tv_onRadioLogLin);
    +0462     gui.radio_handles.lin = uicontrol('Parent',gui.panels.info.HBox7,...
    +0463         'Style','radiobutton','String','lin','FontSize',myui.fontsize,'Tag','lin',...
    +0464         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0465         'Enable','on','Value',0,'Callback',@tv_onRadioLogLin);
    +0466     set(gui.panels.info.HBox7,'Widths',[cpanel_w -1 -1]);
    +0467 
    +0468     % DCM for 2D plot
    +0469     gui.panels.info.HBox8 = uix.HBox('Parent',gui.panels.info.VBox,...
    +0470         'Spacing',3);
    +0471     gui.text_handles.dcm = uicontrol('Parent',gui.panels.info.HBox8,...
    +0472         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0473         'String','2D model data inspection');
    +0474     tstr = "";
    +0475     gui.check_handles.dcm = uicontrol('Parent',gui.panels.info.HBox8,...
    +0476         'Style','checkbox','String','activate','FontSize',myui.fontsize,'Tag','dcm',...
    +0477         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0478         'Enable','off','Callback',@tv_onCheckDCM);
    +0479     set(gui.panels.info.HBox8,'Widths',[cpanel_w -1]);
    +0480 
    +0481     % --- update MAIN GUI button ---
    +0482     gui.panels.save.HBox1 = uix.VBox('Parent',gui.left,...
    +0483         'Spacing',3);   
    +0484     tstr = 'UPDATE 2D inversion data in main NUCLEUSinv GUI.';
    +0485     gui.push_handles.update = uicontrol('Parent',gui.panels.save.HBox1,...
    +0486         'String','UPDATE MAIN GUI','FontSize',myui.fontsize,'Tag','update',...
    +0487         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0488         'Callback',@tv_onPushUpdate);
    +0489     tstr = 'SAVE 2D inversion data to external file.';
    +0490     gui.push_handles.save = uicontrol('Parent',gui.panels.save.HBox1,...
    +0491         'String','SAVE RESULT','FontSize',myui.fontsize,'Tag','save',...
    +0492         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0493         'Callback',@tv_onPushSave);
    +0494     tstr = 'Export current graphics view to Figure.';
    +0495     gui.push_handles.view = uicontrol('Parent',gui.panels.save.HBox1,...
    +0496         'String','VIEW2FIG','FontSize',myui.fontsize,'Tag','view',...
    +0497         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0498         'Callback',@tv_onPushView);
    +0499     % set(gui.panels.save.HBox1,'Widths',[-1 -1]);
    +0500 
    +0501     % fix text vertical alignment
    +0502     jh = findjobj(gui.text_handles.rtdT1);
    +0503     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0504     jh = findjobj(gui.text_handles.rangeT1);
    +0505     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0506     jh = findjobj(gui.text_handles.rtdT2);
    +0507     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0508     jh = findjobj(gui.text_handles.rangeT2);
    +0509     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0510     jh = findjobj(gui.text_handles.diff);
    +0511     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0512     jh = findjobj(gui.text_handles.gradient);
    +0513     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0514     jh = findjobj(gui.text_handles.echo_time);
    +0515     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0516     jh = findjobj(gui.text_handles.first);
    +0517     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0518     jh = findjobj(gui.text_handles.T1type);
    +0519     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0520     jh = findjobj(gui.text_handles.IRtype);
    +0521     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0522     jh = findjobj(gui.text_handles.lambdaT1);
    +0523     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0524     jh = findjobj(gui.text_handles.lambdaT2);
    +0525     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0526     jh = findjobj(gui.text_handles.E0);
    +0527     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0528     jh = findjobj(gui.text_handles.Tlgm);
    +0529     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0530     jh = findjobj(gui.text_handles.Tlgm_ratio);
    +0531     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0532     jh = findjobj(gui.text_handles.Tmax);
    +0533     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0534     jh = findjobj(gui.text_handles.Tmax_ratio);
    +0535     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0536     jh = findjobj(gui.text_handles.loglin_axes);
    +0537     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0538     jh = findjobj(gui.text_handles.dcm);
    +0539     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0540 
    +0541     % empty space at bottom of left side
    +0542     uix.Empty('Parent',gui.left);
    +0543     % adjust the heights of all left-column-panels
    +0544     heights = [22 22 22 28 -1; 22+4*24+6*3 22+7*24+9*4 22+9*24+11*3 28*3 -1];
    +0545     % panel header is always 22 high
    +0546     set(gui.left,'Heights',heights(2,:),...
    +0547         'MinimumHeights',[22 22 22 28 0]);
    +0548 
    +0549     % --- plot boxes ---
    +0550     waitbar(4/steps,hwb,'loading GUI elements - graphics');
    +0551     gui.rightPanel = uix.TabPanel('Parent',gui.right,...
    +0552         'BackGroundColor',colors.panelBG);
    +0553     % -- tab1
    +0554     gui.tab1 = uix.GridFlex('Parent',gui.rightPanel,...
    +0555         'BackGroundColor',colors.panelBG,'Spacing',5);
    +0556 
    +0557     gui.pbox11 = uicontainer('Parent',gui.tab1,...
    +0558         'BackGroundColor',colors.panelBG);
    +0559     gui.pbox13 = uicontainer('Parent',gui.tab1,...
    +0560         'BackGroundColor',colors.panelBG);
    +0561 
    +0562     gui.pbox12 = uicontainer('Parent',gui.tab1,...
    +0563         'BackGroundColor',colors.panelBG);
    +0564     gui.pbox14 = uicontainer('Parent',gui.tab1,...
    +0565         'BackGroundColor',colors.panelBG);
    +0566 
    +0567     set(gui.tab1,'Widths',[-1 -1],'Heights',[-1 -1]);
    +0568 
    +0569     % -- tab2
    +0570     gui.tab2 = uix.GridFlex('Parent',gui.rightPanel,...
    +0571         'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5);
    +0572 
    +0573     gui.pbox21 = uicontainer('Parent',gui.tab2,...
    +0574         'BackGroundColor',colors.panelBG);
    +0575     gui.pbox22 = uicontainer('Parent',gui.tab2,...
    +0576         'BackGroundColor',colors.panelBG);
    +0577 
    +0578     gui.pbox23 = uicontainer('Parent',gui.tab2,...
    +0579         'BackGroundColor',colors.panelBG);
    +0580     gui.pbox24 = uicontainer('Parent',gui.tab2,...
    +0581         'BackGroundColor',colors.panelBG);
    +0582 
    +0583     set(gui.tab2,'Widths',[-6 -1],'Heights',[-1 -6]);
    +0584 
    +0585     % -- tab3
    +0586     gui.tab3 = uix.VBoxFlex('Parent',gui.rightPanel,...
    +0587         'BackGroundColor',colors.panelBG,'Spacing',5);
    +0588     gui.pbox31 = uicontainer('Parent',gui.tab3,...
    +0589         'BackGroundColor',colors.panelBG);
    +0590     gui.pbox32 = uicontainer('Parent',gui.tab3,...
    +0591         'BackGroundColor',colors.panelBG);
    +0592     set(gui.tab3,'Heights',[-1 -2]);
    +0593 
    +0594     gui.rightPanel.TabTitles = {'DATA','2D INV','FITS'};
    +0595     gui.rightPanel.TabWidth = 75;
    +0596     gui.rightPanel.TabEnables = {'on','on','on'};
    +0597 
    +0598     % -- plot axes --
    +0599     gui.axes11 = axes('Parent',gui.pbox11,'Box','on');
    +0600     gui.axes12 = axes('Parent',gui.pbox12,'Box','on');
    +0601     gui.axes13 = axes('Parent',gui.pbox13,'Box','on');
    +0602     gui.axes14 = axes('Parent',gui.pbox14,'Box','on');
    +0603     gui.axes2 = axes('Parent',gui.pbox22,'Box','on','Tag','2D');
    +0604     gui.axes21 = axes('Parent',gui.pbox21,'Box','on');
    +0605     gui.axes24 = axes('Parent',gui.pbox24,'Box','on');
    +0606     gui.axes31 = axes('Parent',gui.pbox31,'Box','on');
    +0607     gui.axes32 = axes('Parent',gui.pbox32,'Box','on');
    +0608 
    +0609     % create data curor mode for 2D inv plot inspection
    +0610     gui.dcm = datacursormode(fig_T1T2map);
    +0611     gui.dcm.UpdateFcn = @(hObj,event,ax)localDcmFcn(hObj,event,gui.axes2);
    +0612     gui.dcm.Enable = 'off';
    +0613 
    +0614     % --- store main GUI settings ---
    +0615     gui.myui = nucleus.gui.myui;
    +0616     gui.myui.heights = heights;
    +0617     gui.figh_nucleus = figh_nucleus;
    +0618 
    +0619     % --- save gui data to GUI ---
    +0620     setappdata(fig_T1T2map,'gui',gui);
    +0621     setappdata(fig_T1T2map,'data',data);
    +0622 
    +0623     % minimize upper panel at startup
    +0624     tmp_h = gui.myui.heights(2,:);
    +0625     tmp_h(1) = gui.myui.heights(1,1);
    +0626     set(gui.left,'Heights',tmp_h);
    +0627     set(gui.panels.prop.main,'Minimized',true);
    +0628 
    +0629     % make GUI visible
    +0630     delete(hwb);
    +0631     set(gui.main,'Visible','on');
    +0632 else
    +0633     % if the figure is already open load the GUI data
    +0634     data = getappdata(fig_T1T2map,'data');
    +0635     gui = getappdata(fig_T1T2map,'gui');
    +0636 end
    +0637 
    +0638 % import the current data from the main NUCLEUS GUI
    +0639 data.results.T1T2map = nucleus.data.import.T1T2map;
    +0640 data.results.T1T2map.import = nucleus.data.import.NMR.data;
    +0641 
    +0642 % check if there is already 2D inversion data in the main NUCLEUS GUI
    +0643 if isfield(nucleus.data,'results') && isfield(nucleus.data.results,'inv2D')
    +0644     % if it is there, then load the INVdata
    +0645     nucleus.INVdata = getappdata(figh_nucleus,'INVdata');    
    +0646     % the 2D data is stored within the data struct of the merged T1 curve
    +0647     data.results.inv2D = nucleus.INVdata{end}.results.inv2D;
    +0648     % update new 2Dinv GUI data
    +0649     setappdata(fig_T1T2map,'data',data);
    +0650     % clear axes
    +0651     clearAllAxes(fig_T1T2map);
    +0652     % prepare raw data
    +0653     tv_prepareRawData(fig_T1T2map);
    +0654     % plot the imported raw data
    +0655     tv_plotRawData(fig_T1T2map);
    +0656     tv_plotResults(fig_T1T2map);
    +0657 else
    +0658     % set the last echo entry
    +0659     data.prop.last = data.results.T1T2map.t2N;
    +0660     set(gui.edit_handles.last,'String',num2str(data.prop.last));
    +0661     % update new 2Dinv GUI data
    +0662     setappdata(fig_T1T2map,'data',data);
    +0663     % clear axes
    +0664     clearAllAxes(fig_T1T2map);
    +0665     % prepare raw data
    +0666     tv_prepareRawData(fig_T1T2map);
    +0667     % plot the imported raw data
    +0668     tv_plotRawData(fig_T1T2map);
    +0669 end
    +0670 
    +0671 tv_estimateIRtype(fig_T1T2map);
    +0672 beautifyAxes(fig_T1T2map);
    +0673 end
    +0674 
    +0675 %% subfunction to update the edit fields
    +0676 function tv_onEditValue(src,~)
    +0677 figh = ancestor(src,'figure','toplevel');
    +0678 gui = getappdata(figh,'gui');
    +0679 data = getappdata(figh,'data');
    +0680 
    +0681 % get the edit field value
    +0682 val = str2double(get(src,'String'));
    +0683 
    +0684 switch get(src,'Tag')
    +0685     case {'diff','gradient','echo_time'}
    +0686         data.prop.D = str2double(get(gui.edit_handles.diff,'String'))/1e9;
    +0687         data.prop.G0 = str2double(get(gui.edit_handles.gradient,'String'));
    +0688         data.prop.te = str2double(get(gui.edit_handles.echo_time,'String'))/1e6;
    +0689     case {'first','last'}
    +0690         data.prop.first = str2double(get(gui.edit_handles.first,'String'));
    +0691         data.prop.last = str2double(get(gui.edit_handles.last,'String'));
    +0692         % update GUI data
    +0693         setappdata(figh,'data',data);
    +0694         clearAllAxes(figh);
    +0695         tv_prepareRawData(figh);
    +0696         data = getappdata(figh,'data');
    +0697         tv_plotRawData(figh);
    +0698         beautifyAxes(figh);
    +0699     case {'rtdT1min','rtdT1max','rtdT1N'}
    +0700         data.inv.T1min = str2double(get(gui.edit_handles.rtdT1min,'String'));
    +0701         data.inv.T1max = str2double(get(gui.edit_handles.rtdT1max,'String'));
    +0702         data.inv.T1N = str2double(get(gui.edit_handles.rtdT1N,'String'));
    +0703     case {'rtdT2min','rtdT2max','rtdT2N'}
    +0704         data.inv.T2min = str2double(get(gui.edit_handles.rtdT2min,'String'));
    +0705         data.inv.T2max = str2double(get(gui.edit_handles.rtdT2max,'String'));
    +0706         data.inv.T2N = str2double(get(gui.edit_handles.rtdT2N,'String'));
    +0707     case 'lambdaT1'
    +0708         data.inv.T1lambda = str2double(get(src,'String'));
    +0709     case 'orderT1'
    +0710         set(gui.edit_handles.orderT2,'String',num2str(val));
    +0711         data.inv.T1order = str2double(get(src,'String'));
    +0712         data.inv.T2order = str2double(get(gui.edit_handles.orderT2,'String'));
    +0713     case 'lambdaT2'
    +0714         data.inv.T2lambda = str2double(get(src,'String'));
    +0715     case 'orderT2'
    +0716         data.inv.T2order = str2double(get(src,'String'));
    +0717     case {'T1min','T1max','T2min','T2max'}
    +0718         data.info.T1min = str2double(get(gui.edit_handles.T1min,'String'));
    +0719         data.info.T1max = str2double(get(gui.edit_handles.T1max,'String'));
    +0720         data.info.T2min = str2double(get(gui.edit_handles.T2min,'String'));
    +0721         data.info.T2max = str2double(get(gui.edit_handles.T2max,'String'));
    +0722         % update GUI data
    +0723         setappdata(figh,'data',data);
    +0724         tv_getTLGM(figh);
    +0725         data = getappdata(figh,'data');
    +0726         tv_plotResults(figh);
    +0727         beautifyAxes(figh);
    +0728 end
    +0729 
    +0730 % update GUI data
    +0731 setappdata(figh,'data',data);
    +0732 % in case an error occurred, reset the RUN button
    +0733 set(gui.push_handles.run_inv,'String','RUN 2D INV',...
    +0734     'BackgroundColor','g','Enable','on','Callback',@tv_onPushRun);
    +0735 setappdata(figh,'gui',gui);
    +0736 end
    +0737 
    +0738 %% subfunction to set the T1 type
    +0739 function tv_onPopupT1Type(src,~)
    +0740 figh = ancestor(src,'figure','toplevel');
    +0741 data = getappdata(figh,'data');
    +0742 gui = getappdata(figh,'gui');
    +0743 
    +0744 switch get(src,'Value')
    +0745     case 1 % Saturation Recovery
    +0746         data.inv.T1IRfac = 1;
    +0747         set(gui.popup_handles.IRtype,'Enable','off');
    +0748     case 2 % Inversion Recovery
    +0749         data.inv.T1IRfac = 2;
    +0750         set(gui.popup_handles.IRtype,'Enable','on');
    +0751 end
    +0752 
    +0753 % update GUI data
    +0754 setappdata(figh,'data',data);
    +0755 setappdata(figh,'gui',gui);
    +0756 end
    +0757 
    +0758 %% subfunction to set the IR type
    +0759 function tv_onPopupIRType(src,~)
    +0760 figh = ancestor(src,'figure','toplevel');
    +0761 data = getappdata(figh,'data');
    +0762 
    +0763 switch get(src,'Value')
    +0764     case 1 % IR standard 1-2exp()
    +0765         data.inv.IRtype = 1;
    +0766     case 2 % IR Hürlimann -exp()
    +0767         data.inv.IRtype = 2;
    +0768 end
    +0769 
    +0770 % update GUI data
    +0771 setappdata(figh,'data',data);
    +0772 end
    +0773 
    +0774 %% subfunction to start a new uncertainty calculation
    +0775 function tv_onPushRun(src,~)
    +0776 figh = ancestor(src,'figure','toplevel');
    +0777 gui = getappdata(figh,'gui');
    +0778 data = getappdata(figh,'data');
    +0779 % NUCLEUSinv data
    +0780 guiN = getappdata(gui.figh_nucleus,'gui');
    +0781 dataN = getappdata(gui.figh_nucleus,'data');
    +0782 % local T1T2 data
    +0783 T1T2map = data.results.T1T2map;
    +0784 
    +0785 % prepare inversion parameter struct
    +0786 param.T1T2 = 'T1T2'; % T1-T2 2D inv
    +0787 
    +0788 % get system properties
    +0789 param.D = data.prop.D;
    +0790 param.G0 = data.prop.G0;
    +0791 param.te = data.prop.te;
    +0792 
    +0793 % IR/SR factor
    +0794 param.T1IRfac = data.inv.T1IRfac;
    +0795 param.IRtype = data.inv.IRtype;
    +0796 
    +0797 % get T1/T2 RTDs values
    +0798 param.T1min = data.inv.T1min;
    +0799 param.T1max = data.inv.T1max;
    +0800 param.T1N = data.inv.T1N;
    +0801 param.T2min = data.inv.T2min;
    +0802 param.T2max = data.inv.T2max;
    +0803 param.T2N = data.inv.T2N;
    +0804 
    +0805 % inversion/regularization settings
    +0806 param.lamT1 = data.inv.T1lambda;
    +0807 param.lamT2 = data.inv.T2lambda;
    +0808 param.orderT1 = data.inv.T1order;
    +0809 param.orderT2 = data.inv.T2order;
    +0810 
    +0811 % prepare data
    +0812 dat = struct;
    +0813 for n = 1:numel(T1T2map.t_recov)
    +0814     dat(n).t = T1T2map.t2;
    +0815     dat(n).s = T1T2map.E_raw_surf(n,:)';
    +0816     dat(n).noise = std(T1T2map.N_raw_surf(n,:));
    +0817     dat(n).T1 = T1T2map.t_recov(n);
    +0818 end
    +0819 % global noise
    +0820 param.noise = std(T1T2map.N_raw_surf(:));
    +0821 
    +0822 % take solver from main NUCLEUS GUI
    +0823 param.solver = dataN.info.solver;
    +0824 switch dataN.info.InvInfo
    +0825     case 'on'
    +0826         param.info = 'final';
    +0827     case 'off'
    +0828         param.info = 'off';
    +0829 end
    +0830 
    +0831 % status bar information
    +0832 switch dataN.info.solver
    +0833     case 'lsqlin'
    +0834         infostring = '2D Inversion using ''Optimization Toolbox'' ... ';
    +0835     case 'lsqnonneg'
    +0836         infostring = '2D Inversion using ''lsqnonneg'' ... ';
    +0837 end
    +0838 displayStatusText(guiN,infostring);
    +0839 
    +0840 % disable the RUN button to indicate a running inversion
    +0841 set(gui.push_handles.run_inv,'String','RUNNING ...',...
    +0842     'BackgroundColor',get(gui.push_handles.update,'BackgroundColor'),...
    +0843     'Enable','off'); pause(0.01);
    +0844 
    +0845 tic;
    +0846 % call 2D inversion
    +0847 inv2D = fitData2D(dat,param);
    +0848 runtime = toc;
    +0849 displayStatusText(guiN,[infostring,'done | inversion took ',...
    +0850     sprintf('%5.2f',runtime),' s']);
    +0851 
    +0852 % enable the RN button
    +0853 set(gui.push_handles.run_inv,'String','RUN 2D INV',...
    +0854     'BackgroundColor','g','Enable','on','Callback',@tv_onPushRun);
    +0855 setappdata(figh,'gui',gui);
    +0856 
    +0857 % save results
    +0858 data.results.inv2D = inv2D;
    +0859 
    +0860 % update data
    +0861 setappdata(figh,'data',data);
    +0862 
    +0863 % plot all 2D inversion data
    +0864 tv_getTLGM(figh);
    +0865 tv_plotResults(figh);
    +0866 beautifyAxes(figh);
    +0867 set(gui.check_handles.dcm,'Enable','on');
    +0868 end
    +0869 
    +0870 %% subfunction to export the 2D inversion data
    +0871 function tv_onPushSave(src,~)
    +0872 figh = ancestor(src,'figure','toplevel');
    +0873 % local GUI data
    +0874 uvgui = getappdata(figh,'gui');
    +0875 uvdata = getappdata(figh,'data');
    +0876 % NUCLEUSinv data
    +0877 data = getappdata(uvgui.figh_nucleus,'data');
    +0878 
    +0879 % get data path to save inversion results
    +0880 [sfile,spath] = uiputfile('*.mat','Select File for Save',...
    +0881     fullfile(data.import.path,'2Dinvdata.mat'));
    +0882 % if user did not cancel, procceed
    +0883 if sfile > 0
    +0884     invdata = uvdata;
    +0885     save(fullfile(spath,sfile),'invdata');
    +0886     disp('2D Inverions data saved to: ');
    +0887     disp(fullfile(spath,sfile));
    +0888 else
    +0889     disp('Save cancelled.');
    +0890 end
    +0891 
    +0892 end
    +0893 
    +0894 %% subfunction to export the current view to a figure
    +0895 function tv_onPushView(src,~)
    +0896 figh = ancestor(src,'figure','toplevel');
    +0897 % local GUI data
    +0898 gui = getappdata(figh,'gui');
    +0899 
    +0900 % opening the export figure
    +0901 expfig = figure('Color',gui.myui.colors.panelBG);
    +0902 
    +0903 % create axes layout depending on view
    +0904 switch get(gui.rightPanel,'Selection')
    +0905     case 1
    +0906         % create layout
    +0907         ax1 = subplot(2,2,1,'Parent',expfig);
    +0908         ax2 = subplot(2,2,2,'Parent',expfig);
    +0909         ax3 = subplot(2,2,3,'Parent',expfig);
    +0910         ax4 = subplot(2,2,4,'Parent',expfig);
    +0911         % get positions
    +0912         pos1 = get(ax1,'Position');
    +0913         pos2 = get(ax2,'Position');
    +0914         pos3 = get(ax3,'Position');
    +0915         pos4 = get(ax4,'Position');
    +0916         % delete axes
    +0917         delete(ax1);delete(ax2);delete(ax3);delete(ax4);
    +0918         % copy GUI axes
    +0919         ax1 = copyobj(gui.axes11,expfig);
    +0920         ax2 = copyobj(gui.axes12,expfig);
    +0921         ax3 = copyobj(gui.axes13,expfig);
    +0922         ax4 = copyobj(gui.axes14,expfig);
    +0923         % adjust positions
    +0924         set(ax1,'Position',pos1);
    +0925         set(ax2,'Position',pos2);
    +0926         set(ax3,'Position',pos3);
    +0927         set(ax4,'Position',pos4);
    +0928         % set colorbars
    +0929         colorbar(ax1,'Location','EastOutside');
    +0930         colorbar(ax2,'Location','EastOutside');
    +0931         colorbar(ax3,'Location','EastOutside');
    +0932         colorbar(ax4,'Location','EastOutside');
    +0933     case 2
    +0934         % create layout
    +0935         ax1 = subplot(5,5,[1 2 3 4],'Parent',expfig);
    +0936         ax2 = subplot(5,5,[6:9 11:14 16:19 21:24],'Parent',expfig);
    +0937         ax3 = subplot(5,5,[10 15 20 25],'Parent',expfig);
    +0938         % get positions
    +0939         pos1 = get(ax1,'Position');
    +0940         pos2 = get(ax2,'Position');
    +0941         pos3 = get(ax3,'Position');
    +0942         % delete axes
    +0943         delete(ax1);delete(ax2);delete(ax3);
    +0944         % copy GUI axes
    +0945         ax1 = copyobj(gui.axes21,expfig);
    +0946         ax2 = copyobj(gui.axes2,expfig);
    +0947         ax3 = copyobj(gui.axes24,expfig);
    +0948         % adjust positions
    +0949         set(ax1,'Position',pos1);
    +0950         set(ax2,'Position',pos2);
    +0951         set(ax3,'Position',pos3);
    +0952     case 3
    +0953         % create layout
    +0954         ax1 = subplot(7,1,[1 2],'Parent',expfig);
    +0955         ax2 = subplot(7,1,[4 5 6 7],'Parent',expfig);
    +0956         % get positions
    +0957         pos1 = get(ax1,'Position');
    +0958         pos2 = get(ax2,'Position');
    +0959         % delete axes
    +0960         delete(ax1);delete(ax2);
    +0961         % copy GUI axes
    +0962         ax1 = copyobj(gui.axes31,expfig);
    +0963         ax2 = copyobj(gui.axes32,expfig);
    +0964         % adjust positions
    +0965         set(ax1,'Position',pos1);
    +0966         set(ax2,'Position',pos2);
    +0967 end
    +0968 
    +0969 end
    +0970 
    +0971 %% subfunction to update the main NUCLEUSinv GUI
    +0972 function tv_onPushUpdate(src,~)
    +0973 figh = ancestor(src,'figure','toplevel');
    +0974 % local GUI data
    +0975 uvgui = getappdata(figh,'gui');
    +0976 uvdata = getappdata(figh,'data');
    +0977 % NUCLEUSinv data
    +0978 gui = getappdata(uvgui.figh_nucleus,'gui');
    +0979 INVdata = getappdata(uvgui.figh_nucleus,'INVdata');
    +0980 data = getappdata(uvgui.figh_nucleus,'data');
    +0981 
    +0982 % loop over all signals
    +0983 E_inv = zeros(size(uvdata.results.T1T2map.t_recov));
    +0984 for id = 1:numel(INVdata)
    +0985     % the standard INVdata struct
    +0986     INVdata{id} = [];
    +0987     
    +0988     % old, slow but consistent way
    +0989     % trigger the listbox entry
    +0990     % set(gui.listbox_handles.signal,'Value',id);
    +0991     % onListboxData(gui.listbox_handles.signal);
    +0992     % no gating
    +0993     % which radiobutton ('log', 'lin' or 'none')
    +0994     % onRadioGates(gui.radio_handles.process_gates_none);
    +0995     % get the fresh data
    +0996     % data = getappdata(uvgui.figh_nucleus,'data');
    +0997     
    +0998     % new, fast and hopefully consistent :-) way
    +0999     if id == numel(INVdata)
    +1000         data.process.start = 1;
    +1001         data.process.end = numel(uvdata.results.T1T2map.import{id}.time);
    +1002     else
    +1003         data.process.start = uvdata.prop.first;
    +1004         data.process.end = uvdata.prop.last; %numel(uvdata.results.T1T2map.import{id}.time);
    +1005     end
    +1006     data.process.gatetype = 'raw';
    +1007     data.process.isgated = false;
    +1008     % update 2Dinv GUI settings
    +1009     data.inv2D.prop = uvdata.prop;
    +1010     data.inv2D.inv = uvdata.inv;
    +1011     data.inv2D.info = uvdata.info;
    +1012     % create raw data struct
    +1013     data.results.nmrraw.t = uvdata.results.T1T2map.import{id}.time;
    +1014     data.results.nmrraw.s = uvdata.results.T1T2map.import{id}.signal;
    +1015     if id == numel(INVdata)
    +1016         data.results.nmrraw.noise = uvdata.results.T1T2map.import{id}.noise;
    +1017         data.results.nmrproc.T1T2 = 'T1';
    +1018         data.results.nmrproc.T1IRfac = 2;
    +1019     else
    +1020         data.results.nmrraw.phase = uvdata.results.T1T2map.import{id}.phase;
    +1021         data.results.nmrproc.T1T2 = 'T2';
    +1022         data.results.nmrproc.T1IRfac = 1;
    +1023     end
    +1024     % create proc data struct
    +1025     if id == numel(INVdata)
    +1026         data.results.nmrproc.start = 1;
    +1027         data.results.nmrproc.end = numel(uvdata.results.T1T2map.import{id}.time);
    +1028     else
    +1029         data.results.nmrproc.start = uvdata.prop.first;
    +1030         data.results.nmrproc.end = uvdata.prop.last; %numel(uvdata.results.T1T2map.import{id}.time);
    +1031     end    
    +1032     data.results.nmrproc.gatetype = 'raw';
    +1033     data.results.nmrproc.isgated = false;
    +1034     data.results.nmrproc.t = uvdata.results.T1T2map.import{id}.time(data.results.nmrproc.start:data.results.nmrproc.end);
    +1035     data.results.nmrproc.s = real(uvdata.results.T1T2map.import{id}.signal(data.results.nmrproc.start:data.results.nmrproc.end));
    +1036     data.results.nmrproc.N = ones(size(data.results.nmrproc.s));
    +1037     if isfield(uvdata.results.T1T2map.import{id},'noise')
    +1038         data.results.nmrproc.noise = uvdata.results.T1T2map.import{id}.noise;
    +1039     else
    +1040         range = floor(numel(data.results.nmrproc.s)/2):numel(data.results.nmrproc.s);
    +1041         data.results.nmrproc.noise = std(imag(uvdata.results.T1T2map.import{id}.signal(range)));
    +1042     end
    +1043     data.results.nmrproc.e = data.results.nmrproc.noise*ones(size(data.results.nmrproc.s));
    +1044     if isfield(data.results.nmrproc,'W')
    +1045         data.results.nmrproc = rmfield(data.results.nmrproc,'W');
    +1046     end
    +1047 
    +1048     % and use it for the INVdata
    +1049     INVdata{id} = data;
    +1050     INVdata{id} = rmfield(INVdata{id},'import');
    +1051     INVdata{id} = rmfield(INVdata{id},'info');
    +1052     INVdata{id} = rmfield(INVdata{id},'calib');
    +1053     INVdata{id} = rmfield(INVdata{id},'pressure');
    +1054 
    +1055     % now add a dummy "invstd" field
    +1056     if id == numel(INVdata)
    +1057         % for the final merged T1
    +1058         INVdata{id}.results.invstd.fit_t = uvdata.results.T1T2map.t_recov;
    +1059         INVdata{id}.results.invstd.fit_s = E_inv;
    +1060         INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.E0;
    +1061         INVdata{id}.results.invstd.ciE0 = NaN;
    +1062         out = getFitErrors(uvdata.results.T1T2map.E_raw(:,1),E_inv,data.results.nmrproc.noise);
    +1063         INVdata{id}.results.invstd.resnorm = out.resnorm;
    +1064         INVdata{id}.results.invstd.residual = out.residual;
    +1065         INVdata{id}.results.invstd.chi2 = out.chi2;
    +1066         INVdata{id}.results.invstd.rms = out.rms;
    +1067     else
    +1068         % for the individual signals
    +1069         INVdata{id}.results.invstd.fit_t = uvdata.results.inv2D.data(id).t;
    +1070         INVdata{id}.results.invstd.fit_s = uvdata.results.inv2D.data(id).s_fit;
    +1071         E_inv(id,1) = uvdata.results.inv2D.data(id).s_fit(1);
    +1072         INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.data(id).s_fit(1);
    +1073         INVdata{id}.results.invstd.ciE0 = NaN;
    +1074         INVdata{id}.results.invstd.resnorm = uvdata.results.inv2D.data(id).resnorm;
    +1075         INVdata{id}.results.invstd.residual = uvdata.results.inv2D.data(id).residual;
    +1076         INVdata{id}.results.invstd.chi2 = uvdata.results.inv2D.data(id).chi2;
    +1077         INVdata{id}.results.invstd.rms = uvdata.results.inv2D.data(id).rms;
    +1078     end
    +1079     INVdata{id}.results.invstd.lambda_out = 1;
    +1080     INVdata{id}.results.invstd.xn = 0;
    +1081     INVdata{id}.results.invstd.rn = 0;
    +1082     INVdata{id}.results.invstd.invtype = data.invstd.invtype;
    +1083     INVdata{id}.results.invstd.invparams = NaN;
    +1084     if id == numel(INVdata)
    +1085         INVdata{id}.results.inv2D = uvdata.results.inv2D;
    +1086     else
    +1087         INVdata{id}.results.inv2D = true;
    +1088     end
    +1089 
    +1090     % color the corresponding list entries in the main GUI
    +1091     strL = get(gui.listbox_handles.signal,'String');
    +1092     str1 = strL{id};
    +1093     str2 = ['<HTML><BODY bgcolor="rgb(',...
    +1094         sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',str1,'</BODY></HTML>'];
    +1095     strL{id} = str2;
    +1096     set(gui.listbox_handles.signal,'String',strL);
    +1097 end
    +1098 
    +1099 % update GUI INVdata
    +1100 setappdata(uvgui.figh_nucleus,'INVdata',INVdata);
    +1101 
    +1102 % set focus on first signal
    +1103 set(gui.listbox_handles.signal,'Value',1);
    +1104 onListboxData(gui.listbox_handles.signal);
    +1105 end
    +1106 
    +1107 %% subfunction zo switch x-axis scaling
    +1108 function tv_onRadioLogLin(src,~)
    +1109 figh = ancestor(src,'figure','toplevel');
    +1110 gui = getappdata(figh,'gui');
    +1111 % get tag of the radio menu
    +1112 tag = get(src,'Tag');
    +1113 val = get(src,'Value');
    +1114 
    +1115 switch tag
    +1116     case 'log'
    +1117         switch val
    +1118             case 1 % log should be used
    +1119                 set(gui.radio_handles.lin,'Value',0);
    +1120             case 0 % lin should be used
    +1121                 set(gui.radio_handles.lin,'Value',1);
    +1122         end
    +1123     case 'lin'
    +1124         switch val
    +1125             case 1 % lin should be used
    +1126                 set(gui.radio_handles.log,'Value',0);
    +1127             case 0 % log should be used
    +1128                 set(gui.radio_handles.log,'Value',1);
    +1129         end
    +1130 end
    +1131 % update GUI data
    +1132 setappdata(figh,'gui',gui);
    +1133 
    +1134 % call function to adapt the axes scaling
    +1135 tv_setAxesScaling(figh);
    +1136 end
    +1137 
    +1138 %% subfunction to activate data tips on 2D plot
    +1139 function tv_onCheckDCM(src,~)
    +1140 figh = ancestor(src,'figure','toplevel');
    +1141 gui = getappdata(figh,'gui');
    +1142 % get tag of the radio menu
    +1143 val = get(src,'Value');
    +1144 
    +1145 switch val
    +1146     case 1 % DCM on
    +1147         gui.dcm.Enable = 'on';
    +1148     case 0 % DCM off
    +1149         gui.dcm.Enable = 'off';
    +1150 end
    +1151 
    +1152 % update GUI data
    +1153 setappdata(figh,'gui',gui);
    +1154 end
    +1155 
    +1156 %% subfunction to switch x-axis scaling log<->lin
    +1157 function tv_setAxesScaling(figh)
    +1158 gui = getappdata(figh,'gui');
    +1159 
    +1160 uselog = get(gui.radio_handles.log,'Value');
    +1161 switch uselog
    +1162     case 1
    +1163         set(gui.axes11,'XScale','log');
    +1164         set(gui.axes12,'XScale','log');
    +1165         set(gui.axes13,'XScale','log');
    +1166         set(gui.axes14,'XScale','log');
    +1167         log_t_ticks = logspace(-5,2,8);
    +1168         set(gui.axes32,'XScale','log','XTick',log_t_ticks);
    +1169     case 0
    +1170         set(gui.axes11,'XScale','lin');
    +1171         set(gui.axes12,'XScale','lin');
    +1172         set(gui.axes13,'XScale','lin');
    +1173         set(gui.axes14,'XScale','lin');
    +1174         set(gui.axes32,'XScale','lin','XTickMode','auto');
    +1175 end
    +1176 
    +1177 end
    +1178 
    +1179 %% subfunction to update all plots
    +1180 function tv_plotResults(figh)
    +1181 gui = getappdata(figh,'gui');
    +1182 data = getappdata(figh,'data');
    +1183 T1T2map = data.results.T1T2map;
    +1184 inv2D = data.results.inv2D;
    +1185 col = gui.myui.colors;
    +1186 
    +1187 % clear axes
    +1188 clearSingleAxis(gui.axes13);
    +1189 clearSingleAxis(gui.axes14);
    +1190 clearSingleAxis(gui.axes2);
    +1191 clearSingleAxis(gui.axes21);
    +1192 clearSingleAxis(gui.axes24);
    +1193 clearSingleAxis(gui.axes31);
    +1194 clearSingleAxis(gui.axes32);
    +1195 hold(gui.axes13,'on');
    +1196 hold(gui.axes14,'on');
    +1197 hold(gui.axes2,'on');
    +1198 hold(gui.axes21,'on');
    +1199 hold(gui.axes24,'on');
    +1200 hold(gui.axes31,'on');
    +1201 hold(gui.axes32,'on');
    +1202 
    +1203 % get T1/T2 range from GUI
    +1204 T1range(1) = str2double(get(gui.edit_handles.T1min,'String'));
    +1205 T1range(2) = str2double(get(gui.edit_handles.T1max,'String'));
    +1206 T2range(1) = str2double(get(gui.edit_handles.T2min,'String'));
    +1207 T2range(2) = str2double(get(gui.edit_handles.T2max,'String'));
    +1208 
    +1209 % define some axes settings
    +1210 log_t_ticks = logspace(-5,2,8);
    +1211 t_recov_lims = [min(T1T2map.t_recov)/2 max(T1T2map.t_recov)*2];
    +1212 p_alpha = 0.8;
    +1213 
    +1214 z_max = max(inv2D.f_2Dmap(:));
    +1215 % tab 2 - 2D inversion model
    +1216 [X,Y] = meshgrid(inv2D.T2vec,inv2D.T1vec);
    +1217 % imagescnan(X,Y,inv2D.f_2Dmap,'Parent',gui.axes2);
    +1218 sh = surf(X,Y,inv2D.f_2Dmap,'Parent',gui.axes2);
    +1219 sh.FaceColor = 'flat';
    +1220 sh.EdgeColor = 'none';
    +1221 plot3(inv2D.T2tlgm,inv2D.T1tlgm,z_max,'o','Color',col.FIT,'Parent',gui.axes2);
    +1222 plot3(inv2D.T2tmax,inv2D.T1tmax,z_max,'+','Color',col.FIT,'Parent',gui.axes2);
    +1223 plot3([1e-5 100],[1e-5 100],[z_max z_max],...
    +1224     '--','Color','w','LineWidth',1,'Parent',gui.axes2);
    +1225 view(gui.axes2,[0 90]);
    +1226 set(gui.axes2,'XScale','log','XTick',log_t_ticks,...
    +1227     'XLim',[min(inv2D.T2vec) max(inv2D.T2vec)]);
    +1228 set(gui.axes2,'YScale','log','XTick',log_t_ticks,...
    +1229     'YLim',[min(inv2D.T1vec) max(inv2D.T1vec)],'YDir','normal');
    +1230 set(get(gui.axes2,'XLabel'),'String','relaxation time T2 [s]');
    +1231 set(get(gui.axes2,'YLabel'),'String','relaxation time T1 [s]');
    +1232 set(gui.axes2,'Layer','top','XGrid','off','YGrid','off');
    +1233 colorbar(gui.axes2,'Location','EastOutside');
    +1234 
    +1235 % sum along each dimension to get both RTDs
    +1236 T1rtd = sum(inv2D.f_2Dmap,2);
    +1237 T2rtd = sum(inv2D.f_2Dmap,1);
    +1238 % find common maximum for y-axis setting
    +1239 ymax = max([max(T1rtd) max(T2rtd)])*1.1;
    +1240 % T1 RTD
    +1241 plot(T1rtd,inv2D.T1vec,'Color',col.FIT,'Parent',gui.axes24);
    +1242 amp = findApproxTlgmAmplitude(inv2D.T1vec,T1rtd,inv2D.T1tlgm);
    +1243 plot([0 amp],[inv2D.T1tlgm inv2D.T1tlgm],'Color',col.FIT,'LineStyle','--',...
    +1244     'LineWidth',1,'DisplayName','Tlgm','Tag','TLGM','Parent',gui.axes24);
    +1245 amp = findApproxTlgmAmplitude(inv2D.T1vec,T1rtd,inv2D.T1tmax);
    +1246 plot([0 amp],[inv2D.T1tmax inv2D.T1tmax],'Color',col.FIT,'LineStyle','-.',...
    +1247     'LineWidth',1,'DisplayName','Tmax','Tag','TMAX','Parent',gui.axes24);
    +1248 set(gui.axes24,'XScale','lin','XLim',[0 ymax]);
    +1249 set(gui.axes24,'YScale','log','YTickLabel','');
    +1250 if T1range(1)>inv2D.T1vec(1)
    +1251     xlims = get(gui.axes24,'XLim');
    +1252     % draw a transparent patch
    +1253     v = [xlims(1) inv2D.T1vec(1); xlims(2) inv2D.T1vec(1);
    +1254         xlims(2) T1range(1); xlims(1) T1range(1)];
    +1255     f = [1 2 3 4 1];
    +1256     patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,...
    +1257         'HandleVisibility','off','Tag','infolines','Parent', gui.axes24);
    +1258 end
    +1259 if T1range(2)<inv2D.T1vec(end)
    +1260     xlims = get(gui.axes24,'XLim');
    +1261     % draw a transparent patch
    +1262     v = [xlims(1) inv2D.T1vec(end); xlims(2) inv2D.T1vec(end);
    +1263         xlims(2) T1range(2); xlims(1) T1range(2)];
    +1264     f = [1 2 3 4 1];
    +1265     patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,...
    +1266         'HandleVisibility','off','Tag','infolines','Parent', gui.axes24);
    +1267 end
    +1268 
    +1269 % T2 RTD
    +1270 plot(inv2D.T2vec,T2rtd,'Color',col.FIT,'DisplayName','RTD','Parent',gui.axes21);
    +1271 amp = findApproxTlgmAmplitude(inv2D.T2vec,T2rtd,inv2D.T2tlgm);
    +1272 plot([inv2D.T2tlgm inv2D.T2tlgm],[0 amp],'Color',col.FIT,'LineStyle','--',...
    +1273     'LineWidth',1,'DisplayName','Tlgm','Tag','TLGM','Parent',gui.axes21);
    +1274 amp = findApproxTlgmAmplitude(inv2D.T2vec,T2rtd,inv2D.T2tmax);
    +1275 plot([inv2D.T2tmax inv2D.T2tmax],[0 amp],'Color',col.FIT,'LineStyle','-.',...
    +1276     'LineWidth',1,'DisplayName','Tmax','Tag','TMAX','Parent',gui.axes21);
    +1277 set(gui.axes21,'YScale','lin','YLim',[0 ymax]);
    +1278 set(gui.axes21,'XScale','log','XTickLabel','');
    +1279 legend(gui.axes21,'Location','East','FontSize',8);
    +1280 if T2range(1)>inv2D.T2vec(1)
    +1281     ylims = get(gui.axes21,'YLim');
    +1282     % draw a transparent patch
    +1283     v = [inv2D.T2vec(1) ylims(1);inv2D.T2vec(1) ylims(2);
    +1284         T2range(1) ylims(2);T2range(1) ylims(1)];
    +1285     f = [1 2 3 4 1];
    +1286     patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,...
    +1287         'HandleVisibility','off','Tag','infolines','Parent', gui.axes21);
    +1288 end
    +1289 if T2range(2)<inv2D.T2vec(end)
    +1290     ylims = get(gui.axes21,'YLim');
    +1291     % draw a transparent patch
    +1292     v = [inv2D.T2vec(end) ylims(1);inv2D.T2vec(end) ylims(2);
    +1293         T2range(2) ylims(2);T2range(2) ylims(1)];
    +1294     f = [1 2 3 4 1];
    +1295     patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,...
    +1296         'HandleVisibility','off','Tag','infolines','Parent', gui.axes21);
    +1297 end
    +1298 
    +1299 % tab 1 - model response
    +1300 data_inv = inv2D.data;
    +1301 E_fit_surf = zeros(numel(data_inv),numel(inv2D.data(1).t));
    +1302 Residual_surf = E_fit_surf;
    +1303 for nn = 1:numel(data_inv)
    +1304     E_fit_surf(nn,:) = data_inv(nn).s_fit;
    +1305     Residual_surf(nn,:) = data_inv(nn).residual;
    +1306 end
    +1307 [tx,ty] = meshgrid(T1T2map.t2,T1T2map.t_recov);
    +1308 % data
    +1309 imagescnan(tx,ty,E_fit_surf,'Parent',gui.axes13);
    +1310 view(gui.axes13,[0 90]);
    +1311 set(gui.axes13,'XScale','log');
    +1312 set(gui.axes13,'YScale','log','YDir','normal');
    +1313 set(get(gui.axes13,'XLabel'),'String','time [s]');
    +1314 set(get(gui.axes13,'YLabel'),'String','recovery time t_{rec} [s]');
    +1315 set(get(gui.axes13,'Title'),'String','d pred');
    +1316 set(gui.axes13,'CLim',get(gui.axes11,'CLim'));
    +1317 set(gui.axes13,'Layer','top','XGrid','off','YGrid','off');
    +1318 cb = colorbar(gui.axes13);
    +1319 set(cb,'Location','EastOutside');
    +1320 % residual
    +1321 imagescnan(tx,ty,Residual_surf,'Parent',gui.axes14);
    +1322 view(gui.axes14,[0 90]);
    +1323 set(gui.axes14,'XScale','log');
    +1324 set(gui.axes14,'YScale','log','YDir','normal');
    +1325 set(get(gui.axes14,'XLabel'),'String','time [s]');
    +1326 set(get(gui.axes14,'YLabel'),'String','recovery time t_{rec} [s]');
    +1327 set(get(gui.axes14,'Title'),'String',...
    +1328     ['residual (RMS=',sprintf('%3.2f',inv2D.error_global.rms),...
    +1329     ';X^2=',sprintf('%3.2f',inv2D.error_global.chi2),')']);
    +1330 set(gui.axes14,'CLim',get(gui.axes12,'CLim'));
    +1331 set(gui.axes14,'Layer','top','XGrid','off','YGrid','off');
    +1332 cb = colorbar(gui.axes14);
    +1333 set(cb,'Location','EastOutside');
    +1334 
    +1335 % prepare the data for the combined T1 curve
    +1336 E_inv = zeros(size(T1T2map.t_recov));
    +1337 for nn = 1:numel(data_inv)
    +1338     E_inv(nn) = data_inv(nn).s_fit(1);
    +1339     % E_inv(nn,2) = std(T1T2map.data(nn).s);
    +1340     % plot individual T2 signals and fits
    +1341     plot3(inv2D.data(nn).t,inv2D.data(nn).T1*ones(size(inv2D.data(nn).s)),...
    +1342         inv2D.data(nn).s,'Color',col.RE,'DisplayName','T2 signals',...
    +1343         'LineWidth',1,'Parent',gui.axes32);
    +1344     plot3(data_inv(nn).t,data_inv(nn).T1*ones(size(data_inv(nn).s_fit)),data_inv(nn).s_fit,...
    +1345         'Color',col.FIT,'DisplayName','fits','Parent',gui.axes32);
    +1346 end
    +1347 view(gui.axes32,[30 20]);
    +1348 set(gui.axes32,'XScale','log','XTick',log_t_ticks);
    +1349 set(gui.axes32,'YScale','log','YDir','normal','YTick',log_t_ticks,'YLim',t_recov_lims);
    +1350 set(get(gui.axes32,'XLabel'),'String','time [s]');
    +1351 set(get(gui.axes32,'YLabel'),'String','recovery time t_{rec} [s]');
    +1352 set(get(gui.axes32,'ZLabel'),'String','amplitude [a.u.]');
    +1353 
    +1354 % tab 3 - combined T1 curve and fit
    +1355 plot(T1T2map.t_recov,T1T2map.E_raw(:,1),'o-','Color',col.RE,...
    +1356     'LineWidth',1,'DisplayName','T1 curve','Parent',gui.axes31);
    +1357 plot(T1T2map.t_recov,E_inv,'Color',col.FIT,'DisplayName','fit','Parent',gui.axes31);
    +1358 set(gui.axes31,'XScale','log','XLim',t_recov_lims);
    +1359 set(gui.axes31,'YScale','lin');
    +1360 set(get(gui.axes31,'XLabel'),'String','recovery time t_{rec} [s]');
    +1361 set(get(gui.axes31,'YLabel'),'String','mean(E(1:3)) [a.u.]');
    +1362 legend(gui.axes31,'Location','SouthEast');
    +1363 
    +1364 % hold off all axes
    +1365 hold(gui.axes13,'off');
    +1366 hold(gui.axes14,'off');
    +1367 hold(gui.axes2,'off');
    +1368 hold(gui.axes21,'off');
    +1369 hold(gui.axes24,'off');
    +1370 hold(gui.axes31,'off');
    +1371 hold(gui.axes32,'off');
    +1372 
    +1373 % call function to adapt the axes scaling
    +1374 tv_setAxesScaling(figh);
    +1375 end
    +1376 
    +1377 %%  subfunction to plot the raw data
    +1378 function tv_plotRawData(figh)
    +1379 gui = getappdata(figh,'gui');
    +1380 data = getappdata(figh,'data');
    +1381 T1T2map = data.results.T1T2map;
    +1382 col = gui.myui.colors;
    +1383 hold(gui.axes32,'on');
    +1384 
    +1385 % ticks and limits
    +1386 log_t_ticks = logspace(-5,2,8);
    +1387 t_recov_lims = [min(T1T2map.t_recov)/2 max(T1T2map.t_recov)*2];
    +1388 
    +1389 % plot the raw signals in the 3D axis
    +1390 for i = 1:numel(T1T2map.t_recov)
    +1391     % plot the individual T2 signals into the 3D data cube
    +1392     plot3(T1T2map.t2,T1T2map.t_recov(i)*ones(size(T1T2map.t2)),T1T2map.E_raw_surf(i,:),...
    +1393         'Color',col.RE,'DisplayName','T2 signals','LineWidth',1,'Parent',gui.axes32);
    +1394 end
    +1395 
    +1396 % tab 1 - surface plots
    +1397 [tx,ty] = meshgrid(T1T2map.t2,T1T2map.t_recov);
    +1398 % signal
    +1399 imagescnan(tx,ty,T1T2map.E_raw_surf,'Parent',gui.axes11);
    +1400 view(gui.axes11,[0 90]);
    +1401 set(gui.axes11,'XScale','log');
    +1402 set(gui.axes11,'YScale','log','YDir','normal');
    +1403 set(get(gui.axes11,'XLabel'),'String','time [s]');
    +1404 set(get(gui.axes11,'YLabel'),'String','recovery time t_{rec} [s]');
    +1405 set(get(gui.axes11,'Title'),'String','d obs');
    +1406 set(gui.axes11,'Layer','top','XGrid','off','YGrid','off');
    +1407 cb = colorbar(gui.axes11);
    +1408 set(cb,'Location','EastOutside');
    +1409 
    +1410 % noise
    +1411 imagescnan(tx,ty,T1T2map.N_raw_surf,'Parent',gui.axes12);
    +1412 view(gui.axes12,[0 90]);
    +1413 % limits & ticks
    +1414 set(gui.axes12,'XScale','log');
    +1415 set(gui.axes12,'YScale','log','YDir','normal');
    +1416 set(get(gui.axes12,'XLabel'),'String','time [s]');
    +1417 set(get(gui.axes12,'YLabel'),'String','recovery time t_{rec} [s]');
    +1418 set(get(gui.axes12,'Title'),'String',['e obs (STD=',sprintf('%3.2f',...
    +1419     std(T1T2map.N_raw_surf(:))),')']);
    +1420 set(gui.axes12,'Layer','top','XGrid','off','YGrid','off');
    +1421 cb = colorbar(gui.axes12);
    +1422 set(cb,'Location','EastOutside');
    +1423 
    +1424 % tab 3 - combined T1 curve
    +1425 plot(T1T2map.t_recov,T1T2map.E_raw(:,1),'o-','Color',col.RE,...
    +1426     'LineWidth',1,'DisplayName','T1 curve','Parent',gui.axes31);
    +1427 set(gui.axes31,'XScale','log','XLim',t_recov_lims);
    +1428 set(gui.axes31,'YScale','lin');
    +1429 set(get(gui.axes31,'XLabel'),'String','recovery time t_{rec} [s]');
    +1430 set(get(gui.axes31,'YLabel'),'String','mean(E(1:3)) [a.u.]');
    +1431 legend(gui.axes31,'Location','SouthEast');
    +1432 
    +1433 % tab 3  - 2D data cube
    +1434 view(gui.axes32,[30 20]);
    +1435 set(gui.axes32,'XScale','log','XTick',log_t_ticks);
    +1436 set(gui.axes32,'YScale','log','YDir','normal','YTick',log_t_ticks,'YLim',t_recov_lims);
    +1437 set(get(gui.axes32,'XLabel'),'String','time [s]');
    +1438 set(get(gui.axes32,'YLabel'),'String','recovery time t_{rec} [s]');
    +1439 set(get(gui.axes32,'ZLabel'),'String','amplitude [a.u.]');
    +1440 hold(gui.axes32,'off');
    +1441 
    +1442 % call function to adapt the axes scaling
    +1443 tv_setAxesScaling(figh);
    +1444 end
    +1445 
    +1446 %% subfunction to update all plots
    +1447 function tv_getTLGM(figh)
    +1448 % local GUI data
    +1449 gui = getappdata(figh,'gui');
    +1450 data = getappdata(figh,'data');
    +1451 % get 2D inversion data
    +1452 inv2D = data.results.inv2D;
    +1453 
    +1454 % get T1/T2 range from GUI
    +1455 T1range(1) = data.info.T1min;
    +1456 T1range(2) = data.info.T1max;
    +1457 T2range(1) = data.info.T2min;
    +1458 T2range(2) = data.info.T2max;
    +1459 
    +1460 % get TLGM and TMAX accounting for T1 and T2 ranges
    +1461 [TLGM,TMAX] = getTLogMean2D(inv2D.T1vec,inv2D.T2vec,inv2D.f_2Dmap,T1range,T2range);
    +1462 
    +1463 % update results in data struct
    +1464 inv2D.T1tlgm = TLGM(1);
    +1465 inv2D.T2tlgm = TLGM(2);
    +1466 inv2D.T1tmax = TMAX(1);
    +1467 inv2D.T2tmax = TMAX(2);
    +1468 
    +1469 % update GUI data struct
    +1470 data.info.E0 = inv2D.E0;
    +1471 data.info.T1tlgm = inv2D.T1tlgm;
    +1472 data.info.T2tlgm = inv2D.T2tlgm;
    +1473 data.info.T1tmax = inv2D.T1tmax;
    +1474 data.info.T2tmax = inv2D.T2tmax;
    +1475 
    +1476 % update GUI elements
    +1477 set(gui.edit_handles.E0,'String',sprintf('%4.3f',inv2D.E0));
    +1478 set(gui.edit_handles.T1tlgm,'String',sprintf('%4.3f',inv2D.T1tlgm));
    +1479 set(gui.edit_handles.T2tlgm,'String',sprintf('%4.3f',inv2D.T2tlgm));
    +1480 set(gui.edit_handles.Tlgm_ratio,'String',sprintf('%4.3f',inv2D.T1tlgm/inv2D.T2tlgm));
    +1481 set(gui.edit_handles.T1tmax,'String',sprintf('%4.3f',inv2D.T1tmax));
    +1482 set(gui.edit_handles.T2tmax,'String',sprintf('%4.3f',inv2D.T2tmax));
    +1483 set(gui.edit_handles.Tmax_ratio,'String',sprintf('%4.3f',inv2D.T1tmax/inv2D.T2tmax));
    +1484 
    +1485 % update data
    +1486 data.results.inv2D = inv2D;
    +1487 setappdata(figh,'data',data);
    +1488 end
    +1489 
    +1490 %% subfunction to find RTD amplitude
    +1491 function amp = findApproxTlgmAmplitude(t,f,TLGM)
    +1492 
    +1493 if isnan(TLGM)
    +1494     amp = NaN;
    +1495 else
    +1496     index = find(abs(t-TLGM)==min(abs(t-TLGM)));
    +1497     if index == 1 || index == numel(t)
    +1498         amp = f(index);
    +1499     else
    +1500         amp = interp1(t(index-1:index+1),f(index-1:index+1),TLGM);
    +1501     end
    +1502 end
    +1503 
    +1504 end
    +1505 
    +1506 %%  subfunction to plot the raw data
    +1507 function tv_prepareRawData(figh)
    +1508 data = getappdata(figh,'data');
    +1509 T1T2map = data.results.T1T2map;
    +1510 
    +1511 % select first T2 echo
    +1512 firstN = data.prop.first;
    +1513 lastN = data.prop.last;
    +1514 T1T2map.t2 = T1T2map.import{1}.time(firstN:lastN);
    +1515 
    +1516 % prepare the surface plots for the raw data
    +1517 T1T2map.E_raw_surf = zeros(numel(T1T2map.t_recov),lastN-firstN+1);
    +1518 T1T2map.N_raw_surf = zeros(numel(T1T2map.t_recov),lastN-firstN+1);
    +1519 for i = 1:numel(T1T2map.t_recov)
    +1520     T1T2map.E_raw_surf(i,:) = real(T1T2map.import{i}.signal(firstN:lastN));
    +1521     T1T2map.N_raw_surf(i,:) = imag(T1T2map.import{i}.signal(firstN:lastN));
    +1522 end
    +1523 % get merged T1 curve
    +1524 T1T2map.E_raw = T1T2map.import{end}.signal;
    +1525 
    +1526 % update the data
    +1527 data.results.T1T2map = T1T2map;
    +1528 % update GUI data
    +1529 setappdata(figh,'data',data);
    +1530 end
    +1531 
    +1532 %% estimate IR type
    +1533 function tv_estimateIRtype(figh)
    +1534 data = getappdata(figh,'data');
    +1535 gui = getappdata(figh,'gui');
    +1536 T1T2map = data.results.T1T2map;
    +1537 
    +1538 % the T1 curve
    +1539 E = T1T2map.E_raw;
    +1540 
    +1541 if E(1) > 0
    +1542     % possibly SR
    +1543     data.inv.IRtype = 1;
    +1544     data.inv.T1IRfac = 1;
    +1545     set(gui.popup_handles.T1type,'Value',1);
    +1546     set(gui.popup_handles.IRtype,'Enable','off');
    +1547 else
    +1548     if E(end) < abs(E(1))*0.5
    +1549         % possibly IR with kernel type 2 => -exp(t/T1)
    +1550         data.inv.IRtype = 2;
    +1551         set(gui.popup_handles.T1type,'Value',2);
    +1552         set(gui.popup_handles.IRtype,'Value',2);
    +1553     else
    +1554         % possibly IR with kernel type 1 => 1-2exp(t/T1)
    +1555         data.inv.IRtype = 1;
    +1556         data.inv.T1IRfac = 2;
    +1557         set(gui.popup_handles.T1type,'Value',2);
    +1558         set(gui.popup_handles.IRtype,'Value',1);
    +1559     end
    +1560 end
    +1561 
    +1562 % update GUI data
    +1563 setappdata(figh,'data',data);
    +1564 setappdata(figh,'gui',gui);
    +1565 end
    +1566 
    +1567 %% adjust the data tip on the 2D axes
    +1568 function txt = localDcmFcn(~,event,ax)
    +1569 
    +1570 if strcmp(get(ax,'Tag'),'2D')
    +1571     % find indices to closest x and y data values. This requires the
    +1572     % number of values in XData and YData to agree with CData size.
    +1573     [~, xidx] = min(abs(event.Target.XData - event.Position(1)),[],2);
    +1574     [~, yidx] = min(abs(event.Target.YData - event.Position(2)),[],1);
    +1575     colorbarValue = event.Target.CData(yidx(1), xidx(1));
    +1576     % colormapIdx = round((colorbarValue - ax.CLim(1))/(ax.CLim(2)-ax.CLim(1)) * (size(ax.Colormap,1)-1) +1);
    +1577     txt = sprintf('[T2,T1]: [%.2g, %.2g]\nValue: %.2g', ...
    +1578         event.Position(1:2), colorbarValue);
    +1579 end
    +1580 
    +1581 end
    +1582 
    +1583 %% close function
    +1584 function tv_closeme(src,~)
    +1585 figh = ancestor(src,'figure','toplevel');
    +1586 % try to close the sub GUI in a clean manner
    +1587 try
    +1588     % NOTE: maybe needed at some later point
    +1589     %     gui = getappdata(figh,'gui');
    +1590     %     data = getappdata(gui.figh_nucleus,'data');
    +1591     %     % update NUCLEUSinv
    +1592     %     setappdata(gui.figh_nucleus,'data',data);
    +1593     delete(figh);
    +1594 catch
    +1595     % if this is not working: just close it
    +1596     delete(figh);
    +1597 end
    +1598 
    +1599 end
    +1600 
    +1601 %------------- END OF CODE --------------
    +1602 
    +1603 %% License:
    +1604 % MIT License
    +1605 %
    +1606 % Copyright (c) 2024 Thomas Hiller
    +1607 %
    +1608 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +1609 % of this software and associated documentation files (the "Software"), to deal
    +1610 % in the Software without restriction, including without limitation the rights
    +1611 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +1612 % copies of the Software, and to permit persons to whom the Software is
    +1613 % furnished to do so, subject to the following conditions:
    +1614 %
    +1615 % The above copyright notice and this permission notice shall be included in all
    +1616 % copies or substantial portions of the Software.
    +1617 %
    +1618 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +1619 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +1620 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +1621 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +1622 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +1623 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +1624 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/interface/Mod2DView.html b/doc/nucleus/functions/interface/Mod2DView.html new file mode 100644 index 0000000..9b7dc2b --- /dev/null +++ b/doc/nucleus/functions/interface/Mod2DView.html @@ -0,0 +1,1238 @@ + + + + Description of Mod2DView + + + + + + + + + + + +

    Mod2DView +

    + +

    PURPOSE ^

    +
    is an extra subGUI to calculate 2D forward T1-T2 data
    + +

    SYNOPSIS ^

    +
    function Mod2DView(src,~)
    + +

    DESCRIPTION ^

    +
    Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
    +
    + Syntax:
    +       Mod2DView
    +
    + Inputs:
    +       src - handle of the calling object
    +
    + Outputs:
    +       none
    +
    + Example:
    +       Mod2DView(src,~)
    +
    + Other m-files required:
    +       beautifyAxes
    +       clearAllAxes
    +       displayStatusText
    +       fitData2D_T1T2
    +       imagescnan
    +
    + Subfunctions:
    +
    + MAT-files required:
    +       none
    +
    + See also: NUCLEUSmod
    + 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 Mod2DView(src,~)
    +0002 %Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
    +0003 %
    +0004 % Syntax:
    +0005 %       Mod2DView
    +0006 %
    +0007 % Inputs:
    +0008 %       src - handle of the calling object
    +0009 %
    +0010 % Outputs:
    +0011 %       none
    +0012 %
    +0013 % Example:
    +0014 %       Mod2DView(src,~)
    +0015 %
    +0016 % Other m-files required:
    +0017 %       beautifyAxes
    +0018 %       clearAllAxes
    +0019 %       displayStatusText
    +0020 %       fitData2D_T1T2
    +0021 %       imagescnan
    +0022 %
    +0023 % Subfunctions:
    +0024 %
    +0025 % MAT-files required:
    +0026 %       none
    +0027 %
    +0028 % See also: NUCLEUSmod
    +0029 % Author: see AUTHORS.md
    +0030 % email: see AUTHORS.md
    +0031 % License: MIT License (at end)
    +0032 
    +0033 %------------- BEGIN CODE --------------
    +0034 
    +0035 %% get GUI handle and data
    +0036 figh_nucleus = ancestor(src,'figure','toplevel');
    +0037 nucleus.data = getappdata(figh_nucleus,'data');
    +0038 nucleus.gui = getappdata(figh_nucleus,'gui');
    +0039 myui = nucleus.gui.myui;
    +0040 colors = myui.colors;
    +0041 
    +0042 %% get GUI data from NUCLEUS
    +0043 data = nucleus.data.mod2D;
    +0044 
    +0045 % check if the figure is already open
    +0046 fig_2Dmod = findobj('Tag','2DMOD');
    +0047 % if not, create it
    +0048 if isempty(fig_2Dmod)
    +0049     % draw the figure on top of NUCLEUSinv
    +0050     fig_2Dmod = figure('Name','NUCLEUSmod - 2D Modeling',...
    +0051         'NumberTitle','off','Resize','on','ToolBar','none',...
    +0052         'Tag','2DMOD','CloseRequestFcn',@fv_closeme,...
    +0053         'MenuBar','none');
    +0054     pos0 = get(figh_nucleus,'Position');
    +0055     cent(1) = (pos0(1)+pos0(3)/2);
    +0056     cent(2) = (pos0(2)+pos0(4)/2);
    +0057     posf = [cent(1)-pos0(3)/2.5 pos0(2)+22 pos0(3)/1.25 pos0(4)-22];
    +0058     % posf = pos0;
    +0059     set(fig_2Dmod,'Position',posf);
    +0060 
    +0061     gui.menu.view = uimenu(fig_2Dmod,'Label','View');
    +0062     gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',...
    +0063         'Callback',@onMenuView);
    +0064 
    +0065     cpanel_w = 190;
    +0066 
    +0067     % create the main layout
    +0068     gui.main = uix.HBox('Parent',fig_2Dmod,'BackGroundColor',colors.panelBG,...
    +0069         'Spacing',5,'Padding',5,'Visible','off');
    +0070     gui.left = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,...
    +0071         'Spacing',5,'Padding',0); % controls
    +0072     gui.right = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,...
    +0073         'Spacing',5,'Padding',0); % plots
    +0074 
    +0075     set(gui.main,'Widths',[400 -1 ]);
    +0076 
    +0077     % waitbar indicating the loading of the GUI
    +0078     steps = 4;
    +0079     hwb = waitbar(0,'loading ...','Name','2DMod GUI initialization','Visible','off');
    +0080     set(hwb,'Units','Pixel')
    +0081     posw = get(hwb,'Position');
    +0082     set(hwb,'Position',[posf(1)+posf(3)/2-posw(3)/2 posf(2)+posf(4)/2-posw(4)/2 posw(3:4)]);
    +0083     set(hwb,'Visible','on');
    +0084 
    +0085     % --- modelling panel ---
    +0086     waitbar(1/steps,hwb,'loading GUI elements - 2D modelling');
    +0087     gui.panels.mod.main = uix.BoxPanel('Parent',gui.left,...
    +0088         'Title','2D modelling settings','MinimizeFcn',@minimizePanel,...
    +0089         'TitleColor',colors.GEO,'ForegroundColor',colors.BoxTitle);
    +0090     gui.panels.mod.VBox = uix.VBox('Parent',gui.panels.mod.main,...
    +0091         'Spacing',3,'Padding',3);
    +0092 
    +0093     % RTD T1
    +0094     gui.panels.mod.HBox1 = uix.HBox('Parent',gui.panels.mod.VBox,...
    +0095         'Spacing',3);
    +0096     gui.text_handles.rtdT1 = uicontrol('Parent',gui.panels.mod.HBox1,...
    +0097         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0098         'String','RTD T1 -  min [s] | max [s] | #');
    +0099     tstr = "";
    +0100     gui.edit_handles.rtdT1min = uicontrol('Parent',gui.panels.mod.HBox1,...
    +0101         'Style','edit','String',sprintf('%5.4f',data.mod.T1min),...
    +0102         'FontSize',myui.fontsize,'Tag','rtdT1min',...
    +0103         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0104         'Callback',@fv_onEditValue);
    +0105     tstr = "";
    +0106     gui.edit_handles.rtdT1max = uicontrol('Parent',gui.panels.mod.HBox1,...
    +0107         'Style','edit','String',sprintf('%d',data.mod.T1max),...
    +0108         'FontSize',myui.fontsize,'Tag','rtdT1max',...
    +0109         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0110         'Callback',@fv_onEditValue);
    +0111     tstr = "";
    +0112     gui.edit_handles.rtdT1N = uicontrol('Parent',gui.panels.mod.HBox1,...
    +0113         'Style','edit','String',sprintf('%d',data.mod.T1N),...
    +0114         'FontSize',myui.fontsize,'Tag','rtdT1N',...
    +0115         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0116         'Callback',@fv_onEditValue);
    +0117     set(gui.panels.mod.HBox1,'Widths',[cpanel_w -1 -1 -1]);
    +0118 
    +0119     % RTD T2
    +0120     gui.panels.mod.HBox2 = uix.HBox('Parent',gui.panels.mod.VBox,...
    +0121         'Spacing',3);
    +0122     gui.text_handles.rtdT2 = uicontrol('Parent',gui.panels.mod.HBox2,...
    +0123         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0124         'String','RTD T2 - min [s] | max [s] | #');
    +0125     tstr = "";
    +0126     gui.edit_handles.rtdT2min = uicontrol('Parent',gui.panels.mod.HBox2,...
    +0127         'Style','edit','String',sprintf('%5.4f',data.mod.T2min),...
    +0128         'FontSize',myui.fontsize,'Tag','rtdT2min',...
    +0129         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0130         'Callback',@fv_onEditValue);
    +0131     tstr = "";
    +0132     gui.edit_handles.rtdT2max = uicontrol('Parent',gui.panels.mod.HBox2,...
    +0133         'Style','edit','String',sprintf('%d',data.mod.T2max),...
    +0134         'FontSize',myui.fontsize,'Tag','rtdT2max',...
    +0135         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0136         'Callback',@fv_onEditValue);
    +0137     tstr = "";
    +0138     gui.edit_handles.rtdT2N = uicontrol('Parent',gui.panels.mod.HBox2,...
    +0139         'Style','edit','String',sprintf('%d',data.mod.T2N),...
    +0140         'FontSize',myui.fontsize,'Tag','rtdT2N',...
    +0141         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0142         'Callback',@fv_onEditValue);
    +0143     set(gui.panels.mod.HBox2,'Widths',[cpanel_w -1 -1 -1]);
    +0144 
    +0145     uix.Empty('Parent',gui.panels.mod.VBox);
    +0146     % table
    +0147     gui.panels.mod.HBox3 = uix.HBox('Parent',gui.panels.mod.VBox,...
    +0148         'Spacing',3);
    +0149     m = data.mod.mu;
    +0150     s = data.mod.sigma;
    +0151     a = data.mod.amp;
    +0152     table = cell(1,1);
    +0153     for i = 1:data.mod.Ndist
    +0154         table{i,1} = false;
    +0155         table{i,2} = m(i,1);
    +0156         table{i,3} = m(i,2);
    +0157         table{i,4} = s{i}(1,1);
    +0158         table{i,5} = s{i}(2,2);
    +0159         table{i,6} = s{i}(1,2);
    +0160         table{i,7} = s{i}(2,1);
    +0161         table{i,8} = a(i);
    +0162     end
    +0163     table{1,1} = true;
    +0164     data.results.mod2D.table = table;
    +0165     gui.table_handles.mod = uitable('Parent',gui.panels.mod.HBox3,...
    +0166     'Data',table,...
    +0167     'ColumnFormat',({'logical' 'short' 'short' 'bank' 'bank' 'bank' 'bank' 'bank'}),...
    +0168     'ColumnEditable',[true true true true true true true true],...
    +0169     'ColumnWidth',{35 77 77 33 33 33 33 33},...
    +0170     'RowName','numbered',...
    +0171     'ColumnName',{'use' 'mX','mY','xx','yy','xy','yx','A'},...
    +0172     'UserData',struct('Tooltipstr',tstr),...
    +0173     'CellEditCallback',@fv_onEditTable,...
    +0174     'FontSize',myui.fontsize);
    +0175     
    +0176     % UPDATE button
    +0177     % gui.panels.mod.HBox5 = uix.HBox('Parent',gui.panels.mod.VBox,...
    +0178     %     'Spacing',3);
    +0179     % uix.Empty('Parent',gui.panels.mod.HBox5);
    +0180     % tstr = 'Update model';
    +0181     % gui.push_handles.model = uicontrol('Parent',gui.panels.mod.HBox5,...
    +0182     %     'String','UPDATE MODEL','FontSize',myui.fontsize,'Tag','rtd',...
    +0183     %     'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0184     %     'BackGroundColor','g','Callback',@fv_getModel);
    +0185     % set(gui.panels.mod.HBox5,'Widths',[cpanel_w -1]);
    +0186 
    +0187     % adjust heights
    +0188     set(gui.panels.mod.VBox,'Heights',[25 25 25 -1]);
    +0189 
    +0190     %% --- properties panel ---
    +0191     waitbar(2/steps,hwb,'loading GUI elements - properties');
    +0192     gui.panels.prop.main = uix.BoxPanel('Parent',gui.left,...
    +0193         'Title','Properties','MinimizeFcn',@minimizePanel,...
    +0194         'TitleColor',colors.GEO,'ForegroundColor',colors.BoxTitle);
    +0195     gui.panels.prop.VBox = uix.VBox('Parent',gui.panels.prop.main,...
    +0196         'Spacing',3,'Padding',3);
    +0197 
    +0198     % D coeff.
    +0199     gui.panels.prop.HBox1 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0200         'Spacing',3);
    +0201     gui.text_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,...
    +0202         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0203         'String',['Diffusion coeff. [10',char(hex2dec('207B')),...
    +0204         char(hex2dec('2079')),' m',char(hex2dec('00B2')),'/s]']);
    +0205     uix.Empty('Parent',gui.panels.prop.HBox1);
    +0206     tstr = 'Set diffusion coefficient.';
    +0207     gui.edit_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,...
    +0208         'Style','edit','String',sprintf('%4.3f',data.prop.D*1e9),...
    +0209         'FontSize',myui.fontsize,'Tag','diff',...
    +0210         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0211         'Callback',@fv_onEditValue);
    +0212     set(gui.panels.prop.HBox1,'Widths',[cpanel_w -1 -1]);
    +0213 
    +0214     % Gradient
    +0215     gui.panels.prop.HBox2 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0216         'Spacing',3);
    +0217     gui.text_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,...
    +0218         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0219         'String',"Gradient [T/m]");
    +0220     uix.Empty('Parent',gui.panels.prop.HBox2);
    +0221     tstr = 'Set device gradient.';
    +0222     gui.edit_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,...
    +0223         'Style','edit','String',sprintf('%d',data.prop.G0),...
    +0224         'FontSize',myui.fontsize,'Tag','gradient',...
    +0225         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0226         'Callback',@fv_onEditValue);
    +0227     set(gui.panels.prop.HBox2,'Widths',[cpanel_w -1 -1]);
    +0228 
    +0229     % echo time
    +0230     gui.panels.prop.HBox3 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0231         'Spacing',3);
    +0232     gui.text_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,...
    +0233         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0234         'String',"Echo time tE [µs]");
    +0235     uix.Empty('Parent',gui.panels.prop.HBox3);
    +0236     tstr = 'Set echo time tE.';
    +0237     gui.edit_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,...
    +0238         'Style','edit','String',sprintf('%d',data.nmr.T2te*1e6),...
    +0239         'FontSize',myui.fontsize,'Tag','echo_time',...
    +0240         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0241         'Enable','off',...
    +0242         'Callback',@fv_onEditValue);
    +0243     set(gui.panels.prop.HBox3,'Widths',[cpanel_w -1 -1]);
    +0244 
    +0245     % Tbulk
    +0246     gui.panels.prop.HBox4 = uix.HBox('Parent',gui.panels.prop.VBox,...
    +0247         'Spacing',3);
    +0248     gui.text_handles.Tbulk = uicontrol('Parent',gui.panels.prop.HBox4,...
    +0249         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0250         'String',"Bulk relaxation [s]");
    +0251     uix.Empty('Parent',gui.panels.prop.HBox4);
    +0252     tstr = 'Set Tbulk value.';
    +0253     gui.edit_handles.Tbulk = uicontrol('Parent',gui.panels.prop.HBox4,...
    +0254         'Style','edit','String',sprintf('%d',data.prop.Tbulk),...
    +0255         'FontSize',myui.fontsize,'Tag','Tbulk',...
    +0256         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0257         'Callback',@fv_onEditValue);
    +0258     set(gui.panels.prop.HBox4,'Widths',[cpanel_w -1 -1]);
    +0259 
    +0260     %% --- NMR signal panel ---
    +0261     waitbar(3/steps,hwb,'loading GUI elements - Signal panel');
    +0262     gui.panels.nmr.main = uix.BoxPanel('Parent',gui.left,...
    +0263         'Title','NMR signals','MinimizeFcn',@minimizePanel,...
    +0264         'TitleColor',colors.NMR,'ForegroundColor',colors.BoxTitle);
    +0265     gui.panels.nmr.VBox = uix.VBox('Parent',gui.panels.nmr.main,...
    +0266         'Spacing',3,'Padding',3);
    +0267 
    +0268     % T1type
    +0269     gui.panels.nmr.HBox0 = uix.HBox('Parent',gui.panels.nmr.VBox,...
    +0270         'Spacing',3);
    +0271     gui.text_handles.T1type = uicontrol('Parent',gui.panels.nmr.HBox0,...
    +0272         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0273         'String','T1 type (SR / IR)');
    +0274     tstr = 'Choose between Saturation and Inversion Recovery.';
    +0275     gui.popup_handles.T1type = uicontrol('Parent',gui.panels.nmr.HBox0,...
    +0276         'Style','popup','String',{'Saturation Recovery','Inversion Recovery'},...
    +0277         'Value',data.nmr.T1IRfac,'FontSize',myui.fontsize,'UserData',struct('Tooltipstr',tstr),...
    +0278         'Callback',@fv_onPopupT1Type);
    +0279     set(gui.panels.nmr.HBox0,'Widths',[cpanel_w -1]);
    +0280 
    +0281     % T1 timings
    +0282     gui.panels.nmr.HBox1 = uix.HBox('Parent',gui.panels.nmr.VBox,...
    +0283         'Spacing',3);
    +0284     gui.text_handles.timeT1 = uicontrol('Parent',gui.panels.nmr.HBox1,...
    +0285         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0286         'String','T1 recov -  min [s] | max [s] | #');
    +0287     tstr = "";
    +0288     gui.edit_handles.T1trmin = uicontrol('Parent',gui.panels.nmr.HBox1,...
    +0289         'Style','edit','String',sprintf('%5.4f',data.nmr.T1trmin),...
    +0290         'FontSize',myui.fontsize,'Tag','T1trmin',...
    +0291         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0292         'Callback',@fv_onEditValue);
    +0293     tstr = "";
    +0294     gui.edit_handles.T1trmax = uicontrol('Parent',gui.panels.nmr.HBox1,...
    +0295         'Style','edit','String',sprintf('%d',data.nmr.T1trmax),...
    +0296         'FontSize',myui.fontsize,'Tag','T1trmax',...
    +0297         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0298         'Callback',@fv_onEditValue);
    +0299     tstr = "";
    +0300     gui.edit_handles.T1trN = uicontrol('Parent',gui.panels.nmr.HBox1,...
    +0301         'Style','edit','String',sprintf('%d',data.nmr.T1trN),...
    +0302         'FontSize',myui.fontsize,'Tag','T1trN',...
    +0303         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0304         'Callback',@fv_onEditValue);
    +0305     set(gui.panels.nmr.HBox1,'Widths',[cpanel_w -1 -1 -1]);
    +0306 
    +0307     % T2 timings
    +0308     gui.panels.nmr.HBox2 = uix.HBox('Parent',gui.panels.nmr.VBox,...
    +0309         'Spacing',3);
    +0310     gui.text_handles.timeT2 = uicontrol('Parent',gui.panels.nmr.HBox2,...
    +0311         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0312         'String','T2 echo time [µs] | # echos');
    +0313     tstr = "";
    +0314     gui.edit_handles.T2te = uicontrol('Parent',gui.panels.nmr.HBox2,...
    +0315         'Style','edit','String',sprintf('%5.2f',data.nmr.T2te*1e6),...
    +0316         'FontSize',myui.fontsize,'Tag','T2te',...
    +0317         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0318         'Callback',@fv_onEditValue);
    +0319     tstr = "";
    +0320     gui.edit_handles.T2teN = uicontrol('Parent',gui.panels.nmr.HBox2,...
    +0321         'Style','edit','String',sprintf('%d',data.nmr.T2teN),...
    +0322         'FontSize',myui.fontsize,'Tag','T2teN',...
    +0323         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0324         'Callback',@fv_onEditValue);
    +0325     set(gui.panels.nmr.HBox2,'Widths',[cpanel_w -1 -1]);
    +0326     
    +0327     % noise
    +0328     gui.panels.nmr.HBox3 = uix.HBox('Parent',gui.panels.nmr.VBox,...
    +0329         'Spacing',3);
    +0330     gui.text_handles.noise = uicontrol('Parent',gui.panels.nmr.HBox3,...
    +0331         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0332         'String','Noise settings');
    +0333     tstr = ['<HTML>NMR data noise method.<br><br>',...
    +0334         'A noise level will be used globally for all NMR signals.<br>',...
    +0335         'A signal-to-ratio will be used individually on every single NMR signal.<br><br>',...
    +0336         '<u>Available options:</u><br>',...
    +0337         '<b>noise level</b> or <b>SNR</b> <br><br>',...
    +0338         '<u>Default value:</u><br>',...
    +0339         '<b>noise level</b> <br>'];
    +0340     gui.popup_handles.noisetype = uicontrol('Parent',gui.panels.nmr.HBox3,...
    +0341         'Style','popup','String',{'noise level','SNR'},...
    +0342         'Value',1,'FontSize',myui.fontsize,'UserData',struct('Tooltipstr',tstr),...
    +0343         'Callback',@fv_onPopupNoiseType);
    +0344     tstr = ['<HTML>NMR data noise.<br><br>',...
    +0345         '<u>Hint:</u><br>',...
    +0346         'You do not need to press RUN to add noise to the NMR signals.<br>',...
    +0347         'The raw NMR signals are stored internally and the noise is<br>',...
    +0348         'applied instantaneously.<br><br>',...
    +0349         '<u>Default value:</u><br>',...
    +0350         '<b>0</b><br>'];
    +0351     gui.edit_handles.noise = uicontrol('Parent',gui.panels.nmr.HBox3,...
    +0352         'Style','edit','String',num2str(data.nmr.noise),'FontSize',myui.fontsize,...
    +0353         'UserData',struct('Tooltipstr',tstr,'defaults',[data.nmr.noise 1 1]),...
    +0354         'Tag','nmr_noise','Enable','on','Callback',@fv_onEditValue);
    +0355     set(gui.panels.nmr.HBox3,'Widths',[cpanel_w -1 -1]);
    +0356 
    +0357     % Calc button
    +0358     gui.panels.nmr.HBox4 = uix.HBox('Parent',gui.panels.nmr.VBox,...
    +0359         'Spacing',3);
    +0360     uix.Empty('Parent',gui.panels.nmr.HBox4);
    +0361     tstr = 'Get NMR signals';
    +0362     gui.push_handles.nmr = uicontrol('Parent',gui.panels.nmr.HBox4,...
    +0363         'String','GET NMR SIGNALS','FontSize',myui.fontsize,'Tag','2dmod',...
    +0364         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0365         'BackGroundColor','g','Callback',@fv_getNMR);
    +0366     set(gui.panels.nmr.HBox4,'Widths',[cpanel_w -1]);
    +0367 
    +0368     % log/lin axes
    +0369     gui.panels.nmr.HBox5 = uix.HBox('Parent',gui.panels.nmr.VBox,...
    +0370         'Spacing',3);
    +0371     gui.text_handles.loglin_axes = uicontrol('Parent',gui.panels.nmr.HBox5,...
    +0372         'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',...
    +0373         'String','Echo time axes');
    +0374     tstr = "";
    +0375     gui.radio_handles.log = uicontrol('Parent',gui.panels.nmr.HBox5,...
    +0376         'Style','radiobutton','String','log','FontSize',myui.fontsize,'Tag','log',...
    +0377         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0378         'Enable','on','Value',1,'Callback',@fv_onRadioLogLin);
    +0379     gui.radio_handles.lin = uicontrol('Parent',gui.panels.nmr.HBox5,...
    +0380         'Style','radiobutton','String','lin','FontSize',myui.fontsize,'Tag','lin',...
    +0381         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0382         'Enable','on','Value',0,'Callback',@fv_onRadioLogLin);
    +0383     set(gui.panels.nmr.HBox5,'Widths',[cpanel_w -1 -1]);
    +0384 
    +0385     %% --- update MAIN GUI button ---
    +0386     gui.panels.save.HBox1 = uix.VBox('Parent',gui.left,...
    +0387         'Spacing',3);   
    +0388     tstr = 'UPDATE 2D inversion data in main NUCLEUSinv GUI.';
    +0389     gui.push_handles.update = uicontrol('Parent',gui.panels.save.HBox1,...
    +0390         'String','UPDATE MAIN GUI','FontSize',myui.fontsize,'Tag','update',...
    +0391         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0392         'Callback',@fv_onPushUpdate,'Enable','off');
    +0393     tstr = 'SAVE 2D inversion data to external file.';
    +0394     gui.push_handles.save = uicontrol('Parent',gui.panels.save.HBox1,...
    +0395         'String','SAVE RESULT','FontSize',myui.fontsize,'Tag','save',...
    +0396         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0397         'Callback',@fv_onPushSave);
    +0398     tstr = 'Export current graphics view to Figure.';
    +0399     gui.push_handles.view = uicontrol('Parent',gui.panels.save.HBox1,...
    +0400         'String','VIEW2FIG','FontSize',myui.fontsize,'Tag','view',...
    +0401         'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),...
    +0402         'Callback',@fv_onPushView);
    +0403     % set(gui.panels.save.HBox1,'Widths',[-1 -1]);
    +0404 
    +0405     % fix text vertical alignment
    +0406     jh = findjobj(gui.text_handles.diff);
    +0407     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0408     jh = findjobj(gui.text_handles.gradient);
    +0409     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0410     jh = findjobj(gui.text_handles.echo_time);
    +0411     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0412     jh = findjobj(gui.text_handles.Tbulk);
    +0413     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0414 
    +0415     jh = findjobj(gui.text_handles.rtdT1);
    +0416     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0417     jh = findjobj(gui.text_handles.rtdT2);
    +0418     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0419     
    +0420     jh = findjobj(gui.text_handles.T1type);
    +0421     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0422     jh = findjobj(gui.text_handles.timeT1);
    +0423     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0424     jh = findjobj(gui.text_handles.timeT2);
    +0425     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0426     jh = findjobj(gui.text_handles.noise);
    +0427     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0428     jh = findjobj(gui.text_handles.loglin_axes);
    +0429     jh.setVerticalAlignment(javax.swing.JLabel.CENTER);
    +0430 
    +0431     % empty space at bottom of left side
    +0432     uix.Empty('Parent',gui.left);
    +0433     % adjust the heights of all left-column-panels
    +0434     heights = [22 22 22 28 -1; 22+2*24+3*4+115 22+4*24+6*3 22+6*24+8*3 28*3 -1];
    +0435     % panel header is always 22 high
    +0436     set(gui.left,'Heights',heights(2,:),...
    +0437         'MinimumHeights',[22 22 22 28 0]);
    +0438 
    +0439     %% --- plot boxes ---
    +0440     waitbar(4/steps,hwb,'loading GUI elements - graphics');
    +0441     gui.rightPanel = uix.TabPanel('Parent',gui.right,...
    +0442         'BackGroundColor',colors.panelBG);
    +0443 
    +0444     % -- tab2
    +0445     gui.tab2 = uix.GridFlex('Parent',gui.rightPanel,...
    +0446         'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5);
    +0447 
    +0448     gui.pbox21 = uicontainer('Parent',gui.tab2,...
    +0449         'BackGroundColor',colors.panelBG);
    +0450     gui.pbox22 = uicontainer('Parent',gui.tab2,...
    +0451         'BackGroundColor',colors.panelBG);
    +0452 
    +0453     gui.pbox23 = uicontainer('Parent',gui.tab2,...
    +0454         'BackGroundColor',colors.panelBG);
    +0455     gui.pbox24 = uicontainer('Parent',gui.tab2,...
    +0456         'BackGroundColor',colors.panelBG);
    +0457 
    +0458     set(gui.tab2,'Widths',[-6 -1],'Heights',[-1 -6]);
    +0459 
    +0460     % -- tab3
    +0461     gui.tab3 = uix.VBoxFlex('Parent',gui.rightPanel,...
    +0462         'BackGroundColor',colors.panelBG,'Spacing',5);
    +0463     gui.pbox31 = uicontainer('Parent',gui.tab3,...
    +0464         'BackGroundColor',colors.panelBG);
    +0465     gui.pbox32 = uicontainer('Parent',gui.tab3,...
    +0466         'BackGroundColor',colors.panelBG);
    +0467     set(gui.tab3,'Heights',[-1 -2]);
    +0468 
    +0469     gui.rightPanel.TabTitles = {'MODEL','SIGNALS'};
    +0470     gui.rightPanel.TabWidth = 75;
    +0471     gui.rightPanel.TabEnables = {'on','on'};
    +0472 
    +0473     % -- plot axes --
    +0474     gui.axes2 = axes('Parent',gui.pbox22,'Box','on');
    +0475     gui.axes21 = axes('Parent',gui.pbox21,'Box','on');
    +0476     gui.axes24 = axes('Parent',gui.pbox24,'Box','on');
    +0477     gui.axes31 = axes('Parent',gui.pbox31,'Box','on');
    +0478     gui.axes32 = axes('Parent',gui.pbox32,'Box','on');
    +0479 
    +0480     % --- store main GUI settings ---
    +0481     gui.myui = nucleus.gui.myui;
    +0482     gui.myui.heights = heights;
    +0483     gui.figh_nucleus = figh_nucleus;
    +0484 
    +0485     % --- save gui data to GUI ---
    +0486     setappdata(fig_2Dmod,'gui',gui);
    +0487     setappdata(fig_2Dmod,'data',data);
    +0488 
    +0489     % make GUI visible
    +0490     delete(hwb);
    +0491     set(gui.main,'Visible','on');
    +0492 else
    +0493     % if the figure is already open bring t to the front
    +0494     figure(fig_2Dmod);
    +0495 end
    +0496 
    +0497 % trigger the model update pushbutton for the initial view
    +0498 fv_getModel(fig_2Dmod);
    +0499 beautifyAxes(fig_2Dmod);
    +0500 end
    +0501 
    +0502 %% subfunction to update the table entries
    +0503 function fv_onEditTable(src,~)
    +0504 figh = ancestor(src,'figure','toplevel');
    +0505 fv_getModel(figh)
    +0506 
    +0507 end
    +0508 
    +0509 %% subfunction to update the edit fields
    +0510 function fv_onEditValue(src,~)
    +0511 figh = ancestor(src,'figure','toplevel');
    +0512 gui = getappdata(figh,'gui');
    +0513 data = getappdata(figh,'data');
    +0514 
    +0515 switch get(src,'Tag')
    +0516     case {'diff','gradient','Tbulk'}
    +0517         data.prop.D = str2double(get(gui.edit_handles.diff,'String'))/1e9;
    +0518         data.prop.G0 = str2double(get(gui.edit_handles.gradient,'String'));        
    +0519         data.prop.Tbulk = str2double(get(gui.edit_handles.Tbulk,'String'));
    +0520     case {'rtdT1min','rtdT1max','rtdT1N'}
    +0521         data.mod.T1min = str2double(get(gui.edit_handles.rtdT1min,'String'));
    +0522         data.mod.T1max = str2double(get(gui.edit_handles.rtdT1max,'String'));
    +0523         data.mod.T1N = str2double(get(gui.edit_handles.rtdT1N,'String'));
    +0524         setappdata(figh,'data',data);
    +0525         fv_getModel(gui.push_handles.model);
    +0526         data = getappdata(figh,'data');
    +0527     case {'rtdT2min','rtdT2max','rtdT2N'}
    +0528         data.mod.T2min = str2double(get(gui.edit_handles.rtdT2min,'String'));
    +0529         data.mod.T2max = str2double(get(gui.edit_handles.rtdT2max,'String'));
    +0530         data.mod.T2N = str2double(get(gui.edit_handles.rtdT2N,'String'));
    +0531         setappdata(figh,'data',data);
    +0532         fv_getModel(gui.push_handles.model);
    +0533         data = getappdata(figh,'data');
    +0534      case {'T1trmin','T1trmax','T1trN'}
    +0535         data.nmr.T1trmin = str2double(get(gui.edit_handles.T1trmin,'String'));
    +0536         data.nmr.T1trmax = str2double(get(gui.edit_handles.T1trmax,'String'));
    +0537         data.nmr.T1trN = str2double(get(gui.edit_handles.T1trN,'String'));
    +0538     case {'T2te','T2teN'}
    +0539         data.nmr.T2te = str2double(get(gui.edit_handles.T2te,'String'))/1e6;
    +0540         data.nmr.T2teN = str2double(get(gui.edit_handles.T2teN,'String'));
    +0541 
    +0542         data.prop.te = data.nmr.T2te;
    +0543         set(gui.edit_handles.echo_time,'String',data.prop.te*1e6);
    +0544     case {'nmr_noise'}
    +0545         data.nmr.noise = str2double(get(gui.edit_handles.noise,'String'));
    +0546         switch data.nmr.noisetype
    +0547             case 'level'
    +0548             case 'SNR'
    +0549                 if data.nmr.noise == 0
    +0550                     data.nmr.noise = Inf;
    +0551                     set(src,'String',num2str(data.nmr.noise));
    +0552                 end
    +0553         end
    +0554         setappdata(figh,'data',data);
    +0555         if isfield(data.results.mod2D,'data')
    +0556             fv_addNoise(figh)
    +0557             data = getappdata(figh,'data');
    +0558         end        
    +0559 end
    +0560 
    +0561 % update GUI data
    +0562 setappdata(figh,'data',data);
    +0563 end
    +0564 
    +0565 %% subfunction to set the T1 type
    +0566 function fv_onPopupT1Type(src,~)
    +0567 figh = ancestor(src,'figure','toplevel');
    +0568 data = getappdata(figh,'data');
    +0569 
    +0570 switch get(src,'Value')
    +0571     case 1 % Saturation Recovery
    +0572         data.nmr.T1IRfac = 1;
    +0573     case 2 % Inversion Recovery
    +0574         data.nmr.T1IRfac = 2;
    +0575 end
    +0576 
    +0577 % update GUI data
    +0578 setappdata(figh,'data',data);
    +0579 end
    +0580 
    +0581 %% subfunction to set the NMR data noise type
    +0582 function fv_onPopupNoiseType(src,~)
    +0583 figh = ancestor(src,'figure','toplevel');
    +0584 gui = getappdata(figh,'gui');
    +0585 data = getappdata(figh,'data');
    +0586 
    +0587 % change settings accordingly
    +0588 switch get(src,'Value')
    +0589     case 1 % noise level
    +0590         data.nmr.noisetype = 'level';
    +0591         if data.nmr.noise > 0
    +0592             data.nmr.noise = 1/data.nmr.noise;
    +0593         end        
    +0594     case 2 % signal-to-noise ratio (SNR)
    +0595         data.nmr.noisetype = 'SNR';
    +0596         if data.nmr.noise == 0
    +0597             data.nmr.noise = inf;
    +0598         else
    +0599             data.nmr.noise = 1/data.nmr.noise;
    +0600         end        
    +0601 end
    +0602 % update the corresponding edit field
    +0603 set(gui.edit_handles.noise,'String',num2str(data.nmr.noise));
    +0604 
    +0605 % update GUI data
    +0606 setappdata(figh,'data',data);
    +0607 % update NMR data (if available)
    +0608 if isfield(data.results.mod2D,'data')
    +0609     fv_addNoise(figh);
    +0610 end
    +0611 
    +0612 end
    +0613 
    +0614 %% subfunction to set the T1 t<pe
    +0615 function fv_addNoise(figh)
    +0616 data = getappdata(figh,'data');
    +0617 mod2D = data.results.mod2D;
    +0618 
    +0619 % first check what is the noise type
    +0620 switch data.nmr.noisetype
    +0621     case 'level'
    +0622         noise = data.nmr.noise;
    +0623     case 'SNR'
    +0624         SNR = data.nmr.noise;
    +0625         noise = 1./SNR;
    +0626 end
    +0627 
    +0628 if noise > 0
    +0629     for n = 1:numel(mod2D.data)
    +0630         mod2D.data(n).noise = noise;
    +0631         [re,im] = addNoiseToSignal(mod2D.data(n).s_raw,0,noise);
    +0632         mod2D.data(n).s = complex(re,im);
    +0633     end
    +0634 else
    +0635     % reset the NMR signals with the raw data (without noise)
    +0636     for n = 1:numel(mod2D.data)
    +0637         mod2D.data(n).noise = 0;
    +0638         mod2D.data(n).s = complex(mod2D.data(n).s_raw,zeros(size(mod2D.data(n).s_raw)));
    +0639     end
    +0640 end
    +0641 
    +0642 % update the GUI data
    +0643 data.results.mod2D = mod2D;
    +0644 setappdata(figh,'data',data);
    +0645 % plot all signals
    +0646 fv_plotSignals(figh);
    +0647 beautifyAxes(figh);
    +0648 end
    +0649 
    +0650 %% subfunction to get the 2D model
    +0651 function fv_getModel(figh)
    +0652 % figh = ancestor(src,'figure','toplevel');
    +0653 gui = getappdata(figh,'gui');
    +0654 data = getappdata(figh,'data');
    +0655 
    +0656 % create model space from relaxation time T vectors
    +0657 T1min = data.mod.T1min;
    +0658 T1max = data.mod.T1max;
    +0659 T1N = data.mod.T1N;
    +0660 T2min = data.mod.T2min;
    +0661 T2max = data.mod.T2max;
    +0662 T2N = data.mod.T2N;
    +0663 
    +0664 T1vec = logspace(log10(T1min),log10(T1max),T1N);
    +0665 T2vec = logspace(log10(T2min),log10(T2max),T2N);
    +0666 MOD = zeros(numel(T1vec),numel(T2vec));
    +0667 
    +0668 [X1,X2] = meshgrid(T2vec,T1vec);
    +0669 X = [X1(:) X2(:)];
    +0670 
    +0671 % get table with model parameters
    +0672 table = get(gui.table_handles.mod,'Data');
    +0673 data.results.mod2D.table = table;
    +0674 % create distributions
    +0675 for nn = 1:size(table,1)
    +0676     if table{nn,1}
    +0677         % muX muY
    +0678         mu = [table{nn,2} table{nn,3}];
    +0679         % sigma = [xx xy; yx yy]
    +0680         Sigma = [table{nn,4} table{nn,6}; table{nn,7} table{nn,5}];
    +0681         % get multivariate distribution of linearized data
    +0682         p = getMultivariateGaussian(log10(X), log10(mu), Sigma);
    +0683         p = reshape(p,T1N,T2N);
    +0684         Amp = table{nn,8};
    +0685         MOD = MOD + Amp*p./max(p(:));
    +0686     end
    +0687 end
    +0688 
    +0689 if any(isnan(MOD))
    +0690     MOD = ones(size(MOD));
    +0691 end
    +0692 
    +0693 % normalize to 1
    +0694 MOD = MOD./sum(MOD(:));
    +0695 
    +0696 data.results.mod2D.T1vec = T1vec;
    +0697 data.results.mod2D.T2vec = T2vec;
    +0698 data.results.mod2D.MOD = MOD;
    +0699 % update GUI data
    +0700 setappdata(figh,'data',data);
    +0701 % update plot
    +0702 fv_plotModel(figh);
    +0703 beautifyAxes(figh);
    +0704 end
    +0705 
    +0706 %% subfunction to calculate the NMR signals
    +0707 function fv_getNMR(src,~)
    +0708 figh = ancestor(src,'figure','toplevel');
    +0709 gui = getappdata(figh,'gui');
    +0710 data = getappdata(figh,'data');
    +0711 mod2D = data.results.mod2D;
    +0712 
    +0713 % prepare parameters
    +0714 % IR / SR factor
    +0715 T1IRfac = data.nmr.T1IRfac;
    +0716 IRtype = data.nmr.IRtype;
    +0717 
    +0718 % get system properties
    +0719 D = data.prop.D;
    +0720 G0 = data.prop.G0;
    +0721 te = data.prop.te;
    +0722 Tbulk = data.prop.Tbulk;
    +0723 
    +0724 T1vec = mod2D.T1vec;
    +0725 T2vec = mod2D.T2vec;
    +0726 
    +0727 % disable the RUN button to indicate a running inversion
    +0728 set(gui.push_handles.nmr,'String','RUNNING ...',...
    +0729     'BackgroundColor',get(gui.push_handles.update,'BackgroundColor'),...
    +0730     'Enable','off'); pause(0.01);
    +0731 
    +0732 % prepare data
    +0733 % T2 time vector
    +0734 t2 = getNMRTimeVector(data.nmr.T2te,'s','N',data.nmr.T2teN);
    +0735 T1 = logspace(log10(data.nmr.T1trmin),log10(data.nmr.T1trmax),data.nmr.T1trN);
    +0736 dat = struct;
    +0737 for n = 1:numel(T1)
    +0738     dat(n).t = t2;
    +0739     dat(n).s = zeros(size(t2));
    +0740     dat(n).T1 = T1(n);
    +0741 end
    +0742 
    +0743 % create the Kernel matrix for inversion
    +0744 p.G0 = G0;
    +0745 p.D = D;
    +0746 p.te = te;
    +0747 p.Tbulk = Tbulk;
    +0748 p.T1IRfac = T1IRfac;
    +0749 p.IRtype = IRtype;
    +0750 [K,indices] = createKernelMatrix2D(dat,T1vec,T2vec,p);
    +0751 
    +0752 MODvec = reshape(mod2D.MOD',size(mod2D.MOD,1)*size(mod2D.MOD,2),1);
    +0753 RESvec = K*MODvec;
    +0754 
    +0755 for n = 1:numel(T1)
    +0756     dat(n).s = RESvec(indices.lin_1(n):indices.lin_end(n));
    +0757     dat(n).s_raw = RESvec(indices.lin_1(n):indices.lin_end(n));
    +0758 end
    +0759 
    +0760 % enable the RN button
    +0761 set(gui.push_handles.nmr,'String','GET NMR SIGNALS',...
    +0762     'BackgroundColor','g','Enable','on','Callback',@fv_getNMR);
    +0763 setappdata(figh,'gui',gui);
    +0764 
    +0765 % save results
    +0766 data.results.mod2D.t2 = t2;
    +0767 data.results.mod2D.t_recov = T1;
    +0768 data.results.mod2D.data = dat;
    +0769 
    +0770 % update data
    +0771 setappdata(figh,'data',data);
    +0772 fv_addNoise(figh)
    +0773 
    +0774 % plot all signals
    +0775 fv_plotSignals(figh);
    +0776 beautifyAxes(figh);
    +0777 gui.rightPanel.Selection = 2;
    +0778 end
    +0779 
    +0780 %% subfunction to export the 2D inversion data
    +0781 function fv_onPushSave(src,~)
    +0782 figh = ancestor(src,'figure','toplevel');
    +0783 % local GUI data
    +0784 data = getappdata(figh,'data');
    +0785 
    +0786 % get data path to save inversion results
    +0787 [sfile,spath] = uiputfile('*.mat','Select File for Save',...
    +0788     fullfile(pwd,'2Dmoddata.mat'));
    +0789 % if user did not cancel, procceed
    +0790 if sfile > 0
    +0791     moddata = data;
    +0792     save(fullfile(spath,sfile),'moddata');
    +0793     disp('2D Modeling data saved to: ');
    +0794     disp(fullfile(spath,sfile));
    +0795 else
    +0796     disp('Save cancelled.');
    +0797 end
    +0798 
    +0799 end
    +0800 
    +0801 %% subfunction to export the current view to a figure
    +0802 function fv_onPushView(src,~)
    +0803 figh = ancestor(src,'figure','toplevel');
    +0804 % local GUI data
    +0805 gui = getappdata(figh,'gui');
    +0806 
    +0807 % opening the export figure
    +0808 expfig = figure('Color',gui.myui.colors.panelBG);
    +0809 
    +0810 % create axes layout depending on view
    +0811 switch get(gui.rightPanel,'Selection')
    +0812     case 1
    +0813         % create layout
    +0814         ax1 = subplot(5,5,[1 2 3 4],'Parent',expfig);
    +0815         ax2 = subplot(5,5,[6:9 11:14 16:19 21:24],'Parent',expfig);
    +0816         ax3 = subplot(5,5,[10 15 20 25],'Parent',expfig);
    +0817         % get positions
    +0818         pos1 = get(ax1,'Position');
    +0819         pos2 = get(ax2,'Position');
    +0820         pos3 = get(ax3,'Position');
    +0821         % delete axes
    +0822         delete(ax1);delete(ax2);delete(ax3);
    +0823         % copy GUI axes
    +0824         ax1 = copyobj(gui.axes21,expfig);
    +0825         ax2 = copyobj(gui.axes2,expfig);
    +0826         ax3 = copyobj(gui.axes24,expfig);
    +0827         % adjust positions
    +0828         set(ax1,'Position',pos1);
    +0829         set(ax2,'Position',pos2);
    +0830         set(ax3,'Position',pos3);
    +0831     case 2
    +0832         % create layout
    +0833         ax1 = subplot(7,1,[1 2],'Parent',expfig);
    +0834         ax2 = subplot(7,1,[4 5 6 7],'Parent',expfig);
    +0835         % get positions
    +0836         pos1 = get(ax1,'Position');
    +0837         pos2 = get(ax2,'Position');
    +0838         % delete axes
    +0839         delete(ax1);delete(ax2);
    +0840         % copy GUI axes
    +0841         ax1 = copyobj(gui.axes31,expfig);
    +0842         ax2 = copyobj(gui.axes32,expfig);
    +0843         % adjust positions
    +0844         set(ax1,'Position',pos1);
    +0845         set(ax2,'Position',pos2);
    +0846 end
    +0847 
    +0848 end
    +0849 
    +0850 %% subfunction to update the main NUCLEUSinv GUI
    +0851 function fv_onPushUpdate(src,~)
    +0852 figh = ancestor(src,'figure','toplevel');
    +0853 % local GUI data
    +0854 uvgui = getappdata(figh,'gui');
    +0855 uvdata = getappdata(figh,'data');
    +0856 % NUCLEUSinv data
    +0857 gui = getappdata(uvgui.figh_nucleus,'gui');
    +0858 INVdata = getappdata(uvgui.figh_nucleus,'INVdata');
    +0859 data = getappdata(uvgui.figh_nucleus,'data');
    +0860 
    +0861 % loop over all signals
    +0862 E_inv = zeros(size(uvdata.results.T1T2map.t_recov));
    +0863 for id = 1:numel(INVdata)
    +0864     % the standard INVdata struct
    +0865     INVdata{id} = [];
    +0866     
    +0867     % old, slow but consistent way
    +0868     % trigger the listbox entry
    +0869     % set(gui.listbox_handles.signal,'Value',id);
    +0870     % onListboxData(gui.listbox_handles.signal);
    +0871     % no gating
    +0872     % which radiobutton ('log', 'lin' or 'none')
    +0873     % onRadioGates(gui.radio_handles.process_gates_none);
    +0874     % get the fresh data
    +0875     % data = getappdata(uvgui.figh_nucleus,'data');
    +0876     
    +0877     % new, fast and hopefully consistent :-) way
    +0878     data.process.start = 1;
    +0879     data.process.end = numel(uvdata.results.T1T2map.import{id}.time);
    +0880     data.process.gatetype = 'raw';
    +0881     % update 2Dinv GUI settings
    +0882     data.inv2D.prop = uvdata.prop;
    +0883     data.inv2D.inv = uvdata.inv;
    +0884     data.inv2D.info = uvdata.info;
    +0885     % create raw data struct
    +0886     data.results.nmrraw.t = uvdata.results.T1T2map.import{id}.time;
    +0887     data.results.nmrraw.s = uvdata.results.T1T2map.import{id}.signal;
    +0888     if id == numel(INVdata)
    +0889         data.results.nmrraw.noise = uvdata.results.T1T2map.import{id}.noise;
    +0890         data.results.nmrproc.T1T2 = 'T1';
    +0891         data.results.nmrproc.T1IRfac = 2;
    +0892     else
    +0893         data.results.nmrraw.phase = uvdata.results.T1T2map.import{id}.phase;
    +0894     end
    +0895     % create proc data struct
    +0896     data.results.nmrproc.start = 1;
    +0897     data.results.nmrproc.end = numel(uvdata.results.T1T2map.import{id}.time);
    +0898     data.results.nmrproc.gatetype = 'raw';
    +0899     data.results.nmrproc.t = uvdata.results.T1T2map.import{id}.time;
    +0900     data.results.nmrproc.s = real(uvdata.results.T1T2map.import{id}.signal);
    +0901     data.results.nmrproc.N = ones(size(data.results.nmrproc.s));
    +0902     if isfield(uvdata.results.T1T2map.import{id},'noise')
    +0903         data.results.nmrproc.noise = uvdata.results.T1T2map.import{id}.noise;
    +0904     else
    +0905         range = floor(numel(data.results.nmrproc.s)/2):numel(data.results.nmrproc.s);
    +0906         data.results.nmrproc.noise = std(imag(uvdata.results.T1T2map.import{id}.signal(range)));
    +0907     end
    +0908     data.results.nmrproc.e = data.results.nmrproc.noise*ones(size(data.results.nmrproc.s));
    +0909     if isfield(data.results.nmrproc,'W')
    +0910         data.results.nmrproc = rmfield(data.results.nmrproc,'W');
    +0911     end
    +0912 
    +0913     % and use it for the INVdata
    +0914     INVdata{id} = data;
    +0915     INVdata{id} = rmfield(INVdata{id},'import');
    +0916     INVdata{id} = rmfield(INVdata{id},'info');
    +0917     INVdata{id} = rmfield(INVdata{id},'calib');
    +0918     INVdata{id} = rmfield(INVdata{id},'pressure');
    +0919 
    +0920     % now add a dummy "invstd" field
    +0921     if id == numel(INVdata)
    +0922         % for the final merged T1
    +0923         INVdata{id}.results.invstd.fit_t = uvdata.results.T1T2map.t_recov;
    +0924         INVdata{id}.results.invstd.fit_s = E_inv;
    +0925         INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.E0;
    +0926         INVdata{id}.results.invstd.ciE0 = NaN;
    +0927         out = getFitErrors(uvdata.results.T1T2map.E_raw(:,1),E_inv,data.results.nmrproc.noise);
    +0928         INVdata{id}.results.invstd.resnorm = out.resnorm;
    +0929         INVdata{id}.results.invstd.residual = out.residual;
    +0930         INVdata{id}.results.invstd.chi2 = out.chi2;
    +0931         INVdata{id}.results.invstd.rms = out.rms;
    +0932     else
    +0933         % for the individual signals
    +0934         INVdata{id}.results.invstd.fit_t = uvdata.results.inv2D.data(id).t;
    +0935         INVdata{id}.results.invstd.fit_s = uvdata.results.inv2D.data(id).s_fit;
    +0936         E_inv(id,1) = uvdata.results.inv2D.data(id).s_fit(1);
    +0937         INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.data(id).s_fit(1);
    +0938         INVdata{id}.results.invstd.ciE0 = NaN;
    +0939         INVdata{id}.results.invstd.resnorm = uvdata.results.inv2D.data(id).resnorm;
    +0940         INVdata{id}.results.invstd.residual = uvdata.results.inv2D.data(id).residual;
    +0941         INVdata{id}.results.invstd.chi2 = uvdata.results.inv2D.data(id).chi2;
    +0942         INVdata{id}.results.invstd.rms = uvdata.results.inv2D.data(id).rms;
    +0943     end
    +0944     INVdata{id}.results.invstd.lambda_out = 1;
    +0945     INVdata{id}.results.invstd.xn = 0;
    +0946     INVdata{id}.results.invstd.rn = 0;
    +0947     INVdata{id}.results.invstd.invtype = data.invstd.invtype;
    +0948     INVdata{id}.results.invstd.invparams = NaN;
    +0949     if id == numel(INVdata)
    +0950         INVdata{id}.results.inv2D = uvdata.results.inv2D;
    +0951     else
    +0952         INVdata{id}.results.inv2D = true;
    +0953     end
    +0954 
    +0955     % color the corresponding list entries in the main GUI
    +0956     strL = get(gui.listbox_handles.signal,'String');
    +0957     str1 = strL{id};
    +0958     str2 = ['<HTML><BODY bgcolor="rgb(',...
    +0959         sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',str1,'</BODY></HTML>'];
    +0960     strL{id} = str2;
    +0961     set(gui.listbox_handles.signal,'String',strL);
    +0962 end
    +0963 
    +0964 % update GUI INVdata
    +0965 setappdata(uvgui.figh_nucleus,'INVdata',INVdata);
    +0966 
    +0967 % set focus on first signal
    +0968 set(gui.listbox_handles.signal,'Value',1);
    +0969 onListboxData(gui.listbox_handles.signal);
    +0970 end
    +0971 
    +0972 %% subfunction to update all plots
    +0973 function fv_plotSignals(figh)
    +0974 gui = getappdata(figh,'gui');
    +0975 data = getappdata(figh,'data');
    +0976 mod2D = data.results.mod2D;
    +0977 data_mod = mod2D.data;
    +0978 col = gui.myui.colors;
    +0979 
    +0980 % clear axes
    +0981 clearSingleAxis(gui.axes31);
    +0982 clearSingleAxis(gui.axes32);
    +0983 hold(gui.axes31,'on');
    +0984 hold(gui.axes32,'on');
    +0985 
    +0986 % define some axes settings
    +0987 log_t_ticks = logspace(-5,2,8);
    +0988 t_recov_lims = [min(mod2D.t_recov)/2 max(mod2D.t_recov)*2];
    +0989 
    +0990 % prepare the data for the combined T1 curve
    +0991 E_mod = zeros(size(mod2D.t_recov));
    +0992 for nn = 1:numel(data_mod)
    +0993     E_mod(nn,1) = data_mod(nn).s(1);
    +0994     % plot individual T2 signals and fits
    +0995     plot3(data_mod(nn).t,data_mod(nn).T1*ones(size(data_mod(nn).s)),...
    +0996         data_mod(nn).s,'Color',col.axisL,'DisplayName','T2 signals',...
    +0997         'LineWidth',1,'Parent',gui.axes32);
    +0998 end
    +0999 view(gui.axes32,[30 20]);
    +1000 set(gui.axes32,'XScale','log','XTick',log_t_ticks);
    +1001 set(gui.axes32,'YScale','log','YDir','normal','YTick',log_t_ticks,'YLim',t_recov_lims);
    +1002 set(get(gui.axes32,'XLabel'),'String','time [s]');
    +1003 set(get(gui.axes32,'YLabel'),'String','recovery time t_{rec} [s]');
    +1004 set(get(gui.axes32,'ZLabel'),'String','amplitude [a.u.]');
    +1005 % fv_fixLabel3DAxes(gui.axes32)
    +1006 
    +1007 % tab 3 - combined T1 curve and fit
    +1008 plot(mod2D.t_recov,E_mod(:,1),'o-','Color',col.axisL,...
    +1009     'LineWidth',1,'DisplayName','T1 curve','Parent',gui.axes31);
    +1010 set(gui.axes31,'XScale','log','XLim',t_recov_lims);
    +1011 set(gui.axes31,'YScale','lin');
    +1012 set(get(gui.axes31,'XLabel'),'String','recovery time t_{rec} [s]');
    +1013 set(get(gui.axes31,'YLabel'),'String','mean(E(1:3)) [a.u.]');
    +1014 legend(gui.axes31,'Location','SouthEast');
    +1015 
    +1016 % hold off all axes
    +1017 hold(gui.axes31,'off');
    +1018 hold(gui.axes32,'off');
    +1019 
    +1020 % call function to adapt the axes scaling
    +1021 fv_setAxesScaling(figh);
    +1022 end
    +1023 
    +1024 %%  subfunction to plot the raw data
    +1025 function fv_plotModel(figh)
    +1026 gui = getappdata(figh,'gui');
    +1027 data = getappdata(figh,'data');
    +1028 col = gui.myui.colors;
    +1029 mod2D = data.results.mod2D;
    +1030 
    +1031 clearSingleAxis(gui.axes2);
    +1032 clearSingleAxis(gui.axes21);
    +1033 clearSingleAxis(gui.axes24);
    +1034 hold(gui.axes2,'on');
    +1035 hold(gui.axes21,'on');
    +1036 hold(gui.axes24,'on');
    +1037 
    +1038 log_t_ticks = logspace(-5,2,8);
    +1039 
    +1040 % tab 2 - 2D inversion model
    +1041 [X,Y] = meshgrid(mod2D.T2vec,mod2D.T1vec);
    +1042 imagescnan(X,Y,mod2D.MOD,'Parent',gui.axes2);
    +1043 plot([1e-5 100],[1e-5 100],...
    +1044     '--','Color','w','LineWidth',1,'Parent',gui.axes2);
    +1045 view(gui.axes2,[0 90]);
    +1046 set(gui.axes2,'XScale','log','XTick',log_t_ticks,...
    +1047     'XLim',[min(mod2D.T2vec) max(mod2D.T2vec)]);
    +1048 set(gui.axes2,'YScale','log','XTick',log_t_ticks,...
    +1049     'YLim',[min(mod2D.T1vec) max(mod2D.T1vec)],'YDir','normal');
    +1050 set(get(gui.axes2,'XLabel'),'String','relaxation time T2 [s]');
    +1051 set(get(gui.axes2,'YLabel'),'String','relaxation time T1 [s]');
    +1052 set(gui.axes2,'Layer','top','XGrid','off','YGrid','off');
    +1053 
    +1054 % sum along each dimension to get both RTDs
    +1055 T1rtd = sum(mod2D.MOD,2);
    +1056 T2rtd = sum(mod2D.MOD,1);
    +1057 % find common maximum for y-axis setting
    +1058 ymax = max([max(T1rtd) max(T2rtd)])*1.1;
    +1059 % T1 RTD
    +1060 plot(T1rtd,mod2D.T1vec,'Color',col.axisL,'Parent',gui.axes24);
    +1061 set(gui.axes24,'XScale','lin','XLim',[0 ymax]);
    +1062 set(gui.axes24,'YScale','log','YTickLabel','');
    +1063 
    +1064 % T2 RTD
    +1065 plot(mod2D.T2vec,T2rtd,'Color',col.axisL,'DisplayName','RTD','Parent',gui.axes21);
    +1066 set(gui.axes21,'YScale','lin','YLim',[0 ymax]);
    +1067 set(gui.axes21,'XScale','log','XTickLabel','');
    +1068 
    +1069 hold(gui.axes2,'off');
    +1070 hold(gui.axes21,'off');
    +1071 hold(gui.axes24,'off');
    +1072 end
    +1073 
    +1074 %% subfunction zo switch x-axis scaling
    +1075 function fv_onRadioLogLin(src,~)
    +1076 figh = ancestor(src,'figure','toplevel');
    +1077 gui = getappdata(figh,'gui');
    +1078 % get tag of the radio menu
    +1079 tag = get(src,'Tag');
    +1080 val = get(src,'Value');
    +1081 
    +1082 switch tag
    +1083     case 'log'
    +1084         switch val
    +1085             case 1 % log should be used
    +1086                 set(gui.radio_handles.lin,'Value',0);
    +1087             case 0 % lin should be used
    +1088                 set(gui.radio_handles.lin,'Value',1);
    +1089         end
    +1090     case 'lin'
    +1091         switch val
    +1092             case 1 % lin should be used
    +1093                 set(gui.radio_handles.log,'Value',0);
    +1094             case 0 % log should be used
    +1095                 set(gui.radio_handles.log,'Value',1);
    +1096         end
    +1097 end
    +1098 % update GUI data
    +1099 setappdata(figh,'gui',gui);
    +1100 
    +1101 % call function to adapt the axes scaling
    +1102 fv_setAxesScaling(figh);
    +1103 end
    +1104 
    +1105 %% subfunction to switch x-axis scaling log<->lin
    +1106 function fv_setAxesScaling(figh)
    +1107 gui = getappdata(figh,'gui');
    +1108 
    +1109 uselog = get(gui.radio_handles.log,'Value');
    +1110 switch uselog
    +1111     case 1
    +1112         log_t_ticks = logspace(-5,2,8);
    +1113         set(gui.axes32,'XScale','log','XTick',log_t_ticks);
    +1114     case 0
    +1115         set(gui.axes32,'XScale','lin','XTickMode','auto');
    +1116 end
    +1117 
    +1118 end
    +1119 
    +1120 %% close function
    +1121 function fv_closeme(src,~)
    +1122 figh = ancestor(src,'figure','toplevel');
    +1123 % try to close the sub GUI in a clean manner
    +1124 try
    +1125     % NOTE: maybe needed at some later point
    +1126     %     gui = getappdata(figh,'gui');
    +1127     %     data = getappdata(gui.figh_nucleus,'data');
    +1128     %     % update NUCLEUSinv
    +1129     %     setappdata(gui.figh_nucleus,'data',data);
    +1130     delete(figh);
    +1131 catch
    +1132     % if this is not working: just close it
    +1133     delete(figh);
    +1134 end
    +1135 
    +1136 end
    +1137 
    +1138 %------------- END OF CODE --------------
    +1139 
    +1140 %% License:
    +1141 % MIT License
    +1142 %
    +1143 % Copyright (c) 2024 Thomas Hiller
    +1144 %
    +1145 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +1146 % of this software and associated documentation files (the "Software"), to deal
    +1147 % in the Software without restriction, including without limitation the rights
    +1148 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +1149 % copies of the Software, and to permit persons to whom the Software is
    +1150 % furnished to do so, subject to the following conditions:
    +1151 %
    +1152 % The above copyright notice and this permission notice shall be included in all
    +1153 % copies or substantial portions of the Software.
    +1154 %
    +1155 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +1156 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +1157 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +1158 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +1159 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +1160 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +1161 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/interface/PhaseView.html b/doc/nucleus/functions/interface/PhaseView.html index d9a8132..4b89c67 100644 --- a/doc/nucleus/functions/interface/PhaseView.html +++ b/doc/nucleus/functions/interface/PhaseView.html @@ -4,7 +4,7 @@ Description of PhaseView - + @@ -20,13 +20,13 @@

    PhaseView

    PURPOSE ^

    -
    is an extra subGUI to visualize the phase of a T2 signal
    +
    is an extra subGUI to manipulate the phase of a T2 signal

    SYNOPSIS ^

    function PhaseView(src,~)

    DESCRIPTION ^

    -
    PhaseView is an extra subGUI to visualize the phase of a T2 signal
    +
    PhaseView is an extra subGUI to manipulate the phase of a T2 signal
     
      Syntax:
            PhaseView
    @@ -41,15 +41,21 @@ 

    DESCRIPTION ^DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • onListboxData handles the calls from the context menu of the data
  • onMenuView handles the view menu entries
  • clearAllAxes clears all axes of a given figure
  • clearSingleAxis clears an individual axis
  • minimizePanel handles the minimization/maximization of all box-panels for
  • fitDataFree is a control routine that uses 'lsqcurvefit' to fit NMR data
  • This function is called by:
    • onListboxData handles the calls from the context menu of the data
    • onMenuSubGUIs handles the extra menu entries to open NUCLEUS sub GUIs
    @@ -71,11 +77,11 @@

    CROSS-REFERENCE INFORMATION ^
 
 <h2><a name=SUBFUNCTIONS ^

    +
  • function pv_onEditValue(src,~)
  • function pv_onPushAngle(src,~)
  • function pv_onPushApply(src,~)
  • function pv_onPushKeep(src,~)
  • function pv_onPushRun(src,~)
  • function sse = phasefit_fcn(alpha,s,method)
  • function pv_onSlider(src,~)
  • function pv_updateFullDataSet(fig_phase)
  • function pv_plotSignal(fig_phase)
  • function pv_plotSSR(fig_phase)
  • function ssr = getSSR(signal)
  • SOURCE CODE ^

    0001 function PhaseView(src,~)
    -0002 %PhaseView is an extra subGUI to visualize the phase of a T2 signal
    +0002 %PhaseView is an extra subGUI to manipulate the phase of a T2 signal
     0003 %
     0004 % Syntax:
     0005 %       PhaseView
    @@ -90,364 +96,857 @@ 

    SOURCE CODE ^% PhaseView(src,~) 0015 % 0016 % Other m-files required: -0017 % none -0018 % -0019 % Subfunctions: -0020 % pv_onPushDefault -0021 % pv_onPushSave -0022 % pv_showSignal -0023 % pv_updateSlider -0024 % pv_updatePhase -0025 % shift_phase -0026 % -0027 % MAT-files required: -0028 % none -0029 % -0030 % See also: NUCLEUSinv -0031 % Author: see AUTHORS.md -0032 % email: see AUTHORS.md -0033 % License: MIT License (at end) -0034 -0035 %------------- BEGIN CODE -------------- -0036 -0037 %% get GUI handle and data -0038 fig = ancestor(src,'figure','toplevel'); -0039 nucleus.data = getappdata(fig,'data'); -0040 nucleus.gui = getappdata(fig,'gui'); -0041 colors = nucleus.gui.myui.colors; +0017 % onListboxData +0018 % onMenuView +0019 % +0020 % Subfunctions: +0021 % getSSR +0022 % phasefit_fcn +0023 % pv_onEditValues +0024 % pv_onPushAngle +0025 % pv_onPushApply +0026 % pv_onPushKeep +0027 % pv_onPushRun +0028 % pv_onSlider +0029 % pv_plotSignal +0030 % pv_plotSSR +0031 % pv_updateFullDataSet +0032 % +0033 % MAT-files required: +0034 % none +0035 % +0036 % See also: NUCLEUSinv +0037 % Author: see AUTHORS.md +0038 % email: see AUTHORS.md +0039 % License: MIT License (at end) +0040 +0041 %------------- BEGIN CODE -------------- 0042 -0043 hasData = false; -0044 if isfield(nucleus.data,'results') -0045 if isfield(nucleus.data.results,'nmrraw') &&... -0046 isfield(nucleus.data.results,'nmrproc') -0047 hasData = true; -0048 end -0049 end -0050 -0051 %% proceed if there is data -0052 if hasData -0053 % check if the figure is already open -0054 fig_phase = findobj('Tag','PHASEVIEW'); -0055 % if not, create it -0056 if isempty(fig_phase) -0057 % draw the figure on top of NUCLEUSinv -0058 fig_phase = figure('Name','NUCLEUSinv - PhaseView',... -0059 'NumberTitle','off','ToolBar','none','Tag','PHASEVIEW'); -0060 pos0 = get(fig,'Position'); -0061 pos1 = get(fig_phase,'Position'); -0062 cent(1) = (pos0(1)+pos0(3)/2); -0063 cent(2) = (pos0(2)+pos0(4)/2); -0064 set(fig_phase,'Position',[cent(1)-pos0(3)/3 pos0(2) pos0(3)/1.5 pos0(4)]); -0065 -0066 % create the layout -0067 gui.main = uix.VBox('Parent',fig_phase,'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); -0068 gui.row1 = uicontainer('Parent',gui.main,'BackGroundColor',colors.panelBG); % axes real -0069 gui.row2 = uicontainer('Parent',gui.main,'BackGroundColor',colors.panelBG); % axes imag -0070 gui.row3 = uicontainer('Parent',gui.main,'BackGroundColor',colors.panelBG); % axes SSE -0071 gui.row4 = uix.HBox('Parent',gui.main,'BackGroundColor',colors.panelBG,'Spacing',5); % control elements -0072 set(gui.main,'Heights',[-1 -1 -1 90]); +0043 %% get GUI handle and data +0044 fig = ancestor(src,'figure','toplevel'); +0045 nucleus.data = getappdata(fig,'data'); +0046 nucleus.gui = getappdata(fig,'gui'); +0047 myui = nucleus.gui.myui; +0048 colors = nucleus.gui.myui.colors; +0049 +0050 hasData = false; +0051 if isfield(nucleus.data,'results') +0052 if isfield(nucleus.data.results,'nmrraw') &&... +0053 isfield(nucleus.data.results,'nmrproc') +0054 hasData = true; +0055 ID = get(nucleus.gui.listbox_handles.signal,'value'); +0056 end +0057 end +0058 +0059 %% proceed if there is data +0060 if hasData +0061 % check if the figure is already open +0062 fig_phase = findobj('Tag','PHASEVIEW'); +0063 % if not, create it +0064 if isempty(fig_phase) +0065 % draw the figure on top of NUCLEUSinv +0066 fig_phase = figure('Name','NUCLEUSinv - PhaseView',... +0067 'NumberTitle','off','Resize','on','ToolBar','none',... +0068 'Tag','PHASEVIEW','Menubar','none'); +0069 pos0 = get(fig,'Position'); +0070 cent(1) = (pos0(1)+pos0(3)/2); +0071 cent(2) = (pos0(2)+pos0(4)/2); +0072 set(fig_phase,'Position',[cent(1)-pos0(3)/3 pos0(2)+22 pos0(3)/1.5 pos0(4)-22]); 0073 -0074 % all axes -0075 gui.axes_handles.real = axes('Parent',gui.row1,... -0076 'Color',colors.axisBG,'XColor',colors.axisFG,... -0077 'YColor',colors.axisFG); -0078 gui.axes_handles.imag = axes('Parent',gui.row2,... -0079 'Color',colors.axisBG,'XColor',colors.axisFG,... -0080 'YColor',colors.axisFG); -0081 gui.axes_handles.sse = axes('Parent',gui.row3,... -0082 'Color',colors.axisBG,'XColor',colors.axisFG,... -0083 'YColor',colors.axisFG); -0084 -0085 % 3 horizontal boxes -0086 uix.Empty('Parent',gui.row4); -0087 gui.vbox1 = uix.VBox('Parent',gui.row4,'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); % control elements -0088 uix.Empty('Parent',gui.row4); -0089 set(gui.row4,'Widths',[-1 -2 -1]); -0090 -0091 % edit field -0092 gui.hbox11 = uix.HBox('Parent',gui.vbox1,'BackGroundColor',colors.panelBG,'Spacing',5); -0093 uix.Empty('Parent',gui.hbox11); -0094 gui.edit_phase = uicontrol('Parent',gui.hbox11,... -0095 'Style','edit','FontSize',nucleus.gui.myui.fontsize,'Tag','phase',... -0096 'String',num2str(0),'BackGroundColor',colors.editBG,... -0097 'ForeGroundColor',colors.panelFG,... -0098 'Callback',@pv_updatePhase); -0099 uix.Empty('Parent',gui.hbox11); -0100 set(gui.hbox11,'Widths',[-1 -1 -1]); -0101 -0102 % slider -0103 gui.hbox12 = uix.HBox('Parent',gui.vbox1,'BackGroundColor',colors.panelBG,'Spacing',5); -0104 gui.hbox121 = uix.HBox('Parent',gui.hbox12,'BackGroundColor',colors.panelBG,'Spacing',5); -0105 gui.text_down = uicontrol('Parent',gui.hbox121,'Style','text',... -0106 'String','down','FontSize',nucleus.gui.myui.fontsize,... -0107 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0108 'HorizontalAlignment','right'); -0109 gui.slider = uicontrol('Parent',gui.hbox12,'Style','slider',... -0110 'Min',-180,'Max',180,'Value',0,'SliderStep',[0.1/360 5/360],... -0111 'Callback',@pv_updateSlider); -0112 gui.hbox122 = uix.HBox('Parent',gui.hbox12,'BackGroundColor',colors.panelBG,'Spacing',5); -0113 gui.text_up = uicontrol('Parent',gui.hbox122,'Style','text',... -0114 'String','up','FontSize',nucleus.gui.myui.fontsize,... -0115 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... -0116 'HorizontalAlignment','left'); -0117 set(gui.hbox12,'Widths',[-1 -9 -1]); -0118 -0119 % buttons -0120 gui.hbox13 = uix.HBox('Parent',gui.vbox1,'BackGroundColor',colors.panelBG,'Spacing',5); -0121 uix.Empty('Parent',gui.hbox13); -0122 gui.push_default = uicontrol('Parent',gui.hbox13,... -0123 'Style','pushbutton','FontSize',nucleus.gui.myui.fontsize,'Tag','default',... -0124 'String','DEFAULT','Callback',@pv_onPushDefault); -0125 uix.Empty('Parent',gui.hbox13); -0126 gui.push_save = uicontrol('Parent',gui.hbox13,... -0127 'Style','pushbutton','FontSize',nucleus.gui.myui.fontsize,'Tag','save',... -0128 'String','KEEP','Callback',@pv_onPushSave); -0129 uix.Empty('Parent',gui.hbox13); -0130 set(gui.hbox13,'Widths',[-1 -2 -1 -2 -1]); -0131 -0132 set(gui.vbox1,'Heights',[-1 20 -1]); -0133 -0134 % Java Hack to adjust vertical alignment of text fields -0135 jh = findjobj(gui.text_down); -0136 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0137 jh = findjobj(gui.text_up); -0138 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); -0139 -0140 % store some main GUI settings -0141 gui.myui = nucleus.gui.myui; -0142 -0143 % save to GUI -0144 setappdata(fig_phase,'gui',gui); -0145 end -0146 % if the figure is already open load the GUI data -0147 gui = getappdata(fig_phase,'gui'); -0148 -0149 % clear all axes -0150 clearAllAxes(fig_phase); -0151 -0152 if strcmp(nucleus.data.results.nmrproc.T1T2,'T2') -0153 -0154 %% get signal to show -0155 nmrraw = nucleus.data.results.nmrraw; -0156 loglinx = get(nucleus.gui.cm_handles.axes_raw_xaxis,'Label'); -0157 -0158 % axes setting -0159 data.loglinx = loglinx; -0160 % phase from import-fit -0161 data.phase_default = rad2deg(nucleus.data.results.nmrraw.phase); -0162 % phase used in PhaseView -0163 data.phase = data.phase_default; -0164 set(gui.edit_phase,'String',num2str(data.phase)); -0165 set(gui.slider,'Value',data.phase); -0166 % time -0167 data.time = nmrraw.t; -0168 -0169 % original unrotated signal -0170 data.signal_raw = nmrraw.s * exp(1i*deg2rad(shift_phase(-data.phase))); -0171 % rotated signal -0172 data.signal_rot = nmrraw.s; -0173 data.s_max = max(real(data.signal_rot)); -0174 -0175 % SSE data -0176 beta_range = 0:1:360; -0177 SSE = data.signal_raw*exp(1i*deg2rad(beta_range)); -0178 t0 = zeros(size(SSE)); -0179 residual_i = t0-imag(SSE); -0180 residual_r = t0-real(SSE); -0181 sse_i = sum(residual_i.^2,1); -0182 sse_r = sum(residual_r.^2,1)*-1; -0183 data.beta_range = beta_range; -0184 data.sse_i = sse_i; -0185 data.sse_r = sse_r; +0074 gui.menu.view = uimenu(fig_phase,'Label','View'); +0075 gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',... +0076 'Callback',@onMenuView); +0077 +0078 cpanel_w = 150; +0079 % phase angle fit range +0080 data.phase_range = [-180 180]; +0081 % SSR data +0082 % phase angle range to show nice diagram +0083 data.beta_range = -180:1:180; +0084 % echo range to calculate SSR +0085 data.echo_range = [nucleus.data.process.start nucleus.data.process.end]; +0086 +0087 % create the main layout +0088 gui.main = uix.HBox('Parent',fig_phase,'BackGroundColor',colors.panelBG,... +0089 'Spacing',5,'Padding',5,'Visible','off'); +0090 gui.left = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,... +0091 'Spacing',5,'Padding',0); % controls +0092 gui.right = uix.VBox('Parent',gui.main,'BackGroundColor',colors.panelBG,... +0093 'Spacing',5,'Padding',0); % plots +0094 +0095 set(gui.main,'Widths',[300 -1 ]); +0096 +0097 % empty space at top of left side +0098 uix.Empty('Parent',gui.left); +0099 +0100 % --- properties panel --- +0101 % waitbar(1/steps,hwb,'loading GUI elements - properties'); +0102 gui.panels.prop.main = uix.BoxPanel('Parent',gui.left,... +0103 'Title','Fit phase angle','MinimizeFcn',@minimizePanel,... +0104 'TitleColor',colors.BoxPRC,'ForegroundColor',colors.BoxTitle); +0105 gui.panels.prop.VBox = uix.VBox('Parent',gui.panels.prop.main,... +0106 'Spacing',3,'Padding',3); +0107 +0108 % first and last echo +0109 gui.panels.prop.HBox1 = uix.HBox('Parent',gui.panels.prop.VBox,... +0110 'Spacing',3); +0111 gui.text_handles.first = uicontrol('Parent',gui.panels.prop.HBox1,... +0112 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0113 'String',"T2 echoes - first | last"); +0114 tstr = 'Set first / last echo of all T2 signals.'; +0115 gui.edit_handles.first = uicontrol('Parent',gui.panels.prop.HBox1,... +0116 'Style','edit','String',sprintf('%d',nucleus.data.process.start),... +0117 'FontSize',myui.fontsize,'Tag','first',... +0118 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0119 'Callback',@pv_onEditValue); +0120 gui.edit_handles.last = uicontrol('Parent',gui.panels.prop.HBox1,... +0121 'Style','edit','String',sprintf('%d',nucleus.data.process.end),... +0122 'FontSize',myui.fontsize,'Tag','last',... +0123 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0124 'Callback',@pv_onEditValue); +0125 set(gui.panels.prop.HBox1,'Widths',[cpanel_w -1 -1]); +0126 +0127 % phase angle range +0128 gui.panels.prop.HBox2 = uix.HBox('Parent',gui.panels.prop.VBox,... +0129 'Spacing',3); +0130 gui.text_handles.range = uicontrol('Parent',gui.panels.prop.HBox2,... +0131 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0132 'String',"Phase range [-180, 180]"); +0133 tstr = 'Set phase angle range for fitting'; +0134 gui.edit_handles.range_min = uicontrol('Parent',gui.panels.prop.HBox2,... +0135 'Style','edit','String',sprintf('%d',-180),... +0136 'FontSize',myui.fontsize,'Tag','range_min',... +0137 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0138 'Callback',@pv_onEditValue); +0139 gui.edit_handles.range_max = uicontrol('Parent',gui.panels.prop.HBox2,... +0140 'Style','edit','String',sprintf('%d',180),... +0141 'FontSize',myui.fontsize,'Tag','range_max',... +0142 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0143 'Callback',@pv_onEditValue); +0144 set(gui.panels.prop.HBox2,'Widths',[cpanel_w -1 -1]); +0145 +0146 % fit method +0147 gui.panels.prop.HBox3 = uix.HBox('Parent',gui.panels.prop.VBox,... +0148 'Spacing',3); +0149 gui.text_handles.fitmethod = uicontrol('Parent',gui.panels.prop.HBox3,... +0150 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0151 'String',"Phase fit method"); +0152 tstr = ['<HTML>Choose the phase fitting method.<br><br>',... +0153 '<u>Available options:</u><br>',... +0154 '<b>maxRE minIM</b> maximize REal part, minimize IMag part.<br>',... +0155 '<b>maxRE</b> Only maximize REal part.<br>',... +0156 '<b>minIM</b> Only minimize IMag part.<br>',... +0157 '<b>minIMstd</b> Only minimize standard deviation of IMag part.<br><br>',... +0158 '<u>Default value:</u><br>',... +0159 '<b>maxRE minIM</b><br>']; +0160 gui.popup_handles.fitmethod = uicontrol('Parent',gui.panels.prop.HBox3,... +0161 'Style','popup','String',{'maxRE minIM','maxRE','minIM','minIMstd'},... +0162 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0163 'FontSize',myui.fontsize,'Tag','control'); +0164 set(gui.panels.prop.HBox3,'Widths',[cpanel_w -1]); +0165 +0166 % run fit +0167 gui.panels.prop.HBox4 = uix.HBox('Parent',gui.panels.prop.VBox,... +0168 'Spacing',3); +0169 uix.Empty('Parent',gui.panels.prop.HBox4); +0170 tstr = 'RUN phase fitting.'; +0171 gui.push_handles.runfit = uicontrol('Parent',gui.panels.prop.HBox4,... +0172 'Style','pushbutton','String','RUN phase fit',... +0173 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0174 'BackGroundColor','g','FontSize',myui.fontsize,... +0175 'Tag','control','Callback',@pv_onPushRun); +0176 set(gui.panels.prop.HBox4,'Widths',[cpanel_w -1]); +0177 +0178 +0179 % --- manual control panel --- +0180 % waitbar(1/steps,hwb,'loading GUI elements - properties'); +0181 gui.panels.manual.main = uix.BoxPanel('Parent',gui.left,... +0182 'Title','Manually set phase angle','MinimizeFcn',@minimizePanel,... +0183 'TitleColor',colors.BoxPRC,'ForegroundColor',colors.BoxTitle); +0184 gui.panels.manual.VBox = uix.VBox('Parent',gui.panels.manual.main,... +0185 'Spacing',3,'Padding',3); 0186 -0187 setappdata(fig_phase,'data',data); -0188 setappdata(fig_phase,'gui',gui); -0189 pv_showSignal(fig_phase); -0190 else -0191 helpdlg({'function: PhaseView',... -0192 'Cannot continue because there is no T2 data!'},... -0193 'No T2 data.'); -0194 delete(fig_phase); -0195 end -0196 end -0197 -0198 end +0187 % edit field +0188 gui.panels.manual.HBox1 = uix.HBox('Parent',gui.panels.manual.VBox,... +0189 'BackGroundColor',colors.panelBG,'Spacing',3); +0190 gui.text_handles.edit_manual = uicontrol('Parent',gui.panels.manual.HBox1,... +0191 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... +0192 'String',"Current phase [deg]"); +0193 gui.edit_handles.phase = uicontrol('Parent',gui.panels.manual.HBox1,... +0194 'Style','edit','FontSize',nucleus.gui.myui.fontsize,'Tag','phase',... +0195 'String',num2str(0),'BackGroundColor',colors.editBG,... +0196 'ForeGroundColor',colors.panelFG,... +0197 'Callback',@pv_onEditValue); +0198 set(gui.panels.manual.HBox1,'Widths',[cpanel_w -1]); 0199 -0200 function pv_onPushDefault(src,~) -0201 fig_phase = ancestor(src,'figure','toplevel'); -0202 gui = getappdata(fig_phase,'gui'); -0203 data = getappdata(fig_phase,'data'); -0204 -0205 data.phase = data.phase_default; -0206 set(gui.slider,'Value',data.phase); -0207 set(gui.edit_phase,'String',num2str(data.phase)); -0208 -0209 data.signal_rot = data.signal_raw * exp(1i*deg2rad(shift_phase(data.phase))); -0210 -0211 setappdata(fig_phase,'data',data); -0212 setappdata(fig_phase,'gui',gui); -0213 pv_showSignal(fig_phase); -0214 -0215 end -0216 -0217 function pv_onPushSave(src,~) -0218 fig_phase = ancestor(src,'figure','toplevel'); -0219 gui = getappdata(fig_phase,'gui'); -0220 data = getappdata(fig_phase,'data'); -0221 -0222 fig = findobj('Tag','INV'); -0223 nucleus.data = getappdata(fig,'data'); -0224 nucleus.gui = getappdata(fig,'gui'); -0225 -0226 % get the selected signal ID -0227 id = get(nucleus.gui.listbox_handles.signal,'Value'); -0228 % update phase -0229 nucleus.data.import.NMR.data{id}.phase = deg2rad(data.phase); -0230 nucleus.data.results.nmrraw.phase = deg2rad(data.phase); -0231 % update signal -0232 nucleus.data.import.NMR.data{id}.signal = data.signal_rot; -0233 nucleus.data.results.nmrraw.s = data.signal_rot; -0234 -0235 % update GUI data -0236 setappdata(fig,'data',nucleus.data); -0237 -0238 end -0239 -0240 function pv_showSignal(fig_phase) -0241 data = getappdata(fig_phase,'data'); -0242 gui = getappdata(fig_phase,'gui'); -0243 -0244 % axes handles -0245 ax1 = gui.axes_handles.real; -0246 ax2 = gui.axes_handles.imag; -0247 ax3 = gui.axes_handles.sse; -0248 % clear all axes -0249 clearAllAxes(fig_phase); -0250 hold(ax1,'on'); -0251 hold(ax2,'on'); -0252 hold(ax3,'on'); -0253 -0254 plot(data.time,real(data.signal_rot),'Color',gui.myui.colors.RE,'Parent',ax1); -0255 plot(data.time,imag(data.signal_rot),'Color',gui.myui.colors.IM,'Parent',ax2); -0256 -0257 switch data.loglinx -0258 case 'x-axis -> lin' % log axes -0259 xticks = floor(log10(data.time(1)))-1:1:log10(max(data.time))+1; -0260 set(ax1,'XScale','log','XLim',[data.time(1) max(data.time)],'XTick',10.^xticks); -0261 set(ax2,'XScale','log','XLim',[data.time(1) max(data.time)],'XTick',10.^xticks); -0262 case 'x-axis -> log' % lin axes -0263 set(ax1,'XScale','lin','XLim',[0 max(data.time)],'XTickMode','auto'); -0264 set(ax2,'XScale','lin','XLim',[0 max(data.time)],'XTickMode','auto'); -0265 end -0266 grid(ax1,'on'); -0267 grid(ax2,'on'); -0268 -0269 line(get(ax2,'XLim'),[0 0],'LineStyle','--','Color',gui.myui.colors.axisL,'LineWidth',1,'Parent',ax2); -0270 hold(ax2,'off'); -0271 -0272 %residual of current phase angle -0273 res_r = zeros(size(data.time))-real(data.signal_rot); -0274 res_i = zeros(size(data.time))-imag(data.signal_rot); -0275 sse_r = sum(res_r.^2); -0276 sse_i = sum(res_i.^2); -0277 -0278 set(get(ax1,'XLabel'),'String','time'); -0279 set(get(ax1,'YLabel'),'String','\Reeal'); -0280 text(0.975,0.8,['\Sigma \epsilon^2 = ',sprintf('%6.5e',sse_r)],... -0281 'HorizontalAlignment','right','BackgroundColor',gui.myui.colors.axisBG,... -0282 'Color',gui.myui.colors.panelFG,'Units','normalized',... -0283 'FontSize',12,'Parent',ax1); -0284 set(get(ax2,'XLabel'),'String','time'); -0285 set(get(ax2,'YLabel'),'String','\Immag'); -0286 text(0.975,0.8,['\Sigma \epsilon^2 = ',sprintf('%6.5e',sse_i)],... -0287 'HorizontalAlignment','right','BackgroundColor',gui.myui.colors.axisBG,... -0288 'Color',gui.myui.colors.panelFG,'Units','normalized',... -0289 'FontSize',12,'Parent',ax2); -0290 -0291 ymin = min([-1.*data.sse_r data.sse_i]); -0292 ymax = max([-1.*data.sse_r data.sse_i]); -0293 plot(data.beta_range-180,-1.*data.sse_r,'Color',gui.myui.colors.RE,'Parent',ax3); -0294 plot(data.beta_range-180,data.sse_i,'Color',gui.myui.colors.IM,'Parent',ax3); -0295 line([data.phase data.phase],[ymin ymax],'Color',gui.myui.colors.axisL,'LineStyle','--','Parent',ax3) -0296 lgh = legend(ax3,'\Reeal','\Immag','\phi'); -0297 set(lgh,'FontSize',12,'TextColor',gui.myui.colors.panelFG); -0298 -0299 set(ax3,'XLim',[-180 180],'XTick',-180:30:180); -0300 set(ax3,'YLim',[ymin ymax]); -0301 set(get(ax3,'XLabel'),'String','phase \phi [deg]'); -0302 set(get(ax3,'YLabel'),'String','\Sigma \epsilon^2'); -0303 hold(ax3,'off'); -0304 -0305 set(ax1,'FontSize',gui.myui.fontsize); -0306 set(ax2,'FontSize',gui.myui.fontsize); -0307 set(ax3,'FontSize',gui.myui.fontsize); -0308 -0309 set(get(ax1,'YLabel'),'FontSize',16); -0310 set(get(ax2,'YLabel'),'FontSize',16); -0311 -0312 end -0313 -0314 function pv_updateSlider(src,~) -0315 fig_phase = ancestor(src,'figure','toplevel'); -0316 gui = getappdata(fig_phase,'gui'); -0317 data = getappdata(fig_phase,'data'); -0318 -0319 data.phase = get(gui.slider,'Value'); -0320 set(gui.edit_phase,'String',num2str(data.phase)); -0321 -0322 data.signal_rot = data.signal_raw * exp(1i*deg2rad(shift_phase(data.phase))); +0200 % slider +0201 gui.panels.manual.HBox2 = uix.HBox('Parent',gui.panels.manual.VBox,... +0202 'BackGroundColor',colors.panelBG,'Spacing',3); +0203 gui.text_handles.slider_down = uicontrol('Parent',gui.panels.manual.HBox2,'Style','text',... +0204 'String','down','FontSize',nucleus.gui.myui.fontsize,... +0205 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0206 'HorizontalAlignment','center'); +0207 gui.slider_handles.slider = uicontrol('Parent',gui.panels.manual.HBox2,'Style','slider',... +0208 'Min',-180,'Max',180,'Value',0,'SliderStep',[0.1/360 5/360],... +0209 'Callback',@pv_onSlider); +0210 gui.text_handles.slider_up = uicontrol('Parent',gui.panels.manual.HBox2,'Style','text',... +0211 'String','up','FontSize',nucleus.gui.myui.fontsize,... +0212 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... +0213 'HorizontalAlignment','center'); +0214 set(gui.panels.manual.HBox2,'Widths',[-1 -6 -1]); +0215 +0216 % buttons +0217 gui.panels.manual.HBox3 = uix.HBox('Parent',gui.panels.manual.VBox,... +0218 'BackGroundColor',colors.panelBG,'Spacing',3); +0219 tstr = 'Change phase angle by -90°.'; +0220 gui.push_handles.button_m90 = uicontrol('Parent',gui.panels.manual.HBox3,... +0221 'Style','pushbutton','String','-90',... +0222 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0223 'FontSize',myui.fontsize,... +0224 'Tag','button_m90','Callback',@pv_onPushAngle); +0225 tstr = 'Change phase angle by -45°.'; +0226 gui.push_handles.button_m45 = uicontrol('Parent',gui.panels.manual.HBox3,... +0227 'Style','pushbutton','String','-45',... +0228 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0229 'FontSize',myui.fontsize,... +0230 'Tag','button_m45','Callback',@pv_onPushAngle); +0231 tstr = 'Change phase angle by +-180°.'; +0232 gui.push_handles.button_pm180 = uicontrol('Parent',gui.panels.manual.HBox3,... +0233 'Style','pushbutton','String','+-180',... +0234 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0235 'FontSize',myui.fontsize,... +0236 'Tag','button_pm180','Callback',@pv_onPushAngle); +0237 tstr = 'Change phase angle by +45°.'; +0238 gui.push_handles.button_p45 = uicontrol('Parent',gui.panels.manual.HBox3,... +0239 'Style','pushbutton','String','+45',... +0240 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0241 'FontSize',myui.fontsize,... +0242 'Tag','button_p45','Callback',@pv_onPushAngle); +0243 tstr = 'Change phase angle by +90°.'; +0244 gui.push_handles.button_p90 = uicontrol('Parent',gui.panels.manual.HBox3,... +0245 'Style','pushbutton','String','+90',... +0246 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0247 'FontSize',myui.fontsize,... +0248 'Tag','button_p90','Callback',@pv_onPushAngle); +0249 set(gui.panels.manual.HBox3,'Widths',[-1 -1 -1 -1 -1]); +0250 +0251 % --- update MAIN GUI buttons --- +0252 gui.panels.save.VBox1 = uix.VBox('Parent',gui.left,... +0253 'Spacing',3); +0254 tstr = 'KEEP default phase angle from NUCLEUSinv GUI import.'; +0255 gui.push_handles.default = uicontrol('Parent',gui.panels.save.VBox1,... +0256 'String','KEEP default phase angle','FontSize',myui.fontsize,'Tag','default',... +0257 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0258 'Callback',@pv_onPushKeep); +0259 tstr = 'APPLY the current phase angle to the signal in the NUCLEUSinv GUI'; +0260 gui.push_handles.apply_single = uicontrol('Parent',gui.panels.save.VBox1,... +0261 'String','APPLY current phase angle','FontSize',myui.fontsize,'Tag','apply',... +0262 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0263 'Callback',@pv_onPushApply); +0264 tstr = 'APPLY the current phase angle to all signals in the NUCLEUSinv GUI'; +0265 gui.push_handles.apply_all = uicontrol('Parent',gui.panels.save.VBox1,... +0266 'String','APPLY current phase angle 2 all','FontSize',myui.fontsize,'Tag','apply2all',... +0267 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... +0268 'Callback',@pv_onPushApply); +0269 +0270 % Java Hack to adjust vertical alignment of text fields +0271 jh = findjobj(gui.text_handles.first); +0272 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0273 jh = findjobj(gui.text_handles.fitmethod); +0274 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0275 jh = findjobj(gui.text_handles.edit_manual); +0276 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0277 jh = findjobj(gui.text_handles.slider_down); +0278 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0279 jh = findjobj(gui.text_handles.slider_up); +0280 jh.setVerticalAlignment(javax.swing.JLabel.CENTER); +0281 +0282 % empty space at bottom of left side +0283 uix.Empty('Parent',gui.left); +0284 % adjust the heights of all left-column-panels +0285 heights = [-1 22 22 28 -1; -1 22+4*24+6*3 22+3*24+5*3 28*3 -1]; +0286 % panel header is always 22 high +0287 set(gui.left,'Heights',heights(2,:),... +0288 'MinimumHeights',[0 22 22 28 0]); +0289 +0290 % --- plot boxes --- +0291 % -- tab3 +0292 gui.tab = uix.VBoxFlex('Parent',gui.right,... +0293 'BackGroundColor',colors.panelBG,'Spacing',5); +0294 gui.pbox1 = uicontainer('Parent',gui.tab,... +0295 'BackGroundColor',colors.panelBG); +0296 gui.pbox2 = uicontainer('Parent',gui.tab,... +0297 'BackGroundColor',colors.panelBG); +0298 gui.pbox3 = uicontainer('Parent',gui.tab,... +0299 'BackGroundColor',colors.panelBG); +0300 set(gui.tab,'Heights',[-1 -1 -1]); +0301 +0302 % -- plot axes -- +0303 gui.axes_handles.real = axes('Parent',gui.pbox1,'Color',colors.axisBG,... +0304 'XColor',colors.axisFG,'YColor',colors.axisFG,'Box','on'); +0305 gui.axes_handles.imag = axes('Parent',gui.pbox2,'Color',colors.axisBG,... +0306 'XColor',colors.axisFG,'YColor',colors.axisFG,'Box','on'); +0307 gui.axes_handles.sse = axes('Parent',gui.pbox3,'Color',colors.axisBG,... +0308 'XColor',colors.axisFG,'YColor',colors.axisFG,'Box','on'); +0309 +0310 % store some main GUI settings +0311 gui.myui = nucleus.gui.myui; +0312 +0313 % save to GUI +0314 setappdata(fig_phase,'gui',gui); +0315 +0316 % make GUI visible +0317 % delete(hwb); +0318 set(gui.main,'Visible','on'); +0319 else +0320 % if the figure is already open load the GUI data +0321 gui = getappdata(fig_phase,'gui'); +0322 data = getappdata(fig_phase,'data'); 0323 -0324 setappdata(fig_phase,'data',data); -0325 setappdata(fig_phase,'gui',gui); -0326 pv_showSignal(fig_phase); -0327 -0328 end -0329 -0330 function pv_updatePhase(src,~) -0331 fig_phase = ancestor(src,'figure','toplevel'); -0332 gui = getappdata(fig_phase,'gui'); -0333 data = getappdata(fig_phase,'data'); -0334 -0335 data.phase = str2double(get(gui.edit_phase,'String')); -0336 set(gui.slider,'Value',data.phase); -0337 -0338 data.signal_rot = data.signal_raw * exp(1i*deg2rad(shift_phase(data.phase))); -0339 -0340 setappdata(fig_phase,'data',data); -0341 setappdata(fig_phase,'gui',gui); -0342 pv_showSignal(fig_phase); -0343 -0344 end -0345 -0346 function phase = shift_phase(phase) -0347 % shifts the phase values from [-180,180] to [0,360] -0348 phase = phase + 180; -0349 end -0350 -0351 %------------- END OF CODE -------------- -0352 -0353 %% License: -0354 % MIT License -0355 % -0356 % Copyright (c) 2019 Thomas Hiller -0357 % -0358 % Permission is hereby granted, free of charge, to any person obtaining a copy -0359 % of this software and associated documentation files (the "Software"), to deal -0360 % in the Software without restriction, including without limitation the rights -0361 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0362 % copies of the Software, and to permit persons to whom the Software is -0363 % furnished to do so, subject to the following conditions: -0364 % -0365 % The above copyright notice and this permission notice shall be included in all -0366 % copies or substantial portions of the Software. -0367 % -0368 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0369 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0370 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0371 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0372 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0373 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0374 % SOFTWARE.

    +0324 % echo range to calculate SSR +0325 if data.echo_range(2) > nucleus.data.process.end +0326 data.echo_range(2) = nucleus.data.process.end; +0327 set(gui.edit_handles.last,'String',sprintf('%d',data.echo_range(2))); +0328 end +0329 % data.echo_range = [nucleus.data.process.start nucleus.data.process.end]; +0330 end +0331 +0332 +0333 % clear all axes +0334 clearAllAxes(fig_phase); +0335 +0336 if strcmp(nucleus.data.results.nmrproc.T1T2,'T2') +0337 % get signal to show +0338 nmrraw = nucleus.data.results.nmrraw; +0339 loglinx = get(nucleus.gui.cm_handles.axes_raw_xaxis,'Label'); +0340 +0341 % axes setting +0342 data.loglinx = loglinx; +0343 % phase from import-fit +0344 data.phase_default = rad2deg(nucleus.data.results.nmrraw.phase); +0345 % phase used in PhaseView +0346 data.phase = data.phase_default; +0347 set(gui.edit_handles.phase,'String',num2str(data.phase)); +0348 set(gui.slider_handles.slider,'Value',data.phase); +0349 % time +0350 data.time = nmrraw.t; +0351 +0352 % original unrotated signal +0353 data.signal_raw = nmrraw.s * exp(1i*deg2rad(-data.phase)); +0354 % rotated signal +0355 data.signal_rot = nmrraw.s; +0356 data.s_max = max(real(data.signal_rot)); +0357 +0358 % keep original signal +0359 data.orig_data = nucleus.data.import.NMR.data{ID}; +0360 data.orig_para = nucleus.data.import.NMR.para{ID}; +0361 +0362 % update GUI data +0363 setappdata(fig_phase,'data',data); +0364 setappdata(fig_phase,'gui',gui); +0365 % calculate SSR +0366 pv_updateFullDataSet(fig_phase); +0367 % update plots +0368 pv_plotSignal(fig_phase); +0369 pv_plotSSR(fig_phase); +0370 +0371 else +0372 % close the GUI because the selected signal is not a T2 signal +0373 helpdlg({'function: PhaseView',... +0374 'Cannot continue because there is no T2 data!'},... +0375 'No T2 data.'); +0376 delete(fig_phase); +0377 end +0378 end +0379 +0380 end +0381 +0382 %% subfunction to update the edit fields +0383 function pv_onEditValue(src,~) +0384 fig_phase = ancestor(src,'figure','toplevel'); +0385 gui = getappdata(fig_phase,'gui'); +0386 data = getappdata(fig_phase,'data'); +0387 +0388 switch get(src,'Tag') +0389 case {'first','last'} +0390 data.echo_range(1) = str2double(get(gui.edit_handles.first,'String')); +0391 data.echo_range(2) = str2double(get(gui.edit_handles.last,'String')); +0392 % update GUI data +0393 setappdata(fig_phase,'data',data); +0394 pv_updateFullDataSet(fig_phase); +0395 data = getappdata(fig_phase,'data'); +0396 setappdata(fig_phase,'data',data); +0397 pv_plotSignal(fig_phase); +0398 pv_plotSSR(fig_phase); +0399 case {'range_min','range_max'} +0400 data.phase_range(1) = str2double(get(gui.edit_handles.range_min,'String')); +0401 data.phase_range(2) = str2double(get(gui.edit_handles.range_max,'String')); +0402 % update GUI data +0403 setappdata(fig_phase,'data',data); +0404 pv_plotSSR(fig_phase); +0405 case 'phase' +0406 data.phase = str2double(get(gui.edit_handles.phase,'String')); +0407 % update slider +0408 set(gui.slider_handles.slider,'Value',data.phase); +0409 % apply new phase +0410 data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); +0411 % update GUI data +0412 setappdata(fig_phase,'data',data); +0413 setappdata(fig_phase,'gui',gui); +0414 pv_plotSignal(fig_phase); +0415 pv_plotSSR(fig_phase); +0416 end +0417 +0418 % update GUI data +0419 setappdata(fig_phase,'data',data); +0420 end +0421 +0422 %% subfunction to control the phase angle push buttons +0423 function pv_onPushAngle(src,~) +0424 fig_phase = ancestor(src,'figure','toplevel'); +0425 gui = getappdata(fig_phase,'gui'); +0426 data = getappdata(fig_phase,'data'); +0427 +0428 % get the angle offset according to the chosen button +0429 switch get(src,'Tag') +0430 case 'button_m90' +0431 offset = -90; +0432 case 'button_m45' +0433 offset = -45; +0434 case 'button_pm180' +0435 offset = 180; +0436 case 'button_p45' +0437 offset = 45; +0438 case 'button_p90' +0439 offset = 90; +0440 otherwise +0441 offset = 0; +0442 end +0443 +0444 % map phase into the correct range +0445 data.phase = -180 + mod((data.phase + offset)+180,360); +0446 % update edit field +0447 set(gui.edit_handles.phase,'String',num2str(data.phase)); +0448 % update slider +0449 set(gui.slider_handles.slider,'Value',data.phase); +0450 % new rotated signal +0451 data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); +0452 +0453 % update GUI data +0454 setappdata(fig_phase,'data',data); +0455 setappdata(fig_phase,'gui',gui); +0456 % update plots +0457 pv_plotSignal(fig_phase); +0458 pv_plotSSR(fig_phase); +0459 end +0460 +0461 %% subfunction to control the push button to apply the phase angle +0462 function pv_onPushApply(src,~) +0463 fig_phase = ancestor(src,'figure','toplevel'); +0464 data = getappdata(fig_phase,'data'); +0465 +0466 % get handle and data of main GUI +0467 fig = findobj('Tag','INV'); +0468 nucleus.data = getappdata(fig,'data'); +0469 nucleus.gui = getappdata(fig,'gui'); +0470 +0471 % get selected signal ID from main GUI +0472 id = get(nucleus.gui.listbox_handles.signal,'Value'); +0473 +0474 switch get(src,'Tag') +0475 case 'apply' +0476 % update phase +0477 nucleus.data.import.NMR.data{id}.phase = deg2rad(data.phase); +0478 nucleus.data.results.nmrraw.phase = deg2rad(data.phase); +0479 % update signal +0480 nucleus.data.import.NMR.data{id}.signal = data.signal_rot; +0481 nucleus.data.results.nmrraw.s = data.signal_rot; +0482 +0483 case 'apply2all' +0484 N = numel(nucleus.data.import.NMR.data); +0485 for i1 = 1:N +0486 % only proceed if the signal is complex (T2 data) +0487 if ~isreal(nucleus.data.import.NMR.data{i1}.signal) +0488 % original unrotated signal +0489 phase_org = rad2deg(nucleus.data.import.NMR.data{i1}.phase); +0490 s_raw = nucleus.data.import.NMR.data{i1}.raw.signal; +0491 s_raw = s_raw * exp(1i*deg2rad(-phase_org)); +0492 +0493 % new phase +0494 phase_new = data.phase; +0495 nucleus.data.import.NMR.data{i1}.phase = deg2rad(phase_new); +0496 % signal with new phase +0497 s_new = s_raw * exp(1i*deg2rad(phase_new)); +0498 % update signal +0499 nucleus.data.import.NMR.data{i1}.signal = s_new; +0500 nucleus.data.import.NMR.data{i1}.raw.signal= s_new; +0501 end +0502 end +0503 % check if it is a T1-T2 data set, because then we need to adjust +0504 % the merged T1 curve also +0505 if isfield(nucleus.data.import,'T1T2map') +0506 % the last signal is the merged T1 curve +0507 N = numel(nucleus.data.import.T1T2map.t_recov) + 1; +0508 +0509 s_old = nucleus.data.import.NMR.data{N}.signal; +0510 time = nucleus.data.import.T1T2map.t_recov; +0511 s_new = zeros(size(s_old)); +0512 for i1 = 1:numel(time) +0513 s_new(i1) = mean(real(nucleus.data.import.NMR.data{i1}.signal(1:3))); +0514 end +0515 +0516 % estimate noise of the new merged T1 curve +0517 disp('NUCLUESinv PhaseView: Estimating noise from exponential fit ...'); +0518 flag = 'T1'; +0519 param.T1IRfac = nucleus.data.import.NMR.data{N}.T1IRfac; +0520 param.noise = 0; +0521 param.optim = 'off'; +0522 param.Tfixed_bool = [0 0 0 0 0]; +0523 param.Tfixed_val = [0 0 0 0 0]; +0524 for i1 = 1:5 +0525 invstd = fitDataFree(time,s_new,flag,param,i1); +0526 if i1 == 1 +0527 noise = invstd.rms; +0528 else +0529 noise = min([noise invstd.rms]); +0530 end +0531 end +0532 % update data +0533 nucleus.data.import.NMR.data{N}.signal = s_new; +0534 nucleus.data.import.NMR.data{N}.noise = noise; +0535 nucleus.data.import.NMR.data{N}.raw.signal = s_new; +0536 end +0537 end +0538 +0539 % update main GUI data +0540 setappdata(fig,'data',nucleus.data); +0541 % set focus on chosen signal +0542 set(nucleus.gui.listbox_handles.signal,'Value',id); +0543 onListboxData(nucleus.gui.listbox_handles.signal); +0544 end +0545 +0546 %% subfunction to control the push button to restore the default phase angle +0547 function pv_onPushKeep(src,~) +0548 fig_phase = ancestor(src,'figure','toplevel'); +0549 gui = getappdata(fig_phase,'gui'); +0550 data = getappdata(fig_phase,'data'); +0551 +0552 % get original pahse +0553 data.phase = data.phase_default; +0554 % update edit field +0555 set(gui.edit_handles.phase,'String',num2str(data.phase)); +0556 % update slider +0557 set(gui.slider_handles.slider,'Value',data.phase); +0558 % new rotated signal +0559 data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); +0560 +0561 % update GUI data +0562 setappdata(fig_phase,'data',data); +0563 setappdata(fig_phase,'gui',gui); +0564 % update plots +0565 pv_plotSignal(fig_phase); +0566 pv_plotSSR(fig_phase); +0567 end +0568 +0569 %% subfunction to control the push button to fit the phase angle +0570 function pv_onPushRun(src,~) +0571 fig_phase = ancestor(src,'figure','toplevel'); +0572 gui = getappdata(fig_phase,'gui'); +0573 data = getappdata(fig_phase,'data'); +0574 +0575 % get signal +0576 s = data.signal_raw; +0577 +0578 % get signal bounds +0579 te_start = data.echo_range(1); +0580 te_end = data.echo_range(2); +0581 +0582 % get fit method +0583 fitval = get(gui.popup_handles.fitmethod,'Value'); +0584 fitmethod = get(gui.popup_handles.fitmethod,'String'); +0585 fitmethod = fitmethod{fitval}; +0586 +0587 % get phase angle range +0588 alpha_range = deg2rad(data.phase_range); +0589 +0590 % optim settings +0591 options = optimset('MaxFunEvals',100,'MaxIter',100,'TolFun',1e-6,'TolX',1e-6); +0592 % call fit function +0593 [alpha,~,~,~] = fminsearchbnd(@(alpha) phasefit_fcn(alpha,s(te_start:te_end),fitmethod),... +0594 mean(alpha_range),alpha_range(1),alpha_range(2),options); +0595 +0596 % s_rot is rotated signal +0597 data.signal_rot = s .* exp(1i*alpha); +0598 +0599 % save new phase +0600 data.phase = rad2deg(alpha); +0601 % update edit field +0602 set(gui.edit_handles.phase,'String',num2str(data.phase)); +0603 % update slider +0604 set(gui.slider_handles.slider,'Value',data.phase); +0605 +0606 % update GUI data +0607 setappdata(fig_phase,'data',data); +0608 setappdata(fig_phase,'gui',gui); +0609 % update plots +0610 pv_plotSignal(fig_phase); +0611 pv_plotSSR(fig_phase); +0612 end +0613 +0614 % minimization function +0615 function sse = phasefit_fcn(alpha,s,method) +0616 % Inputs: +0617 % alpha - rotation phase angle in [rad] +0618 % s - NMR signal vector (has to be complex!) +0619 % method - "maxRE minIM", "maxRE", "minIM" or "minIMstd" +0620 % +0621 % Outputs: +0622 % sse - sum of squared residuals (option 1 to 3) or +0623 % standard deviation of imag. part (option 4) +0624 +0625 s = s(:); +0626 switch method +0627 case 'maxRE minIM' +0628 % make a vector of zeros +0629 t0 = zeros(size(s,1),1); +0630 t0 = t0(:); +0631 % s_rot is the rotated signal +0632 s_rot = s .* exp(1i*alpha); +0633 % create residuals +0634 residuali = t0-imag(s_rot); +0635 residualr = t0-real(s_rot); +0636 % real part times -1 because we seek the maximum +0637 sse = sum(residuali.^2) + sum(residualr.^2)*-1; +0638 case 'maxRE' +0639 % make a vector of zeros +0640 t0 = zeros(size(s,1),1); +0641 t0 = t0(:); +0642 % s_rot is the rotated signal +0643 s_rot = s .* exp(1i*alpha); +0644 % create residuals +0645 residualr = t0-real(s_rot); +0646 % maximum of real part should be maximized +0647 sse = sum(residualr.^2)*-1; +0648 case 'minIM' +0649 % make a vector of zeros +0650 t0 = zeros(size(s,1),1); +0651 t0 = t0(:); +0652 % s_rot is the rotated signal +0653 s_rot = s .* exp(1i*alpha); +0654 % create residuals +0655 residuali = t0-imag(s_rot); +0656 % sse +0657 sse = sum(residuali.^2); +0658 case 'minIMstd' +0659 % s_rot is the rotated signal +0660 s_rot = s .* exp(1i*alpha); +0661 % standard deviation of the imaginary part should be minimized +0662 sse = std(imag(s_rot)); +0663 end +0664 +0665 end +0666 +0667 %% subfunction to control the slider +0668 function pv_onSlider(src,~) +0669 fig_phase = ancestor(src,'figure','toplevel'); +0670 gui = getappdata(fig_phase,'gui'); +0671 data = getappdata(fig_phase,'data'); +0672 +0673 % new phase angle from slider +0674 data.phase = get(src,'Value'); +0675 % update edit field +0676 set(gui.edit_handles.phase,'String',num2str(data.phase)); +0677 % new rotated signal +0678 data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); +0679 +0680 % update GUI data +0681 setappdata(fig_phase,'data',data); +0682 setappdata(fig_phase,'gui',gui); +0683 % update signals +0684 pv_plotSignal(fig_phase); +0685 pv_plotSSR(fig_phase); +0686 end +0687 +0688 %% subfunction to calculate the full SSE values for a range of phase angles +0689 function pv_updateFullDataSet(fig_phase) +0690 data = getappdata(fig_phase,'data'); +0691 +0692 % get echo range +0693 te_start = data.echo_range(1); +0694 te_end = data.echo_range(2); +0695 % get all signals with the desired phase angles +0696 SSE = data.signal_raw*exp(1i*deg2rad(data.beta_range)); +0697 +0698 % get individual SSRs +0699 sse_r = getSSR(real(SSE(te_start:te_end,:))); +0700 sse_i = getSSR(imag(SSE(te_start:te_end,:))); +0701 % save data +0702 data.sse_i = sse_i; +0703 data.sse_r = sse_r; +0704 +0705 % update GUI data +0706 setappdata(fig_phase,'data',data); +0707 end +0708 +0709 %% subfunction to plot the REal and IMag signal parts +0710 function pv_plotSignal(fig_phase) +0711 data = getappdata(fig_phase,'data'); +0712 gui = getappdata(fig_phase,'gui'); +0713 +0714 % axes handles +0715 ax1 = gui.axes_handles.real; +0716 ax2 = gui.axes_handles.imag; +0717 clearSingleAxis(ax1); +0718 clearSingleAxis(ax2); +0719 +0720 % plot Real and IMag part of signal +0721 plot(data.time,real(data.signal_rot),'Color',gui.myui.colors.RE,'Parent',ax1); +0722 plot(data.time,imag(data.signal_rot),'Color',gui.myui.colors.IM,'Parent',ax2); +0723 +0724 hold(ax1,'on'); +0725 hold(ax2,'on'); +0726 +0727 switch data.loglinx +0728 case 'x-axis -> lin' % log axes +0729 xticks = floor(log10(data.time(1)))-1:1:log10(max(data.time))+1; +0730 set([ax1 ax2],'XScale','log','XLim',[data.time(1) max(data.time)],'XTick',10.^xticks); +0731 case 'x-axis -> log' % lin axes +0732 set([ax1 ax2],'XScale','lin','XLim',[0 max(data.time)],'XTickMode','auto'); +0733 end +0734 grid([ax1 ax2],'on'); +0735 +0736 set([ax1 ax2],'XLim',[data.orig_data.raw.time(1) data.orig_data.raw.time(end)]); +0737 set(get(ax1,'YLabel'),'String','Real Ampl.'); +0738 set(get(ax2,'XLabel'),'String','time [s]'); +0739 set(get(ax2,'YLabel'),'String','Imag Ampl.'); +0740 +0741 % get SSR of current signal +0742 te_start = data.echo_range(1); +0743 te_end = data.echo_range(2); +0744 sse_r = getSSR(real(data.signal_rot(te_start:te_end))); +0745 sse_i = getSSR(imag(data.signal_rot(te_start:te_end))); +0746 +0747 set(get(ax1,'Title'),'String',['SSR: ',sprintf('%6.5e',sse_r)]); +0748 set(get(ax2,'Title'),'String',['SSR: ',sprintf('%6.5e',sse_i)]); +0749 +0750 % plot patches to indicate echo range +0751 p_alpha = 0.8; +0752 xlims = get(ax1,'XLim'); +0753 ylims_re = get(ax1,'YLim'); +0754 ylims_im = get(ax2,'YLim'); +0755 if data.time(te_start)>xlims(1) +0756 % draw a transparent patch +0757 v_re = [xlims(1) ylims_re(1); xlims(1) ylims_re(2); +0758 data.time(te_start) ylims_re(2); data.time(te_start) ylims_re(1)]; +0759 v_im = [xlims(1) ylims_im(1); xlims(1) ylims_im(2); +0760 data.time(te_start) ylims_im(2); data.time(te_start) ylims_im(1)]; +0761 f = [1 2 3 4 1]; +0762 patch('Vertices',v_re,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +0763 'HandleVisibility','off','Tag','infolines','Parent', ax1); +0764 patch('Vertices',v_im,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +0765 'HandleVisibility','off','Tag','infolines','Parent', ax2); +0766 end +0767 if data.time(te_end)<xlims(2) +0768 % draw a transparent patch +0769 v_re = [xlims(2) ylims_re(1); xlims(2) ylims_re(2); +0770 data.time(te_end) ylims_re(2); data.time(te_end) ylims_re(1)]; +0771 v_im = [xlims(2) ylims_im(1); xlims(2) ylims_im(2); +0772 data.time(te_end) ylims_im(2); data.time(te_end) ylims_im(1)]; +0773 f = [1 2 3 4 1]; +0774 patch('Vertices',v_re,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +0775 'HandleVisibility','off','Tag','infolines','Parent', ax1); +0776 patch('Vertices',v_im,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +0777 'HandleVisibility','off','Tag','infolines','Parent', ax2); +0778 end +0779 set(ax1,'YLim',ylims_re); +0780 set(ax2,'YLim',ylims_im); +0781 set([ax1 ax2],'FontSize',gui.myui.fontsize); +0782 hold(ax1,'off'); +0783 hold(ax2,'off'); +0784 end +0785 +0786 %% subfunction to plot the SSR +0787 function pv_plotSSR(fig_phase) +0788 data = getappdata(fig_phase,'data'); +0789 gui = getappdata(fig_phase,'gui'); +0790 +0791 % axes handles +0792 ax = gui.axes_handles.sse; +0793 clearSingleAxis(ax); +0794 hold(ax,'on'); +0795 +0796 % plot REal and IMag SSRs +0797 ymin = min([data.sse_r data.sse_i]); +0798 ymax = max([data.sse_r data.sse_i]); +0799 plot(data.beta_range,data.sse_r,'Color',gui.myui.colors.RE,'Parent',ax); +0800 plot(data.beta_range,data.sse_i,'Color',gui.myui.colors.IM,'Parent',ax); +0801 % indicate current phase angle +0802 line([data.phase data.phase],[ymin ymax],'Color',gui.myui.colors.axisL,'LineStyle','--','Parent',ax) +0803 lgh = legend(ax,'Real','Imag','Phase'); +0804 set(lgh,'TextColor',gui.myui.colors.panelFG); +0805 +0806 % plot patches to indicate angle range +0807 p_alpha = 0.8; +0808 xlims = [-180 180]; +0809 ylims = [ymin ymax]; +0810 if data.phase_range(1)>xlims(1) +0811 % draw a transparent patch +0812 v = [xlims(1) ylims(1); xlims(1) ylims(2); +0813 data.phase_range(1) ylims(2); data.phase_range(1) ylims(1)]; +0814 f = [1 2 3 4 1]; +0815 patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +0816 'HandleVisibility','off','Tag','infolines','Parent', ax); +0817 end +0818 if data.phase_range(2)<xlims(2) +0819 % draw a transparent patch +0820 v = [xlims(2) ylims(1); xlims(2) ylims(2); +0821 data.phase_range(2) ylims(2); data.phase_range(2) ylims(1)]; +0822 f = [1 2 3 4 1]; +0823 patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +0824 'HandleVisibility','off','Tag','infolines','Parent', ax); +0825 end +0826 +0827 xticks = -180:45:180; +0828 set(ax,'XLim',[-180 180],'XTick',xticks); +0829 set(ax,'YLim',[ymin ymax]); +0830 set(get(ax,'XLabel'),'String','phase angle [deg]'); +0831 set(get(ax,'YLabel'),'String','squared sum res. (SSR)'); +0832 hold(ax,'off'); +0833 set(ax,'FontSize',gui.myui.fontsize); +0834 end +0835 +0836 %% subfunction to get the SSR +0837 function ssr = getSSR(signal) +0838 % residual of signal +0839 res = zeros(size(signal))-signal; +0840 % sum of squared residuals SSR +0841 ssr = sum(res.^2); +0842 end +0843 +0844 %------------- END OF CODE -------------- +0845 +0846 %% License: +0847 % MIT License +0848 % +0849 % Copyright (c) 2019 Thomas Hiller +0850 % +0851 % Permission is hereby granted, free of charge, to any person obtaining a copy +0852 % of this software and associated documentation files (the "Software"), to deal +0853 % in the Software without restriction, including without limitation the rights +0854 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0855 % copies of the Software, and to permit persons to whom the Software is +0856 % furnished to do so, subject to the following conditions: +0857 % +0858 % The above copyright notice and this permission notice shall be included in all +0859 % copies or substantial portions of the Software. +0860 % +0861 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0862 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0863 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0864 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0865 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0866 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0867 % 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 index 18d56a5..8f0e166 100644 --- a/doc/nucleus/functions/interface/UncertView.html +++ b/doc/nucleus/functions/interface/UncertView.html @@ -72,7 +72,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • onMenuView handles the view menu entries
  • beautifyAxes can be used to globally change the general appearance of axes
  • clearAllAxes clears all axes of a given figure
  • getKernelDensityEstimate computes the one dimensional kernel density estimate
  • minimizePanel handles the minimization/maximization of all box-panels for
  • updateInfo updates the information shown in all information list boxes
  • updatePlotsDistribution plots the RTD and PSD curves into NUCLEUSinv
  • updatePlotsSignal plots the raw and processed NMR signals in NUCLEUSinv
  • createKernelMatrix creates a Kernel matrix from signal time vector "t"
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • getAAD gets the average absolute deviation from the values in x
  • getUncertaintyStatistics
  • This function is called by: @@ -80,7 +80,7 @@

    CROSS-REFERENCE INFORMATION ^
 
 <h2><a name=SUBFUNCTIONS ^

    +
  • function uv_onEditValue(src,~)
  • function uv_onPushSend(src,~)
  • function uv_onContextPlotsColor(src,~)
  • function uv_onContextPlotsRTD(src,~)
  • function data = uv_updateMASK(data)
  • function uv_onPopupMethod(src,~)
  • function uv_onPushRun(src,~)
  • function uv_onPushView(src,~)
  • function uv_onPushUpdate(src,~)
  • function uv_onPushReset(src,~)
  • function uv_updateInformation(figh)
  • function uv_updatePlots(figh)
  • function uv_closeme(src,~)
  • SOURCE CODE ^

    0001 function UncertView(src,~)
    @@ -153,1420 +153,1529 @@ 

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

    +1349 % --- RTDs --- +1350 plotmethod = 1; +1351 switch uv.rtd_plotstyle +1352 case 'patchmean' +1353 plotmethod = 2; +1354 case 'patchmedian' +1355 plotmethod = 3; +1356 otherwise +1357 % nothing to do because 'lines' is default +1358 end +1359 +1360 % the 'init' RTD +1361 F0 = invstd.T1T2f; +1362 % normalize all curves to the median of all E0 values +1363 E0norm = uv.E0_aadmed(1); +1364 if sum(F0)>0 +1365 F = (data.invstd.porosity*100).*F0./E0norm; +1366 ylims = [0 max(F)*1.05]; +1367 else +1368 ylims = [-1 1]; +1369 end +1370 % the uncertainty runs +1371 % only the selected ones within the chi2 and xn bounds +1372 FDIST = uncert.interp_f(in,:); +1373 % scaling +1374 FDIST = (data.invstd.porosity*100).*FDIST./E0norm; +1375 +1376 % if selected plot lines +1377 if plotmethod == 1 +1378 % find maximum for axis limts +1379 f_max = max([ylims(2) max(FDIST(:))]); +1380 switch uv.colorstyle +1381 case {'chi2','xn'} +1382 % get colormap from chi2 vs xn axis +1383 cmap = get(gui.axes12,'Colormap'); +1384 % make vector of values to sort +1385 idc = linspace(clims(1),clims(2),size(cmap,1)); +1386 for i1 = 1:sum(in) +1387 % find closest value (need for coloring) +1388 idc1 = find(abs(idc-tmp(idx(i1)))==min(abs(idc-tmp(idx(i1))))); +1389 % idc1 = abs(idc-tmp(idx(i1)))==min(abs(idc-tmp(idx(i1)))); +1390 % plot line with correct color +1391 plot(invstd.T1T2me,FDIST(idx(i1),:),'-','Color',cmap(idc1(1),:),... +1392 'LineWidth',1,'Displayname',num2str(tmp(idx(i1))),'Parent',gui.axes2); +1393 end +1394 % adjust color limits +1395 set(gui.axes2,'CLim',clims); +1396 otherwise +1397 % need to plot transpose of FDIST because 'x' is a column vector +1398 % otherwise plot goes bananas if numel(x) = #models +1399 plot(invstd.T1T2me,FDIST','-','Color',[0.5 0.5 0.5],... +1400 'LineWidth',1,'Parent',gui.axes2); +1401 end +1402 end +1403 +1404 % if selected plot patch +1405 if plotmethod > 1 +1406 % what kind of patch is created +1407 if plotmethod == 2 % mean +- std +1408 mean_f = mean(FDIST); +1409 std_f = std(FDIST); +1410 else % median +- mad +1411 mean_f = median(FDIST); +1412 std_f = getAAD(FDIST,1); +1413 end +1414 +1415 % patch lower and upper bounds +1416 patch_f_std1 = [mean_f+std_f;mean_f-std_f]; +1417 patch_f_std2 = [mean_f+2*std_f;mean_f-2*std_f]; +1418 patch_f_std3 = [mean_f+3*std_f;mean_f-3*std_f]; +1419 patch_f_std1(patch_f_std1<0) = 0; +1420 patch_f_std2(patch_f_std2<0) = 0; +1421 patch_f_std3(patch_f_std3<0) = 0; +1422 f_max = max([ylims(2) max(patch_f_std1) max(patch_f_std2) max(patch_f_std3)]); +1423 +1424 % draw all three patches on top of each other +1425 verts = [invstd.T1T2me patch_f_std3(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std3(1,:)')]; +1426 faces = 1:1:size(verts,1); +1427 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.6 0.6 0.6],... +1428 'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2); +1429 verts = [invstd.T1T2me patch_f_std2(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std2(1,:)')]; +1430 faces = 1:1:size(verts,1); +1431 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.4 0.4 0.4],... +1432 'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2); +1433 verts = [invstd.T1T2me patch_f_std1(2,:)'; flipud(invstd.T1T2me) flipud(patch_f_std1(1,:)')]; +1434 faces = 1:1:size(verts,1); +1435 patch('Faces',faces,'Vertices',verts,'FaceColor',[0.2 0.2 0.2],... +1436 'FaceAlpha',0.75,'EdgeColor','none','Parent',gui.axes2); +1437 end +1438 +1439 % adjust y-limits +1440 ylims(2) = max([ylims(2) max(f_max)*1.05]); +1441 +1442 % plot original solution +1443 plot(invstd.T1T2me,F,'-','Color',col.FIT,'Parent',gui.axes2); +1444 +1445 % axes properties +1446 ticks = 10.^(round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me)))); +1447 set(gui.axes2,'XScale','log','XLim',[ticks(1) ticks(end)],'XTick',ticks); +1448 set(gui.axes2,'YScale','lin','YLim',ylims); +1449 set(get(gui.axes2,'XLabel'),'String','relaxation time'); +1450 set(get(gui.axes2,'YLabel'),'String','amplitude'); +1451 grid(gui.axes2,'on'); +1452 +1453 % -- RTD bounds -- +1454 uv = data.uv; +1455 % line([uv.rtd_range(1) uv.rtd_range(1)],[0 ylims(2)],'Color',[0.25 0.25 0.25],... +1456 % 'LineStyle','-.','LineWidth',2,'Parent',gui.axes2,'Tag','infolines'); +1457 % line([uv.rtd_range(2) uv.rtd_range(2)],[0 ylims(2)],'Color',[0.25 0.25 0.25],... +1458 % 'LineStyle','-.','LineWidth',2,'Parent',gui.axes2,'Tag','infolines'); +1459 p_alpha = 0.8; +1460 if uv.rtd_range(1)>ticks(1) +1461 % draw a transparent patch +1462 v = [ticks(1) ylims(1); ticks(1) ylims(2); +1463 uv.rtd_range(1) ylims(2); uv.rtd_range(1) ylims(1)]; +1464 f = [1 2 3 4 1]; +1465 patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +1466 'HandleVisibility','off','Tag','infolines','Parent', gui.axes2); +1467 end +1468 if uv.rtd_range(2)<ticks(end) +1469 % draw a transparent patch +1470 v = [ticks(end) ylims(1); ticks(end) ylims(2); +1471 uv.rtd_range(2) ylims(2); uv.rtd_range(2) ylims(1)]; +1472 f = [1 2 3 4 1]; +1473 patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... +1474 'HandleVisibility','off','Tag','infolines','Parent', gui.axes2); +1475 end +1476 +1477 % --- Histograms --- +1478 % [f1,xi1] = getKernelDensityEstimate(uncert.interp_E0(in)); +1479 % [f2,xi2] = getKernelDensityEstimate(uncert.interp_Tlgm(in)); +1480 [f1,xi1] = getKernelDensityEstimate(uv.stats.E0_all); +1481 [f2,xi2] = getKernelDensityEstimate(uv.stats.Tlgm_all); +1482 +1483 % plot the KDEs +1484 plot(xi1,f1,'Color',[0.5 0.5 0.5],'DisplayName','KDE','Parent',gui.axes21); +1485 plot(xi2,f2,'Color',[0.5 0.5 0.5],'DisplayName','KDE','Parent',gui.axes22); +1486 +1487 % "init" E0 +1488 line([invstd.E0 invstd.E0],[0 max(f1)],'Color',col.FIT,... +1489 'LineStyle',':','LineWidth',2,'Parent',gui.axes21,'DisplayName','init',... +1490 'Tag','infolines'); +1491 % "init" TLGM +1492 line([invstd.Tlgm invstd.Tlgm],[0 max(f2)],'Color',col.FIT,... +1493 'LineStyle',':','LineWidth',2,'Parent',gui.axes22,'DisplayName','init',... +1494 'Tag','infolines'); +1495 +1496 % mean E0 +1497 line([uv.E0(1) uv.E0(1)],[0 max(f1)],'Color',col.BoxPRC,... +1498 'LineStyle','-','LineWidth',2,'Parent',gui.axes21,'DisplayName','mean'); +1499 line([uv.E0(1)+2*uv.E0(2) uv.E0(1)+2*uv.E0(2)],[0 max(f1)],'Color',col.BoxPRC,... +1500 'LineStyle','--','LineWidth',1,'Parent',gui.axes21,'DisplayName','2*std'); +1501 line([uv.E0(1)-2*uv.E0(2) uv.E0(1)-2*uv.E0(2)],[0 max(f1)],'Color',col.BoxPRC,... +1502 'LineStyle','--','LineWidth',1,'Parent',gui.axes21,'DisplayName','2*std',... +1503 'HandleVisibility','off','Tag','infolines'); +1504 +1505 % mean TLGM +1506 line([uv.Tlgm(1) uv.Tlgm(1)],[0 max(f2)],'Color',col.BoxPRC,... +1507 'LineStyle','-','LineWidth',2,'Parent',gui.axes22,'DisplayName','mean'); +1508 line([uv.Tlgm(1)+2*uv.Tlgm(2) uv.Tlgm(1)+2*uv.Tlgm(2)],[0 max(f2)],'Color',col.BoxPRC,... +1509 'LineStyle','--','LineWidth',1,'Parent',gui.axes22,'DisplayName','2*std'); +1510 line([uv.Tlgm(1)-2*uv.Tlgm(2) uv.Tlgm(1)-2*uv.Tlgm(2)],[0 max(f2)],'Color',col.BoxPRC,... +1511 'LineStyle','--','LineWidth',1,'Parent',gui.axes22,'DisplayName','2*std',... +1512 'HandleVisibility','off','Tag','infolines'); +1513 +1514 % median E0 +1515 line([uv.E0_aadmed(1) uv.E0_aadmed(1)],[0 max(f1)],'Color',col.BoxCPS,... +1516 'LineStyle','-','LineWidth',2,'Parent',gui.axes21,'DisplayName','median'); +1517 line([uv.E0_aadmed(1)+2*uv.E0_aadmed(2) uv.E0_aadmed(1)+2*uv.E0_aadmed(2)],... +1518 [0 max(f1)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... +1519 'Parent',gui.axes21,'DisplayName','2*aad'); +1520 line([uv.E0_aadmed(1)-2*uv.E0_aadmed(2) uv.E0_aadmed(1)-2*uv.E0_aadmed(2)],... +1521 [0 max(f1)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... +1522 'Parent',gui.axes21,'DisplayName','2*aad','HandleVisibility','off',... +1523 'Tag','infolines'); +1524 +1525 % median TLGM +1526 line([uv.Tlgm_aadmed(1) uv.Tlgm_aadmed(1)],[0 max(f2)],'Color',col.BoxCPS,... +1527 'LineStyle','-','LineWidth',2,'Parent',gui.axes22,'DisplayName','median'); +1528 line([uv.Tlgm_aadmed(1)+2*uv.Tlgm_aadmed(2) uv.Tlgm_aadmed(1)+2*uv.Tlgm_aadmed(2)],... +1529 [0 max(f2)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... +1530 'Parent',gui.axes22,'DisplayName','2*aad'); +1531 line([uv.Tlgm_aadmed(1)-2*uv.Tlgm_aadmed(2) uv.Tlgm_aadmed(1)-2*uv.Tlgm_aadmed(2)],... +1532 [0 max(f2)],'Color',col.BoxCPS,'LineStyle','--','LineWidth',1,... +1533 'Parent',gui.axes22,'DisplayName','2*aad','HandleVisibility','off',... +1534 'Tag','infolines'); +1535 +1536 legend(gui.axes22,'Location','NorthWest'); +1537 +1538 % axes properties +1539 set(get(gui.axes21,'XLabel'),'String','E0'); +1540 set(get(gui.axes21,'YLabel'),'String','kernel denisty estimate'); +1541 set(get(gui.axes22,'XLabel'),'String','TLGM'); +1542 set(get(gui.axes22,'YLabel'),'String','kernel density estimate'); +1543 +1544 % hold off all axes +1545 hold(gui.axes11,'off'); +1546 hold(gui.axes12,'off'); +1547 hold(gui.axes2,'off'); +1548 hold(gui.axes21,'off'); +1549 hold(gui.axes22,'off'); +1550 end +1551 +1552 %% close function +1553 function uv_closeme(src,~) +1554 figh = ancestor(src,'figure','toplevel'); +1555 % try to close the sub GUI in a clean manner +1556 try +1557 % NOTE: maybe needed at some later point +1558 % gui = getappdata(figh,'gui'); +1559 % data = getappdata(gui.figh_nucleus,'data'); +1560 % % update NUCLEUSinv +1561 % setappdata(gui.figh_nucleus,'data',data); +1562 delete(figh); +1563 catch +1564 % if this is not working: just close it +1565 delete(figh); +1566 end +1567 +1568 end +1569 +1570 %------------- END OF CODE -------------- +1571 +1572 %% License: +1573 % MIT License +1574 % +1575 % Copyright (c) 2024 Thomas Hiller +1576 % +1577 % Permission is hereby granted, free of charge, to any person obtaining a copy +1578 % of this software and associated documentation files (the "Software"), to deal +1579 % in the Software without restriction, including without limitation the rights +1580 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +1581 % copies of the Software, and to permit persons to whom the Software is +1582 % furnished to do so, subject to the following conditions: +1583 % +1584 % The above copyright notice and this permission notice shall be included in all +1585 % copies or substantial portions of the Software. +1586 % +1587 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +1588 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +1589 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +1590 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +1591 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +1592 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +1593 % 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 2f7745f..7916e4d 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
  • 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
  • +
  • NUCLEUSinv_createPanelPlots creates graphics panel
  • NUCLEUSmod_createPanelPlots creates graphics panel
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • 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/cleanupGUIData.html b/doc/nucleus/functions/interface/cleanupGUIData.html index cd3e468..601ad97 100644 --- a/doc/nucleus/functions/interface/cleanupGUIData.html +++ b/doc/nucleus/functions/interface/cleanupGUIData.html @@ -66,7 +66,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importMOD2INV
  • importNMRdata is the general import routine for NMR data
  • +
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
  • importMOD2INV imports data directly from the NUCLEUSmod GUI or and
  • importNMRdata is the general import routine for NMR data
  • diff --git a/doc/nucleus/functions/interface/clearAllAxes.html b/doc/nucleus/functions/interface/clearAllAxes.html index 85a6dda..191d500 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
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • PhaseView is an extra subGUI to manipulate 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
  • importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
  • importMOD2INV imports data directly from the NUCLEUSmod GUI or and
  • 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/clearSingleAxis.html b/doc/nucleus/functions/interface/clearSingleAxis.html index 0c9306c..fac2217 100644 --- a/doc/nucleus/functions/interface/clearSingleAxis.html +++ b/doc/nucleus/functions/interface/clearSingleAxis.html @@ -61,7 +61,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • 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
  • onPopupInvjointTypeOptional select regularization option for the joint
  • onPopupInvstdTypeOptional select regularization option for the standard
  • onPopupPressureLoglin select if the pressure range values are spaced
  • 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"
  • caluclatePressureSaturation calculates the geometry dependent pressure
  • clearAllAxes clears all axes of a given figure
  • clearInversion removes inversion results from the internal data structure
  • runInversionJoint controls the joint inversion process to infer a pore size
  • runInversionStd controls the standard inversion process to invert a
  • updatePlotsDistribution plots the RTD and PSD curves into NUCLEUSinv
  • 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
  • +
  • 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
  • onPopupInvjointTypeOptional select regularization option for the joint
  • onPopupInvstdTypeOptional select regularization option for the standard
  • onPopupPressureLoglin select if the pressure range values are spaced
  • 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"
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • PhaseView is an extra subGUI to manipulate the phase of a T2 signal
  • caluclatePressureSaturation calculates the geometry dependent pressure
  • clearAllAxes clears all axes of a given figure
  • clearInversion removes inversion results from the internal data structure
  • runInversionJoint controls the joint inversion process to infer a pore size
  • runInversionStd controls the standard inversion process to invert a
  • updatePlotsDistribution plots the RTD and PSD curves into NUCLEUSinv
  • 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
  • @@ -104,46 +104,51 @@

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

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • NUCLEUSinv_createGUI controls the creation of all GUI elements
  • NUCLEUSmod_createGUI controls the creation of all GUI elements
  • LoadNMRData_rwth loads RWTH NMR data (saved by the old Prospa version)
  • calculateNMR calculates the NMR signals for the full and partially saturated
  • caluclatePressureSaturation calculates the geometry dependent pressure
  • exportData exports data from both GUIs into various formats
  • exportGraphics exports graphics from both GUIs into various formats
  • exportINV exports NUCLEUSinv GUI data to a mat-file
  • importCalibrationData
  • importINV2INV imports a previously saved NUCLEUSinv session
  • importNMRdata is the general import routine for NMR data
  • runInversionBatch batch processes the inversion using for all NMR signals
  • runInversionJoint controls the joint inversion process to infer a pore size
  • runInversionStd controls the standard inversion process to invert a
  • useSignalAsCalibration uses E0 as porosity calibration factor.
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • +
  • NUCLEUSinv_createGUI controls the creation of all GUI elements
  • NUCLEUSmod_createGUI controls the creation of all GUI elements
  • LoadNMRData_rwth loads RWTH NMR data (saved by the old Prospa version)
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • calculateNMR calculates the NMR signals for the full and partially saturated
  • caluclatePressureSaturation calculates the geometry dependent pressure
  • exportData exports data from both GUIs into various formats
  • exportGraphics exports graphics from both GUIs into various formats
  • exportINV exports NUCLEUSinv GUI data to a mat-file
  • importCalibrationData
  • importINV2INV imports a previously saved NUCLEUSinv session
  • importNMRdata is the general import routine for NMR data
  • runInversionBatch batch processes the inversion using for all NMR signals
  • runInversionJoint controls the joint inversion process to infer a pore size
  • runInversionStd controls the standard inversion process to invert a
  • useSignalAsCalibration uses E0 as porosity calibration factor.
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • diff --git a/doc/nucleus/functions/interface/enableGUIelements.html b/doc/nucleus/functions/interface/enableGUIelements.html index e8d60ab..94dd315 100644 --- a/doc/nucleus/functions/interface/enableGUIelements.html +++ b/doc/nucleus/functions/interface/enableGUIelements.html @@ -62,7 +62,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=onMenuExpert handles the call from the menu that activates / deactivates This function is called by: +
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importINV2INV imports a previously saved NUCLEUSinv session
  • importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
  • importMOD2INV imports data directly from the NUCLEUSmod GUI or and
  • importNMRdata is the general import routine for NMR data
  • diff --git a/doc/nucleus/functions/interface/importASCIIdata.html b/doc/nucleus/functions/interface/importASCIIdata.html index 2b9e466..c94a6f4 100644 --- a/doc/nucleus/functions/interface/importASCIIdata.html +++ b/doc/nucleus/functions/interface/importASCIIdata.html @@ -61,7 +61,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: @@ -234,7 +234,7 @@

    SOURCE CODE ^if size(tmp_data,2)>2 0164 tmp_signal = complex(tmp_data(:,2),tmp_data(:,3)); -0165 [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); +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 diff --git a/doc/nucleus/functions/interface/importEXCELdata.html b/doc/nucleus/functions/interface/importEXCELdata.html index f7f3432..e0c7225 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: @@ -268,7 +268,7 @@

    SOURCE CODE ^if size(num,2)>2 0197 tmp_signal = complex(num(:,2),num(:,3)); -0198 [tmp_signal,tmp_phase] = rotateT2phase(tmp_signal); +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 diff --git a/doc/nucleus/functions/interface/importMOD2D2INV.html b/doc/nucleus/functions/interface/importMOD2D2INV.html new file mode 100644 index 0000000..c81f97f --- /dev/null +++ b/doc/nucleus/functions/interface/importMOD2D2INV.html @@ -0,0 +1,322 @@ + + + + Description of importMOD2D2INV + + + + + + + + + + + +

    importMOD2D2INV +

    + +

    PURPOSE ^

    +
    imports data directly from the NUCLEUSmod 2D GUI
    + +

    SYNOPSIS ^

    +
    function importMOD2D2INV(src)
    + +

    DESCRIPTION ^

    +
    importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
    +
    + Syntax:
    +       importMOD2INV(src)
    +
    + Inputs:
    +       src - handle to the calling uimenu
    +
    + Outputs:
    +       none
    +
    + Example:
    +       importMOD2INV(src)
    +
    + Other m-files required:
    +       clearAllAxes
    +       enableGUIelements
    +       NUCLEUSinv_updateInterface
    +
    + 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: + + + + + +

    SOURCE CODE ^

    +
    0001 function importMOD2D2INV(src)
    +0002 %importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
    +0003 %
    +0004 % Syntax:
    +0005 %       importMOD2INV(src)
    +0006 %
    +0007 % Inputs:
    +0008 %       src - handle to the calling uimenu
    +0009 %
    +0010 % Outputs:
    +0011 %       none
    +0012 %
    +0013 % Example:
    +0014 %       importMOD2INV(src)
    +0015 %
    +0016 % Other m-files required:
    +0017 %       clearAllAxes
    +0018 %       enableGUIelements
    +0019 %       NUCLEUSinv_updateInterface
    +0020 %
    +0021 % Subfunctions:
    +0022 %       none
    +0023 %
    +0024 % MAT-files required:
    +0025 %       none
    +0026 %
    +0027 % See also: NUCLEUSinv
    +0028 % Author: see AUTHORS.md
    +0029 % email: see AUTHORS.md
    +0030 % License: MIT License (at end)
    +0031 
    +0032 %------------- BEGIN CODE --------------
    +0033 
    +0034 %% get GUI handle and data
    +0035 fig = findobj('Tag','INV');
    +0036 gui = getappdata(fig,'gui');
    +0037 data = getappdata(fig,'data');
    +0038 
    +0039 % remove old fields and data
    +0040 data = cleanupGUIData(data);
    +0041 
    +0042 % check import format and load the data
    +0043 label = get(src,'Label');
    +0044 
    +0045 % get file name
    +0046 NMRpath = -1;
    +0047 NMRfile = -1;
    +0048 switch label
    +0049     case '2D GUI'
    +0050         % check if GUI is open
    +0051         figmod = findobj('Tag','2DMOD');
    +0052         if ~isempty(figmod)
    +0053             % now check if there is data to use
    +0054             datamod = getappdata(figmod,'data');
    +0055             if isfield(datamod,'results')
    +0056                 if isfield(datamod.results,'mod2D')
    +0057                     % file info
    +0058                     fileID.name = 'NUCLEUSmod 2D GUI';
    +0059                     fileID.date = string(datetime("now"));
    +0060                     fileID.datenum = convertTo(datetime("now"),"datenum");
    +0061                     fileID.bytes = 0;
    +0062                     
    +0063                     NMRpath = pwd;
    +0064                     NMRfile = 'NUCLEUSmod 2D GUI';
    +0065                     % import the data
    +0066                     data.import.NMRMOD.nmr = datamod.results.mod2D.data;
    +0067                 else
    +0068                     helpdlg({'importNUCLEUSmod:',...
    +0069                         'No data in NUCLEUSmod to use.'},'no data');
    +0070                 end
    +0071             else
    +0072                 helpdlg({'importNUCLEUSmod:',...
    +0073                     'No data in NUCLEUSmod to use.'},'no data');
    +0074             end
    +0075         else
    +0076             helpdlg({'importNUCLEUSmod:',...
    +0077                 'NUCLEUSmod is not open.'},'not found');
    +0078         end
    +0079     otherwise
    +0080         helpdlg({'importNUCLEUSmod2d:',...
    +0081                 'NUCLEUSmod 2D is not open.'},'not found');
    +0082 end
    +0083 
    +0084 % if data was imported we can proceed
    +0085 if isfield(data.import,'NMRMOD')
    +0086     data.import.fileformat = 'NMRMOD';
    +0087     data.import.path = NMRpath;
    +0088     data.import.file = NMRfile;
    +0089     
    +0090     % update the path-info string
    +0091     if NMRfile > 0
    +0092         tmpstr = fullfile(NMRpath,NMRfile);
    +0093     else
    +0094         tmpstr = NMRpath;
    +0095     end
    +0096     if length(tmpstr)>50
    +0097         set(gui.text_handles.data_path,'String',['...',tmpstr(end-50:end)],...
    +0098             'HorizontalAlignment','left');
    +0099     else
    +0100         set(gui.text_handles.data_path,'String',tmpstr,...
    +0101             'HorizontalAlignment','left');
    +0102     end
    +0103     set(gui.text_handles.data_path,'TooltipString',tmpstr);
    +0104     
    +0105     fnames = struct;
    +0106     % shownames is just a dummy to hold all data file names that
    +0107     % will be shown in the listbox
    +0108     shownames = cell(1,1);
    +0109     
    +0110     T1T2 = 'T2';
    +0111     T1IRfac = datamod.nmr.T1IRfac;
    +0112     
    +0113     c = 0;
    +0114     for i = 1:numel(data.import.NMRMOD.nmr)
    +0115         % the individual file names
    +0116         c = c + 1;
    +0117         fnames(c).parfile = '';
    +0118         fnames(c).datafile = data.import.file;
    +0119         fnames(c).T2specfile = '';
    +0120         
    +0121         shownames{c} = ['NUCLEUSmod_',T1T2,'_2D_',num2str(i)];
    +0122         
    +0123         % the 'header' data
    +0124         data.import.NMR.data{c}.datfile = fileID.name;
    +0125         data.import.NMR.data{c}.date = datestr(addtodate(fileID.datenum,-numel(data.import.NMRMOD.nmr)+i,'minute'));
    +0126         data.import.NMR.data{c}.datenum = addtodate(fileID.datenum,-numel(data.import.NMRMOD.nmr)+i,'minute');
    +0127         data.import.NMR.data{c}.bytes = fileID.bytes;
    +0128         % the NMR data
    +0129         data.import.NMR.data{c}.flag = T1T2;
    +0130         data.import.NMR.data{c}.T1IRfac = T1IRfac;
    +0131         data.import.NMR.data{c}.time = data.import.NMRMOD.nmr(i).t(:);
    +0132 
    +0133         data.import.NMR.data{c}.signal = data.import.NMRMOD.nmr(i).s(:);
    +0134         data.import.NMR.data{c}.noise = data.import.NMRMOD.nmr(i).noise;
    +0135 
    +0136         data.import.NMR.data{c}.phase = 0;
    +0137         data.import.NMR.data{c}.raw.time = data.import.NMR.data{c}.time;
    +0138         data.import.NMR.data{c}.raw.signal = data.import.NMR.data{c}.signal;
    +0139         
    +0140         % data.import.NMR.para{c}.geom = data.import.NMRMOD.geom.type;
    +0141         data.import.NMR.para{c}.Tbulk = datamod.prop.Tbulk;
    +0142         data.import.NMR.para{c}.Tdiff = 1e6;
    +0143         data.import.NMR.para{c}.t_echo = datamod.nmr.T2te;
    +0144         data.import.NMR.para{c}.rho = 100;
    +0145         data.import.NMR.para{c}.porosity = 1;
    +0146     end
    +0147     
    +0148     % set T2 echo time
    +0149     data.inv2D.prop.te = datamod.nmr.T2te;
    +0150 
    +0151     % save the recovery time vector for later use
    +0152     data.import.T1T2map.t_recov = datamod.results.mod2D.t_recov(:);
    +0153     data.import.T1T2map.t2 = data.import.NMR.data{1}.time;
    +0154     data.import.T1T2map.t2N = numel(data.import.NMR.data{1}.time);
    +0155 
    +0156     % add the stacked signal to the data
    +0157     flag = 'T1';
    +0158     time = data.import.T1T2map.t_recov;
    +0159     signal = zeros(numel(data.import.NMR.data),1);
    +0160     for i1 = 1:numel(data.import.NMR.data)
    +0161         % signal(i1,1) = mean(real(data.import.NMR.data{i1}.signal(1:3)));
    +0162         signal(i1,1) = real(data.import.NMR.data{i1}.signal(1));
    +0163     end
    +0164     disp('NUCLUESinv import: Estimating noise from exponential fit ...');
    +0165     param.T1IRfac = 2;
    +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     for i1 = 1:5
    +0171         invstd = fitDataFree(time,signal,flag,param,i1);
    +0172         if i1 == 1
    +0173             noise = invstd.rms;
    +0174         else
    +0175             noise = min([noise invstd.rms]);
    +0176         end
    +0177     end
    +0178     disp('NUCLUESinv import: done.')
    +0179     % finally create a new "import" data set
    +0180     data_new = data.import.NMR.data(1);
    +0181     para_new = data.import.NMR.para(1);
    +0182 
    +0183     data_new{1}.flag = flag;
    +0184     data_new{1}.T1IRfac = param.T1IRfac;
    +0185     data_new{1}.time = time;
    +0186     data_new{1}.signal = signal;
    +0187     data_new{1}.noise = noise;
    +0188     data_new{1}.raw.time = time;
    +0189     data_new{1}.raw.signal = signal;
    +0190 
    +0191     data.import.NMR.data{numel(time)+1} = data_new{1};
    +0192     data.import.NMR.para{numel(time)+1} = para_new{1};
    +0193     fnames(numel(time)+1).datafile = 'T1_merged.dat';
    +0194     shownames{numel(time)+1} = 'T1_merged';
    +0195 
    +0196     data.import.NMR.files = fnames;
    +0197     data.import.NMR.filesShort = shownames;
    +0198 
    +0199     % update the list of file names
    +0200     set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort);
    +0201     set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0);
    +0202     
    +0203     % create a global INVdata struct for every file in the list
    +0204     if isstruct(getappdata(fig,'INVdata'))
    +0205         setappdata(fig,'INVdata',[]);
    +0206     end
    +0207     INVdata = cell(length(data.import.NMR.filesShort),1);
    +0208     setappdata(fig,'INVdata',INVdata);
    +0209     
    +0210     %  clear all axes
    +0211     clearAllAxes(gui.figh);
    +0212     
    +0213     % enable GUI data and interface
    +0214     setappdata(fig,'data',data);
    +0215     setappdata(fig,'gui',gui);
    +0216     enableGUIelements('MOD');
    +0217     NUCLEUSinv_updateInterface;
    +0218 else
    +0219     helpdlg({'importNUCLEUSmod:',...
    +0220         'NUCLEUSmod data import unsuccessful.'},'import error');
    +0221 end
    +0222 
    +0223 end
    +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.
    +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.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/interface/importMOD2INV.html b/doc/nucleus/functions/interface/importMOD2INV.html index d82d4b2..f60f08b 100644 --- a/doc/nucleus/functions/interface/importMOD2INV.html +++ b/doc/nucleus/functions/interface/importMOD2INV.html @@ -4,7 +4,7 @@ Description of importMOD2INV - + @@ -20,13 +20,13 @@

    importMOD2INV

    PURPOSE ^

    -
    +
    imports data directly from the NUCLEUSmod GUI or and

    SYNOPSIS ^

    function importMOD2INV(src)

    DESCRIPTION ^

    -
    importINV2INV imports data directly from the NUCLEUSmod GUI or and
    +
    importMOD2INV imports data directly from the NUCLEUSmod GUI or and
     NUCLEUSmod data file
     
      Syntax:
    @@ -71,7 +71,7 @@ 

    CROSS-REFERENCE INFORMATION ^
 
 <h2><a name=SOURCE CODE ^

    0001 function importMOD2INV(src)
    -0002 %importINV2INV imports data directly from the NUCLEUSmod GUI or and
    +0002 %importMOD2INV imports data directly from the NUCLEUSmod GUI or and
     0003 %NUCLEUSmod data file
     0004 %
     0005 % Syntax:
    @@ -159,8 +159,8 @@ 

    SOURCE CODE ^if isfield(datamod.results,'NMR') 0088 % file info 0089 fileID.name = 'NUCLEUSmod GUI'; -0090 fileID.date = datestr(now); -0091 fileID.datenum = now; +0090 fileID.date = string(datetime("now")); +0091 fileID.datenum = convertTo(datetime("now"),"datenum"); 0092 fileID.bytes = 0; 0093 0094 NMRpath = pwd; diff --git a/doc/nucleus/functions/interface/importNMRdata.html b/doc/nucleus/functions/interface/importNMRdata.html index 386697e..1f710eb 100644 --- a/doc/nucleus/functions/interface/importNMRdata.html +++ b/doc/nucleus/functions/interface/importNMRdata.html @@ -73,7 +73,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • NUCLEUSinv_updateInterface updates all GUI elements
  • LoadNMRData_driver loads NMR raw data from different file formats
  • fixParameterString cleans parameter file lines when the properties have a
  • 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
  • displayStatusText shows status information either in the GUI or on the
  • 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: @@ -81,7 +81,7 @@

    CROSS-REFERENCE INFORMATION ^
 
 <h2><a name=SUBFUNCTIONS ^

    +
  • function [NMRpath,NMRfile] = getNMRPathFile(label,import)
  • function [data,gui] = importDataMouseCPMG(data,gui)
  • function [data,gui] = importDataBGRmat(data,gui)
  • function [data,gui] = importDataBGRliftSingle(data,gui)
  • function [data,gui] = importDataBGRlift(data,gui)
  • function [data,gui] = importDataHeliosCPMG(data,gui)
  • function [data,gui] = importDataHeliosSeries(data,gui)
  • function [data,gui] = importDataDartSeries(data,gui)
  • function [data,gui] = importDataDartT2logging(data,gui,useburst)
  • function [data,gui] = importDataDart(data,gui)
  • function [data,gui] = importDataRoCAT1T2(data,gui)
  • function [data,gui] = importDataGeneral(data,gui)
  • function [data,gui] = importDataLIAG(data,gui)
  • function [data,gui] = importDataLIAGcore(data,gui)
  • function [data,gui] = importDataLIAGproject(data,gui)
  • function [data,gui] = importDataMouse(data,gui)
  • function [data,gui] = importDataIBAC(data,gui)
  • function data = loadGUIParameters(datapath,fname)
  • function data = loadGUIrawdata(data,NMRpath,NMRfile)
  • SOURCE CODE ^

    0001 function importNMRdata(src)
    @@ -142,1473 +142,2210 @@ 

    SOURCE CODE ^'Label'); 0057 0058 % set file format for later use -0059 if strcmp(label,'BAM TOM') -0060 data.import.fileformat = 'bamtom'; -0061 elseif strcmp(label,'BGR mat') -0062 data.import.fileformat = 'bgrmat'; -0063 elseif strcmp(label,'BGR std') -0064 data.import.fileformat = 'bgr'; -0065 elseif strcmp(label,'CoreLab ascii') -0066 data.import.fileformat = 'corelab'; -0067 elseif strcmp(label,'DART') -0068 data.import.fileformat = 'dart'; -0069 elseif strcmp(label,'GGE ascii') -0070 data.import.fileformat = 'rwth'; -0071 elseif strcmp(label,'GGE field') -0072 data.import.fileformat = 'field'; -0073 elseif strcmp(label,'GGE Dart') -0074 data.import.fileformat = 'dart'; -0075 elseif strcmp(label,'HeliosCPMG') -0076 data.import.fileformat = 'heliosCPMG'; -0077 elseif strcmp(label,'HeliosSeries') -0078 data.import.fileformat = 'heliosSeries'; -0079 elseif strcmp(label,'LIAG core') -0080 data.import.fileformat = 'liag'; -0081 elseif strcmp(label,'LIAG from project') -0082 data.import.fileformat = 'liag'; -0083 elseif strcmp(label,'LIAG last project') -0084 data.import.fileformat = 'liag'; -0085 elseif strcmp(label,'LIAG single') +0059 if strcmp(label,'Dart T1T2') +0060 data.import.fileformat = 'dartSeries'; +0061 elseif strcmp(label,'Dart T2 logging') +0062 data.import.fileformat = 'dartT2logging'; +0063 elseif strcmp(label,'BAM TOM') +0064 data.import.fileformat = 'bamtom'; +0065 elseif strcmp(label,'BGR mat') +0066 data.import.fileformat = 'bgrmat'; +0067 elseif strcmp(label,'BGR std') +0068 data.import.fileformat = 'bgr'; +0069 elseif strcmp(label,'CoreLab ascii') +0070 data.import.fileformat = 'corelab'; +0071 elseif strcmp(label,'DART') +0072 data.import.fileformat = 'dart'; +0073 elseif strcmp(label,'DART (+Burst)') +0074 data.import.fileformat = 'dartT2logging'; +0075 elseif strcmp(label,'GGE ascii') +0076 data.import.fileformat = 'rwth'; +0077 elseif strcmp(label,'GGE field') +0078 data.import.fileformat = 'field'; +0079 elseif strcmp(label,'GGE Dart') +0080 data.import.fileformat = 'dart'; +0081 elseif strcmp(label,'HeliosCPMG') +0082 data.import.fileformat = 'heliosCPMG'; +0083 elseif strcmp(label,'HeliosSeries') +0084 data.import.fileformat = 'heliosSeries'; +0085 elseif strcmp(label,'LIAG core') 0086 data.import.fileformat = 'liag'; -0087 elseif strcmp(label,'MOUSE') -0088 data.import.fileformat = 'mouse'; -0089 elseif strcmp(label,'MouseCPMG') -0090 data.import.fileformat = 'MouseCPMG'; -0091 elseif strcmp(label,'MouseLift') -0092 data.import.fileformat = 'MouseLift'; -0093 elseif strcmp(label,'PM5') -0094 data.import.fileformat = 'pm5'; -0095 elseif strcmp(label,'PM25') -0096 data.import.fileformat = 'pm25'; -0097 else -0098 helpdlg('Something is utterly wrong.','onMenuImport: Choose again.'); -0099 end -0100 -0101 % remove info field if any -0102 ih = findobj('Tag','inv_info'); -0103 if ~isempty(ih); delete(ih); end -0104 -0105 % depending on the import format get the corresponding path / file -0106 [NMRpath,NMRfile] = getNMRPathFile(label,data.import); -0107 -0108 % only continue if user didn't cancel -0109 if sum([NMRpath NMRfile]) > 0 -0110 % remove old fields and data -0111 data = cleanupGUIData(data); -0112 -0113 % check for mat-file with GUI rawdata and import data -0114 isfile = dir(fullfile(NMRpath,'NUCLEUSinv_raw.mat')); -0115 -0116 % if there is no raw-file import from folder/file -0117 if isempty(isfile) -0118 % import data -0119 data.import.path = NMRpath; -0120 data.import.file = -1; -0121 displayStatusText(gui,'Reading NMR Data ...'); -0122 % call the corresponding subroutines -0123 switch label -0124 case {'BAM TOM','BGR std','CoreLab ascii','GGE ascii',... -0125 'GGE field'} -0126 [data,gui] = importDataGeneral(data,gui); -0127 case 'GGE Dart' -0128 data.import.file = NMRfile; -0129 % the data in the example folder is an older type -0130 if contains(NMRpath,'nucleus\example_data\dart') -0131 data.import.version = 1; -0132 else -0133 data.import.version = 2; -0134 end -0135 [data,gui] = importDataDart(data,gui); -0136 case 'DART' -0137 data.import.file = NMRfile; -0138 data.import.version = 3; -0139 [data,gui] = importDataDart(data,gui); -0140 case 'MOUSE' -0141 [data,gui] = importDataMouse(data,gui); -0142 case 'LIAG single' -0143 [data,gui] = importDataLIAG(data,gui); -0144 case 'LIAG core' -0145 [data,gui] = importDataLIAGcore(data,gui); -0146 case {'LIAG from project','LIAG last project'} -0147 [data,gui] = importDataLIAGproject(data,gui); -0148 % make the Petro Panel visible as default -0149 tmp_h = gui.myui.heights(2,:); -0150 tmp_h(3) = gui.myui.heights(2,3); -0151 % but the CPS panel stays minimized -0152 tmp_h(5) = gui.myui.heights(1,3); -0153 set(gui.panels.main,'Heights',tmp_h); -0154 set(gui.panels.petro.main,'Minimized',false); -0155 case 'BGR mat' -0156 data.import.file = NMRfile; -0157 [data,gui] = importDataBGRmat(data,gui); -0158 case 'MouseCPMG' -0159 [data,gui] = importDataMouseCPMG(data,gui); -0160 case 'MouseLift' -0161 [data,gui] = importDataBGRlift(data,gui); -0162 case 'HeliosCPMG' -0163 data.import.file = NMRfile; -0164 [data,gui] = importDataHeliosCPMG(data,gui); -0165 case 'HeliosSeries' -0166 data.import.file = NMRfile; -0167 [data,gui] = importDataHeliosSeries(data,gui); -0168 case {'PM5','PM25'} -0169 data.import.file = NMRfile; -0170 [data,gui] = importDataIBAC(data,gui); -0171 end -0172 displayStatusText(gui,'Reading NMR Data ... done'); -0173 else -0174 % import from mat-file -0175 displayStatusText(gui,'Importing NMR raw data from mat-file ...'); -0176 data = loadGUIrawdata(data,NMRpath,NMRfile); -0177 displayStatusText(gui,'Importing NMR raw data from mat-file ... done'); -0178 end -0179 -0180 % update the path info field with "NMRpath" ("NMRfile") -0181 if NMRfile > 0 -0182 tmpstr = fullfile(NMRpath,NMRfile); -0183 else -0184 tmpstr = NMRpath; -0185 end -0186 if length(tmpstr)>50 -0187 set(gui.text_handles.data_path,'String',['...',tmpstr(end-50:end)],... -0188 'HorizontalAlignment','left'); -0189 else -0190 set(gui.text_handles.data_path,'String',tmpstr,... -0191 'HorizontalAlignment','left'); -0192 end -0193 set(gui.text_handles.data_path,'TooltipString',tmpstr); -0194 -0195 % update the ini-file -0196 gui.myui.inidata.importpath = data.import.path; -0197 gui = makeINIfile(gui,'update'); -0198 -0199 % update the list of file names -0200 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); -0201 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); -0202 -0203 % create a global INVdata struct for every file in the list -0204 if isstruct(getappdata(fig,'INVdata')) -0205 setappdata(fig,'INVdata',[]); -0206 end -0207 INVdata = cell(length(data.import.NMR.filesShort),1); -0208 setappdata(fig,'INVdata',INVdata); -0209 -0210 % clear all axes -0211 clearAllAxes(gui.figh); -0212 -0213 % update GUI data and interface -0214 setappdata(fig,'data',data); -0215 setappdata(fig,'gui',gui); -0216 enableGUIelements('NMR'); -0217 -0218 % special treatment of LIAG projects -0219 switch label -0220 case {'LIAG from project','LIAG last project'} -0221 cpath = data.import.LIAG.calibrationpath; -0222 % check if this calibration file was already used -0223 isfile = dir(fullfile(cpath,'NUCLEUS_calibData.mat')); -0224 if ~isempty(isfile) -0225 id = 2; -0226 % if data is there reuse it -0227 calib = load(fullfile(cpath,isfile.name),'calib'); -0228 INVdata{id} = calib.calib; -0229 data.calib = INVdata{id}.calib; -0230 data.import.LIAG.Tbulk = INVdata{id}.results.invstd.T2; -0231 setappdata(fig,'INVdata',INVdata); -0232 setappdata(fig,'data',data); -0233 % color the list entry -0234 strL = get(gui.listbox_handles.signal,'String'); -0235 str1 = strL{id}; -0236 str2 = ['<HTML><BODY bgcolor="rgb(',... -0237 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',... -0238 str1,'</BODY></HTML>']; -0239 strL{id} = str2; -0240 set(gui.listbox_handles.signal,'String',strL); -0241 end -0242 otherwise -0243 end -0244 % update GUI interface -0245 NUCLEUSinv_updateInterface; -0246 end -0247 -0248 catch ME -0249 % show error message in case import fails -0250 errmsg = {ME.message;[ME.stack(1).name,' Line: ',num2str(ME.stack(1).line)];... -0251 'Check File Format settings.'}; -0252 errordlg(errmsg,'importNMRdata: Error!'); -0253 end -0254 -0255 end -0256 -0257 %% -0258 function [NMRpath,NMRfile] = getNMRPathFile(label,import) -0259 -0260 NMRpath = -1; -0261 NMRfile = -1; -0262 % for almost all import cases we load a folder ... but not for all -0263 switch label -0264 case {'BAM TOM','BGR std','CoreLab ascii','GGE ascii','GGE field',... -0265 'HeliosCPMG','HeliosSeries','LIAG core','LIAG single',... -0266 'MOUSE','MouseCPMG','MouseLift','PM25'} -0267 % if there is already a data folder present we start from here -0268 if isfield(import,'path') -0269 NMRpath = uigetdir(import.path,'Choose Data Path'); -0270 else -0271 % otherwise we start at the current working dircetory -0272 % 'NMRpath' holds the name of the choosen data path -0273 here = mfilename('fullpath'); -0274 [pathstr,~,~] = fileparts(here); -0275 NMRpath = uigetdir(pathstr,'Choose Data Path'); -0276 end -0277 case 'LIAG from project' -0278 % if there is already a data folder present we start from here -0279 if isfield(import,'path') -0280 NMRpath = uigetdir(import.path,'Choose Project Path'); -0281 else -0282 % otherwise we start at the current working dircetory -0283 % 'NMRpath' holds the name of the choosen data path -0284 here = mfilename('fullpath'); -0285 [pathstr,~,~] = fileparts(here); -0286 NMRpath = uigetdir(pathstr,'Choose Project Path'); -0287 end -0288 case 'LIAG last project' -0289 % there is already a data folder and we use this one -0290 if isfield(import,'path') -0291 NMRpath = import.path; -0292 else -0293 % otherwise we start at the current working dircetory -0294 % 'NMRpath' holds the name of the choosen data path -0295 here = mfilename('fullpath'); -0296 [pathstr,~,~] = fileparts(here); -0297 NMRpath = uigetdir(pathstr,'Choose Project Path'); -0298 end -0299 case {'GGE Dart','DART','BGR mat','NMR mat'} -0300 % if there is already a data folder present we start from here -0301 if isfield(import,'path') -0302 [NMRfile,NMRpath] = uigetfile(import.path,'Choose Data file'); -0303 else -0304 % otherwise we start at the current working dircetory -0305 % 'foldername' hold s the name of the choosen data path -0306 here = mfilename('fullpath'); -0307 [pathstr,~,~] = fileparts(here); -0308 [NMRfile,NMRpath] = uigetfile(pathstr,'Choose Data file'); -0309 end -0310 case 'PM5' -0311 % if there is already a data folder present we start from here -0312 if isfield(import,'path') -0313 NMRpath = uigetdir(import.path,'Choose PM5 Data Path'); -0314 else -0315 % otherwise we start at the current working dircetory -0316 % 'NMRpath' holds the name of the choosen data path -0317 here = mfilename('fullpath'); -0318 [pathstr,~,~] = fileparts(here); -0319 NMRpath = uigetdir(pathstr,'Choose PM5 Data Path'); -0320 end -0321 -0322 % check if there are multiple inf-files available -0323 % if yes -> choose one -0324 inffiles = dir(fullfile(NMRpath,'*.inf')); -0325 if numel(inffiles) > 1 -0326 [NMRfile,NMRpath] = uigetfile(fullfile(NMRpath,'*.inf'),... -0327 'Choose INF file'); -0328 elseif numel(inffiles) == 1 -0329 NMRfile = inffiles.name; +0087 elseif strcmp(label,'LIAG from project') +0088 data.import.fileformat = 'liag'; +0089 elseif strcmp(label,'LIAG last project') +0090 data.import.fileformat = 'liag'; +0091 elseif strcmp(label,'LIAG single') +0092 data.import.fileformat = 'liag'; +0093 elseif strcmp(label,'MOUSE') +0094 data.import.fileformat = 'mouse'; +0095 elseif strcmp(label,'MouseCPMG') +0096 data.import.fileformat = 'MouseCPMG'; +0097 elseif strcmp(label,'MouseLift') +0098 data.import.fileformat = 'MouseLift'; +0099 elseif strcmp(label,'PM5') +0100 data.import.fileformat = 'pm5'; +0101 elseif strcmp(label,'PM25') +0102 data.import.fileformat = 'pm25'; +0103 elseif strcmp(label,'RoCA T1T2') +0104 data.import.fileformat = 'rocaT1T2'; +0105 else +0106 helpdlg('Something is utterly wrong.','onMenuImport: Choose again.'); +0107 end +0108 +0109 % remove info field if any +0110 ih = findobj('Tag','inv_info'); +0111 if ~isempty(ih); delete(ih); end +0112 +0113 % depending on the import format get the corresponding path / file +0114 [NMRpath,NMRfile] = getNMRPathFile(label,data.import); +0115 +0116 % only continue if user didn't cancel +0117 if sum([NMRpath NMRfile]) > 0 +0118 % remove old fields and data +0119 data = cleanupGUIData(data); +0120 +0121 % check for mat-file with GUI rawdata and import data +0122 isfile = dir(fullfile(NMRpath,'NUCLEUSinv_raw.mat')); +0123 +0124 % if there is no raw-file import from folder/file +0125 if isempty(isfile) +0126 % import data +0127 data.import.path = NMRpath; +0128 data.import.file = -1; +0129 displayStatusText(gui,'Reading NMR Data ...'); +0130 % call the corresponding subroutines +0131 switch label +0132 case {'BAM TOM','BGR std','CoreLab ascii','GGE ascii',... +0133 'GGE field'} +0134 [data,gui] = importDataGeneral(data,gui); +0135 case 'GGE Dart' +0136 data.import.file = NMRfile; +0137 % the data in the example folder is an older type +0138 if contains(NMRpath,'nucleus\example_data\dart') +0139 data.import.version = 1; +0140 else +0141 data.import.version = 2; +0142 end +0143 [data,gui] = importDataDart(data,gui); +0144 case 'DART' +0145 data.import.file = NMRfile; +0146 data.import.version = 3; +0147 [data,gui] = importDataDart(data,gui); +0148 case 'DART (+Burst)' +0149 data.import.file = NMRfile; +0150 [data,gui] = importDataDartT2logging(data,gui,1); +0151 case 'MOUSE' +0152 [data,gui] = importDataMouse(data,gui); +0153 case 'LIAG single' +0154 [data,gui] = importDataLIAG(data,gui); +0155 case 'LIAG core' +0156 [data,gui] = importDataLIAGcore(data,gui); +0157 case {'LIAG from project','LIAG last project'} +0158 [data,gui] = importDataLIAGproject(data,gui); +0159 % make the Petro Panel visible as default +0160 tmp_h = gui.myui.heights(2,:); +0161 tmp_h(3) = gui.myui.heights(2,3); +0162 % but the CPS panel stays minimized +0163 tmp_h(5) = gui.myui.heights(1,3); +0164 set(gui.panels.main,'Heights',tmp_h); +0165 set(gui.panels.petro.main,'Minimized',false); +0166 case 'BGR mat' +0167 data.import.file = NMRfile; +0168 [data,gui] = importDataBGRmat(data,gui); +0169 case 'MouseCPMG' +0170 [data,gui] = importDataMouseCPMG(data,gui); +0171 case 'MouseLift' +0172 [data,gui] = importDataBGRlift(data,gui); +0173 case 'HeliosCPMG' +0174 data.import.file = NMRfile; +0175 [data,gui] = importDataHeliosCPMG(data,gui); +0176 case 'HeliosSeries' +0177 data.import.file = NMRfile; +0178 [data,gui] = importDataHeliosSeries(data,gui); +0179 case {'PM5','PM25'} +0180 data.import.file = NMRfile; +0181 [data,gui] = importDataIBAC(data,gui); +0182 case 'Dart T1T2' +0183 data.import.file = NMRfile; +0184 [data,gui] = importDataDartSeries(data,gui); +0185 case 'Dart T2 logging' +0186 data.import.file = NMRfile; +0187 [data,gui] = importDataDartT2logging(data,gui,0); +0188 case 'RoCA T1T2' +0189 data.import.file = NMRfile; +0190 [data,gui] = importDataRoCAT1T2(data,gui); +0191 end +0192 displayStatusText(gui,'Reading NMR Data ... done'); +0193 else +0194 % import from mat-file +0195 displayStatusText(gui,'Importing NMR raw data from mat-file ...'); +0196 data = loadGUIrawdata(data,NMRpath,NMRfile); +0197 displayStatusText(gui,'Importing NMR raw data from mat-file ... done'); +0198 end +0199 +0200 % update the path info field with "NMRpath" ("NMRfile") +0201 if NMRfile > 0 +0202 tmpstr = fullfile(NMRpath,NMRfile); +0203 else +0204 tmpstr = NMRpath; +0205 end +0206 if length(tmpstr)>50 +0207 set(gui.text_handles.data_path,'String',['...',tmpstr(end-50:end)],... +0208 'HorizontalAlignment','left'); +0209 else +0210 set(gui.text_handles.data_path,'String',tmpstr,... +0211 'HorizontalAlignment','left'); +0212 end +0213 set(gui.text_handles.data_path,'TooltipString',tmpstr); +0214 +0215 % update the ini-file +0216 gui.myui.inidata.importpath = data.import.path; +0217 gui = makeINIfile(gui,'update'); +0218 +0219 % update the list of file names +0220 set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); +0221 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); +0222 +0223 % create a global INVdata struct for every file in the list +0224 if isstruct(getappdata(fig,'INVdata')) +0225 setappdata(fig,'INVdata',[]); +0226 end +0227 INVdata = cell(length(data.import.NMR.filesShort),1); +0228 setappdata(fig,'INVdata',INVdata); +0229 +0230 % clear all axes +0231 clearAllAxes(gui.figh); +0232 +0233 % update GUI data and interface +0234 setappdata(fig,'data',data); +0235 setappdata(fig,'gui',gui); +0236 enableGUIelements('NMR'); +0237 +0238 % special treatment of LIAG projects +0239 switch label +0240 case {'LIAG from project','LIAG last project'} +0241 cpath = data.import.LIAG.calibrationpath; +0242 % check if this calibration file was already used +0243 isfile = dir(fullfile(cpath,'NUCLEUS_calibData.mat')); +0244 if ~isempty(isfile) +0245 id = 2; +0246 % if data is there reuse it +0247 calib = load(fullfile(cpath,isfile.name),'calib'); +0248 INVdata{id} = calib.calib; +0249 data.calib = INVdata{id}.calib; +0250 data.import.LIAG.Tbulk = INVdata{id}.results.invstd.T2; +0251 setappdata(fig,'INVdata',INVdata); +0252 setappdata(fig,'data',data); +0253 % color the list entry +0254 strL = get(gui.listbox_handles.signal,'String'); +0255 str1 = strL{id}; +0256 str2 = ['<HTML><BODY bgcolor="rgb(',... +0257 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',... +0258 str1,'</BODY></HTML>']; +0259 strL{id} = str2; +0260 set(gui.listbox_handles.signal,'String',strL); +0261 end +0262 otherwise +0263 end +0264 % update GUI interface +0265 NUCLEUSinv_updateInterface; +0266 end +0267 +0268 catch ME +0269 % show error message in case import fails +0270 errmsg = {ME.message;[ME.stack(1).name,' Line: ',num2str(ME.stack(1).line)];... +0271 'Check File Format settings.'}; +0272 errordlg(errmsg,'importNMRdata: Error!'); +0273 end +0274 +0275 end +0276 +0277 %% +0278 function [NMRpath,NMRfile] = getNMRPathFile(label,import) +0279 +0280 NMRpath = -1; +0281 NMRfile = -1; +0282 % for almost all import cases we load a folder ... but not for all +0283 switch label +0284 case {'BAM TOM','BGR std','CoreLab ascii','GGE ascii','GGE field',... +0285 'HeliosCPMG','HeliosSeries','LIAG core','LIAG single',... +0286 'MOUSE','MouseCPMG','MouseLift','PM25','Dart T1T2','Dart T2 logging',... +0287 'DART (+Burst)','RoCA T1T2'} +0288 % if there is already a data folder present we start from here +0289 if isfield(import,'path') +0290 NMRpath = uigetdir(import.path,'Choose Data Path'); +0291 else +0292 % otherwise we start at the current working dircetory +0293 % 'NMRpath' holds the name of the choosen data path +0294 here = mfilename('fullpath'); +0295 [pathstr,~,~] = fileparts(here); +0296 NMRpath = uigetdir(pathstr,'Choose Data Path'); +0297 end +0298 case 'LIAG from project' +0299 % if there is already a data folder present we start from here +0300 if isfield(import,'path') +0301 NMRpath = uigetdir(import.path,'Choose Project Path'); +0302 else +0303 % otherwise we start at the current working dircetory +0304 % 'NMRpath' holds the name of the choosen data path +0305 here = mfilename('fullpath'); +0306 [pathstr,~,~] = fileparts(here); +0307 NMRpath = uigetdir(pathstr,'Choose Project Path'); +0308 end +0309 case 'LIAG last project' +0310 % there is already a data folder and we use this one +0311 if isfield(import,'path') +0312 NMRpath = import.path; +0313 else +0314 % otherwise we start at the current working dircetory +0315 % 'NMRpath' holds the name of the choosen data path +0316 here = mfilename('fullpath'); +0317 [pathstr,~,~] = fileparts(here); +0318 NMRpath = uigetdir(pathstr,'Choose Project Path'); +0319 end +0320 case {'GGE Dart','DART','BGR mat','NMR mat'} +0321 % if there is already a data folder present we start from here +0322 if isfield(import,'path') +0323 [NMRfile,NMRpath] = uigetfile(import.path,'Choose Data file'); +0324 else +0325 % otherwise we start at the current working dircetory +0326 % 'foldername' hold s the name of the choosen data path +0327 here = mfilename('fullpath'); +0328 [pathstr,~,~] = fileparts(here); +0329 [NMRfile,NMRpath] = uigetfile(pathstr,'Choose Data file'); 0330 end -0331 end -0332 -0333 end -0334 -0335 %% -0336 function [data,gui] = importDataMouseCPMG(data,gui) -0337 -0338 csv_t2path = dir(fullfile(data.import.path,'CPMG')); -0339 csv_t2path = csv_t2path(~ismember({csv_t2path.name},{'.','..'})); -0340 -0341 fnames = struct; -0342 % shownames is just a dummy to hold all data file names that -0343 % will be shown in the listbox -0344 shownames = cell(1,1); -0345 -0346 c = 0; -0347 if ~isempty(csv_t2path) -0348 for i = 1:size(csv_t2path,1) -0349 in.T1T2 = 'T2'; -0350 in.path = fullfile(data.import.path,'CPMG',csv_t2path(i).name); -0351 in.fileformat = data.import.fileformat; -0352 out = LoadNMRData_driver(in); -0353 -0354 for j = 1:size(out.nmrData,2) -0355 % the individual file names -0356 c = c + 1; -0357 fnames(c).parfile = 'acqu.par'; -0358 fnames(c).datafile = out.nmrData{j}.datfile; -0359 fnames(c).T2specfile = ''; -0360 -0361 shownames{c} = ['T2_',csv_t2path(i).name,'_',fnames(c).datafile]; -0362 -0363 % the NMR data -0364 % here we fix the time scale from [ms] to [s] -0365 if max(out.nmrData{j}.time) > 100 -0366 out.nmrData{j}.time = out.nmrData{j}.time/1000; -0367 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; -0368 end -0369 data.import.NMR.data{c} = out.nmrData{j}; -0370 data.import.NMR.para{c} = out.parData; -0371 end -0372 end -0373 end -0374 -0375 if isempty(csv_t2path) -0376 helpdlg('No data folders in the given directory.','onMenuImport: No data.'); -0377 else -0378 % update the global data structure -0379 data.import.NMR.files = fnames; -0380 data.import.NMR.filesShort = shownames; -0381 end -0382 -0383 end -0384 -0385 %% -0386 function [data,gui] = importDataBGRmat(data,gui) -0387 -0388 in.path = fullfile(data.import.path); -0389 in.name = data.import.file; -0390 in.fileformat = data.import.fileformat; -0391 out = LoadNMRData_driver(in); -0392 -0393 fnames = struct; -0394 % shownames is just a dummy to hold all data file names that -0395 % will be shown in the listbox -0396 shownames = cell(1,1); -0397 -0398 c = 0; -0399 table = {true,0,1,'D'}; -0400 for j = 1:size(out.nmrData,2) -0401 % the individual file names -0402 c = c + 1; -0403 fnames(c).parfile = ''; -0404 fnames(c).datafile = data.import.file; -0405 fnames(c).T2specfile = ''; -0406 -0407 shownames{c} = out.parData{j}.file; -0408 -0409 data.import.NMR.data{c} = out.nmrData{j}; -0410 data.import.NMR.para{c} = out.parData{j}; -0411 -0412 if isfield(out,'pressData') -0413 % convert hPa to Pa -0414 table{c,1} = true; -0415 table{c,2} = out.pressData.p(j)*1e2; -0416 table{c,3} = out.pressData.S(j); -0417 table{c,4} = 'D'; -0418 end -0419 end -0420 -0421 % global Tbulk -0422 data.invstd.Tbulk = out.parData{1}.Tbulk; -0423 % global porosity -0424 data.import.BGR.porosity = out.parData{1}.porosity; -0425 -0426 data.import.NMR.files = fnames; -0427 data.import.NMR.filesShort = shownames; -0428 -0429 % import pressure / saturation data -0430 if isfield(out,'pressData') -0431 data.pressure.unit = 'kPa'; -0432 data.pressure.unitfac = 1e-3; -0433 data.pressure.table = table; -0434 end -0435 -0436 end -0437 -0438 %% -0439 function [data,gui] = importDataBGRliftSingle(data,gui) -0440 -0441 % first check whether T1 or T2 was measured... -0442 % by analyzing the name of data folder -0443 ind = find(data.import.path == filesep); -0444 checkT1T2 = data.import.path(ind(end-1)+1:ind(end)-1); -0445 if strcmp(checkT1T2,'t1test') -0446 in.T1T2 = 'T1'; -0447 elseif strcmp(checkT1T2,'T1auto') -0448 in.T1T2 = 'T1'; -0449 elseif strcmp(checkT1T2,'cpmgfastautotest') -0450 in.T1T2 = 'T2'; -0451 elseif strcmp(checkT1T2,'cpmgfastauto') -0452 in.T1T2 = 'T2'; -0453 else -0454 disp('Please chose an original Prospa folder for Mouse Lift data!'); +0331 case 'PM5' +0332 % if there is already a data folder present we start from here +0333 if isfield(import,'path') +0334 NMRpath = uigetdir(import.path,'Choose PM5 Data Path'); +0335 else +0336 % otherwise we start at the current working dircetory +0337 % 'NMRpath' holds the name of the choosen data path +0338 here = mfilename('fullpath'); +0339 [pathstr,~,~] = fileparts(here); +0340 NMRpath = uigetdir(pathstr,'Choose PM5 Data Path'); +0341 end +0342 +0343 % check if there are multiple inf-files available +0344 % if yes -> choose one +0345 inffiles = dir(fullfile(NMRpath,'*.inf')); +0346 if numel(inffiles) > 1 +0347 [NMRfile,NMRpath] = uigetfile(fullfile(NMRpath,'*.inf'),... +0348 'Choose INF file'); +0349 elseif numel(inffiles) == 1 +0350 NMRfile = inffiles.name; +0351 end +0352 end +0353 +0354 end +0355 +0356 %% +0357 function [data,gui] = importDataMouseCPMG(data,gui) +0358 +0359 csv_t2path = dir(fullfile(data.import.path,'CPMG')); +0360 csv_t2path = csv_t2path(~ismember({csv_t2path.name},{'.','..'})); +0361 +0362 fnames = struct; +0363 % shownames is just a dummy to hold all data file names that +0364 % will be shown in the listbox +0365 shownames = cell(1,1); +0366 +0367 c = 0; +0368 if ~isempty(csv_t2path) +0369 for i = 1:size(csv_t2path,1) +0370 in.T1T2 = 'T2'; +0371 in.path = fullfile(data.import.path,'CPMG',csv_t2path(i).name); +0372 in.fileformat = data.import.fileformat; +0373 out = LoadNMRData_driver(in); +0374 +0375 for j = 1:size(out.nmrData,2) +0376 % the individual file names +0377 c = c + 1; +0378 fnames(c).parfile = 'acqu.par'; +0379 fnames(c).datafile = out.nmrData{j}.datfile; +0380 fnames(c).T2specfile = ''; +0381 +0382 shownames{c} = ['T2_',csv_t2path(i).name,'_',fnames(c).datafile]; +0383 +0384 % the NMR data +0385 % here we fix the time scale from [ms] to [s] +0386 if max(out.nmrData{j}.time) > 100 +0387 out.nmrData{j}.time = out.nmrData{j}.time/1000; +0388 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; +0389 end +0390 data.import.NMR.data{c} = out.nmrData{j}; +0391 data.import.NMR.para{c} = out.parData; +0392 end +0393 end +0394 end +0395 +0396 if isempty(csv_t2path) +0397 helpdlg('No data folders in the given directory.','onMenuImport: No data.'); +0398 else +0399 % update the global data structure +0400 data.import.NMR.files = fnames; +0401 data.import.NMR.filesShort = shownames; +0402 end +0403 +0404 end +0405 +0406 %% +0407 function [data,gui] = importDataBGRmat(data,gui) +0408 +0409 in.path = fullfile(data.import.path); +0410 in.name = data.import.file; +0411 in.fileformat = data.import.fileformat; +0412 out = LoadNMRData_driver(in); +0413 +0414 fnames = struct; +0415 % shownames is just a dummy to hold all data file names that +0416 % will be shown in the listbox +0417 shownames = cell(1,1); +0418 +0419 c = 0; +0420 table = {true,0,1,'D'}; +0421 for j = 1:size(out.nmrData,2) +0422 % the individual file names +0423 c = c + 1; +0424 fnames(c).parfile = ''; +0425 fnames(c).datafile = data.import.file; +0426 fnames(c).T2specfile = ''; +0427 +0428 shownames{c} = out.parData{j}.file; +0429 +0430 data.import.NMR.data{c} = out.nmrData{j}; +0431 data.import.NMR.para{c} = out.parData{j}; +0432 +0433 if isfield(out,'pressData') +0434 % convert hPa to Pa +0435 table{c,1} = true; +0436 table{c,2} = out.pressData.p(j)*1e2; +0437 table{c,3} = out.pressData.S(j); +0438 table{c,4} = 'D'; +0439 end +0440 end +0441 +0442 % global Tbulk +0443 data.invstd.Tbulk = out.parData{1}.Tbulk; +0444 % global porosity +0445 data.import.BGR.porosity = out.parData{1}.porosity; +0446 +0447 data.import.NMR.files = fnames; +0448 data.import.NMR.filesShort = shownames; +0449 +0450 % import pressure / saturation data +0451 if isfield(out,'pressData') +0452 data.pressure.unit = 'kPa'; +0453 data.pressure.unitfac = 1e-3; +0454 data.pressure.table = table; 0455 end 0456 -0457 % % there should be folders with integer values in their names -0458 % t1t2path = data.import.path; -0459 -0460 fnames = struct; -0461 % shownames is just a dummy to hold all data file names that -0462 % will be shown in the listbox -0463 shownames = cell(1,1); -0464 -0465 c = 0; -0466 if ~isempty(data.import.path) -0467 % for i = 1:size(t1t2path,1) -0468 in.path = data.import.path; -0469 in.fileformat = data.import.fileformat; -0470 out = LoadNMRData_driver(in); -0471 -0472 for j = 1:size(out.nmrData,2) -0473 % the individual file names -0474 c = c + 1; -0475 fnames(c).parfile = 'acq.par'; -0476 fnames(c).datafile = out.nmrData{j}.datfile; -0477 -0478 shownames{c} = [in.T1T2,'_',fnames(c).datafile]; -0479 -0480 % the NMR data -0481 % here we fix the time scale from [ms] to [s] -0482 if max(out.nmrData{j}.time) > 100 -0483 out.nmrData{j}.time = out.nmrData{j}.time/1000; -0484 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; -0485 end -0486 data.import.NMR.data{c} = out.nmrData{j}; -0487 data.import.NMR.para{c} = out.parData; -0488 end -0489 else -0490 helpdlg('No data folders in the given directory.','onMenuImport: No data.'); -0491 end -0492 -0493 % update the global data structure -0494 data.import.NMR.files = fnames; -0495 data.import.NMR.filesShort = shownames; -0496 -0497 end -0498 %% -0499 function [data,gui] = importDataBGRlift(data,gui) -0500 -0501 % 1) show all folders and ask for sample -0502 subdirs = dir(data.import.path); -0503 % remove the dot-dirs -0504 subdirs = subdirs(~ismember({subdirs.name},{'.','..'})); -0505 -0506 fnames = {subdirs.name}; -0507 [indx,~] = listdlg('PromptString','Choose data set:',... -0508 'SelectionMode','multiple',... -0509 'ListString',fnames); -0510 -0511 % first check whether T1 or T2 was measured -0512 ind = find(data.import.path == filesep); -0513 checkT1T2 = data.import.path(ind(end)+1:end); -0514 if strcmp(checkT1T2,'t1test') -0515 in.T1T2 = 'T1'; -0516 elseif strcmp(checkT1T2,'T1auto') -0517 in.T1T2 = 'T1'; -0518 elseif strcmp(checkT1T2,'cpmgfastautotest') -0519 in.T1T2 = 'T2'; -0520 elseif strcmp(checkT1T2,'cpmgfastauto') -0521 in.T1T2 = 'T2'; -0522 else -0523 helpdlg('No original data folder','onMenuImport: No data.'); -0524 end -0525 -0526 % now ask for stacking -0527 answer = questdlg('Do you want to stack the slices?'); -0528 switch answer -0529 case 'Yes' -0530 doSliceStack = true; -0531 % if stacking ask for stack-rotate-order -0532 answer = questdlg('Select stack-rotate-order:',... -0533 'Select order', ... -0534 'stack-rotate (default)','rotate-stack','Cancel','stack-rotate (default)'); -0535 switch answer -0536 case 'stack-rotate' -0537 StackFirst = true; -0538 case 'rotate-stack' -0539 StackFirst = false; -0540 otherwise -0541 StackFirst = true; -0542 end -0543 otherwise -0544 doSliceStack = false; -0545 end -0546 -0547 fnames = struct; -0548 % shownames is just a dummy to hold all data file names that -0549 % will be shown in the listbox -0550 shownames = cell(1,1); -0551 -0552 c = 0; -0553 if ~isempty(indx) -0554 for i = indx -0555 in.path = fullfile(data.import.path,subdirs(i).name); -0556 in.fileformat = data.import.fileformat; -0557 out = LoadNMRData_driver(in); -0558 -0559 if doSliceStack -0560 % the individual file names -0561 c = c + 1; -0562 fnames(c).parfile = 'acq.par'; -0563 fnames(c).datafile = out.nmrData{1}.datfile; -0564 -0565 shownames{c} = [in.T1T2,'_',subdirs(i).name]; -0566 -0567 % use the meta data from the first slice -0568 % fix the time scale from [ms] to [s] -0569 if max(out.nmrData{1}.time) > 100 -0570 out.nmrData{1}.time = out.nmrData{1}.time/1000; -0571 out.nmrData{1}.raw.time = out.nmrData{1}.raw.time/1000; -0572 end -0573 % import into GUI data struct -0574 data.import.NMR.data{c} = out.nmrData{1}; -0575 -0576 % stacking -0577 for j = 1:size(out.nmrData,2) -0578 if j == 1 -0579 signal = out.nmrData{j}.signal; -0580 else -0581 signal = signal + out.nmrData{j}.signal; -0582 end -0583 end -0584 signal = signal./size(out.nmrData,2); -0585 -0586 % now rotate after the stacking -0587 if StackFirst -0588 [signal,phase] = rotateT2phase(signal); -0589 data.import.NMR.data{c}.phase = phase; -0590 data.import.NMR.data{c}.signal = signal; -0591 data.import.NMR.data{c}.raw.signal = signal; -0592 else -0593 % no rotation after stacking -0594 data.import.NMR.data{c}.signal = signal; -0595 data.import.NMR.data{c}.raw.signal = signal; -0596 end -0597 -0598 % parameter data -0599 data.import.NMR.para{c} = out.parData; -0600 else -0601 -0602 for j = 1:size(out.nmrData,2) -0603 % the individual file names -0604 c = c + 1; -0605 fnames(c).parfile = 'acq.par'; -0606 fnames(c).datafile = out.nmrData{j}.datfile; +0457 end +0458 +0459 %% +0460 function [data,gui] = importDataBGRliftSingle(data,gui) +0461 +0462 % first check whether T1 or T2 was measured... +0463 % by analyzing the name of data folder +0464 ind = find(data.import.path == filesep); +0465 checkT1T2 = data.import.path(ind(end-1)+1:ind(end)-1); +0466 if strcmp(checkT1T2,'t1test') +0467 in.T1T2 = 'T1'; +0468 elseif strcmp(checkT1T2,'T1auto') +0469 in.T1T2 = 'T1'; +0470 elseif strcmp(checkT1T2,'cpmgfastautotest') +0471 in.T1T2 = 'T2'; +0472 elseif strcmp(checkT1T2,'cpmgfastauto') +0473 in.T1T2 = 'T2'; +0474 else +0475 disp('Please chose an original Prospa folder for Mouse Lift data!'); +0476 end +0477 +0478 % % there should be folders with integer values in their names +0479 % t1t2path = data.import.path; +0480 +0481 fnames = struct; +0482 % shownames is just a dummy to hold all data file names that +0483 % will be shown in the listbox +0484 shownames = cell(1,1); +0485 +0486 c = 0; +0487 if ~isempty(data.import.path) +0488 % for i = 1:size(t1t2path,1) +0489 in.path = data.import.path; +0490 in.fileformat = data.import.fileformat; +0491 out = LoadNMRData_driver(in); +0492 +0493 for j = 1:size(out.nmrData,2) +0494 % the individual file names +0495 c = c + 1; +0496 fnames(c).parfile = 'acq.par'; +0497 fnames(c).datafile = out.nmrData{j}.datfile; +0498 +0499 shownames{c} = [in.T1T2,'_',fnames(c).datafile]; +0500 +0501 % the NMR data +0502 % here we fix the time scale from [ms] to [s] +0503 if max(out.nmrData{j}.time) > 100 +0504 out.nmrData{j}.time = out.nmrData{j}.time/1000; +0505 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; +0506 end +0507 data.import.NMR.data{c} = out.nmrData{j}; +0508 data.import.NMR.para{c} = out.parData; +0509 end +0510 else +0511 helpdlg('No data folders in the given directory.','onMenuImport: No data.'); +0512 end +0513 +0514 % update the global data structure +0515 data.import.NMR.files = fnames; +0516 data.import.NMR.filesShort = shownames; +0517 +0518 end +0519 +0520 %% +0521 function [data,gui] = importDataBGRlift(data,gui) +0522 +0523 % 1) show all folders and ask for sample +0524 subdirs = dir(data.import.path); +0525 % remove the dot-dirs +0526 subdirs = subdirs(~ismember({subdirs.name},{'.','..'})); +0527 +0528 fnames = {subdirs.name}; +0529 [indx,~] = listdlg('PromptString','Choose data set:',... +0530 'SelectionMode','multiple',... +0531 'ListString',fnames); +0532 +0533 % first check whether T1 or T2 was measured +0534 ind = find(data.import.path == filesep); +0535 checkT1T2 = data.import.path(ind(end)+1:end); +0536 if strcmp(checkT1T2,'t1test') +0537 in.T1T2 = 'T1'; +0538 elseif strcmp(checkT1T2,'T1auto') +0539 in.T1T2 = 'T1'; +0540 elseif strcmp(checkT1T2,'cpmgfastautotest') +0541 in.T1T2 = 'T2'; +0542 elseif strcmp(checkT1T2,'cpmgfastauto') +0543 in.T1T2 = 'T2'; +0544 else +0545 helpdlg('No original data folder','onMenuImport: No data.'); +0546 end +0547 +0548 % now ask for stacking +0549 answer = questdlg('Do you want to stack the slices?'); +0550 switch answer +0551 case 'Yes' +0552 doSliceStack = true; +0553 % if stacking ask for stack-rotate-order +0554 answer = questdlg('Select stack-rotate-order:',... +0555 'Select order', ... +0556 'stack-rotate (default)','rotate-stack','Cancel','stack-rotate (default)'); +0557 switch answer +0558 case 'stack-rotate' +0559 StackFirst = true; +0560 case 'rotate-stack' +0561 StackFirst = false; +0562 otherwise +0563 StackFirst = true; +0564 end +0565 otherwise +0566 doSliceStack = false; +0567 end +0568 +0569 fnames = struct; +0570 % shownames is just a dummy to hold all data file names that +0571 % will be shown in the listbox +0572 shownames = cell(1,1); +0573 +0574 c = 0; +0575 if ~isempty(indx) +0576 for i = indx +0577 in.path = fullfile(data.import.path,subdirs(i).name); +0578 in.fileformat = data.import.fileformat; +0579 out = LoadNMRData_driver(in); +0580 +0581 if doSliceStack +0582 % the individual file names +0583 c = c + 1; +0584 fnames(c).parfile = 'acq.par'; +0585 fnames(c).datafile = out.nmrData{1}.datfile; +0586 +0587 shownames{c} = [in.T1T2,'_',subdirs(i).name]; +0588 +0589 % use the meta data from the first slice +0590 % fix the time scale from [ms] to [s] +0591 if max(out.nmrData{1}.time) > 100 +0592 out.nmrData{1}.time = out.nmrData{1}.time/1000; +0593 out.nmrData{1}.raw.time = out.nmrData{1}.raw.time/1000; +0594 end +0595 % import into GUI data struct +0596 data.import.NMR.data{c} = out.nmrData{1}; +0597 +0598 % stacking +0599 for j = 1:size(out.nmrData,2) +0600 if j == 1 +0601 signal = out.nmrData{j}.signal; +0602 else +0603 signal = signal + out.nmrData{j}.signal; +0604 end +0605 end +0606 signal = signal./size(out.nmrData,2); 0607 -0608 shownames{c} = [in.T1T2,'_',subdirs(i).name,'_',fnames(c).datafile]; -0609 -0610 % the NMR data -0611 % here we fix the time scale from [ms] to [s] -0612 if max(out.nmrData{j}.time) > 100 -0613 out.nmrData{j}.time = out.nmrData{j}.time/1000; -0614 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; -0615 end -0616 data.import.NMR.data{c} = out.nmrData{j}; -0617 data.import.NMR.para{c} = out.parData; +0608 % now rotate after the stacking +0609 if StackFirst +0610 [signal,phase] = rotateT2phase(signal); +0611 data.import.NMR.data{c}.phase = phase; +0612 data.import.NMR.data{c}.signal = signal; +0613 data.import.NMR.data{c}.raw.signal = signal; +0614 else +0615 % no rotation after stacking +0616 data.import.NMR.data{c}.signal = signal; +0617 data.import.NMR.data{c}.raw.signal = signal; 0618 end -0619 end -0620 end -0621 else -0622 helpdlg('No data folders in the given directory.','onMenuImport: No data.'); -0623 end -0624 -0625 % update the global data structure -0626 data.import.NMR.files = fnames; -0627 data.import.NMR.filesShort = shownames; -0628 -0629 end -0630 -0631 %% -0632 function [data,gui] = importDataHeliosCPMG(data,gui) -0633 -0634 % first check the subpaths -0635 % there should be some folders with names ... -0636 % ... similar to the data filenames inside them -0637 datpath = dir(data.import.path); -0638 datpath = datpath(~ismember({datpath.name},{'.','..'})); -0639 -0640 fnames = struct; -0641 % shownames is just a dummy to hold all data file names that -0642 % will be shown in the listbox -0643 shownames = cell(1,1); -0644 -0645 c = 0; -0646 if ~isempty(datpath) -0647 for i = 1:size(datpath,1) -0648 % does datpath.name points to a folder? -0649 if datpath(i).isdir -0650 % check if datpath.name includes regular Helios data files -0651 content = dir([data.import.path,filesep,datpath(i).name]); -0652 content = content(~ismember({content.name},{'.','..'})); -0653 for j = 1:size(content,1) -0654 if strcmp(content(j).name,[datpath(i).name,'.hrd']) -0655 if ~strcmp(content(j).name,[datpath(i).name,'_ref']) -0656 in.T1T2 = 'T2'; -0657 in.name = content(j).name; -0658 in.path = fullfile(data.import.path,filesep,datpath(i).name); -0659 in.fileformat = data.import.fileformat; -0660 out = LoadNMRData_driver(in); -0661 -0662 % the individual file names -0663 c = c + 1; -0664 fnames(c).parfile = ''; -0665 fnames(c).datafile = out.nmrData.datfile; -0666 fnames(c).T2specfile = ''; -0667 shownames{c} = ['T2_',datpath(i).name]; -0668 -0669 data.import.NMR.data{c} = out.nmrData; -0670 data.import.NMR.para{c} = out.parData; -0671 end -0672 end -0673 end -0674 end -0675 end -0676 end -0677 -0678 % update the global data structure -0679 data.import.NMR.files = fnames; -0680 data.import.NMR.filesShort = shownames; -0681 -0682 end -0683 -0684 %% -0685 function [data,gui] = importDataHeliosSeries(data,gui) -0686 -0687 % first check the subpaths -0688 % there should be some folders with names ... -0689 % ... similar to the data filenames inside them -0690 datpath = dir(data.import.path); -0691 datpath = datpath(~ismember({datpath.name},{'.','..'})); +0619 +0620 % parameter data +0621 data.import.NMR.para{c} = out.parData; +0622 else +0623 +0624 for j = 1:size(out.nmrData,2) +0625 % the individual file names +0626 c = c + 1; +0627 fnames(c).parfile = 'acq.par'; +0628 fnames(c).datafile = out.nmrData{j}.datfile; +0629 +0630 shownames{c} = [in.T1T2,'_',subdirs(i).name,'_',fnames(c).datafile]; +0631 +0632 % the NMR data +0633 % here we fix the time scale from [ms] to [s] +0634 if max(out.nmrData{j}.time) > 100 +0635 out.nmrData{j}.time = out.nmrData{j}.time/1000; +0636 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; +0637 end +0638 data.import.NMR.data{c} = out.nmrData{j}; +0639 data.import.NMR.para{c} = out.parData; +0640 end +0641 end +0642 end +0643 else +0644 helpdlg('No data folders in the given directory.','onMenuImport: No data.'); +0645 end +0646 +0647 % update the global data structure +0648 data.import.NMR.files = fnames; +0649 data.import.NMR.filesShort = shownames; +0650 +0651 end +0652 +0653 %% +0654 function [data,gui] = importDataHeliosCPMG(data,gui) +0655 +0656 % first check the subpaths +0657 % there should be some folders with names ... +0658 % ... similar to the data filenames inside them +0659 datpath = dir(data.import.path); +0660 datpath = datpath(~ismember({datpath.name},{'.','..'})); +0661 +0662 fnames = struct; +0663 % shownames is just a dummy to hold all data file names that +0664 % will be shown in the listbox +0665 shownames = cell(1,1); +0666 +0667 c = 0; +0668 if ~isempty(datpath) +0669 for i = 1:size(datpath,1) +0670 % does datpath.name points to a folder? +0671 if datpath(i).isdir +0672 % check if datpath.name includes regular Helios data files +0673 content = dir([data.import.path,filesep,datpath(i).name]); +0674 content = content(~ismember({content.name},{'.','..'})); +0675 % only keep hrd-files +0676 content = content(contains({content.name},'.hrd')); +0677 % remove reference hrd-files +0678 content = content(~contains({content.name},'_ref.hrd')); +0679 for j = 1:size(content,1) +0680 in.T1T2 = 'T2'; +0681 in.name = content(j).name; +0682 in.path = fullfile(data.import.path,filesep,datpath(i).name); +0683 in.fileformat = data.import.fileformat; +0684 out = LoadNMRData_driver(in); +0685 +0686 % the individual file names +0687 c = c + 1; +0688 fnames(c).parfile = ''; +0689 fnames(c).datafile = out.nmrData.datfile; +0690 fnames(c).T2specfile = ''; +0691 shownames{c} = ['T2_',datpath(i).name]; 0692 -0693 fnames = struct; -0694 % shownames is just a dummy to hold all data file names that -0695 % will be shown in the listbox -0696 shownames = cell(1,1); -0697 -0698 c = 0; -0699 if ~isempty(datpath) -0700 content = datpath; -0701 for j = 1:size(content,1) -0702 if ~strcmp(content(j).name(end-7:end),'_ref.hrd') -0703 in.T1T2 = 'T2'; -0704 in.name = content(j).name; -0705 in.path = fullfile(data.import.path); -0706 in.fileformat = data.import.fileformat; -0707 out = LoadNMRData_driver(in); -0708 % the individual file names -0709 c = c + 1; -0710 fnames(c).parfile = ''; -0711 fnames(c).datafile = out.nmrData.datfile; -0712 fnames(c).T2specfile = ''; -0713 shownames{c} = ['T2_',content(j).name]; -0714 -0715 data.import.NMR.data{c} = out.nmrData; -0716 data.import.NMR.para{c} = out.parData; -0717 end -0718 -0719 end -0720 end -0721 -0722 % update the global data structure -0723 data.import.NMR.files = fnames; -0724 data.import.NMR.filesShort = shownames; -0725 -0726 end -0727 -0728 %% -0729 function [data,gui] = importDataDart(data,gui) -0730 -0731 in.path = fullfile(data.import.path); -0732 in.name = data.import.file; -0733 in.fileformat = data.import.fileformat; -0734 in.version = data.import.version; -0735 out = LoadNMRData_driver(in); -0736 -0737 fnames = struct; -0738 % shownames is just a dummy to hold all data file names that -0739 % will be shown in the listbox -0740 shownames = cell(1,1); -0741 -0742 c = 0; -0743 for j = 1:size(out.nmrData,2) -0744 % the individual file names -0745 c = c + 1; -0746 fnames(c).parfile = ''; -0747 fnames(c).datafile = data.import.file; -0748 fnames(c).T2specfile = ''; -0749 -0750 shownames{c} = ['depth_',sprintf('%04.3f',out.parData{j}.depth)]; -0751 -0752 % the NMR data -0753 % here we fix the time scale from [ms] to [s] -0754 if max(out.nmrData{j}.time) > 100 -0755 out.nmrData{j}.time = out.nmrData{j}.time/1000; -0756 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; -0757 end -0758 data.import.NMR.data{c} = out.nmrData{j}; -0759 data.import.NMR.para{c} = out.parData{j}; -0760 end -0761 -0762 % update the global data structure -0763 data.import.NMR.files = fnames; -0764 data.import.NMR.filesShort = shownames; -0765 -0766 end -0767 -0768 %% -0769 function [data,gui] = importDataGeneral(data,gui) -0770 -0771 % look for all files ending with '.par' -0772 % should exist for T1 and T2 measurements -0773 filenames = dir(fullfile(data.import.path,'*.par')); -0774 -0775 fnames = struct; -0776 % shownames is just a dummy to hold all data file names that -0777 % will be shown in the listbox -0778 shownames = cell(1,1); -0779 -0780 % loop over all found files and import the data -0781 c = 0; -0782 in.path = data.import.path; -0783 for i = 1:size(filenames,1) -0784 ind = strfind(filenames(i).name,'.'); -0785 ind = max(ind); -0786 in.name = filenames(i).name(1:ind-1); -0787 in.fileformat = data.import.fileformat; -0788 out = LoadNMRData_driver(in); -0789 -0790 for j = 1:size(out.nmrData,2) -0791 % the individual file names -0792 c = c + 1; -0793 fnames(c).parfile = filenames(i).name; -0794 fnames(c).datafile = out.nmrData{j}.datfile; -0795 if strcmp(out.nmrData{j}.flag,'T2') && isfield(out.nmrData{j},'specfile') -0796 fnames(c).T2specfile = out.nmrData{j}.specfile; -0797 else -0798 fnames(c).T2specfile = ''; -0799 end -0800 shownames{c} = fnames(c).datafile; -0801 -0802 % the NMR data -0803 % here we fix the time scale from [ms] to [s] -0804 if max(out.nmrData{j}.time) > 100 -0805 out.nmrData{j}.time = out.nmrData{j}.time/1000; -0806 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; -0807 end -0808 data.import.NMR.data{c} = out.nmrData{j}; -0809 data.import.NMR.para{c} = out.parData; -0810 end -0811 end -0812 -0813 switch data.import.fileformat -0814 case 'bamtom' -0815 nslices = out.parData.nSlices; -0816 ncsvfiles = numel(fnames); -0817 -0818 % check for background file ("Leermessung") -0819 has_bg = false; -0820 for i = 1:numel(fnames) -0821 if ~isempty(strfind(fnames(i).datafile,'000')) -0822 has_bg = true; -0823 index_bg = i; -0824 break; -0825 end -0826 end -0827 -0828 if has_bg -0829 % background data set -0830 bg = data.import.NMR.data{index_bg}; -0831 -0832 % vector of indices of the files that get corrected -0833 ind_files = 1:1:ncsvfiles; -0834 ind_files(ind_files==index_bg) = []; -0835 -0836 for i = ind_files -0837 % subtract the background signal -0838 s = data.import.NMR.data{i}.signal; -0839 s_bg = bg.signal; -0840 % if the background signal is longer than the signal cut it -0841 if numel(s_bg) > numel(s) -0842 tmp_s = s_bg(1:numel(s)); -0843 else % if not pad it with zeros -0844 tmp_s = zeros(size(s)); -0845 tmp_s(1:numel(s_bg)) = s_bg; -0846 end -0847 s = complex(real(s)-real(tmp_s),imag(s)-imag(tmp_s)); -0848 % update original data set -0849 data.import.NMR.data{i}.signal = s; -0850 end -0851 -0852 % check if the number of slices is equal to the number of files -0853 % (excluding the background file) -0854 if nslices == numel(ind_files) -0855 % create z-vector -0856 p = out.parData; -0857 zslice = linspace(p.startPos,p.endPos,p.nSlices)'; -0858 data.import.BAM.use_z = true; -0859 data.import.BAM.zslice = zslice; -0860 if numel(zslice) > 1 -0861 c = 0; -0862 for i = ind_files -0863 c = c + 1; -0864 tmp = shownames{i}; -0865 shownames{i} = [tmp,' z:',sprintf('%5.4f',zslice(c))]; -0866 end -0867 end -0868 else -0869 data.import.BAM.use_z = false; -0870 data.import.BAM.zslice = 1:1:max([numel(ind_files) 1]); +0693 data.import.NMR.data{c} = out.nmrData; +0694 data.import.NMR.para{c} = out.parData; +0695 end +0696 end +0697 end +0698 end +0699 +0700 % update the global data structure +0701 data.import.NMR.files = fnames; +0702 data.import.NMR.filesShort = shownames; +0703 +0704 end +0705 +0706 %% +0707 function [data,gui] = importDataHeliosSeries(data,gui) +0708 +0709 % first ask the user if it is pure T2 data or T2 data belonging to a T1 +0710 % measurement to generate T1-T2 maps +0711 answer = questdlg('Is this series a T1 measurement or pure T2?', ... +0712 'HELIOS import', ... +0713 'T1','T2','T2'); +0714 switch answer +0715 case 'T1' +0716 is_T1 = true; +0717 case 'T2' +0718 is_T1 = false; +0719 otherwise +0720 is_T1 = false; +0721 end +0722 +0723 % now ask for manualS stacking (only for T2 data) +0724 if ~is_T1 +0725 answer = questdlg('Do you want to stack several files?','Stack Dialog','No'); +0726 switch answer +0727 case 'Yes' +0728 doStack = true; +0729 prompt = {'Enter No. of files to stack together'}; +0730 dlgtitle = 'Stack Value'; +0731 fieldsize = [1 40]; +0732 definput = {'16'}; +0733 answer2 = inputdlg(prompt,dlgtitle,fieldsize,definput); +0734 if ~isempty(answer2) +0735 nstacks = str2double(answer2{1,1}); +0736 else +0737 doStack = false; +0738 end +0739 otherwise +0740 doStack = false; +0741 end +0742 end +0743 +0744 % now check the subpaths +0745 % there should be some folders with names ... +0746 % ... similar to the data filenames inside them +0747 datpath = dir(data.import.path); +0748 datpath = datpath(~ismember({datpath.name},{'.','..'})); +0749 % remove any subfolder within the data directory +0750 datpath = datpath(~ismember([datpath.isdir],true)); +0751 % only keep hrd-files +0752 datpath = datpath(contains({datpath.name},'.hrd')); +0753 % remove reference hrd-files +0754 datpath = datpath(~contains({datpath.name},'_ref.hrd')); +0755 +0756 fnames = struct; +0757 % shownames is just a dummy to hold all data file names that +0758 % will be shown in the listbox +0759 shownames = cell(1,1); +0760 +0761 c = 0; +0762 if ~isempty(datpath) +0763 content = datpath; +0764 if is_T1 +0765 t_recov = zeros(floor(numel(content)/2),2); +0766 end +0767 for j = 1:size(content,1) +0768 in.T1T2 = 'T2'; +0769 in.name = content(j).name; +0770 in.path = fullfile(data.import.path); +0771 in.fileformat = data.import.fileformat; +0772 out = LoadNMRData_driver(in); +0773 % the individual file names +0774 c = c + 1; +0775 fnames(c).parfile = ''; +0776 fnames(c).datafile = out.nmrData.datfile; +0777 fnames(c).T2specfile = ''; +0778 if is_T1 +0779 shownames{c} = content(j).name; +0780 else +0781 shownames{c} = ['T2_',content(j).name]; +0782 end +0783 +0784 data.import.NMR.data{c} = out.nmrData; +0785 data.import.NMR.para{c} = out.parData; +0786 +0787 % collect recovery times in case of T1 data set +0788 if is_T1 +0789 t_recov(c,1) = out.parData.t_recov; +0790 t_recov(c,2) = out.nmrData.phase; +0791 end +0792 end +0793 +0794 % in case of T1 data, use the phase of the signal with the longest +0795 % recovery time to rotate the other signals +0796 if is_T1 +0797 phase = t_recov(t_recov(:,1)==max(t_recov(:,1)),2); +0798 for i1 = 1:numel(data.import.NMR.data) +0799 % the original raw data +0800 s = data.import.NMR.data{i1}.raw.signal; +0801 s = s * exp(1i*(-data.import.NMR.data{i1}.phase)); +0802 % s_rot is the rotated signal +0803 s_rot = s .* exp(1i*phase); +0804 % write the rotated signal back to the data struct +0805 data.import.NMR.data{i1}.signal = s_rot; +0806 data.import.NMR.data{i1}.phase = phase; +0807 +0808 % get the shortest T2 signal length +0809 if i1 == 1 +0810 t2N = numel(data.import.NMR.data{i1}.raw.time); +0811 else +0812 t2N = min([t2N numel(data.import.NMR.data{i1}.raw.time)]); +0813 end +0814 t2 = data.import.NMR.data{i1}.raw.time(1:t2N); +0815 end +0816 +0817 % for convenience, sort the data by recovery time +0818 [t_s,ix] = sort(t_recov(:,1)); +0819 data.import.NMR.data = data.import.NMR.data(ix); +0820 data.import.NMR.para = data.import.NMR.para(ix); +0821 fnames = fnames(ix); +0822 shownames = shownames(ix); +0823 +0824 % save the recovery time vector for later use +0825 data.import.T1T2map.t_recov = t_s(:,1)/1000; +0826 data.import.T1T2map.t2 = t2; +0827 data.import.T1T2map.t2N = t2N; +0828 +0829 % ask if the single measurements should be "stacked" to one T1 +0830 % curve +0831 answer = questdlg('Do you want a single T1 curve or T1-T2 2D Inversion?', ... +0832 'HELIOS import', ... +0833 'single T1','2D Inv','2D Inv'); +0834 switch answer +0835 case 'single T1' +0836 singleT1 = true; +0837 case '2D Inv' +0838 singleT1 = false; +0839 end +0840 +0841 if singleT1 +0842 % ask how many T2-echos should be stacked together to one T1 +0843 % point +0844 prompt = {'Enter T2 #echos for one T1 point'}; +0845 dlgtitle = 'How many T2 echos'; +0846 fieldsize = [1 45]; +0847 definput = {'3'}; +0848 answer = inputdlg(prompt,dlgtitle,fieldsize,definput); +0849 Nechos = str2double(answer{1}); +0850 +0851 flag = 'T1'; +0852 time = data.import.T1T2map.t_recov; +0853 signal = zeros(numel(data.import.NMR.data),1); +0854 for i1 = 1:numel(data.import.NMR.data) +0855 signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); +0856 end +0857 +0858 disp('NUCLUESinv import: Estimating noise from exponential fit ...'); +0859 param.T1IRfac = 2; +0860 param.noise = 0; +0861 param.optim = 'off'; +0862 param.Tfixed_bool = [0 0 0 0 0]; +0863 param.Tfixed_val = [0 0 0 0 0]; +0864 for i1 = 1:5 +0865 invstd = fitDataFree(time,signal,flag,param,i1); +0866 if i1 == 1 +0867 noise = invstd.rms; +0868 else +0869 noise = min([noise invstd.rms]); +0870 end 0871 end -0872 -0873 else -0874 if nslices == ncsvfiles -0875 % create z-vector -0876 p = out.parData; -0877 zslice = linspace(p.startPos,p.endPos,p.nSlices)'; -0878 data.import.BAM.use_z = true; -0879 data.import.BAM.zslice = zslice; -0880 if numel(zslice) > 1 -0881 for i = 1:numel(zslice) -0882 tmp = shownames{i}; -0883 shownames{i} = [tmp,' z:',sprintf('%5.4f',zslice(i))]; -0884 end -0885 end -0886 else -0887 data.import.BAM.use_z = false; -0888 data.import.BAM.zslice = 1:1:ncsvfiles; -0889 end -0890 end -0891 end -0892 -0893 % update the global data structure -0894 data.import.NMR.files = fnames; -0895 data.import.NMR.filesShort = shownames; -0896 -0897 end -0898 -0899 %% -0900 function [data,gui] = importDataLIAG(data,gui) -0901 -0902 in.path = fullfile(data.import.path); -0903 in.fileformat = data.import.fileformat; -0904 out = LoadNMRData_driver(in); -0905 -0906 fnames = struct; -0907 % shownames is just a dummy to hold all data file names that -0908 % will be shown in the listbox -0909 shownames = cell(1,1); -0910 -0911 c = 0; -0912 for j = 1:size(out.nmrData,2) -0913 % the individual file names -0914 c = c + 1; -0915 fnames(c).parfile = 'acqu.par'; -0916 fnames(c).datafile = out.nmrData{j}.datfile; -0917 fnames(c).T2specfile = ''; -0918 -0919 shownames{c} = fnames(c).datafile; -0920 -0921 % the NMR data -0922 % here we fix the time scale to [s] if neccessary -0923 TE = out.parData.echoTime; % [µs] -0924 if out.nmrData{j}.time(1)== TE/1e3 -0925 % change [ms] to [s] -0926 out.nmrData{j}.time = out.nmrData{j}.time/1e3; -0927 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1e3; -0928 elseif out.nmrData{j}.time(1)== TE -0929 % change [µs] to [s] -> very unlikely -0930 out.nmrData{j}.time = out.nmrData{j}.time/1e6; -0931 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1e6; -0932 end -0933 data.import.NMR.data{c} = out.nmrData{j}; -0934 data.import.NMR.para{c} = out.parData; -0935 end -0936 -0937 % update the global data structure -0938 data.import.NMR.files = fnames; -0939 data.import.NMR.filesShort = shownames; -0940 -0941 end -0942 -0943 %% -0944 function [data,gui] = importDataLIAGcore(data,gui) -0945 -0946 % get all subfolders containing a measurement at a certain heigth -0947 subdirs = dir(data.import.path); -0948 % remove the dot-dirs -0949 subdirs = subdirs(~ismember({subdirs.name},{'.','..'})); -0950 -0951 % now get the background data ("Leermessung") -0952 bgPath = uigetdir(data.import.path,'Choose Background Data Path'); -0953 isbgPath = false; -0954 if bgPath == 0 -0955 disp('NUCLEUSinv: LIAG core import: No background file provided.'); -0956 else -0957 isbgPath = true; -0958 in.path = fullfile(bgPath); -0959 in.fileformat = data.import.fileformat; -0960 bgout = LoadNMRData_driver(in); -0961 ref1.t = bgout.nmrData{1}.time; -0962 ref1.s = bgout.nmrData{1}.signal; -0963 [ref1.s,~] = rotateT2phase(ref1.s); -0964 end -0965 -0966 % get the Position file -0967 [posFile,posFilePath] = uigetfile('*.*','Choose Lift Position File',data.import.path); -0968 isposFile = false; -0969 if posFilePath == 0 -0970 disp('NUCLEUSinv: LIAG core import: No position file provided.'); -0971 else -0972 isposFile = true; -0973 % import LIAG lift file -0974 buffer = fileread(fullfile(posFilePath,posFile)); -0975 -0976 % get the time stamps of the lift positions -0977 substr = 'Zeit:' ; -0978 loc = strfind(buffer, substr); -0979 timepoint = cell(1,1); -0980 for i = 1:length(loc) -0981 timestr = strtrim(buffer(loc(i)+numel(substr):loc(i)+numel(substr)+19)); -0982 timepoint{i} = datetime(timestr,'InputFormat','dd.MM.yyyy HH:mm:ss'); -0983 end -0984 % ignore the first time stamp -0985 t_range = [datenum(timepoint{2}), datenum(timepoint{3})]; -0986 % get the z coords -0987 substr = 'Z1='; -0988 loc = strfind(buffer, substr) ; -0989 z_range(1) = sscanf(buffer(loc+numel(substr):loc+numel(substr)+10),'%f',1); -0990 substr = 'Z2='; -0991 loc = strfind(buffer, substr) ; -0992 z_range(2) = sscanf(buffer(loc+numel(substr):loc+numel(substr)+10),'%f',1); -0993 end +0872 disp('NUCLUESinv import: done.') +0873 +0874 % finally create a new "import" data set +0875 data_new = data.import.NMR.data(1); +0876 para_new = data.import.NMR.para(1); +0877 data.import = rmfield(data.import,'T1T2map'); +0878 +0879 data_new{1}.flag = flag; +0880 data_new{1}.T1IRfac = param.T1IRfac; +0881 data_new{1}.time = time; +0882 data_new{1}.signal = signal; +0883 data_new{1}.noise = noise; +0884 data_new{1}.raw.time = time; +0885 data_new{1}.raw.signal = signal; +0886 +0887 fnames = fnames(1); +0888 shownames = shownames(1); +0889 +0890 data.import.NMR.data = data_new; +0891 data.import.NMR.para = para_new; +0892 else +0893 prompt = {'Enter T2 #echos for one T1 point for the merged T1 curve'}; +0894 dlgtitle = 'How many T2 echos'; +0895 fieldsize = [1 45]; +0896 definput = {'3'}; +0897 answer = inputdlg(prompt,dlgtitle,fieldsize,definput); +0898 Nechos = str2double(answer{1}); +0899 +0900 % add the stacked signal to the data +0901 flag = 'T1'; +0902 time = data.import.T1T2map.t_recov; +0903 signal = zeros(numel(data.import.NMR.data),1); +0904 for i1 = 1:numel(data.import.NMR.data) +0905 signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); +0906 end +0907 +0908 disp('NUCLUESinv import: Estimating noise from exponential fit ...'); +0909 param.T1IRfac = 2; +0910 param.noise = 0; +0911 param.optim = 'off'; +0912 param.Tfixed_bool = [0 0 0 0 0]; +0913 param.Tfixed_val = [0 0 0 0 0]; +0914 for i1 = 1:5 +0915 invstd = fitDataFree(time,signal,flag,param,i1); +0916 if i1 == 1 +0917 noise = invstd.rms; +0918 else +0919 noise = min([noise invstd.rms]); +0920 end +0921 end +0922 disp('NUCLUESinv import: done.') +0923 +0924 % finally create a new "import" data set +0925 data_new = data.import.NMR.data(1); +0926 para_new = data.import.NMR.para(1); +0927 +0928 data_new{1}.flag = flag; +0929 data_new{1}.T1IRfac = param.T1IRfac; +0930 data_new{1}.time = time; +0931 data_new{1}.signal = signal; +0932 data_new{1}.noise = noise; +0933 data_new{1}.raw.time = time; +0934 data_new{1}.raw.signal = signal; +0935 +0936 data.import.NMR.data{numel(t_s)+1} = data_new{1}; +0937 data.import.NMR.para{numel(t_s)+1} = para_new{1}; +0938 fnames(numel(t_s)+1).datafile = 'T1_merged.dat'; +0939 shownames{numel(t_s)+1} = 'T1_merged'; +0940 % set global echo time +0941 data.inv2D.prop.te = data.import.NMR.para{1}.t_echo; +0942 % set T1 SR/IR factor +0943 data.inv2D.inv.T1IRfac = 2; % Helios default +0944 end +0945 else % pure T2 data +0946 % do restacking if desired +0947 if doStack +0948 % before stacking, sort the data by date (time) +0949 N = length(shownames); +0950 time = zeros(N,1); +0951 for i = 1:N +0952 time(i,1) = data.import.NMR.data{i}.datenum; +0953 end +0954 [~,ix] = sort(time); +0955 % now apply changes - resort the imported data +0956 data.import.NMR.data = {data.import.NMR.data{ix'}}; %#ok<*CCAT1> +0957 data.import.NMR.para = {data.import.NMR.para{ix'}}; +0958 fnames = fnames(ix); +0959 shownames = {shownames{ix'}}; +0960 +0961 c = 0; +0962 % prepare data variables +0963 datanew = cell(1,1); +0964 paranew = cell(1,1); +0965 fnamesnew = fnames(1); +0966 shownamesnew = cell(1,1); +0967 tmp_signal = zeros(size(data.import.NMR.data{1}.signal)); +0968 % loop over all already imported files +0969 for i1 = 1:numel(fnames) +0970 % stack up files +0971 tmp_signal = tmp_signal + data.import.NMR.data{i1}.signal; +0972 % check if stack count is reached +0973 if mod(i1,nstacks)==0 +0974 % current stack has finished +0975 c = c + 1; +0976 % save data +0977 datanew{c} = data.import.NMR.data{i1}; +0978 datanew{c}.signal = tmp_signal./nstacks; +0979 datanew{c}.raw.signal = tmp_signal./nstacks; +0980 +0981 paranew{c} = data.import.NMR.para{i1}; +0982 paranew{c}.Nscans = paranew{c}.Nscans*nstacks; +0983 paranew{c}.all{1,1}{6} = ['Nscans = ',num2str(paranew{c}.Nscans)]; +0984 +0985 fnamesnew(c) = fnames(i1); +0986 shownamesnew{c} = [shownames{i1},'_',num2str(nstacks)]; +0987 +0988 % reset the tmp_signal to zero +0989 tmp_signal = zeros(size(data.import.NMR.data{1}.signal)); +0990 end +0991 end +0992 data.import.NMR.data = datanew; +0993 data.import.NMR.para = paranew; 0994 -0995 % import the NMR data -0996 count = 0; -0997 levels = zeros(size(subdirs)); -0998 nmrDataTMP = cell(1,1); -0999 for i = 1:numel(subdirs) -1000 if ~isnan(str2double(subdirs(i).name)) -1001 -1002 % import the NMR file -1003 in.path = fullfile(data.import.path,subdirs(i).name,'T2CPMG'); -1004 in.fileformat = data.import.fileformat; -1005 out = LoadNMRData_driver(in); +0995 fnames = fnamesnew; +0996 shownames = shownamesnew; +0997 end +0998 end +0999 end +1000 +1001 % update the global data structure +1002 data.import.NMR.files = fnames; +1003 data.import.NMR.filesShort = shownames; +1004 +1005 end 1006 -1007 % if there is a position file -1008 if isposFile -1009 % keep only files within the correct time range -1010 if out.nmrData{1}.datenum > t_range(1) && out.nmrData{1}.datenum < t_range(2) -1011 count = count + 1; -1012 % interpolate the z position via the time stamp of the NMR file -1013 levels(count) = interp1(t_range,z_range,out.nmrData{1}.datenum,'linear'); -1014 nmrDataTMP{count} = out; -1015 end -1016 else % just read everything -1017 count = count + 1; -1018 levels(count) = str2double(subdirs(i).name); -1019 nmrDataTMP{count} = out; -1020 end -1021 end +1007 %% +1008 function [data,gui] = importDataDartSeries(data,gui) +1009 +1010 % first ask the user if it is pure T2 data or T2 data belonging to a T1 +1011 % measurement to generate T1-T2 maps +1012 answer = questdlg('Is this series a T1 measurement or pure T2?', ... +1013 'DART import', ... +1014 'T1','T2','T2'); +1015 switch answer +1016 case 'T1' +1017 is_T1 = true; +1018 case 'T2' +1019 is_T1 = false; +1020 otherwise +1021 is_T1 = false; 1022 end -1023 % cut off data that is not part of the scan -1024 levels = levels(1:count); -1025 % sort in ascending order -1026 [levels,idx] = sort(levels); -1027 -1028 % sort the NMR data accordingly -1029 fnames = struct; -1030 % shownames is just a dummy to hold all data file names that -1031 % will be shown in the listbox -1032 shownames = cell(1,1); -1033 for c = 1:numel(levels) -1034 % the individual file names -1035 fnames(c).parfile = 'acqu.par'; -1036 fnames(c).datafile = nmrDataTMP{idx(c)}.nmrData{1}.datfile; -1037 fnames(c).T2specfile = ''; -1038 -1039 shownames{c} = fnames(c).datafile; -1040 tmp = shownames{c}; -1041 if isposFile -1042 shownames{c} = [tmp,': ',sprintf('%4d',floor(levels(c))),'mm']; -1043 else -1044 shownames{c} = [tmp,' level:',sprintf('%d',levels(c))]; -1045 end -1046 out = nmrDataTMP{idx(c)}; -1047 -1048 % the NMR data -1049 % here we fix the time scale to [s] if neccessary -1050 TE = out.parData.echoTime; % [µs] -1051 if out.nmrData{1}.time(1) == TE/1e3 -1052 % change [ms] to [s] -1053 out.nmrData{1}.time = out.nmrData{1}.time/1e3; -1054 out.nmrData{1}.raw.time = out.nmrData{1}.raw.time/1e3; -1055 elseif out.nmrData{1}.time(1) == TE -1056 % change [µs] to [s] -> very unlikely -1057 out.nmrData{1}.time = out.nmrData{1}.time/1e6; -1058 out.nmrData{1}.raw.time = out.nmrData{1}.raw.time/1e6; -1059 end -1060 data.import.NMR.data{c} = out.nmrData{1}; -1061 data.import.NMR.para{c} = out.parData; -1062 -1063 % subtract the background signal is one is available -1064 if isbgPath -1065 % get the original signal -1066 s = data.import.NMR.data{c}.signal; -1067 % if the background signal is longer than the signal cut it, if -1068 % not extend it with zeros -1069 if numel(ref1.s) > numel(s) -1070 tmp_r = ref1.s(1:numel(s)); -1071 else -1072 tmp_r = zeros(size(s)); -1073 tmp_r(1:numel(ref1.s)) = ref1.s; -1074 end -1075 s = complex(real(s)-real(tmp_r),imag(s)-imag(tmp_r)); -1076 -1077 % sign check -1078 if real(s(1:3))<0 -1079 s = s*-1; -1080 end -1081 -1082 % rotate phase again - TEST -1083 [s,~] = rotateT2phase(s); -1084 -1085 % update signal -1086 data.import.NMR.data{c}.signal = s; -1087 data.import.NMR.data{c}.raw.signal = s; -1088 end -1089 end -1090 if isposFile -1091 data.import.LIAGCORE.use_z = true; -1092 else -1093 data.import.LIAGCORE.use_z = false; -1094 end -1095 data.import.LIAGCORE.zslice = levels; -1096 -1097 % update the global data structure -1098 data.import.NMR.files = fnames; -1099 data.import.NMR.filesShort = shownames; -1100 -1101 end -1102 -1103 %% -1104 function [data,gui] = importDataLIAGproject(data,gui) -1105 -1106 % 1) show all folders and ask for sample -1107 subdirs = dir(data.import.path); -1108 % remove the dot-dirs -1109 subdirs = subdirs(~ismember({subdirs.name},{'.','..'})); -1110 -1111 fnames = {subdirs.name}; -1112 [indx,~] = listdlg('PromptString','Select Sample:',... -1113 'SelectionMode','single',... -1114 'ListString',fnames); -1115 -1116 if ~isempty(indx) -1117 % 2) check corresponding SampleParameter.par file for reference and -1118 % calibration sample and other parameters -1119 datapath = fullfile(data.import.path,fnames{indx}); -1120 % load SampleParameter file for sample -1121 [SampleParameter] = loadGUIParameters(datapath,'SampleParameters.par'); -1122 if isfield(SampleParameter,'sampleVolume') -1123 dataVol = SampleParameter.sampleVolume; -1124 else -1125 dataVol = 1; -1126 end -1127 -1128 % 2a) background file #1 -1129 backgroundFile1 = SampleParameter.backgroundFile; -1130 if isempty(backgroundFile1) -1131 bnames = {subdirs.name}; -1132 bnames(indx) = []; -1133 [indb,~] = listdlg('PromptString','Select Background File:',... -1134 'SelectionMode','single',... -1135 'ListString',bnames); -1136 if ~isempty(indb) -1137 backgroundFile1 = bnames{indb}; -1138 else -1139 backgroundFile1 = ''; -1140 end -1141 end -1142 if ~isempty(backgroundFile1) -1143 ind = strfind(backgroundFile1,filesep); -1144 if ~isempty(ind) -1145 backgroundFile1 = backgroundFile1(ind(end)+1:end); -1146 end -1147 fileInList = ismember(fnames,{backgroundFile1}); -1148 if any(fileInList) -1149 backgroundpath1 = fullfile(data.import.path,fnames{fileInList}); -1150 end -1151 else -1152 backgroundpath1 = ''; -1153 backgroundFile1 = ''; -1154 end -1155 backVol = 1; -1156 -1157 % 2b) calibration file -1158 c = 0; -1159 if isfield(SampleParameter,'calibrationFile0') -1160 c = c + 1; -1161 calibrationFiles{c} = SampleParameter.calibrationFile0; -1162 end -1163 if isfield(SampleParameter,'calibrationFile1') -1164 c = c + 1; -1165 calibrationFiles{c} = SampleParameter.calibrationFile1; -1166 end -1167 if isfield(SampleParameter,'calibrationFile2') -1168 c = c + 1; -1169 calibrationFiles{c} = SampleParameter.calibrationFile2; -1170 end -1171 if isfield(SampleParameter,'calibrationFile3') -1172 c = c + 1; -1173 calibrationFiles{c} = SampleParameter.calibrationFile3; -1174 end -1175 -1176 % find the non-empty one -1177 ind = ismember(calibrationFiles,{''}); -1178 % there are three possibilities: 0, 1 and more than 1 calib. files -1179 calibrationFiles(ind) = []; -1180 if isempty(calibrationFiles) -1181 cnames = {subdirs.name}; -1182 cnames(indx) = []; -1183 [indc,~] = listdlg('PromptString','Select Calibration File:',... -1184 'SelectionMode','single',... -1185 'ListString',cnames); -1186 if ~isempty(indc) -1187 calibrationFiles = cnames{indc}; -1188 else -1189 calibrationFiles = ''; -1190 end -1191 else -1192 % if there are more than one let the user select the correct one -1193 if numel(calibrationFiles) > 1 -1194 [ind,~] = listdlg('PromptString','Select Calibration File:',... -1195 'SelectionMode','single',... -1196 'ListString',calibrationFiles); -1197 calibrationFiles = calibrationFiles{ind}; -1198 else -1199 calibrationFiles = calibrationFiles{1}; -1200 end -1201 end -1202 if ~isempty(calibrationFiles) -1203 ind = strfind(calibrationFiles,filesep); -1204 if ~isempty(ind) -1205 calibrationFiles = calibrationFiles(ind(end)+1:end); -1206 end -1207 fileInList = ismember(fnames,{calibrationFiles}); -1208 if any(fileInList) -1209 calibrationpath = fullfile(data.import.path,fnames{fileInList}); -1210 end -1211 else -1212 calibrationpath = ''; -1213 calibrationFiles = ''; -1214 end -1215 -1216 if ~isempty(calibrationpath) -1217 [SampleParameterC] = loadGUIParameters(calibrationpath,'SampleParameters.par'); -1218 if isfield(SampleParameterC,'sampleVolume') -1219 calibVol = SampleParameterC.sampleVolume; -1220 else -1221 calibVol = 1; +1023 +1024 % now check the subpaths +1025 % there should be some folders with names ... +1026 % ... similar to the data filenames inside them +1027 datpath = dir(data.import.path); +1028 datpath = datpath(~ismember({datpath.name},{'.','..'})); +1029 % remove any subfolder within the data directory +1030 datpath = datpath(~ismember([datpath.isdir],true)); +1031 +1032 fnames = struct; +1033 % shownames is just a dummy to hold all data file names that +1034 % will be shown in the listbox +1035 shownames = cell(1,1); +1036 +1037 c = 0; +1038 if ~isempty(datpath) +1039 content = datpath; +1040 if is_T1 +1041 t_recov = zeros(1,2); +1042 end +1043 for j = 1:size(content,1) +1044 if strcmp(content(j).name(end-3:end),'.jrd') +1045 in.T1T2 = 'T2'; +1046 in.name = content(j).name; +1047 in.path = fullfile(data.import.path); +1048 in.fileformat = data.import.fileformat; +1049 in.version = 4; +1050 out = LoadNMRData_driver(in); +1051 % the individual file names +1052 c = c + 1; +1053 fnames(c).parfile = ''; +1054 fnames(c).datafile = out.nmrData.datfile; +1055 fnames(c).T2specfile = ''; +1056 if is_T1 +1057 shownames{c} = content(j).name; +1058 else +1059 shownames{c} = ['T2_',content(j).name]; +1060 end +1061 +1062 data.import.NMR.data{c} = out.nmrData; +1063 data.import.NMR.para{c} = out.parData; +1064 +1065 % collect recovery times in case of T1 data set +1066 if is_T1 +1067 t_recov(c,1) = out.parData.t_recov; +1068 t_recov(c,2) = out.nmrData.phase; +1069 end +1070 end +1071 end +1072 +1073 % in case if T1 data, use the phase of the signal with the longest +1074 % recovery time to rotate the other signals +1075 if is_T1 +1076 phase = t_recov(t_recov(:,1)==max(t_recov(:,1)),2); +1077 for i1 = 1:numel(data.import.NMR.data) +1078 % the original raw data +1079 s = data.import.NMR.data{i1}.raw.signal; +1080 % s_rot is the rotated signal +1081 s_rot = s .* exp(1i*phase); +1082 % write the rotated signal back to the data struct +1083 data.import.NMR.data{i1}.signal = s_rot; +1084 data.import.NMR.data{i1}.phase = phase; +1085 +1086 % get the shortest T2 signal length +1087 if i1 == 1 +1088 t2N = numel(data.import.NMR.data{i1}.raw.time); +1089 else +1090 t2N = min([t2N numel(data.import.NMR.data{i1}.raw.time)]); +1091 end +1092 t2 = data.import.NMR.data{i1}.raw.time(1:t2N); +1093 end +1094 +1095 % for convenience, sort the data by recovery time +1096 [t_s,ix] = sort(t_recov(:,1)); +1097 data.import.NMR.data = data.import.NMR.data(ix); +1098 data.import.NMR.para = data.import.NMR.para(ix); +1099 fnames = fnames(ix); +1100 shownames = shownames(ix); +1101 +1102 % save the recovery time vector for later use +1103 data.import.T1T2map.t_recov = t_s(:,1)/1000; +1104 data.import.T1T2map.t2 = t2; +1105 data.import.T1T2map.t2N = t2N; +1106 +1107 % ask if the single measurements should be "stacked" to one T1 +1108 % curve +1109 answer = questdlg('Do you want a single T1 curve or T1-T2 2D Inversion?', ... +1110 'DART import', ... +1111 'single T1','2D Inv','2D Inv'); +1112 switch answer +1113 case 'single T1' +1114 singleT1 = true; +1115 case '2D Inv' +1116 singleT1 = false; +1117 end +1118 +1119 if singleT1 +1120 % ask how many T2-echos should be stacked together to one T1 +1121 % point +1122 prompt = {'Enter T2 #echos for one T1 point'}; +1123 dlgtitle = 'How many T2 echos'; +1124 fieldsize = [1 45]; +1125 definput = {'3'}; +1126 answer = inputdlg(prompt,dlgtitle,fieldsize,definput); +1127 Nechos = str2double(answer{1}); +1128 +1129 flag = 'T1'; +1130 time = data.import.T1T2map.t_recov; +1131 signal = zeros(numel(data.import.NMR.data),1); +1132 for i1 = 1:numel(data.import.NMR.data) +1133 signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); +1134 end +1135 +1136 disp('NUCLUESinv import: Estimating noise from exponential fit ...'); +1137 param.T1IRfac = 1; +1138 param.noise = 0; +1139 param.optim = 'off'; +1140 param.Tfixed_bool = [0 0 0 0 0]; +1141 param.Tfixed_val = [0 0 0 0 0]; +1142 for i1 = 1:5 +1143 invstd = fitDataFree(time,signal,flag,param,i1); +1144 if i1 == 1 +1145 noise = invstd.rms; +1146 else +1147 noise = min([noise invstd.rms]); +1148 end +1149 end +1150 disp('NUCLUESinv import: done.') +1151 +1152 % finally create a new "import" data set +1153 data_new = data.import.NMR.data(1); +1154 para_new = data.import.NMR.para(1); +1155 data.import = rmfield(data.import,'T1T2map'); +1156 +1157 data_new{1}.flag = flag; +1158 data_new{1}.T1IRfac = param.T1IRfac; +1159 data_new{1}.time = time; +1160 data_new{1}.signal = signal; +1161 data_new{1}.noise = noise; +1162 data_new{1}.raw.time = time; +1163 data_new{1}.raw.signal = signal; +1164 +1165 fnames = fnames(1); +1166 shownames = shownames(1); +1167 +1168 data.import.NMR.data = data_new; +1169 data.import.NMR.para = para_new; +1170 else +1171 prompt = {'Enter T2 #echos for one T1 point for the merged T1 curve'}; +1172 dlgtitle = 'How many T2 echos'; +1173 fieldsize = [1 45]; +1174 definput = {'3'}; +1175 answer = inputdlg(prompt,dlgtitle,fieldsize,definput); +1176 Nechos = str2double(answer{1}); +1177 +1178 % add the stacked signal to the data +1179 flag = 'T1'; +1180 time = data.import.T1T2map.t_recov; +1181 signal = zeros(numel(data.import.NMR.data),1); +1182 for i1 = 1:numel(data.import.NMR.data) +1183 signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); +1184 end +1185 +1186 disp('NUCLUESinv import: Estimating noise from exponential fit ...'); +1187 param.T1IRfac = 1; +1188 param.noise = 0; +1189 param.optim = 'off'; +1190 param.Tfixed_bool = [0 0 0 0 0]; +1191 param.Tfixed_val = [0 0 0 0 0]; +1192 for i1 = 1:5 +1193 invstd = fitDataFree(time,signal,flag,param,i1); +1194 if i1 == 1 +1195 noise = invstd.rms; +1196 else +1197 noise = min([noise invstd.rms]); +1198 end +1199 end +1200 disp('NUCLUESinv import: done.') +1201 +1202 % finally create a new "import" data set +1203 data_new = data.import.NMR.data(1); +1204 para_new = data.import.NMR.para(1); +1205 +1206 data_new{1}.flag = flag; +1207 data_new{1}.T1IRfac = param.T1IRfac; +1208 data_new{1}.time = time; +1209 data_new{1}.signal = signal; +1210 data_new{1}.noise = noise; +1211 data_new{1}.raw.time = time; +1212 data_new{1}.raw.signal = signal; +1213 +1214 data.import.NMR.data{numel(t_s)+1} = data_new{1}; +1215 data.import.NMR.para{numel(t_s)+1} = para_new{1}; +1216 fnames(numel(t_s)+1).datafile = 'T1_merged.dat'; +1217 shownames{numel(t_s)+1} = 'T1_merged'; +1218 % set global echo time +1219 data.inv2D.prop.te = data.import.NMR.para{1}.t_echo; +1220 % set T1 SR/IR factor +1221 data.inv2D.inv.T1IRfac = 1; % Dart default 1222 end -1223 -1224 % 2a) background file #2 -1225 backgroundFile2 = SampleParameterC.backgroundFile; -1226 if isempty(backgroundFile2) -1227 bnames = {subdirs.name}; -1228 bnames(indx) = []; -1229 [indb,~] = listdlg('PromptString','Select Background File for Calibration:',... -1230 'SelectionMode','single',... -1231 'ListString',bnames); -1232 if ~isempty(indb) -1233 backgroundFile2 = bnames{indb}; -1234 else -1235 backgroundFile2 = ''; -1236 end -1237 end -1238 if ~isempty(backgroundFile2) -1239 ind = strfind(backgroundFile2,filesep); -1240 if ~isempty(ind) -1241 backgroundFile2 = backgroundFile2(ind(end)+1:end); -1242 end -1243 fileInList = ismember(fnames,{backgroundFile2}); -1244 if any(fileInList) -1245 backgroundpath2 = fullfile(data.import.path,fnames{fileInList}); -1246 end -1247 else -1248 backgroundpath2 = ''; -1249 backgroundFile2 = ''; -1250 end -1251 else -1252 calibVol = 1; -1253 backgroundpath2 = ''; -1254 backgroundFile2 = ''; -1255 end -1256 -1257 % 3) now load the data -1258 workpaths = {datapath,calibrationpath,backgroundpath1,backgroundpath2}; -1259 workfiles = {fnames{indx},[calibrationFiles,' - calibration'],... -1260 [backgroundFile1,' - backgroundS'],[backgroundFile2,' - backgroundC']}; -1261 out = cell(size(workpaths)); -1262 count = 0; -1263 keep = false(size(workpaths)); -1264 for i = 1:numel(workpaths) -1265 if ~isempty(workpaths{i}) -1266 workdirs = dir(workpaths{i}); -1267 workdirs = workdirs(~ismember({workdirs.name},{'.','..'})); -1268 isT2 = ismember({workdirs.name},{'T2CPMG'}); -1269 if any(isT2) -1270 keep(i) = true; -1271 count = count + 1; -1272 T2path = fullfile(workdirs(isT2).folder,workdirs(isT2).name); -1273 in.path = T2path; -1274 in.fileformat = data.import.fileformat; -1275 out{i} = LoadNMRData_driver(in); -1276 end -1277 end -1278 end -1279 -1280 if isempty(backgroundpath1) -1281 ref1 = struct; -1282 else -1283 background1 = out{3}; -1284 % get the background data 1 -1285 ref1.t = background1.nmrData{1}.time; -1286 ref1.s = background1.nmrData{1}.signal; -1287 [ref1.s,~] = rotateT2phase(ref1.s); -1288 end -1289 -1290 if isempty(backgroundpath2) -1291 ref2 = struct; -1292 else -1293 background2 = out{4}; -1294 % get the background data 2 -1295 ref2.t = background2.nmrData{1}.time; -1296 ref2.s = background2.nmrData{1}.signal; -1297 [ref2.s,~] = rotateT2phase(ref2.s); -1298 end -1299 -1300 workpaths = workpaths(keep); -1301 workfiles = workfiles(keep); -1302 out = out(keep); -1303 -1304 ffnames = struct; -1305 % shownames is just a dummy to hold all data file names that -1306 % will be shown in the listbox -1307 shownames = cell(1,1); -1308 -1309 for i = 1:count -1310 ffnames(i).parfile = 'acqu.par'; -1311 ffnames(i).datafile = workfiles{i}; -1312 ffnames(i).T2specfile = ''; -1313 -1314 shownames{i} = ffnames(i).datafile; -1315 -1316 % the NMR data -1317 % here we fix the time scale to [s] if neccessary -1318 TE = out{i}.parData.echoTime; % [µs] -1319 if out{i}.nmrData{1}.time(1)== TE/1e3 -1320 % change [ms] to [s] -1321 out{i}.nmrData{1}.time = out{i}.nmrData{1}.time/1e3; -1322 out{i}.nmrData{1}.raw.time = out{i}.nmrData{1}.raw.time/1e3; -1323 elseif out{i}.nmrData{1}.time(1)== TE -1324 % change [µs] to [s] -> very unlikely -1325 out{i}.nmrData{1}.time = out{i}.nmrData{1}.time/1e6; -1326 out{i}.nmrData{1}.raw.time = out{i}.nmrData{1}.raw.time/1e6; -1327 end -1328 -1329 data.import.NMR.data{i} = out{i}.nmrData{1}; -1330 data.import.NMR.para{i} = out{i}.parData; -1331 data.import.NMR.para{i}.SampleParameter = SampleParameter; -1332 -1333 % subtract the background signal -1334 s = data.import.NMR.data{i}.signal; -1335 if i==1 && isfield(ref1,'s') -1336 % if the background signal is longer than the signal cut it, if -1337 % not extend it with zeros -1338 if numel(ref1.s) > numel(s) -1339 tmp_r = ref1.s(1:numel(s)); -1340 else -1341 tmp_r = zeros(size(s)); -1342 tmp_r(1:numel(ref1.s)) = ref1.s; -1343 end -1344 s = complex(real(s)-real(tmp_r),imag(s)-imag(tmp_r)); -1345 elseif i==2 && isfield(ref2,'s') -1346 % if the background signal is longer than the signal cut it, if -1347 % not extend it with zeros -1348 if numel(ref2.s) > numel(s) -1349 tmp_r = ref2.s(1:numel(s)); -1350 else -1351 tmp_r = zeros(size(s)); -1352 tmp_r(1:numel(ref2.s)) = ref2.s; -1353 end -1354 s = complex(real(s)-real(tmp_r),imag(s)-imag(tmp_r)); -1355 end -1356 data.import.NMR.data{i}.signal = s; -1357 data.import.NMR.data{i}.raw.signal = s; -1358 -1359 if ~isempty(strfind(workfiles{i},' - background')) -1360 data.import.LIAG.sampleVol(i) = backVol; -1361 elseif ~isempty(strfind(workfiles{i},' - calibration')) -1362 data.import.LIAG.sampleVol(i) = calibVol; -1363 elseif isempty(strfind(workfiles{i},' - background')) &&... -1364 isempty(strfind(workfiles{i},' - calibration')) -1365 data.import.LIAG.sampleVol(i) = dataVol; -1366 end -1367 end -1368 data.import.LIAG.Tbulk = 1e6; -1369 data.import.LIAG.workpaths = workpaths; -1370 data.import.LIAG.datapath = datapath; -1371 data.import.LIAG.calibrationpath = calibrationpath; -1372 data.import.LIAG.backgroundpath1 = backgroundpath1; -1373 data.import.LIAG.backgroundpath2 = backgroundpath2; -1374 -1375 % update the global data structure -1376 data.import.NMR.files = ffnames; -1377 data.import.NMR.filesShort = shownames; -1378 end -1379 -1380 end -1381 -1382 %% -1383 function [data,gui] = importDataMouse(data,gui) -1384 -1385 in.path = fullfile(data.import.path); -1386 in.fileformat = data.import.fileformat; -1387 out = LoadNMRData_driver(in); -1388 -1389 fnames = struct; -1390 % shownames is just a dummy to hold all data file names that -1391 % will be shown in the listbox -1392 shownames = cell(1,1); -1393 -1394 c = 0; -1395 for j = 1:size(out.nmrData,2) -1396 % the individual file names -1397 c = c + 1; -1398 fnames(c).parfile = 'acq.par'; -1399 fnames(c).datafile = out.nmrData{j}.datfile; -1400 fnames(c).T2specfile = ''; -1401 -1402 shownames{c} = ['T2_',fnames(c).datafile]; -1403 -1404 % the NMR data -1405 % here we fix the time scale from [ms] to [s] -1406 if max(out.nmrData{j}.time) > 100 -1407 out.nmrData{j}.time = out.nmrData{j}.time/1000; -1408 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; -1409 end -1410 data.import.NMR.data{c} = out.nmrData{j}; -1411 data.import.NMR.para{c} = out.parData; -1412 end -1413 -1414 % update the global data structure -1415 data.import.NMR.files = fnames; -1416 data.import.NMR.filesShort = shownames; -1417 -1418 end -1419 -1420 %% -1421 function [data,gui] = importDataIBAC(data,gui) -1422 -1423 in.path = fullfile(data.import.path); -1424 in.name = data.import.file; -1425 in.fileformat = data.import.fileformat; -1426 out = LoadNMRData_driver(in); +1223 end +1224 end +1225 +1226 % update the global data structure +1227 data.import.NMR.files = fnames; +1228 data.import.NMR.filesShort = shownames; +1229 +1230 end +1231 +1232 %% +1233 function [data,gui] = importDataDartT2logging(data,gui,useburst) +1234 +1235 % now check the subpaths +1236 % there should be some folders with names ... +1237 % ... similar to the data filenames inside them +1238 datpath = dir(data.import.path); +1239 datpath = datpath(~ismember({datpath.name},{'.','..'})); +1240 % remove any subfolder within the data directory +1241 datpath = datpath(~ismember([datpath.isdir],true)); +1242 +1243 fnames = struct; +1244 % shownames is just a dummy to hold all data file names that +1245 % will be shown in the listbox +1246 shownames = cell(1,1); +1247 +1248 c = 0; +1249 if ~isempty(datpath) +1250 content = datpath; +1251 for j = 1:size(content,1) +1252 in.T1T2 = 'T2'; +1253 in.name = content(j).name; +1254 in.path = fullfile(data.import.path); +1255 in.fileformat = data.import.fileformat; +1256 in.version = 5; +1257 out = LoadNMRData_driver(in); +1258 +1259 if useburst +1260 for nn = 1:2 +1261 % get normal and burst signal +1262 idN = nn; +1263 idB = idN+2; +1264 +1265 % add both signals to the data +1266 c = c + 1; +1267 fnames(c).parfile = ''; +1268 fnames(c).datafile = out.nmrData{idN}.datfile; +1269 fnames(c).T2specfile = ''; +1270 if out.parData{nn}.freq/1e3 < 450 +1271 % 433 kHz +1272 shownames{c} = ['433kHz_',content(j).name]; +1273 else +1274 % 486 kHz +1275 shownames{c} = ['486kHz_',content(j).name]; +1276 end +1277 data.import.NMR.data{c} = out.nmrData{idN}; +1278 data.import.NMR.para{c} = out.parData{idN}; +1279 +1280 c = c + 1; +1281 fnames(c).parfile = ''; +1282 fnames(c).datafile = out.nmrData{idB}.datfile; +1283 fnames(c).T2specfile = ''; +1284 if out.parData{nn}.freq/1e3 < 450 +1285 % 433 kHz +1286 shownames{c} = ['433kHz_',content(j).name,'_burst']; +1287 else +1288 % 486 kHz +1289 shownames{c} = ['486kHz_',content(j).name,'_burst']; +1290 end +1291 data.import.NMR.data{c} = out.nmrData{idB}; +1292 data.import.NMR.para{c} = out.parData{idB}; +1293 +1294 % 1. fit both T2 signals mono-exponentially +1295 time0 = data.import.NMR.data{c-1}.time; +1296 signal = data.import.NMR.data{c-1}.signal; +1297 param.T1IRfac = 1; +1298 param.noise = std(imag(signal)); +1299 param.optim = 'off'; +1300 param.Tfixed_bool = [0 0 0 0 0]; +1301 param.Tfixed_val = [0 0 0 0 0]; +1302 invstd0 = fitDataFree(time0,real(signal),'T2',param,1); +1303 +1304 time1 = data.import.NMR.data{c}.time; +1305 signal = data.import.NMR.data{c}.signal; +1306 param.T1IRfac = 1; +1307 param.noise = std(imag(signal)); +1308 param.optim = 'off'; +1309 param.Tfixed_bool = [0 0 0 0 0]; +1310 param.Tfixed_val = [0 0 0 0 0]; +1311 invstd1 = fitDataFree(time1,real(signal),'T2',param,1); +1312 +1313 % now assemble a dummy T1 curve +1314 t = [1e-4 data.import.NMR.para{c}.t_wait data.import.NMR.para{c-1}.t_wait]; +1315 s = [0 invstd1.E0 invstd0.E0]; +1316 % finally create a new "import" data set +1317 data_new = data.import.NMR.data(c); +1318 para_new = data.import.NMR.para(c); +1319 +1320 data_new{1}.flag = 'T1'; +1321 data_new{1}.T1IRfac = 1; +1322 data_new{1}.time = t; +1323 data_new{1}.signal = s; +1324 data_new{1}.noise = 0; +1325 data_new{1}.raw.time = t; +1326 data_new{1}.raw.signal = s; +1327 +1328 c = c + 1; +1329 data.import.NMR.data{c} = data_new{1}; +1330 data.import.NMR.para{c} = para_new{1}; +1331 fnames(c).datafile = 'T1_merged.dat'; +1332 shownames{c} = [shownames{c-1}(1:end-5),'T1_merged']; +1333 end +1334 else +1335 for nn = 1:2 +1336 % the individual file names +1337 c = c + 1; +1338 fnames(c).parfile = ''; +1339 fnames(c).datafile = out.nmrData{nn}.datfile; +1340 fnames(c).T2specfile = ''; +1341 if out.parData{nn}.freq/1e3 < 450 +1342 % 433 kHz +1343 shownames{c} = ['433kHz_',content(j).name]; +1344 else +1345 % 486 kHz +1346 shownames{c} = ['486kHz_',content(j).name]; +1347 end +1348 +1349 data.import.NMR.data{c} = out.nmrData{nn}; +1350 data.import.NMR.para{c} = out.parData{nn}; +1351 end +1352 end +1353 end +1354 end +1355 +1356 % update the global data structure +1357 data.import.NMR.files = fnames; +1358 data.import.NMR.filesShort = shownames; +1359 +1360 end +1361 +1362 %% +1363 function [data,gui] = importDataDart(data,gui) +1364 +1365 in.path = fullfile(data.import.path); +1366 in.name = data.import.file; +1367 in.fileformat = data.import.fileformat; +1368 in.version = data.import.version; +1369 out = LoadNMRData_driver(in); +1370 +1371 fnames = struct; +1372 % shownames is just a dummy to hold all data file names that +1373 % will be shown in the listbox +1374 shownames = cell(1,1); +1375 +1376 c = 0; +1377 for j = 1:size(out.nmrData,2) +1378 % the individual file names +1379 c = c + 1; +1380 fnames(c).parfile = ''; +1381 fnames(c).datafile = data.import.file; +1382 fnames(c).T2specfile = ''; +1383 +1384 shownames{c} = ['depth_',sprintf('%04.3f',out.parData{j}.depth)]; +1385 +1386 % the NMR data +1387 % here we fix the time scale from [ms] to [s] +1388 if max(out.nmrData{j}.time) > 100 +1389 out.nmrData{j}.time = out.nmrData{j}.time/1000; +1390 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; +1391 end +1392 data.import.NMR.data{c} = out.nmrData{j}; +1393 data.import.NMR.para{c} = out.parData{j}; +1394 end +1395 +1396 % update the global data structure +1397 data.import.NMR.files = fnames; +1398 data.import.NMR.filesShort = shownames; +1399 +1400 end +1401 +1402 %% +1403 function [data,gui] = importDataRoCAT1T2(data,gui) +1404 +1405 % there should be some folders with names ... +1406 % ... similar to the data filenames inside them +1407 datpath = dir(data.import.path); +1408 datpath = datpath(~ismember({datpath.name},{'.','..'})); +1409 % remove any subfolder within the data directory +1410 datpath = datpath(~ismember([datpath.isdir],true)); +1411 +1412 fnames = struct; +1413 % shownames is just a dummy to hold all data file names that +1414 % will be shown in the listbox +1415 shownames = cell(1,1); +1416 +1417 c = 0; +1418 if ~isempty(datpath) +1419 content = datpath; +1420 for j = 1:size(content,1) +1421 if strcmp(content(j).name,'data2.csv') +1422 in.T1T2 = 'T2'; +1423 in.name = content(j).name; +1424 in.path = fullfile(data.import.path); +1425 in.fileformat = data.import.fileformat; +1426 out = LoadNMRData_driver(in); 1427 -1428 nslices = out.parData.depths; -1429 nfiles = size(out.nmrData,2); -1430 -1431 fnames = struct; -1432 % shownames is just a dummy to hold all data file names that -1433 % will be shown in the listbox -1434 shownames = cell(1,1); -1435 -1436 c = 0; -1437 for j = 1:size(out.nmrData,2) -1438 % the individual file names -1439 c = c + 1; -1440 fnames(c).parfile = out.parData.parfile; -1441 fnames(c).datafile = out.nmrData{j}.datfile; -1442 fnames(c).T2specfile = ''; -1443 -1444 shownames{c} = [fnames(c).datafile]; -1445 -1446 data.import.NMR.data{c} = out.nmrData{j}; -1447 data.import.NMR.para{c} = out.parData; -1448 end -1449 -1450 % check if the number of depth levels is equal to the number of -1451 % measurements -1452 if nslices == nfiles -1453 % create z-vector -1454 p = out.parData; -1455 zslice = linspace(p.initialdepth,p.finaldepth,p.depths)'; -1456 data.import.IBAC.use_z = true; -1457 data.import.IBAC.zslice = zslice; -1458 if numel(zslice) > 1 -1459 c = 0; -1460 for i = 1:nfiles -1461 c = c + 1; -1462 tmp = shownames{i}; -1463 shownames{i} = [tmp,' z:',sprintf('%05d',zslice(c))]; -1464 end -1465 end -1466 else -1467 data.import.IBAC.use_z = false; -1468 data.import.IBAC.zslice = 1:1:max([nfiles 1]); -1469 end -1470 -1471 % update the global data structure -1472 data.import.NMR.files = fnames; -1473 data.import.NMR.filesShort = shownames; -1474 -1475 end -1476 -1477 %% -1478 function data = loadGUIParameters(datapath,fname) -1479 fid = fopen(fullfile(datapath,fname)); -1480 d = textscan(fid,'%s','Delimiter','\n'); -1481 fclose(fid); -1482 data = struct; -1483 for i = 1:size(d{1},1) -1484 str = char(d{1}(i)); -1485 str = fixParameterString(str); -1486 eval(['data.',str,';']); %#ok<EVLDOT> -1487 end -1488 -1489 end -1490 -1491 %% -1492 function data = loadGUIrawdata(data,NMRpath,NMRfile) -1493 -1494 load(fullfile(NMRpath,'NUCLEUSinv_raw.mat'),'savedata'); -1495 -1496 data.import.file = NMRfile; -1497 data.import.path = NMRpath; -1498 data.import.NMR = savedata; -1499 -1500 end +1428 for j1 = 1:numel(out.nmrData) +1429 % the individual file names +1430 c = c + 1; +1431 fnames(c).parfile = 'acqu.par'; +1432 fnames(c).datafile = out.nmrData{j1}.datfile; +1433 fnames(c).T2specfile = ''; +1434 +1435 shownames{c} = ['T2_',content(j).name,'_',sprintf('%03d',j1)]; +1436 +1437 data.import.NMR.data{c} = out.nmrData{j1}; +1438 data.import.NMR.para{c} = out.parData; +1439 end +1440 end +1441 end +1442 +1443 % save the recovery time vector for later use +1444 t2 = data.import.NMR.data{1}.time; +1445 t2N = numel(t2); +1446 t_recov = logspace(log10(out.parData.minTau),log10(out.parData.maxTau),out.parData.tauSteps); +1447 data.import.T1T2map.t_recov = t_recov(:)./1e3; % to [s] +1448 data.import.T1T2map.t2 = t2; +1449 data.import.T1T2map.t2N = t2N; +1450 +1451 % add the stacked signal to the data +1452 Nechos = 1; +1453 flag = 'T1'; +1454 time = data.import.T1T2map.t_recov; +1455 signal = zeros(numel(data.import.NMR.data),1); +1456 for i1 = 1:numel(data.import.NMR.data) +1457 signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); +1458 end +1459 +1460 disp('NUCLUESinv import: Estimating noise from exponential fit ...'); +1461 param.T1IRfac = 2; +1462 param.noise = 0; +1463 param.optim = 'off'; +1464 param.Tfixed_bool = [0 0 0 0 0]; +1465 param.Tfixed_val = [0 0 0 0 0]; +1466 for i1 = 1:5 +1467 invstd = fitDataFree(time,signal,flag,param,i1); +1468 if i1 == 1 +1469 noise = invstd.rms; +1470 else +1471 noise = min([noise invstd.rms]); +1472 end +1473 end +1474 disp('NUCLUESinv import: done.') +1475 +1476 % finally create a new "import" data set +1477 data_new = data.import.NMR.data(1); +1478 para_new = data.import.NMR.para(1); +1479 +1480 data_new{1}.flag = flag; +1481 data_new{1}.T1IRfac = param.T1IRfac; +1482 data_new{1}.time = time; +1483 data_new{1}.signal = signal; +1484 data_new{1}.noise = noise; +1485 data_new{1}.raw.time = time; +1486 data_new{1}.raw.signal = signal; +1487 +1488 data.import.NMR.data{c+1} = data_new{1}; +1489 data.import.NMR.para{c+1} = para_new{1}; +1490 fnames(c+1).datafile = 'T1_merged.dat'; +1491 shownames{c+1} = 'T1_merged'; +1492 % set global echo time +1493 data.inv2D.prop.te = data.import.NMR.para{1}.echoTime/1e6; % [s] +1494 % set T1 SR/IR factor +1495 data.inv2D.inv.T1IRfac = 2; % Rock Core Analyzer default(?) +1496 end +1497 +1498 % update the global data structure +1499 data.import.NMR.files = fnames; +1500 data.import.NMR.filesShort = shownames; 1501 -1502 %------------- END OF CODE -------------- +1502 end 1503 -1504 %% License: -1505 % MIT License -1506 % -1507 % Copyright (c) 2018 Thomas Hiller -1508 % -1509 % Permission is hereby granted, free of charge, to any person obtaining a copy -1510 % of this software and associated documentation files (the "Software"), to deal -1511 % in the Software without restriction, including without limitation the rights -1512 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -1513 % copies of the Software, and to permit persons to whom the Software is -1514 % furnished to do so, subject to the following conditions: -1515 % -1516 % The above copyright notice and this permission notice shall be included in all -1517 % copies or substantial portions of the Software. -1518 % -1519 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -1520 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -1521 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -1522 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -1523 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -1524 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -1525 % SOFTWARE.

    +1504 %% +1505 function [data,gui] = importDataGeneral(data,gui) +1506 +1507 % look for all files ending with '.par' +1508 % should exist for T1 and T2 measurements +1509 filenames = dir(fullfile(data.import.path,'*.par')); +1510 +1511 fnames = struct; +1512 % shownames is just a dummy to hold all data file names that +1513 % will be shown in the listbox +1514 shownames = cell(1,1); +1515 +1516 % loop over all found files and import the data +1517 c = 0; +1518 in.path = data.import.path; +1519 for i = 1:size(filenames,1) +1520 ind = strfind(filenames(i).name,'.'); +1521 ind = max(ind); +1522 in.name = filenames(i).name(1:ind-1); +1523 in.fileformat = data.import.fileformat; +1524 out = LoadNMRData_driver(in); +1525 +1526 for j = 1:size(out.nmrData,2) +1527 % the individual file names +1528 c = c + 1; +1529 fnames(c).parfile = filenames(i).name; +1530 fnames(c).datafile = out.nmrData{j}.datfile; +1531 if strcmp(out.nmrData{j}.flag,'T2') && isfield(out.nmrData{j},'specfile') +1532 fnames(c).T2specfile = out.nmrData{j}.specfile; +1533 else +1534 fnames(c).T2specfile = ''; +1535 end +1536 shownames{c} = fnames(c).datafile; +1537 +1538 % the NMR data +1539 % here we fix the time scale from [ms] to [s] +1540 if max(out.nmrData{j}.time) > 100 +1541 out.nmrData{j}.time = out.nmrData{j}.time/1000; +1542 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; +1543 end +1544 data.import.NMR.data{c} = out.nmrData{j}; +1545 data.import.NMR.para{c} = out.parData; +1546 end +1547 end +1548 +1549 switch data.import.fileformat +1550 case 'bamtom' +1551 nslices = out.parData.nSlices; +1552 ncsvfiles = numel(fnames); +1553 +1554 % check for background file ("Leermessung") +1555 has_bg = false; +1556 for i = 1:numel(fnames) +1557 if ~isempty(strfind(fnames(i).datafile,'000')) +1558 has_bg = true; +1559 index_bg = i; +1560 break; +1561 end +1562 end +1563 +1564 if has_bg +1565 % background data set +1566 bg = data.import.NMR.data{index_bg}; +1567 +1568 % vector of indices of the files that get corrected +1569 ind_files = 1:1:ncsvfiles; +1570 ind_files(ind_files==index_bg) = []; +1571 +1572 for i = ind_files +1573 % subtract the background signal +1574 s = data.import.NMR.data{i}.signal; +1575 s_bg = bg.signal; +1576 % if the background signal is longer than the signal cut it +1577 if numel(s_bg) > numel(s) +1578 tmp_s = s_bg(1:numel(s)); +1579 else % if not pad it with zeros +1580 tmp_s = zeros(size(s)); +1581 tmp_s(1:numel(s_bg)) = s_bg; +1582 end +1583 s = complex(real(s)-real(tmp_s),imag(s)-imag(tmp_s)); +1584 % update original data set +1585 data.import.NMR.data{i}.signal = s; +1586 end +1587 +1588 % check if the number of slices is equal to the number of files +1589 % (excluding the background file) +1590 if nslices == numel(ind_files) +1591 % create z-vector +1592 p = out.parData; +1593 zslice = linspace(p.startPos,p.endPos,p.nSlices)'; +1594 data.import.BAM.use_z = true; +1595 data.import.BAM.zslice = zslice; +1596 if numel(zslice) > 1 +1597 c = 0; +1598 for i = ind_files +1599 c = c + 1; +1600 tmp = shownames{i}; +1601 shownames{i} = [tmp,' z:',sprintf('%5.4f',zslice(c))]; +1602 end +1603 end +1604 else +1605 data.import.BAM.use_z = false; +1606 data.import.BAM.zslice = 1:1:max([numel(ind_files) 1]); +1607 end +1608 +1609 else +1610 if nslices == ncsvfiles +1611 % create z-vector +1612 p = out.parData; +1613 zslice = linspace(p.startPos,p.endPos,p.nSlices)'; +1614 data.import.BAM.use_z = true; +1615 data.import.BAM.zslice = zslice; +1616 if numel(zslice) > 1 +1617 for i = 1:numel(zslice) +1618 tmp = shownames{i}; +1619 shownames{i} = [tmp,' z:',sprintf('%5.4f',zslice(i))]; +1620 end +1621 end +1622 else +1623 data.import.BAM.use_z = false; +1624 data.import.BAM.zslice = 1:1:ncsvfiles; +1625 end +1626 end +1627 end +1628 +1629 % update the global data structure +1630 data.import.NMR.files = fnames; +1631 data.import.NMR.filesShort = shownames; +1632 +1633 end +1634 +1635 %% +1636 function [data,gui] = importDataLIAG(data,gui) +1637 +1638 in.path = fullfile(data.import.path); +1639 in.fileformat = data.import.fileformat; +1640 out = LoadNMRData_driver(in); +1641 +1642 fnames = struct; +1643 % shownames is just a dummy to hold all data file names that +1644 % will be shown in the listbox +1645 shownames = cell(1,1); +1646 +1647 c = 0; +1648 for j = 1:size(out.nmrData,2) +1649 % the individual file names +1650 c = c + 1; +1651 fnames(c).parfile = 'acqu.par'; +1652 fnames(c).datafile = out.nmrData{j}.datfile; +1653 fnames(c).T2specfile = ''; +1654 +1655 shownames{c} = fnames(c).datafile; +1656 +1657 % the NMR data +1658 % here we fix the time scale to [s] if neccessary +1659 TE = out.parData.echoTime; % [µs] +1660 if out.nmrData{j}.time(1)== TE/1e3 +1661 % change [ms] to [s] +1662 out.nmrData{j}.time = out.nmrData{j}.time/1e3; +1663 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1e3; +1664 elseif out.nmrData{j}.time(1)== TE +1665 % change [µs] to [s] -> very unlikely +1666 out.nmrData{j}.time = out.nmrData{j}.time/1e6; +1667 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1e6; +1668 end +1669 data.import.NMR.data{c} = out.nmrData{j}; +1670 data.import.NMR.para{c} = out.parData; +1671 end +1672 +1673 % update the global data structure +1674 data.import.NMR.files = fnames; +1675 data.import.NMR.filesShort = shownames; +1676 +1677 end +1678 +1679 %% +1680 function [data,gui] = importDataLIAGcore(data,gui) +1681 +1682 % get all subfolders containing a measurement at a certain heigth +1683 subdirs = dir(data.import.path); +1684 % remove the dot-dirs +1685 subdirs = subdirs(~ismember({subdirs.name},{'.','..'})); +1686 +1687 % now get the background data ("Leermessung") +1688 bgPath = uigetdir(data.import.path,'Choose Background Data Path'); +1689 isbgPath = false; +1690 if bgPath == 0 +1691 disp('NUCLEUSinv: LIAG core import: No background file provided.'); +1692 else +1693 isbgPath = true; +1694 in.path = fullfile(bgPath); +1695 in.fileformat = data.import.fileformat; +1696 bgout = LoadNMRData_driver(in); +1697 ref1.t = bgout.nmrData{1}.time; +1698 ref1.s = bgout.nmrData{1}.signal; +1699 [ref1.s,~] = rotateT2phase(ref1.s); +1700 end +1701 +1702 % get the Position file +1703 [posFile,posFilePath] = uigetfile('*.*','Choose Lift Position File',data.import.path); +1704 isposFile = false; +1705 if posFilePath == 0 +1706 disp('NUCLEUSinv: LIAG core import: No position file provided.'); +1707 else +1708 isposFile = true; +1709 % import LIAG lift file +1710 buffer = fileread(fullfile(posFilePath,posFile)); +1711 +1712 % get the time stamps of the lift positions +1713 substr = 'Zeit:' ; +1714 loc = strfind(buffer, substr); +1715 timepoint = cell(1,1); +1716 for i = 1:length(loc) +1717 timestr = strtrim(buffer(loc(i)+numel(substr):loc(i)+numel(substr)+19)); +1718 timepoint{i} = datetime(timestr,'InputFormat','dd.MM.yyyy HH:mm:ss'); +1719 end +1720 % ignore the first time stamp +1721 t_range = [datenum(timepoint{2}), datenum(timepoint{3})]; +1722 % get the z coords +1723 substr = 'Z1='; +1724 loc = strfind(buffer, substr) ; +1725 z_range(1) = sscanf(buffer(loc+numel(substr):loc+numel(substr)+10),'%f',1); +1726 substr = 'Z2='; +1727 loc = strfind(buffer, substr) ; +1728 z_range(2) = sscanf(buffer(loc+numel(substr):loc+numel(substr)+10),'%f',1); +1729 end +1730 +1731 % import the NMR data +1732 count = 0; +1733 levels = zeros(size(subdirs)); +1734 nmrDataTMP = cell(1,1); +1735 for i = 1:numel(subdirs) +1736 if ~isnan(str2double(subdirs(i).name)) +1737 +1738 % import the NMR file +1739 in.path = fullfile(data.import.path,subdirs(i).name,'T2CPMG'); +1740 in.fileformat = data.import.fileformat; +1741 out = LoadNMRData_driver(in); +1742 +1743 % if there is a position file +1744 if isposFile +1745 % keep only files within the correct time range +1746 if out.nmrData{1}.datenum > t_range(1) && out.nmrData{1}.datenum < t_range(2) +1747 count = count + 1; +1748 % interpolate the z position via the time stamp of the NMR file +1749 levels(count) = interp1(t_range,z_range,out.nmrData{1}.datenum,'linear'); +1750 nmrDataTMP{count} = out; +1751 end +1752 else % just read everything +1753 count = count + 1; +1754 levels(count) = str2double(subdirs(i).name); +1755 nmrDataTMP{count} = out; +1756 end +1757 end +1758 end +1759 % cut off data that is not part of the scan +1760 levels = levels(1:count); +1761 % sort in ascending order +1762 [levels,idx] = sort(levels); +1763 +1764 % sort the NMR data accordingly +1765 fnames = struct; +1766 % shownames is just a dummy to hold all data file names that +1767 % will be shown in the listbox +1768 shownames = cell(1,1); +1769 for c = 1:numel(levels) +1770 % the individual file names +1771 fnames(c).parfile = 'acqu.par'; +1772 fnames(c).datafile = nmrDataTMP{idx(c)}.nmrData{1}.datfile; +1773 fnames(c).T2specfile = ''; +1774 +1775 shownames{c} = fnames(c).datafile; +1776 tmp = shownames{c}; +1777 if isposFile +1778 shownames{c} = [tmp,': ',sprintf('%4d',floor(levels(c))),'mm']; +1779 else +1780 shownames{c} = [tmp,' level:',sprintf('%d',levels(c))]; +1781 end +1782 out = nmrDataTMP{idx(c)}; +1783 +1784 % the NMR data +1785 % here we fix the time scale to [s] if neccessary +1786 TE = out.parData.echoTime; % [µs] +1787 if out.nmrData{1}.time(1) == TE/1e3 +1788 % change [ms] to [s] +1789 out.nmrData{1}.time = out.nmrData{1}.time/1e3; +1790 out.nmrData{1}.raw.time = out.nmrData{1}.raw.time/1e3; +1791 elseif out.nmrData{1}.time(1) == TE +1792 % change [µs] to [s] -> very unlikely +1793 out.nmrData{1}.time = out.nmrData{1}.time/1e6; +1794 out.nmrData{1}.raw.time = out.nmrData{1}.raw.time/1e6; +1795 end +1796 data.import.NMR.data{c} = out.nmrData{1}; +1797 data.import.NMR.para{c} = out.parData; +1798 +1799 % subtract the background signal is one is available +1800 if isbgPath +1801 % get the original signal +1802 s = data.import.NMR.data{c}.signal; +1803 % if the background signal is longer than the signal cut it, if +1804 % not extend it with zeros +1805 if numel(ref1.s) > numel(s) +1806 tmp_r = ref1.s(1:numel(s)); +1807 else +1808 tmp_r = zeros(size(s)); +1809 tmp_r(1:numel(ref1.s)) = ref1.s; +1810 end +1811 s = complex(real(s)-real(tmp_r),imag(s)-imag(tmp_r)); +1812 +1813 % sign check +1814 if real(s(1:3))<0 +1815 s = s*-1; +1816 end +1817 +1818 % rotate phase again - TEST +1819 [s,~] = rotateT2phase(s); +1820 +1821 % update signal +1822 data.import.NMR.data{c}.signal = s; +1823 data.import.NMR.data{c}.raw.signal = s; +1824 end +1825 end +1826 if isposFile +1827 data.import.LIAGCORE.use_z = true; +1828 else +1829 data.import.LIAGCORE.use_z = false; +1830 end +1831 data.import.LIAGCORE.zslice = levels; +1832 +1833 % update the global data structure +1834 data.import.NMR.files = fnames; +1835 data.import.NMR.filesShort = shownames; +1836 +1837 end +1838 +1839 %% +1840 function [data,gui] = importDataLIAGproject(data,gui) +1841 +1842 % 1) show all folders and ask for sample +1843 subdirs = dir(data.import.path); +1844 % remove the dot-dirs +1845 subdirs = subdirs(~ismember({subdirs.name},{'.','..'})); +1846 +1847 fnames = {subdirs.name}; +1848 [indx,~] = listdlg('PromptString','Select Sample:',... +1849 'SelectionMode','single',... +1850 'ListString',fnames); +1851 +1852 if ~isempty(indx) +1853 % 2) check corresponding SampleParameter.par file for reference and +1854 % calibration sample and other parameters +1855 datapath = fullfile(data.import.path,fnames{indx}); +1856 % load SampleParameter file for sample +1857 [SampleParameter] = loadGUIParameters(datapath,'SampleParameters.par'); +1858 if isfield(SampleParameter,'sampleVolume') +1859 dataVol = SampleParameter.sampleVolume; +1860 else +1861 dataVol = 1; +1862 end +1863 +1864 % 2a) background file #1 +1865 backgroundFile1 = SampleParameter.backgroundFile; +1866 if isempty(backgroundFile1) +1867 bnames = {subdirs.name}; +1868 bnames(indx) = []; +1869 [indb,~] = listdlg('PromptString','Select Background File:',... +1870 'SelectionMode','single',... +1871 'ListString',bnames); +1872 if ~isempty(indb) +1873 backgroundFile1 = bnames{indb}; +1874 else +1875 backgroundFile1 = ''; +1876 end +1877 end +1878 if ~isempty(backgroundFile1) +1879 ind = strfind(backgroundFile1,filesep); +1880 if ~isempty(ind) +1881 backgroundFile1 = backgroundFile1(ind(end)+1:end); +1882 end +1883 fileInList = ismember(fnames,{backgroundFile1}); +1884 if any(fileInList) +1885 backgroundpath1 = fullfile(data.import.path,fnames{fileInList}); +1886 end +1887 else +1888 backgroundpath1 = ''; +1889 backgroundFile1 = ''; +1890 end +1891 backVol = 1; +1892 +1893 % 2b) calibration file +1894 c = 0; +1895 if isfield(SampleParameter,'calibrationFile0') +1896 c = c + 1; +1897 calibrationFiles{c} = SampleParameter.calibrationFile0; +1898 end +1899 if isfield(SampleParameter,'calibrationFile1') +1900 c = c + 1; +1901 calibrationFiles{c} = SampleParameter.calibrationFile1; +1902 end +1903 if isfield(SampleParameter,'calibrationFile2') +1904 c = c + 1; +1905 calibrationFiles{c} = SampleParameter.calibrationFile2; +1906 end +1907 if isfield(SampleParameter,'calibrationFile3') +1908 c = c + 1; +1909 calibrationFiles{c} = SampleParameter.calibrationFile3; +1910 end +1911 +1912 % find the non-empty one +1913 ind = ismember(calibrationFiles,{''}); +1914 % there are three possibilities: 0, 1 and more than 1 calib. files +1915 calibrationFiles(ind) = []; +1916 if isempty(calibrationFiles) +1917 cnames = {subdirs.name}; +1918 cnames(indx) = []; +1919 [indc,~] = listdlg('PromptString','Select Calibration File:',... +1920 'SelectionMode','single',... +1921 'ListString',cnames); +1922 if ~isempty(indc) +1923 calibrationFiles = cnames{indc}; +1924 else +1925 calibrationFiles = ''; +1926 end +1927 else +1928 % if there are more than one let the user select the correct one +1929 if numel(calibrationFiles) > 1 +1930 [ind,~] = listdlg('PromptString','Select Calibration File:',... +1931 'SelectionMode','single',... +1932 'ListString',calibrationFiles); +1933 calibrationFiles = calibrationFiles{ind}; +1934 else +1935 calibrationFiles = calibrationFiles{1}; +1936 end +1937 end +1938 if ~isempty(calibrationFiles) +1939 ind = strfind(calibrationFiles,filesep); +1940 if ~isempty(ind) +1941 calibrationFiles = calibrationFiles(ind(end)+1:end); +1942 end +1943 fileInList = ismember(fnames,{calibrationFiles}); +1944 if any(fileInList) +1945 calibrationpath = fullfile(data.import.path,fnames{fileInList}); +1946 end +1947 else +1948 calibrationpath = ''; +1949 calibrationFiles = ''; +1950 end +1951 +1952 if ~isempty(calibrationpath) +1953 [SampleParameterC] = loadGUIParameters(calibrationpath,'SampleParameters.par'); +1954 if isfield(SampleParameterC,'sampleVolume') +1955 calibVol = SampleParameterC.sampleVolume; +1956 else +1957 calibVol = 1; +1958 end +1959 +1960 % 2a) background file #2 +1961 backgroundFile2 = SampleParameterC.backgroundFile; +1962 if isempty(backgroundFile2) +1963 bnames = {subdirs.name}; +1964 bnames(indx) = []; +1965 [indb,~] = listdlg('PromptString','Select Background File for Calibration:',... +1966 'SelectionMode','single',... +1967 'ListString',bnames); +1968 if ~isempty(indb) +1969 backgroundFile2 = bnames{indb}; +1970 else +1971 backgroundFile2 = ''; +1972 end +1973 end +1974 if ~isempty(backgroundFile2) +1975 ind = strfind(backgroundFile2,filesep); +1976 if ~isempty(ind) +1977 backgroundFile2 = backgroundFile2(ind(end)+1:end); +1978 end +1979 fileInList = ismember(fnames,{backgroundFile2}); +1980 if any(fileInList) +1981 backgroundpath2 = fullfile(data.import.path,fnames{fileInList}); +1982 end +1983 else +1984 backgroundpath2 = ''; +1985 backgroundFile2 = ''; +1986 end +1987 else +1988 calibVol = 1; +1989 backgroundpath2 = ''; +1990 backgroundFile2 = ''; +1991 end +1992 +1993 % 3) now load the data +1994 workpaths = {datapath,calibrationpath,backgroundpath1,backgroundpath2}; +1995 workfiles = {fnames{indx},[calibrationFiles,' - calibration'],... +1996 [backgroundFile1,' - backgroundS'],[backgroundFile2,' - backgroundC']}; +1997 out = cell(size(workpaths)); +1998 count = 0; +1999 keep = false(size(workpaths)); +2000 for i = 1:numel(workpaths) +2001 if ~isempty(workpaths{i}) +2002 workdirs = dir(workpaths{i}); +2003 workdirs = workdirs(~ismember({workdirs.name},{'.','..'})); +2004 isT2 = ismember({workdirs.name},{'T2CPMG'}); +2005 if any(isT2) +2006 keep(i) = true; +2007 count = count + 1; +2008 T2path = fullfile(workdirs(isT2).folder,workdirs(isT2).name); +2009 in.path = T2path; +2010 in.fileformat = data.import.fileformat; +2011 out{i} = LoadNMRData_driver(in); +2012 end +2013 end +2014 end +2015 +2016 if isempty(backgroundpath1) +2017 ref1 = struct; +2018 else +2019 background1 = out{3}; +2020 % get the background data 1 +2021 ref1.t = background1.nmrData{1}.time; +2022 ref1.s = background1.nmrData{1}.signal; +2023 [ref1.s,~] = rotateT2phase(ref1.s); +2024 end +2025 +2026 if isempty(backgroundpath2) +2027 ref2 = struct; +2028 else +2029 background2 = out{4}; +2030 % get the background data 2 +2031 ref2.t = background2.nmrData{1}.time; +2032 ref2.s = background2.nmrData{1}.signal; +2033 [ref2.s,~] = rotateT2phase(ref2.s); +2034 end +2035 +2036 workpaths = workpaths(keep); +2037 workfiles = workfiles(keep); +2038 out = out(keep); +2039 +2040 ffnames = struct; +2041 % shownames is just a dummy to hold all data file names that +2042 % will be shown in the listbox +2043 shownames = cell(1,1); +2044 +2045 for i = 1:count +2046 ffnames(i).parfile = 'acqu.par'; +2047 ffnames(i).datafile = workfiles{i}; +2048 ffnames(i).T2specfile = ''; +2049 +2050 shownames{i} = ffnames(i).datafile; +2051 +2052 % the NMR data +2053 % here we fix the time scale to [s] if neccessary +2054 TE = out{i}.parData.echoTime; % [µs] +2055 if out{i}.nmrData{1}.time(1)== TE/1e3 +2056 % change [ms] to [s] +2057 out{i}.nmrData{1}.time = out{i}.nmrData{1}.time/1e3; +2058 out{i}.nmrData{1}.raw.time = out{i}.nmrData{1}.raw.time/1e3; +2059 elseif out{i}.nmrData{1}.time(1)== TE +2060 % change [µs] to [s] -> very unlikely +2061 out{i}.nmrData{1}.time = out{i}.nmrData{1}.time/1e6; +2062 out{i}.nmrData{1}.raw.time = out{i}.nmrData{1}.raw.time/1e6; +2063 end +2064 +2065 data.import.NMR.data{i} = out{i}.nmrData{1}; +2066 data.import.NMR.para{i} = out{i}.parData; +2067 data.import.NMR.para{i}.SampleParameter = SampleParameter; +2068 +2069 % subtract the background signal +2070 s = data.import.NMR.data{i}.signal; +2071 if i==1 && isfield(ref1,'s') +2072 % if the background signal is longer than the signal cut it, if +2073 % not extend it with zeros +2074 if numel(ref1.s) > numel(s) +2075 tmp_r = ref1.s(1:numel(s)); +2076 else +2077 tmp_r = zeros(size(s)); +2078 tmp_r(1:numel(ref1.s)) = ref1.s; +2079 end +2080 s = complex(real(s)-real(tmp_r),imag(s)-imag(tmp_r)); +2081 elseif i==2 && isfield(ref2,'s') +2082 % if the background signal is longer than the signal cut it, if +2083 % not extend it with zeros +2084 if numel(ref2.s) > numel(s) +2085 tmp_r = ref2.s(1:numel(s)); +2086 else +2087 tmp_r = zeros(size(s)); +2088 tmp_r(1:numel(ref2.s)) = ref2.s; +2089 end +2090 s = complex(real(s)-real(tmp_r),imag(s)-imag(tmp_r)); +2091 end +2092 data.import.NMR.data{i}.signal = s; +2093 data.import.NMR.data{i}.raw.signal = s; +2094 +2095 if ~isempty(strfind(workfiles{i},' - background')) +2096 data.import.LIAG.sampleVol(i) = backVol; +2097 elseif ~isempty(strfind(workfiles{i},' - calibration')) +2098 data.import.LIAG.sampleVol(i) = calibVol; +2099 elseif isempty(strfind(workfiles{i},' - background')) &&... +2100 isempty(strfind(workfiles{i},' - calibration')) +2101 data.import.LIAG.sampleVol(i) = dataVol; +2102 end +2103 end +2104 data.import.LIAG.Tbulk = 1e6; +2105 data.import.LIAG.Tbulk_keep_fit = false; +2106 data.import.LIAG.workpaths = workpaths; +2107 data.import.LIAG.datapath = datapath; +2108 data.import.LIAG.calibrationpath = calibrationpath; +2109 data.import.LIAG.backgroundpath1 = backgroundpath1; +2110 data.import.LIAG.backgroundpath2 = backgroundpath2; +2111 +2112 % update the global data structure +2113 data.import.NMR.files = ffnames; +2114 data.import.NMR.filesShort = shownames; +2115 end +2116 +2117 end +2118 +2119 %% +2120 function [data,gui] = importDataMouse(data,gui) +2121 +2122 in.path = fullfile(data.import.path); +2123 in.fileformat = data.import.fileformat; +2124 out = LoadNMRData_driver(in); +2125 +2126 fnames = struct; +2127 % shownames is just a dummy to hold all data file names that +2128 % will be shown in the listbox +2129 shownames = cell(1,1); +2130 +2131 c = 0; +2132 for j = 1:size(out.nmrData,2) +2133 % the individual file names +2134 c = c + 1; +2135 fnames(c).parfile = 'acq.par'; +2136 fnames(c).datafile = out.nmrData{j}.datfile; +2137 fnames(c).T2specfile = ''; +2138 +2139 shownames{c} = ['T2_',fnames(c).datafile]; +2140 +2141 % the NMR data +2142 % here we fix the time scale from [ms] to [s] +2143 if max(out.nmrData{j}.time) > 100 +2144 out.nmrData{j}.time = out.nmrData{j}.time/1000; +2145 out.nmrData{j}.raw.time = out.nmrData{j}.raw.time/1000; +2146 end +2147 data.import.NMR.data{c} = out.nmrData{j}; +2148 data.import.NMR.para{c} = out.parData; +2149 end +2150 +2151 % update the global data structure +2152 data.import.NMR.files = fnames; +2153 data.import.NMR.filesShort = shownames; +2154 +2155 end +2156 +2157 %% +2158 function [data,gui] = importDataIBAC(data,gui) +2159 +2160 in.path = fullfile(data.import.path); +2161 in.name = data.import.file; +2162 in.fileformat = data.import.fileformat; +2163 out = LoadNMRData_driver(in); +2164 +2165 nslices = out.parData.depths; +2166 nfiles = size(out.nmrData,2); +2167 +2168 fnames = struct; +2169 % shownames is just a dummy to hold all data file names that +2170 % will be shown in the listbox +2171 shownames = cell(1,1); +2172 +2173 c = 0; +2174 for j = 1:size(out.nmrData,2) +2175 % the individual file names +2176 c = c + 1; +2177 fnames(c).parfile = out.parData.parfile; +2178 fnames(c).datafile = out.nmrData{j}.datfile; +2179 fnames(c).T2specfile = ''; +2180 +2181 shownames{c} = [fnames(c).datafile]; +2182 +2183 data.import.NMR.data{c} = out.nmrData{j}; +2184 data.import.NMR.para{c} = out.parData; +2185 end +2186 +2187 % check if the number of depth levels is equal to the number of +2188 % measurements +2189 if nslices == nfiles +2190 % create z-vector +2191 p = out.parData; +2192 zslice = linspace(p.initialdepth,p.finaldepth,p.depths)'; +2193 data.import.IBAC.use_z = true; +2194 data.import.IBAC.zslice = zslice; +2195 if numel(zslice) > 1 +2196 c = 0; +2197 for i = 1:nfiles +2198 c = c + 1; +2199 tmp = shownames{i}; +2200 shownames{i} = [tmp,' z:',sprintf('%05d',zslice(c))]; +2201 end +2202 end +2203 else +2204 data.import.IBAC.use_z = false; +2205 data.import.IBAC.zslice = 1:1:max([nfiles 1]); +2206 end +2207 +2208 % update the global data structure +2209 data.import.NMR.files = fnames; +2210 data.import.NMR.filesShort = shownames; +2211 +2212 end +2213 +2214 %% +2215 function data = loadGUIParameters(datapath,fname) +2216 fid = fopen(fullfile(datapath,fname)); +2217 d = textscan(fid,'%s','Delimiter','\n'); +2218 fclose(fid); +2219 data = struct; +2220 for i = 1:size(d{1},1) +2221 str = char(d{1}(i)); +2222 str = fixParameterString(str); +2223 eval(['data.',str,';']); %#ok<EVLDOT> +2224 end +2225 +2226 end +2227 +2228 %% +2229 function data = loadGUIrawdata(data,NMRpath,NMRfile) +2230 +2231 load(fullfile(NMRpath,'NUCLEUSinv_raw.mat'),'savedata'); +2232 +2233 data.import.file = NMRfile; +2234 data.import.path = NMRpath; +2235 data.import.NMR = savedata; +2236 +2237 end +2238 +2239 %------------- END OF CODE -------------- +2240 +2241 %% License: +2242 % MIT License +2243 % +2244 % Copyright (c) 2018 Thomas Hiller +2245 % +2246 % Permission is hereby granted, free of charge, to any person obtaining a copy +2247 % of this software and associated documentation files (the "Software"), to deal +2248 % in the Software without restriction, including without limitation the rights +2249 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +2250 % copies of the Software, and to permit persons to whom the Software is +2251 % furnished to do so, subject to the following conditions: +2252 % +2253 % The above copyright notice and this permission notice shall be included in all +2254 % copies or substantial portions of the Software. +2255 % +2256 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +2257 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +2258 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +2259 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +2260 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +2261 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +2262 % 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 437b1e5..4549c4b 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
  • Inv2DView
  • Mod2DView
  • PhaseView
  • UncertView
  • beautifyAxes
  • calculateGeometry
  • calculateGuiOnMonitorPosition
  • calculateNMR
  • calibratePorosity
  • caluclatePressureSaturation
  • changeColorTheme
  • checkIfInversionExists
  • cleanupGUIData
  • clearAllAxes
  • clearInversion
  • clearSingleAxis
  • displayStatusText
  • enableGUIelements
  • exportData
  • exportGraphics
  • exportINV
  • findParentOfType
  • fixAxes
  • getColorIndex
  • getColorTheme
  • getKernelDensityEstimate
  • getVersionNoFromString
  • importASCIIdata
  • importCPSdata
  • importCalibrationData
  • importEXCELdata
  • importINV2INV
  • importMOD2D2INV
  • 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:

      diff --git a/doc/nucleus/functions/interface/minimizePanel.html b/doc/nucleus/functions/interface/minimizePanel.html index 29c50bc..3bc36e6 100644 --- a/doc/nucleus/functions/interface/minimizePanel.html +++ b/doc/nucleus/functions/interface/minimizePanel.html @@ -62,7 +62,7 @@

      CROSS-REFERENCE INFORMATION ^
 <li><a href=findParentOfType is a "hack" because Matlab changed the parent-child
    • onFigureSizeChange fixes an ugly Matlab bug when resizing a box-panel
    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
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • PhaseView is an extra subGUI to manipulate the phase of a T2 signal
  • UncertView is an extra subGUI to show results of the uncertainty
  • @@ -273,36 +273,72 @@

    SOURCE CODE ^'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.

    +0206 case '2DINV' +0207 panel_1 = 'Properties'; +0208 panel_2 = '2D inversion settings'; +0209 panel_3 = 'Information'; +0210 +0211 switch paneltitle +0212 case panel_1 +0213 id = 1; +0214 case panel_2 +0215 id = 2; +0216 case panel_3 +0217 id = 3; +0218 otherwise +0219 helpdlg({'function: minimizePanel',... +0220 'Something is utterly wrong.'},'Info'); +0221 end +0222 +0223 switch paneltitle +0224 case {panel_1,panel_2,panel_3} +0225 % all heights of the left panels +0226 heights = get(gui.left,'Heights'); +0227 % default height of this panel +0228 pheight = def_heights(2,id); +0229 if isminimized % maximize panel +0230 heights(id) = pheight; +0231 set(gui.left,'Heights',heights); +0232 set(panel,'Minimized',false); +0233 else % minimize panel +0234 heights(id) = pheightmin; +0235 set(gui.left,'Heights',heights); +0236 set(panel,'Minimized',true) +0237 end +0238 otherwise +0239 helpdlg({'function: minimizePanel',... +0240 'Something is utterly wrong.'},'Info'); +0241 end +0242 end +0243 % update GUI data +0244 setappdata(fig,'gui',gui); +0245 +0246 end +0247 +0248 %------------- END OF CODE -------------- +0249 +0250 %% License: +0251 % MIT License +0252 % +0253 % Copyright (c) 2018 Thomas Hiller +0254 % +0255 % Permission is hereby granted, free of charge, to any person obtaining a copy +0256 % of this software and associated documentation files (the "Software"), to deal +0257 % in the Software without restriction, including without limitation the rights +0258 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0259 % copies of the Software, and to permit persons to whom the Software is +0260 % furnished to do so, subject to the following conditions: +0261 % +0262 % The above copyright notice and this permission notice shall be included in all +0263 % copies or substantial portions of the Software. +0264 % +0265 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0266 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0267 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0268 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0269 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0270 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0271 % SOFTWARE.

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/readINIfile.html b/doc/nucleus/functions/interface/readINIfile.html index fefd30b..b9fba36 100644 --- a/doc/nucleus/functions/interface/readINIfile.html +++ b/doc/nucleus/functions/interface/readINIfile.html @@ -108,7 +108,7 @@

    SOURCE CODE ^%% process lines 0040 for i = 1:size(inilines,1) 0041 tmp = char(inilines(i)); -0042 if ~isempty(strfind(tmp,'=')) +0042 if contains(tmp,'=') 0043 ind = strfind(tmp,'='); 0044 prop = tmp(1:ind-1); 0045 value = tmp(ind+1:end); diff --git a/doc/nucleus/functions/interface/removeInversionFields.html b/doc/nucleus/functions/interface/removeInversionFields.html index 15a985d..282e917 100644 --- a/doc/nucleus/functions/interface/removeInversionFields.html +++ b/doc/nucleus/functions/interface/removeInversionFields.html @@ -108,37 +108,40 @@

    SOURCE CODE ^if isfield(data.results,'invjoint') 0039 data.results = rmfield(data.results,'invjoint'); 0040 end -0041 if isfield(data.results,'lcurve') -0042 data.results = rmfield(data.results,'lcurve'); +0041 if isfield(data.results,'inv2D') +0042 data.results = rmfield(data.results,'inv2D'); 0043 end -0044 end -0045 -0046 return -0047 -0048 %------------- END OF CODE -------------- -0049 -0050 %% License: -0051 % MIT License -0052 % -0053 % Copyright (c) 2018 Thomas Hiller -0054 % -0055 % Permission is hereby granted, free of charge, to any person obtaining a copy -0056 % of this software and associated documentation files (the "Software"), to deal -0057 % in the Software without restriction, including without limitation the rights -0058 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0059 % copies of the Software, and to permit persons to whom the Software is -0060 % furnished to do so, subject to the following conditions: -0061 % -0062 % The above copyright notice and this permission notice shall be included in all -0063 % copies or substantial portions of the Software. +0044 if isfield(data.results,'lcurve') +0045 data.results = rmfield(data.results,'lcurve'); +0046 end +0047 end +0048 +0049 return +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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0066 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0067 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0068 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0069 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0070 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0071 % SOFTWARE. +0065 % The above copyright notice and this permission notice shall be included in all +0066 % copies or substantial portions of the Software. +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.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/removeSignalFromList.html b/doc/nucleus/functions/interface/removeSignalFromList.html index bfa5628..cf231a9 100644 --- a/doc/nucleus/functions/interface/removeSignalFromList.html +++ b/doc/nucleus/functions/interface/removeSignalFromList.html @@ -118,72 +118,81 @@

    SOURCE CODE ^% empty all axes -0053 clearAllAxes(fig); -0054 -0055 % update the listbox entries -0056 shownames = data.import.NMR.filesShort; -0057 set(gui.listbox_handles.signal,'String',shownames); -0058 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); -0059 -0060 % color the list entries that already have an inversion result -0061 strL = get(gui.listbox_handles.signal,'String'); -0062 for i = 1:size(INVdata,1) -0063 if isstruct(INVdata{i}) -0064 str1 = strL{i}; -0065 str2 = ['<HTML><BODY bgcolor="rgb(',... -0066 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',... -0067 str1,'</BODY></HTML>']; -0068 strL{i} = str2; -0069 end -0070 end -0071 set(gui.listbox_handles.signal,'String',strL); -0072 -0073 % if there are as many CPS data points as NMR files remove the -0074 % corresponding CPS point as well -0075 ntable = size(data.pressure.table,1); -0076 if nINVdata == ntable -0077 data.pressure.table(id,:) = []; -0078 end -0079 -0080 else -0081 % if there is no data to sort throw a help dialog -0082 helpdlg('Nothing to do because there is no data loaded!',... -0083 'removeSignalFromList: Load NMR data first.'); -0084 end -0085 -0086 % update GUI data and interface -0087 setappdata(fig,'data',data); -0088 setappdata(fig,'INVdata',INVdata); -0089 NUCLEUSinv_updateInterface; -0090 -0091 end -0092 -0093 %------------- END OF CODE -------------- +0051 +0052 % take care of possible 2D data +0053 if isfield(data.import,'T1T2map') +0054 data.import.T1T2map.t_recov(id) = []; +0055 data.import.NMR.data{end}.time(id) = []; +0056 data.import.NMR.data{end}.signal(id) = []; +0057 data.import.NMR.data{end}.raw.time(id) = []; +0058 data.import.NMR.data{end}.raw.signal(id) = []; +0059 end +0060 +0061 % empty all axes +0062 clearAllAxes(fig); +0063 +0064 % update the listbox entries +0065 shownames = data.import.NMR.filesShort; +0066 set(gui.listbox_handles.signal,'String',shownames); +0067 set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); +0068 +0069 % color the list entries that already have an inversion result +0070 strL = get(gui.listbox_handles.signal,'String'); +0071 for i = 1:size(INVdata,1) +0072 if isstruct(INVdata{i}) +0073 str1 = strL{i}; +0074 str2 = ['<HTML><BODY bgcolor="rgb(',... +0075 sprintf('%d,%d,%d',gui.myui.colors.listINV.*255),')">',... +0076 str1,'</BODY></HTML>']; +0077 strL{i} = str2; +0078 end +0079 end +0080 set(gui.listbox_handles.signal,'String',strL); +0081 +0082 % if there are as many CPS data points as NMR files remove the +0083 % corresponding CPS point as well +0084 ntable = size(data.pressure.table,1); +0085 if nINVdata == ntable +0086 data.pressure.table(id,:) = []; +0087 end +0088 +0089 else +0090 % if there is no data to sort throw a help dialog +0091 helpdlg('Nothing to do because there is no data loaded!',... +0092 'removeSignalFromList: Load NMR data first.'); +0093 end 0094 -0095 %% License: -0096 % MIT License -0097 % -0098 % Copyright (c) 2018 Thomas Hiller -0099 % -0100 % Permission is hereby granted, free of charge, to any person obtaining a copy -0101 % of this software and associated documentation files (the "Software"), to deal -0102 % in the Software without restriction, including without limitation the rights -0103 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0104 % copies of the Software, and to permit persons to whom the Software is -0105 % furnished to do so, subject to the following conditions: +0095 % update GUI data and interface +0096 setappdata(fig,'data',data); +0097 setappdata(fig,'INVdata',INVdata); +0098 NUCLEUSinv_updateInterface; +0099 +0100 end +0101 +0102 %------------- END OF CODE -------------- +0103 +0104 %% License: +0105 % MIT License 0106 % -0107 % The above copyright notice and this permission notice shall be included in all -0108 % copies or substantial portions of the Software. -0109 % -0110 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0111 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0112 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0113 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0114 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0115 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0116 % SOFTWARE. +0107 % Copyright (c) 2018 Thomas Hiller +0108 % +0109 % Permission is hereby granted, free of charge, to any person obtaining a copy +0110 % of this software and associated documentation files (the "Software"), to deal +0111 % in the Software without restriction, including without limitation the rights +0112 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0113 % copies of the Software, and to permit persons to whom the Software is +0114 % furnished to do so, subject to the following conditions: +0115 % +0116 % The above copyright notice and this permission notice shall be included in all +0117 % copies or substantial portions of the Software. +0118 % +0119 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0120 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0121 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0122 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0123 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0124 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0125 % 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 fad0e7f..63c3b9b 100644 --- a/doc/nucleus/functions/interface/runInversionBatch.html +++ b/doc/nucleus/functions/interface/runInversionBatch.html @@ -333,73 +333,74 @@

    SOURCE CODE ^'processing ...',num2str(id),... 0256 ' / ',num2str(steps),' NMR signals']); 0257 else -0258 % otherwise only update every 25 signals +0258 % otherwise only show 25 increments of the waitbar 0259 % NOTE: Matlab's wait-bar SLOWS DOWN the calculation 0260 % MASSIVELY -0261 if id == 1 || mod(id,25) == 0 -0262 waitbar(id / steps,hwb,['processing ...',num2str(id),... -0263 ' / ',num2str(steps),' NMR signals']); -0264 end -0265 end -0266 end -0267 else -0268 displayStatusText(gui,[infostring,' was canceled']); -0269 % remove temporary data fields -0270 data = removeInversionFields(data); -0271 % remove data from fields not processed -0272 INVdata{id} = []; -0273 end -0274 end % id = 1:size(INVdata,1) -0275 -0276 % delete wait-bar -0277 if wbopts.show -0278 delete(hwb); -0279 end -0280 if get(gui.push_handles.invstd_run,'UserData') == 1 % STOP was not pressed -0281 displayStatusText(gui,[infostring,'done']); -0282 end -0283 -0284 % update INVdata to GUI -0285 setappdata(fig,'INVdata',INVdata); -0286 % make the STOP button a RUN again -0287 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... -0288 'BackgroundColor','g','Callback',@onPushRun); -0289 % update GUI data -0290 setappdata(fig,'gui',gui); -0291 % set focus on the first entry in the list -0292 set(gui.listbox_handles.signal,'Value',1); -0293 onListboxData(gui.listbox_handles.signal); -0294 else -0295 helpdlg('Nothing to do because there is no data loaded!',... -0296 'runInversioBatch: Load NMR data first.'); -0297 end -0298 -0299 end -0300 -0301 %------------- END OF CODE -------------- -0302 -0303 %% License: -0304 % MIT License -0305 % -0306 % Copyright (c) 2018 Thomas Hiller -0307 % -0308 % Permission is hereby granted, free of charge, to any person obtaining a copy -0309 % of this software and associated documentation files (the "Software"), to deal -0310 % in the Software without restriction, including without limitation the rights -0311 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0312 % copies of the Software, and to permit persons to whom the Software is -0313 % furnished to do so, subject to the following conditions: -0314 % -0315 % The above copyright notice and this permission notice shall be included in all -0316 % copies or substantial portions of the Software. -0317 % -0318 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0319 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0320 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0321 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0322 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0323 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0324 % SOFTWARE. +0261 my_mod = round(size(INVdata,1)/25); +0262 if id == 1 || mod(id,my_mod) == 0 +0263 waitbar(id / steps,hwb,['processing ...',num2str(id),... +0264 ' / ',num2str(steps),' NMR signals']); +0265 end +0266 end +0267 end +0268 else +0269 displayStatusText(gui,[infostring,' was canceled']); +0270 % remove temporary data fields +0271 data = removeInversionFields(data); +0272 % remove data from fields not processed +0273 INVdata{id} = []; +0274 end +0275 end % id = 1:size(INVdata,1) +0276 +0277 % delete wait-bar +0278 if wbopts.show +0279 delete(hwb); +0280 end +0281 if get(gui.push_handles.invstd_run,'UserData') == 1 % STOP was not pressed +0282 displayStatusText(gui,[infostring,'done']); +0283 end +0284 +0285 % update INVdata to GUI +0286 setappdata(fig,'INVdata',INVdata); +0287 % make the STOP button a RUN again +0288 set(gui.push_handles.invstd_run,'String','<HTML><u>R</u>UN',... +0289 'BackgroundColor','g','Callback',@onPushRun); +0290 % update GUI data +0291 setappdata(fig,'gui',gui); +0292 % set focus on the first entry in the list +0293 set(gui.listbox_handles.signal,'Value',1); +0294 onListboxData(gui.listbox_handles.signal); +0295 else +0296 helpdlg('Nothing to do because there is no data loaded!',... +0297 'runInversioBatch: Load NMR data first.'); +0298 end +0299 +0300 end +0301 +0302 %------------- END OF CODE -------------- +0303 +0304 %% License: +0305 % MIT License +0306 % +0307 % Copyright (c) 2018 Thomas Hiller +0308 % +0309 % Permission is hereby granted, free of charge, to any person obtaining a copy +0310 % of this software and associated documentation files (the "Software"), to deal +0311 % in the Software without restriction, including without limitation the rights +0312 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0313 % copies of the Software, and to permit persons to whom the Software is +0314 % furnished to do so, subject to the following conditions: +0315 % +0316 % The above copyright notice and this permission notice shall be included in all +0317 % copies or substantial portions of the Software. +0318 % +0319 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0320 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0321 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0322 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0323 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0324 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0325 % 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 5a6bec6..ac9c12e 100644 --- a/doc/nucleus/functions/interface/runInversionStd.html +++ b/doc/nucleus/functions/interface/runInversionStd.html @@ -279,263 +279,264 @@

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

    SOURCE CODE ^'on'); 0226 switch data.invstd.invtype 0227 case 'mono' -0228 errorbar(xval,E0,E0_er,'o','Color',col.FIT,'Parent',ax1,... -0229 'DisplayName','E0'); -0230 case 'free' -0231 errorbar(xval,E0,E0_er,'o','Color',col.FIT,'Parent',ax1,... -0232 'LineWidth',1.5,'DisplayName','E0'); -0233 for i = 1:size(Ex,2) -0234 errorbar(xval,Ex(:,i),E0_er(:,1),'o','Color',mycols(i,:),... -0235 'DisplayName',['Ex',num2str(i)],'Parent',ax1); -0236 end -0237 case 'MUMO' -0238 if hasUncert -0239 errorbar(xval,E0_init,[],'o','Color',col.FIT,... -0240 'DisplayName','E0(init)','Parent',ax1); -0241 errorbar(xval,E0,E0_er,'ko','DisplayName','E0(uncert)',... -0242 'LineWidth',1.5,'Parent',ax1); -0243 else -0244 plot(xval,E0,'o','Color',col.FIT,'Parent',ax1,... -0245 'DisplayName','E0'); -0246 end -0247 for i = 1:size(Ex,2) -0248 errorbar(xval,Ex(:,i),Ex_er(:,1),'o','Color',mycols(i,:),... -0249 'DisplayName',['Ex',num2str(i)],'Parent',ax1); -0250 end -0251 otherwise -0252 if hasUncert -0253 errorbar(xval,E0_init,[],'o','Color',col.FIT,'DisplayName','E0(init)',... -0254 'Parent',ax1); -0255 errorbar(xval,E0,E0_er,'ko','DisplayName','E0(uncert)',... -0256 'LineWidth',1.5,'Parent',ax1); -0257 else -0258 plot(xval,E0,'o','Color',col.FIT,'DisplayName','E0',... -0259 'Parent',ax1); -0260 end -0261 end -0262 ylims = [min([0 min(E0)*0.9 min(Ex)*0.9]) max(E0)*1.1]; -0263 grid(ax1,'on'); -0264 set(get(ax1,'YLabel'),'String','E0'); -0265 set(ax1,'YLim',ylims); -0266 legend(ax1,'Location','SouthWest'); -0267 -0268 % T relaxation times -0269 hold(ax2,'on'); -0270 switch data.invstd.invtype -0271 case 'mono' -0272 errorbar(xval,T,T_er,'o','Color',col.FIT,'DisplayName','T0','Parent',ax2); -0273 set(get(ax2,'YLabel'),'String',['T [',timescale,']']); -0274 case 'free' -0275 for i = 1:size(Tx,2) -0276 errorbar(xval,Tx(:,i),Tx_er(:,i),'o','Color',mycols(i,:),... -0277 'DisplayName',['Tx',num2str(i)],'Parent',ax2); -0278 end -0279 set(get(ax2,'YLabel'),'String',['T_x [',timescale,']']); -0280 set(ax2,'YScale','log'); -0281 case 'MUMO' -0282 if hasUncert -0283 errorbar(xval,T_init,[],'o','Color',col.FIT,... -0284 'DisplayName','Tlgm(init)','Parent',ax2); -0285 errorbar(xval,T,T_er,'ko','LineWidth',1.5,... -0286 'DisplayName','Tlgm(uncert)','Parent',ax2); -0287 else -0288 plot(xval,T,'o','Color',col.FIT,... -0289 'DisplayName','Tlgm','Parent',ax2); -0290 end -0291 for i = 1:size(Tx,2) -0292 errorbar(xval,Tx(:,i),Tx_er(:,i),'o','Color',mycols(i,:),... -0293 'DisplayName',['Tx',num2str(i)],'Parent',ax2); +0228 % init dummy Ex (for plotting) +0229 Ex = E0; +0230 errorbar(xval,E0,E0_er,'o','Color',col.FIT,'Parent',ax1,... +0231 'DisplayName','E0'); +0232 case 'free' +0233 errorbar(xval,E0,E0_er,'o','Color',col.FIT,'Parent',ax1,... +0234 'LineWidth',1.5,'DisplayName','E0'); +0235 for i = 1:size(Ex,2) +0236 errorbar(xval,Ex(:,i),E0_er(:,1),'o','Color',mycols(i,:),... +0237 'DisplayName',['Ex',num2str(i)],'Parent',ax1); +0238 end +0239 case 'MUMO' +0240 if hasUncert +0241 errorbar(xval,E0_init,[],'o','Color',col.FIT,... +0242 'DisplayName','E0(init)','Parent',ax1); +0243 errorbar(xval,E0,E0_er,'ko','DisplayName','E0(uncert)',... +0244 'LineWidth',1.5,'Parent',ax1); +0245 else +0246 plot(xval,E0,'o','Color',col.FIT,'Parent',ax1,... +0247 'DisplayName','E0'); +0248 end +0249 for i = 1:size(Ex,2) +0250 errorbar(xval,Ex(:,i),Ex_er(:,1),'o','Color',mycols(i,:),... +0251 'DisplayName',['Ex',num2str(i)],'Parent',ax1); +0252 end +0253 otherwise +0254 if hasUncert +0255 errorbar(xval,E0_init,[],'o','Color',col.FIT,'DisplayName','E0(init)',... +0256 'Parent',ax1); +0257 errorbar(xval,E0,E0_er,'ko','DisplayName','E0(uncert)',... +0258 'LineWidth',1.5,'Parent',ax1); +0259 else +0260 plot(xval,E0,'o','Color',col.FIT,'DisplayName','E0',... +0261 'Parent',ax1); +0262 end +0263 end +0264 ylims = [min([0 min(E0)*0.9 min(Ex)*0.9]) max(E0)*1.1]; +0265 grid(ax1,'on'); +0266 set(get(ax1,'YLabel'),'String','E0'); +0267 set(ax1,'YLim',ylims); +0268 legend(ax1,'Location','SouthWest'); +0269 +0270 % T relaxation times +0271 hold(ax2,'on'); +0272 switch data.invstd.invtype +0273 case 'mono' +0274 % init dummy Tx (for plotting) +0275 Tx = T; +0276 errorbar(xval,T,T_er,'o','Color',col.FIT,'DisplayName','T0','Parent',ax2); +0277 set(get(ax2,'YLabel'),'String',['T [',timescale,']']); +0278 case 'free' +0279 for i = 1:size(Tx,2) +0280 errorbar(xval,Tx(:,i),Tx_er(:,i),'o','Color',mycols(i,:),... +0281 'DisplayName',['Tx',num2str(i)],'Parent',ax2); +0282 end +0283 set(get(ax2,'YLabel'),'String',['T_x [',timescale,']']); +0284 set(ax2,'YScale','log'); +0285 case 'MUMO' +0286 if hasUncert +0287 errorbar(xval,T_init,[],'o','Color',col.FIT,... +0288 'DisplayName','Tlgm(init)','Parent',ax2); +0289 errorbar(xval,T,T_er,'ko','LineWidth',1.5,... +0290 'DisplayName','Tlgm(uncert)','Parent',ax2); +0291 else +0292 plot(xval,T,'o','Color',col.FIT,... +0293 'DisplayName','Tlgm','Parent',ax2); 0294 end -0295 set(get(ax2,'YLabel'),'String',['T_x [',timescale,']']); -0296 set(ax2,'YScale','log'); -0297 otherwise -0298 if hasUncert -0299 errorbar(xval,T_init,[],'o','Color',col.FIT,... -0300 'DisplayName','Tlgm(init)','Parent',ax2); -0301 errorbar(xval,T,T_er,'ko','DisplayName','Tlgm(uncert)',... -0302 'LineWidth',1.5,'Parent',ax2); -0303 else -0304 for i = 1:size(T,2) -0305 plot(xval,T(:,i),'o','Color',col.FIT,... -0306 'DisplayName','Tlgm','Parent',ax2); -0307 end -0308 end -0309 set(get(ax2,'YLabel'),'String',['TLGM [',timescale,']']); -0310 end -0311 ylims = [min([0 min(T)*0.9 min(Tx)*0.9]) max([max(T) max(Tx)])*1.1]; -0312 grid(ax2,'on'); -0313 set(ax2,'YLim',ylims); -0314 legend(ax2,'Location','SouthWest'); -0315 -0316 % signal-to-noise-ratio SNR -0317 hold(ax3,'on'); -0318 plot(xval,SNR,'o','Color',col.FIT,'LineWidth',1.5,'Parent',ax3); -0319 grid on; -0320 xlabel(xlabelstr); -0321 set(get(ax3,'YLabel'),'String','signal-to-noise ratio'); -0322 -0323 % link axes for combined zooming and panning -0324 linkaxes([ax1 ax2 ax3], 'x'); -0325 -0326 % make nice date ticks -0327 if strcmp(xlabelstr,'date') -0328 isfile = which('dynamicDateTicks'); -0329 if ~isempty(isfile) -0330 dynamicDateTicks([ax1 ax2 ax3],'link','dd.mm. HH:MM'); -0331 else -0332 datetick(ax1,'x','dd.mm. HH:MM','keepticks'); -0333 datetick(ax2,'x','dd.mm. HH:MM','keepticks'); -0334 datetick(ax3,'x','dd.mm. HH:MM','keepticks'); -0335 end -0336 end -0337 -0338 case 'ampvst' -0339 f = figure; -0340 ax1 = axes('Parent',f); +0295 for i = 1:size(Tx,2) +0296 errorbar(xval,Tx(:,i),Tx_er(:,i),'o','Color',mycols(i,:),... +0297 'DisplayName',['Tx',num2str(i)],'Parent',ax2); +0298 end +0299 set(get(ax2,'YLabel'),'String',['T_x [',timescale,']']); +0300 set(ax2,'YScale','log'); +0301 otherwise +0302 if hasUncert +0303 errorbar(xval,T_init,[],'o','Color',col.FIT,... +0304 'DisplayName','Tlgm(init)','Parent',ax2); +0305 errorbar(xval,T,T_er,'ko','DisplayName','Tlgm(uncert)',... +0306 'LineWidth',1.5,'Parent',ax2); +0307 else +0308 for i = 1:size(T,2) +0309 plot(xval,T(:,i),'o','Color',col.FIT,... +0310 'DisplayName','Tlgm','Parent',ax2); +0311 end +0312 end +0313 set(get(ax2,'YLabel'),'String',['TLGM [',timescale,']']); +0314 end +0315 ylims = [min([0 min(T)*0.9 min(Tx)*0.9]) max([max(T) max(Tx)])*1.1]; +0316 grid(ax2,'on'); +0317 set(ax2,'YLim',ylims); +0318 legend(ax2,'Location','SouthWest'); +0319 +0320 % signal-to-noise-ratio SNR +0321 hold(ax3,'on'); +0322 plot(xval,SNR,'o','Color',col.FIT,'LineWidth',1.5,'Parent',ax3); +0323 grid on; +0324 xlabel(xlabelstr); +0325 set(get(ax3,'YLabel'),'String','signal-to-noise ratio'); +0326 +0327 % link axes for combined zooming and panning +0328 linkaxes([ax1 ax2 ax3], 'x'); +0329 +0330 % make nice date ticks +0331 if strcmp(xlabelstr,'date') +0332 isfile = which('dynamicDateTicks'); +0333 if ~isempty(isfile) +0334 dynamicDateTicks([ax1 ax2 ax3],'link','dd.mm. HH:MM'); +0335 else +0336 datetick(ax1,'x','dd.mm. HH:MM','keepticks'); +0337 datetick(ax2,'x','dd.mm. HH:MM','keepticks'); +0338 datetick(ax3,'x','dd.mm. HH:MM','keepticks'); +0339 end +0340 end 0341 -0342 plot(E0,T,'ko','Parent',ax1), -0343 set(get(ax1,'XLabel'),'String','E0'); -0344 set(get(ax1,'YLabel'),'String',['T [',timescale,']']); +0342 case 'ampvst' +0343 f = figure; +0344 ax1 = axes('Parent',f); 0345 -0346 case 'rtd' -0347 switch data.invstd.invtype -0348 case {'LU','NNLS','MUMO'} -0349 if strcmp(xlabelstr,'date') -0350 mycol = jet(size(Tspec,1)); -0351 [time,ix] = sort(xval); -0352 Tspec = Tspec(ix,:); -0353 f = figure; -0354 ax = axes('Parent',f); -0355 hold(ax,'on') -0356 for i = 1:size(Tspec,1) -0357 plot3(time(i)*ones(size(Tt)),Tt,Tspec(i,:),... -0358 'Color',mycol(i,:),'Parent',ax); -0359 end -0360 grid on; box on; -0361 xlabel('date'); -0362 ylabel(['relaxation time [',timescale,']']); -0363 zlabel('amplitude [-]'); -0364 -0365 set(ax,'YScale','log'); -0366 isfile = which('dynamicDateTicks'); -0367 if ~isempty(isfile) -0368 dynamicDateTicks(ax,'dd.mm. HH:MM'); -0369 else -0370 datetick(ax,'x','dd.mm. HH:MM','keepticks'); -0371 end -0372 view([90 0]); -0373 else -0374 dx = xval(2)-xval(1); -0375 [xx,yy] = meshgrid(Tt',[xval-dx/2; xval(end)+dx/2]); -0376 f = figure; -0377 ax = axes('Parent',f); -0378 hold(ax,'on') -0379 -0380 % remove the backgound file -0381 Tspec(isnan(Tspec)) = []; -0382 xi = numel(Tspec)/numel(Tt); -0383 Tspec = reshape(Tspec,[xi numel(Tt)]); -0384 -0385 surf(xx,yy,zeros(size(xx)),Tspec./max(Tspec(:)),'Parent',ax); -0386 shading(ax,'flat'); -0387 xticks = log10(min(Tt)):1:log10(max(Tt)); -0388 set(ax,'XScale','log','XLim',[10^xticks(1) 10^xticks(end)],... -0389 'XTick',10.^xticks,'Layer','top','Box','on'); -0390 set(ax,'YLim',[min(yy(:)) max(yy(:))],'YDir','normal') -0391 cmap = jet; cmap = flipud(cmap); -0392 colormap(ax,cmap); -0393 xlabel(['relaxation time [',timescale,']']); -0394 ylabel(ylabelstr); -0395 cb = colorbar; -0396 set(get(cb,'YLabel'),'String','norm. amplitude'); -0397 -0398 % context menu to flip y-axis direction -0399 axes_cm = uicontextmenu(f); -0400 gui.cm_handles.axes_proc_xaxis = uimenu(axes_cm,... -0401 'Label','flip y-axis','Tag','flip','Enable','on',... -0402 'Callback',@onContextFlip); -0403 gui.cm_handles.axes_proc_xaxis2 = uimenu(axes_cm,... -0404 'Label','color scale log/lin','Tag','loglin','Enable','on',... -0405 'Callback',@onContextFlip); -0406 set(ax,'UIContextMenu',axes_cm); -0407 -0408 end -0409 otherwise -0410 helpdlg({'function: showExtraGraphics',... -0411 'Cannot plot RTDs because the inversion was not multi exponential'},... -0412 'Invert NMR data first.'); -0413 end -0414 end -0415 -0416 catch ME -0417 % show error message in case import fails -0418 errmsg = {ME.message;[ME.stack(1).name,' Line: ',num2str(ME.stack(1).line)];... -0419 'Cannot show figure.'}; -0420 errordlg(errmsg,'showExtraGraphics: Error!'); -0421 end -0422 else -0423 helpdlg({'function: showExtraGraphics',... -0424 'Cannot continue because there need to be at least two NMR measurements.'},... -0425 'Not enough data to show'); -0426 end -0427 -0428 end -0429 -0430 function onContextFlip(src,~) -0431 f = ancestor(src,'Figure','toplevel'); -0432 ax = findobj(f,'Type','Axes'); -0433 tag = get(src,'Tag'); -0434 -0435 switch tag -0436 case 'loglin' -0437 isscale = get(ax,'ColorScale'); -0438 switch isscale -0439 case 'log' -0440 set(ax,'ColorScale','lin','CLim',[0 1]); -0441 case 'linear' -0442 set(ax,'ColorScale','log','CLim',[0.01 1]); -0443 end -0444 case 'flip' -0445 direction = get(ax,'Ydir'); -0446 switch direction -0447 case 'normal' -0448 set(ax,'Ydir','reverse') -0449 case 'reverse' -0450 set(ax,'Ydir','normal') -0451 end -0452 end -0453 -0454 end -0455 -0456 %------------- END OF CODE -------------- +0346 plot(E0,T,'ko','Parent',ax1), +0347 set(get(ax1,'XLabel'),'String','E0'); +0348 set(get(ax1,'YLabel'),'String',['T [',timescale,']']); +0349 +0350 case 'rtd' +0351 switch data.invstd.invtype +0352 case {'LU','NNLS','MUMO'} +0353 if strcmp(xlabelstr,'date') +0354 mycol = jet(size(Tspec,1)); +0355 [time,ix] = sort(xval); +0356 Tspec = Tspec(ix,:); +0357 f = figure; +0358 ax = axes('Parent',f); +0359 hold(ax,'on') +0360 for i = 1:size(Tspec,1) +0361 plot3(time(i)*ones(size(Tt)),Tt,Tspec(i,:),... +0362 'Color',mycol(i,:),'Parent',ax); +0363 end +0364 grid on; box on; +0365 xlabel('date'); +0366 ylabel(['relaxation time [',timescale,']']); +0367 zlabel('amplitude [-]'); +0368 +0369 set(ax,'YScale','log'); +0370 isfile = which('dynamicDateTicks'); +0371 if ~isempty(isfile) +0372 dynamicDateTicks(ax,'dd.mm. HH:MM'); +0373 else +0374 datetick(ax,'x','dd.mm. HH:MM','keepticks'); +0375 end +0376 view([90 0]); +0377 else +0378 dx = xval(2)-xval(1); +0379 [xx,yy] = meshgrid(Tt',[xval-dx/2; xval(end)+dx/2]); +0380 f = figure; +0381 ax = axes('Parent',f); +0382 hold(ax,'on') +0383 +0384 % remove the backgound file +0385 Tspec(isnan(Tspec)) = []; +0386 xi = numel(Tspec)/numel(Tt); +0387 Tspec = reshape(Tspec,[xi numel(Tt)]); +0388 +0389 surf(xx,yy,zeros(size(xx)),Tspec./max(Tspec(:)),'Parent',ax); +0390 shading(ax,'flat'); +0391 xticks = log10(min(Tt)):1:log10(max(Tt)); +0392 set(ax,'XScale','log','XLim',[10^xticks(1) 10^xticks(end)],... +0393 'XTick',10.^xticks,'Layer','top','Box','on'); +0394 set(ax,'YLim',[min(yy(:)) max(yy(:))],'YDir','normal') +0395 cmap = jet; cmap = flipud(cmap); +0396 colormap(ax,cmap); +0397 xlabel(['relaxation time [',timescale,']']); +0398 ylabel(ylabelstr); +0399 cb = colorbar; +0400 set(get(cb,'YLabel'),'String','norm. amplitude'); +0401 +0402 % context menu to flip y-axis direction +0403 axes_cm = uicontextmenu(f); +0404 gui.cm_handles.axes_proc_xaxis = uimenu(axes_cm,... +0405 'Label','flip y-axis','Tag','flip','Enable','on',... +0406 'Callback',@onContextFlip); +0407 gui.cm_handles.axes_proc_xaxis2 = uimenu(axes_cm,... +0408 'Label','color scale log/lin','Tag','loglin','Enable','on',... +0409 'Callback',@onContextFlip); +0410 set(ax,'UIContextMenu',axes_cm); +0411 +0412 end +0413 otherwise +0414 helpdlg({'function: showExtraGraphics',... +0415 'Cannot plot RTDs because the inversion was not multi exponential'},... +0416 'Invert NMR data first.'); +0417 end +0418 end +0419 +0420 catch ME +0421 % show error message in case import fails +0422 errmsg = {ME.message;[ME.stack(1).name,' Line: ',num2str(ME.stack(1).line)];... +0423 'Cannot show figure.'}; +0424 errordlg(errmsg,'showExtraGraphics: Error!'); +0425 end +0426 else +0427 helpdlg({'function: showExtraGraphics',... +0428 'Cannot continue because there need to be at least two NMR measurements.'},... +0429 'Not enough data to show'); +0430 end +0431 +0432 end +0433 +0434 function onContextFlip(src,~) +0435 f = ancestor(src,'Figure','toplevel'); +0436 ax = findobj(f,'Type','Axes'); +0437 tag = get(src,'Tag'); +0438 +0439 switch tag +0440 case 'loglin' +0441 isscale = get(ax,'ColorScale'); +0442 switch isscale +0443 case 'log' +0444 set(ax,'ColorScale','lin','CLim',[0 1]); +0445 case 'linear' +0446 set(ax,'ColorScale','log','CLim',[0.01 1]); +0447 end +0448 case 'flip' +0449 direction = get(ax,'Ydir'); +0450 switch direction +0451 case 'normal' +0452 set(ax,'Ydir','reverse') +0453 case 'reverse' +0454 set(ax,'Ydir','normal') +0455 end +0456 end 0457 -0458 %% License: -0459 % MIT License -0460 % -0461 % Copyright (c) 2018 Thomas Hiller -0462 % -0463 % Permission is hereby granted, free of charge, to any person obtaining a copy -0464 % of this software and associated documentation files (the "Software"), to deal -0465 % in the Software without restriction, including without limitation the rights -0466 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0467 % copies of the Software, and to permit persons to whom the Software is -0468 % furnished to do so, subject to the following conditions: -0469 % -0470 % The above copyright notice and this permission notice shall be included in all -0471 % copies or substantial portions of the Software. -0472 % -0473 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0474 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0475 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0476 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0477 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0478 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0479 % SOFTWARE. +0458 end +0459 +0460 %------------- END OF CODE -------------- +0461 +0462 %% License: +0463 % MIT License +0464 % +0465 % Copyright (c) 2018 Thomas Hiller +0466 % +0467 % Permission is hereby granted, free of charge, to any person obtaining a copy +0468 % of this software and associated documentation files (the "Software"), to deal +0469 % in the Software without restriction, including without limitation the rights +0470 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0471 % copies of the Software, and to permit persons to whom the Software is +0472 % furnished to do so, subject to the following conditions: +0473 % +0474 % The above copyright notice and this permission notice shall be included in all +0475 % copies or substantial portions of the Software. +0476 % +0477 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0478 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0479 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0480 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0481 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0482 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0483 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/uncheckImportMenus.html b/doc/nucleus/functions/interface/uncheckImportMenus.html index bdcb707..e2ccbe6 100644 --- a/doc/nucleus/functions/interface/uncheckImportMenus.html +++ b/doc/nucleus/functions/interface/uncheckImportMenus.html @@ -120,43 +120,48 @@

    SOURCE CODE ^'Checked','off'); 0052 set(gui.menu.file_import_lab_bgr_helios_series,'Checked','off'); 0053 set(gui.menu.file_import_lab_bam_tom,'Checked','off'); -0054 set(gui.menu.file_import_lab_ascii_T1,'Checked','off'); -0055 set(gui.menu.file_import_lab_ascii_T2,'Checked','off'); -0056 set(gui.menu.file_import_lab_excel_T1,'Checked','off'); -0057 set(gui.menu.file_import_lab_excel_T2,'Checked','off'); -0058 set(gui.menu.file_import_nmrinv_file,'Checked','off'); -0059 set(gui.menu.file_import_nmrmod_file,'Checked','off'); -0060 set(gui.menu.file_import_nmrmod_gui,'Checked','off'); -0061 -0062 % update GUI data -0063 setappdata(fig,'gui',gui); -0064 -0065 end +0054 set(gui.menu.file_import_lab_aarhus_dartT1T2,'Checked','off'); +0055 set(gui.menu.file_import_lab_aarhus_dartT2,'Checked','off'); +0056 set(gui.menu.file_import_lab_rutgers_T1T2,'Checked','off'); +0057 set(gui.menu.file_import_lab_ascii_T1,'Checked','off'); +0058 set(gui.menu.file_import_lab_ascii_T2,'Checked','off'); +0059 set(gui.menu.file_import_lab_excel_T1,'Checked','off'); +0060 set(gui.menu.file_import_lab_excel_T2,'Checked','off'); +0061 set(gui.menu.file_import_lab_dart,'Checked','off'); +0062 set(gui.menu.file_import_lab_dartburst,'Checked','off'); +0063 set(gui.menu.file_import_nmrinv_file,'Checked','off'); +0064 set(gui.menu.file_import_nmrmod_file,'Checked','off'); +0065 set(gui.menu.file_import_nmrmod_gui,'Checked','off'); 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. +0067 % update GUI data +0068 setappdata(fig,'gui',gui); +0069 +0070 end +0071 +0072 %------------- END OF CODE -------------- +0073 +0074 %% License: +0075 % MIT License +0076 % +0077 % Copyright (c) 2018 Thomas Hiller +0078 % +0079 % Permission is hereby granted, free of charge, to any person obtaining a copy +0080 % of this software and associated documentation files (the "Software"), to deal +0081 % in the Software without restriction, including without limitation the rights +0082 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0083 % copies of the Software, and to permit persons to whom the Software is +0084 % furnished to do so, subject to the following conditions: +0085 % +0086 % The above copyright notice and this permission notice shall be included in all +0087 % copies or substantial portions of the Software. +0088 % +0089 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0090 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0091 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0092 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0093 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0094 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0095 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/updateInfo.html b/doc/nucleus/functions/interface/updateInfo.html index 1474f4a..9bb215f 100644 --- a/doc/nucleus/functions/interface/updateInfo.html +++ b/doc/nucleus/functions/interface/updateInfo.html @@ -403,274 +403,278 @@

    SOURCE CODE ^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' +0337 % check for 2D data +0338 is1D = true; +0339 if isfield(data.results,'inv2D') +0340 is1D = false; +0341 end +0342 if is1D && isfield(data.results,'invstd') +0343 nmrproc = data.results.nmrproc; +0344 invstd = data.results.invstd; +0345 invtype = data.invstd.invtype; +0346 hasUncert = false; +0347 if isfield(invstd,'uncert') +0348 hasUncert = true; +0349 uncert = invstd.uncert; +0350 end +0351 +0352 switch invtype +0353 case 'mono' +0354 info{end+1,1} = invtype; +0355 info{end+1,1} = ' '; +0356 ciT = sum(full(invstd.ci(2:2:end))); +0357 +0358 if data.invstd.Tfixed_bool(1) +0359 col = gui.myui.colors.listINV.*255; +0360 else +0361 col = [1 1 1].*255; +0362 end +0363 +0364 switch nmrproc.T1T2 +0365 case 'T1' 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),... +0367 sprintf('%d,%d,%d',col),')">T<sub><font size="',num2str(subfs),'">1</sub> = ',... +0368 sprintf('%5.3f',invstd.T1),... 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; +0370 case 'T2' +0371 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... +0372 sprintf('%d,%d,%d',col),')">T<sub><font size="',num2str(subfs),'">2</sub> = ',... +0373 sprintf('%5.3f',invstd.T2),... +0374 ' &#8723 (',sprintf('%5.3f',ciT),')','</BODY></HTML>']; +0375 end 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 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.statistics.Tlgm(1)),... -0416 ' &#8723 (',sprintf('%5.3f',2*uncert.statistics.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.statistics.Tlgm(1)),... -0454 ' &#8723 (',sprintf('%5.3f',2*uncert.statistics.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} = ' '; +0378 case 'free' +0379 str = [invtype,' ',num2str(data.invstd.freeDT)]; +0380 info{end+1,1} = str; +0381 info{end+1,1} = ' '; +0382 +0383 E0 = invstd.E0; +0384 ciE0 = full(invstd.ci(1:2:end)); +0385 ciT = full(invstd.ci(2:2:end)); +0386 +0387 switch nmrproc.T1T2 +0388 case 'T1' +0389 T = invstd.T1; +0390 case 'T2' +0391 T = invstd.T2; +0392 end +0393 +0394 for i = 1:length(T) +0395 +0396 if data.invstd.Tfixed_bool(i) +0397 col = gui.myui.colors.listINV.*255; +0398 else +0399 col = [1 1 1].*255; +0400 end +0401 +0402 info{end+1,1} = ['<HTML><BODY bgcolor="rgb(',... +0403 sprintf('%d,%d,%d',col),')">T(',num2str(i),') = ',sprintf('%5.3f',T(i)),... +0404 ' &#8723 (',sprintf('%5.3f',ciT(i)),')','</BODY></HTML>']; %#ok<*AGROW> +0405 info{end+1,1} = ['<HTML><BODY>E(',num2str(i),') = ',sprintf('%5.3f',E0(i)),... +0406 ' &#8723 (',sprintf('%5.3f',ciE0(i)),')','</BODY></HTML>']; +0407 info{end+1,1} = ' '; +0408 end +0409 +0410 case {'LU','NNLS'} +0411 % info is a cell array +0412 str = [invtype,' ',data.invstd.regtype,' ',num2str(data.invstd.Lorder)]; +0413 info{end+1,1} = str; +0414 info{end+1,1} = ' '; +0415 +0416 % TLGM +0417 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0418 ')">TLGM</sub> = ',sprintf('%5.3f',invstd.Tlgm),'</BODY></HTML>']; +0419 if hasUncert +0420 info{end+1,1} = ['<HTML><BODY>TLGM</sub> = ',sprintf('%5.3f',uncert.statistics.Tlgm(1)),... +0421 ' &#8723 (',sprintf('%5.3f',2*uncert.statistics.Tlgm(2)),')','</BODY></HTML>']; +0422 end +0423 info{end+1,1} = ' '; +0424 +0425 % clay-bound water CBW < tcut ms +0426 % irreducible water / capillary water BVI ccut - tcut ms +0427 % movable water BVM > tcut ms +0428 switch data.process.timescale +0429 case 's' +0430 ccut = data.param.CBWcutoff/1000; +0431 tcut = data.param.BVIcutoff/1000; +0432 case 'ms' +0433 ccut = data.param.CBWcutoff; +0434 tcut = data.param.BVIcutoff; +0435 end +0436 por = data.invstd.porosity; +0437 CBW = abs(sum(invstd.T1T2f(invstd.T1T2me<=ccut))/sum(invstd.T1T2f)); +0438 BVI = abs(sum(invstd.T1T2f(invstd.T1T2me>ccut & invstd.T1T2me<=tcut))/sum(invstd.T1T2f)); +0439 BVM = abs(sum(invstd.T1T2f(invstd.T1T2me>tcut))/sum(invstd.T1T2f)); +0440 info{end+1,1} = ['CBW(',sprintf('%2d',data.param.CBWcutoff),... +0441 ') = ',sprintf('%5.2f',por*CBW*100),' [vol. %]']; +0442 +0443 info{end+1,1} = ['BVI(',sprintf('%2d',data.param.BVIcutoff),... +0444 ') = ',sprintf('%5.2f',por*BVI*100),' [vol. %]']; +0445 info{end+1,1} = ['BVM = ',sprintf('%5.2f',por*BVM*100),' [vol. %]']; +0446 +0447 case {'MUMO'} +0448 % info is a cell array +0449 str = [invtype,' ',num2str(data.invstd.freeDT)]; +0450 info{end+1,1} = str; +0451 info{end+1,1} = ' '; +0452 +0453 % TLGM +0454 info{end+1,1} = ['<HTML><BODY color="rgb(',sprintf('%d,%d,%d',gui.myui.colors.FIT.*255),... +0455 ')">TLGM</sub> = ',sprintf('%5.3f',invstd.Tlgm),'</BODY></HTML>']; +0456 if hasUncert +0457 info{end+1,1} = ['<HTML><BODY>TLGM</sub> = ',sprintf('%5.3f',uncert.statistics.Tlgm(1)),... +0458 ' &#8723 (',sprintf('%5.3f',2*uncert.statistics.Tlgm(2)),')','</BODY></HTML>']; +0459 end +0460 info{end+1,1} = ' '; +0461 +0462 % clay-bound water CBW < tcut ms +0463 % irreducible water / capillary water BVI ccut - tcut ms +0464 % movable water BVM > tcut ms +0465 switch data.process.timescale +0466 case 's' +0467 ccut = data.param.CBWcutoff/1000; +0468 tcut = data.param.BVIcutoff/1000; +0469 case 'ms' +0470 ccut = data.param.CBWcutoff; +0471 tcut = data.param.BVIcutoff; +0472 end +0473 por = data.invstd.porosity; +0474 CBW = abs(sum(invstd.T1T2f(invstd.T1T2me<=ccut))/sum(invstd.T1T2f)); +0475 BVI = abs(sum(invstd.T1T2f(invstd.T1T2me>ccut & invstd.T1T2me<=tcut))/sum(invstd.T1T2f)); +0476 BVM = abs(sum(invstd.T1T2f(invstd.T1T2me>tcut))/sum(invstd.T1T2f)); +0477 info{end+1,1} = ['CBW(',sprintf('%2d',data.param.CBWcutoff),... +0478 ') = ',sprintf('%5.2f',por*CBW*100),' [vol. %]']; +0479 +0480 info{end+1,1} = ['BVI(',sprintf('%2d',data.param.BVIcutoff),... +0481 ') = ',sprintf('%5.2f',por*BVI*100),' [vol. %]']; +0482 info{end+1,1} = ['BVM = ',sprintf('%5.2f',por*BVM*100),' [vol. %]']; +0483 info{end+1,1} = ' '; +0484 +0485 % values for T, sigma and amplitude +0486 T = invstd.T; ciT = invstd.ci(1:3:end); +0487 S = invstd.S; ciS = invstd.ci(2:3:end); +0488 E = invstd.E; ciE = invstd.ci(3:3:end); +0489 % transform ciT because it is in log scale +0490 tmpT = log(T)-ciT'; +0491 ciT = T - exp(tmpT); +0492 +0493 for i = 1:length(T) +0494 info{end+1,1} = ['<HTML><BODY>T(',num2str(i),') = ',sprintf('%5.3f',T(i)),... +0495 ' &#8723 (',sprintf('%5.3f',ciT(i)),')','</BODY></HTML>']; %#ok<*AGROW> +0496 info{end+1,1} = ['<HTML><BODY>S(',num2str(i),') = ',sprintf('%5.3f',S(i)),... +0497 ' &#8723 (',sprintf('%5.3f',ciS(i)),')','</BODY></HTML>']; +0498 info{end+1,1} = ['<HTML><BODY>E(',num2str(i),') = ',sprintf('%5.3f',E(i)),... +0499 ' &#8723 (',sprintf('%5.3f',ciE(i)),')','</BODY></HTML>']; +0500 info{end+1,1} = ' '; +0501 end +0502 end +0503 end +0504 end 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']; +0506 case 2 % PSD +0507 info{end+1,1} = 'PSD'; +0508 info{end+1,1} = ' '; +0509 +0510 case 3 % PSDJ +0511 if isfield(data,'results') +0512 if isfield(data.results,'invjoint') +0513 invjoint = data.results.invjoint; +0514 +0515 info{end+1,1} = ['Inversion type: ',data.invjoint.invtype]; +0516 info{end+1,1} = ' '; +0517 switch data.invjoint.geometry_type +0518 case 'cyl' +0519 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type]; +0520 info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; +0521 case 'ang' +0522 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,' ',... +0523 num2str(invjoint.iGEOM.angles(1)),' ',... +0524 num2str(invjoint.iGEOM.angles(2)),' ',... +0525 num2str(invjoint.iGEOM.angles(3))]; 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 -------------- +0527 case 'poly' +0528 info{end+1,1} = ['Shape: ',data.invjoint.geometry_type,... +0529 ' ',num2str(data.invjoint.polyN),' sides']; +0530 info{end+1,1} = ['Geom.: ',sprintf('%5.3f',invjoint.iGEOM.a)]; +0531 end +0532 info{end+1,1} = ' '; +0533 info{end+1,1} = ['rho (INV): ',sprintf('%5.3f',invjoint.irho*1e6),' [µm/s]']; +0534 if isfield(data.import,'NMRMOD') +0535 info{end+1,1} = ['rho (MOD): ',... +0536 sprintf('%5.3f',data.import.NMRMOD.nmr.rho*1e6),' [µm/s]']; +0537 end +0538 end +0539 end +0540 end +0541 % and update the text box +0542 set(gui.listbox_handles.info_dist,'String',info,'Value',[],'Max',2,'Min',0); +0543 +0544 %% CPS panel info +0545 % check if the CPS panel is maximized +0546 isminimized = get(gui.plots.CPSPanel,'Minimized'); +0547 if ~isminimized +0548 clear info; +0549 info{1,1} = ' '; +0550 if isfield(data,'results') +0551 if isfield(data.results,'invjoint') +0552 invjoint = data.results.invjoint; +0553 nmr = invjoint.idata.nmr; +0554 levels = invjoint.levels; +0555 +0556 for i = 1:numel(levels) +0557 info{end+1,1} = nmr{levels(i)}.name; +0558 info{end+1,1} = ['press. : ',... +0559 sprintf('%5.3f',invjoint.p0(levels(i))*data.pressure.unitfac),... +0560 ' [',data.pressure.unit,']']; +0561 switch invjoint.T1T2 +0562 case 'T1' +0563 info{end+1,1} = ['sat. (INV) : ',... +0564 sprintf('%5.3f',invjoint.idata.nmr{levels(i)}.fit_g(end))]; +0565 case 'T2' +0566 info{end+1,1} = ['sat. (INV) : ',... +0567 sprintf('%5.3f',invjoint.idata.nmr{levels(i)}.fit_g(1))]; +0568 end +0569 info{end+1,1} = ['sat. (MOD) : ',... +0570 sprintf('%5.3f',invjoint.S0(levels(i)))]; +0571 info{end+1,1} = ' '; +0572 end +0573 end +0574 end +0575 set(gui.listbox_handles.info_cps,'String',info,'Value',[],'Max',2,'Min',0); +0576 end +0577 +0578 % update GUI data +0579 setappdata(fig,'data',data); +0580 setappdata(fig,'gui',gui); +0581 end 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. +0583 end +0584 +0585 %------------- END OF CODE -------------- +0586 +0587 %% License: +0588 % MIT License +0589 % +0590 % Copyright (c) 2018 Thomas Hiller +0591 % +0592 % Permission is hereby granted, free of charge, to any person obtaining a copy +0593 % of this software and associated documentation files (the "Software"), to deal +0594 % in the Software without restriction, including without limitation the rights +0595 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0596 % copies of the Software, and to permit persons to whom the Software is +0597 % furnished to do so, subject to the following conditions: +0598 % +0599 % The above copyright notice and this permission notice shall be included in all +0600 % copies or substantial portions of the Software. +0601 % +0602 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0603 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0604 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0605 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0606 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0607 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0608 % 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 2e78625..7d26c5a 100644 --- a/doc/nucleus/functions/interface/updatePlotsDistribution.html +++ b/doc/nucleus/functions/interface/updatePlotsDistribution.html @@ -113,554 +113,561 @@

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

    SOURCE CODE ^end 0045 -0046 % default color -0047 col = gui.myui.colors.axisL; -0048 -0049 % RTD axis -0050 ax = gui.axes_handles.rtd; +0046 % check for 2D data +0047 is1D = true; +0048 if isfield(data,'results') && isfield(data.results,'inv2D') +0049 is1D = false; +0050 end 0051 -0052 if hasUncert -0053 % uncertainty RTD calculation range -0054 rtd_range = uncert.statistics.RTD_bounds; -0055 rtd_range0 = data.invstd.time; -0056 yy = get(ax,'YLim'); +0052 % default color +0053 col = gui.myui.colors.axisL; +0054 +0055 % RTD axis +0056 ax = gui.axes_handles.rtd; 0057 -0058 if rtd_range(1) > rtd_range0(1) -0059 line([rtd_range(1) rtd_range(1)],[yy(1) yy(2)],'Color',[0.25 0.25 0.25],... -0060 'LineStyle','-.','LineWidth',2,'Parent',ax,'Tag','infolines',... -0061 'HandleVisibility','off'); -0062 text(rtd_range(1), yy(2)*0.5,'uncert stat bounds','Color',[0.25 0.25 0.25],... -0063 'FontSize',12,'Rotation',90,'HorizontalAlignment','center',... -0064 'VerticalAlignment','bottom','Tag','infolines','Parent',ax); -0065 end -0066 -0067 if rtd_range(2) < rtd_range0(2) -0068 line([rtd_range(2) rtd_range(2)],[yy(1) yy(2)],'Color',[0.25 0.25 0.25],... -0069 'LineStyle','-.','LineWidth',2,'Parent',ax,'Tag','infolines',... -0070 'HandleVisibility','off'); -0071 text(rtd_range(2), yy(2)*0.5,'uncert stat bounds','Color',[0.25 0.25 0.25],... -0072 'FontSize',12,'Rotation',90,'HorizontalAlignment','center',... -0073 'VerticalAlignment','top','Tag','infolines','Parent',ax); -0074 end -0075 -0076 else -0077 % CUT OFF info -0078 % time-scale dependent scaling -0079 switch data.process.timescale -0080 case 's' -0081 CBW = data.param.CBWcutoff/1000; -0082 BVI = data.param.BVIcutoff/1000; -0083 case 'ms' -0084 CBW = data.param.CBWcutoff; -0085 BVI = data.param.BVIcutoff; -0086 end -0087 -0088 xx = get(ax,'XLim'); -0089 yy = get(ax,'YLim'); -0090 line([CBW CBW],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0091 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); -0092 line([BVI BVI],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0093 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); -0094 -0095 if CBW > xx(1) -0096 xx1 = mean([log10(xx(1)) log10(CBW)]); -0097 text(10^xx1, yy(2)*0.9,'CBW','Color',col,... -0098 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... -0099 'Tag','infolines'); -0100 end -0101 if BVI > xx(1) -0102 if CBW > xx(1) -0103 xx2 = mean([log10(CBW) log10(BVI)]); -0104 else -0105 xx2 = mean([log10(xx(1)) log10(BVI)]); -0106 end -0107 text(10^xx2, yy(2)*0.9,'BVI','Color',col,... -0108 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... -0109 'Tag','infolines'); -0110 end -0111 if BVI < xx(2) -0112 xx3 = mean([log10(BVI) log10(xx(2))]); -0113 text(10^xx3, yy(2)*0.9,'BVM','Color',col,... +0058 if hasUncert +0059 % uncertainty RTD calculation range +0060 rtd_range = uncert.statistics.RTD_bounds; +0061 rtd_range0 = data.invstd.time; +0062 yy = get(ax,'YLim'); +0063 +0064 if rtd_range(1) > rtd_range0(1) +0065 line([rtd_range(1) rtd_range(1)],[yy(1) yy(2)],'Color',[0.25 0.25 0.25],... +0066 'LineStyle','-.','LineWidth',2,'Parent',ax,'Tag','infolines',... +0067 'HandleVisibility','off'); +0068 text(rtd_range(1), yy(2)*0.5,'uncert stat bounds','Color',[0.25 0.25 0.25],... +0069 'FontSize',12,'Rotation',90,'HorizontalAlignment','center',... +0070 'VerticalAlignment','bottom','Tag','infolines','Parent',ax); +0071 end +0072 +0073 if rtd_range(2) < rtd_range0(2) +0074 line([rtd_range(2) rtd_range(2)],[yy(1) yy(2)],'Color',[0.25 0.25 0.25],... +0075 'LineStyle','-.','LineWidth',2,'Parent',ax,'Tag','infolines',... +0076 'HandleVisibility','off'); +0077 text(rtd_range(2), yy(2)*0.5,'uncert stat bounds','Color',[0.25 0.25 0.25],... +0078 'FontSize',12,'Rotation',90,'HorizontalAlignment','center',... +0079 'VerticalAlignment','top','Tag','infolines','Parent',ax); +0080 end +0081 +0082 else +0083 % CUT OFF info +0084 % time-scale dependent scaling +0085 switch data.process.timescale +0086 case 's' +0087 CBW = data.param.CBWcutoff/1000; +0088 BVI = data.param.BVIcutoff/1000; +0089 case 'ms' +0090 CBW = data.param.CBWcutoff; +0091 BVI = data.param.BVIcutoff; +0092 end +0093 +0094 xx = get(ax,'XLim'); +0095 yy = get(ax,'YLim'); +0096 line([CBW CBW],[yy(1) yy(2)],'Color',col,'LineStyle','--',... +0097 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); +0098 line([BVI BVI],[yy(1) yy(2)],'Color',col,'LineStyle','--',... +0099 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); +0100 +0101 if CBW > xx(1) +0102 xx1 = mean([log10(xx(1)) log10(CBW)]); +0103 text(10^xx1, yy(2)*0.9,'CBW','Color',col,... +0104 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... +0105 'Tag','infolines'); +0106 end +0107 if BVI > xx(1) +0108 if CBW > xx(1) +0109 xx2 = mean([log10(CBW) log10(BVI)]); +0110 else +0111 xx2 = mean([log10(xx(1)) log10(BVI)]); +0112 end +0113 text(10^xx2, yy(2)*0.9,'BVI','Color',col,... 0114 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... 0115 'Tag','infolines'); 0116 end -0117 end -0118 -0119 % check for lsqlin "EchoFlag" and plot an info line if available -0120 if strcmp(data.invstd.invtype,'NNLS') && ... -0121 strcmp(data.results.invstd.invparams.EchoFlag,'on') -0122 -0123 TEmin = data.results.nmrproc.t(1); -0124 rtd_range0 = data.invstd.time; -0125 yy = get(ax,'YLim'); -0126 -0127 if TEmin/5 > rtd_range0(1) -0128 line([TEmin/5 TEmin/5],[yy(1) yy(2)],'Color',gui.myui.colors.RE,... -0129 'LineStyle','-.','LineWidth',2,'Parent',ax,'Tag','infolines',... -0130 'HandleVisibility','off'); -0131 text(TEmin/5, yy(2)*0.5,'RTD<TE/5=0','Color',gui.myui.colors.RE,... -0132 'FontSize',12,'Rotation',90,'HorizontalAlignment','center',... -0133 'VerticalAlignment','bottom','Tag','infolines','Parent',ax); -0134 end -0135 end -0136 -0137 -0138 % diffusion regime info -0139 % PSD axis -0140 ax = gui.axes_handles.psd; -0141 -0142 % surface relaxivity in [m/s] -0143 rho = data.param.rho/1e6; -0144 % diffusion coeff. of water [m^2/s] -0145 D = 2.1e-9; -0146 fast = 1*D/rho; % [m] -0147 slow = 10*D/rho; % [m] -0148 switch data.process.timescale -0149 case 'ms' -0150 fast = fast*1e3; -0151 slow = slow*1e3; -0152 otherwise -0153 % nothing to do -0154 end -0155 -0156 xx = get(ax,'XLim'); -0157 yy = get(ax,'YLim'); -0158 line([fast fast],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0159 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); -0160 line([slow slow],[yy(1) yy(2)],'Color',col,'LineStyle','--',... -0161 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); -0162 -0163 if fast > xx(1) -0164 xx2 = mean([log10(xx(1)) log10(fast)]); -0165 text(10^xx2, yy(2)*0.9,'fast','Color',col,... -0166 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... -0167 'Tag','infolines'); -0168 end -0169 if slow < xx(2) -0170 xx3 = mean([log10(slow) log10(xx(2))]); -0171 text(10^xx3, yy(2)*0.9,'slow','Color',col,... +0117 if BVI < xx(2) +0118 xx3 = mean([log10(BVI) log10(xx(2))]); +0119 text(10^xx3, yy(2)*0.9,'BVM','Color',col,... +0120 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... +0121 'Tag','infolines'); +0122 end +0123 end +0124 +0125 % check for lsqlin "EchoFlag" and plot an info line if available +0126 if is1D && strcmp(data.invstd.invtype,'NNLS') && ... +0127 strcmp(data.results.invstd.invparams.EchoFlag,'on') +0128 +0129 TEmin = data.results.nmrproc.t(1); +0130 rtd_range0 = data.invstd.time; +0131 yy = get(ax,'YLim'); +0132 +0133 if TEmin/5 > rtd_range0(1) +0134 line([TEmin/5 TEmin/5],[yy(1) yy(2)],'Color',gui.myui.colors.RE,... +0135 'LineStyle','-.','LineWidth',2,'Parent',ax,'Tag','infolines',... +0136 'HandleVisibility','off'); +0137 text(TEmin/5, yy(2)*0.5,'RTD<TE/5=0','Color',gui.myui.colors.RE,... +0138 'FontSize',12,'Rotation',90,'HorizontalAlignment','center',... +0139 'VerticalAlignment','bottom','Tag','infolines','Parent',ax); +0140 end +0141 end +0142 +0143 +0144 % diffusion regime info +0145 % PSD axis +0146 ax = gui.axes_handles.psd; +0147 +0148 % surface relaxivity in [m/s] +0149 rho = data.param.rho/1e6; +0150 % diffusion coeff. of water [m^2/s] +0151 D = 2.1e-9; +0152 fast = 1*D/rho; % [m] +0153 slow = 10*D/rho; % [m] +0154 switch data.process.timescale +0155 case 'ms' +0156 fast = fast*1e3; +0157 slow = slow*1e3; +0158 otherwise +0159 % nothing to do +0160 end +0161 +0162 xx = get(ax,'XLim'); +0163 yy = get(ax,'YLim'); +0164 line([fast fast],[yy(1) yy(2)],'Color',col,'LineStyle','--',... +0165 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); +0166 line([slow slow],[yy(1) yy(2)],'Color',col,'LineStyle','--',... +0167 'LineWidth',2,'Parent',ax,'Tag','infolines','HandleVisibility','off'); +0168 +0169 if fast > xx(1) +0170 xx2 = mean([log10(xx(1)) log10(fast)]); +0171 text(10^xx2, yy(2)*0.9,'fast','Color',col,... 0172 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... 0173 'Tag','infolines'); 0174 end -0175 -0176 end -0177 -0178 %------------- END OF CODE -------------- -0179 -0180 %% License: -0181 % MIT License -0182 % -0183 % Copyright (c) 2018 Thomas Hiller -0184 % -0185 % Permission is hereby granted, free of charge, to any person obtaining a copy -0186 % of this software and associated documentation files (the "Software"), to deal -0187 % in the Software without restriction, including without limitation the rights -0188 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0189 % copies of the Software, and to permit persons to whom the Software is -0190 % furnished to do so, subject to the following conditions: -0191 % -0192 % The above copyright notice and this permission notice shall be included in all -0193 % copies or substantial portions of the Software. -0194 % -0195 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0196 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0197 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0198 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0199 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0200 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0201 % SOFTWARE. +0175 if slow < xx(2) +0176 xx3 = mean([log10(slow) log10(xx(2))]); +0177 text(10^xx3, yy(2)*0.9,'slow','Color',col,... +0178 'FontSize',16,'HorizontalAlignment','center','Parent',ax,... +0179 'Tag','infolines'); +0180 end +0181 +0182 end +0183 +0184 %------------- END OF CODE -------------- +0185 +0186 %% License: +0187 % MIT License +0188 % +0189 % Copyright (c) 2018 Thomas Hiller +0190 % +0191 % Permission is hereby granted, free of charge, to any person obtaining a copy +0192 % of this software and associated documentation files (the "Software"), to deal +0193 % in the Software without restriction, including without limitation the rights +0194 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0195 % copies of the Software, and to permit persons to whom the Software is +0196 % furnished to do so, subject to the following conditions: +0197 % +0198 % The above copyright notice and this permission notice shall be included in all +0199 % copies or substantial portions of the Software. +0200 % +0201 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0202 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0203 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0204 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0205 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0206 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0207 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/interface/updatePlotsSignal.html b/doc/nucleus/functions/interface/updatePlotsSignal.html index b7cfeba..0d00ddb 100644 --- a/doc/nucleus/functions/interface/updatePlotsSignal.html +++ b/doc/nucleus/functions/interface/updatePlotsSignal.html @@ -154,411 +154,413 @@

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

    applyRegularization2D +

    + +

    PURPOSE ^

    +
    + +

    SYNOPSIS ^

    +
    function [Kreg,dat_inp,L,LD] = applyRegularization2D(K,order,Tvec,Dvec,indices,dat_vec,lambda)
    + +

    DESCRIPTION ^

    +
    applyRegularization applies a manual regularization to the kernel matrix K
    +
    + Syntax:
    +       applyRegularization2D(K,order,Tvec,Dvec,indices,dat_vec,lambda)
    +
    + Inputs:
    +       K - Kernel matrix
    +       order - smoothness constraint: '0', '1' or '2' for both dimensions
    +               the same so far
    +       Tvec - relaxation time vector: here T2
    +       Dvec - diffusion / relaxation time vector: here T1
    +       indices - struct holding tile indices
    +       dat_vec - signal vector
    +       lambda - 1x2 vector holding lambda for both dimensions
    +
    + Outputs:
    +       Kreg - expanded (regularized) Kernel matrix
    +       dat_inp - expanded signal vector
    +       L - smoothness matrix regarding T dim
    +       LD - smoothness matrix regarding D dim
    +
    + Example:
    +       [Kreg,dat_inp,~,~] = applyRegularization2D(K,order,T2vec,T1vec,indices,dat_vec,lambda)
    +
    + Other m-files required:
    +       get_l (from Regularization toolbox)
    +
    + 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: + + + + + +

    SOURCE CODE ^

    +
    0001 function [Kreg,dat_inp,L,LD] = applyRegularization2D(K,order,Tvec,Dvec,indices,dat_vec,lambda)
    +0002 %applyRegularization applies a manual regularization to the kernel matrix K
    +0003 %
    +0004 % Syntax:
    +0005 %       applyRegularization2D(K,order,Tvec,Dvec,indices,dat_vec,lambda)
    +0006 %
    +0007 % Inputs:
    +0008 %       K - Kernel matrix
    +0009 %       order - smoothness constraint: '0', '1' or '2' for both dimensions
    +0010 %               the same so far
    +0011 %       Tvec - relaxation time vector: here T2
    +0012 %       Dvec - diffusion / relaxation time vector: here T1
    +0013 %       indices - struct holding tile indices
    +0014 %       dat_vec - signal vector
    +0015 %       lambda - 1x2 vector holding lambda for both dimensions
    +0016 %
    +0017 % Outputs:
    +0018 %       Kreg - expanded (regularized) Kernel matrix
    +0019 %       dat_inp - expanded signal vector
    +0020 %       L - smoothness matrix regarding T dim
    +0021 %       LD - smoothness matrix regarding D dim
    +0022 %
    +0023 % Example:
    +0024 %       [Kreg,dat_inp,~,~] = applyRegularization2D(K,order,T2vec,T1vec,indices,dat_vec,lambda)
    +0025 %
    +0026 % Other m-files required:
    +0027 %       get_l (from Regularization toolbox)
    +0028 %
    +0029 % Subfunctions:
    +0030 %       none
    +0031 %
    +0032 % MAT-files required:
    +0033 %       none
    +0034 %
    +0035 % See also:
    +0036 % Author: see AUTHORS.md
    +0037 % email: see AUTHORS.md
    +0038 % License: MIT License (at end)
    +0039 
    +0040 %------------- BEGIN CODE --------------
    +0041 
    +0042 %% get lambda values
    +0043 lamT = lambda(2); % T2
    +0044 lamD = lambda(1); % T1
    +0045 
    +0046 %% get column indices
    +0047 col_end = indices.col_end;
    +0048 
    +0049 % get first smoothness matrix
    +0050 L = get_l(length(Tvec)*length(Dvec),order);
    +0051 
    +0052 % regularization along first dimension, normally Tvec (here T2)
    +0053 % loop necessary to correct the transitions among the tiles
    +0054 for n = 1:length(Dvec)-1
    +0055         L(col_end(n)-order+1:col_end(n),col_end(n)+1:col_end(n)+order) = zeros(order);  
    +0056 end
    +0057 % first expanded kernel matrix
    +0058 KregT = [K;lamT * L];
    +0059 
    +0060 % regularization along second dimension, normally D (here T1)
    +0061 LD = zeros(size(L,1)-order*length(Tvec),size(L,2));
    +0062 for no = 1:order + 1
    +0063     for n = 1:size(LD,2) - (order) * length(Tvec)
    +0064          LD(n,n+(no-1)*length(Tvec)) = L(1,no); 
    +0065     end
    +0066 end
    +0067 % final expanded kernel matrix
    +0068 Kreg = [KregT;lamD * LD];
    +0069 
    +0070 % expanded data vector
    +0071 dat_inp = dat_vec;
    +0072 dat_inp(length(dat_vec)+1:length(dat_vec)+size(L,1)+size(LD,1),1) = 0;
    +0073 
    +0074 return
    +0075 
    +0076 %------------- END OF CODE --------------
    +0077 
    +0078 %% License:
    +0079 % MIT License
    +0080 %
    +0081 % Copyright (c) 2024 Thomas Hiller
    +0082 %
    +0083 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +0084 % of this software and associated documentation files (the "Software"), to deal
    +0085 % in the Software without restriction, including without limitation the rights
    +0086 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +0087 % copies of the Software, and to permit persons to whom the Software is
    +0088 % furnished to do so, subject to the following conditions:
    +0089 %
    +0090 % The above copyright notice and this permission notice shall be included in all
    +0091 % copies or substantial portions of the Software.
    +0092 %
    +0093 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +0094 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +0095 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +0096 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +0097 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +0098 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +0099 % SOFTWARE.
    +0100 
    +0101 
    +0102         
    +0103
    +
    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 8f8f6cd..d722c8e 100644 --- a/doc/nucleus/functions/inversion/createKernelMatrix.html +++ b/doc/nucleus/functions/inversion/createKernelMatrix.html @@ -30,7 +30,7 @@

    DESCRIPTION ^SOURCE CODE ^%and relaxation time vector "T" 0004 % 0005 % Syntax: -0006 % createKernelMatrix(t,T,Tbulk,Tflag,T1IRflag) +0006 % createKernelMatrix(t,T,Tbulk,Tflag,T1IRflag) 0007 % 0008 % Inputs: 0009 % t - signal time vector diff --git a/doc/nucleus/functions/inversion/createKernelMatrix2D.html b/doc/nucleus/functions/inversion/createKernelMatrix2D.html new file mode 100644 index 0000000..730f207 --- /dev/null +++ b/doc/nucleus/functions/inversion/createKernelMatrix2D.html @@ -0,0 +1,237 @@ + + + + Description of createKernelMatrix2D + + + + + + + + + + + +

    createKernelMatrix2D +

    + +

    PURPOSE ^

    +
    creates a Kernel matrix from signals time vectors "t"
    + +

    SYNOPSIS ^

    +
    function [K,indices] = createKernelMatrix2D(dat,T1vec,T2vec,p)
    + +

    DESCRIPTION ^

    +
    createKernelMatrix2D creates a Kernel matrix from signals time vectors "t"
    +and relaxation time vector "T1vec" and "T2vec"
    +
    + Syntax:
    +       createKernelMatrix2D(dat,T1vec,T2vec,G0,D,te,T1IRfac)
    +
    + Inputs:
    +       dat - struct holding signal data including time vector "t" in [s]
    +       T1vec - relaxation times vector in [s]
    +       T2vec - relaxation times vector in [s]
    +       p - struct holding optional settings
    +           G0 - gradient in [T/m]
    +           D - diffusion coefficient [m²/s]
    +           te - echo time in [s]
    +           Tbulk - Bulk relaxation time in [s]
    +           T1IRfac - 1 or 2 (Sat. or Inv. Recovery)
    +           IRtype - 1 or 2 (1-2exp() or -exp())
    +
    + Outputs:
    +       K - Kernel matrix size(length(t),length(T1vec)*length(T2vec))
    +       indices - struct holding tile indices
    +
    + Example:
    +       K = createKernelMatrix(dat,T1,T2,0,2e-9,2e-4,2)
    +
    + 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: + + + + + +

    SOURCE CODE ^

    +
    0001 function [K,indices] = createKernelMatrix2D(dat,T1vec,T2vec,p)
    +0002 %createKernelMatrix2D creates a Kernel matrix from signals time vectors "t"
    +0003 %and relaxation time vector "T1vec" and "T2vec"
    +0004 %
    +0005 % Syntax:
    +0006 %       createKernelMatrix2D(dat,T1vec,T2vec,G0,D,te,T1IRfac)
    +0007 %
    +0008 % Inputs:
    +0009 %       dat - struct holding signal data including time vector "t" in [s]
    +0010 %       T1vec - relaxation times vector in [s]
    +0011 %       T2vec - relaxation times vector in [s]
    +0012 %       p - struct holding optional settings
    +0013 %           G0 - gradient in [T/m]
    +0014 %           D - diffusion coefficient [m²/s]
    +0015 %           te - echo time in [s]
    +0016 %           Tbulk - Bulk relaxation time in [s]
    +0017 %           T1IRfac - 1 or 2 (Sat. or Inv. Recovery)
    +0018 %           IRtype - 1 or 2 (1-2exp() or -exp())
    +0019 %
    +0020 % Outputs:
    +0021 %       K - Kernel matrix size(length(t),length(T1vec)*length(T2vec))
    +0022 %       indices - struct holding tile indices
    +0023 %
    +0024 % Example:
    +0025 %       K = createKernelMatrix(dat,T1,T2,0,2e-9,2e-4,2)
    +0026 %
    +0027 % Other m-files required:
    +0028 %       none
    +0029 %
    +0030 % Subfunctions:
    +0031 %       none
    +0032 %
    +0033 % MAT-files required:
    +0034 %       none
    +0035 %
    +0036 % See also:
    +0037 % Author: see AUTHORS.md
    +0038 % email: see AUTHORS.md
    +0039 % License: MIT License (at end)
    +0040 
    +0041 %------------- BEGIN CODE --------------
    +0042 
    +0043 %%
    +0044 useTbulk = false;
    +0045 if isfield(p,'Tbulk')
    +0046     useTbulk = true;
    +0047     Tbulk = p.Tbulk;
    +0048 end
    +0049 if isfield(p,'G0')
    +0050     G0 = p.G0;
    +0051 else
    +0052     G0 = 0;
    +0053 end
    +0054 if isfield(p,'D')
    +0055     D = p.D;
    +0056 else
    +0057     D = 2.025e-09;
    +0058 end
    +0059 if isfield(p,'te')
    +0060     te = p.te;
    +0061 else
    +0062     te = 2e-4;
    +0063 end
    +0064 if isfield(p,'T1IRfac')
    +0065     T1IRfac = p.T1IRfac;
    +0066 else
    +0067     T1IRfac = 2;
    +0068 end
    +0069 if isfield(p,'IRtype')
    +0070     IRtype = p.IRtype;
    +0071 else
    +0072     IRtype = 1;
    +0073 end
    +0074 
    +0075 %% gyromagnetic ratio of hydrogen
    +0076 gyro = 0.267*1e9; % [rad/(T*s)]
    +0077 
    +0078 %% how many recovery times?
    +0079 num_T1 = length(dat);
    +0080 
    +0081 %% init data
    +0082 lin_1 = zeros(1,num_T1);
    +0083 lin_end = zeros(1,num_T1);
    +0084 col_1 = zeros(1,numel(T1vec));
    +0085 col_end = zeros(1,numel(T1vec));
    +0086 
    +0087 % determine cumulative length of all involved t-vectors
    +0088 t_dim = 0;
    +0089 for nn = 1:num_T1
    +0090     lin_1(nn) = 1 + t_dim;
    +0091     t_dim = t_dim + length(dat(nn).t);
    +0092     lin_end(nn) = t_dim;
    +0093 end
    +0094 K = zeros(t_dim,length(T1vec)*length(T2vec));
    +0095 
    +0096 % assemble kernel
    +0097 for n = 1:numel(T1vec)
    +0098     % determine current tile:
    +0099     col_1(n) = (n-1) * length(T2vec) + 1;
    +0100     col_end(n) = n * length(T2vec);
    +0101     for nn = 1:num_T1
    +0102         % time vectors
    +0103         tr = repmat(dat(nn).t(:),[1,numel(T2vec)]);
    +0104         Tr = repmat(T2vec,[numel(dat(nn).t),1]);
    +0105         % diffusion relaxation rate:
    +0106         Tdiff_rate = (D*(gyro*G0*te)^2)/12;
    +0107         % T1 relaxation
    +0108         if IRtype == 1
    +0109             T1loss = (1-T1IRfac*exp(-dat(nn).T1/T1vec(n)));
    +0110         else
    +0111             % after Hürlimann 2001 JMR
    +0112             T1loss = -(exp(-dat(nn).T1/T1vec(n)));
    +0113         end
    +0114         % kernel
    +0115         if useTbulk
    +0116             K(lin_1(nn):lin_end(nn),col_1(n):col_end(n)) = T1loss*exp(-tr./Tr).*exp(-tr.*Tdiff_rate).*exp(-tr./Tbulk);
    +0117         else
    +0118             K(lin_1(nn):lin_end(nn),col_1(n):col_end(n)) = T1loss*exp(-tr./Tr).*exp(-tr.*Tdiff_rate);
    +0119         end        
    +0120     end
    +0121 end
    +0122 
    +0123 % struc holding tile indices
    +0124 indices.lin_1 = lin_1;
    +0125 indices.lin_end = lin_end;
    +0126 indices.col_1 = col_1;
    +0127 indices.col_end = col_end;
    +0128 
    +0129 return
    +0130 
    +0131 %------------- END OF CODE --------------
    +0132 
    +0133 %% License:
    +0134 % MIT License
    +0135 %
    +0136 % Copyright (c) 2024 Thomas Hiller
    +0137 %
    +0138 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +0139 % of this software and associated documentation files (the "Software"), to deal
    +0140 % in the Software without restriction, including without limitation the rights
    +0141 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +0142 % copies of the Software, and to permit persons to whom the Software is
    +0143 % furnished to do so, subject to the following conditions:
    +0144 %
    +0145 % The above copyright notice and this permission notice shall be included in all
    +0146 % copies or substantial portions of the Software.
    +0147 %
    +0148 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +0149 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +0150 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +0151 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +0152 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +0153 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +0154 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/fitData2D.html b/doc/nucleus/functions/inversion/fitData2D.html new file mode 100644 index 0000000..2afc261 --- /dev/null +++ b/doc/nucleus/functions/inversion/fitData2D.html @@ -0,0 +1,275 @@ + + + + Description of fitData2D + + + + + + + + + + + +

    fitData2D +

    + +

    PURPOSE ^

    +
    is a control routine that fits 2D NMR data;
    + +

    SYNOPSIS ^

    +
    function fitdata = fitData2D(data,parameter)
    + +

    DESCRIPTION ^

    +
    fitData2D is a control routine that fits 2D NMR data;
    +if the Optimization Toolbox is available the user can select LSQLIN,
    +otherwise the default built-in LSQNONNEG is used;
    +
    + Syntax:
    +       fitData2D(data,parameter)
    +
    + Inputs:
    +       data - struct that holds the NMR signal data
    +       parameter - struct that holds settings:
    +
    + Outputs:
    +       fitdata - struct that holds the inversion results:
    +
    + Example:
    +       [fitdata] = fitData2D(data,parameter)
    +
    + Other m-files required:
    +       Optimization Toolbox from Mathworks (optional)
    +       applyRegularization2D
    +       createKernelMatrix2D
    +       getFitErrors
    +       getTLogMean2D
    +       lsqnonneg
    +       lsqlin (optional)
    +
    + 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: + + + + + +

    SOURCE CODE ^

    +
    0001 function fitdata = fitData2D(data,parameter)
    +0002 %fitData2D is a control routine that fits 2D NMR data;
    +0003 %if the Optimization Toolbox is available the user can select LSQLIN,
    +0004 %otherwise the default built-in LSQNONNEG is used;
    +0005 %
    +0006 % Syntax:
    +0007 %       fitData2D(data,parameter)
    +0008 %
    +0009 % Inputs:
    +0010 %       data - struct that holds the NMR signal data
    +0011 %       parameter - struct that holds settings:
    +0012 %
    +0013 % Outputs:
    +0014 %       fitdata - struct that holds the inversion results:
    +0015 %
    +0016 % Example:
    +0017 %       [fitdata] = fitData2D(data,parameter)
    +0018 %
    +0019 % Other m-files required:
    +0020 %       Optimization Toolbox from Mathworks (optional)
    +0021 %       applyRegularization2D
    +0022 %       createKernelMatrix2D
    +0023 %       getFitErrors
    +0024 %       getTLogMean2D
    +0025 %       lsqnonneg
    +0026 %       lsqlin (optional)
    +0027 %
    +0028 % Subfunctions:
    +0029 %       none
    +0030 %
    +0031 % MAT-files required:
    +0032 %       none
    +0033 %
    +0034 % See also:
    +0035 % Author: see AUTHORS.md
    +0036 % email: see AUTHORS.md
    +0037 % License: MIT License (at end)
    +0038 
    +0039 %------------- BEGIN CODE --------------
    +0040 
    +0041 % get the input parameters
    +0042 % flag = parameter.T1T2;           % T1/T2 switch
    +0043 T1IRfac = parameter.T1IRfac;       % T1 Sat/Inv Recovery factor
    +0044 IRtype = parameter.IRtype;         % T1 IR kernel type
    +0045 % Tb = parameter.Tb;               % bulk relaxation time
    +0046 % Td = parameter.Td;               % diffusion relaxation time
    +0047 
    +0048 noise = parameter.noise;
    +0049 % get system properties
    +0050 D = parameter.D;
    +0051 G0 = parameter.G0;
    +0052 te = parameter.te;
    +0053 
    +0054 % create model space from relaxation time T vectors
    +0055 T1min = parameter.T1min;
    +0056 T1max = parameter.T1max;
    +0057 T1N = parameter.T1N;
    +0058 T2min = parameter.T2min;
    +0059 T2max = parameter.T2max;
    +0060 T2N = parameter.T2N;
    +0061 
    +0062 T1vec = logspace(log10(T1min),log10(T1max),T1N);
    +0063 T2vec = logspace(log10(T2min),log10(T2max),T2N);
    +0064 MOD = zeros(numel(T2vec),numel(T1vec));
    +0065 
    +0066 % prepare data vector
    +0067 Nsignals = numel(data);
    +0068 Nechos = numel(data(1).t);
    +0069 dat_vec = zeros(Nsignals*Nechos,1);
    +0070 for n = 1:numel(data)
    +0071     if n == 1
    +0072         dat_vec(1:Nechos,1) = data(n).s;
    +0073     else
    +0074         dat_vec((n-1)*Nechos+1:n*Nechos,1) = data(n).s;
    +0075     end
    +0076 end
    +0077 
    +0078 % create the Kernel matrix for inversion
    +0079 p.G0 = G0;
    +0080 p.D = D;
    +0081 p.te = te;
    +0082 p.T1IRfac = T1IRfac;
    +0083 p.IRtype = IRtype;
    +0084 [K,indices] = createKernelMatrix2D(data,T1vec,T2vec,p);
    +0085 
    +0086 % regularization
    +0087 order = parameter.orderT1;
    +0088 lambda = [parameter.lamT1 parameter.lamT2];
    +0089 
    +0090 [KK,dat_inp,LT,LD] = applyRegularization2D(K,order,T2vec,T1vec,indices,dat_vec,lambda);
    +0091 
    +0092 switch parameter.solver
    +0093     case 'lsqlin'
    +0094         x0 = zeros(size(KK,2),1);
    +0095         lb = zeros(size(KK,2),1);
    +0096         ub = ones(size(KK,2),1);
    +0097 
    +0098         options = optimoptions('lsqlin');
    +0099         options.Display = parameter.info;
    +0100         % options.OptimalityTolerance = 1e-16;
    +0101         % options.StepTolerance = 1e-16;
    +0102         % options.MaxIterations = 2000;
    +0103         [f_vec,RESNORM,RESIDUAL,EXITFLAG,OUTPUT] = lsqlin(KK,dat_inp,[],[],[],[],...
    +0104             lb,ub,x0,options);
    +0105 
    +0106     case 'lsqnonneg'
    +0107         options = optimset('lsqnonneg');
    +0108         options.Display = parameter.info;
    +0109         [f_vec,RESNORM,RESIDUAL,EXITFLAG,OUTPUT] = lsqnonneg(KK,dat_inp,options);
    +0110 end
    +0111 
    +0112 % global model response (fit)
    +0113 s_fit = K * f_vec;
    +0114 % global fit errors
    +0115 out_global = getFitErrors(dat_vec,s_fit,noise);
    +0116 % local fit errors
    +0117 for n = 1:numel(data)
    +0118     data(n).s_fit = s_fit((n-1)*Nechos+1:n*Nechos);
    +0119     out = getFitErrors(data(n).s,data(n).s_fit,data(n).noise);
    +0120     data(n).resnorm = out.resnorm;
    +0121     data(n).residual = out.residual;
    +0122     data(n).chi2 = out.chi2;
    +0123     data(n).rms = out.rms;
    +0124 end
    +0125 
    +0126 % L-curve parameter
    +0127 % model norm |L*x|_2
    +0128 xn = norm([LT;LD]*f_vec,2);
    +0129 % residual norm |A*x-b|_2
    +0130 rn = norm(out_global.residual,2);
    +0131 
    +0132 % create the Kernel matrix for E0
    +0133 dat0.t=0;
    +0134 dat0.T1=10000;
    +0135 [K0,~] = createKernelMatrix2D(dat0,T1vec,T2vec,p);
    +0136 E0 = K0*f_vec;
    +0137 
    +0138 % sort the result
    +0139 f_2Dmap = zeros(size(MOD'));
    +0140 for n = 1:length(T1vec)
    +0141     f_2Dmap(n,:) = f_vec(indices.col_1(n):indices.col_end(n));
    +0142 end
    +0143 
    +0144 % get TLGM and TMAX
    +0145 [TLGM,TMAX] = getTLogMean2D(T1vec,T2vec,f_2Dmap);
    +0146 
    +0147 % output struct
    +0148 fitdata.data = data;
    +0149 fitdata.T1vec = T1vec;
    +0150 fitdata.T2vec = T2vec;
    +0151 fitdata.indices = indices;
    +0152 fitdata.f_vec = f_vec;
    +0153 fitdata.f_2Dmap = f_2Dmap;
    +0154 fitdata.E0 = E0;
    +0155 fitdata.T1tlgm = TLGM(1);
    +0156 fitdata.T2tlgm = TLGM(2);
    +0157 fitdata.T1tmax = TMAX(1);
    +0158 fitdata.T2tmax = TMAX(2);
    +0159 fitdata.error_global = out_global;
    +0160 fitdata.xn = xn;
    +0161 fitdata.rn = rn;
    +0162 fitdata.solver_out.RESNORM = RESNORM;
    +0163 fitdata.solver_out.RESIDUAL = RESIDUAL;
    +0164 fitdata.solver_out.EXITFLAG = EXITFLAG;
    +0165 fitdata.solver_out.OUTPUT = OUTPUT;
    +0166 fitdata.param = parameter;
    +0167 % fitdata.K = K;
    +0168 
    +0169 return
    +0170 
    +0171 %------------- END OF CODE --------------
    +0172 
    +0173 %% License:
    +0174 % MIT License
    +0175 %
    +0176 % Copyright (c) 2018 Thomas Hiller
    +0177 %
    +0178 % Permission is hereby granted, free of charge, to any person obtaining a copy
    +0179 % of this software and associated documentation files (the "Software"), to deal
    +0180 % in the Software without restriction, including without limitation the rights
    +0181 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +0182 % copies of the Software, and to permit persons to whom the Software is
    +0183 % furnished to do so, subject to the following conditions:
    +0184 %
    +0185 % The above copyright notice and this permission notice shall be included in all
    +0186 % copies or substantial portions of the Software.
    +0187 %
    +0188 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +0189 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +0190 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +0191 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +0192 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +0193 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +0194 % SOFTWARE.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/fitDataFree.html b/doc/nucleus/functions/inversion/fitDataFree.html index 8517544..6c3ced1 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
  • PhaseView is an extra subGUI to manipulate the phase of a T2 signal
  • importASCIIdata imports NMR data from ASCII files
  • importEXCELdata imports NMR data from Excel files
  • importMOD2D2INV imports data directly from the NUCLEUSmod 2D GUI
  • importNMRdata is the general import routine for NMR data
  • 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
  • @@ -262,105 +262,107 @@

    SOURCE CODE ^'MaxIter',5000,'TolFun',1e-12,'TolX',1e-12); 0163 switch flag 0164 case 'T1' -0165 [x,~,~,output] = fminsearchbnd(@(x) fcn_fitFreeT1_fmin(x,t,s,IRfac),... -0166 x0,lb,ub,options); -0167 case 'T2' -0168 [x,~,~,output] = fminsearchbnd(@(x) fcn_fitFreeT2_fmin(x,t,s,e),... -0169 x0,lb,ub,options); -0170 end -0171 end -0172 -0173 % get the fit -0174 fit_t = t; -0175 switch flag -0176 case 'T1' -0177 fit_s = fcn_fitFreeT1(x,fit_t,IRfac); -0178 case 'T2' -0179 fit_s = fcn_fitFreeT2(x,fit_t); -0180 end -0181 -0182 % get residuals and error measures -0183 if isfield(parameter,'W') -0184 % when signal gating was used the error estimates need to be adjusted -0185 out = getFitErrors(signal,fit_s,parameter.noise,parameter.W); -0186 else -0187 out = getFitErrors(signal,fit_s,parameter.noise); -0188 end -0189 -0190 % get Jacobian -0191 switch parameter.optim -0192 case 'on' -0193 % nothing to do because the Optim. Toolbox gives the jacobian as -0194 % output -0195 case 'off' -0196 jacobian = getFitFreeJacobian(x,t,flag,IRfac); -0197 end -0198 -0199 % confidence interval -0200 ci = getConfInterval(out.resnorm,jacobian,0.05); -0201 -0202 % sort the relaxation times in ascending order -0203 E0 = x(1:2:end); -0204 T = x(2:2:end); -0205 if any(parameter.Tfixed_bool) -0206 idx = 1:1:nExp; -0207 else -0208 [T,idx] = sort(T); -0209 end -0210 E0 = E0(idx); -0211 ciT = ci(2:2:end); -0212 ciE = ci(1:2:end); -0213 ciT = ciT(idx); -0214 ciE = ciE(idx); -0215 ci(2:2:end) = ciT; -0216 ci(1:2:end) = ciE; -0217 -0218 % output struct -0219 fitdata.E0 = E0; -0220 switch flag -0221 case 'T1' -0222 fitdata.T1 = T; -0223 case 'T2' -0224 fitdata.T2 = T; -0225 end -0226 fitdata.T = T; -0227 fitdata.fit_t = fit_t; -0228 fitdata.fit_s = fit_s; -0229 fitdata.resnorm = out.resnorm; -0230 fitdata.residual = out.residual; -0231 fitdata.errornorm = out.errnorm1; -0232 fitdata.rms = out.rms; -0233 fitdata.chi2 = out.chi2; -0234 fitdata.ci = ci; -0235 fitdata.x = x; -0236 fitdata.output = output; -0237 -0238 return +0165 % set all start values to 0 (if something is not working as expected, comment it and try again) +0166 x0 = zeros(size(lb)); +0167 [x,~,~,output] = fminsearchbnd(@(x) fcn_fitFreeT1_fmin(x,t,s,IRfac),... +0168 x0,lb,ub,options); +0169 case 'T2' +0170 [x,~,~,output] = fminsearchbnd(@(x) fcn_fitFreeT2_fmin(x,t,s,e),... +0171 x0,lb,ub,options); +0172 end +0173 end +0174 +0175 % get the fit +0176 fit_t = t; +0177 switch flag +0178 case 'T1' +0179 fit_s = fcn_fitFreeT1(x,fit_t,IRfac); +0180 case 'T2' +0181 fit_s = fcn_fitFreeT2(x,fit_t); +0182 end +0183 +0184 % get residuals and error measures +0185 if isfield(parameter,'W') +0186 % when signal gating was used the error estimates need to be adjusted +0187 out = getFitErrors(signal,fit_s,parameter.noise,parameter.W); +0188 else +0189 out = getFitErrors(signal,fit_s,parameter.noise); +0190 end +0191 +0192 % get Jacobian +0193 switch parameter.optim +0194 case 'on' +0195 % nothing to do because the Optim. Toolbox gives the jacobian as +0196 % output +0197 case 'off' +0198 jacobian = getFitFreeJacobian(x,t,flag,IRfac); +0199 end +0200 +0201 % confidence interval +0202 ci = getConfInterval(out.resnorm,jacobian,0.05); +0203 +0204 % sort the relaxation times in ascending order +0205 E0 = x(1:2:end); +0206 T = x(2:2:end); +0207 if any(parameter.Tfixed_bool) +0208 idx = 1:1:nExp; +0209 else +0210 [T,idx] = sort(T); +0211 end +0212 E0 = E0(idx); +0213 ciT = ci(2:2:end); +0214 ciE = ci(1:2:end); +0215 ciT = ciT(idx); +0216 ciE = ciE(idx); +0217 ci(2:2:end) = ciT; +0218 ci(1:2:end) = ciE; +0219 +0220 % output struct +0221 fitdata.E0 = E0; +0222 switch flag +0223 case 'T1' +0224 fitdata.T1 = T; +0225 case 'T2' +0226 fitdata.T2 = T; +0227 end +0228 fitdata.T = T; +0229 fitdata.fit_t = fit_t; +0230 fitdata.fit_s = fit_s; +0231 fitdata.resnorm = out.resnorm; +0232 fitdata.residual = out.residual; +0233 fitdata.errornorm = out.errnorm1; +0234 fitdata.rms = out.rms; +0235 fitdata.chi2 = out.chi2; +0236 fitdata.ci = ci; +0237 fitdata.x = x; +0238 fitdata.output = output; 0239 -0240 %------------- END OF CODE -------------- +0240 return 0241 -0242 %% License: -0243 % MIT License -0244 % -0245 % Copyright (c) 2018 Thomas Hiller +0242 %------------- END OF CODE -------------- +0243 +0244 %% License: +0245 % MIT License 0246 % -0247 % Permission is hereby granted, free of charge, to any person obtaining a copy -0248 % of this software and associated documentation files (the "Software"), to deal -0249 % in the Software without restriction, including without limitation the rights -0250 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0251 % copies of the Software, and to permit persons to whom the Software is -0252 % furnished to do so, subject to the following conditions: -0253 % -0254 % The above copyright notice and this permission notice shall be included in all -0255 % copies or substantial portions of the Software. -0256 % -0257 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0258 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0259 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0260 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0261 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0262 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0263 % SOFTWARE. +0247 % Copyright (c) 2018 Thomas Hiller +0248 % +0249 % Permission is hereby granted, free of charge, to any person obtaining a copy +0250 % of this software and associated documentation files (the "Software"), to deal +0251 % in the Software without restriction, including without limitation the rights +0252 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0253 % copies of the Software, and to permit persons to whom the Software is +0254 % furnished to do so, subject to the following conditions: +0255 % +0256 % The above copyright notice and this permission notice shall be included in all +0257 % copies or substantial portions of the Software. +0258 % +0259 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0260 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0261 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0262 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0263 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0264 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0265 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/inversion/getChi2.html b/doc/nucleus/functions/inversion/getChi2.html index c76f596..149bd31 100644 --- a/doc/nucleus/functions/inversion/getChi2.html +++ b/doc/nucleus/functions/inversion/getChi2.html @@ -103,7 +103,7 @@

    SOURCE CODE ^%------------- BEGIN CODE -------------- 0033 0034 %% residual -0035 residual = signal - fit; +0035 residual = fit-signal; 0036 0037 %% chi2 0038 % sqrt(sum(N.^2)) = norm(N) (if N is a vector) diff --git a/doc/nucleus/functions/inversion/getConfInterval.html b/doc/nucleus/functions/inversion/getConfInterval.html index 8f274f2..62f7194 100644 --- a/doc/nucleus/functions/inversion/getConfInterval.html +++ b/doc/nucleus/functions/inversion/getConfInterval.html @@ -145,7 +145,7 @@

    SOURCE CODE ^if StatBox == 1 0069 stud_fac = tinv(1-alpha,deg_free); 0070 else -0071 if deg_free <= 1000 +0071 if deg_free > 0 && deg_free <= 1000 0072 stud_fac = getStudentInvCDF(1-alpha,deg_free); 0073 else 0074 stud_fac = 1;%NaN; diff --git a/doc/nucleus/functions/inversion/getFitErrors.html b/doc/nucleus/functions/inversion/getFitErrors.html index 419b52b..8e7b256 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: +
  • Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • fitData2D is a control routine that fits 2D NMR data;
  • 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
  • @@ -129,7 +129,7 @@

    SOURCE CODE ^end 0050 0051 %% residuals -0052 residual = s-sfit; +0052 residual = sfit-s; 0053 0054 %% L1 norm 0055 errnorm1 = sum(abs(residual)); diff --git a/doc/nucleus/functions/inversion/getTLogMean2D.html b/doc/nucleus/functions/inversion/getTLogMean2D.html new file mode 100644 index 0000000..e23cbeb --- /dev/null +++ b/doc/nucleus/functions/inversion/getTLogMean2D.html @@ -0,0 +1,184 @@ + + + + Description of getTLogMean2D + + + + + + + + + + + +

    getTLogMean2D +

    + +

    PURPOSE ^

    +
    + +

    SYNOPSIS ^

    +
    function [TLGM,TMAX] = getTLogMean2D(T1,T2,f,varargin)
    + +

    DESCRIPTION ^

    +
    getTLogMean calculates the T logmean value out of a relaxation time
    +distribution
    +
    + Syntax:
    +       getTLogMean2D(T1,T2,f)
    +
    + Inputs:
    +       T1 - T1 relaxation times
    +       T2 - T2 relaxation times
    +       f - 2D distribution
    +       varargin - 2 1x2 vectors giving a range [Tmin Tmax] for both
    +       dimensions
    +
    + Outputs:
    +       TLGM - vector [T1tlgm T2tlgm] -> 2D log mean value of RTD
    +       TMAX - vector [T1tmax T2tmax] -> 2D maximum of RTD
    +
    + Example:
    +       [TLGM,TMAX] = getTLogMean2D(T1,T2,f)
    +
    + 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: + + + + + +

    SOURCE CODE ^

    +
    0001 function [TLGM,TMAX] = getTLogMean2D(T1,T2,f,varargin)
    +0002 %getTLogMean calculates the T logmean value out of a relaxation time
    +0003 %distribution
    +0004 %
    +0005 % Syntax:
    +0006 %       getTLogMean2D(T1,T2,f)
    +0007 %
    +0008 % Inputs:
    +0009 %       T1 - T1 relaxation times
    +0010 %       T2 - T2 relaxation times
    +0011 %       f - 2D distribution
    +0012 %       varargin - 2 1x2 vectors giving a range [Tmin Tmax] for both
    +0013 %       dimensions
    +0014 %
    +0015 % Outputs:
    +0016 %       TLGM - vector [T1tlgm T2tlgm] -> 2D log mean value of RTD
    +0017 %       TMAX - vector [T1tmax T2tmax] -> 2D maximum of RTD
    +0018 %
    +0019 % Example:
    +0020 %       [TLGM,TMAX] = getTLogMean2D(T1,T2,f)
    +0021 %
    +0022 % Other m-files required:
    +0023 %       none
    +0024 %
    +0025 % Subfunctions:
    +0026 %       none
    +0027 %
    +0028 % MAT-files required:
    +0029 %       none
    +0030 %
    +0031 % See also:
    +0032 % Author: see AUTHORS.md
    +0033 % email: see AUTHORS.md
    +0034 % License: MIT License (at end)
    +0035 
    +0036 %------------- BEGIN CODE --------------
    +0037 
    +0038 %% calculate TLGM
    +0039 % check input
    +0040 if nargin > 3
    +0041     T1range = varargin{1};
    +0042     T2range = varargin{2};
    +0043 else
    +0044     % use full T1 and T2 range for calculation
    +0045     T1range = [min(T1) max(T1)];
    +0046     T2range = [min(T2) max(T2)];
    +0047 end
    +0048 
    +0049 % make T1-T2 2D map
    +0050 [X,Y] = meshgrid(T2,T1);
    +0051 
    +0052 % calc TLGM of entire map
    +0053 mask1 = Y >= T1range(1) & Y <= T1range(2);
    +0054 mask2 = X >= T2range(1) & X <= T2range(2);
    +0055 x_m1 = 10^(sum(sum(log10(X(mask2)) .* f(mask2)/sum(sum(f(mask2))))));
    +0056 y_m1 = 10^(sum(sum(log10(Y(mask1)) .* f(mask1)/sum(sum(f(mask1))))));
    +0057 
    +0058 % calc TMAX of entire map
    +0059 f1 = f.*mask1.*mask2;
    +0060 [ix,iy] = find(f1==max(f1(:)));
    +0061 x_max1 = X(ix,iy);
    +0062 y_max1 = Y(ix,iy);
    +0063 
    +0064 % calc TMAX of entire map
    +0065 % mask1 = T1 >= T1range(1) & T1 <= T1range(2);
    +0066 % mask2 = T2 >= T2range(1) & T2 <= T2range(2);
    +0067 % T1lim = T1(mask1);
    +0068 % T2lim = T2(mask2);
    +0069 % [dummy1] = max(f,[],2);
    +0070 % [~,ii1] = max(dummy1(mask1));
    +0071 % [dummy2] = max(f,[],1);
    +0072 % [~,ii2] = max(dummy2(mask2));
    +0073 % x_max = T2lim(ii2);
    +0074 % y_max = T1lim(ii1);
    +0075 
    +0076 % save results
    +0077 TLGM = [y_m1 x_m1]; % [T1tlgm T2tlgm]
    +0078 % TMAX = [y_max x_max]; % [T1tmax T2tmax]
    +0079 TMAX = [y_max1 x_max1]; % [T1tmax T2tmax]
    +0080 
    +0081 return
    +0082 
    +0083 %------------- END OF CODE --------------
    +0084 
    +0085 %% License:
    +0086 % MIT License
    +0087 %
    +0088 % Copyright (c) 2024 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/functions/inversion/getUncertaintyStatistics.html b/doc/nucleus/functions/inversion/getUncertaintyStatistics.html index c933dd8..08ebd68 100644 --- a/doc/nucleus/functions/inversion/getUncertaintyStatistics.html +++ b/doc/nucleus/functions/inversion/getUncertaintyStatistics.html @@ -131,39 +131,41 @@

    SOURCE CODE ^getAAD(TLGM_tmp,1)]; 0059 out.E0 = [mean(E0_tmp) std(E0_tmp) getAAD(E0_tmp,0)]; 0060 out.E0_med = [median(E0_tmp) getAAD(E0_tmp,1)]; -0061 -0062 else -0063 helpdlg({'function: getUncertainty Statistics',... -0064 'Cannot continue because data has incompatible size'},... -0065 'Check input!'); -0066 end -0067 -0068 return +0061 out.Tlgm_all = TLGM_tmp; +0062 out.E0_all = E0_tmp; +0063 +0064 else +0065 helpdlg({'function: getUncertainty Statistics',... +0066 'Cannot continue because data has incompatible size'},... +0067 'Check input!'); +0068 end 0069 -0070 %------------- END OF CODE -------------- +0070 return 0071 -0072 %% License: -0073 % MIT License -0074 % -0075 % Copyright (c) 2024 Thomas Hiller +0072 %------------- END OF CODE -------------- +0073 +0074 %% License: +0075 % MIT License 0076 % -0077 % Permission is hereby granted, free of charge, to any person obtaining a copy -0078 % of this software and associated documentation files (the "Software"), to deal -0079 % in the Software without restriction, including without limitation the rights -0080 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -0081 % copies of the Software, and to permit persons to whom the Software is -0082 % furnished to do so, subject to the following conditions: -0083 % -0084 % The above copyright notice and this permission notice shall be included in all -0085 % copies or substantial portions of the Software. -0086 % -0087 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -0088 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -0089 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -0090 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -0091 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -0092 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -0093 % SOFTWARE. +0077 % Copyright (c) 2024 Thomas Hiller +0078 % +0079 % Permission is hereby granted, free of charge, to any person obtaining a copy +0080 % of this software and associated documentation files (the "Software"), to deal +0081 % in the Software without restriction, including without limitation the rights +0082 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0083 % copies of the Software, and to permit persons to whom the Software is +0084 % furnished to do so, subject to the following conditions: +0085 % +0086 % The above copyright notice and this permission notice shall be included in all +0087 % copies or substantial portions of the Software. +0088 % +0089 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0090 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0091 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0092 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0093 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0094 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0095 % 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 0b70718..334ad87 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
  • applyRegularization2D
  • createKernelMatrix
  • createKernelMatrix2D
  • estimateJacobian
  • estimateUncertainty
  • fcn_JointInvfixed
  • fcn_JointInvfree
  • fcn_JointInvshape
  • fcn_fitFreeT1
  • fcn_fitFreeT1_fmin
  • fcn_fitFreeT2
  • fcn_fitFreeT2_fmin
  • fcn_fitFreeT2w
  • fcn_fitMultiModal
  • fitData2D
  • fitDataFree
  • fitDataLSQ
  • fitDataLUdecomp
  • fitDataMultiModal
  • getAAD
  • getChi2
  • getConfInterval
  • getFitErrors
  • getFitFreeJacobian
  • getLambdaFromLCurve
  • getLambdaFromRMS
  • getStudentInvCDF
  • getTLogMean
  • getTLogMean2D
  • getUncertaintyStatistics
  • runUncertaintyCalculation
  • diff --git a/doc/nucleus/functions/inversion/runUncertaintyCalculation.html b/doc/nucleus/functions/inversion/runUncertaintyCalculation.html index 34d1d6b..c2c2fb3 100644 --- a/doc/nucleus/functions/inversion/runUncertaintyCalculation.html +++ b/doc/nucleus/functions/inversion/runUncertaintyCalculation.html @@ -59,7 +59,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • onPushRun handles the callbacks to all RUN push buttons in both GUIs and
  • UncertView is an extra subGUI to show results of the uncertainty
  • updateInfo updates the information shown in all information list boxes
  • updatePlotsDistribution plots the RTD and PSD curves into NUCLEUSinv
  • updatePlotsSignal plots the raw and processed NMR signals in NUCLEUSinv
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • This function is called by: @@ -110,82 +110,92 @@

    SOURCE CODE ^'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; +0043 % disable the CALC: button to indicate a running calculation +0044 set(gui.push_handles.uncert,'String','RUNNING ...',... +0045 'BackgroundColor',[0.94 0.94 0.94],... +0046 'Enable','inactive'); pause(0.01); 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 data.results.invstd = invstd; -0071 INVdata0.results.invstd = invstd; -0072 -0073 % update INVdata -0074 INVdata{id} = INVdata0; -0075 % update GUI data -0076 setappdata(fig,'data',data); -0077 % update GUI INVdata -0078 setappdata(fig,'INVdata',INVdata); -0079 -0080 % update plots and INFO fields -0081 updatePlotsSignal; -0082 updatePlotsDistribution; -0083 updateInfo(gui.plots.SignalPanel); -0084 % if the UncertView window is open update it -0085 if ~isempty(findobj('Tag','UNCERTVIEW')) -0086 UncertView(gui.menu.extra_uncert); -0087 end -0088 else -0089 helpdlg('Cannot start calculation because there is no suitable data!',... -0090 'Perform inversion first.'); -0091 end -0092 -0093 end -0094 -0095 %------------- END OF CODE -------------- -0096 -0097 %% License: -0098 % MIT License -0099 % -0100 % Copyright (c) 2023 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. +0048 % get original inversion data +0049 INVdata0 = INVdata{id}; +0050 invstd = INVdata0.results.invstd; % results from original inversion +0051 invtype = INVdata0.invstd.invtype; +0052 +0053 % original fit parameter +0054 iparam = invstd.invparams; +0055 +0056 % uncertainty parameter +0057 uparam.id = id; +0058 uparam.time = INVdata0.results.nmrproc.t; +0059 uparam.signal = INVdata0.results.nmrproc.s; +0060 % can be set when switching the inversion method +0061 switch invtype +0062 case {'LU','NNLS'} +0063 uparam.uncert.Method = 'RMS_bound'; +0064 case 'MUMO' +0065 uparam.uncert.Method = 'RMS_free'; +0066 end +0067 uparam.uncert.Thresh = data.uncert.Thresh; +0068 uparam.uncert.chi2_range = [0 100]; +0069 uparam.uncert.mnorm_range = [0 1.5*invstd.xn]; +0070 uparam.uncert.N = data.uncert.N; +0071 uparam.uncert.Max = data.uncert.Max; +0072 invstd = estimateUncertainty(invtype,invstd,iparam,uparam); +0073 +0074 % enable the CALC. button +0075 set(gui.push_handles.uncert,'String','CALC.',... +0076 'BackgroundColor','g','Enable','on','Callback',@onPushRun); +0077 setappdata(fig,'gui',gui); +0078 +0079 % save updated inversion results +0080 data.results.invstd = invstd; +0081 INVdata0.results.invstd = invstd; +0082 +0083 % update INVdata +0084 INVdata{id} = INVdata0; +0085 % update GUI data +0086 setappdata(fig,'data',data); +0087 % update GUI INVdata +0088 setappdata(fig,'INVdata',INVdata); +0089 +0090 % update plots and INFO fields +0091 updatePlotsSignal; +0092 updatePlotsDistribution; +0093 updateInfo(gui.plots.SignalPanel); +0094 % if the UncertView window is open update it +0095 if ~isempty(findobj('Tag','UNCERTVIEW')) +0096 UncertView(gui.menu.extra_uncert); +0097 end +0098 else +0099 helpdlg('Cannot start calculation because there is no suitable data!',... +0100 'Perform inversion first.'); +0101 end +0102 +0103 end +0104 +0105 %------------- END OF CODE -------------- +0106 +0107 %% License: +0108 % MIT License +0109 % +0110 % Copyright (c) 2023 Thomas Hiller 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. +0112 % Permission is hereby granted, free of charge, to any person obtaining a copy +0113 % of this software and associated documentation files (the "Software"), to deal +0114 % in the Software without restriction, including without limitation the rights +0115 % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +0116 % copies of the Software, and to permit persons to whom the Software is +0117 % furnished to do so, subject to the following conditions: +0118 % +0119 % The above copyright notice and this permission notice shall be included in all +0120 % copies or substantial portions of the Software. +0121 % +0122 % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +0123 % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +0124 % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +0125 % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +0126 % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +0127 % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +0128 % SOFTWARE.
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/nucleus/functions/modeling/addNoiseToSignal.html b/doc/nucleus/functions/modeling/addNoiseToSignal.html index 533d50b..cbc6d5f 100644 --- a/doc/nucleus/functions/modeling/addNoiseToSignal.html +++ b/doc/nucleus/functions/modeling/addNoiseToSignal.html @@ -65,7 +65,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • updateNMRsignals adds noise to the forward NMR signals and scales the
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • +
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • updateNMRsignals adds noise to the forward NMR signals and scales the
  • estimateUncertainty calculates pseudo uncertainty estimates for multi
  • diff --git a/doc/nucleus/functions/modeling/getMultivariateGaussian.html b/doc/nucleus/functions/modeling/getMultivariateGaussian.html new file mode 100644 index 0000000..23d035f --- /dev/null +++ b/doc/nucleus/functions/modeling/getMultivariateGaussian.html @@ -0,0 +1,149 @@ + + + + Description of getMultivariateGaussian + + + + + + + + + + + +

    getMultivariateGaussian +

    + +

    PURPOSE ^

    +
    + +

    SYNOPSIS ^

    +
    function pdf = getMultivariateGaussian(X,mu,sigma)
    + +

    DESCRIPTION ^

    +
    MULTIVARIATEGAUSSIAN Computes the probability density function of the
    +multivariate gaussian distribution.%
    +
    + Syntax:
    +       pdf = getMultivariateGaussian(X,mu,sigma)
    +
    + Inputs:
    +       X - n x d -> (x,y,...) vectors
    +       mu - 1 x d -> mean values
    +       sigma - d x d covariance matrix
    +
    + Outputs:
    +       pdf - probability density function
    +
    + Example:
    +       p = getMultivariateGaussian([-1 0;0 0;1 0],[0 0],[1 0;0 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: + + + + + +

    SOURCE CODE ^

    +
    0001 function pdf = getMultivariateGaussian(X,mu,sigma)
    +0002 %MULTIVARIATEGAUSSIAN Computes the probability density function of the
    +0003 %multivariate gaussian distribution.%
    +0004 %
    +0005 % Syntax:
    +0006 %       pdf = getMultivariateGaussian(X,mu,sigma)
    +0007 %
    +0008 % Inputs:
    +0009 %       X - n x d -> (x,y,...) vectors
    +0010 %       mu - 1 x d -> mean values
    +0011 %       sigma - d x d covariance matrix
    +0012 %
    +0013 % Outputs:
    +0014 %       pdf - probability density function
    +0015 %
    +0016 % Example:
    +0017 %       p = getMultivariateGaussian([-1 0;0 0;1 0],[0 0],[1 0;0 1])
    +0018 %
    +0019 % Other m-files required:
    +0020 %       none
    +0021 %
    +0022 % Subfunctions:
    +0023 %       none
    +0024 %
    +0025 % MAT-files required:
    +0026 %       none
    +0027 %
    +0028 % See also:
    +0029 % Author: see AUTHORS.md
    +0030 % email: see AUTHORS.md
    +0031 % License: MIT License (at end)
    +0032 
    +0033 %------------- BEGIN CODE --------------
    +0034 
    +0035 % get dimension
    +0036 d = length(mu);
    +0037 
    +0038 if (size(sigma, 2) == 1) || (size(sigma, 1) == 1)
    +0039     sigma = diag(sigma);
    +0040 end
    +0041 
    +0042 % subtract mu to shift everything to (0,0)
    +0043 X = bsxfun(@minus, X, mu(:)');
    +0044 
    +0045 % calculate p
    +0046 pdf = 1 / ( sqrt(det(sigma)*((2*pi)^d)) ) * ...
    +0047     exp(-0.5 * sum(bsxfun(@times, X * pinv(sigma), X), 2));
    +0048 
    +0049 return
    +0050 
    +0051 %------------- END OF CODE --------------
    +0052 
    +0053 %% License:
    +0054 % MIT License
    +0055 %
    +0056 % Copyright (c) 2024 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.
    +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.
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/nucleus/functions/modeling/getNMRTimeVector.html b/doc/nucleus/functions/modeling/getNMRTimeVector.html index 192bcd8..96db5b5 100644 --- a/doc/nucleus/functions/modeling/getNMRTimeVector.html +++ b/doc/nucleus/functions/modeling/getNMRTimeVector.html @@ -73,7 +73,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • calculateNMR calculates the NMR signals for the full and partially saturated
  • +
  • Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data
  • calculateNMR calculates the NMR signals for the full and partially saturated
  • diff --git a/doc/nucleus/functions/modeling/menu.html b/doc/nucleus/functions/modeling/menu.html index 60aaa02..d489a65 100644 --- a/doc/nucleus/functions/modeling/menu.html +++ b/doc/nucleus/functions/modeling/menu.html @@ -18,7 +18,7 @@

    Index for nucleus\functions\modeling

    Matlab files in this directory:

    +
  • addNoiseToSignal
  • createPSD
  • getAngularityFactor
  • getAreaFactor
  • getConduct
  • getConstants
  • getCornerNMRparameter
  • getCornerSaturation
  • getCriticalPressure
  • getGeometryParameter
  • getMultivariateGaussian
  • getNMRSignal
  • getNMRTimeVector
  • getPartialSaturationMatrix
  • getPointCoordinates
  • getPressureRangeFromPSD
  • getRaRaEps
  • getSaturationFromPressure
  • getSaturationFromPressureBatch
  • getSaturationLevelData
  • getShapeFactor
  • diff --git a/externals/imagscnan/imagescnan.m b/externals/imagscnan/imagescnan.m new file mode 100644 index 0000000..d71f3c9 --- /dev/null +++ b/externals/imagscnan/imagescnan.m @@ -0,0 +1,451 @@ +function [H,HNAN] = imagescnan(varargin) +%IMAGESCNAN Scale data and display as image with uncolored NaNs. +% +% SYNTAX: +% imagescnan(U) +% imagescnan(U,...,'NanColor',CNAN) +% imagescnan(U,...,'NanMask',MNAN) +% imagescnan(U,...,IOPT) +% imagescnan(X,Y,U,...) +% [H,HNAN] = imagescnan(...); +% +% INPUT: +% U - 2 dimensional N-by-M image or N-by-M-by-3 RGB image. +% X - 2 extrema X-axis data; or the M values; or the N-by-M values +% as obtained from MESHGRID (see DESCRIPTION below). +% DEFAULT: [1 N] +% Y - 2 extrema X-axis data; or the N values; or the N-by-M values +% as obtained from MESHGRID (see DESCRIPTION below). +% DEFAULT: [1 M] +% CNAN - Color for the NaNs elements. May be a char specifier or an [R +% G B] triplet specifying the color. +% DEFAULT: invisible (axes background color) +% MNAN - Elements to be ignored besides not finite values. May be an +% scalar or a logical M-by-N matrix indicating the elements to +% be ignored. +% DEFAULT: [] +% IOPT - IMAGE function normal optional pair arguments like +% ('Parent',H) or/and CLIM like optional last argument as in +% IMAGESC. +% DEFAULT: none +% +% OUTPUT (all optional): +% H - Image handle +% HNAN - Handle of every ignored (NaN) value colored patch. +% +% DESCRIPTION: +% MATLAB function IMAGESC does not work properly with NaNs. This +% programs deals with this problem by including colored patches over +% this elements and maybe others specyfied by the user with MNAN. +% +% Besides, those functions does not work properly with X,Y values +% variable interval, but this functions does it by generating a whole +% new image of several rectangular patches, but whose centers may not +% lay in the specified coordinate (see NOTE below). This functionality +% is experimental and not recommended (see ADDITIONAL NOTES inside this +% program). +% +% In previous release, 2-dim input images were transformed into a +% 3-dim RGB image. This is not used anymore (see ADDITIONAL NOTES +% inside this file). +% +% NOTE: +% * Optional inputs use its DEFAULT value when not given or []. +% * Optional outputs may or not be called. +% * If X is a two element vector, min(X) will be the coordinate of the +% first column and max(X) of the last column. +% * If Y is a two element vector, min(Y) will be the coordinate of the +% first row and max(Y) of the last row. +% * If vector X-axis is decreasing U=fliplr(U) will be used. +% * If vector Y-axis is decreasing U=flipud(U) will be used. +% * When X or Y do not have a constant increasing/decreasing step, the +% vertices of the color rectangules are set in the middle of each +% pair of coordinates. For this reason its center may not lay on the +% specified coordinate, except on the coordinates at the edges where +% it always lays on the center. +% * To get a non-scaled image (IMAGE instead of IMAGESC) use: +% >> H = imagescnan(...); +% >> set(H,'CDataMapping','direct') +% * ADDITIONAL NOTES are included inside this file. +% +% EXAMPLE: +% % Compares with normal IMAGESC: +% N = 100; +% PNaNs = 0.10; +% U = peaks(N); +% U(round(1 + (N^2-1).*rand(N^2*PNaNs,1))) = NaN; % Adds NaNs +% subplot(221), imagesc(U) +% title('With IMAGESC: ugly NaNs') +% subplot(222), imagescnan(U) +% title('With IMAGESCNAN: uncolored NaNs') +% % Compares with SPY: +% subplot(223), spy(isnan(U)) +% title('SPY(isnan(U))') +% subplot(224), imagescnan(isnan(U),'NaNMask',0), axis equal tight +% title('SPY with IMAGESCNAN') +% +% SEE ALSO: +% IMAGE, IMAGESC, COLORBAR, IMREAD, IMWRITE +% and +% CMAPPING, CBFREEZE by Carlos Vargas +% at http://www.mathworks.com/matlabcentral/fileexchange +% +% +% --- +% MFILE: imagescnan.m +% VERSION: 2.1 (Aug 20, 2009) (download) +% MATLAB: 7.7.0.471 (R2008b) +% AUTHOR: Carlos Adrian Vargas Aguilera (MEXICO) +% CONTACT: nubeobscura@hotmail.com +% ADDITIONAL NOTES: +% * I keep getting a kind of BUG with the edges of the patched NaNs. I +% added two NOTE inside this program that may fix this problem. +% Another way is to convert the intensity matrix U into RGB colors by +% using the CMAPPING function, as used by the first version of this +% program. +% * Besides, if the matrix is too large, sometimes there is an +% undocumented failure while drawing the patch NaNs. Is recommended +% to use U = cmapping(U,[],'k','discrete') instead, and change the +% CLIM to [min(U(:)) max(U(:))]. +% * The use of not homogeneous step interval X,Y axes is not +% recommended because the program tries to put its value in the +% middle of the colored rectangule (as IMAGESC does) and soetimes the +% result may not be what the user wants. So this is for experimental +% use only. +% REVISIONS: +% 1.0 Released. (Jun 30, 2008) +% 1.1 Fixed bug when CAXIS used. Colorbar freezed colormap. Fixed +% bug in color vector input (Found by Greg King) and now +% accets RGB image as input. (Jul 14, 2008) +% 2.0 Totally rewritten code. Do not converts to RGB anymore. Do not +% freezes the colormap anymore. Do not output any colorbar. New +% X and Y variable steps accepted input. Now uses patches. (Jun +% 08, 2009) +% 2.1 Fixed bug with RGB input. Added a NOTE about the use of +% CMAPPING. (Aug 20, 2009) +% DISCLAIMER: +% imagescnan.m is provided "as is" without warranty of any kind, under +% the revised BSD license. +% Copyright (c) 2008,2009 Carlos Adrian Vargas Aguilera +% INPUTS CHECK-IN +% ------------------------------------------------------------------------- +% Initializes: +X = []; +Y = []; +CNAN = []; +MNAN = []; +ha = []; +% Checks number of inputs: +if nargin<1 + error('CVARGAS:imagescnan:notEnoughInputs',... + 'At least 1 input is required.') +elseif nargout>2 + error('CVARGAS:imagescnan:tooManyOutputs',... + 'At most 2 outputs are allowed.') +end +% Gets X,Y,U: +if ((nargin==1) || (nargin==2)) + U = varargin{1}; + varargin(1) = []; +else + if (isnumeric(varargin{1}) && isnumeric(varargin{2}) && ... + isnumeric(varargin{3})) + X = varargin{1}; + Y = varargin{2}; + U = varargin{3}; + varargin(1:3) = []; + else + U = varargin{1}; + varargin(1) = []; + end +end +% Check U: +ndim = ndims(U); +if (ndim==2) + [M,N] = size(U); + O = 1; +elseif (ndim==3) + [M,N,O] = size(U); + if (O~=3) + error('CVARGAS:imagescnan:incorrectRgbImage',... + 'RGB image must be of size M-by-N-by-3.') + end +else + error('CVARGAS:imagescnan:incorrectImageSize',... + 'Image must be 2-dimensional or a 3-dim RGB image.') +end +% Check X: +aequal = true; % Equal intervals on x-axis? +dX = []; +if isempty(X) + X = [1 N]; +else + if (ndims(X)>2) + error('CVARGAS:imagescnan:incorrectXDims',... + 'X must be a vector or a matrix as a result of MESHGRID.') + end + if any(~isfinite(X(:))) + error('CVARGAS:imagescnan:incorrectXValue',... + 'X elements must be numeric and finite.') + end + [Mx,Nx] = size(X); + if ((Mx*Nx)==2) + if X(2)(eps*max(abs(dX(:)))*1000)) + error('CVARGAS:imagescnan:incorrectXMatrix',... + 'X matrix must be as generated by MESHGRID.') + end + X = X(1,:); + elseif (~any([Mx Nx]==1) && ~((Mx*Nx)==N)) + error('CVARGAS:imagescnan:incorrectXSize',... + 'X must be an scalar or a matrix.') + end + % Forces ascending x-axis: + [X,I] = sort(X(:).'); + for k = 1:O % Fixed bug Aug 2009 + U(:,:,k) = U(:,I,k); + end + clear I + % Checks equal intervals: + dX = diff(X); + if any(abs(dX(1)-dX(2:end))>(eps*max(dX)*1000)) + if aequal + aequal = false; + end + else + X = [X(1) X(end)]; + dX = []; + end + end +end +% Check Y: +dY = []; +if isempty(Y) + Y = [1 M]; +else + if (ndims(Y)>2) + error('CVARGAS:imagescnan:incorrectYDims',... + 'Y must be a vector or a matrix as a result of MESHGRID.') + end + if any(~isfinite(Y(:))) + error('CVARGAS:imagescnan:incorrectYValue',... + 'Y elements must be numeric and finite.') + end + [My,Ny] = size(Y); + if ((My*Ny)==2) + if Y(2)(eps*max(abs(dY(:)))*1000)) + error('CVARGAS:imagescnan:incorrectYMatrix',... + 'Y matrix must be as generated by MESHGRID.') + end + Y = Y(:,1); + elseif (~any([My Ny]==1) && ~((My*Ny)==M)) + error('CVARGAS:imagescnan:incorrectYSize',... + 'Y must be an scalar or a matrix.') + end + % Forces ascending y-axis: + [Y,I] = sort(Y(:).'); + for k = 1:O % Fixed bug Aug 2009 + U(:,:,k) = U(I,:,k); + end + clear I + % Checks equal intervals: + dY = diff(Y); + if any(abs(dY(1)-dY(2:end))>(eps*max(dY)*1000)) + if aequal + aequal = false; + end + else + Y = [Y(1) Y(end)]; + dY = []; + end + end +end +% Checks varargin: +ind = []; +Nopt = length(varargin); +for k = 1:Nopt-1 + if (~isempty(varargin{k}) && ischar(varargin{k})) + if strncmpi(varargin{k},'NanColor',4) + CNAN = varargin{k+1}; + ind = [ind k k+1]; + elseif strncmpi(varargin{k},'NanMask',4) + MNAN = varargin{k+1}; + ind = [ind k k+1]; + elseif (strncmpi(varargin{k},'Parent',2) && isempty(CNAN)) + try + CNAN = get(varargin{k+1},'Color'); + ha = varargin{k+1}; + catch + error('CVARGAS:imagescnan:incorrectParentHandle',... + '''Parent'' must be a valid axes handle.') + end + end + end +end +varargin(ind) = []; +Nargin = length(varargin); +% Check ha: +if isempty(ha) + ha = gca; +end +% Check CNAN: +if isempty(CNAN) + CNAN = get(ha,'Color'); +elseif ischar(CNAN) + switch lower(CNAN) + case 'y', CNAN = [1 1 0]; + case 'm', CNAN = [1 0 0]; + case 'c', CNAN = [0 1 1]; + case 'r', CNAN = [1 0 0]; + case 'g', CNAN = [0 1 0]; + case 'b', CNAN = [0 0 1]; + case 'w', CNAN = [1 1 1]; + case 'k', CNAN = [0 0 0]; + otherwise + error('CVARGAS:imagescnan:incorrectNancString',... + 'Color string must be a valid color identifier. One of ''ymcrgbwk''.') + end +elseif isnumeric(CNAN) && (length(CNAN)==3) + CNAN = CNAN(:).'; % Forces row vector. +else + error('CVARGAS:imagescnan:incorrectNancInput',... + 'Not recognized CNAN input.') +end +% Check MNAN: +if isempty(MNAN) + MNAN = any(~isfinite(U),3); +else + if (ndims(MNAN)==2) + [Mm,Nm] = size(MNAN); + if ((Mm*Nm)==1) + MNAN = (any(~isfinite(U),3) | any(U==MNAN,3)); + elseif ((Mm==M) && (Nm==N) && islogical(MNAN)) + MNAN = (any(~isfinite(U),3) | MNAN); + else + error('CVARGAS:imagescnan:incorrectNanmSize',... + 'MNAN must be an scalar or a logical matrix of size M-by-N.') + end + else + error('CVARGAS:imagescnan:incorrectNanmDims',... + 'MNAN must be an scalar or a matrix.') + end +end +% ------------------------------------------------------------------------- +% MAIN +% ------------------------------------------------------------------------- +% Generates the image: +if aequal + % IMAGESC way. + H = imagesc(X,Y,U,varargin{:}); +else + % PATCH way. + % Check clim: + if (rem(Nargin,2)==1) + clim = varargin{end}; + varargin(end) = []; + if ((length(clim)~=2) || (clim(1)>clim(2))) + error('CVARGAS:imagescnan:incorrectClimInput',... + 'clim must be a 2 element increasing vector.') + end + else + clim = []; + end + % Generates vertices between coordinates (coordinates may not be at the + % center of these vertices): + if (length(X)~=N) + X = (0:N-1)*((X(2)-X(1))/(N-1)) + X(1); + end + if (length(Y)~=M) + Y = (0:M-1)*((Y(2)-Y(1))/(M-1)) + Y(1); + end + if isempty(dX) + dX = diff(X); + end + if isempty(dY) + dY = diff(Y); + end + [X,Y] = meshgrid([X(1)-dX(1)/2 X+dX([1:N-1 N-1])/2],... + [Y(1)-dY(1)/2 Y+dY([1:M-1 M-1])/2]); + + % Generates faces: + ind = (1:(M+1)*N)'; + ind(M+1:M+1:end) = []; + + % Generates patches: + H = patch(... + 'Vertices' ,[X(:) Y(:)],... + 'Faces' ,[ind ind+1 ind+M+2 ind+M+1],... + 'FaceVertexCData',U(:),... + 'FaceColor' ,'flat',... + 'EdgeColor' ,'none',... % NOTE: Sometimes this is not required. + varargin{:}); + set(ha,... + 'YDir' ,'reverse',... + 'View' ,[0 90],... + 'Box' ,'on',... + 'Layer','top') + axis(ha,'tight') + + % Sets clim: + if ~isempty(clim) + set(ha,'CLim',clim) + else + set(ha,'CLimMode','auto') + end + +end +% Adds NaNs patches: +if any(MNAN(:)) + if aequal + % dX and dY is constant: + [MNAN,NNAN] = ind2sub([M,N],find(MNAN)); + Nnan = length(MNAN); + dX = (X(2)-X(1))/(N-1)/2; + dY = (Y(2)-Y(1))/(M-1)/2; + HNAN = patch(repmat((X(1)+(NNAN(:)'-1)*(2*dX)),4,1) + ... + (repmat([-1 1 1 -1]'*dX,1,Nnan)),... + repmat((Y(1)+(MNAN(:)'-1)*(2*dY)),4,1) + ... + (repmat([1 1 -1 -1]'*dY,1,Nnan)),... + CNAN,... + 'EdgeColor',CNAN,... 'EdgeColor','none',... + varargin{1:Nargin-rem(Nargin,2)}); + else + % dX and/or dY is not constant: + MNAN = find(MNAN); + HNAN = patch(... + 'Vertices' ,[X(:) Y(:)],... + 'Faces' ,[ind(MNAN) ind(MNAN)+1 ind(MNAN)+M+2 ind(MNAN)+M+1],... + 'FaceColor' ,CNAN,... + 'EdgeColor' ,'none',... 'EdgeColor',CNAN,... % NOTE: may be better? + varargin{:}); + end +else + HNAN = []; +end + +% OUTPUTS CHECK-OUT +% ------------------------------------------------------------------------- +% Clears outputs?: +if (nargout==0) + clear H +end +% [EOF] imagescnan.m \ No newline at end of file diff --git a/functions/import/LoadNMRData_dart.m b/functions/import/LoadNMRData_dart.m index a3a4a4f..ef65ae8 100644 --- a/functions/import/LoadNMRData_dart.m +++ b/functions/import/LoadNMRData_dart.m @@ -38,13 +38,13 @@ %------------- BEGIN CODE -------------- %% start processing the files -% load the Matlab mat-file -data = load(fullfile(in.path,in.name)); -file = dir(fullfile(in.path,in.name)); switch in.version - case 1 + % load the Matlab mat-file + data = load(fullfile(in.path,in.name)); + file = dir(fullfile(in.path,in.name)); + % init stuff parData = cell(1,1); tmp = cell(1,1); @@ -52,7 +52,7 @@ if size(data.se_vector_wc,2) > 1 % command line output disp([in.name,': importing NMR files ...']); - + nmrData = cell(1,size(data.se_vector_wc,2)); for i = 1:size(data.se_vector_wc,2) % calculate amplitudes from water contents with the @@ -62,13 +62,13 @@ elseif extras.freq(i) <= 4.4e+05 && data.extras.freq(i) >= 4.2e+05 % frequency 2 se_vector_amp = data.se_vector_wc(:,i)./8.429; end - + % get file statistics nmrData{i}.datfile = file.name; nmrData{i}.date = file.date; nmrData{i}.datenum = file.datenum; nmrData{i}.bytes = file.bytes; - + % save the NMR data nmrData{i}.flag = 'T2'; nmrData{i}.T1IRfac = 1; @@ -77,14 +77,14 @@ nmrData{i}.raw.time = data.time; nmrData{i}.raw.signal = se_vector_amp; nmrData{i}.phase = data.extras.phase(i); - + % create parameter data parData{i}.acq_params_Tr = data.acq_params.Tr; parData{i}.depth = data.depth(i); parData{i}.Qs = data.extras.Qs(i); parData{i}.DCbus = data.extras.DC_bus(i); parData{i}.freq = data.extras.freq(i); - + fields = fieldnames(parData{i}); for j = 1:size(fields,1) tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',... @@ -93,12 +93,12 @@ d{1} = tmp; parData{i}.all = d; clear d tmp - + % command line output disp([in.name,': importing NMR files ',sprintf('%03d',i),... ' / ',sprintf('%03d',size(data.se_vector_wc,2))]); end - + else % calculate amplitudes from water contents with the % frequency-specific multiplication factors @@ -107,13 +107,13 @@ elseif extras.freq <= 4.4e+05 && extras.freq >= 4.2e+05 % frequency 2 se_vector_amp = data.se_vector_wc./8.429; end - + % get file statistics nmrData{1}.datfile = file.name; nmrData{1}.date = file.date; nmrData{1}.datenum = file.datenum; nmrData{1}.bytes = file.bytes; - + % save the NMR data nmrData{1}.flag = 'T2'; nmrData{1}.T1IRfac = 1; @@ -122,14 +122,14 @@ nmrData{1}.raw.time = data.time; nmrData{1}.raw.signal = se_vector_amp; nmrData{1}.phase = data.extras.phase; - + % create parameter data parData{1}.acq_params_Tr = data.acq_params.Tr; parData{1}.depth = data.depth; parData{1}.Qs = data.extras.Qs; parData{1}.DCbus = data.extras.DC_bus; parData{1}.freq = data.extras.freq; - + fields = fieldnames(parData{1}); for j = 1:size(fields,1) tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',... @@ -138,8 +138,12 @@ d{1} = tmp; parData{1}.all = d; end - + case 2 + % load the Matlab mat-file + data = load(fullfile(in.path,in.name)); + file = dir(fullfile(in.path,in.name)); + % init stuff parData = cell(1,size(data.jpd.stack.se,1)); tmp = cell(1,1); @@ -147,28 +151,28 @@ if size(data.jpd.stack.se,1) > 1 % command line output disp([in.name,': importing NMR files ...']); - + nmrData = cell(1,size(data.jpd.stack.se,1)); - for i = 1:size(data.jpd.stack.se,1) % loop over all depths + for i = 1:size(data.jpd.stack.se,1) % loop over all depths % get file statistics nmrData{i}.datfile = file.name; nmrData{i}.date = datestr(data.jpd.acq_time(i)); nmrData{i}.datenum = data.jpd.acq_time(i); nmrData{i}.bytes = file.bytes; - + % save the NMR data nmrData{i}.flag = 'T2'; nmrData{i}.T1IRfac = 1; nmrData{i}.time = data.jpd.stack.time(1,1:end)'; - nmrData{i}.signal = data.jpd.stack.se(i,1:end)'; + nmrData{i}.signal = data.jpd.stack.se(i,1:end)'; nmrData{i}.raw.time = data.jpd.stack.time(1,1:end)'; nmrData{i}.raw.signal = data.jpd.stack.se(i,1:end)'; nmrData{i}.phase = 0; - + % create parameter data parData{i}.acq_params_Tr = 4; parData{i}.depth = data.jpd.depth_raw(i); - + fields = fieldnames(parData{i}); for j = 1:size(fields,1) tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(i),'}.',fields{j}]))]; @@ -176,19 +180,19 @@ d{1} = tmp; parData{i}.all = d; clear d tmp - + % command line output disp([in.name,': importing NMR files ',sprintf('%03d',i),... - ' / ',sprintf('%03d',size(data.jpd.stack.se,1))]); + ' / ',sprintf('%03d',size(data.jpd.stack.se,1))]); end - - else + + else % get file statistics nmrData{1}.datfile = file.name; nmrData{1}.date = file.date; nmrData{1}.datenum = file.datenum; nmrData{1}.bytes = file.bytes; - + % save the NMR data nmrData{1}.flag = 'T2'; nmrData{1}.T1IRfac = 1; @@ -197,20 +201,23 @@ nmrData{1}.raw.time = data.jpd.stack.time(1,1:end)'; nmrData{1}.raw.signal = data.jpd.stack.se(1,1:end)'; nmrData{1}.phase = 0; - + % create parameter data parData{1}.acq_params_Tr = 4; parData{1}.depth = data.jpd.depth_raw(1); - + fields = fieldnames(parData{1}); for j = 1:size(fields,1) tmp{j,1} = [fields{j},'=',num2str(eval(['parData{',num2str(1),'}.',fields{j}]))]; end d{1} = tmp; - parData{1}.all = d; + parData{1}.all = d; end case 3 % University of Vienna + % load the Matlab mat-file + data = load(fullfile(in.path,in.name)); + file = dir(fullfile(in.path,in.name)); disp([in.name,': importing NMR data ...']); @@ -218,7 +225,7 @@ tmp = cell(1,1); nmrData = cell(1,numel(data.jpd.depth)); parData = cell(1,numel(data.jpd.depth)); - + for i = 1:numel(data.jpd.depth) % loop over all depths % get file statistics nmrData{i}.datfile = file.name; @@ -258,6 +265,51 @@ disp([in.name,': importing NMR data from depth: ',... sprintf('%3.2f',data.jpd.depth(i)),' ',data.jpd.depth_units]); end + + case 4 % Aarhus T1T2 + % read the data file + datafile = dir(fullfile(in.path,in.name)); + [data,parData] = LoadDataFile(in.path,in.name,in.T1T2); + + % get file statistics + nmrData.datfile = datafile.name; + nmrData.date = datafile.date; + nmrData.datenum = datafile.datenum; + nmrData.bytes = datafile.bytes; + + % save the NMR data + nmrData.flag = data.flag; + nmrData.T1IRfac = 1; + nmrData.time = data.time; + nmrData.signal = data.signal; + nmrData.raw = data.raw; + if strcmp(in.T1T2,'T2') + nmrData.phase = data.phase; + end + + case 5 % Dart T2 logging + % read the data file + datafile = dir(fullfile(in.path,in.name)); + [data,parData] = LoadDataFileLogging(in.path,in.name,in.T1T2); + + nmrData = cell(1,1); + for nn = 1:numel(data) + % get file statistics + nmrData{nn}.datfile = datafile.name; + nmrData{nn}.date = datafile.date; + nmrData{nn}.datenum = datafile.datenum; + nmrData{nn}.bytes = datafile.bytes; + + % save the NMR data + nmrData{nn}.flag = data{nn}.flag; + nmrData{nn}.T1IRfac = 1; + nmrData{nn}.time = data{nn}.time; + nmrData{nn}.signal = data{nn}.signal; + nmrData{nn}.raw = data{nn}.raw; + if strcmp(in.T1T2,'T2') + nmrData{nn}.phase = data{nn}.phase; + end + end end % save data to output struct @@ -266,6 +318,130 @@ end +%% load NMR data file +function [data,pardata] = LoadDataFile(datapath,fname,flag) + +% importdata is rather slow for row data +% A = importdata(fullfile(datapath,fname),'\t'); + +% first read the file to get the number of echos +fid = fopen(fullfile(datapath,fname)); +A0 = textscan(fid,'%f','Delimiter','\n'); +fclose(fid); +% now read all three lines +fid = fopen(fullfile(datapath,fname)); +A1 = textscan(fid,'%f',A0{1}(3)); +A2 = textscan(fid,'%f',A0{1}(3)); +A3 = textscan(fid,'%f',A0{1}(3)); +fclose(fid); +% and stitch them together +A = [A1{1}';A2{1}';A3{1}']; + +t_echo = A(1,2); +n_echo = A(1,3); +freq = A(1,4); +Nscans = A(1,5); +t_recov = A(1,57); % DART + +time = t_echo:t_echo:t_echo*n_echo; +time = time(:); +re = A(2,1:length(time)); +im = A(3,1:length(time)); +re = re(:); +im = im(:); + +data.flag = flag; +data.raw.time = time; +data.raw.signal = complex(re,im); +[data.signal,data.phase] = rotateT2phase(data.raw.signal); + +data.time = data.raw.time; + +pardata.t_echo = t_echo; +pardata.n_echo = n_echo; +pardata.t_recov = t_recov; +pardata.freq = freq; +pardata.Nscans = Nscans; +d{1}{1,1} = ['t_echo = ',num2str(t_echo)]; +d{1}{2,1} = ['n_echo = ',num2str(n_echo)]; +d{1}{3,1} = ['t_recov = ',num2str(t_recov)]; +d{1}{4,1} = ['freq = ',num2str(freq)]; +d{1}{5,1} = ['Nscans = ',num2str(Nscans)]; +pardata.all = d; + +end + +%% load NMR data file +function [data,pardata] = LoadDataFileLogging(datapath,fname,flag) + +% importdata is rather slow for row data +% A = importdata(fullfile(datapath,fname),'\t'); + +% first read the file to get the number of echos +fid = fopen(fullfile(datapath,fname)); +A0 = textscan(fid,'%f','Delimiter','\n'); +fclose(fid); + +% get the number of Echos +n_echo = A0{1}(3); +N = numel(A0{1}); +% reshape the data +A1 = reshape(A0{1},[n_echo N/n_echo]); +A2 = A1'; + +data = cell(1,1); +pardata = cell(1,1); +for nn = 1:size(A2,1)/3 + t_echo = A2(3*nn-2,2); + n_echo = A2(3*nn-2,3); + freq = A2(3*nn-2,4); + Nscans = A2(3*nn-2,5); + depth = A2(3*nn-2,9); + t_wait = A2(3*nn-2,14); + time = t_echo:t_echo:t_echo*n_echo; + re = A2(3*nn-1,1:length(time)); + im = A2(3*nn,1:length(time)); + time = time(:); + re = re(:); + im = im(:); + data{nn}.flag = flag; + data{nn}.raw.time = time; + data{nn}.raw.signal = complex(re,im); + data{nn}.time = data{nn}.raw.time; + [data{nn}.signal,data{nn}.phase] = rotateT2phase(data{nn}.raw.signal); + + pardata{nn}.t_echo = t_echo; + pardata{nn}.n_echo = n_echo; + pardata{nn}.freq = freq; + pardata{nn}.Nscans = Nscans; + pardata{nn}.depth = depth; + pardata{nn}.t_wait = t_wait; + d{1}{1,1} = ['t_echo = ',num2str(t_echo)]; + d{1}{2,1} = ['n_echo = ',num2str(n_echo)]; + d{1}{3,1} = ['freq = ',num2str(freq)]; + d{1}{4,1} = ['Nscans = ',num2str(Nscans)]; + d{1}{5,1} = ['depth = ',num2str(depth)]; + d{1}{6,1} = ['t_wait = ',num2str(t_wait)]; + pardata{nn}.all = d; +end + + +% figure; +% subplot(211); +% plot(data{1}.time,real(data{1}.signal),'k'); hold on +% plot(data{1}.time,imag(data{1}.signal),'k--','LineWidth',1); +% plot(data{3}.time,real(data{3}.signal),'r'); +% plot(data{3}.time,imag(data{3}.signal),'r--','LineWidth',1); +% set(gca,'XScale','log','YScale','lin'); +% subplot(212); +% plot(data{2}.time,real(data{2}.signal),'k'); hold on +% plot(data{2}.time,imag(data{2}.signal),'k--','LineWidth',1); +% plot(data{4}.time,real(data{4}.signal),'r'); +% plot(data{4}.time,imag(data{4}.signal),'r--','LineWidth',1); +% set(gca,'XScale','log','YScale','lin'); + +end + %------------- END OF CODE -------------- %% License: diff --git a/functions/import/LoadNMRData_driver.m b/functions/import/LoadNMRData_driver.m index 72e8e1a..1be8be4 100644 --- a/functions/import/LoadNMRData_driver.m +++ b/functions/import/LoadNMRData_driver.m @@ -9,6 +9,7 @@ % in.path - data path % in.name - file name (optional) % in.fileformat - varying +% in.version - varying (dependent on fileformat) % % Outputs: % out - output structure @@ -55,7 +56,7 @@ out = LoadNMRData_bgrmat(in); case 'corelab' out = LoadNMRData_corelab(in); - case 'dart' + case {'dart','dartSeries','dartT2logging'} out = LoadNMRData_dart(in); case 'field' out = LoadNMRData_field(in); @@ -75,11 +76,14 @@ out = LoadNMRData_ibac(in); case 'pm25' out = LoadNMRData_ibac(in); + case 'rocaT1T2' + out = LoadNMRData_rocaT1T2(in); end % if an imported T2 signal has no imaginary part, the noise is estimated % from an exponential fit if ~strcmp(in.fileformat,'heliosCPMG') && ~strcmp(in.fileformat,'heliosSeries')... + && ~strcmp(in.fileformat,'dartSeries') && ~strcmp(in.fileformat,'dartT2logging')... && (isfield(in,'T1T2') && ~strcmp(in.T1T2,'T1')) for i = 1:numel(out.nmrData) if isreal(out.nmrData{i}.signal) diff --git a/functions/import/LoadNMRData_helios.m b/functions/import/LoadNMRData_helios.m index f6573a7..6a28255 100644 --- a/functions/import/LoadNMRData_helios.m +++ b/functions/import/LoadNMRData_helios.m @@ -86,6 +86,9 @@ n_echo = A(1,3); freq = A(1,4); Nscans = A(1,5); +t_recov = A(1,9); % HELIOS +t_rep = A(1,14); % HELIOS +timestamp = A(1,42); % HELIOS time = t_echo:t_echo:t_echo*n_echo; time = time(:); @@ -97,18 +100,27 @@ data.flag = flag; data.raw.time = time; data.raw.signal = complex(re,im); -[data.signal,data.phase] = rotateT2phase(data.raw.signal); +% the HELIOS phase is generally around 140°, hence we give a range for +% finding the optimal phase angle +[data.signal,data.phase] = rotateT2phase(data.raw.signal,'stdIm',... + [deg2rad(140-25) deg2rad(140+25)]); data.time = data.raw.time; +data.raw.signal = data.signal; pardata.t_echo = t_echo; pardata.n_echo = n_echo; +pardata.t_recov = t_recov; +pardata.t_rep = t_rep; pardata.freq = freq; pardata.Nscans = Nscans; +pardata.timestamp = timestamp; d{1}{1,1} = ['t_echo = ',num2str(t_echo)]; d{1}{2,1} = ['n_echo = ',num2str(n_echo)]; -d{1}{3,1} = ['freq = ',num2str(freq)]; -d{1}{4,1} = ['Nscans = ',num2str(Nscans)]; +d{1}{3,1} = ['t_recov = ',num2str(t_recov)]; +d{1}{4,1} = ['t_rep = ',num2str(t_rep)]; +d{1}{5,1} = ['freq = ',num2str(freq)]; +d{1}{6,1} = ['Nscans = ',num2str(Nscans)]; pardata.all = d; end diff --git a/functions/import/LoadNMRData_mouselift.m b/functions/import/LoadNMRData_mouselift.m index 9dec426..ca7ad03 100644 --- a/functions/import/LoadNMRData_mouselift.m +++ b/functions/import/LoadNMRData_mouselift.m @@ -1,6 +1,6 @@ function out = LoadNMRData_mouselift(in) %LoadNMRData_mouselift loads NMR Mouse data from an original folder structure as -%generated by the NMR MOUSE when using it wogether with the lift +%generated by the NMR MOUSE when using it together with the lift % % Syntax: % out = LoadNMRData_mouselift(in) diff --git a/functions/import/LoadNMRData_rocaT1T2.m b/functions/import/LoadNMRData_rocaT1T2.m new file mode 100644 index 0000000..9d9d71c --- /dev/null +++ b/functions/import/LoadNMRData_rocaT1T2.m @@ -0,0 +1,274 @@ +function out = LoadNMRData_rocaT1T2(in) +%LoadNMRData_rocaT1T2 loads T1T2 NMR data from a typical folder structure +%produced by the Magritek Rock Core Analyzer +% +% Syntax: +% out = LoadNMRData_rocaT1T2(in) +% +% Inputs: +% in - input structure +% in.path - data path +% in.T1T2 - T1 / T2 flag +% in.fileformat - 'rocaT1T2' +% +% Outputs: +% out - output structure +% out.parData - parameter file data +% out.nmrData - NMR data +% +% Example: +% out = LoadNMRData_helios(in) +% +% Other m-files required: +% fixParameterString +% +% Subfunctions: +% LoadDataFile +% +% MAT-files required: +% none +% +% See also: NUCLEUSinv +% Author: see AUTHORS.md +% email: see AUTHORS.md +% License: MIT License (at end) + +%------------- BEGIN CODE -------------- + +%% start processing the files + +% read the data file +datafile = dir(fullfile(in.path,in.name)); +% load Parameter file +parData = LoadParameterFile(in.path,'acqu.par'); +data = LoadDataFile(in.path,in.name,in.T1T2,parData); + +nmrData = cell(1,1); +for j1 = 1:numel(data) + % get file statistics + nmrData{j1}.datfile = datafile.name; + nmrData{j1}.date = datafile.date; + nmrData{j1}.datenum = datafile.datenum; + nmrData{j1}.bytes = datafile.bytes; + + % save the NMR data + nmrData{j1}.flag = data(j1).flag; + nmrData{j1}.T1IRfac = 1; + nmrData{j1}.time = data(j1).time; + nmrData{j1}.signal = data(j1).signal; + nmrData{j1}.raw = data(j1).raw; + if strcmp(in.T1T2,'T2') + nmrData{j1}.phase = data(j1).phase; + end +end + +% save data to output struct +out.parData = parData; +out.nmrData = nmrData; + +end + +%% load NMR data file +function data = LoadDataFile(datapath,fname,flag,pardata) + +% first read the file +d = importdata(fullfile(datapath,fname)); + +% create echo time vector +time = pardata.echoTime:pardata.echoTime:pardata.echoTime*pardata.nrEchoes; +time = time(:)./1e6; % to [s] + +% swicth on/off debug plots +do_debug = false; + +%% start of DEBUG part +if do_debug + figure; %#ok<*UNRCH> + ax1 = subplot(131); + ax2 = subplot(132); + ax3 = subplot(133); + hold([ax1 ax2 ax3],'on'); + id_last = size(d,1); + id_test = round(linspace(1,id_last-1,8)); + for j1 = [id_test id_last] + re = d(j1,1:2:end); + im = d(j1,2:2:end); + + mag = abs(complex(re,im)); + + if j1 < id_last + LS = '-'; + else + LS = '--'; + end + plot(time,re','LineStyle',LS,'DisplayName',['row',sprintf('%d',j1)],'Parent',ax1); + plot(time,im','LineStyle',LS,'DisplayName',['row',sprintf('%d',j1)],'Parent',ax2); + plot(time,mag','LineStyle',LS,'DisplayName',['row',sprintf('%d',j1)],'Parent',ax3); + + end + hold([ax1 ax2 ax3],'off'); + set([ax1 ax2 ax3],'XScale','log'); + set(get(ax1,'Xlabel'),'String','time [s]'); + set(get(ax2,'Xlabel'),'String','time [s]'); + set(get(ax3,'Xlabel'),'String','time [s]'); + set(get(ax1,'Ylabel'),'String','Real part'); + set(get(ax2,'Ylabel'),'String','Imag part'); + set(get(ax3,'Ylabel'),'String','Magntiude sqrt(Re^2+Im^2)'); + + figure; + ax1 = subplot(131); + ax2 = subplot(132); + ax3 = subplot(133); + hold([ax1 ax2 ax3],'on'); + for j1 = id_test + re = d(j1,1:2:end)-d(id_last,1:2:end); + im = d(j1,2:2:end)-d(id_last,2:2:end); + + mag = abs(complex(re,im)); + + plot(time,re','DisplayName',['row',sprintf('%d',j1)],'Parent',ax1); + plot(time,im','DisplayName',['row',sprintf('%d',j1)],'Parent',ax2); + plot(time,mag','DisplayName',['row',sprintf('%d',j1)],'Parent',ax3); + + end + hold([ax1 ax2 ax3],'off'); + set([ax1 ax2 ax3],'XScale','log'); + set(get(ax1,'Xlabel'),'String','time [s]'); + set(get(ax2,'Xlabel'),'String','time [s]'); + set(get(ax3,'Xlabel'),'String','time [s]'); + set(get(ax1,'Ylabel'),'String','Real part'); + set(get(ax2,'Ylabel'),'String','Imag part'); + set(get(ax3,'Ylabel'),'String','Magntiude sqrt(Re^2+Im^2)'); +end +% end of DEBUG part + +% +% correction after Hürliman 2001, JMR 148 +% last row is the correction signal +dref = d(end,:); +% the data without the last row +d = d(1:end-1,:); +% subtract the correction signal from all other signals +d = d - dref; + +% rotate the longest delay time (last row) and get its phase +dlong = complex(d(end,1:2:end),d(end,2:2:end)); +[dlong_rot,dlong_phase] = rotateT2phase(dlong); + +if do_debug + figure; + subplot(121); + plot(time,real(dlong)); hold on + plot(time,imag(dlong)); + xlabel('time [s]'); + ylabel('amplitude'); + title('from file'); + subplot(122); + plot(time,real(dlong_rot)); hold on + plot(time,imag(dlong_rot)); + xlabel('time [s]'); + ylabel('amplitude'); + title('after rotation'); + + plotphase = zeros(pardata.tauSteps,1); +end + +data = struct; +for j1 = 1:pardata.tauSteps + re = d(j1,1:2:end); + im = d(j1,2:2:end); + re = re(:); + im = im(:); + data(j1).flag = flag; + data(j1).raw.time = time; + data(j1).time = time; + + tmp_s = complex(re,im); + + % rotate the signal with an angle within reference phase +- 5deg + [tmp_s,tmp_phase] = rotateT2phase(tmp_s,'stdIm',... + [dlong_phase-deg2rad(5) dlong_phase+deg2rad(5)]); + + % save the data + data(j1).raw.signal = tmp_s; + data(j1).signal = data(j1).raw.signal; + data(j1).phase = tmp_phase; + + if do_debug + plotphase(j1) = tmp_phase; + end +end +if do_debug + figure; + plot(rad2deg(plotphase)); + xlabel('row number'); + ylabel('phase angle [deg]'); + + figure; + ax1 = subplot(131); + ax2 = subplot(132); + ax3 = subplot(133); + hold([ax1 ax2 ax3],'on'); + for j1 = id_test + re = real(data(j1).raw.signal); + im = imag(data(j1).raw.signal); + + mag = abs(complex(re,im)); + + plot(time,re','DisplayName',['row',sprintf('%d',j1)],'Parent',ax1); + plot(time,im','DisplayName',['row',sprintf('%d',j1)],'Parent',ax2); + plot(time,mag','DisplayName',['row',sprintf('%d',j1)],'Parent',ax3); + + end + hold([ax1 ax2 ax3],'off'); + set([ax1 ax2 ax3],'XScale','log'); + set(get(ax1,'Xlabel'),'String','time [s]'); + set(get(ax2,'Xlabel'),'String','time [s]'); + set(get(ax3,'Xlabel'),'String','time [s]'); + set(get(ax1,'Ylabel'),'String','Real part'); + set(get(ax2,'Ylabel'),'String','Imag part'); + set(get(ax3,'Ylabel'),'String','Magntiude sqrt(Re^2+Im^2)'); +end + +end + +%% load parameter file +function [data] = LoadParameterFile(datapath,fname) + +fid = fopen(fullfile(datapath,fname)); +d = textscan(fid,'%s','Delimiter','\n'); +fclose(fid); + +for i = 1:size(d{1},1) + str = char(d{1}(i)); + str = fixParameterString(str); + eval(['data.',str,';']); %#ok +end +data.all = d; + +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. diff --git a/functions/import/rotateT2phase.m b/functions/import/rotateT2phase.m index b88a0e5..35898ea 100644 --- a/functions/import/rotateT2phase.m +++ b/functions/import/rotateT2phase.m @@ -1,4 +1,4 @@ -function [s_rot,alpha] = rotateT2phase(s) +function [s_rot,alpha] = rotateT2phase(s,varargin) %rotateT2phase rotateT2phase rotates the complex NMR T2 signal so that the imaginary %part is zero. % @@ -31,20 +31,35 @@ %------------- BEGIN CODE -------------- +%% +method = 'minReIm'; +if nargin > 1 + method = varargin{1}; +end +range = [-pi pi]; +if nargin > 2 + range = varargin{2}; +end + %% only proceed if signal is complex if ~isreal(s) % fminsearch options options = optimset('MaxFunEvals',100,'MaxIter',100,'TolFun',1e-6,'TolX',1e-6); % let fminsearch minimize fun1 - [alpha,~,~,~] = fminsearch(@(alpha) fun1(alpha,s,'minReIm'),pi/18,options); + % method = 'maxRe'; + % [alpha,~,~,~] = fminsearch(@(alpha) fun1(alpha,s(1:end),method),pi/18,options); + + [alpha,~,~,~] = fminsearchbnd(@(alpha) fun1(alpha,s(1:end),method),... + pi/18,range(1),range(2),options); % s_rot is the rotated signal s_rot = s .* exp(1i*alpha); % if the real part is negative rotate by 180° - if real(s_rot(1)) < 0 - s_rot = s_rot .* exp(1i*pi); - end + % if real(s_rot(1)) < 0 + % s_rot = s_rot .* exp(1i*pi); + % alpha = alpha + pi; + % end else % do nothing s_rot = s; @@ -71,7 +86,7 @@ t0 = zeros(size(s,1),1); t0 = t0(:); % s_rot is the rotated signal - s_rot = s .* exp(1i*alpha); + s_rot = s .* exp(1i*alpha); % create residuals residuali = t0-imag(s_rot); residualr = t0-real(s_rot); diff --git a/functions/interface/ConductView.m b/functions/interface/ConductView.m index 372e6b5..573eea2 100644 --- a/functions/interface/ConductView.m +++ b/functions/interface/ConductView.m @@ -88,12 +88,15 @@ function ConductView(src,~) if isempty(fig_conduct) % draw the figure on top of NUCLEUS fig_conduct = figure('Name','NUCLEUS - ConductView',... - 'NumberTitle','off','ToolBar','none','Tag','CONDUCT'); + 'NumberTitle','off','ToolBar','none','Menubar','none','Tag','CONDUCT'); pos0 = get(fig,'Position'); - pos1 = get(fig_conduct,'Position'); cent(1) = (pos0(1)+pos0(3)/2); cent(2) = (pos0(2)+pos0(4)/2); - set(fig_conduct,'Position',[cent(1)-pos0(3)/3 pos0(2) pos0(3)/1.5 pos0(4)]); + set(fig_conduct,'Position',[cent(1)-pos0(3)/3 pos0(2)+22 pos0(3)/1.5 pos0(4)-22]); + + gui.menu.view = uimenu(fig_conduct,'Label','View'); + gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',... + 'Callback',@onMenuView); % create the layout gui.main = uix.HBox('Parent',fig_conduct,... diff --git a/functions/interface/Inv2DView.m b/functions/interface/Inv2DView.m new file mode 100644 index 0000000..d7d9a6e --- /dev/null +++ b/functions/interface/Inv2DView.m @@ -0,0 +1,1624 @@ +function Inv2DView(src,~) +%Inv2DView is an extra subGUI to calculate 2D inversion of T1-T2 data +% +% Syntax: +% Inv2DView +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% Inv2DView(src,~) +% +% Other m-files required: +% beautifyAxes +% clearAllAxes +% displayStatusText +% fitData2D +% imagescnan +% onListboxData +% onRadioGates +% updatePlotsSignal; +% updatePlotsDistribution; +% updateInfo; +% +% Subfunctions: +% findApproxTlgmAmplitude +% tv_closeme +% tv_estimateIRtype +% tv_getTLGM +% tv_onCheckDCM +% tv_onEditValue +% tv_onPopupIRType +% tv_onPopupT1Type +% tv_onPushRun +% tv_onPushSave +% tv_onPushView +% tv_onPushUpdate +% tv_onRadioLogLin +% tv_plotResults +% tv_plotRawData +% tv_prepareRawData +% tv_setAxesScaling +% +% 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; + +%% get GUI data from NUCLEUS +data = nucleus.data.inv2D; + +% check if the figure is already open +fig_T1T2map = findobj('Tag','2DINV'); +% if not, create it +if isempty(fig_T1T2map) + % draw the figure on top of NUCLEUSinv + fig_T1T2map = figure('Name','NUCLEUSinv - 2D Inversion',... + 'NumberTitle','off','Resize','on','ToolBar','none',... + 'Tag','2DINV','CloseRequestFcn',@tv_closeme,... + 'MenuBar','none'); + pos0 = get(figh_nucleus,'Position'); + cent(1) = (pos0(1)+pos0(3)/2); + cent(2) = (pos0(2)+pos0(4)/2); + posf = [cent(1)-pos0(3)/2.5 pos0(2)+22 pos0(3)/1.25 pos0(4)-22]; + % posf = pos0; + set(fig_T1T2map,'Position',posf); + + gui.menu.view = uimenu(fig_T1T2map,'Label','View'); + gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',... + 'Callback',@onMenuView); + + cpanel_w = 175; + + % create the main layout + gui.main = uix.HBox('Parent',fig_T1T2map,'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',[350 -1 ]); + + % waitbar indicating the loading of the GUI + steps = 4; + hwb = waitbar(0,'loading ...','Name','T1T2 2DInv GUI 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'); + + % --- properties panel --- + waitbar(1/steps,hwb,'loading GUI elements - properties'); + gui.panels.prop.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Properties','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle); + gui.panels.prop.VBox = uix.VBox('Parent',gui.panels.prop.main,... + 'Spacing',3,'Padding',3); + + % D coeff. + gui.panels.prop.HBox1 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',['Diffusion coeff. [10',char(hex2dec('207B')),... + char(hex2dec('2079')),' m',char(hex2dec('00B2')),'/s]']); + uix.Empty('Parent',gui.panels.prop.HBox1); + tstr = 'Set diffusion coefficient.'; + gui.edit_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,... + 'Style','edit','String',sprintf('%4.3f',data.prop.D*1e9),... + 'FontSize',myui.fontsize,'Tag','diff',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.prop.HBox1,'Widths',[cpanel_w -1 -1]); + + % Gradient + gui.panels.prop.HBox2 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Gradient [T/m]"); + uix.Empty('Parent',gui.panels.prop.HBox2); + tstr = 'Set device gradient.'; + gui.edit_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,... + 'Style','edit','String',sprintf('%d',data.prop.G0),... + 'FontSize',myui.fontsize,'Tag','gradient',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.prop.HBox2,'Widths',[cpanel_w -1 -1]); + + % echo time + gui.panels.prop.HBox3 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Echo time tE [µs]"); + uix.Empty('Parent',gui.panels.prop.HBox3); + tstr = 'Set echo time tE.'; + gui.edit_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,... + 'Style','edit','String',sprintf('%d',data.prop.te*1e6),... + 'FontSize',myui.fontsize,'Tag','echo_time',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off',... + 'Callback',@tv_onEditValue); + set(gui.panels.prop.HBox3,'Widths',[cpanel_w -1 -1]); + + % first and last echo + gui.panels.prop.HBox4 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.first = uicontrol('Parent',gui.panels.prop.HBox4,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"T2 echoes - first | last"); + tstr = 'Set first / last echo of all T2 signals.'; + gui.edit_handles.first = uicontrol('Parent',gui.panels.prop.HBox4,... + 'Style','edit','String',sprintf('%d',data.prop.first),... + 'FontSize',myui.fontsize,'Tag','first',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + gui.edit_handles.last = uicontrol('Parent',gui.panels.prop.HBox4,... + 'Style','edit','String',sprintf('%d',data.prop.last),... + 'FontSize',myui.fontsize,'Tag','last',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.prop.HBox4,'Widths',[cpanel_w -1 -1]); + + % --- inversion panel --- + waitbar(2/steps,hwb,'loading GUI elements - 2D inversion'); + gui.panels.inv.main = uix.BoxPanel('Parent',gui.left,... + 'Title','2D inversion settings','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle); + gui.panels.inv.VBox = uix.VBox('Parent',gui.panels.inv.main,... + 'Spacing',3,'Padding',3); + + % T1type + gui.panels.inv.HBox0 = uix.HBox('Parent',gui.panels.inv.VBox,... + 'Spacing',3); + gui.text_handles.T1type = uicontrol('Parent',gui.panels.inv.HBox0,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T1 type (SR / IR)'); + tstr = 'Choose between Saturation and Inversion Recovery.'; + gui.popup_handles.T1type = uicontrol('Parent',gui.panels.inv.HBox0,... + 'Style','popup','String',{'Saturation Recovery','Inversion Recovery'},... + 'Value',data.inv.T1IRfac,'FontSize',myui.fontsize,... + 'UserData',struct('Tooltipstr',tstr),'Callback',@tv_onPopupT1Type); + set(gui.panels.inv.HBox0,'Widths',[cpanel_w -1]); + + % IR kernel type + gui.panels.inv.HBox01 = uix.HBox('Parent',gui.panels.inv.VBox,... + 'Spacing',3); + gui.text_handles.IRtype = uicontrol('Parent',gui.panels.inv.HBox01,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','IR kernel type'); + tstr = 'Choose IR kernel type.'; + gui.popup_handles.IRtype = uicontrol('Parent',gui.panels.inv.HBox01,... + 'Style','popup','String',{'1-2exp(-t/T1)','-exp(-t/T1)'},... + 'Value',1,'FontSize',myui.fontsize,... + 'UserData',struct('Tooltipstr',tstr),'Callback',@tv_onPopupIRType); + set(gui.panels.inv.HBox01,'Widths',[cpanel_w -1]); + + % RTD T1 + gui.panels.inv.HBox1 = uix.HBox('Parent',gui.panels.inv.VBox,... + 'Spacing',3); + gui.text_handles.rtdT1 = uicontrol('Parent',gui.panels.inv.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','RTD T1 - min [s] | max [s] | #'); + tstr = ""; + gui.edit_handles.rtdT1min = uicontrol('Parent',gui.panels.inv.HBox1,... + 'Style','edit','String',sprintf('%5.4f',data.inv.T1min),... + 'FontSize',myui.fontsize,'Tag','rtdT1min',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT1max = uicontrol('Parent',gui.panels.inv.HBox1,... + 'Style','edit','String',sprintf('%d',data.inv.T1max),... + 'FontSize',myui.fontsize,'Tag','rtdT1max',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT1N = uicontrol('Parent',gui.panels.inv.HBox1,... + 'Style','edit','String',sprintf('%d',data.inv.T1N),... + 'FontSize',myui.fontsize,'Tag','rtdT1N',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.inv.HBox1,'Widths',[cpanel_w -1 -1 -1]); + + % RTD T2 + gui.panels.inv.HBox2 = uix.HBox('Parent',gui.panels.inv.VBox,... + 'Spacing',3); + gui.text_handles.rtdT2 = uicontrol('Parent',gui.panels.inv.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','RTD T2 - min [s] | max [s] | #'); + tstr = ""; + gui.edit_handles.rtdT2min = uicontrol('Parent',gui.panels.inv.HBox2,... + 'Style','edit','String',sprintf('%5.4f',data.inv.T2min),... + 'FontSize',myui.fontsize,'Tag','rtdT2min',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT2max = uicontrol('Parent',gui.panels.inv.HBox2,... + 'Style','edit','String',sprintf('%d',data.inv.T2max),... + 'FontSize',myui.fontsize,'Tag','rtdT2max',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT2N = uicontrol('Parent',gui.panels.inv.HBox2,... + 'Style','edit','String',sprintf('%d',data.inv.T2N),... + 'FontSize',myui.fontsize,'Tag','rtdT2N',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.inv.HBox2,'Widths',[cpanel_w -1 -1 -1]); + + % T1 lambda / order + gui.panels.inv.HBox3 = uix.HBox('Parent',gui.panels.inv.VBox,... + 'Spacing',3); + gui.text_handles.lambdaT1 = uicontrol('Parent',gui.panels.inv.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T1 - lambda | L-order'); + tstr = ""; + gui.edit_handles.lambdaT1 = uicontrol('Parent',gui.panels.inv.HBox3,... + 'Style','edit','String',sprintf('%d',data.inv.T1lambda),... + 'FontSize',myui.fontsize,'Tag','lambdaT1',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.orderT1 = uicontrol('Parent',gui.panels.inv.HBox3,... + 'Style','edit','String',sprintf('%d',data.inv.T1order),... + 'FontSize',myui.fontsize,'Tag','orderT1',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.inv.HBox3,'Widths',[cpanel_w -1 -1]); + + % T2 lambda / order + gui.panels.inv.HBox4 = uix.HBox('Parent',gui.panels.inv.VBox,... + 'Spacing',3); + gui.text_handles.lambdaT2 = uicontrol('Parent',gui.panels.inv.HBox4,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T2 - lambda | L-order'); + tstr = ""; + gui.edit_handles.lambdaT2 = uicontrol('Parent',gui.panels.inv.HBox4,... + 'Style','edit','String',sprintf('%d',data.inv.T2lambda),... + 'FontSize',myui.fontsize,'Tag','lambdaT2',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.orderT2 = uicontrol('Parent',gui.panels.inv.HBox4,... + 'Style','edit','String',sprintf('%d',data.inv.T2order),... + 'FontSize',myui.fontsize,'Tag','orderT2',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@tv_onEditValue); + set(gui.panels.inv.HBox4,'Widths',[cpanel_w -1 -1]); + + % RUN button + gui.panels.inv.HBox5 = uix.HBox('Parent',gui.panels.inv.VBox,... + 'Spacing',3); + uix.Empty('Parent',gui.panels.inv.HBox5); + tstr = 'RUN 2D inversion.'; + gui.push_handles.run_inv = uicontrol('Parent',gui.panels.inv.HBox5,... + 'String','RUN 2D INV','FontSize',myui.fontsize,'Tag','rtd',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackGroundColor','g','Callback',@tv_onPushRun); + set(gui.panels.inv.HBox5,'Widths',[cpanel_w -1]); + + % --- information panel --- + waitbar(3/steps,hwb,'loading GUI elements - information panel'); + gui.panels.info.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Information','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxINV,'ForegroundColor',colors.BoxTitle); + gui.panels.info.VBox = uix.VBox('Parent',gui.panels.info.main,... + 'Spacing',3,'Padding',3); + + % T1 range + gui.panels.info.HBox1 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.rangeT1 = uicontrol('Parent',gui.panels.info.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T1 range - min [s] | max [s]'); + tstr = ""; + gui.edit_handles.T1min = uicontrol('Parent',gui.panels.info.HBox1,... + 'Style','edit','String',sprintf('%5.4f',data.info.T1min),... + 'FontSize',myui.fontsize,'Tag','T1min',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.T1max = uicontrol('Parent',gui.panels.info.HBox1,... + 'Style','edit','String',sprintf('%d',data.info.T1max),... + 'FontSize',myui.fontsize,'Tag','T1max',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.info.HBox1,'Widths',[cpanel_w -1 -1]); + + % T2 range + gui.panels.info.HBox2 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.rangeT2 = uicontrol('Parent',gui.panels.info.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T2 range - min [s] | max [s]'); + tstr = ""; + gui.edit_handles.T2min = uicontrol('Parent',gui.panels.info.HBox2,... + 'Style','edit','String',sprintf('%5.4f',data.info.T2min),... + 'FontSize',myui.fontsize,'Tag','T2min',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + tstr = ""; + gui.edit_handles.T2max = uicontrol('Parent',gui.panels.info.HBox2,... + 'Style','edit','String',sprintf('%d',data.info.T2max),... + 'FontSize',myui.fontsize,'Tag','T2max',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onEditValue); + set(gui.panels.info.HBox2,'Widths',[cpanel_w -1 -1]); + + % E0 + gui.panels.info.HBox0 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.E0 = uicontrol('Parent',gui.panels.info.HBox0,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','E0 [-]'); + uix.Empty('Parent',gui.panels.info.HBox0); + tstr = ""; + gui.edit_handles.E0 = uicontrol('Parent',gui.panels.info.HBox0,... + 'Style','edit','String',sprintf('%4.3f',data.info.E0),... + 'FontSize',myui.fontsize,'Tag','E0',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off'); + set(gui.panels.info.HBox0,'Widths',[cpanel_w -1 -1]); + + % TLGM + gui.panels.info.HBox3 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.Tlgm = uicontrol('Parent',gui.panels.info.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','TLGM [s] (T1,T2)'); + tstr = ""; + gui.edit_handles.T1tlgm = uicontrol('Parent',gui.panels.info.HBox3,... + 'Style','edit','String',sprintf('%4.3f',data.info.T1tlgm),... + 'FontSize',myui.fontsize,'Tag','T1tlgm',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off'); + tstr = ""; + gui.edit_handles.T2tlgm = uicontrol('Parent',gui.panels.info.HBox3,... + 'Style','edit','String',sprintf('%4.3f',data.info.T2tlgm),... + 'FontSize',myui.fontsize,'Tag','T2tlgm',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off'); + set(gui.panels.info.HBox3,'Widths',[cpanel_w -1 -1]); + + % TLGM ratio + gui.panels.info.HBox4 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.Tlgm_ratio = uicontrol('Parent',gui.panels.info.HBox4,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','TLGM ratio T1/T2'); + uix.Empty('Parent',gui.panels.info.HBox4); + tstr = ""; + gui.edit_handles.Tlgm_ratio = uicontrol('Parent',gui.panels.info.HBox4,... + 'Style','edit','String',sprintf('%4.3f',data.info.T1tlgm/data.info.T2tlgm),... + 'FontSize',myui.fontsize,'Tag','Tlgm_ratio',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off'); + set(gui.panels.info.HBox4,'Widths',[cpanel_w -1 -1]); + + % Tmax + gui.panels.info.HBox5 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.Tmax = uicontrol('Parent',gui.panels.info.HBox5,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','TMAX [s] (T1,T2)'); + tstr = ""; + gui.edit_handles.T1tmax = uicontrol('Parent',gui.panels.info.HBox5,... + 'Style','edit','String',sprintf('%4.3f',data.info.T1tmax),... + 'FontSize',myui.fontsize,'Tag','T1tmax',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off'); + tstr = ""; + gui.edit_handles.T2tmax = uicontrol('Parent',gui.panels.info.HBox5,... + 'Style','edit','String',sprintf('%4.3f',data.info.T2tmax),... + 'FontSize',myui.fontsize,'Tag','T2tmax',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off'); + set(gui.panels.info.HBox5,'Widths',[cpanel_w -1 -1]); + + % Tmax ratio + gui.panels.info.HBox6 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.Tmax_ratio = uicontrol('Parent',gui.panels.info.HBox6,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','TMAX ratio T1/T2'); + uix.Empty('Parent',gui.panels.info.HBox6); + tstr = ""; + gui.edit_handles.Tmax_ratio = uicontrol('Parent',gui.panels.info.HBox6,... + 'Style','edit','String',sprintf('%4.3f',data.info.T1tmax/data.info.T2tmax),... + 'FontSize',myui.fontsize,'Tag','Tmax_ratio',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off'); + set(gui.panels.info.HBox6,'Widths',[cpanel_w -1 -1]); + + % log/lin axes + gui.panels.info.HBox7 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.loglin_axes = uicontrol('Parent',gui.panels.info.HBox7,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','Echo time axes'); + tstr = ""; + gui.radio_handles.log = uicontrol('Parent',gui.panels.info.HBox7,... + 'Style','radiobutton','String','log','FontSize',myui.fontsize,'Tag','log',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','on','Value',1,'Callback',@tv_onRadioLogLin); + gui.radio_handles.lin = uicontrol('Parent',gui.panels.info.HBox7,... + 'Style','radiobutton','String','lin','FontSize',myui.fontsize,'Tag','lin',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','on','Value',0,'Callback',@tv_onRadioLogLin); + set(gui.panels.info.HBox7,'Widths',[cpanel_w -1 -1]); + + % DCM for 2D plot + gui.panels.info.HBox8 = uix.HBox('Parent',gui.panels.info.VBox,... + 'Spacing',3); + gui.text_handles.dcm = uicontrol('Parent',gui.panels.info.HBox8,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','2D model data inspection'); + tstr = ""; + gui.check_handles.dcm = uicontrol('Parent',gui.panels.info.HBox8,... + 'Style','checkbox','String','activate','FontSize',myui.fontsize,'Tag','dcm',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off','Callback',@tv_onCheckDCM); + set(gui.panels.info.HBox8,'Widths',[cpanel_w -1]); + + % --- update MAIN GUI button --- + gui.panels.save.HBox1 = uix.VBox('Parent',gui.left,... + 'Spacing',3); + tstr = 'UPDATE 2D inversion data in main NUCLEUSinv GUI.'; + gui.push_handles.update = uicontrol('Parent',gui.panels.save.HBox1,... + 'String','UPDATE MAIN GUI','FontSize',myui.fontsize,'Tag','update',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onPushUpdate); + tstr = 'SAVE 2D inversion data to external file.'; + gui.push_handles.save = uicontrol('Parent',gui.panels.save.HBox1,... + 'String','SAVE RESULT','FontSize',myui.fontsize,'Tag','save',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onPushSave); + tstr = 'Export current graphics view to Figure.'; + gui.push_handles.view = uicontrol('Parent',gui.panels.save.HBox1,... + 'String','VIEW2FIG','FontSize',myui.fontsize,'Tag','view',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@tv_onPushView); + % set(gui.panels.save.HBox1,'Widths',[-1 -1]); + + % fix text vertical alignment + jh = findjobj(gui.text_handles.rtdT1); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.rangeT1); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.rtdT2); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.rangeT2); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.diff); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.gradient); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.echo_time); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.first); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.T1type); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.IRtype); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.lambdaT1); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.lambdaT2); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.E0); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.Tlgm); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.Tlgm_ratio); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.Tmax); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.Tmax_ratio); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.loglin_axes); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.dcm); + 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 28 -1; 22+4*24+6*3 22+7*24+9*4 22+9*24+11*3 28*3 -1]; + % panel header is always 22 high + set(gui.left,'Heights',heights(2,:),... + 'MinimumHeights',[22 22 22 28 0]); + + % --- plot boxes --- + waitbar(4/steps,hwb,'loading GUI elements - graphics'); + gui.rightPanel = uix.TabPanel('Parent',gui.right,... + 'BackGroundColor',colors.panelBG); + % -- tab1 + gui.tab1 = uix.GridFlex('Parent',gui.rightPanel,... + 'BackGroundColor',colors.panelBG,'Spacing',5); + + gui.pbox11 = uicontainer('Parent',gui.tab1,... + 'BackGroundColor',colors.panelBG); + gui.pbox13 = uicontainer('Parent',gui.tab1,... + 'BackGroundColor',colors.panelBG); + + gui.pbox12 = uicontainer('Parent',gui.tab1,... + 'BackGroundColor',colors.panelBG); + gui.pbox14 = uicontainer('Parent',gui.tab1,... + 'BackGroundColor',colors.panelBG); + + set(gui.tab1,'Widths',[-1 -1],'Heights',[-1 -1]); + + % -- tab2 + gui.tab2 = uix.GridFlex('Parent',gui.rightPanel,... + 'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); + + gui.pbox21 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + gui.pbox22 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + + gui.pbox23 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + gui.pbox24 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + + set(gui.tab2,'Widths',[-6 -1],'Heights',[-1 -6]); + + % -- tab3 + gui.tab3 = uix.VBoxFlex('Parent',gui.rightPanel,... + 'BackGroundColor',colors.panelBG,'Spacing',5); + gui.pbox31 = uicontainer('Parent',gui.tab3,... + 'BackGroundColor',colors.panelBG); + gui.pbox32 = uicontainer('Parent',gui.tab3,... + 'BackGroundColor',colors.panelBG); + set(gui.tab3,'Heights',[-1 -2]); + + gui.rightPanel.TabTitles = {'DATA','2D INV','FITS'}; + gui.rightPanel.TabWidth = 75; + gui.rightPanel.TabEnables = {'on','on','on'}; + + % -- plot axes -- + gui.axes11 = axes('Parent',gui.pbox11,'Box','on'); + gui.axes12 = axes('Parent',gui.pbox12,'Box','on'); + gui.axes13 = axes('Parent',gui.pbox13,'Box','on'); + gui.axes14 = axes('Parent',gui.pbox14,'Box','on'); + gui.axes2 = axes('Parent',gui.pbox22,'Box','on','Tag','2D'); + gui.axes21 = axes('Parent',gui.pbox21,'Box','on'); + gui.axes24 = axes('Parent',gui.pbox24,'Box','on'); + gui.axes31 = axes('Parent',gui.pbox31,'Box','on'); + gui.axes32 = axes('Parent',gui.pbox32,'Box','on'); + + % create data curor mode for 2D inv plot inspection + gui.dcm = datacursormode(fig_T1T2map); + gui.dcm.UpdateFcn = @(hObj,event,ax)localDcmFcn(hObj,event,gui.axes2); + gui.dcm.Enable = 'off'; + + % --- 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_T1T2map,'gui',gui); + setappdata(fig_T1T2map,'data',data); + + % minimize upper panel at startup + tmp_h = gui.myui.heights(2,:); + tmp_h(1) = gui.myui.heights(1,1); + set(gui.left,'Heights',tmp_h); + set(gui.panels.prop.main,'Minimized',true); + + % make GUI visible + delete(hwb); + set(gui.main,'Visible','on'); +else + % if the figure is already open load the GUI data + data = getappdata(fig_T1T2map,'data'); + gui = getappdata(fig_T1T2map,'gui'); +end + +% import the current data from the main NUCLEUS GUI +data.results.T1T2map = nucleus.data.import.T1T2map; +data.results.T1T2map.import = nucleus.data.import.NMR.data; + +% check if there is already 2D inversion data in the main NUCLEUS GUI +if isfield(nucleus.data,'results') && isfield(nucleus.data.results,'inv2D') + % if it is there, then load the INVdata + nucleus.INVdata = getappdata(figh_nucleus,'INVdata'); + % the 2D data is stored within the data struct of the merged T1 curve + data.results.inv2D = nucleus.INVdata{end}.results.inv2D; + % update new 2Dinv GUI data + setappdata(fig_T1T2map,'data',data); + % clear axes + clearAllAxes(fig_T1T2map); + % prepare raw data + tv_prepareRawData(fig_T1T2map); + % plot the imported raw data + tv_plotRawData(fig_T1T2map); + tv_plotResults(fig_T1T2map); +else + % set the last echo entry + data.prop.last = data.results.T1T2map.t2N; + set(gui.edit_handles.last,'String',num2str(data.prop.last)); + % update new 2Dinv GUI data + setappdata(fig_T1T2map,'data',data); + % clear axes + clearAllAxes(fig_T1T2map); + % prepare raw data + tv_prepareRawData(fig_T1T2map); + % plot the imported raw data + tv_plotRawData(fig_T1T2map); +end + +tv_estimateIRtype(fig_T1T2map); +beautifyAxes(fig_T1T2map); +end + +%% subfunction to update the edit fields +function tv_onEditValue(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); + +% get the edit field value +val = str2double(get(src,'String')); + +switch get(src,'Tag') + case {'diff','gradient','echo_time'} + data.prop.D = str2double(get(gui.edit_handles.diff,'String'))/1e9; + data.prop.G0 = str2double(get(gui.edit_handles.gradient,'String')); + data.prop.te = str2double(get(gui.edit_handles.echo_time,'String'))/1e6; + case {'first','last'} + data.prop.first = str2double(get(gui.edit_handles.first,'String')); + data.prop.last = str2double(get(gui.edit_handles.last,'String')); + % update GUI data + setappdata(figh,'data',data); + clearAllAxes(figh); + tv_prepareRawData(figh); + data = getappdata(figh,'data'); + tv_plotRawData(figh); + beautifyAxes(figh); + case {'rtdT1min','rtdT1max','rtdT1N'} + data.inv.T1min = str2double(get(gui.edit_handles.rtdT1min,'String')); + data.inv.T1max = str2double(get(gui.edit_handles.rtdT1max,'String')); + data.inv.T1N = str2double(get(gui.edit_handles.rtdT1N,'String')); + case {'rtdT2min','rtdT2max','rtdT2N'} + data.inv.T2min = str2double(get(gui.edit_handles.rtdT2min,'String')); + data.inv.T2max = str2double(get(gui.edit_handles.rtdT2max,'String')); + data.inv.T2N = str2double(get(gui.edit_handles.rtdT2N,'String')); + case 'lambdaT1' + data.inv.T1lambda = str2double(get(src,'String')); + case 'orderT1' + set(gui.edit_handles.orderT2,'String',num2str(val)); + data.inv.T1order = str2double(get(src,'String')); + data.inv.T2order = str2double(get(gui.edit_handles.orderT2,'String')); + case 'lambdaT2' + data.inv.T2lambda = str2double(get(src,'String')); + case 'orderT2' + data.inv.T2order = str2double(get(src,'String')); + case {'T1min','T1max','T2min','T2max'} + data.info.T1min = str2double(get(gui.edit_handles.T1min,'String')); + data.info.T1max = str2double(get(gui.edit_handles.T1max,'String')); + data.info.T2min = str2double(get(gui.edit_handles.T2min,'String')); + data.info.T2max = str2double(get(gui.edit_handles.T2max,'String')); + % update GUI data + setappdata(figh,'data',data); + tv_getTLGM(figh); + data = getappdata(figh,'data'); + tv_plotResults(figh); + beautifyAxes(figh); +end + +% update GUI data +setappdata(figh,'data',data); +% in case an error occurred, reset the RUN button +set(gui.push_handles.run_inv,'String','RUN 2D INV',... + 'BackgroundColor','g','Enable','on','Callback',@tv_onPushRun); +setappdata(figh,'gui',gui); +end + +%% subfunction to set the T1 type +function tv_onPopupT1Type(src,~) +figh = ancestor(src,'figure','toplevel'); +data = getappdata(figh,'data'); +gui = getappdata(figh,'gui'); + +switch get(src,'Value') + case 1 % Saturation Recovery + data.inv.T1IRfac = 1; + set(gui.popup_handles.IRtype,'Enable','off'); + case 2 % Inversion Recovery + data.inv.T1IRfac = 2; + set(gui.popup_handles.IRtype,'Enable','on'); +end + +% update GUI data +setappdata(figh,'data',data); +setappdata(figh,'gui',gui); +end + +%% subfunction to set the IR type +function tv_onPopupIRType(src,~) +figh = ancestor(src,'figure','toplevel'); +data = getappdata(figh,'data'); + +switch get(src,'Value') + case 1 % IR standard 1-2exp() + data.inv.IRtype = 1; + case 2 % IR Hürlimann -exp() + data.inv.IRtype = 2; +end + +% update GUI data +setappdata(figh,'data',data); +end + +%% subfunction to start a new uncertainty calculation +function tv_onPushRun(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +% NUCLEUSinv data +guiN = getappdata(gui.figh_nucleus,'gui'); +dataN = getappdata(gui.figh_nucleus,'data'); +% local T1T2 data +T1T2map = data.results.T1T2map; + +% prepare inversion parameter struct +param.T1T2 = 'T1T2'; % T1-T2 2D inv + +% get system properties +param.D = data.prop.D; +param.G0 = data.prop.G0; +param.te = data.prop.te; + +% IR/SR factor +param.T1IRfac = data.inv.T1IRfac; +param.IRtype = data.inv.IRtype; + +% get T1/T2 RTDs values +param.T1min = data.inv.T1min; +param.T1max = data.inv.T1max; +param.T1N = data.inv.T1N; +param.T2min = data.inv.T2min; +param.T2max = data.inv.T2max; +param.T2N = data.inv.T2N; + +% inversion/regularization settings +param.lamT1 = data.inv.T1lambda; +param.lamT2 = data.inv.T2lambda; +param.orderT1 = data.inv.T1order; +param.orderT2 = data.inv.T2order; + +% prepare data +dat = struct; +for n = 1:numel(T1T2map.t_recov) + dat(n).t = T1T2map.t2; + dat(n).s = T1T2map.E_raw_surf(n,:)'; + dat(n).noise = std(T1T2map.N_raw_surf(n,:)); + dat(n).T1 = T1T2map.t_recov(n); +end +% global noise +param.noise = std(T1T2map.N_raw_surf(:)); + +% take solver from main NUCLEUS GUI +param.solver = dataN.info.solver; +switch dataN.info.InvInfo + case 'on' + param.info = 'final'; + case 'off' + param.info = 'off'; +end + +% status bar information +switch dataN.info.solver + case 'lsqlin' + infostring = '2D Inversion using ''Optimization Toolbox'' ... '; + case 'lsqnonneg' + infostring = '2D Inversion using ''lsqnonneg'' ... '; +end +displayStatusText(guiN,infostring); + +% disable the RUN button to indicate a running inversion +set(gui.push_handles.run_inv,'String','RUNNING ...',... + 'BackgroundColor',get(gui.push_handles.update,'BackgroundColor'),... + 'Enable','off'); pause(0.01); + +tic; +% call 2D inversion +inv2D = fitData2D(dat,param); +runtime = toc; +displayStatusText(guiN,[infostring,'done | inversion took ',... + sprintf('%5.2f',runtime),' s']); + +% enable the RN button +set(gui.push_handles.run_inv,'String','RUN 2D INV',... + 'BackgroundColor','g','Enable','on','Callback',@tv_onPushRun); +setappdata(figh,'gui',gui); + +% save results +data.results.inv2D = inv2D; + +% update data +setappdata(figh,'data',data); + +% plot all 2D inversion data +tv_getTLGM(figh); +tv_plotResults(figh); +beautifyAxes(figh); +set(gui.check_handles.dcm,'Enable','on'); +end + +%% subfunction to export the 2D inversion data +function tv_onPushSave(src,~) +figh = ancestor(src,'figure','toplevel'); +% local GUI data +uvgui = getappdata(figh,'gui'); +uvdata = getappdata(figh,'data'); +% NUCLEUSinv data +data = getappdata(uvgui.figh_nucleus,'data'); + +% get data path to save inversion results +[sfile,spath] = uiputfile('*.mat','Select File for Save',... + fullfile(data.import.path,'2Dinvdata.mat')); +% if user did not cancel, procceed +if sfile > 0 + invdata = uvdata; + save(fullfile(spath,sfile),'invdata'); + disp('2D Inverions data saved to: '); + disp(fullfile(spath,sfile)); +else + disp('Save cancelled.'); +end + +end + +%% subfunction to export the current view to a figure +function tv_onPushView(src,~) +figh = ancestor(src,'figure','toplevel'); +% local GUI data +gui = getappdata(figh,'gui'); + +% opening the export figure +expfig = figure('Color',gui.myui.colors.panelBG); + +% create axes layout depending on view +switch get(gui.rightPanel,'Selection') + case 1 + % create layout + ax1 = subplot(2,2,1,'Parent',expfig); + ax2 = subplot(2,2,2,'Parent',expfig); + ax3 = subplot(2,2,3,'Parent',expfig); + ax4 = subplot(2,2,4,'Parent',expfig); + % get positions + pos1 = get(ax1,'Position'); + pos2 = get(ax2,'Position'); + pos3 = get(ax3,'Position'); + pos4 = get(ax4,'Position'); + % delete axes + delete(ax1);delete(ax2);delete(ax3);delete(ax4); + % copy GUI axes + ax1 = copyobj(gui.axes11,expfig); + ax2 = copyobj(gui.axes12,expfig); + ax3 = copyobj(gui.axes13,expfig); + ax4 = copyobj(gui.axes14,expfig); + % adjust positions + set(ax1,'Position',pos1); + set(ax2,'Position',pos2); + set(ax3,'Position',pos3); + set(ax4,'Position',pos4); + % set colorbars + colorbar(ax1,'Location','EastOutside'); + colorbar(ax2,'Location','EastOutside'); + colorbar(ax3,'Location','EastOutside'); + colorbar(ax4,'Location','EastOutside'); + case 2 + % create layout + ax1 = subplot(5,5,[1 2 3 4],'Parent',expfig); + ax2 = subplot(5,5,[6:9 11:14 16:19 21:24],'Parent',expfig); + ax3 = subplot(5,5,[10 15 20 25],'Parent',expfig); + % get positions + pos1 = get(ax1,'Position'); + pos2 = get(ax2,'Position'); + pos3 = get(ax3,'Position'); + % delete axes + delete(ax1);delete(ax2);delete(ax3); + % copy GUI axes + ax1 = copyobj(gui.axes21,expfig); + ax2 = copyobj(gui.axes2,expfig); + ax3 = copyobj(gui.axes24,expfig); + % adjust positions + set(ax1,'Position',pos1); + set(ax2,'Position',pos2); + set(ax3,'Position',pos3); + case 3 + % create layout + ax1 = subplot(7,1,[1 2],'Parent',expfig); + ax2 = subplot(7,1,[4 5 6 7],'Parent',expfig); + % get positions + pos1 = get(ax1,'Position'); + pos2 = get(ax2,'Position'); + % delete axes + delete(ax1);delete(ax2); + % copy GUI axes + ax1 = copyobj(gui.axes31,expfig); + ax2 = copyobj(gui.axes32,expfig); + % adjust positions + set(ax1,'Position',pos1); + set(ax2,'Position',pos2); +end + +end + +%% subfunction to update the main NUCLEUSinv GUI +function tv_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'); +INVdata = getappdata(uvgui.figh_nucleus,'INVdata'); +data = getappdata(uvgui.figh_nucleus,'data'); + +% loop over all signals +E_inv = zeros(size(uvdata.results.T1T2map.t_recov)); +for id = 1:numel(INVdata) + % the standard INVdata struct + INVdata{id} = []; + + % old, slow but consistent way + % trigger the listbox entry + % set(gui.listbox_handles.signal,'Value',id); + % onListboxData(gui.listbox_handles.signal); + % no gating + % which radiobutton ('log', 'lin' or 'none') + % onRadioGates(gui.radio_handles.process_gates_none); + % get the fresh data + % data = getappdata(uvgui.figh_nucleus,'data'); + + % new, fast and hopefully consistent :-) way + if id == numel(INVdata) + data.process.start = 1; + data.process.end = numel(uvdata.results.T1T2map.import{id}.time); + else + data.process.start = uvdata.prop.first; + data.process.end = uvdata.prop.last; %numel(uvdata.results.T1T2map.import{id}.time); + end + data.process.gatetype = 'raw'; + data.process.isgated = false; + % update 2Dinv GUI settings + data.inv2D.prop = uvdata.prop; + data.inv2D.inv = uvdata.inv; + data.inv2D.info = uvdata.info; + % create raw data struct + data.results.nmrraw.t = uvdata.results.T1T2map.import{id}.time; + data.results.nmrraw.s = uvdata.results.T1T2map.import{id}.signal; + if id == numel(INVdata) + data.results.nmrraw.noise = uvdata.results.T1T2map.import{id}.noise; + data.results.nmrproc.T1T2 = 'T1'; + data.results.nmrproc.T1IRfac = 2; + else + data.results.nmrraw.phase = uvdata.results.T1T2map.import{id}.phase; + data.results.nmrproc.T1T2 = 'T2'; + data.results.nmrproc.T1IRfac = 1; + end + % create proc data struct + if id == numel(INVdata) + data.results.nmrproc.start = 1; + data.results.nmrproc.end = numel(uvdata.results.T1T2map.import{id}.time); + else + data.results.nmrproc.start = uvdata.prop.first; + data.results.nmrproc.end = uvdata.prop.last; %numel(uvdata.results.T1T2map.import{id}.time); + end + data.results.nmrproc.gatetype = 'raw'; + data.results.nmrproc.isgated = false; + data.results.nmrproc.t = uvdata.results.T1T2map.import{id}.time(data.results.nmrproc.start:data.results.nmrproc.end); + data.results.nmrproc.s = real(uvdata.results.T1T2map.import{id}.signal(data.results.nmrproc.start:data.results.nmrproc.end)); + data.results.nmrproc.N = ones(size(data.results.nmrproc.s)); + if isfield(uvdata.results.T1T2map.import{id},'noise') + data.results.nmrproc.noise = uvdata.results.T1T2map.import{id}.noise; + else + range = floor(numel(data.results.nmrproc.s)/2):numel(data.results.nmrproc.s); + data.results.nmrproc.noise = std(imag(uvdata.results.T1T2map.import{id}.signal(range))); + end + data.results.nmrproc.e = data.results.nmrproc.noise*ones(size(data.results.nmrproc.s)); + if isfield(data.results.nmrproc,'W') + data.results.nmrproc = rmfield(data.results.nmrproc,'W'); + end + + % and use it for the INVdata + INVdata{id} = data; + INVdata{id} = rmfield(INVdata{id},'import'); + INVdata{id} = rmfield(INVdata{id},'info'); + INVdata{id} = rmfield(INVdata{id},'calib'); + INVdata{id} = rmfield(INVdata{id},'pressure'); + + % now add a dummy "invstd" field + if id == numel(INVdata) + % for the final merged T1 + INVdata{id}.results.invstd.fit_t = uvdata.results.T1T2map.t_recov; + INVdata{id}.results.invstd.fit_s = E_inv; + INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.E0; + INVdata{id}.results.invstd.ciE0 = NaN; + out = getFitErrors(uvdata.results.T1T2map.E_raw(:,1),E_inv,data.results.nmrproc.noise); + INVdata{id}.results.invstd.resnorm = out.resnorm; + INVdata{id}.results.invstd.residual = out.residual; + INVdata{id}.results.invstd.chi2 = out.chi2; + INVdata{id}.results.invstd.rms = out.rms; + else + % for the individual signals + INVdata{id}.results.invstd.fit_t = uvdata.results.inv2D.data(id).t; + INVdata{id}.results.invstd.fit_s = uvdata.results.inv2D.data(id).s_fit; + E_inv(id,1) = uvdata.results.inv2D.data(id).s_fit(1); + INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.data(id).s_fit(1); + INVdata{id}.results.invstd.ciE0 = NaN; + INVdata{id}.results.invstd.resnorm = uvdata.results.inv2D.data(id).resnorm; + INVdata{id}.results.invstd.residual = uvdata.results.inv2D.data(id).residual; + INVdata{id}.results.invstd.chi2 = uvdata.results.inv2D.data(id).chi2; + INVdata{id}.results.invstd.rms = uvdata.results.inv2D.data(id).rms; + end + INVdata{id}.results.invstd.lambda_out = 1; + INVdata{id}.results.invstd.xn = 0; + INVdata{id}.results.invstd.rn = 0; + INVdata{id}.results.invstd.invtype = data.invstd.invtype; + INVdata{id}.results.invstd.invparams = NaN; + if id == numel(INVdata) + INVdata{id}.results.inv2D = uvdata.results.inv2D; + else + INVdata{id}.results.inv2D = true; + end + + % color the corresponding list entries in the main GUI + strL = get(gui.listbox_handles.signal,'String'); + str1 = strL{id}; + str2 = ['',str1,'']; + strL{id} = str2; + set(gui.listbox_handles.signal,'String',strL); +end + +% update GUI INVdata +setappdata(uvgui.figh_nucleus,'INVdata',INVdata); + +% set focus on first signal +set(gui.listbox_handles.signal,'Value',1); +onListboxData(gui.listbox_handles.signal); +end + +%% subfunction zo switch x-axis scaling +function tv_onRadioLogLin(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +% get tag of the radio menu +tag = get(src,'Tag'); +val = get(src,'Value'); + +switch tag + case 'log' + switch val + case 1 % log should be used + set(gui.radio_handles.lin,'Value',0); + case 0 % lin should be used + set(gui.radio_handles.lin,'Value',1); + end + case 'lin' + switch val + case 1 % lin should be used + set(gui.radio_handles.log,'Value',0); + case 0 % log should be used + set(gui.radio_handles.log,'Value',1); + end +end +% update GUI data +setappdata(figh,'gui',gui); + +% call function to adapt the axes scaling +tv_setAxesScaling(figh); +end + +%% subfunction to activate data tips on 2D plot +function tv_onCheckDCM(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +% get tag of the radio menu +val = get(src,'Value'); + +switch val + case 1 % DCM on + gui.dcm.Enable = 'on'; + case 0 % DCM off + gui.dcm.Enable = 'off'; +end + +% update GUI data +setappdata(figh,'gui',gui); +end + +%% subfunction to switch x-axis scaling log<->lin +function tv_setAxesScaling(figh) +gui = getappdata(figh,'gui'); + +uselog = get(gui.radio_handles.log,'Value'); +switch uselog + case 1 + set(gui.axes11,'XScale','log'); + set(gui.axes12,'XScale','log'); + set(gui.axes13,'XScale','log'); + set(gui.axes14,'XScale','log'); + log_t_ticks = logspace(-5,2,8); + set(gui.axes32,'XScale','log','XTick',log_t_ticks); + case 0 + set(gui.axes11,'XScale','lin'); + set(gui.axes12,'XScale','lin'); + set(gui.axes13,'XScale','lin'); + set(gui.axes14,'XScale','lin'); + set(gui.axes32,'XScale','lin','XTickMode','auto'); +end + +end + +%% subfunction to update all plots +function tv_plotResults(figh) +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +T1T2map = data.results.T1T2map; +inv2D = data.results.inv2D; +col = gui.myui.colors; + +% clear axes +clearSingleAxis(gui.axes13); +clearSingleAxis(gui.axes14); +clearSingleAxis(gui.axes2); +clearSingleAxis(gui.axes21); +clearSingleAxis(gui.axes24); +clearSingleAxis(gui.axes31); +clearSingleAxis(gui.axes32); +hold(gui.axes13,'on'); +hold(gui.axes14,'on'); +hold(gui.axes2,'on'); +hold(gui.axes21,'on'); +hold(gui.axes24,'on'); +hold(gui.axes31,'on'); +hold(gui.axes32,'on'); + +% get T1/T2 range from GUI +T1range(1) = str2double(get(gui.edit_handles.T1min,'String')); +T1range(2) = str2double(get(gui.edit_handles.T1max,'String')); +T2range(1) = str2double(get(gui.edit_handles.T2min,'String')); +T2range(2) = str2double(get(gui.edit_handles.T2max,'String')); + +% define some axes settings +log_t_ticks = logspace(-5,2,8); +t_recov_lims = [min(T1T2map.t_recov)/2 max(T1T2map.t_recov)*2]; +p_alpha = 0.8; + +z_max = max(inv2D.f_2Dmap(:)); +% tab 2 - 2D inversion model +[X,Y] = meshgrid(inv2D.T2vec,inv2D.T1vec); +% imagescnan(X,Y,inv2D.f_2Dmap,'Parent',gui.axes2); +sh = surf(X,Y,inv2D.f_2Dmap,'Parent',gui.axes2); +sh.FaceColor = 'flat'; +sh.EdgeColor = 'none'; +plot3(inv2D.T2tlgm,inv2D.T1tlgm,z_max,'o','Color',col.FIT,'Parent',gui.axes2); +plot3(inv2D.T2tmax,inv2D.T1tmax,z_max,'+','Color',col.FIT,'Parent',gui.axes2); +plot3([1e-5 100],[1e-5 100],[z_max z_max],... + '--','Color','w','LineWidth',1,'Parent',gui.axes2); +view(gui.axes2,[0 90]); +set(gui.axes2,'XScale','log','XTick',log_t_ticks,... + 'XLim',[min(inv2D.T2vec) max(inv2D.T2vec)]); +set(gui.axes2,'YScale','log','XTick',log_t_ticks,... + 'YLim',[min(inv2D.T1vec) max(inv2D.T1vec)],'YDir','normal'); +set(get(gui.axes2,'XLabel'),'String','relaxation time T2 [s]'); +set(get(gui.axes2,'YLabel'),'String','relaxation time T1 [s]'); +set(gui.axes2,'Layer','top','XGrid','off','YGrid','off'); +colorbar(gui.axes2,'Location','EastOutside'); + +% sum along each dimension to get both RTDs +T1rtd = sum(inv2D.f_2Dmap,2); +T2rtd = sum(inv2D.f_2Dmap,1); +% find common maximum for y-axis setting +ymax = max([max(T1rtd) max(T2rtd)])*1.1; +% T1 RTD +plot(T1rtd,inv2D.T1vec,'Color',col.FIT,'Parent',gui.axes24); +amp = findApproxTlgmAmplitude(inv2D.T1vec,T1rtd,inv2D.T1tlgm); +plot([0 amp],[inv2D.T1tlgm inv2D.T1tlgm],'Color',col.FIT,'LineStyle','--',... + 'LineWidth',1,'DisplayName','Tlgm','Tag','TLGM','Parent',gui.axes24); +amp = findApproxTlgmAmplitude(inv2D.T1vec,T1rtd,inv2D.T1tmax); +plot([0 amp],[inv2D.T1tmax inv2D.T1tmax],'Color',col.FIT,'LineStyle','-.',... + 'LineWidth',1,'DisplayName','Tmax','Tag','TMAX','Parent',gui.axes24); +set(gui.axes24,'XScale','lin','XLim',[0 ymax]); +set(gui.axes24,'YScale','log','YTickLabel',''); +if T1range(1)>inv2D.T1vec(1) + xlims = get(gui.axes24,'XLim'); + % draw a transparent patch + v = [xlims(1) inv2D.T1vec(1); xlims(2) inv2D.T1vec(1); + xlims(2) T1range(1); xlims(1) T1range(1)]; + f = [1 2 3 4 1]; + patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... + 'HandleVisibility','off','Tag','infolines','Parent', gui.axes24); +end +if T1range(2)inv2D.T2vec(1) + ylims = get(gui.axes21,'YLim'); + % draw a transparent patch + v = [inv2D.T2vec(1) ylims(1);inv2D.T2vec(1) ylims(2); + T2range(1) ylims(2);T2range(1) ylims(1)]; + f = [1 2 3 4 1]; + patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... + 'HandleVisibility','off','Tag','infolines','Parent', gui.axes21); +end +if T2range(2) 0 + % possibly SR + data.inv.IRtype = 1; + data.inv.T1IRfac = 1; + set(gui.popup_handles.T1type,'Value',1); + set(gui.popup_handles.IRtype,'Enable','off'); +else + if E(end) < abs(E(1))*0.5 + % possibly IR with kernel type 2 => -exp(t/T1) + data.inv.IRtype = 2; + set(gui.popup_handles.T1type,'Value',2); + set(gui.popup_handles.IRtype,'Value',2); + else + % possibly IR with kernel type 1 => 1-2exp(t/T1) + data.inv.IRtype = 1; + data.inv.T1IRfac = 2; + set(gui.popup_handles.T1type,'Value',2); + set(gui.popup_handles.IRtype,'Value',1); + end +end + +% update GUI data +setappdata(figh,'data',data); +setappdata(figh,'gui',gui); +end + +%% adjust the data tip on the 2D axes +function txt = localDcmFcn(~,event,ax) + +if strcmp(get(ax,'Tag'),'2D') + % find indices to closest x and y data values. This requires the + % number of values in XData and YData to agree with CData size. + [~, xidx] = min(abs(event.Target.XData - event.Position(1)),[],2); + [~, yidx] = min(abs(event.Target.YData - event.Position(2)),[],1); + colorbarValue = event.Target.CData(yidx(1), xidx(1)); + % colormapIdx = round((colorbarValue - ax.CLim(1))/(ax.CLim(2)-ax.CLim(1)) * (size(ax.Colormap,1)-1) +1); + txt = sprintf('[T2,T1]: [%.2g, %.2g]\nValue: %.2g', ... + event.Position(1:2), colorbarValue); +end + +end + +%% close function +function tv_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/Mod2DView.m b/functions/interface/Mod2DView.m new file mode 100644 index 0000000..2eed685 --- /dev/null +++ b/functions/interface/Mod2DView.m @@ -0,0 +1,1161 @@ +function Mod2DView(src,~) +%Mod2DView is an extra subGUI to calculate 2D forward T1-T2 data +% +% Syntax: +% Mod2DView +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% Mod2DView(src,~) +% +% Other m-files required: +% beautifyAxes +% clearAllAxes +% displayStatusText +% fitData2D_T1T2 +% imagescnan +% +% Subfunctions: +% +% MAT-files required: +% none +% +% See also: NUCLEUSmod +% 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; + +%% get GUI data from NUCLEUS +data = nucleus.data.mod2D; + +% check if the figure is already open +fig_2Dmod = findobj('Tag','2DMOD'); +% if not, create it +if isempty(fig_2Dmod) + % draw the figure on top of NUCLEUSinv + fig_2Dmod = figure('Name','NUCLEUSmod - 2D Modeling',... + 'NumberTitle','off','Resize','on','ToolBar','none',... + 'Tag','2DMOD','CloseRequestFcn',@fv_closeme,... + 'MenuBar','none'); + pos0 = get(figh_nucleus,'Position'); + cent(1) = (pos0(1)+pos0(3)/2); + cent(2) = (pos0(2)+pos0(4)/2); + posf = [cent(1)-pos0(3)/2.5 pos0(2)+22 pos0(3)/1.25 pos0(4)-22]; + % posf = pos0; + set(fig_2Dmod,'Position',posf); + + gui.menu.view = uimenu(fig_2Dmod,'Label','View'); + gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',... + 'Callback',@onMenuView); + + cpanel_w = 190; + + % create the main layout + gui.main = uix.HBox('Parent',fig_2Dmod,'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',[400 -1 ]); + + % waitbar indicating the loading of the GUI + steps = 4; + hwb = waitbar(0,'loading ...','Name','2DMod GUI 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'); + + % --- modelling panel --- + waitbar(1/steps,hwb,'loading GUI elements - 2D modelling'); + gui.panels.mod.main = uix.BoxPanel('Parent',gui.left,... + 'Title','2D modelling settings','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.GEO,'ForegroundColor',colors.BoxTitle); + gui.panels.mod.VBox = uix.VBox('Parent',gui.panels.mod.main,... + 'Spacing',3,'Padding',3); + + % RTD T1 + gui.panels.mod.HBox1 = uix.HBox('Parent',gui.panels.mod.VBox,... + 'Spacing',3); + gui.text_handles.rtdT1 = uicontrol('Parent',gui.panels.mod.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','RTD T1 - min [s] | max [s] | #'); + tstr = ""; + gui.edit_handles.rtdT1min = uicontrol('Parent',gui.panels.mod.HBox1,... + 'Style','edit','String',sprintf('%5.4f',data.mod.T1min),... + 'FontSize',myui.fontsize,'Tag','rtdT1min',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT1max = uicontrol('Parent',gui.panels.mod.HBox1,... + 'Style','edit','String',sprintf('%d',data.mod.T1max),... + 'FontSize',myui.fontsize,'Tag','rtdT1max',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT1N = uicontrol('Parent',gui.panels.mod.HBox1,... + 'Style','edit','String',sprintf('%d',data.mod.T1N),... + 'FontSize',myui.fontsize,'Tag','rtdT1N',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + set(gui.panels.mod.HBox1,'Widths',[cpanel_w -1 -1 -1]); + + % RTD T2 + gui.panels.mod.HBox2 = uix.HBox('Parent',gui.panels.mod.VBox,... + 'Spacing',3); + gui.text_handles.rtdT2 = uicontrol('Parent',gui.panels.mod.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','RTD T2 - min [s] | max [s] | #'); + tstr = ""; + gui.edit_handles.rtdT2min = uicontrol('Parent',gui.panels.mod.HBox2,... + 'Style','edit','String',sprintf('%5.4f',data.mod.T2min),... + 'FontSize',myui.fontsize,'Tag','rtdT2min',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT2max = uicontrol('Parent',gui.panels.mod.HBox2,... + 'Style','edit','String',sprintf('%d',data.mod.T2max),... + 'FontSize',myui.fontsize,'Tag','rtdT2max',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + tstr = ""; + gui.edit_handles.rtdT2N = uicontrol('Parent',gui.panels.mod.HBox2,... + 'Style','edit','String',sprintf('%d',data.mod.T2N),... + 'FontSize',myui.fontsize,'Tag','rtdT2N',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + set(gui.panels.mod.HBox2,'Widths',[cpanel_w -1 -1 -1]); + + uix.Empty('Parent',gui.panels.mod.VBox); + % table + gui.panels.mod.HBox3 = uix.HBox('Parent',gui.panels.mod.VBox,... + 'Spacing',3); + m = data.mod.mu; + s = data.mod.sigma; + a = data.mod.amp; + table = cell(1,1); + for i = 1:data.mod.Ndist + table{i,1} = false; + table{i,2} = m(i,1); + table{i,3} = m(i,2); + table{i,4} = s{i}(1,1); + table{i,5} = s{i}(2,2); + table{i,6} = s{i}(1,2); + table{i,7} = s{i}(2,1); + table{i,8} = a(i); + end + table{1,1} = true; + data.results.mod2D.table = table; + gui.table_handles.mod = uitable('Parent',gui.panels.mod.HBox3,... + 'Data',table,... + 'ColumnFormat',({'logical' 'short' 'short' 'bank' 'bank' 'bank' 'bank' 'bank'}),... + 'ColumnEditable',[true true true true true true true true],... + 'ColumnWidth',{35 77 77 33 33 33 33 33},... + 'RowName','numbered',... + 'ColumnName',{'use' 'mX','mY','xx','yy','xy','yx','A'},... + 'UserData',struct('Tooltipstr',tstr),... + 'CellEditCallback',@fv_onEditTable,... + 'FontSize',myui.fontsize); + + % UPDATE button + % gui.panels.mod.HBox5 = uix.HBox('Parent',gui.panels.mod.VBox,... + % 'Spacing',3); + % uix.Empty('Parent',gui.panels.mod.HBox5); + % tstr = 'Update model'; + % gui.push_handles.model = uicontrol('Parent',gui.panels.mod.HBox5,... + % 'String','UPDATE MODEL','FontSize',myui.fontsize,'Tag','rtd',... + % 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + % 'BackGroundColor','g','Callback',@fv_getModel); + % set(gui.panels.mod.HBox5,'Widths',[cpanel_w -1]); + + % adjust heights + set(gui.panels.mod.VBox,'Heights',[25 25 25 -1]); + + %% --- properties panel --- + waitbar(2/steps,hwb,'loading GUI elements - properties'); + gui.panels.prop.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Properties','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.GEO,'ForegroundColor',colors.BoxTitle); + gui.panels.prop.VBox = uix.VBox('Parent',gui.panels.prop.main,... + 'Spacing',3,'Padding',3); + + % D coeff. + gui.panels.prop.HBox1 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',['Diffusion coeff. [10',char(hex2dec('207B')),... + char(hex2dec('2079')),' m',char(hex2dec('00B2')),'/s]']); + uix.Empty('Parent',gui.panels.prop.HBox1); + tstr = 'Set diffusion coefficient.'; + gui.edit_handles.diff = uicontrol('Parent',gui.panels.prop.HBox1,... + 'Style','edit','String',sprintf('%4.3f',data.prop.D*1e9),... + 'FontSize',myui.fontsize,'Tag','diff',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + set(gui.panels.prop.HBox1,'Widths',[cpanel_w -1 -1]); + + % Gradient + gui.panels.prop.HBox2 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Gradient [T/m]"); + uix.Empty('Parent',gui.panels.prop.HBox2); + tstr = 'Set device gradient.'; + gui.edit_handles.gradient = uicontrol('Parent',gui.panels.prop.HBox2,... + 'Style','edit','String',sprintf('%d',data.prop.G0),... + 'FontSize',myui.fontsize,'Tag','gradient',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + set(gui.panels.prop.HBox2,'Widths',[cpanel_w -1 -1]); + + % echo time + gui.panels.prop.HBox3 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Echo time tE [µs]"); + uix.Empty('Parent',gui.panels.prop.HBox3); + tstr = 'Set echo time tE.'; + gui.edit_handles.echo_time = uicontrol('Parent',gui.panels.prop.HBox3,... + 'Style','edit','String',sprintf('%d',data.nmr.T2te*1e6),... + 'FontSize',myui.fontsize,'Tag','echo_time',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','off',... + 'Callback',@fv_onEditValue); + set(gui.panels.prop.HBox3,'Widths',[cpanel_w -1 -1]); + + % Tbulk + gui.panels.prop.HBox4 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.Tbulk = uicontrol('Parent',gui.panels.prop.HBox4,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Bulk relaxation [s]"); + uix.Empty('Parent',gui.panels.prop.HBox4); + tstr = 'Set Tbulk value.'; + gui.edit_handles.Tbulk = uicontrol('Parent',gui.panels.prop.HBox4,... + 'Style','edit','String',sprintf('%d',data.prop.Tbulk),... + 'FontSize',myui.fontsize,'Tag','Tbulk',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + set(gui.panels.prop.HBox4,'Widths',[cpanel_w -1 -1]); + + %% --- NMR signal panel --- + waitbar(3/steps,hwb,'loading GUI elements - Signal panel'); + gui.panels.nmr.main = uix.BoxPanel('Parent',gui.left,... + 'Title','NMR signals','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.NMR,'ForegroundColor',colors.BoxTitle); + gui.panels.nmr.VBox = uix.VBox('Parent',gui.panels.nmr.main,... + 'Spacing',3,'Padding',3); + + % T1type + gui.panels.nmr.HBox0 = uix.HBox('Parent',gui.panels.nmr.VBox,... + 'Spacing',3); + gui.text_handles.T1type = uicontrol('Parent',gui.panels.nmr.HBox0,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T1 type (SR / IR)'); + tstr = 'Choose between Saturation and Inversion Recovery.'; + gui.popup_handles.T1type = uicontrol('Parent',gui.panels.nmr.HBox0,... + 'Style','popup','String',{'Saturation Recovery','Inversion Recovery'},... + 'Value',data.nmr.T1IRfac,'FontSize',myui.fontsize,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onPopupT1Type); + set(gui.panels.nmr.HBox0,'Widths',[cpanel_w -1]); + + % T1 timings + gui.panels.nmr.HBox1 = uix.HBox('Parent',gui.panels.nmr.VBox,... + 'Spacing',3); + gui.text_handles.timeT1 = uicontrol('Parent',gui.panels.nmr.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T1 recov - min [s] | max [s] | #'); + tstr = ""; + gui.edit_handles.T1trmin = uicontrol('Parent',gui.panels.nmr.HBox1,... + 'Style','edit','String',sprintf('%5.4f',data.nmr.T1trmin),... + 'FontSize',myui.fontsize,'Tag','T1trmin',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + tstr = ""; + gui.edit_handles.T1trmax = uicontrol('Parent',gui.panels.nmr.HBox1,... + 'Style','edit','String',sprintf('%d',data.nmr.T1trmax),... + 'FontSize',myui.fontsize,'Tag','T1trmax',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + tstr = ""; + gui.edit_handles.T1trN = uicontrol('Parent',gui.panels.nmr.HBox1,... + 'Style','edit','String',sprintf('%d',data.nmr.T1trN),... + 'FontSize',myui.fontsize,'Tag','T1trN',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + set(gui.panels.nmr.HBox1,'Widths',[cpanel_w -1 -1 -1]); + + % T2 timings + gui.panels.nmr.HBox2 = uix.HBox('Parent',gui.panels.nmr.VBox,... + 'Spacing',3); + gui.text_handles.timeT2 = uicontrol('Parent',gui.panels.nmr.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','T2 echo time [µs] | # echos'); + tstr = ""; + gui.edit_handles.T2te = uicontrol('Parent',gui.panels.nmr.HBox2,... + 'Style','edit','String',sprintf('%5.2f',data.nmr.T2te*1e6),... + 'FontSize',myui.fontsize,'Tag','T2te',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + tstr = ""; + gui.edit_handles.T2teN = uicontrol('Parent',gui.panels.nmr.HBox2,... + 'Style','edit','String',sprintf('%d',data.nmr.T2teN),... + 'FontSize',myui.fontsize,'Tag','T2teN',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onEditValue); + set(gui.panels.nmr.HBox2,'Widths',[cpanel_w -1 -1]); + + % noise + gui.panels.nmr.HBox3 = uix.HBox('Parent',gui.panels.nmr.VBox,... + 'Spacing',3); + gui.text_handles.noise = uicontrol('Parent',gui.panels.nmr.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','Noise settings'); + tstr = ['NMR data noise method.

    ',... + 'A noise level will be used globally for all NMR signals.
    ',... + 'A signal-to-ratio will be used individually on every single NMR signal.

    ',... + 'Available options:
    ',... + 'noise level or SNR

    ',... + 'Default value:
    ',... + 'noise level
    ']; + gui.popup_handles.noisetype = uicontrol('Parent',gui.panels.nmr.HBox3,... + 'Style','popup','String',{'noise level','SNR'},... + 'Value',1,'FontSize',myui.fontsize,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onPopupNoiseType); + tstr = ['NMR data noise.

    ',... + 'Hint:
    ',... + 'You do not need to press RUN to add noise to the NMR signals.
    ',... + 'The raw NMR signals are stored internally and the noise is
    ',... + 'applied instantaneously.

    ',... + 'Default value:
    ',... + '0
    ']; + gui.edit_handles.noise = uicontrol('Parent',gui.panels.nmr.HBox3,... + 'Style','edit','String',num2str(data.nmr.noise),'FontSize',myui.fontsize,... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.nmr.noise 1 1]),... + 'Tag','nmr_noise','Enable','on','Callback',@fv_onEditValue); + set(gui.panels.nmr.HBox3,'Widths',[cpanel_w -1 -1]); + + % Calc button + gui.panels.nmr.HBox4 = uix.HBox('Parent',gui.panels.nmr.VBox,... + 'Spacing',3); + uix.Empty('Parent',gui.panels.nmr.HBox4); + tstr = 'Get NMR signals'; + gui.push_handles.nmr = uicontrol('Parent',gui.panels.nmr.HBox4,... + 'String','GET NMR SIGNALS','FontSize',myui.fontsize,'Tag','2dmod',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackGroundColor','g','Callback',@fv_getNMR); + set(gui.panels.nmr.HBox4,'Widths',[cpanel_w -1]); + + % log/lin axes + gui.panels.nmr.HBox5 = uix.HBox('Parent',gui.panels.nmr.VBox,... + 'Spacing',3); + gui.text_handles.loglin_axes = uicontrol('Parent',gui.panels.nmr.HBox5,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String','Echo time axes'); + tstr = ""; + gui.radio_handles.log = uicontrol('Parent',gui.panels.nmr.HBox5,... + 'Style','radiobutton','String','log','FontSize',myui.fontsize,'Tag','log',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','on','Value',1,'Callback',@fv_onRadioLogLin); + gui.radio_handles.lin = uicontrol('Parent',gui.panels.nmr.HBox5,... + 'Style','radiobutton','String','lin','FontSize',myui.fontsize,'Tag','lin',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Enable','on','Value',0,'Callback',@fv_onRadioLogLin); + set(gui.panels.nmr.HBox5,'Widths',[cpanel_w -1 -1]); + + %% --- update MAIN GUI button --- + gui.panels.save.HBox1 = uix.VBox('Parent',gui.left,... + 'Spacing',3); + tstr = 'UPDATE 2D inversion data in main NUCLEUSinv GUI.'; + gui.push_handles.update = uicontrol('Parent',gui.panels.save.HBox1,... + 'String','UPDATE MAIN GUI','FontSize',myui.fontsize,'Tag','update',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onPushUpdate,'Enable','off'); + tstr = 'SAVE 2D inversion data to external file.'; + gui.push_handles.save = uicontrol('Parent',gui.panels.save.HBox1,... + 'String','SAVE RESULT','FontSize',myui.fontsize,'Tag','save',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onPushSave); + tstr = 'Export current graphics view to Figure.'; + gui.push_handles.view = uicontrol('Parent',gui.panels.save.HBox1,... + 'String','VIEW2FIG','FontSize',myui.fontsize,'Tag','view',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@fv_onPushView); + % set(gui.panels.save.HBox1,'Widths',[-1 -1]); + + % fix text vertical alignment + jh = findjobj(gui.text_handles.diff); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.gradient); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.echo_time); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.Tbulk); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + + jh = findjobj(gui.text_handles.rtdT1); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.rtdT2); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + + jh = findjobj(gui.text_handles.T1type); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.timeT1); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.timeT2); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.noise); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.loglin_axes); + 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 28 -1; 22+2*24+3*4+115 22+4*24+6*3 22+6*24+8*3 28*3 -1]; + % panel header is always 22 high + set(gui.left,'Heights',heights(2,:),... + 'MinimumHeights',[22 22 22 28 0]); + + %% --- plot boxes --- + waitbar(4/steps,hwb,'loading GUI elements - graphics'); + gui.rightPanel = uix.TabPanel('Parent',gui.right,... + 'BackGroundColor',colors.panelBG); + + % -- tab2 + gui.tab2 = uix.GridFlex('Parent',gui.rightPanel,... + 'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); + + gui.pbox21 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + gui.pbox22 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + + gui.pbox23 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + gui.pbox24 = uicontainer('Parent',gui.tab2,... + 'BackGroundColor',colors.panelBG); + + set(gui.tab2,'Widths',[-6 -1],'Heights',[-1 -6]); + + % -- tab3 + gui.tab3 = uix.VBoxFlex('Parent',gui.rightPanel,... + 'BackGroundColor',colors.panelBG,'Spacing',5); + gui.pbox31 = uicontainer('Parent',gui.tab3,... + 'BackGroundColor',colors.panelBG); + gui.pbox32 = uicontainer('Parent',gui.tab3,... + 'BackGroundColor',colors.panelBG); + set(gui.tab3,'Heights',[-1 -2]); + + gui.rightPanel.TabTitles = {'MODEL','SIGNALS'}; + gui.rightPanel.TabWidth = 75; + gui.rightPanel.TabEnables = {'on','on'}; + + % -- plot axes -- + gui.axes2 = axes('Parent',gui.pbox22,'Box','on'); + gui.axes21 = axes('Parent',gui.pbox21,'Box','on'); + gui.axes24 = axes('Parent',gui.pbox24,'Box','on'); + gui.axes31 = axes('Parent',gui.pbox31,'Box','on'); + gui.axes32 = axes('Parent',gui.pbox32,'Box','on'); + + % --- 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_2Dmod,'gui',gui); + setappdata(fig_2Dmod,'data',data); + + % make GUI visible + delete(hwb); + set(gui.main,'Visible','on'); +else + % if the figure is already open bring t to the front + figure(fig_2Dmod); +end + +% trigger the model update pushbutton for the initial view +fv_getModel(fig_2Dmod); +beautifyAxes(fig_2Dmod); +end + +%% subfunction to update the table entries +function fv_onEditTable(src,~) +figh = ancestor(src,'figure','toplevel'); +fv_getModel(figh) + +end + +%% subfunction to update the edit fields +function fv_onEditValue(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); + +switch get(src,'Tag') + case {'diff','gradient','Tbulk'} + data.prop.D = str2double(get(gui.edit_handles.diff,'String'))/1e9; + data.prop.G0 = str2double(get(gui.edit_handles.gradient,'String')); + data.prop.Tbulk = str2double(get(gui.edit_handles.Tbulk,'String')); + case {'rtdT1min','rtdT1max','rtdT1N'} + data.mod.T1min = str2double(get(gui.edit_handles.rtdT1min,'String')); + data.mod.T1max = str2double(get(gui.edit_handles.rtdT1max,'String')); + data.mod.T1N = str2double(get(gui.edit_handles.rtdT1N,'String')); + setappdata(figh,'data',data); + fv_getModel(gui.push_handles.model); + data = getappdata(figh,'data'); + case {'rtdT2min','rtdT2max','rtdT2N'} + data.mod.T2min = str2double(get(gui.edit_handles.rtdT2min,'String')); + data.mod.T2max = str2double(get(gui.edit_handles.rtdT2max,'String')); + data.mod.T2N = str2double(get(gui.edit_handles.rtdT2N,'String')); + setappdata(figh,'data',data); + fv_getModel(gui.push_handles.model); + data = getappdata(figh,'data'); + case {'T1trmin','T1trmax','T1trN'} + data.nmr.T1trmin = str2double(get(gui.edit_handles.T1trmin,'String')); + data.nmr.T1trmax = str2double(get(gui.edit_handles.T1trmax,'String')); + data.nmr.T1trN = str2double(get(gui.edit_handles.T1trN,'String')); + case {'T2te','T2teN'} + data.nmr.T2te = str2double(get(gui.edit_handles.T2te,'String'))/1e6; + data.nmr.T2teN = str2double(get(gui.edit_handles.T2teN,'String')); + + data.prop.te = data.nmr.T2te; + set(gui.edit_handles.echo_time,'String',data.prop.te*1e6); + case {'nmr_noise'} + data.nmr.noise = str2double(get(gui.edit_handles.noise,'String')); + switch data.nmr.noisetype + case 'level' + case 'SNR' + if data.nmr.noise == 0 + data.nmr.noise = Inf; + set(src,'String',num2str(data.nmr.noise)); + end + end + setappdata(figh,'data',data); + if isfield(data.results.mod2D,'data') + fv_addNoise(figh) + data = getappdata(figh,'data'); + end +end + +% update GUI data +setappdata(figh,'data',data); +end + +%% subfunction to set the T1 type +function fv_onPopupT1Type(src,~) +figh = ancestor(src,'figure','toplevel'); +data = getappdata(figh,'data'); + +switch get(src,'Value') + case 1 % Saturation Recovery + data.nmr.T1IRfac = 1; + case 2 % Inversion Recovery + data.nmr.T1IRfac = 2; +end + +% update GUI data +setappdata(figh,'data',data); +end + +%% subfunction to set the NMR data noise type +function fv_onPopupNoiseType(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); + +% change settings accordingly +switch get(src,'Value') + case 1 % noise level + data.nmr.noisetype = 'level'; + if data.nmr.noise > 0 + data.nmr.noise = 1/data.nmr.noise; + end + case 2 % signal-to-noise ratio (SNR) + data.nmr.noisetype = 'SNR'; + if data.nmr.noise == 0 + data.nmr.noise = inf; + else + data.nmr.noise = 1/data.nmr.noise; + end +end +% update the corresponding edit field +set(gui.edit_handles.noise,'String',num2str(data.nmr.noise)); + +% update GUI data +setappdata(figh,'data',data); +% update NMR data (if available) +if isfield(data.results.mod2D,'data') + fv_addNoise(figh); +end + +end + +%% subfunction to set the T1 t 0 + for n = 1:numel(mod2D.data) + mod2D.data(n).noise = noise; + [re,im] = addNoiseToSignal(mod2D.data(n).s_raw,0,noise); + mod2D.data(n).s = complex(re,im); + end +else + % reset the NMR signals with the raw data (without noise) + for n = 1:numel(mod2D.data) + mod2D.data(n).noise = 0; + mod2D.data(n).s = complex(mod2D.data(n).s_raw,zeros(size(mod2D.data(n).s_raw))); + end +end + +% update the GUI data +data.results.mod2D = mod2D; +setappdata(figh,'data',data); +% plot all signals +fv_plotSignals(figh); +beautifyAxes(figh); +end + +%% subfunction to get the 2D model +function fv_getModel(figh) +% figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); + +% create model space from relaxation time T vectors +T1min = data.mod.T1min; +T1max = data.mod.T1max; +T1N = data.mod.T1N; +T2min = data.mod.T2min; +T2max = data.mod.T2max; +T2N = data.mod.T2N; + +T1vec = logspace(log10(T1min),log10(T1max),T1N); +T2vec = logspace(log10(T2min),log10(T2max),T2N); +MOD = zeros(numel(T1vec),numel(T2vec)); + +[X1,X2] = meshgrid(T2vec,T1vec); +X = [X1(:) X2(:)]; + +% get table with model parameters +table = get(gui.table_handles.mod,'Data'); +data.results.mod2D.table = table; +% create distributions +for nn = 1:size(table,1) + if table{nn,1} + % muX muY + mu = [table{nn,2} table{nn,3}]; + % sigma = [xx xy; yx yy] + Sigma = [table{nn,4} table{nn,6}; table{nn,7} table{nn,5}]; + % get multivariate distribution of linearized data + p = getMultivariateGaussian(log10(X), log10(mu), Sigma); + p = reshape(p,T1N,T2N); + Amp = table{nn,8}; + MOD = MOD + Amp*p./max(p(:)); + end +end + +if any(isnan(MOD)) + MOD = ones(size(MOD)); +end + +% normalize to 1 +MOD = MOD./sum(MOD(:)); + +data.results.mod2D.T1vec = T1vec; +data.results.mod2D.T2vec = T2vec; +data.results.mod2D.MOD = MOD; +% update GUI data +setappdata(figh,'data',data); +% update plot +fv_plotModel(figh); +beautifyAxes(figh); +end + +%% subfunction to calculate the NMR signals +function fv_getNMR(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +mod2D = data.results.mod2D; + +% prepare parameters +% IR / SR factor +T1IRfac = data.nmr.T1IRfac; +IRtype = data.nmr.IRtype; + +% get system properties +D = data.prop.D; +G0 = data.prop.G0; +te = data.prop.te; +Tbulk = data.prop.Tbulk; + +T1vec = mod2D.T1vec; +T2vec = mod2D.T2vec; + +% disable the RUN button to indicate a running inversion +set(gui.push_handles.nmr,'String','RUNNING ...',... + 'BackgroundColor',get(gui.push_handles.update,'BackgroundColor'),... + 'Enable','off'); pause(0.01); + +% prepare data +% T2 time vector +t2 = getNMRTimeVector(data.nmr.T2te,'s','N',data.nmr.T2teN); +T1 = logspace(log10(data.nmr.T1trmin),log10(data.nmr.T1trmax),data.nmr.T1trN); +dat = struct; +for n = 1:numel(T1) + dat(n).t = t2; + dat(n).s = zeros(size(t2)); + dat(n).T1 = T1(n); +end + +% create the Kernel matrix for inversion +p.G0 = G0; +p.D = D; +p.te = te; +p.Tbulk = Tbulk; +p.T1IRfac = T1IRfac; +p.IRtype = IRtype; +[K,indices] = createKernelMatrix2D(dat,T1vec,T2vec,p); + +MODvec = reshape(mod2D.MOD',size(mod2D.MOD,1)*size(mod2D.MOD,2),1); +RESvec = K*MODvec; + +for n = 1:numel(T1) + dat(n).s = RESvec(indices.lin_1(n):indices.lin_end(n)); + dat(n).s_raw = RESvec(indices.lin_1(n):indices.lin_end(n)); +end + +% enable the RN button +set(gui.push_handles.nmr,'String','GET NMR SIGNALS',... + 'BackgroundColor','g','Enable','on','Callback',@fv_getNMR); +setappdata(figh,'gui',gui); + +% save results +data.results.mod2D.t2 = t2; +data.results.mod2D.t_recov = T1; +data.results.mod2D.data = dat; + +% update data +setappdata(figh,'data',data); +fv_addNoise(figh) + +% plot all signals +fv_plotSignals(figh); +beautifyAxes(figh); +gui.rightPanel.Selection = 2; +end + +%% subfunction to export the 2D inversion data +function fv_onPushSave(src,~) +figh = ancestor(src,'figure','toplevel'); +% local GUI data +data = getappdata(figh,'data'); + +% get data path to save inversion results +[sfile,spath] = uiputfile('*.mat','Select File for Save',... + fullfile(pwd,'2Dmoddata.mat')); +% if user did not cancel, procceed +if sfile > 0 + moddata = data; + save(fullfile(spath,sfile),'moddata'); + disp('2D Modeling data saved to: '); + disp(fullfile(spath,sfile)); +else + disp('Save cancelled.'); +end + +end + +%% subfunction to export the current view to a figure +function fv_onPushView(src,~) +figh = ancestor(src,'figure','toplevel'); +% local GUI data +gui = getappdata(figh,'gui'); + +% opening the export figure +expfig = figure('Color',gui.myui.colors.panelBG); + +% create axes layout depending on view +switch get(gui.rightPanel,'Selection') + case 1 + % create layout + ax1 = subplot(5,5,[1 2 3 4],'Parent',expfig); + ax2 = subplot(5,5,[6:9 11:14 16:19 21:24],'Parent',expfig); + ax3 = subplot(5,5,[10 15 20 25],'Parent',expfig); + % get positions + pos1 = get(ax1,'Position'); + pos2 = get(ax2,'Position'); + pos3 = get(ax3,'Position'); + % delete axes + delete(ax1);delete(ax2);delete(ax3); + % copy GUI axes + ax1 = copyobj(gui.axes21,expfig); + ax2 = copyobj(gui.axes2,expfig); + ax3 = copyobj(gui.axes24,expfig); + % adjust positions + set(ax1,'Position',pos1); + set(ax2,'Position',pos2); + set(ax3,'Position',pos3); + case 2 + % create layout + ax1 = subplot(7,1,[1 2],'Parent',expfig); + ax2 = subplot(7,1,[4 5 6 7],'Parent',expfig); + % get positions + pos1 = get(ax1,'Position'); + pos2 = get(ax2,'Position'); + % delete axes + delete(ax1);delete(ax2); + % copy GUI axes + ax1 = copyobj(gui.axes31,expfig); + ax2 = copyobj(gui.axes32,expfig); + % adjust positions + set(ax1,'Position',pos1); + set(ax2,'Position',pos2); +end + +end + +%% subfunction to update the main NUCLEUSinv GUI +function fv_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'); +INVdata = getappdata(uvgui.figh_nucleus,'INVdata'); +data = getappdata(uvgui.figh_nucleus,'data'); + +% loop over all signals +E_inv = zeros(size(uvdata.results.T1T2map.t_recov)); +for id = 1:numel(INVdata) + % the standard INVdata struct + INVdata{id} = []; + + % old, slow but consistent way + % trigger the listbox entry + % set(gui.listbox_handles.signal,'Value',id); + % onListboxData(gui.listbox_handles.signal); + % no gating + % which radiobutton ('log', 'lin' or 'none') + % onRadioGates(gui.radio_handles.process_gates_none); + % get the fresh data + % data = getappdata(uvgui.figh_nucleus,'data'); + + % new, fast and hopefully consistent :-) way + data.process.start = 1; + data.process.end = numel(uvdata.results.T1T2map.import{id}.time); + data.process.gatetype = 'raw'; + % update 2Dinv GUI settings + data.inv2D.prop = uvdata.prop; + data.inv2D.inv = uvdata.inv; + data.inv2D.info = uvdata.info; + % create raw data struct + data.results.nmrraw.t = uvdata.results.T1T2map.import{id}.time; + data.results.nmrraw.s = uvdata.results.T1T2map.import{id}.signal; + if id == numel(INVdata) + data.results.nmrraw.noise = uvdata.results.T1T2map.import{id}.noise; + data.results.nmrproc.T1T2 = 'T1'; + data.results.nmrproc.T1IRfac = 2; + else + data.results.nmrraw.phase = uvdata.results.T1T2map.import{id}.phase; + end + % create proc data struct + data.results.nmrproc.start = 1; + data.results.nmrproc.end = numel(uvdata.results.T1T2map.import{id}.time); + data.results.nmrproc.gatetype = 'raw'; + data.results.nmrproc.t = uvdata.results.T1T2map.import{id}.time; + data.results.nmrproc.s = real(uvdata.results.T1T2map.import{id}.signal); + data.results.nmrproc.N = ones(size(data.results.nmrproc.s)); + if isfield(uvdata.results.T1T2map.import{id},'noise') + data.results.nmrproc.noise = uvdata.results.T1T2map.import{id}.noise; + else + range = floor(numel(data.results.nmrproc.s)/2):numel(data.results.nmrproc.s); + data.results.nmrproc.noise = std(imag(uvdata.results.T1T2map.import{id}.signal(range))); + end + data.results.nmrproc.e = data.results.nmrproc.noise*ones(size(data.results.nmrproc.s)); + if isfield(data.results.nmrproc,'W') + data.results.nmrproc = rmfield(data.results.nmrproc,'W'); + end + + % and use it for the INVdata + INVdata{id} = data; + INVdata{id} = rmfield(INVdata{id},'import'); + INVdata{id} = rmfield(INVdata{id},'info'); + INVdata{id} = rmfield(INVdata{id},'calib'); + INVdata{id} = rmfield(INVdata{id},'pressure'); + + % now add a dummy "invstd" field + if id == numel(INVdata) + % for the final merged T1 + INVdata{id}.results.invstd.fit_t = uvdata.results.T1T2map.t_recov; + INVdata{id}.results.invstd.fit_s = E_inv; + INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.E0; + INVdata{id}.results.invstd.ciE0 = NaN; + out = getFitErrors(uvdata.results.T1T2map.E_raw(:,1),E_inv,data.results.nmrproc.noise); + INVdata{id}.results.invstd.resnorm = out.resnorm; + INVdata{id}.results.invstd.residual = out.residual; + INVdata{id}.results.invstd.chi2 = out.chi2; + INVdata{id}.results.invstd.rms = out.rms; + else + % for the individual signals + INVdata{id}.results.invstd.fit_t = uvdata.results.inv2D.data(id).t; + INVdata{id}.results.invstd.fit_s = uvdata.results.inv2D.data(id).s_fit; + E_inv(id,1) = uvdata.results.inv2D.data(id).s_fit(1); + INVdata{id}.results.invstd.E0 = uvdata.results.inv2D.data(id).s_fit(1); + INVdata{id}.results.invstd.ciE0 = NaN; + INVdata{id}.results.invstd.resnorm = uvdata.results.inv2D.data(id).resnorm; + INVdata{id}.results.invstd.residual = uvdata.results.inv2D.data(id).residual; + INVdata{id}.results.invstd.chi2 = uvdata.results.inv2D.data(id).chi2; + INVdata{id}.results.invstd.rms = uvdata.results.inv2D.data(id).rms; + end + INVdata{id}.results.invstd.lambda_out = 1; + INVdata{id}.results.invstd.xn = 0; + INVdata{id}.results.invstd.rn = 0; + INVdata{id}.results.invstd.invtype = data.invstd.invtype; + INVdata{id}.results.invstd.invparams = NaN; + if id == numel(INVdata) + INVdata{id}.results.inv2D = uvdata.results.inv2D; + else + INVdata{id}.results.inv2D = true; + end + + % color the corresponding list entries in the main GUI + strL = get(gui.listbox_handles.signal,'String'); + str1 = strL{id}; + str2 = ['',str1,'']; + strL{id} = str2; + set(gui.listbox_handles.signal,'String',strL); +end + +% update GUI INVdata +setappdata(uvgui.figh_nucleus,'INVdata',INVdata); + +% set focus on first signal +set(gui.listbox_handles.signal,'Value',1); +onListboxData(gui.listbox_handles.signal); +end + +%% subfunction to update all plots +function fv_plotSignals(figh) +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +mod2D = data.results.mod2D; +data_mod = mod2D.data; +col = gui.myui.colors; + +% clear axes +clearSingleAxis(gui.axes31); +clearSingleAxis(gui.axes32); +hold(gui.axes31,'on'); +hold(gui.axes32,'on'); + +% define some axes settings +log_t_ticks = logspace(-5,2,8); +t_recov_lims = [min(mod2D.t_recov)/2 max(mod2D.t_recov)*2]; + +% prepare the data for the combined T1 curve +E_mod = zeros(size(mod2D.t_recov)); +for nn = 1:numel(data_mod) + E_mod(nn,1) = data_mod(nn).s(1); + % plot individual T2 signals and fits + plot3(data_mod(nn).t,data_mod(nn).T1*ones(size(data_mod(nn).s)),... + data_mod(nn).s,'Color',col.axisL,'DisplayName','T2 signals',... + 'LineWidth',1,'Parent',gui.axes32); +end +view(gui.axes32,[30 20]); +set(gui.axes32,'XScale','log','XTick',log_t_ticks); +set(gui.axes32,'YScale','log','YDir','normal','YTick',log_t_ticks,'YLim',t_recov_lims); +set(get(gui.axes32,'XLabel'),'String','time [s]'); +set(get(gui.axes32,'YLabel'),'String','recovery time t_{rec} [s]'); +set(get(gui.axes32,'ZLabel'),'String','amplitude [a.u.]'); +% fv_fixLabel3DAxes(gui.axes32) + +% tab 3 - combined T1 curve and fit +plot(mod2D.t_recov,E_mod(:,1),'o-','Color',col.axisL,... + 'LineWidth',1,'DisplayName','T1 curve','Parent',gui.axes31); +set(gui.axes31,'XScale','log','XLim',t_recov_lims); +set(gui.axes31,'YScale','lin'); +set(get(gui.axes31,'XLabel'),'String','recovery time t_{rec} [s]'); +set(get(gui.axes31,'YLabel'),'String','mean(E(1:3)) [a.u.]'); +legend(gui.axes31,'Location','SouthEast'); + +% hold off all axes +hold(gui.axes31,'off'); +hold(gui.axes32,'off'); + +% call function to adapt the axes scaling +fv_setAxesScaling(figh); +end + +%% subfunction to plot the raw data +function fv_plotModel(figh) +gui = getappdata(figh,'gui'); +data = getappdata(figh,'data'); +col = gui.myui.colors; +mod2D = data.results.mod2D; + +clearSingleAxis(gui.axes2); +clearSingleAxis(gui.axes21); +clearSingleAxis(gui.axes24); +hold(gui.axes2,'on'); +hold(gui.axes21,'on'); +hold(gui.axes24,'on'); + +log_t_ticks = logspace(-5,2,8); + +% tab 2 - 2D inversion model +[X,Y] = meshgrid(mod2D.T2vec,mod2D.T1vec); +imagescnan(X,Y,mod2D.MOD,'Parent',gui.axes2); +plot([1e-5 100],[1e-5 100],... + '--','Color','w','LineWidth',1,'Parent',gui.axes2); +view(gui.axes2,[0 90]); +set(gui.axes2,'XScale','log','XTick',log_t_ticks,... + 'XLim',[min(mod2D.T2vec) max(mod2D.T2vec)]); +set(gui.axes2,'YScale','log','XTick',log_t_ticks,... + 'YLim',[min(mod2D.T1vec) max(mod2D.T1vec)],'YDir','normal'); +set(get(gui.axes2,'XLabel'),'String','relaxation time T2 [s]'); +set(get(gui.axes2,'YLabel'),'String','relaxation time T1 [s]'); +set(gui.axes2,'Layer','top','XGrid','off','YGrid','off'); + +% sum along each dimension to get both RTDs +T1rtd = sum(mod2D.MOD,2); +T2rtd = sum(mod2D.MOD,1); +% find common maximum for y-axis setting +ymax = max([max(T1rtd) max(T2rtd)])*1.1; +% T1 RTD +plot(T1rtd,mod2D.T1vec,'Color',col.axisL,'Parent',gui.axes24); +set(gui.axes24,'XScale','lin','XLim',[0 ymax]); +set(gui.axes24,'YScale','log','YTickLabel',''); + +% T2 RTD +plot(mod2D.T2vec,T2rtd,'Color',col.axisL,'DisplayName','RTD','Parent',gui.axes21); +set(gui.axes21,'YScale','lin','YLim',[0 ymax]); +set(gui.axes21,'XScale','log','XTickLabel',''); + +hold(gui.axes2,'off'); +hold(gui.axes21,'off'); +hold(gui.axes24,'off'); +end + +%% subfunction zo switch x-axis scaling +function fv_onRadioLogLin(src,~) +figh = ancestor(src,'figure','toplevel'); +gui = getappdata(figh,'gui'); +% get tag of the radio menu +tag = get(src,'Tag'); +val = get(src,'Value'); + +switch tag + case 'log' + switch val + case 1 % log should be used + set(gui.radio_handles.lin,'Value',0); + case 0 % lin should be used + set(gui.radio_handles.lin,'Value',1); + end + case 'lin' + switch val + case 1 % lin should be used + set(gui.radio_handles.log,'Value',0); + case 0 % log should be used + set(gui.radio_handles.log,'Value',1); + end +end +% update GUI data +setappdata(figh,'gui',gui); + +% call function to adapt the axes scaling +fv_setAxesScaling(figh); +end + +%% subfunction to switch x-axis scaling log<->lin +function fv_setAxesScaling(figh) +gui = getappdata(figh,'gui'); + +uselog = get(gui.radio_handles.log,'Value'); +switch uselog + case 1 + log_t_ticks = logspace(-5,2,8); + set(gui.axes32,'XScale','log','XTick',log_t_ticks); + case 0 + set(gui.axes32,'XScale','lin','XTickMode','auto'); +end + +end + +%% close function +function fv_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/PhaseView.m b/functions/interface/PhaseView.m index f594d3e..b5a8103 100644 --- a/functions/interface/PhaseView.m +++ b/functions/interface/PhaseView.m @@ -1,5 +1,5 @@ function PhaseView(src,~) -%PhaseView is an extra subGUI to visualize the phase of a T2 signal +%PhaseView is an extra subGUI to manipulate the phase of a T2 signal % % Syntax: % PhaseView @@ -14,15 +14,21 @@ function PhaseView(src,~) % PhaseView(src,~) % % Other m-files required: -% none +% onListboxData +% onMenuView % % Subfunctions: -% pv_onPushDefault -% pv_onPushSave -% pv_showSignal -% pv_updateSlider -% pv_updatePhase -% shift_phase +% getSSR +% phasefit_fcn +% pv_onEditValues +% pv_onPushAngle +% pv_onPushApply +% pv_onPushKeep +% pv_onPushRun +% pv_onSlider +% pv_plotSignal +% pv_plotSSR +% pv_updateFullDataSet % % MAT-files required: % none @@ -38,6 +44,7 @@ function PhaseView(src,~) fig = ancestor(src,'figure','toplevel'); nucleus.data = getappdata(fig,'data'); nucleus.gui = getappdata(fig,'gui'); +myui = nucleus.gui.myui; colors = nucleus.gui.myui.colors; hasData = false; @@ -45,6 +52,7 @@ function PhaseView(src,~) if isfield(nucleus.data.results,'nmrraw') &&... isfield(nucleus.data.results,'nmrproc') hasData = true; + ID = get(nucleus.gui.listbox_handles.signal,'value'); end end @@ -56,102 +64,277 @@ function PhaseView(src,~) if isempty(fig_phase) % draw the figure on top of NUCLEUSinv fig_phase = figure('Name','NUCLEUSinv - PhaseView',... - 'NumberTitle','off','ToolBar','none','Tag','PHASEVIEW'); + 'NumberTitle','off','Resize','on','ToolBar','none',... + 'Tag','PHASEVIEW','Menubar','none'); pos0 = get(fig,'Position'); - pos1 = get(fig_phase,'Position'); cent(1) = (pos0(1)+pos0(3)/2); cent(2) = (pos0(2)+pos0(4)/2); - set(fig_phase,'Position',[cent(1)-pos0(3)/3 pos0(2) pos0(3)/1.5 pos0(4)]); - - % create the layout - gui.main = uix.VBox('Parent',fig_phase,'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); - gui.row1 = uicontainer('Parent',gui.main,'BackGroundColor',colors.panelBG); % axes real - gui.row2 = uicontainer('Parent',gui.main,'BackGroundColor',colors.panelBG); % axes imag - gui.row3 = uicontainer('Parent',gui.main,'BackGroundColor',colors.panelBG); % axes SSE - gui.row4 = uix.HBox('Parent',gui.main,'BackGroundColor',colors.panelBG,'Spacing',5); % control elements - set(gui.main,'Heights',[-1 -1 -1 90]); - - % all axes - gui.axes_handles.real = axes('Parent',gui.row1,... - 'Color',colors.axisBG,'XColor',colors.axisFG,... - 'YColor',colors.axisFG); - gui.axes_handles.imag = axes('Parent',gui.row2,... - 'Color',colors.axisBG,'XColor',colors.axisFG,... - 'YColor',colors.axisFG); - gui.axes_handles.sse = axes('Parent',gui.row3,... - 'Color',colors.axisBG,'XColor',colors.axisFG,... - 'YColor',colors.axisFG); - - % 3 horizontal boxes - uix.Empty('Parent',gui.row4); - gui.vbox1 = uix.VBox('Parent',gui.row4,'BackGroundColor',colors.panelBG,'Spacing',5,'Padding',5); % control elements - uix.Empty('Parent',gui.row4); - set(gui.row4,'Widths',[-1 -2 -1]); + set(fig_phase,'Position',[cent(1)-pos0(3)/3 pos0(2)+22 pos0(3)/1.5 pos0(4)-22]); + + gui.menu.view = uimenu(fig_phase,'Label','View'); + gui.menu.view_toolbar = uimenu(gui.menu.view,'Label','Figure Toolbar',... + 'Callback',@onMenuView); + + cpanel_w = 150; + % phase angle fit range + data.phase_range = [-180 180]; + % SSR data + % phase angle range to show nice diagram + data.beta_range = -180:1:180; + % echo range to calculate SSR + data.echo_range = [nucleus.data.process.start nucleus.data.process.end]; + + % create the main layout + gui.main = uix.HBox('Parent',fig_phase,'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 ]); + + % empty space at top of left side + uix.Empty('Parent',gui.left); + + % --- properties panel --- + % waitbar(1/steps,hwb,'loading GUI elements - properties'); + gui.panels.prop.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Fit phase angle','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxPRC,'ForegroundColor',colors.BoxTitle); + gui.panels.prop.VBox = uix.VBox('Parent',gui.panels.prop.main,... + 'Spacing',3,'Padding',3); + + % first and last echo + gui.panels.prop.HBox1 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.first = uicontrol('Parent',gui.panels.prop.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"T2 echoes - first | last"); + tstr = 'Set first / last echo of all T2 signals.'; + gui.edit_handles.first = uicontrol('Parent',gui.panels.prop.HBox1,... + 'Style','edit','String',sprintf('%d',nucleus.data.process.start),... + 'FontSize',myui.fontsize,'Tag','first',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@pv_onEditValue); + gui.edit_handles.last = uicontrol('Parent',gui.panels.prop.HBox1,... + 'Style','edit','String',sprintf('%d',nucleus.data.process.end),... + 'FontSize',myui.fontsize,'Tag','last',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@pv_onEditValue); + set(gui.panels.prop.HBox1,'Widths',[cpanel_w -1 -1]); + + % phase angle range + gui.panels.prop.HBox2 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.range = uicontrol('Parent',gui.panels.prop.HBox2,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Phase range [-180, 180]"); + tstr = 'Set phase angle range for fitting'; + gui.edit_handles.range_min = uicontrol('Parent',gui.panels.prop.HBox2,... + 'Style','edit','String',sprintf('%d',-180),... + 'FontSize',myui.fontsize,'Tag','range_min',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@pv_onEditValue); + gui.edit_handles.range_max = uicontrol('Parent',gui.panels.prop.HBox2,... + 'Style','edit','String',sprintf('%d',180),... + 'FontSize',myui.fontsize,'Tag','range_max',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@pv_onEditValue); + set(gui.panels.prop.HBox2,'Widths',[cpanel_w -1 -1]); + + % fit method + gui.panels.prop.HBox3 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + gui.text_handles.fitmethod = uicontrol('Parent',gui.panels.prop.HBox3,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Phase fit method"); + tstr = ['Choose the phase fitting method.

    ',... + 'Available options:
    ',... + 'maxRE minIM maximize REal part, minimize IMag part.
    ',... + 'maxRE Only maximize REal part.
    ',... + 'minIM Only minimize IMag part.
    ',... + 'minIMstd Only minimize standard deviation of IMag part.

    ',... + 'Default value:
    ',... + 'maxRE minIM
    ']; + gui.popup_handles.fitmethod = uicontrol('Parent',gui.panels.prop.HBox3,... + 'Style','popup','String',{'maxRE minIM','maxRE','minIM','minIMstd'},... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'FontSize',myui.fontsize,'Tag','control'); + set(gui.panels.prop.HBox3,'Widths',[cpanel_w -1]); + + % run fit + gui.panels.prop.HBox4 = uix.HBox('Parent',gui.panels.prop.VBox,... + 'Spacing',3); + uix.Empty('Parent',gui.panels.prop.HBox4); + tstr = 'RUN phase fitting.'; + gui.push_handles.runfit = uicontrol('Parent',gui.panels.prop.HBox4,... + 'Style','pushbutton','String','RUN phase fit',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'BackGroundColor','g','FontSize',myui.fontsize,... + 'Tag','control','Callback',@pv_onPushRun); + set(gui.panels.prop.HBox4,'Widths',[cpanel_w -1]); + + + % --- manual control panel --- + % waitbar(1/steps,hwb,'loading GUI elements - properties'); + gui.panels.manual.main = uix.BoxPanel('Parent',gui.left,... + 'Title','Manually set phase angle','MinimizeFcn',@minimizePanel,... + 'TitleColor',colors.BoxPRC,'ForegroundColor',colors.BoxTitle); + gui.panels.manual.VBox = uix.VBox('Parent',gui.panels.manual.main,... + 'Spacing',3,'Padding',3); % edit field - gui.hbox11 = uix.HBox('Parent',gui.vbox1,'BackGroundColor',colors.panelBG,'Spacing',5); - uix.Empty('Parent',gui.hbox11); - gui.edit_phase = uicontrol('Parent',gui.hbox11,... + gui.panels.manual.HBox1 = uix.HBox('Parent',gui.panels.manual.VBox,... + 'BackGroundColor',colors.panelBG,'Spacing',3); + gui.text_handles.edit_manual = uicontrol('Parent',gui.panels.manual.HBox1,... + 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... + 'String',"Current phase [deg]"); + gui.edit_handles.phase = uicontrol('Parent',gui.panels.manual.HBox1,... 'Style','edit','FontSize',nucleus.gui.myui.fontsize,'Tag','phase',... 'String',num2str(0),'BackGroundColor',colors.editBG,... 'ForeGroundColor',colors.panelFG,... - 'Callback',@pv_updatePhase); - uix.Empty('Parent',gui.hbox11); - set(gui.hbox11,'Widths',[-1 -1 -1]); + 'Callback',@pv_onEditValue); + set(gui.panels.manual.HBox1,'Widths',[cpanel_w -1]); % slider - gui.hbox12 = uix.HBox('Parent',gui.vbox1,'BackGroundColor',colors.panelBG,'Spacing',5); - gui.hbox121 = uix.HBox('Parent',gui.hbox12,'BackGroundColor',colors.panelBG,'Spacing',5); - gui.text_down = uicontrol('Parent',gui.hbox121,'Style','text',... + gui.panels.manual.HBox2 = uix.HBox('Parent',gui.panels.manual.VBox,... + 'BackGroundColor',colors.panelBG,'Spacing',3); + gui.text_handles.slider_down = uicontrol('Parent',gui.panels.manual.HBox2,'Style','text',... 'String','down','FontSize',nucleus.gui.myui.fontsize,... 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... - 'HorizontalAlignment','right'); - gui.slider = uicontrol('Parent',gui.hbox12,'Style','slider',... + 'HorizontalAlignment','center'); + gui.slider_handles.slider = uicontrol('Parent',gui.panels.manual.HBox2,'Style','slider',... 'Min',-180,'Max',180,'Value',0,'SliderStep',[0.1/360 5/360],... - 'Callback',@pv_updateSlider); - gui.hbox122 = uix.HBox('Parent',gui.hbox12,'BackGroundColor',colors.panelBG,'Spacing',5); - gui.text_up = uicontrol('Parent',gui.hbox122,'Style','text',... + 'Callback',@pv_onSlider); + gui.text_handles.slider_up = uicontrol('Parent',gui.panels.manual.HBox2,'Style','text',... 'String','up','FontSize',nucleus.gui.myui.fontsize,... 'BackGroundColor',colors.panelBG,'ForeGroundColor',colors.panelFG,... - 'HorizontalAlignment','left'); - set(gui.hbox12,'Widths',[-1 -9 -1]); + 'HorizontalAlignment','center'); + set(gui.panels.manual.HBox2,'Widths',[-1 -6 -1]); % buttons - gui.hbox13 = uix.HBox('Parent',gui.vbox1,'BackGroundColor',colors.panelBG,'Spacing',5); - uix.Empty('Parent',gui.hbox13); - gui.push_default = uicontrol('Parent',gui.hbox13,... - 'Style','pushbutton','FontSize',nucleus.gui.myui.fontsize,'Tag','default',... - 'String','DEFAULT','Callback',@pv_onPushDefault); - uix.Empty('Parent',gui.hbox13); - gui.push_save = uicontrol('Parent',gui.hbox13,... - 'Style','pushbutton','FontSize',nucleus.gui.myui.fontsize,'Tag','save',... - 'String','KEEP','Callback',@pv_onPushSave); - uix.Empty('Parent',gui.hbox13); - set(gui.hbox13,'Widths',[-1 -2 -1 -2 -1]); - - set(gui.vbox1,'Heights',[-1 20 -1]); + gui.panels.manual.HBox3 = uix.HBox('Parent',gui.panels.manual.VBox,... + 'BackGroundColor',colors.panelBG,'Spacing',3); + tstr = 'Change phase angle by -90°.'; + gui.push_handles.button_m90 = uicontrol('Parent',gui.panels.manual.HBox3,... + 'Style','pushbutton','String','-90',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'FontSize',myui.fontsize,... + 'Tag','button_m90','Callback',@pv_onPushAngle); + tstr = 'Change phase angle by -45°.'; + gui.push_handles.button_m45 = uicontrol('Parent',gui.panels.manual.HBox3,... + 'Style','pushbutton','String','-45',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'FontSize',myui.fontsize,... + 'Tag','button_m45','Callback',@pv_onPushAngle); + tstr = 'Change phase angle by +-180°.'; + gui.push_handles.button_pm180 = uicontrol('Parent',gui.panels.manual.HBox3,... + 'Style','pushbutton','String','+-180',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'FontSize',myui.fontsize,... + 'Tag','button_pm180','Callback',@pv_onPushAngle); + tstr = 'Change phase angle by +45°.'; + gui.push_handles.button_p45 = uicontrol('Parent',gui.panels.manual.HBox3,... + 'Style','pushbutton','String','+45',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'FontSize',myui.fontsize,... + 'Tag','button_p45','Callback',@pv_onPushAngle); + tstr = 'Change phase angle by +90°.'; + gui.push_handles.button_p90 = uicontrol('Parent',gui.panels.manual.HBox3,... + 'Style','pushbutton','String','+90',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'FontSize',myui.fontsize,... + 'Tag','button_p90','Callback',@pv_onPushAngle); + set(gui.panels.manual.HBox3,'Widths',[-1 -1 -1 -1 -1]); + + % --- update MAIN GUI buttons --- + gui.panels.save.VBox1 = uix.VBox('Parent',gui.left,... + 'Spacing',3); + tstr = 'KEEP default phase angle from NUCLEUSinv GUI import.'; + gui.push_handles.default = uicontrol('Parent',gui.panels.save.VBox1,... + 'String','KEEP default phase angle','FontSize',myui.fontsize,'Tag','default',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@pv_onPushKeep); + tstr = 'APPLY the current phase angle to the signal in the NUCLEUSinv GUI'; + gui.push_handles.apply_single = uicontrol('Parent',gui.panels.save.VBox1,... + 'String','APPLY current phase angle','FontSize',myui.fontsize,'Tag','apply',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@pv_onPushApply); + tstr = 'APPLY the current phase angle to all signals in the NUCLEUSinv GUI'; + gui.push_handles.apply_all = uicontrol('Parent',gui.panels.save.VBox1,... + 'String','APPLY current phase angle 2 all','FontSize',myui.fontsize,'Tag','apply2all',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@pv_onPushApply); % Java Hack to adjust vertical alignment of text fields - jh = findjobj(gui.text_down); + jh = findjobj(gui.text_handles.first); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.fitmethod); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.edit_manual); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER); + jh = findjobj(gui.text_handles.slider_down); jh.setVerticalAlignment(javax.swing.JLabel.CENTER); - jh = findjobj(gui.text_up); + jh = findjobj(gui.text_handles.slider_up); 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 = [-1 22 22 28 -1; -1 22+4*24+6*3 22+3*24+5*3 28*3 -1]; + % panel header is always 22 high + set(gui.left,'Heights',heights(2,:),... + 'MinimumHeights',[0 22 22 28 0]); + + % --- plot boxes --- + % -- tab3 + gui.tab = uix.VBoxFlex('Parent',gui.right,... + 'BackGroundColor',colors.panelBG,'Spacing',5); + gui.pbox1 = uicontainer('Parent',gui.tab,... + 'BackGroundColor',colors.panelBG); + gui.pbox2 = uicontainer('Parent',gui.tab,... + 'BackGroundColor',colors.panelBG); + gui.pbox3 = uicontainer('Parent',gui.tab,... + 'BackGroundColor',colors.panelBG); + set(gui.tab,'Heights',[-1 -1 -1]); + + % -- plot axes -- + gui.axes_handles.real = axes('Parent',gui.pbox1,'Color',colors.axisBG,... + 'XColor',colors.axisFG,'YColor',colors.axisFG,'Box','on'); + gui.axes_handles.imag = axes('Parent',gui.pbox2,'Color',colors.axisBG,... + 'XColor',colors.axisFG,'YColor',colors.axisFG,'Box','on'); + gui.axes_handles.sse = axes('Parent',gui.pbox3,'Color',colors.axisBG,... + 'XColor',colors.axisFG,'YColor',colors.axisFG,'Box','on'); + % store some main GUI settings gui.myui = nucleus.gui.myui; % save to GUI setappdata(fig_phase,'gui',gui); + + % make GUI visible + % delete(hwb); + set(gui.main,'Visible','on'); + else + % if the figure is already open load the GUI data + gui = getappdata(fig_phase,'gui'); + data = getappdata(fig_phase,'data'); + + % echo range to calculate SSR + if data.echo_range(2) > nucleus.data.process.end + data.echo_range(2) = nucleus.data.process.end; + set(gui.edit_handles.last,'String',sprintf('%d',data.echo_range(2))); + end + % data.echo_range = [nucleus.data.process.start nucleus.data.process.end]; end - % if the figure is already open load the GUI data - gui = getappdata(fig_phase,'gui'); + % clear all axes clearAllAxes(fig_phase); if strcmp(nucleus.data.results.nmrproc.T1T2,'T2') - - %% get signal to show + % get signal to show nmrraw = nucleus.data.results.nmrraw; loglinx = get(nucleus.gui.cm_handles.axes_raw_xaxis,'Label'); @@ -161,33 +344,32 @@ function PhaseView(src,~) data.phase_default = rad2deg(nucleus.data.results.nmrraw.phase); % phase used in PhaseView data.phase = data.phase_default; - set(gui.edit_phase,'String',num2str(data.phase)); - set(gui.slider,'Value',data.phase); + set(gui.edit_handles.phase,'String',num2str(data.phase)); + set(gui.slider_handles.slider,'Value',data.phase); % time data.time = nmrraw.t; % original unrotated signal - data.signal_raw = nmrraw.s * exp(1i*deg2rad(shift_phase(-data.phase))); + data.signal_raw = nmrraw.s * exp(1i*deg2rad(-data.phase)); % rotated signal data.signal_rot = nmrraw.s; - data.s_max = max(real(data.signal_rot)); - - % SSE data - beta_range = 0:1:360; - SSE = data.signal_raw*exp(1i*deg2rad(beta_range)); - t0 = zeros(size(SSE)); - residual_i = t0-imag(SSE); - residual_r = t0-real(SSE); - sse_i = sum(residual_i.^2,1); - sse_r = sum(residual_r.^2,1)*-1; - data.beta_range = beta_range; - data.sse_i = sse_i; - data.sse_r = sse_r; + data.s_max = max(real(data.signal_rot)); + % keep original signal + data.orig_data = nucleus.data.import.NMR.data{ID}; + data.orig_para = nucleus.data.import.NMR.para{ID}; + + % update GUI data setappdata(fig_phase,'data',data); setappdata(fig_phase,'gui',gui); - pv_showSignal(fig_phase); + % calculate SSR + pv_updateFullDataSet(fig_phase); + % update plots + pv_plotSignal(fig_phase); + pv_plotSSR(fig_phase); + else + % close the GUI because the selected signal is not a T2 signal helpdlg({'function: PhaseView',... 'Cannot continue because there is no T2 data!'},... 'No T2 data.'); @@ -197,155 +379,466 @@ function PhaseView(src,~) end -function pv_onPushDefault(src,~) +%% subfunction to update the edit fields +function pv_onEditValue(src,~) fig_phase = ancestor(src,'figure','toplevel'); gui = getappdata(fig_phase,'gui'); data = getappdata(fig_phase,'data'); -data.phase = data.phase_default; -set(gui.slider,'Value',data.phase); -set(gui.edit_phase,'String',num2str(data.phase)); +switch get(src,'Tag') + case {'first','last'} + data.echo_range(1) = str2double(get(gui.edit_handles.first,'String')); + data.echo_range(2) = str2double(get(gui.edit_handles.last,'String')); + % update GUI data + setappdata(fig_phase,'data',data); + pv_updateFullDataSet(fig_phase); + data = getappdata(fig_phase,'data'); + setappdata(fig_phase,'data',data); + pv_plotSignal(fig_phase); + pv_plotSSR(fig_phase); + case {'range_min','range_max'} + data.phase_range(1) = str2double(get(gui.edit_handles.range_min,'String')); + data.phase_range(2) = str2double(get(gui.edit_handles.range_max,'String')); + % update GUI data + setappdata(fig_phase,'data',data); + pv_plotSSR(fig_phase); + case 'phase' + data.phase = str2double(get(gui.edit_handles.phase,'String')); + % update slider + set(gui.slider_handles.slider,'Value',data.phase); + % apply new phase + data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); + % update GUI data + setappdata(fig_phase,'data',data); + setappdata(fig_phase,'gui',gui); + pv_plotSignal(fig_phase); + pv_plotSSR(fig_phase); +end -data.signal_rot = data.signal_raw * exp(1i*deg2rad(shift_phase(data.phase))); +% update GUI data +setappdata(fig_phase,'data',data); +end +%% subfunction to control the phase angle push buttons +function pv_onPushAngle(src,~) +fig_phase = ancestor(src,'figure','toplevel'); +gui = getappdata(fig_phase,'gui'); +data = getappdata(fig_phase,'data'); + +% get the angle offset according to the chosen button +switch get(src,'Tag') + case 'button_m90' + offset = -90; + case 'button_m45' + offset = -45; + case 'button_pm180' + offset = 180; + case 'button_p45' + offset = 45; + case 'button_p90' + offset = 90; + otherwise + offset = 0; +end + +% map phase into the correct range +data.phase = -180 + mod((data.phase + offset)+180,360); +% update edit field +set(gui.edit_handles.phase,'String',num2str(data.phase)); +% update slider +set(gui.slider_handles.slider,'Value',data.phase); +% new rotated signal +data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); + +% update GUI data setappdata(fig_phase,'data',data); setappdata(fig_phase,'gui',gui); -pv_showSignal(fig_phase); - +% update plots +pv_plotSignal(fig_phase); +pv_plotSSR(fig_phase); end -function pv_onPushSave(src,~) +%% subfunction to control the push button to apply the phase angle +function pv_onPushApply(src,~) fig_phase = ancestor(src,'figure','toplevel'); -gui = getappdata(fig_phase,'gui'); data = getappdata(fig_phase,'data'); +% get handle and data of main GUI fig = findobj('Tag','INV'); nucleus.data = getappdata(fig,'data'); nucleus.gui = getappdata(fig,'gui'); -% get the selected signal ID +% get selected signal ID from main GUI id = get(nucleus.gui.listbox_handles.signal,'Value'); -% update phase -nucleus.data.import.NMR.data{id}.phase = deg2rad(data.phase); -nucleus.data.results.nmrraw.phase = deg2rad(data.phase); -% update signal -nucleus.data.import.NMR.data{id}.signal = data.signal_rot; -nucleus.data.results.nmrraw.s = data.signal_rot; -% update GUI data -setappdata(fig,'data',nucleus.data); +switch get(src,'Tag') + case 'apply' + % update phase + nucleus.data.import.NMR.data{id}.phase = deg2rad(data.phase); + nucleus.data.results.nmrraw.phase = deg2rad(data.phase); + % update signal + nucleus.data.import.NMR.data{id}.signal = data.signal_rot; + nucleus.data.results.nmrraw.s = data.signal_rot; + + case 'apply2all' + N = numel(nucleus.data.import.NMR.data); + for i1 = 1:N + % only proceed if the signal is complex (T2 data) + if ~isreal(nucleus.data.import.NMR.data{i1}.signal) + % original unrotated signal + phase_org = rad2deg(nucleus.data.import.NMR.data{i1}.phase); + s_raw = nucleus.data.import.NMR.data{i1}.raw.signal; + s_raw = s_raw * exp(1i*deg2rad(-phase_org)); + + % new phase + phase_new = data.phase; + nucleus.data.import.NMR.data{i1}.phase = deg2rad(phase_new); + % signal with new phase + s_new = s_raw * exp(1i*deg2rad(phase_new)); + % update signal + nucleus.data.import.NMR.data{i1}.signal = s_new; + nucleus.data.import.NMR.data{i1}.raw.signal= s_new; + end + end + % check if it is a T1-T2 data set, because then we need to adjust + % the merged T1 curve also + if isfield(nucleus.data.import,'T1T2map') + % the last signal is the merged T1 curve + N = numel(nucleus.data.import.T1T2map.t_recov) + 1; + + s_old = nucleus.data.import.NMR.data{N}.signal; + time = nucleus.data.import.T1T2map.t_recov; + s_new = zeros(size(s_old)); + for i1 = 1:numel(time) + s_new(i1) = mean(real(nucleus.data.import.NMR.data{i1}.signal(1:3))); + end + + % estimate noise of the new merged T1 curve + disp('NUCLUESinv PhaseView: Estimating noise from exponential fit ...'); + flag = 'T1'; + param.T1IRfac = nucleus.data.import.NMR.data{N}.T1IRfac; + param.noise = 0; + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + for i1 = 1:5 + invstd = fitDataFree(time,s_new,flag,param,i1); + if i1 == 1 + noise = invstd.rms; + else + noise = min([noise invstd.rms]); + end + end + % update data + nucleus.data.import.NMR.data{N}.signal = s_new; + nucleus.data.import.NMR.data{N}.noise = noise; + nucleus.data.import.NMR.data{N}.raw.signal = s_new; + end +end +% update main GUI data +setappdata(fig,'data',nucleus.data); +% set focus on chosen signal +set(nucleus.gui.listbox_handles.signal,'Value',id); +onListboxData(nucleus.gui.listbox_handles.signal); end -function pv_showSignal(fig_phase) +%% subfunction to control the push button to restore the default phase angle +function pv_onPushKeep(src,~) +fig_phase = ancestor(src,'figure','toplevel'); +gui = getappdata(fig_phase,'gui'); data = getappdata(fig_phase,'data'); + +% get original pahse +data.phase = data.phase_default; +% update edit field +set(gui.edit_handles.phase,'String',num2str(data.phase)); +% update slider +set(gui.slider_handles.slider,'Value',data.phase); +% new rotated signal +data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); + +% update GUI data +setappdata(fig_phase,'data',data); +setappdata(fig_phase,'gui',gui); +% update plots +pv_plotSignal(fig_phase); +pv_plotSSR(fig_phase); +end + +%% subfunction to control the push button to fit the phase angle +function pv_onPushRun(src,~) +fig_phase = ancestor(src,'figure','toplevel'); gui = getappdata(fig_phase,'gui'); +data = getappdata(fig_phase,'data'); -% axes handles -ax1 = gui.axes_handles.real; -ax2 = gui.axes_handles.imag; -ax3 = gui.axes_handles.sse; -% clear all axes -clearAllAxes(fig_phase); -hold(ax1,'on'); -hold(ax2,'on'); -hold(ax3,'on'); +% get signal +s = data.signal_raw; -plot(data.time,real(data.signal_rot),'Color',gui.myui.colors.RE,'Parent',ax1); -plot(data.time,imag(data.signal_rot),'Color',gui.myui.colors.IM,'Parent',ax2); +% get signal bounds +te_start = data.echo_range(1); +te_end = data.echo_range(2); -switch data.loglinx - case 'x-axis -> lin' % log axes - xticks = floor(log10(data.time(1)))-1:1:log10(max(data.time))+1; - set(ax1,'XScale','log','XLim',[data.time(1) max(data.time)],'XTick',10.^xticks); - set(ax2,'XScale','log','XLim',[data.time(1) max(data.time)],'XTick',10.^xticks); - case 'x-axis -> log' % lin axes - set(ax1,'XScale','lin','XLim',[0 max(data.time)],'XTickMode','auto'); - set(ax2,'XScale','lin','XLim',[0 max(data.time)],'XTickMode','auto'); -end -grid(ax1,'on'); -grid(ax2,'on'); +% get fit method +fitval = get(gui.popup_handles.fitmethod,'Value'); +fitmethod = get(gui.popup_handles.fitmethod,'String'); +fitmethod = fitmethod{fitval}; -line(get(ax2,'XLim'),[0 0],'LineStyle','--','Color',gui.myui.colors.axisL,'LineWidth',1,'Parent',ax2); -hold(ax2,'off'); +% get phase angle range +alpha_range = deg2rad(data.phase_range); + +% optim settings +options = optimset('MaxFunEvals',100,'MaxIter',100,'TolFun',1e-6,'TolX',1e-6); +% call fit function +[alpha,~,~,~] = fminsearchbnd(@(alpha) phasefit_fcn(alpha,s(te_start:te_end),fitmethod),... + mean(alpha_range),alpha_range(1),alpha_range(2),options); + +% s_rot is rotated signal +data.signal_rot = s .* exp(1i*alpha); + +% save new phase +data.phase = rad2deg(alpha); +% update edit field +set(gui.edit_handles.phase,'String',num2str(data.phase)); +% update slider +set(gui.slider_handles.slider,'Value',data.phase); -%residual of current phase angle -res_r = zeros(size(data.time))-real(data.signal_rot); -res_i = zeros(size(data.time))-imag(data.signal_rot); -sse_r = sum(res_r.^2); -sse_i = sum(res_i.^2); - -set(get(ax1,'XLabel'),'String','time'); -set(get(ax1,'YLabel'),'String','\Reeal'); -text(0.975,0.8,['\Sigma \epsilon^2 = ',sprintf('%6.5e',sse_r)],... - 'HorizontalAlignment','right','BackgroundColor',gui.myui.colors.axisBG,... - 'Color',gui.myui.colors.panelFG,'Units','normalized',... - 'FontSize',12,'Parent',ax1); -set(get(ax2,'XLabel'),'String','time'); -set(get(ax2,'YLabel'),'String','\Immag'); -text(0.975,0.8,['\Sigma \epsilon^2 = ',sprintf('%6.5e',sse_i)],... - 'HorizontalAlignment','right','BackgroundColor',gui.myui.colors.axisBG,... - 'Color',gui.myui.colors.panelFG,'Units','normalized',... - 'FontSize',12,'Parent',ax2); - -ymin = min([-1.*data.sse_r data.sse_i]); -ymax = max([-1.*data.sse_r data.sse_i]); -plot(data.beta_range-180,-1.*data.sse_r,'Color',gui.myui.colors.RE,'Parent',ax3); -plot(data.beta_range-180,data.sse_i,'Color',gui.myui.colors.IM,'Parent',ax3); -line([data.phase data.phase],[ymin ymax],'Color',gui.myui.colors.axisL,'LineStyle','--','Parent',ax3) -lgh = legend(ax3,'\Reeal','\Immag','\phi'); -set(lgh,'FontSize',12,'TextColor',gui.myui.colors.panelFG); - -set(ax3,'XLim',[-180 180],'XTick',-180:30:180); -set(ax3,'YLim',[ymin ymax]); -set(get(ax3,'XLabel'),'String','phase \phi [deg]'); -set(get(ax3,'YLabel'),'String','\Sigma \epsilon^2'); -hold(ax3,'off'); - -set(ax1,'FontSize',gui.myui.fontsize); -set(ax2,'FontSize',gui.myui.fontsize); -set(ax3,'FontSize',gui.myui.fontsize); - -set(get(ax1,'YLabel'),'FontSize',16); -set(get(ax2,'YLabel'),'FontSize',16); +% update GUI data +setappdata(fig_phase,'data',data); +setappdata(fig_phase,'gui',gui); +% update plots +pv_plotSignal(fig_phase); +pv_plotSSR(fig_phase); +end +% minimization function +function sse = phasefit_fcn(alpha,s,method) +% Inputs: +% alpha - rotation phase angle in [rad] +% s - NMR signal vector (has to be complex!) +% method - "maxRE minIM", "maxRE", "minIM" or "minIMstd" +% +% Outputs: +% sse - sum of squared residuals (option 1 to 3) or +% standard deviation of imag. part (option 4) + +s = s(:); +switch method + case 'maxRE minIM' + % make a vector of zeros + t0 = zeros(size(s,1),1); + t0 = t0(:); + % s_rot is the rotated signal + s_rot = s .* exp(1i*alpha); + % create residuals + residuali = t0-imag(s_rot); + residualr = t0-real(s_rot); + % real part times -1 because we seek the maximum + sse = sum(residuali.^2) + sum(residualr.^2)*-1; + case 'maxRE' + % make a vector of zeros + t0 = zeros(size(s,1),1); + t0 = t0(:); + % s_rot is the rotated signal + s_rot = s .* exp(1i*alpha); + % create residuals + residualr = t0-real(s_rot); + % maximum of real part should be maximized + sse = sum(residualr.^2)*-1; + case 'minIM' + % make a vector of zeros + t0 = zeros(size(s,1),1); + t0 = t0(:); + % s_rot is the rotated signal + s_rot = s .* exp(1i*alpha); + % create residuals + residuali = t0-imag(s_rot); + % sse + sse = sum(residuali.^2); + case 'minIMstd' + % s_rot is the rotated signal + s_rot = s .* exp(1i*alpha); + % standard deviation of the imaginary part should be minimized + sse = std(imag(s_rot)); end -function pv_updateSlider(src,~) +end + +%% subfunction to control the slider +function pv_onSlider(src,~) fig_phase = ancestor(src,'figure','toplevel'); gui = getappdata(fig_phase,'gui'); data = getappdata(fig_phase,'data'); -data.phase = get(gui.slider,'Value'); -set(gui.edit_phase,'String',num2str(data.phase)); - -data.signal_rot = data.signal_raw * exp(1i*deg2rad(shift_phase(data.phase))); +% new phase angle from slider +data.phase = get(src,'Value'); +% update edit field +set(gui.edit_handles.phase,'String',num2str(data.phase)); +% new rotated signal +data.signal_rot = data.signal_raw * exp(1i*deg2rad(data.phase)); +% update GUI data setappdata(fig_phase,'data',data); setappdata(fig_phase,'gui',gui); -pv_showSignal(fig_phase); - +% update signals +pv_plotSignal(fig_phase); +pv_plotSSR(fig_phase); end -function pv_updatePhase(src,~) -fig_phase = ancestor(src,'figure','toplevel'); -gui = getappdata(fig_phase,'gui'); +%% subfunction to calculate the full SSE values for a range of phase angles +function pv_updateFullDataSet(fig_phase) data = getappdata(fig_phase,'data'); -data.phase = str2double(get(gui.edit_phase,'String')); -set(gui.slider,'Value',data.phase); +% get echo range +te_start = data.echo_range(1); +te_end = data.echo_range(2); +% get all signals with the desired phase angles +SSE = data.signal_raw*exp(1i*deg2rad(data.beta_range)); -data.signal_rot = data.signal_raw * exp(1i*deg2rad(shift_phase(data.phase))); +% get individual SSRs +sse_r = getSSR(real(SSE(te_start:te_end,:))); +sse_i = getSSR(imag(SSE(te_start:te_end,:))); +% save data +data.sse_i = sse_i; +data.sse_r = sse_r; +% update GUI data setappdata(fig_phase,'data',data); -setappdata(fig_phase,'gui',gui); -pv_showSignal(fig_phase); +end + +%% subfunction to plot the REal and IMag signal parts +function pv_plotSignal(fig_phase) +data = getappdata(fig_phase,'data'); +gui = getappdata(fig_phase,'gui'); + +% axes handles +ax1 = gui.axes_handles.real; +ax2 = gui.axes_handles.imag; +clearSingleAxis(ax1); +clearSingleAxis(ax2); + +% plot Real and IMag part of signal +plot(data.time,real(data.signal_rot),'Color',gui.myui.colors.RE,'Parent',ax1); +plot(data.time,imag(data.signal_rot),'Color',gui.myui.colors.IM,'Parent',ax2); + +hold(ax1,'on'); +hold(ax2,'on'); + +switch data.loglinx + case 'x-axis -> lin' % log axes + xticks = floor(log10(data.time(1)))-1:1:log10(max(data.time))+1; + set([ax1 ax2],'XScale','log','XLim',[data.time(1) max(data.time)],'XTick',10.^xticks); + case 'x-axis -> log' % lin axes + set([ax1 ax2],'XScale','lin','XLim',[0 max(data.time)],'XTickMode','auto'); +end +grid([ax1 ax2],'on'); + +set([ax1 ax2],'XLim',[data.orig_data.raw.time(1) data.orig_data.raw.time(end)]); +set(get(ax1,'YLabel'),'String','Real Ampl.'); +set(get(ax2,'XLabel'),'String','time [s]'); +set(get(ax2,'YLabel'),'String','Imag Ampl.'); + +% get SSR of current signal +te_start = data.echo_range(1); +te_end = data.echo_range(2); +sse_r = getSSR(real(data.signal_rot(te_start:te_end))); +sse_i = getSSR(imag(data.signal_rot(te_start:te_end))); + +set(get(ax1,'Title'),'String',['SSR: ',sprintf('%6.5e',sse_r)]); +set(get(ax2,'Title'),'String',['SSR: ',sprintf('%6.5e',sse_i)]); + +% plot patches to indicate echo range +p_alpha = 0.8; +xlims = get(ax1,'XLim'); +ylims_re = get(ax1,'YLim'); +ylims_im = get(ax2,'YLim'); +if data.time(te_start)>xlims(1) + % draw a transparent patch + v_re = [xlims(1) ylims_re(1); xlims(1) ylims_re(2); + data.time(te_start) ylims_re(2); data.time(te_start) ylims_re(1)]; + v_im = [xlims(1) ylims_im(1); xlims(1) ylims_im(2); + data.time(te_start) ylims_im(2); data.time(te_start) ylims_im(1)]; + f = [1 2 3 4 1]; + patch('Vertices',v_re,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... + 'HandleVisibility','off','Tag','infolines','Parent', ax1); + patch('Vertices',v_im,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... + 'HandleVisibility','off','Tag','infolines','Parent', ax2); +end +if data.time(te_end)xlims(1) + % draw a transparent patch + v = [xlims(1) ylims(1); xlims(1) ylims(2); + data.phase_range(1) ylims(2); data.phase_range(1) ylims(1)]; + f = [1 2 3 4 1]; + patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... + 'HandleVisibility','off','Tag','infolines','Parent', ax); +end +if data.phase_range(2)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',... + gui.push_handles.run = uicontrol('Parent',gui.panels.control.HBox7,... + 'String','RUN UNCERT. CALC.','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]); + set(gui.panels.control.HBox7,'Widths',[cpanel_w -1]); % --- process panel --- waitbar(2/steps,hwb,'loading GUI elements - process'); @@ -238,7 +244,7 @@ function UncertView(src,~) '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]); + set(gui.panels.process.HBox1,'Widths',[cpanel_w -1 -1]); % model norm range gui.panels.process.HBox2 = uix.HBox('Parent',gui.panels.process.VBox,... 'Spacing',3); @@ -255,14 +261,14 @@ function UncertView(src,~) '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]); + set(gui.panels.process.HBox2,'Widths',[cpanel_w -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',... + 'String','USE','FontSize',myui.fontsize,'Tag','process',... 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... 'Callback',@uv_onPushSend); tstr = 'RESET processing bounds and plots.'; @@ -270,7 +276,7 @@ function UncertView(src,~) '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]); + set(gui.panels.process.HBox3,'Widths',[cpanel_w -1 -1]); % --- RTD panel --- waitbar(3/steps,hwb,'loading GUI elements - RTD bounds'); @@ -297,7 +303,7 @@ function UncertView(src,~) '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]); + set(gui.panels.rtd.HBox1,'Widths',[cpanel_w -1 -1]); % RESET button gui.panels.rtd.HBox3 = uix.HBox('Parent',gui.panels.rtd.VBox,... 'Spacing',3); @@ -308,7 +314,7 @@ function UncertView(src,~) '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]); + set(gui.panels.rtd.HBox3,'Widths',[cpanel_w -1 -1]); % --- Statistics panel --- waitbar(4/steps,hwb,'loading GUI elements - statistics'); @@ -322,7 +328,7 @@ function UncertView(src,~) 'Spacing',3); gui.text_handles.TLGM = uicontrol('Parent',gui.panels.info.HBox1,... 'Style','text','FontSize',myui.fontsize,'HorizontalAlignment','center',... - 'String','TLGM mean | std'); + 'String','TLGM mean | 2*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,... @@ -333,25 +339,25 @@ function UncertView(src,~) '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]); + set(gui.panels.info.HBox1,'Widths',[cpanel_w -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)'); + 'String','TLGM 2*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]); + set(gui.panels.info.HBox2,'Widths',[cpanel_w -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)'); + 'String','TLGM median | 2*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,... @@ -362,13 +368,13 @@ function UncertView(src,~) '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]); + set(gui.panels.info.HBox3,'Widths',[cpanel_w -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'); + 'String','E0 mean | 2*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,... @@ -379,25 +385,25 @@ function UncertView(src,~) '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]); + set(gui.panels.info.HBox4,'Widths',[cpanel_w -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)'); + 'String','E0 2*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]); + set(gui.panels.info.HBox5,'Widths',[cpanel_w -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)'); + 'String','E0 median | 2*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,... @@ -408,14 +414,21 @@ function UncertView(src,~) '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]); + set(gui.panels.info.HBox6,'Widths',[cpanel_w -1 -1]); % --- update MAIN GUI button --- + gui.panels.save.VBox1 = uix.VBox('Parent',gui.left,... + 'Spacing',3); tstr = 'UPDATE uncertainty data in main NUCLEUSinv GUI.'; - gui.push_handles.update = uicontrol('Parent',gui.left,... + gui.push_handles.update = uicontrol('Parent',gui.panels.save.VBox1,... 'String','UPDATE MAIN GUI','FontSize',myui.fontsize,'Tag','update',... 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... 'Callback',@uv_onPushUpdate); + tstr = 'Export current graphics view to Figure.'; + gui.push_handles.view = uicontrol('Parent',gui.panels.save.VBox1,... + 'String','VIEW2FIG','FontSize',myui.fontsize,'Tag','view',... + 'ToolTipString',tstr,'UserData',struct('Tooltipstr',tstr),... + 'Callback',@uv_onPushView); % fix text vertical alignment jh = findjobj(gui.text_handles.uncertMethod); @@ -428,8 +441,8 @@ function UncertView(src,~) 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.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); @@ -452,7 +465,7 @@ function UncertView(src,~) % 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]; + heights = [22 22 22 22 28 -1; 22+6*24+8*3 22+3*24+5*3 22+2*24+4*4 22+6*24+8*3 28*2 -1]; % panel header is always 22 high set(gui.left,'Heights',heights(2,:),... 'MinimumHeights',[22 22 22 22 28 0]); @@ -483,7 +496,7 @@ function UncertView(src,~) 'BackGroundColor',colors.panelBG); set(gui.righttop2,'Widths',[-1 -1 ]); - gui.rightPanel.TabTitles = {'Statistics','Histograms'}; + gui.rightPanel.TabTitles = {'STATISTICS','HISTOGRAMS'}; gui.rightPanel.TabWidth = 75; gui.rightPanel.TabEnables = {'on','on'}; @@ -703,6 +716,10 @@ function uv_onEditValue(src,~) data.uv = uv; end +% in case of error reactivate the run button +set(gui.push_handles.run,'String','RUN UNCERT. CALC.',... + 'BackgroundColor','g','Enable','on','Callback',@uv_onPushRun); +setappdata(figh,'gui',gui); % update GUI data setappdata(figh,'data',data); % update information @@ -920,6 +937,11 @@ function uv_onPushRun(src,~) invstd = data.results.invstd; uncert = invstd.uncert; +% disable the CALC: button to indicate a running calculation +set(gui.push_handles.run,'String','RUNNING ...',... + 'BackgroundColor',get(gui.push_handles.update,'BackgroundColor'),... + 'Enable','off'); pause(0.01); + % original fit parameter iparam = invstd.invparams; % original uncertainty parameter @@ -933,6 +955,11 @@ function uv_onPushRun(src,~) uparam.uncert.Max = uv.uncertMax; invstd = estimateUncertainty(invstd.invtype,invstd,iparam,uparam); +% enable the CALC. button +set(gui.push_handles.run,'String','RUN UNCERT. CALC.',... + 'BackgroundColor','g','Enable','on','Callback',@uv_onPushRun); +setappdata(figh,'gui',gui); + % save updated inversion results invstd.uncert.params = uparam; data.results.invstd = invstd; @@ -970,6 +997,63 @@ function uv_onPushRun(src,~) beautifyAxes(figh); end +%% subfunction to export the current view to a figure +function uv_onPushView(src,~) +figh = ancestor(src,'figure','toplevel'); +% local GUI data +gui = getappdata(figh,'gui'); + +% opening the export figure +expfig = figure('Color',gui.myui.colors.panelBG); + +% create axes layout depending on view +switch get(gui.rightPanel,'Selection') + case 1 + % create layout + ax1 = subplot(2,2,1,'Parent',expfig); + ax2 = subplot(2,2,2,'Parent',expfig); + ax3 = subplot(2,2,[3 4],'Parent',expfig); + % get positions + pos1 = get(ax1,'Position'); + pos2 = get(ax2,'Position'); + pos3 = get(ax3,'Position'); + % delete axes + delete(ax1);delete(ax2);delete(ax3); + % copy GUI axes + ax1 = copyobj(gui.axes12,expfig); + ax2 = copyobj(gui.axes11,expfig); + ax3 = copyobj(gui.axes2,expfig); + % adjust positions + set(ax1,'Position',pos1); + set(ax2,'Position',pos2); + set(ax3,'Position',pos3); + % legend + legend(ax2,'Location','best'); + case 2 + % create layout + ax1 = subplot(2,2,1,'Parent',expfig); + ax2 = subplot(2,2,2,'Parent',expfig); + ax3 = subplot(2,2,[3 4],'Parent',expfig); + % get positions + pos1 = get(ax1,'Position'); + pos2 = get(ax2,'Position'); + pos3 = get(ax3,'Position'); + % delete axes + delete(ax1);delete(ax2);delete(ax3); + % copy GUI axes + ax1 = copyobj(gui.axes21,expfig); + ax2 = copyobj(gui.axes22,expfig); + ax3 = copyobj(gui.axes2,expfig); + % adjust positions + set(ax1,'Position',pos1); + set(ax2,'Position',pos2); + set(ax3,'Position',pos3); + % legend + legend(ax2,'Location','best'); +end + +end + %% subfunction to update the main NUCLEUSinv GUI function uv_onPushUpdate(src,~) figh = ancestor(src,'figure','toplevel'); @@ -1163,8 +1247,10 @@ function uv_updatePlots(figh) 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); + % tmpE0 = uncert.interp_E0(in); + % tmpTlgm = uncert.interp_Tlgm(in); + tmpE0 = uv.stats.E0_all; + tmpTlgm = uv.stats.Tlgm_all; clims = [0 1]; case 'chi2' tmp = uncert.chi2_all(in); @@ -1172,9 +1258,11 @@ function uv_updatePlots(figh) lcolors = tmpchi2; tmpmnorm = uncert.mnorm_all(in); tmpmnorm = tmpmnorm(idx); - tmpE0 = uncert.interp_E0(in); + % tmpE0 = uncert.interp_E0(in); + tmpE0 = uv.stats.E0_all; tmpE0 = tmpE0(idx); - tmpTlgm = uncert.interp_Tlgm(in); + % tmpTlgm = uncert.interp_Tlgm(in); + tmpTlgm = uv.stats.Tlgm_all; tmpTlgm = tmpTlgm(idx); clims = [min(uncert.chi2_all) max(uncert.chi2_all)]; case 'xn' @@ -1183,9 +1271,11 @@ function uv_updatePlots(figh) lcolors = tmpmnorm; tmpchi2 = uncert.chi2_all(in); tmpchi2 = tmpchi2(idx); - tmpE0 = uncert.interp_E0(in); + % tmpE0 = uncert.interp_E0(in); + tmpE0 = uv.stats.E0_all; tmpE0 = tmpE0(idx); - tmpTlgm = uncert.interp_Tlgm(in); + % tmpTlgm = uncert.interp_Tlgm(in); + tmpTlgm = uv.stats.Tlgm_all; tmpTlgm = tmpTlgm(idx); clims = [min(uncert.mnorm_all) max(uncert.mnorm_all)]; end @@ -1311,7 +1401,7 @@ function uv_updatePlots(figh) end end -% if selcted plot patch +% if selected plot patch if plotmethod > 1 % what kind of patch is created if plotmethod == 2 % mean +- std @@ -1352,24 +1442,43 @@ function uv_updatePlots(figh) % 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); +% axes properties +ticks = 10.^(round(log10(min(invstd.T1T2me)) :1: log10(max(invstd.T1T2me)))); +set(gui.axes2,'XScale','log','XLim',[ticks(1) ticks(end)],'XTick',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'); +% -- 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'); +p_alpha = 0.8; +if uv.rtd_range(1)>ticks(1) + % draw a transparent patch + v = [ticks(1) ylims(1); ticks(1) ylims(2); + uv.rtd_range(1) ylims(2); uv.rtd_range(1) ylims(1)]; + f = [1 2 3 4 1]; + patch('Vertices',v,'Faces',f,'FaceColor','w','FaceAlpha',p_alpha,... + 'HandleVisibility','off','Tag','infolines','Parent', gui.axes2); +end +if uv.rtd_range(2) 0 + tmpstr = fullfile(NMRpath,NMRfile); + else + tmpstr = NMRpath; + end + if length(tmpstr)>50 + set(gui.text_handles.data_path,'String',['...',tmpstr(end-50:end)],... + 'HorizontalAlignment','left'); + else + set(gui.text_handles.data_path,'String',tmpstr,... + 'HorizontalAlignment','left'); + end + set(gui.text_handles.data_path,'TooltipString',tmpstr); + + fnames = struct; + % shownames is just a dummy to hold all data file names that + % will be shown in the listbox + shownames = cell(1,1); + + T1T2 = 'T2'; + T1IRfac = datamod.nmr.T1IRfac; + + c = 0; + for i = 1:numel(data.import.NMRMOD.nmr) + % the individual file names + c = c + 1; + fnames(c).parfile = ''; + fnames(c).datafile = data.import.file; + fnames(c).T2specfile = ''; + + shownames{c} = ['NUCLEUSmod_',T1T2,'_2D_',num2str(i)]; + + % the 'header' data + data.import.NMR.data{c}.datfile = fileID.name; + data.import.NMR.data{c}.date = datestr(addtodate(fileID.datenum,-numel(data.import.NMRMOD.nmr)+i,'minute')); + data.import.NMR.data{c}.datenum = addtodate(fileID.datenum,-numel(data.import.NMRMOD.nmr)+i,'minute'); + data.import.NMR.data{c}.bytes = fileID.bytes; + % the NMR data + data.import.NMR.data{c}.flag = T1T2; + data.import.NMR.data{c}.T1IRfac = T1IRfac; + data.import.NMR.data{c}.time = data.import.NMRMOD.nmr(i).t(:); + + data.import.NMR.data{c}.signal = data.import.NMRMOD.nmr(i).s(:); + data.import.NMR.data{c}.noise = data.import.NMRMOD.nmr(i).noise; + + data.import.NMR.data{c}.phase = 0; + 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.para{c}.geom = data.import.NMRMOD.geom.type; + data.import.NMR.para{c}.Tbulk = datamod.prop.Tbulk; + data.import.NMR.para{c}.Tdiff = 1e6; + data.import.NMR.para{c}.t_echo = datamod.nmr.T2te; + data.import.NMR.para{c}.rho = 100; + data.import.NMR.para{c}.porosity = 1; + end + + % set T2 echo time + data.inv2D.prop.te = datamod.nmr.T2te; + + % save the recovery time vector for later use + data.import.T1T2map.t_recov = datamod.results.mod2D.t_recov(:); + data.import.T1T2map.t2 = data.import.NMR.data{1}.time; + data.import.T1T2map.t2N = numel(data.import.NMR.data{1}.time); + + % add the stacked signal to the data + flag = 'T1'; + time = data.import.T1T2map.t_recov; + signal = zeros(numel(data.import.NMR.data),1); + for i1 = 1:numel(data.import.NMR.data) + % signal(i1,1) = mean(real(data.import.NMR.data{i1}.signal(1:3))); + signal(i1,1) = real(data.import.NMR.data{i1}.signal(1)); + end + disp('NUCLUESinv import: Estimating noise from exponential fit ...'); + 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]; + for i1 = 1:5 + invstd = fitDataFree(time,signal,flag,param,i1); + if i1 == 1 + noise = invstd.rms; + else + noise = min([noise invstd.rms]); + end + end + disp('NUCLUESinv import: done.') + % finally create a new "import" data set + data_new = data.import.NMR.data(1); + para_new = data.import.NMR.para(1); + + data_new{1}.flag = flag; + data_new{1}.T1IRfac = param.T1IRfac; + data_new{1}.time = time; + data_new{1}.signal = signal; + data_new{1}.noise = noise; + data_new{1}.raw.time = time; + data_new{1}.raw.signal = signal; + + data.import.NMR.data{numel(time)+1} = data_new{1}; + data.import.NMR.para{numel(time)+1} = para_new{1}; + fnames(numel(time)+1).datafile = 'T1_merged.dat'; + shownames{numel(time)+1} = 'T1_merged'; + + data.import.NMR.files = fnames; + data.import.NMR.filesShort = shownames; + + % update the list of file names + set(gui.listbox_handles.signal,'String',data.import.NMR.filesShort); + set(gui.listbox_handles.signal,'Value',[],'Max',2,'Min',0); + + % create a global INVdata struct for every file in the list + if isstruct(getappdata(fig,'INVdata')) + setappdata(fig,'INVdata',[]); + end + INVdata = cell(length(data.import.NMR.filesShort),1); + setappdata(fig,'INVdata',INVdata); + + % clear all axes + clearAllAxes(gui.figh); + + % enable GUI data and interface + setappdata(fig,'data',data); + setappdata(fig,'gui',gui); + enableGUIelements('MOD'); + NUCLEUSinv_updateInterface; +else + helpdlg({'importNUCLEUSmod:',... + 'NUCLEUSmod data import unsuccessful.'},'import error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% MIT License +% +% Copyright (c) 2018 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/importMOD2INV.m b/functions/interface/importMOD2INV.m index 7261ea8..24e8a38 100644 --- a/functions/interface/importMOD2INV.m +++ b/functions/interface/importMOD2INV.m @@ -1,5 +1,5 @@ function importMOD2INV(src) -%importINV2INV imports data directly from the NUCLEUSmod GUI or and +%importMOD2INV imports data directly from the NUCLEUSmod GUI or and %NUCLEUSmod data file % % Syntax: @@ -87,8 +87,8 @@ function importMOD2INV(src) if isfield(datamod.results,'NMR') % file info fileID.name = 'NUCLEUSmod GUI'; - fileID.date = datestr(now); - fileID.datenum = now; + fileID.date = string(datetime("now")); + fileID.datenum = convertTo(datetime("now"),"datenum"); fileID.bytes = 0; NMRpath = pwd; diff --git a/functions/interface/importNMRdata.m b/functions/interface/importNMRdata.m index 799c499..1b1ae82 100644 --- a/functions/interface/importNMRdata.m +++ b/functions/interface/importNMRdata.m @@ -56,7 +56,11 @@ function importNMRdata(src) label = get(src,'Label'); % set file format for later use - if strcmp(label,'BAM TOM') + if strcmp(label,'Dart T1T2') + data.import.fileformat = 'dartSeries'; + elseif strcmp(label,'Dart T2 logging') + data.import.fileformat = 'dartT2logging'; + elseif strcmp(label,'BAM TOM') data.import.fileformat = 'bamtom'; elseif strcmp(label,'BGR mat') data.import.fileformat = 'bgrmat'; @@ -65,7 +69,9 @@ function importNMRdata(src) elseif strcmp(label,'CoreLab ascii') data.import.fileformat = 'corelab'; elseif strcmp(label,'DART') - data.import.fileformat = 'dart'; + data.import.fileformat = 'dart'; + elseif strcmp(label,'DART (+Burst)') + data.import.fileformat = 'dartT2logging'; elseif strcmp(label,'GGE ascii') data.import.fileformat = 'rwth'; elseif strcmp(label,'GGE field') @@ -94,6 +100,8 @@ function importNMRdata(src) data.import.fileformat = 'pm5'; elseif strcmp(label,'PM25') data.import.fileformat = 'pm25'; + elseif strcmp(label,'RoCA T1T2') + data.import.fileformat = 'rocaT1T2'; else helpdlg('Something is utterly wrong.','onMenuImport: Choose again.'); end @@ -136,7 +144,10 @@ function importNMRdata(src) case 'DART' data.import.file = NMRfile; data.import.version = 3; - [data,gui] = importDataDart(data,gui); + [data,gui] = importDataDart(data,gui); + case 'DART (+Burst)' + data.import.file = NMRfile; + [data,gui] = importDataDartT2logging(data,gui,1); case 'MOUSE' [data,gui] = importDataMouse(data,gui); case 'LIAG single' @@ -168,6 +179,15 @@ function importNMRdata(src) case {'PM5','PM25'} data.import.file = NMRfile; [data,gui] = importDataIBAC(data,gui); + case 'Dart T1T2' + data.import.file = NMRfile; + [data,gui] = importDataDartSeries(data,gui); + case 'Dart T2 logging' + data.import.file = NMRfile; + [data,gui] = importDataDartT2logging(data,gui,0); + case 'RoCA T1T2' + data.import.file = NMRfile; + [data,gui] = importDataRoCAT1T2(data,gui); end displayStatusText(gui,'Reading NMR Data ... done'); else @@ -263,7 +283,8 @@ function importNMRdata(src) switch label case {'BAM TOM','BGR std','CoreLab ascii','GGE ascii','GGE field',... 'HeliosCPMG','HeliosSeries','LIAG core','LIAG single',... - 'MOUSE','MouseCPMG','MouseLift','PM25'} + 'MOUSE','MouseCPMG','MouseLift','PM25','Dart T1T2','Dart T2 logging',... + 'DART (+Burst)','RoCA T1T2'} % if there is already a data folder present we start from here if isfield(import,'path') NMRpath = uigetdir(import.path,'Choose Data Path'); @@ -495,6 +516,7 @@ function importNMRdata(src) data.import.NMR.filesShort = shownames; end + %% function [data,gui] = importDataBGRlift(data,gui) @@ -650,26 +672,26 @@ function importNMRdata(src) % check if datpath.name includes regular Helios data files content = dir([data.import.path,filesep,datpath(i).name]); content = content(~ismember({content.name},{'.','..'})); + % only keep hrd-files + content = content(contains({content.name},'.hrd')); + % remove reference hrd-files + content = content(~contains({content.name},'_ref.hrd')); for j = 1:size(content,1) - if strcmp(content(j).name,[datpath(i).name,'.hrd']) - if ~strcmp(content(j).name,[datpath(i).name,'_ref']) - in.T1T2 = 'T2'; - in.name = content(j).name; - in.path = fullfile(data.import.path,filesep,datpath(i).name); - in.fileformat = data.import.fileformat; - out = LoadNMRData_driver(in); - - % the individual file names - c = c + 1; - fnames(c).parfile = ''; - fnames(c).datafile = out.nmrData.datfile; - fnames(c).T2specfile = ''; - shownames{c} = ['T2_',datpath(i).name]; - - data.import.NMR.data{c} = out.nmrData; - data.import.NMR.para{c} = out.parData; - end - end + in.T1T2 = 'T2'; + in.name = content(j).name; + in.path = fullfile(data.import.path,filesep,datpath(i).name); + in.fileformat = data.import.fileformat; + out = LoadNMRData_driver(in); + + % the individual file names + c = c + 1; + fnames(c).parfile = ''; + fnames(c).datafile = out.nmrData.datfile; + fnames(c).T2specfile = ''; + shownames{c} = ['T2_',datpath(i).name]; + + data.import.NMR.data{c} = out.nmrData; + data.import.NMR.para{c} = out.parData; end end end @@ -684,11 +706,52 @@ function importNMRdata(src) %% function [data,gui] = importDataHeliosSeries(data,gui) -% first check the subpaths +% first ask the user if it is pure T2 data or T2 data belonging to a T1 +% measurement to generate T1-T2 maps +answer = questdlg('Is this series a T1 measurement or pure T2?', ... + 'HELIOS import', ... + 'T1','T2','T2'); +switch answer + case 'T1' + is_T1 = true; + case 'T2' + is_T1 = false; + otherwise + is_T1 = false; +end + +% now ask for manualS stacking (only for T2 data) +if ~is_T1 + answer = questdlg('Do you want to stack several files?','Stack Dialog','No'); + switch answer + case 'Yes' + doStack = true; + prompt = {'Enter No. of files to stack together'}; + dlgtitle = 'Stack Value'; + fieldsize = [1 40]; + definput = {'16'}; + answer2 = inputdlg(prompt,dlgtitle,fieldsize,definput); + if ~isempty(answer2) + nstacks = str2double(answer2{1,1}); + else + doStack = false; + end + otherwise + doStack = false; + end +end + +% now check the subpaths % there should be some folders with names ... % ... similar to the data filenames inside them datpath = dir(data.import.path); datpath = datpath(~ismember({datpath.name},{'.','..'})); +% remove any subfolder within the data directory +datpath = datpath(~ismember([datpath.isdir],true)); +% only keep hrd-files +datpath = datpath(contains({datpath.name},'.hrd')); +% remove reference hrd-files +datpath = datpath(~contains({datpath.name},'_ref.hrd')); fnames = struct; % shownames is just a dummy to hold all data file names that @@ -698,24 +761,595 @@ function importNMRdata(src) c = 0; if ~isempty(datpath) content = datpath; + if is_T1 + t_recov = zeros(floor(numel(content)/2),2); + end for j = 1:size(content,1) - if ~strcmp(content(j).name(end-7:end),'_ref.hrd') + in.T1T2 = 'T2'; + in.name = content(j).name; + in.path = fullfile(data.import.path); + in.fileformat = data.import.fileformat; + out = LoadNMRData_driver(in); + % the individual file names + c = c + 1; + fnames(c).parfile = ''; + fnames(c).datafile = out.nmrData.datfile; + fnames(c).T2specfile = ''; + if is_T1 + shownames{c} = content(j).name; + else + shownames{c} = ['T2_',content(j).name]; + end + + data.import.NMR.data{c} = out.nmrData; + data.import.NMR.para{c} = out.parData; + + % collect recovery times in case of T1 data set + if is_T1 + t_recov(c,1) = out.parData.t_recov; + t_recov(c,2) = out.nmrData.phase; + end + end + + % in case of T1 data, use the phase of the signal with the longest + % recovery time to rotate the other signals + if is_T1 + phase = t_recov(t_recov(:,1)==max(t_recov(:,1)),2); + for i1 = 1:numel(data.import.NMR.data) + % the original raw data + s = data.import.NMR.data{i1}.raw.signal; + s = s * exp(1i*(-data.import.NMR.data{i1}.phase)); + % s_rot is the rotated signal + s_rot = s .* exp(1i*phase); + % write the rotated signal back to the data struct + data.import.NMR.data{i1}.signal = s_rot; + data.import.NMR.data{i1}.phase = phase; + + % get the shortest T2 signal length + if i1 == 1 + t2N = numel(data.import.NMR.data{i1}.raw.time); + else + t2N = min([t2N numel(data.import.NMR.data{i1}.raw.time)]); + end + t2 = data.import.NMR.data{i1}.raw.time(1:t2N); + end + + % for convenience, sort the data by recovery time + [t_s,ix] = sort(t_recov(:,1)); + data.import.NMR.data = data.import.NMR.data(ix); + data.import.NMR.para = data.import.NMR.para(ix); + fnames = fnames(ix); + shownames = shownames(ix); + + % save the recovery time vector for later use + data.import.T1T2map.t_recov = t_s(:,1)/1000; + data.import.T1T2map.t2 = t2; + data.import.T1T2map.t2N = t2N; + + % ask if the single measurements should be "stacked" to one T1 + % curve + answer = questdlg('Do you want a single T1 curve or T1-T2 2D Inversion?', ... + 'HELIOS import', ... + 'single T1','2D Inv','2D Inv'); + switch answer + case 'single T1' + singleT1 = true; + case '2D Inv' + singleT1 = false; + end + + if singleT1 + % ask how many T2-echos should be stacked together to one T1 + % point + prompt = {'Enter T2 #echos for one T1 point'}; + dlgtitle = 'How many T2 echos'; + fieldsize = [1 45]; + definput = {'3'}; + answer = inputdlg(prompt,dlgtitle,fieldsize,definput); + Nechos = str2double(answer{1}); + + flag = 'T1'; + time = data.import.T1T2map.t_recov; + signal = zeros(numel(data.import.NMR.data),1); + for i1 = 1:numel(data.import.NMR.data) + signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); + end + + disp('NUCLUESinv import: Estimating noise from exponential fit ...'); + 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]; + for i1 = 1:5 + invstd = fitDataFree(time,signal,flag,param,i1); + if i1 == 1 + noise = invstd.rms; + else + noise = min([noise invstd.rms]); + end + end + disp('NUCLUESinv import: done.') + + % finally create a new "import" data set + data_new = data.import.NMR.data(1); + para_new = data.import.NMR.para(1); + data.import = rmfield(data.import,'T1T2map'); + + data_new{1}.flag = flag; + data_new{1}.T1IRfac = param.T1IRfac; + data_new{1}.time = time; + data_new{1}.signal = signal; + data_new{1}.noise = noise; + data_new{1}.raw.time = time; + data_new{1}.raw.signal = signal; + + fnames = fnames(1); + shownames = shownames(1); + + data.import.NMR.data = data_new; + data.import.NMR.para = para_new; + else + prompt = {'Enter T2 #echos for one T1 point for the merged T1 curve'}; + dlgtitle = 'How many T2 echos'; + fieldsize = [1 45]; + definput = {'3'}; + answer = inputdlg(prompt,dlgtitle,fieldsize,definput); + Nechos = str2double(answer{1}); + + % add the stacked signal to the data + flag = 'T1'; + time = data.import.T1T2map.t_recov; + signal = zeros(numel(data.import.NMR.data),1); + for i1 = 1:numel(data.import.NMR.data) + signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); + end + + disp('NUCLUESinv import: Estimating noise from exponential fit ...'); + 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]; + for i1 = 1:5 + invstd = fitDataFree(time,signal,flag,param,i1); + if i1 == 1 + noise = invstd.rms; + else + noise = min([noise invstd.rms]); + end + end + disp('NUCLUESinv import: done.') + + % finally create a new "import" data set + data_new = data.import.NMR.data(1); + para_new = data.import.NMR.para(1); + + data_new{1}.flag = flag; + data_new{1}.T1IRfac = param.T1IRfac; + data_new{1}.time = time; + data_new{1}.signal = signal; + data_new{1}.noise = noise; + data_new{1}.raw.time = time; + data_new{1}.raw.signal = signal; + + data.import.NMR.data{numel(t_s)+1} = data_new{1}; + data.import.NMR.para{numel(t_s)+1} = para_new{1}; + fnames(numel(t_s)+1).datafile = 'T1_merged.dat'; + shownames{numel(t_s)+1} = 'T1_merged'; + % set global echo time + data.inv2D.prop.te = data.import.NMR.para{1}.t_echo; + % set T1 SR/IR factor + data.inv2D.inv.T1IRfac = 2; % Helios default + end + else % pure T2 data + % do restacking if desired + if doStack + % before stacking, sort the data by date (time) + N = length(shownames); + time = zeros(N,1); + for i = 1:N + time(i,1) = data.import.NMR.data{i}.datenum; + end + [~,ix] = sort(time); + % now apply changes - resort the imported data + data.import.NMR.data = {data.import.NMR.data{ix'}}; %#ok<*CCAT1> + data.import.NMR.para = {data.import.NMR.para{ix'}}; + fnames = fnames(ix); + shownames = {shownames{ix'}}; + + c = 0; + % prepare data variables + datanew = cell(1,1); + paranew = cell(1,1); + fnamesnew = fnames(1); + shownamesnew = cell(1,1); + tmp_signal = zeros(size(data.import.NMR.data{1}.signal)); + % loop over all already imported files + for i1 = 1:numel(fnames) + % stack up files + tmp_signal = tmp_signal + data.import.NMR.data{i1}.signal; + % check if stack count is reached + if mod(i1,nstacks)==0 + % current stack has finished + c = c + 1; + % save data + datanew{c} = data.import.NMR.data{i1}; + datanew{c}.signal = tmp_signal./nstacks; + datanew{c}.raw.signal = tmp_signal./nstacks; + + paranew{c} = data.import.NMR.para{i1}; + paranew{c}.Nscans = paranew{c}.Nscans*nstacks; + paranew{c}.all{1,1}{6} = ['Nscans = ',num2str(paranew{c}.Nscans)]; + + fnamesnew(c) = fnames(i1); + shownamesnew{c} = [shownames{i1},'_',num2str(nstacks)]; + + % reset the tmp_signal to zero + tmp_signal = zeros(size(data.import.NMR.data{1}.signal)); + end + end + data.import.NMR.data = datanew; + data.import.NMR.para = paranew; + + fnames = fnamesnew; + shownames = shownamesnew; + end + end +end + +% update the global data structure +data.import.NMR.files = fnames; +data.import.NMR.filesShort = shownames; + +end + +%% +function [data,gui] = importDataDartSeries(data,gui) + +% first ask the user if it is pure T2 data or T2 data belonging to a T1 +% measurement to generate T1-T2 maps +answer = questdlg('Is this series a T1 measurement or pure T2?', ... + 'DART import', ... + 'T1','T2','T2'); +switch answer + case 'T1' + is_T1 = true; + case 'T2' + is_T1 = false; + otherwise + is_T1 = false; +end + +% now check the subpaths +% there should be some folders with names ... +% ... similar to the data filenames inside them +datpath = dir(data.import.path); +datpath = datpath(~ismember({datpath.name},{'.','..'})); +% remove any subfolder within the data directory +datpath = datpath(~ismember([datpath.isdir],true)); + +fnames = struct; +% shownames is just a dummy to hold all data file names that +% will be shown in the listbox +shownames = cell(1,1); + +c = 0; +if ~isempty(datpath) + content = datpath; + if is_T1 + t_recov = zeros(1,2); + end + for j = 1:size(content,1) + if strcmp(content(j).name(end-3:end),'.jrd') in.T1T2 = 'T2'; in.name = content(j).name; in.path = fullfile(data.import.path); in.fileformat = data.import.fileformat; + in.version = 4; out = LoadNMRData_driver(in); % the individual file names c = c + 1; fnames(c).parfile = ''; fnames(c).datafile = out.nmrData.datfile; fnames(c).T2specfile = ''; - shownames{c} = ['T2_',content(j).name]; - + if is_T1 + shownames{c} = content(j).name; + else + shownames{c} = ['T2_',content(j).name]; + end + data.import.NMR.data{c} = out.nmrData; data.import.NMR.para{c} = out.parData; + + % collect recovery times in case of T1 data set + if is_T1 + t_recov(c,1) = out.parData.t_recov; + t_recov(c,2) = out.nmrData.phase; + end + end + end + + % in case if T1 data, use the phase of the signal with the longest + % recovery time to rotate the other signals + if is_T1 + phase = t_recov(t_recov(:,1)==max(t_recov(:,1)),2); + for i1 = 1:numel(data.import.NMR.data) + % the original raw data + s = data.import.NMR.data{i1}.raw.signal; + % s_rot is the rotated signal + s_rot = s .* exp(1i*phase); + % write the rotated signal back to the data struct + data.import.NMR.data{i1}.signal = s_rot; + data.import.NMR.data{i1}.phase = phase; + + % get the shortest T2 signal length + if i1 == 1 + t2N = numel(data.import.NMR.data{i1}.raw.time); + else + t2N = min([t2N numel(data.import.NMR.data{i1}.raw.time)]); + end + t2 = data.import.NMR.data{i1}.raw.time(1:t2N); + end + + % for convenience, sort the data by recovery time + [t_s,ix] = sort(t_recov(:,1)); + data.import.NMR.data = data.import.NMR.data(ix); + data.import.NMR.para = data.import.NMR.para(ix); + fnames = fnames(ix); + shownames = shownames(ix); + + % save the recovery time vector for later use + data.import.T1T2map.t_recov = t_s(:,1)/1000; + data.import.T1T2map.t2 = t2; + data.import.T1T2map.t2N = t2N; + + % ask if the single measurements should be "stacked" to one T1 + % curve + answer = questdlg('Do you want a single T1 curve or T1-T2 2D Inversion?', ... + 'DART import', ... + 'single T1','2D Inv','2D Inv'); + switch answer + case 'single T1' + singleT1 = true; + case '2D Inv' + singleT1 = false; end + if singleT1 + % ask how many T2-echos should be stacked together to one T1 + % point + prompt = {'Enter T2 #echos for one T1 point'}; + dlgtitle = 'How many T2 echos'; + fieldsize = [1 45]; + definput = {'3'}; + answer = inputdlg(prompt,dlgtitle,fieldsize,definput); + Nechos = str2double(answer{1}); + + flag = 'T1'; + time = data.import.T1T2map.t_recov; + signal = zeros(numel(data.import.NMR.data),1); + for i1 = 1:numel(data.import.NMR.data) + signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); + end + + disp('NUCLUESinv import: Estimating noise from exponential fit ...'); + 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]; + for i1 = 1:5 + invstd = fitDataFree(time,signal,flag,param,i1); + if i1 == 1 + noise = invstd.rms; + else + noise = min([noise invstd.rms]); + end + end + disp('NUCLUESinv import: done.') + + % finally create a new "import" data set + data_new = data.import.NMR.data(1); + para_new = data.import.NMR.para(1); + data.import = rmfield(data.import,'T1T2map'); + + data_new{1}.flag = flag; + data_new{1}.T1IRfac = param.T1IRfac; + data_new{1}.time = time; + data_new{1}.signal = signal; + data_new{1}.noise = noise; + data_new{1}.raw.time = time; + data_new{1}.raw.signal = signal; + + fnames = fnames(1); + shownames = shownames(1); + + data.import.NMR.data = data_new; + data.import.NMR.para = para_new; + else + prompt = {'Enter T2 #echos for one T1 point for the merged T1 curve'}; + dlgtitle = 'How many T2 echos'; + fieldsize = [1 45]; + definput = {'3'}; + answer = inputdlg(prompt,dlgtitle,fieldsize,definput); + Nechos = str2double(answer{1}); + + % add the stacked signal to the data + flag = 'T1'; + time = data.import.T1T2map.t_recov; + signal = zeros(numel(data.import.NMR.data),1); + for i1 = 1:numel(data.import.NMR.data) + signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); + end + + disp('NUCLUESinv import: Estimating noise from exponential fit ...'); + 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]; + for i1 = 1:5 + invstd = fitDataFree(time,signal,flag,param,i1); + if i1 == 1 + noise = invstd.rms; + else + noise = min([noise invstd.rms]); + end + end + disp('NUCLUESinv import: done.') + + % finally create a new "import" data set + data_new = data.import.NMR.data(1); + para_new = data.import.NMR.para(1); + + data_new{1}.flag = flag; + data_new{1}.T1IRfac = param.T1IRfac; + data_new{1}.time = time; + data_new{1}.signal = signal; + data_new{1}.noise = noise; + data_new{1}.raw.time = time; + data_new{1}.raw.signal = signal; + + data.import.NMR.data{numel(t_s)+1} = data_new{1}; + data.import.NMR.para{numel(t_s)+1} = para_new{1}; + fnames(numel(t_s)+1).datafile = 'T1_merged.dat'; + shownames{numel(t_s)+1} = 'T1_merged'; + % set global echo time + data.inv2D.prop.te = data.import.NMR.para{1}.t_echo; + % set T1 SR/IR factor + data.inv2D.inv.T1IRfac = 1; % Dart default + end + end +end + +% update the global data structure +data.import.NMR.files = fnames; +data.import.NMR.filesShort = shownames; + +end + +%% +function [data,gui] = importDataDartT2logging(data,gui,useburst) + +% now check the subpaths +% there should be some folders with names ... +% ... similar to the data filenames inside them +datpath = dir(data.import.path); +datpath = datpath(~ismember({datpath.name},{'.','..'})); +% remove any subfolder within the data directory +datpath = datpath(~ismember([datpath.isdir],true)); + +fnames = struct; +% shownames is just a dummy to hold all data file names that +% will be shown in the listbox +shownames = cell(1,1); + +c = 0; +if ~isempty(datpath) + content = datpath; + for j = 1:size(content,1) + in.T1T2 = 'T2'; + in.name = content(j).name; + in.path = fullfile(data.import.path); + in.fileformat = data.import.fileformat; + in.version = 5; + out = LoadNMRData_driver(in); + + if useburst + for nn = 1:2 + % get normal and burst signal + idN = nn; + idB = idN+2; + + % add both signals to the data + c = c + 1; + fnames(c).parfile = ''; + fnames(c).datafile = out.nmrData{idN}.datfile; + fnames(c).T2specfile = ''; + if out.parData{nn}.freq/1e3 < 450 + % 433 kHz + shownames{c} = ['433kHz_',content(j).name]; + else + % 486 kHz + shownames{c} = ['486kHz_',content(j).name]; + end + data.import.NMR.data{c} = out.nmrData{idN}; + data.import.NMR.para{c} = out.parData{idN}; + + c = c + 1; + fnames(c).parfile = ''; + fnames(c).datafile = out.nmrData{idB}.datfile; + fnames(c).T2specfile = ''; + if out.parData{nn}.freq/1e3 < 450 + % 433 kHz + shownames{c} = ['433kHz_',content(j).name,'_burst']; + else + % 486 kHz + shownames{c} = ['486kHz_',content(j).name,'_burst']; + end + data.import.NMR.data{c} = out.nmrData{idB}; + data.import.NMR.para{c} = out.parData{idB}; + + % 1. fit both T2 signals mono-exponentially + time0 = data.import.NMR.data{c-1}.time; + signal = data.import.NMR.data{c-1}.signal; + param.T1IRfac = 1; + param.noise = std(imag(signal)); + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd0 = fitDataFree(time0,real(signal),'T2',param,1); + + time1 = data.import.NMR.data{c}.time; + signal = data.import.NMR.data{c}.signal; + param.T1IRfac = 1; + param.noise = std(imag(signal)); + param.optim = 'off'; + param.Tfixed_bool = [0 0 0 0 0]; + param.Tfixed_val = [0 0 0 0 0]; + invstd1 = fitDataFree(time1,real(signal),'T2',param,1); + + % now assemble a dummy T1 curve + t = [1e-4 data.import.NMR.para{c}.t_wait data.import.NMR.para{c-1}.t_wait]; + s = [0 invstd1.E0 invstd0.E0]; + % finally create a new "import" data set + data_new = data.import.NMR.data(c); + para_new = data.import.NMR.para(c); + + data_new{1}.flag = 'T1'; + data_new{1}.T1IRfac = 1; + data_new{1}.time = t; + data_new{1}.signal = s; + data_new{1}.noise = 0; + data_new{1}.raw.time = t; + data_new{1}.raw.signal = s; + + c = c + 1; + data.import.NMR.data{c} = data_new{1}; + data.import.NMR.para{c} = para_new{1}; + fnames(c).datafile = 'T1_merged.dat'; + shownames{c} = [shownames{c-1}(1:end-5),'T1_merged']; + end + else + for nn = 1:2 + % the individual file names + c = c + 1; + fnames(c).parfile = ''; + fnames(c).datafile = out.nmrData{nn}.datfile; + fnames(c).T2specfile = ''; + if out.parData{nn}.freq/1e3 < 450 + % 433 kHz + shownames{c} = ['433kHz_',content(j).name]; + else + % 486 kHz + shownames{c} = ['486kHz_',content(j).name]; + end + + data.import.NMR.data{c} = out.nmrData{nn}; + data.import.NMR.para{c} = out.parData{nn}; + end + end end end @@ -765,6 +1399,108 @@ function importNMRdata(src) end +%% +function [data,gui] = importDataRoCAT1T2(data,gui) + +% there should be some folders with names ... +% ... similar to the data filenames inside them +datpath = dir(data.import.path); +datpath = datpath(~ismember({datpath.name},{'.','..'})); +% remove any subfolder within the data directory +datpath = datpath(~ismember([datpath.isdir],true)); + +fnames = struct; +% shownames is just a dummy to hold all data file names that +% will be shown in the listbox +shownames = cell(1,1); + +c = 0; +if ~isempty(datpath) + content = datpath; + for j = 1:size(content,1) + if strcmp(content(j).name,'data2.csv') + in.T1T2 = 'T2'; + in.name = content(j).name; + in.path = fullfile(data.import.path); + in.fileformat = data.import.fileformat; + out = LoadNMRData_driver(in); + + for j1 = 1:numel(out.nmrData) + % the individual file names + c = c + 1; + fnames(c).parfile = 'acqu.par'; + fnames(c).datafile = out.nmrData{j1}.datfile; + fnames(c).T2specfile = ''; + + shownames{c} = ['T2_',content(j).name,'_',sprintf('%03d',j1)]; + + data.import.NMR.data{c} = out.nmrData{j1}; + data.import.NMR.para{c} = out.parData; + end + end + end + + % save the recovery time vector for later use + t2 = data.import.NMR.data{1}.time; + t2N = numel(t2); + t_recov = logspace(log10(out.parData.minTau),log10(out.parData.maxTau),out.parData.tauSteps); + data.import.T1T2map.t_recov = t_recov(:)./1e3; % to [s] + data.import.T1T2map.t2 = t2; + data.import.T1T2map.t2N = t2N; + + % add the stacked signal to the data + Nechos = 1; + flag = 'T1'; + time = data.import.T1T2map.t_recov; + signal = zeros(numel(data.import.NMR.data),1); + for i1 = 1:numel(data.import.NMR.data) + signal(i1) = mean(real(data.import.NMR.data{i1}.signal(1:Nechos))); + end + + disp('NUCLUESinv import: Estimating noise from exponential fit ...'); + 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]; + for i1 = 1:5 + invstd = fitDataFree(time,signal,flag,param,i1); + if i1 == 1 + noise = invstd.rms; + else + noise = min([noise invstd.rms]); + end + end + disp('NUCLUESinv import: done.') + + % finally create a new "import" data set + data_new = data.import.NMR.data(1); + para_new = data.import.NMR.para(1); + + data_new{1}.flag = flag; + data_new{1}.T1IRfac = param.T1IRfac; + data_new{1}.time = time; + data_new{1}.signal = signal; + data_new{1}.noise = noise; + data_new{1}.raw.time = time; + data_new{1}.raw.signal = signal; + + data.import.NMR.data{c+1} = data_new{1}; + data.import.NMR.para{c+1} = para_new{1}; + fnames(c+1).datafile = 'T1_merged.dat'; + shownames{c+1} = 'T1_merged'; + % set global echo time + data.inv2D.prop.te = data.import.NMR.para{1}.echoTime/1e6; % [s] + % set T1 SR/IR factor + data.inv2D.inv.T1IRfac = 2; % Rock Core Analyzer default(?) +end + +% update the global data structure +data.import.NMR.files = fnames; +data.import.NMR.filesShort = shownames; + +end + %% function [data,gui] = importDataGeneral(data,gui) @@ -1366,6 +2102,7 @@ function importNMRdata(src) end end data.import.LIAG.Tbulk = 1e6; + data.import.LIAG.Tbulk_keep_fit = false; data.import.LIAG.workpaths = workpaths; data.import.LIAG.datapath = datapath; data.import.LIAG.calibrationpath = calibrationpath; diff --git a/functions/interface/minimizePanel.m b/functions/interface/minimizePanel.m index 2fb5b7b..21e457c 100644 --- a/functions/interface/minimizePanel.m +++ b/functions/interface/minimizePanel.m @@ -203,6 +203,42 @@ function minimizePanel(src,~) helpdlg({'function: minimizePanel',... 'Something is utterly wrong.'},'Info'); end + case '2DINV' + panel_1 = 'Properties'; + panel_2 = '2D inversion settings'; + panel_3 = 'Information'; + + switch paneltitle + case panel_1 + id = 1; + case panel_2 + id = 2; + case panel_3 + id = 3; + otherwise + helpdlg({'function: minimizePanel',... + 'Something is utterly wrong.'},'Info'); + end + + switch paneltitle + case {panel_1,panel_2,panel_3} + % 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/readINIfile.m b/functions/interface/readINIfile.m index 5898461..3997785 100644 --- a/functions/interface/readINIfile.m +++ b/functions/interface/readINIfile.m @@ -39,7 +39,7 @@ %% process lines for i = 1:size(inilines,1) tmp = char(inilines(i)); - if ~isempty(strfind(tmp,'=')) + if contains(tmp,'=') ind = strfind(tmp,'='); prop = tmp(1:ind-1); value = tmp(ind+1:end); diff --git a/functions/interface/removeInversionFields.m b/functions/interface/removeInversionFields.m index 2e7e3f9..674e525 100644 --- a/functions/interface/removeInversionFields.m +++ b/functions/interface/removeInversionFields.m @@ -38,6 +38,9 @@ if isfield(data.results,'invjoint') data.results = rmfield(data.results,'invjoint'); end + if isfield(data.results,'inv2D') + data.results = rmfield(data.results,'inv2D'); + end if isfield(data.results,'lcurve') data.results = rmfield(data.results,'lcurve'); end diff --git a/functions/interface/removeSignalFromList.m b/functions/interface/removeSignalFromList.m index b0e169e..e551a62 100644 --- a/functions/interface/removeSignalFromList.m +++ b/functions/interface/removeSignalFromList.m @@ -48,6 +48,15 @@ function removeSignalFromList(id) data.import.NMR.files(id) = []; data.import.NMR.filesShort(id) = []; INVdata(id) = []; + + % take care of possible 2D data + if isfield(data.import,'T1T2map') + data.import.T1T2map.t_recov(id) = []; + data.import.NMR.data{end}.time(id) = []; + data.import.NMR.data{end}.signal(id) = []; + data.import.NMR.data{end}.raw.time(id) = []; + data.import.NMR.data{end}.raw.signal(id) = []; + end % empty all axes clearAllAxes(fig); diff --git a/functions/interface/runInversionBatch.m b/functions/interface/runInversionBatch.m index b128b0d..677bcc8 100644 --- a/functions/interface/runInversionBatch.m +++ b/functions/interface/runInversionBatch.m @@ -255,10 +255,11 @@ waitbar(id / steps,hwb,['processing ...',num2str(id),... ' / ',num2str(steps),' NMR signals']); else - % otherwise only update every 25 signals + % otherwise only show 25 increments of the waitbar % NOTE: Matlab's wait-bar SLOWS DOWN the calculation % MASSIVELY - if id == 1 || mod(id,25) == 0 + my_mod = round(size(INVdata,1)/25); + if id == 1 || mod(id,my_mod) == 0 waitbar(id / steps,hwb,['processing ...',num2str(id),... ' / ',num2str(steps),' NMR signals']); end diff --git a/functions/interface/runInversionStd.m b/functions/interface/runInversionStd.m index 087c9c5..e82ad7b 100644 --- a/functions/interface/runInversionStd.m +++ b/functions/interface/runInversionStd.m @@ -191,6 +191,7 @@ % disable the RUN button to indicate a running inversion set(gui.push_handles.invstd_run,'String','RUNNING ...',... + 'BackgroundColor',[0.9400 0.9400 0.9400],... 'Enable','inactive'); % switch depending on inversion method switch data.invstd.invtype diff --git a/functions/interface/showExtraGraphics.m b/functions/interface/showExtraGraphics.m index 39ff3f6..0f9516a 100644 --- a/functions/interface/showExtraGraphics.m +++ b/functions/interface/showExtraGraphics.m @@ -225,6 +225,8 @@ function showExtraGraphics(method) hold(ax1,'on'); switch data.invstd.invtype case 'mono' + % init dummy Ex (for plotting) + Ex = E0; errorbar(xval,E0,E0_er,'o','Color',col.FIT,'Parent',ax1,... 'DisplayName','E0'); case 'free' @@ -269,6 +271,8 @@ function showExtraGraphics(method) hold(ax2,'on'); switch data.invstd.invtype case 'mono' + % init dummy Tx (for plotting) + Tx = T; errorbar(xval,T,T_er,'o','Color',col.FIT,'DisplayName','T0','Parent',ax2); set(get(ax2,'YLabel'),'String',['T [',timescale,']']); case 'free' diff --git a/functions/interface/uncheckImportMenus.m b/functions/interface/uncheckImportMenus.m index 606d8cb..0f8f7cd 100644 --- a/functions/interface/uncheckImportMenus.m +++ b/functions/interface/uncheckImportMenus.m @@ -51,10 +51,15 @@ set(gui.menu.file_import_lab_bgr_helios_cpmg,'Checked','off'); set(gui.menu.file_import_lab_bgr_helios_series,'Checked','off'); set(gui.menu.file_import_lab_bam_tom,'Checked','off'); +set(gui.menu.file_import_lab_aarhus_dartT1T2,'Checked','off'); +set(gui.menu.file_import_lab_aarhus_dartT2,'Checked','off'); +set(gui.menu.file_import_lab_rutgers_T1T2,'Checked','off'); set(gui.menu.file_import_lab_ascii_T1,'Checked','off'); set(gui.menu.file_import_lab_ascii_T2,'Checked','off'); set(gui.menu.file_import_lab_excel_T1,'Checked','off'); set(gui.menu.file_import_lab_excel_T2,'Checked','off'); +set(gui.menu.file_import_lab_dart,'Checked','off'); +set(gui.menu.file_import_lab_dartburst,'Checked','off'); set(gui.menu.file_import_nmrinv_file,'Checked','off'); set(gui.menu.file_import_nmrmod_file,'Checked','off'); set(gui.menu.file_import_nmrmod_gui,'Checked','off'); diff --git a/functions/interface/updateInfo.m b/functions/interface/updateInfo.m index 4c0cd50..f5344d7 100644 --- a/functions/interface/updateInfo.m +++ b/functions/interface/updateInfo.m @@ -334,7 +334,12 @@ function updateInfo(src,~) %#ok switch whichdist case 1 % RTD if isfield(data,'results') - if isfield(data.results,'invstd') + % check for 2D data + is1D = true; + if isfield(data.results,'inv2D') + is1D = false; + end + if is1D && isfield(data.results,'invstd') nmrproc = data.results.nmrproc; invstd = data.results.invstd; invtype = data.invstd.invtype; @@ -439,8 +444,7 @@ function updateInfo(src,~) %#ok ') = ',sprintf('%5.2f',por*BVI*100),' [vol. %]']; info{end+1,1} = ['BVM = ',sprintf('%5.2f',por*BVM*100),' [vol. %]']; - case {'MUMO'} - + case {'MUMO'} % info is a cell array str = [invtype,' ',num2str(data.invstd.freeDT)]; info{end+1,1} = str; diff --git a/functions/interface/updatePlotsDistribution.m b/functions/interface/updatePlotsDistribution.m index a1fe960..d59e1cf 100644 --- a/functions/interface/updatePlotsDistribution.m +++ b/functions/interface/updatePlotsDistribution.m @@ -42,8 +42,15 @@ if isfield(data,'results') && isfield(data.results,'nmrproc') nmrproc = data.results.nmrproc; end + +% check for 2D data +is1D = true; +if isfield(data.results,'inv2D') + is1D = false; +end + % only continue if there is actual data to show -if isfield(data,'results') && isfield(data.results,'invstd') +if isfield(data,'results') && isfield(data.results,'invstd') && is1D invstd = data.results.invstd; if isfield(invstd,'uncert') @@ -118,7 +125,7 @@ case {'LU','NNLS'} % scale distribution by porosity F0 = invstd.T1T2f; - if sum(F0)>0 + if sum(abs(F0))>0 F = (data.invstd.porosity*100).*F0./sum(F0); ylims = [0 max(F)*1.05]; else diff --git a/functions/interface/updatePlotsDistributionInfo.m b/functions/interface/updatePlotsDistributionInfo.m index a9a6c3e..816e0f8 100644 --- a/functions/interface/updatePlotsDistributionInfo.m +++ b/functions/interface/updatePlotsDistributionInfo.m @@ -43,6 +43,12 @@ uncert = data.results.invstd.uncert; end +% check for 2D data +is1D = true; +if isfield(data,'results') && isfield(data.results,'inv2D') + is1D = false; +end + % default color col = gui.myui.colors.axisL; @@ -117,7 +123,7 @@ end % check for lsqlin "EchoFlag" and plot an info line if available -if strcmp(data.invstd.invtype,'NNLS') && ... +if is1D && strcmp(data.invstd.invtype,'NNLS') && ... strcmp(data.results.invstd.invparams.EchoFlag,'on') TEmin = data.results.nmrproc.t(1); diff --git a/functions/interface/updatePlotsSignal.m b/functions/interface/updatePlotsSignal.m index 78c3987..db2520e 100644 --- a/functions/interface/updatePlotsSignal.m +++ b/functions/interface/updatePlotsSignal.m @@ -84,7 +84,8 @@ set(ax,'YScale','log','YLim',[10^(ticks(1)) 10^(ticks(end))],.... 'YTick',10.^ticks); case 'y-axis -> log' % lin axes - set(ax,'YScale','lin','YLim',[-0.05 max(real(nmrraw.s))*1.05],... + ymin = min([min(real(nmrraw.s))*1.2 -0.05]); + set(ax,'YScale','lin','YLim',[ymin max(real(nmrraw.s))*1.05],... 'YTickMode','auto'); end case 'T2' @@ -122,7 +123,7 @@ line(xlims,[0 0],'LineStyle','--','LineWidth',1,'Color','k','Parent',axI); imag_mean = mean(imag(nmrraw.s)); imag_std = std(imag(nmrraw.s)); - yticks = [imag_mean-imag_std*2 0 imag_mean+imag_std*2]; + yticks = [imag_mean-imag_std*2 imag_mean 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'); switch loglinx @@ -313,15 +314,16 @@ % legend if isfield(data.results,'invstd') + % show the legend + lgh = legend(ax,'show'); switch nmrproc.T1T2 case 'T1' - lgh = legend(ax,'Location','NorthWest',... - 'Tag','fitlegend','FontSize',10); + set(lgh,'Location','NorthWest'); case 'T2' - lgh = legend(ax,'Location','NorthEast',... - 'Tag','fitlegend','FontSize',10); + set(lgh,'Location','NorthEast'); end - set(lgh,'TextColor',gui.myui.colors.panelFG); + set(lgh,'TextColor',gui.myui.colors.panelFG,'Tag','fitlegend',... + 'FontSize',10); end % grid diff --git a/functions/inversion/applyRegularization2D.m b/functions/inversion/applyRegularization2D.m new file mode 100644 index 0000000..230ca35 --- /dev/null +++ b/functions/inversion/applyRegularization2D.m @@ -0,0 +1,103 @@ +function [Kreg,dat_inp,L,LD] = applyRegularization2D(K,order,Tvec,Dvec,indices,dat_vec,lambda) +%applyRegularization applies a manual regularization to the kernel matrix K +% +% Syntax: +% applyRegularization2D(K,order,Tvec,Dvec,indices,dat_vec,lambda) +% +% Inputs: +% K - Kernel matrix +% order - smoothness constraint: '0', '1' or '2' for both dimensions +% the same so far +% Tvec - relaxation time vector: here T2 +% Dvec - diffusion / relaxation time vector: here T1 +% indices - struct holding tile indices +% dat_vec - signal vector +% lambda - 1x2 vector holding lambda for both dimensions +% +% Outputs: +% Kreg - expanded (regularized) Kernel matrix +% dat_inp - expanded signal vector +% L - smoothness matrix regarding T dim +% LD - smoothness matrix regarding D dim +% +% Example: +% [Kreg,dat_inp,~,~] = applyRegularization2D(K,order,T2vec,T1vec,indices,dat_vec,lambda) +% +% Other m-files required: +% get_l (from Regularization toolbox) +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also: +% Author: see AUTHORS.md +% email: see AUTHORS.md +% License: MIT License (at end) + +%------------- BEGIN CODE -------------- + +%% get lambda values +lamT = lambda(2); % T2 +lamD = lambda(1); % T1 + +%% get column indices +col_end = indices.col_end; + +% get first smoothness matrix +L = get_l(length(Tvec)*length(Dvec),order); + +% regularization along first dimension, normally Tvec (here T2) +% loop necessary to correct the transitions among the tiles +for n = 1:length(Dvec)-1 + L(col_end(n)-order+1:col_end(n),col_end(n)+1:col_end(n)+order) = zeros(order); +end +% first expanded kernel matrix +KregT = [K;lamT * L]; + +% regularization along second dimension, normally D (here T1) +LD = zeros(size(L,1)-order*length(Tvec),size(L,2)); +for no = 1:order + 1 + for n = 1:size(LD,2) - (order) * length(Tvec) + LD(n,n+(no-1)*length(Tvec)) = L(1,no); + end +end +% final expanded kernel matrix +Kreg = [KregT;lamD * LD]; + +% expanded data vector +dat_inp = dat_vec; +dat_inp(length(dat_vec)+1:length(dat_vec)+size(L,1)+size(LD,1),1) = 0; + +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. + + + + diff --git a/functions/inversion/createKernelMatrix.m b/functions/inversion/createKernelMatrix.m index a77addc..c9885ab 100644 --- a/functions/inversion/createKernelMatrix.m +++ b/functions/inversion/createKernelMatrix.m @@ -3,7 +3,7 @@ %and relaxation time vector "T" % % Syntax: -% createKernelMatrix(t,T,Tbulk,Tflag,T1IRflag) +% createKernelMatrix(t,T,Tbulk,Tflag,T1IRflag) % % Inputs: % t - signal time vector diff --git a/functions/inversion/createKernelMatrix2D.m b/functions/inversion/createKernelMatrix2D.m new file mode 100644 index 0000000..1d11cab --- /dev/null +++ b/functions/inversion/createKernelMatrix2D.m @@ -0,0 +1,154 @@ +function [K,indices] = createKernelMatrix2D(dat,T1vec,T2vec,p) +%createKernelMatrix2D creates a Kernel matrix from signals time vectors "t" +%and relaxation time vector "T1vec" and "T2vec" +% +% Syntax: +% createKernelMatrix2D(dat,T1vec,T2vec,G0,D,te,T1IRfac) +% +% Inputs: +% dat - struct holding signal data including time vector "t" in [s] +% T1vec - relaxation times vector in [s] +% T2vec - relaxation times vector in [s] +% p - struct holding optional settings +% G0 - gradient in [T/m] +% D - diffusion coefficient [m²/s] +% te - echo time in [s] +% Tbulk - Bulk relaxation time in [s] +% T1IRfac - 1 or 2 (Sat. or Inv. Recovery) +% IRtype - 1 or 2 (1-2exp() or -exp()) +% +% Outputs: +% K - Kernel matrix size(length(t),length(T1vec)*length(T2vec)) +% indices - struct holding tile indices +% +% Example: +% K = createKernelMatrix(dat,T1,T2,0,2e-9,2e-4,2) +% +% 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 -------------- + +%% +useTbulk = false; +if isfield(p,'Tbulk') + useTbulk = true; + Tbulk = p.Tbulk; +end +if isfield(p,'G0') + G0 = p.G0; +else + G0 = 0; +end +if isfield(p,'D') + D = p.D; +else + D = 2.025e-09; +end +if isfield(p,'te') + te = p.te; +else + te = 2e-4; +end +if isfield(p,'T1IRfac') + T1IRfac = p.T1IRfac; +else + T1IRfac = 2; +end +if isfield(p,'IRtype') + IRtype = p.IRtype; +else + IRtype = 1; +end + +%% gyromagnetic ratio of hydrogen +gyro = 0.267*1e9; % [rad/(T*s)] + +%% how many recovery times? +num_T1 = length(dat); + +%% init data +lin_1 = zeros(1,num_T1); +lin_end = zeros(1,num_T1); +col_1 = zeros(1,numel(T1vec)); +col_end = zeros(1,numel(T1vec)); + +% determine cumulative length of all involved t-vectors +t_dim = 0; +for nn = 1:num_T1 + lin_1(nn) = 1 + t_dim; + t_dim = t_dim + length(dat(nn).t); + lin_end(nn) = t_dim; +end +K = zeros(t_dim,length(T1vec)*length(T2vec)); + +% assemble kernel +for n = 1:numel(T1vec) + % determine current tile: + col_1(n) = (n-1) * length(T2vec) + 1; + col_end(n) = n * length(T2vec); + for nn = 1:num_T1 + % time vectors + tr = repmat(dat(nn).t(:),[1,numel(T2vec)]); + Tr = repmat(T2vec,[numel(dat(nn).t),1]); + % diffusion relaxation rate: + Tdiff_rate = (D*(gyro*G0*te)^2)/12; + % T1 relaxation + if IRtype == 1 + T1loss = (1-T1IRfac*exp(-dat(nn).T1/T1vec(n))); + else + % after Hürlimann 2001 JMR + T1loss = -(exp(-dat(nn).T1/T1vec(n))); + end + % kernel + if useTbulk + K(lin_1(nn):lin_end(nn),col_1(n):col_end(n)) = T1loss*exp(-tr./Tr).*exp(-tr.*Tdiff_rate).*exp(-tr./Tbulk); + else + K(lin_1(nn):lin_end(nn),col_1(n):col_end(n)) = T1loss*exp(-tr./Tr).*exp(-tr.*Tdiff_rate); + end + end +end + +% struc holding tile indices +indices.lin_1 = lin_1; +indices.lin_end = lin_end; +indices.col_1 = col_1; +indices.col_end = col_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/fitData2D.m b/functions/inversion/fitData2D.m new file mode 100644 index 0000000..e5024eb --- /dev/null +++ b/functions/inversion/fitData2D.m @@ -0,0 +1,194 @@ +function fitdata = fitData2D(data,parameter) +%fitData2D is a control routine that fits 2D NMR data; +%if the Optimization Toolbox is available the user can select LSQLIN, +%otherwise the default built-in LSQNONNEG is used; +% +% Syntax: +% fitData2D(data,parameter) +% +% Inputs: +% data - struct that holds the NMR signal data +% parameter - struct that holds settings: +% +% Outputs: +% fitdata - struct that holds the inversion results: +% +% Example: +% [fitdata] = fitData2D(data,parameter) +% +% Other m-files required: +% Optimization Toolbox from Mathworks (optional) +% applyRegularization2D +% createKernelMatrix2D +% getFitErrors +% getTLogMean2D +% lsqnonneg +% lsqlin (optional) +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also: +% Author: see AUTHORS.md +% email: see AUTHORS.md +% License: MIT License (at end) + +%------------- BEGIN CODE -------------- + +% get the input parameters +% flag = parameter.T1T2; % T1/T2 switch +T1IRfac = parameter.T1IRfac; % T1 Sat/Inv Recovery factor +IRtype = parameter.IRtype; % T1 IR kernel type +% Tb = parameter.Tb; % bulk relaxation time +% Td = parameter.Td; % diffusion relaxation time + +noise = parameter.noise; +% get system properties +D = parameter.D; +G0 = parameter.G0; +te = parameter.te; + +% create model space from relaxation time T vectors +T1min = parameter.T1min; +T1max = parameter.T1max; +T1N = parameter.T1N; +T2min = parameter.T2min; +T2max = parameter.T2max; +T2N = parameter.T2N; + +T1vec = logspace(log10(T1min),log10(T1max),T1N); +T2vec = logspace(log10(T2min),log10(T2max),T2N); +MOD = zeros(numel(T2vec),numel(T1vec)); + +% prepare data vector +Nsignals = numel(data); +Nechos = numel(data(1).t); +dat_vec = zeros(Nsignals*Nechos,1); +for n = 1:numel(data) + if n == 1 + dat_vec(1:Nechos,1) = data(n).s; + else + dat_vec((n-1)*Nechos+1:n*Nechos,1) = data(n).s; + end +end + +% create the Kernel matrix for inversion +p.G0 = G0; +p.D = D; +p.te = te; +p.T1IRfac = T1IRfac; +p.IRtype = IRtype; +[K,indices] = createKernelMatrix2D(data,T1vec,T2vec,p); + +% regularization +order = parameter.orderT1; +lambda = [parameter.lamT1 parameter.lamT2]; + +[KK,dat_inp,LT,LD] = applyRegularization2D(K,order,T2vec,T1vec,indices,dat_vec,lambda); + +switch parameter.solver + case 'lsqlin' + x0 = zeros(size(KK,2),1); + lb = zeros(size(KK,2),1); + ub = ones(size(KK,2),1); + + options = optimoptions('lsqlin'); + options.Display = parameter.info; + % options.OptimalityTolerance = 1e-16; + % options.StepTolerance = 1e-16; + % options.MaxIterations = 2000; + [f_vec,RESNORM,RESIDUAL,EXITFLAG,OUTPUT] = lsqlin(KK,dat_inp,[],[],[],[],... + lb,ub,x0,options); + + case 'lsqnonneg' + options = optimset('lsqnonneg'); + options.Display = parameter.info; + [f_vec,RESNORM,RESIDUAL,EXITFLAG,OUTPUT] = lsqnonneg(KK,dat_inp,options); +end + +% global model response (fit) +s_fit = K * f_vec; +% global fit errors +out_global = getFitErrors(dat_vec,s_fit,noise); +% local fit errors +for n = 1:numel(data) + data(n).s_fit = s_fit((n-1)*Nechos+1:n*Nechos); + out = getFitErrors(data(n).s,data(n).s_fit,data(n).noise); + data(n).resnorm = out.resnorm; + data(n).residual = out.residual; + data(n).chi2 = out.chi2; + data(n).rms = out.rms; +end + +% L-curve parameter +% model norm |L*x|_2 +xn = norm([LT;LD]*f_vec,2); +% residual norm |A*x-b|_2 +rn = norm(out_global.residual,2); + +% create the Kernel matrix for E0 +dat0.t=0; +dat0.T1=10000; +[K0,~] = createKernelMatrix2D(dat0,T1vec,T2vec,p); +E0 = K0*f_vec; + +% sort the result +f_2Dmap = zeros(size(MOD')); +for n = 1:length(T1vec) + f_2Dmap(n,:) = f_vec(indices.col_1(n):indices.col_end(n)); +end + +% get TLGM and TMAX +[TLGM,TMAX] = getTLogMean2D(T1vec,T2vec,f_2Dmap); + +% output struct +fitdata.data = data; +fitdata.T1vec = T1vec; +fitdata.T2vec = T2vec; +fitdata.indices = indices; +fitdata.f_vec = f_vec; +fitdata.f_2Dmap = f_2Dmap; +fitdata.E0 = E0; +fitdata.T1tlgm = TLGM(1); +fitdata.T2tlgm = TLGM(2); +fitdata.T1tmax = TMAX(1); +fitdata.T2tmax = TMAX(2); +fitdata.error_global = out_global; +fitdata.xn = xn; +fitdata.rn = rn; +fitdata.solver_out.RESNORM = RESNORM; +fitdata.solver_out.RESIDUAL = RESIDUAL; +fitdata.solver_out.EXITFLAG = EXITFLAG; +fitdata.solver_out.OUTPUT = OUTPUT; +fitdata.param = parameter; +% fitdata.K = K; + +return + +%------------- END OF CODE -------------- + +%% License: +% MIT License +% +% Copyright (c) 2018 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/fitDataFree.m b/functions/inversion/fitDataFree.m index 449a19e..f5e4089 100644 --- a/functions/inversion/fitDataFree.m +++ b/functions/inversion/fitDataFree.m @@ -162,6 +162,8 @@ 'MaxIter',5000,'TolFun',1e-12,'TolX',1e-12); switch flag case 'T1' + % set all start values to 0 (if something is not working as expected, comment it and try again) + x0 = zeros(size(lb)); [x,~,~,output] = fminsearchbnd(@(x) fcn_fitFreeT1_fmin(x,t,s,IRfac),... x0,lb,ub,options); case 'T2' diff --git a/functions/inversion/getChi2.m b/functions/inversion/getChi2.m index b7b672d..36c2ce8 100644 --- a/functions/inversion/getChi2.m +++ b/functions/inversion/getChi2.m @@ -32,7 +32,7 @@ %------------- BEGIN CODE -------------- %% residual -residual = signal - fit; +residual = fit-signal; %% chi2 % sqrt(sum(N.^2)) = norm(N) (if N is a vector) diff --git a/functions/inversion/getConfInterval.m b/functions/inversion/getConfInterval.m index 0562543..83b6979 100644 --- a/functions/inversion/getConfInterval.m +++ b/functions/inversion/getConfInterval.m @@ -68,7 +68,7 @@ if StatBox == 1 stud_fac = tinv(1-alpha,deg_free); else - if deg_free <= 1000 + if deg_free > 0 && deg_free <= 1000 stud_fac = getStudentInvCDF(1-alpha,deg_free); else stud_fac = 1;%NaN; diff --git a/functions/inversion/getFitErrors.m b/functions/inversion/getFitErrors.m index 1852f40..b8d8971 100644 --- a/functions/inversion/getFitErrors.m +++ b/functions/inversion/getFitErrors.m @@ -49,7 +49,7 @@ end %% residuals -residual = s-sfit; +residual = sfit-s; %% L1 norm errnorm1 = sum(abs(residual)); diff --git a/functions/inversion/getTLogMean2D.m b/functions/inversion/getTLogMean2D.m new file mode 100644 index 0000000..9e089f5 --- /dev/null +++ b/functions/inversion/getTLogMean2D.m @@ -0,0 +1,106 @@ +function [TLGM,TMAX] = getTLogMean2D(T1,T2,f,varargin) +%getTLogMean calculates the T logmean value out of a relaxation time +%distribution +% +% Syntax: +% getTLogMean2D(T1,T2,f) +% +% Inputs: +% T1 - T1 relaxation times +% T2 - T2 relaxation times +% f - 2D distribution +% varargin - 2 1x2 vectors giving a range [Tmin Tmax] for both +% dimensions +% +% Outputs: +% TLGM - vector [T1tlgm T2tlgm] -> 2D log mean value of RTD +% TMAX - vector [T1tmax T2tmax] -> 2D maximum of RTD +% +% Example: +% [TLGM,TMAX] = getTLogMean2D(T1,T2,f) +% +% 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 -------------- + +%% calculate TLGM +% check input +if nargin > 3 + T1range = varargin{1}; + T2range = varargin{2}; +else + % use full T1 and T2 range for calculation + T1range = [min(T1) max(T1)]; + T2range = [min(T2) max(T2)]; +end + +% make T1-T2 2D map +[X,Y] = meshgrid(T2,T1); + +% calc TLGM of entire map +mask1 = Y >= T1range(1) & Y <= T1range(2); +mask2 = X >= T2range(1) & X <= T2range(2); +x_m1 = 10^(sum(sum(log10(X(mask2)) .* f(mask2)/sum(sum(f(mask2)))))); +y_m1 = 10^(sum(sum(log10(Y(mask1)) .* f(mask1)/sum(sum(f(mask1)))))); + +% calc TMAX of entire map +f1 = f.*mask1.*mask2; +[ix,iy] = find(f1==max(f1(:))); +x_max1 = X(ix,iy); +y_max1 = Y(ix,iy); + +% calc TMAX of entire map +% mask1 = T1 >= T1range(1) & T1 <= T1range(2); +% mask2 = T2 >= T2range(1) & T2 <= T2range(2); +% T1lim = T1(mask1); +% T2lim = T2(mask2); +% [dummy1] = max(f,[],2); +% [~,ii1] = max(dummy1(mask1)); +% [dummy2] = max(f,[],1); +% [~,ii2] = max(dummy2(mask2)); +% x_max = T2lim(ii2); +% y_max = T1lim(ii1); + +% save results +TLGM = [y_m1 x_m1]; % [T1tlgm T2tlgm] +% TMAX = [y_max x_max]; % [T1tmax T2tmax] +TMAX = [y_max1 x_max1]; % [T1tmax T2tmax] + +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/getUncertaintyStatistics.m b/functions/inversion/getUncertaintyStatistics.m index 59b0e15..a7020ea 100644 --- a/functions/inversion/getUncertaintyStatistics.m +++ b/functions/inversion/getUncertaintyStatistics.m @@ -58,6 +58,8 @@ out.Tlgm_med = [median(TLGM_tmp) getAAD(TLGM_tmp,1)]; out.E0 = [mean(E0_tmp) std(E0_tmp) getAAD(E0_tmp,0)]; out.E0_med = [median(E0_tmp) getAAD(E0_tmp,1)]; + out.Tlgm_all = TLGM_tmp; + out.E0_all = E0_tmp; else helpdlg({'function: getUncertainty Statistics',... diff --git a/functions/inversion/runUncertaintyCalculation.m b/functions/inversion/runUncertaintyCalculation.m index 4ed1d6f..383c457 100644 --- a/functions/inversion/runUncertaintyCalculation.m +++ b/functions/inversion/runUncertaintyCalculation.m @@ -40,6 +40,11 @@ id = get(gui.listbox_handles.signal,'Value'); if ~isempty(id) && ~isempty(INVdata) && isstruct(INVdata{id}) + % disable the CALC: button to indicate a running calculation + set(gui.push_handles.uncert,'String','RUNNING ...',... + 'BackgroundColor',[0.94 0.94 0.94],... + 'Enable','inactive'); pause(0.01); + % get original inversion data INVdata0 = INVdata{id}; invstd = INVdata0.results.invstd; % results from original inversion @@ -65,6 +70,11 @@ uparam.uncert.N = data.uncert.N; uparam.uncert.Max = data.uncert.Max; invstd = estimateUncertainty(invtype,invstd,iparam,uparam); + + % enable the CALC. button + set(gui.push_handles.uncert,'String','CALC.',... + 'BackgroundColor','g','Enable','on','Callback',@onPushRun); + setappdata(fig,'gui',gui); % save updated inversion results data.results.invstd = invstd; diff --git a/functions/modeling/getMultivariateGaussian.m b/functions/modeling/getMultivariateGaussian.m new file mode 100644 index 0000000..feb47bd --- /dev/null +++ b/functions/modeling/getMultivariateGaussian.m @@ -0,0 +1,74 @@ +function pdf = getMultivariateGaussian(X,mu,sigma) +%MULTIVARIATEGAUSSIAN Computes the probability density function of the +%multivariate gaussian distribution.% +% +% Syntax: +% pdf = getMultivariateGaussian(X,mu,sigma) +% +% Inputs: +% X - n x d -> (x,y,...) vectors +% mu - 1 x d -> mean values +% sigma - d x d covariance matrix +% +% Outputs: +% pdf - probability density function +% +% Example: +% p = getMultivariateGaussian([-1 0;0 0;1 0],[0 0],[1 0;0 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 -------------- + +% get dimension +d = length(mu); + +if (size(sigma, 2) == 1) || (size(sigma, 1) == 1) + sigma = diag(sigma); +end + +% subtract mu to shift everything to (0,0) +X = bsxfun(@minus, X, mu(:)'); + +% calculate p +pdf = 1 / ( sqrt(det(sigma)*((2*pi)^d)) ) * ... + exp(-0.5 * sum(bsxfun(@times, X * pinv(sigma), X), 2)); + +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/images/2dinv_gui.png b/images/2dinv_gui.png new file mode 100644 index 0000000..1f39f1c Binary files /dev/null and b/images/2dinv_gui.png differ diff --git a/images/2dmod_gui.png b/images/2dmod_gui.png new file mode 100644 index 0000000..0c0b248 Binary files /dev/null and b/images/2dmod_gui.png differ diff --git a/images/nucleusinv_gui.png b/images/nucleusinv_gui.png new file mode 100644 index 0000000..1519ce4 Binary files /dev/null and b/images/nucleusinv_gui.png differ diff --git a/nucleusmod_gui.png b/images/nucleusmod_gui.png similarity index 100% rename from nucleusmod_gui.png rename to images/nucleusmod_gui.png diff --git a/images/phaseview_gui.png b/images/phaseview_gui.png new file mode 100644 index 0000000..55b70b3 Binary files /dev/null and b/images/phaseview_gui.png differ diff --git a/images/uncertview_gui.png b/images/uncertview_gui.png new file mode 100644 index 0000000..cf4d9ed Binary files /dev/null and b/images/uncertview_gui.png differ diff --git a/nucleusinv_gui.png b/nucleusinv_gui.png deleted file mode 100644 index 39f22aa..0000000 Binary files a/nucleusinv_gui.png and /dev/null differ diff --git a/uncertview_gui.png b/uncertview_gui.png deleted file mode 100644 index f55326a..0000000 Binary files a/uncertview_gui.png and /dev/null differ