diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17a6eb2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.asv +*.aux +*.log +*.toc +*.sty +*.mat +/output +/externals diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..ee3e5d3 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,6 @@ +**GRAINPACKER** is developed by + +* Thomas Hiller, thomas.hiller@bgr.de +* Jan Igel, jan.igel@leibniz-liag.de +* Stephan Schennen, s.schennen@t-online.de +* Sam Stadler, sam.stadler@leibniz-liag.de \ No newline at end of file diff --git a/GPRGRAVEL/GPRGRAVEL.m b/GPRGRAVEL/GPRGRAVEL.m new file mode 100644 index 0000000..42cef17 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL.m @@ -0,0 +1,97 @@ +function GPRGRAVEL +%GPRGRAVEL is a graphical user interface (GUI) to create "grain packings" +%(spheres or ellipsoids) for 3D GPR simulations based on grain size +% distributions (GSDs) +% +% Syntax: +% GPRGRAVEL +% +% Inputs: +% none +% +% Outputs: +% none +% +% Example: +% GPRGRAVEL +% +% Other m-files required: +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% GUI 'header' info and default GUI settings +myui.version = '0.1.0'; +myui.date = '14.07.2023'; +myui.author = 'Thomas Hiller'; + +myui.fontsize = 8; +myui.axfontsize = 10; +myui.linewidth = 2; +myui.color.domain = [141 211 199]./255; +myui.color.grains = [251 128 114]./255; +myui.color.params = [128 177 211]./255; +% 255 255 179 +% 190 186 218 + +%% Default data settings +data = GPRGRAVEL_loadDefaults; +tmp = mfilename('fullpath'); +idcs = strfind(tmp,filesep); +newdir = tmp(1:idcs(end-1)-1); +data.params.GPRGRAVELpath = newdir; + +%% GUI initialization +gui.figh = figure('Name','GPRGRAVEL',... + 'NumberTitle','off','Tag','GPRGRAVEL','ToolBar','none','MenuBar','none',... + 'SizeChangedFcn',@onFigureSizeChange); + +% position on screen +pos = GPRGRAVEL_setPositionOnScreen; +set(gui.figh,'Position',pos); + +%% GUI data +gui.myui = myui; + +% save the data struct within the GUI +setappdata(gui.figh,'data',data); +setappdata(gui.figh,'gui',gui); + +%% Create GUI elements +GPRGRAVEL_createGUI(gui.figh,true); +% update status bar +updateStatusInformation(gui.figh); +% plot domain +plotDomaindata(gui.figh); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/GPRGRAVEL/GPRGRAVEL_createGUI.m b/GPRGRAVEL/GPRGRAVEL_createGUI.m new file mode 100644 index 0000000..f700287 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createGUI.m @@ -0,0 +1,175 @@ +function GPRGRAVEL_createGUI(h,wbon) +%GPRGRAVEL_createGUI controls the creation of all GUI elements +% +% Syntax: +% GPRGRAVEL_createGUI(h) +% +% Inputs: +% h - figure handle +% wbon - show waitbar (yes=true, no=false) +% +% Outputs: +% none +% +% Example: +% GPRGRAVEL_createGUI(h,true) +% +% Other m-files required: +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI data +data = getappdata(h,'data'); +gui = getappdata(h,'gui'); +myui = gui.myui; + +%% initialize wait bar +if wbon + hwb = waitbar(0,'loading ...','Name','GPRGRAVEL initialization','Visible','off'); + steps = 6; + if ~isempty(h) + posf = get(h,'Position'); + 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)]); + end + set(hwb,'Visible','on'); +end + +%% uimenus +if wbon + waitbar(1/steps,hwb,'loading GUI elements - menus'); +end +gui = GPRGRAVEL_createMenus(gui); + +%% MAIN GUI "BOX" +gui.main = uix.VBox('Parent',gui.figh,'Visible','off'); + +% top part for settings and plots +gui.top = uix.HBox('Parent',gui.main); +% bottom part for the status bar +gui.bottom = uix.HBox('Parent',gui.main); +set(gui.main,'Heights',[-1 20]); + +% top left contains the three main panels plus the control panel +gui.leftTop = uix.VBox('Parent',gui.top); +% all plots in a flexible grid on the right side +gui.right = uix.GridFlex('Parent',gui.top,'Spacing',7); +set(gui.top,'Widths',[300 -1]); +set(gui.top,'MinimumWidths',[300 200]); + +% the three main panels are inside a vertically scrollable panel +gui.left = uix.ScrollingPanel('Parent',gui.leftTop); +% but the control panel is fixed to the bottom +gui.panels.Control.main = uix.BoxPanel('Parent',gui.leftTop,'Title','Control',... + 'TitleColor',[164 164 164]./255,'ForegroundColor','k'); +set(gui.leftTop,'Heights',[-1 53]); + +%% A. settings column +gui.panels.main = uix.VBox('Parent',gui.left); +gui.panels.Grains.main = uix.BoxPanel('Parent',gui.panels.main,'Title','Grains',... + 'TitleColor',myui.color.grains,'ForegroundColor','k','MinimizeFcn',@minimizePanel); +gui.panels.Domain.main = uix.BoxPanel('Parent',gui.panels.main,'Title','Domain',... + 'TitleColor',myui.color.domain,'ForegroundColor','k','MinimizeFcn',@minimizePanel); +gui.panels.Params.main = uix.BoxPanel('Parent',gui.panels.main,'Title','Parameter',... + 'TitleColor',myui.color.params,'ForegroundColor','k','MinimizeFcn',@minimizePanel); +uix.Empty('Parent',gui.panels.main); + +% adjust the heights of all left-column-panels +% edit and popup elements are 24 +edith = 22; +% panel header is always 22 high +headerh = 22; +% spacing is set to 3 +spacing = 3; +% maximal height of each panel +grains_max = 6*edith+7*spacing+headerh; +% params_max = 8*edith+9*spacing+headerh-14; +params_max = 13*edith+14*spacing+headerh-5; +domain_max = 8*edith+9*spacing+headerh; +% save the heights information (needed for minimizing the panels) +myui.heights = [22 22 22 -1; grains_max domain_max params_max -1]; +set(gui.panels.main,'Heights',myui.heights(2,:),... + 'MinimumHeights',[22 22 22 0]); +% the 'MinimumHeights' guarantees that the three panels fit into the +% ScrollingPanel when the GUI becomes smaller +set(gui.left,'Heights',-1,'MinimumHeights',grains_max+domain_max+params_max); + +if wbon + waitbar(2/steps,hwb,'loading GUI elements - Grains panel'); +end +[gui,myui] = GPRGRAVEL_createPanelGrains(data,gui,myui); + +if wbon + waitbar(3/steps,hwb,'loading GUI elements - Parameter panel'); +end +[gui,myui] = GPRGRAVEL_createPanelParameter(data,gui,myui); + +if wbon + waitbar(4/steps,hwb,'loading GUI elements - Domain panel'); +end +[gui,myui] = GPRGRAVEL_createPanelDomain(data,gui,myui); + +if wbon + waitbar(5/steps,hwb,'loading GUI elements - Control panel'); +end +[gui,myui] = GPRGRAVEL_createPanelControl(gui,myui); + +if wbon + waitbar(6/steps,hwb,'loading GUI elements - Plot panel'); +end +[gui,myui] = GPRGRAVEL_createGridPlots(gui,myui); + +% delete wait bar +if wbon + delete(hwb); +end + +[gui,myui] = GPRGRAVEL_createStatusbar(gui,myui); + +% make the main GUI visible +set(gui.main,'Visible','on'); + +%% enable all menus +set(gui.menu_handles.file,'Enable','on'); +set(gui.menu_handles.view,'Enable','on'); +set(gui.menu_handles.help,'Enable','on'); + +%% update the GUI data +gui.myui = myui; +setappdata(gui.figh,'gui',gui); +setappdata(gui.figh,'data',data); +set(gui.text_handles.Status,'String','GPRGRAVEL successfully started'); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/GPRGRAVEL/GPRGRAVEL_createGridPlots.m b/GPRGRAVEL/GPRGRAVEL_createGridPlots.m new file mode 100644 index 0000000..90902f7 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createGridPlots.m @@ -0,0 +1,200 @@ +function [gui,myui] = GPRGRAVEL_createGridPlots(gui,myui) +%GPRGRAVEL_createGridPlots creates the "Plots" grid panel +% +% Syntax: +% [gui,myui] = GPRGRAVEL_createGridPlots(gui,myui) +% +% Inputs: +% gui - figure gui elements structure +% myui - individual GUI settings structure +% +% Outputs: +% gui +% myui +% +% Example: +% [gui,myui] = GPRGRAVEL_createGridPlots(gui,myui) +% +% Other m-files required: +% findjobj.m +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% first create the individual tab panels +%(1,1) grains +gui.panels.Plot.grains = uix.TabPanel('Parent',gui.right,... + 'BackgroundColor',myui.color.grains); +%(2,1) results +gui.panels.Plot.result = uix.TabPanel('Parent',gui.right,... + 'BackgroundColor',myui.color.params); +%(1,2) domain +gui.panels.Plot.domain = uix.TabPanel('Parent',gui.right,... + 'BackgroundColor',myui.color.domain); +%(2,2) info +gui.panels.Plot.info = uix.TabPanel('Parent',gui.right,... + 'BackgroundColor',[164 164 164]./255); + +%% domain panel +plotDOMAIN = uix.VBox('Parent',gui.panels.Plot.domain,'Spacing',3,'Padding',3); +gui.panels.Plot.domain.TabTitles = {'Domain Setup'}; +gui.panels.Plot.domain.TabWidth = 75; + +% add view buttons and axes to the panel +plotDomain = uicontainer('Parent',plotDOMAIN); +DomainButtons = uix.HButtonBox('Parent',plotDOMAIN); +gui.push_handles.XZLd = uicontrol('Parent',DomainButtons,... + 'String','XZ',... + 'Tag','domain',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.YZLd = uicontrol('Parent',DomainButtons,... + 'String','YZ',... + 'Tag','domain',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.XYLd = uicontrol('Parent',DomainButtons,... + 'String','XY',... + 'Tag','domain',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.DLd = uicontrol('Parent',DomainButtons,... + 'String','3D',... + 'Tag','domain',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +set(plotDOMAIN,'Heights',[-1 30]); +gui.axes_handles.domain = axes('Parent',plotDomain,'Box','on'); +view(gui.axes_handles.domain,3); +axis(gui.axes_handles.domain,'equal'); +clearSingleAxis(gui.axes_handles.domain); + +%% results panel +plotVOLUME = uix.VBox('Parent',gui.panels.Plot.result,'Spacing',3,'Padding',3); +plotSLICE = uix.VBox('Parent',gui.panels.Plot.result,'Spacing',3,'Padding',3); +plotPROFILE = uix.HBox('Parent',gui.panels.Plot.result,'Spacing',3,'Padding',3); + +gui.panels.Plot.result.TabTitles = {'Monitor','Slice','Profiles'}; +gui.panels.Plot.result.TabWidth = 85; + +% Volume +% add view buttons and axes to the panel +plotVolume = uicontainer('Parent',plotVOLUME); +VolumeButtons = uix.HButtonBox('Parent',plotVOLUME); +gui.push_handles.XZLv = uicontrol('Parent',VolumeButtons,... + 'String','XZ',... + 'Tag','monitor',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.YZLv = uicontrol('Parent',VolumeButtons,... + 'String','YZ',... + 'Tag','monitor',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.XYLv = uicontrol('Parent',VolumeButtons,... + 'String','XY',... + 'Tag','monitor',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.DLv = uicontrol('Parent',VolumeButtons,... + 'String','3D',... + 'Tag','monitor',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +set(plotVOLUME,'Heights',[-1 30]); +gui.axes_handles.Volume = axes('Parent',plotVolume,'Box','on'); +view(gui.axes_handles.Volume,3); +axis(gui.axes_handles.Volume,'equal'); +clearSingleAxis(gui.axes_handles.Volume); + +% Slice +plotSliceBox = uix.HBox('Parent',plotSLICE); +plotSlice = uicontainer('Parent',plotSliceBox); +gui.slider_handles.slider = uicontrol('Style','Slider',... + 'Parent',plotSliceBox,'Callback',@onSlider); + +SliceButtons = uix.HButtonBox('Parent',plotSLICE); +gui.push_handles.XZLs = uicontrol('Parent',SliceButtons,... + 'String','XZ',... + 'Tag','slice',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.YZLs = uicontrol('Parent',SliceButtons,... + 'String','YZ',... + 'Tag','slice',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +gui.push_handles.XYLs = uicontrol('Parent',SliceButtons,... + 'String','XY',... + 'Tag','slice',... + 'FontSize',myui.fontsize,... + 'Callback',@onPushAxView); +set(plotSLICE,'Heights',[-1 30]); +set(plotSliceBox,'Widths',[-1 20]); +gui.axes_handles.Slice = axes('Parent',plotSlice,'Box','on'); +axis(gui.axes_handles.Slice,'equal'); +clearSingleAxis(gui.axes_handles.Slice); + +% Profiles +plotProfile1 = uicontainer('Parent',plotPROFILE); +plotProfile2 = uicontainer('Parent',plotPROFILE); +gui.axes_handles.ProfileAir = axes('Parent',plotProfile1,'Box','on'); +gui.axes_handles.ProfileH2O = axes('Parent',plotProfile2,'Box','on'); +clearSingleAxis(gui.axes_handles.ProfileAir); +clearSingleAxis(gui.axes_handles.ProfileH2O); + +%% grains / histogram panel +plotGrainsHistIn = uicontainer('Parent',gui.panels.Plot.grains); +plotGrainsHistOut = uicontainer('Parent',gui.panels.Plot.grains); +gui.panels.Plot.grains.TabTitles = {'GSD Input','GSD Output'}; +gui.panels.Plot.grains.TabWidth = 75; + +gui.axes_handles.histIn = axes('Parent',plotGrainsHistIn,'Box','on'); +gui.axes_handles.histOut = axes('Parent',plotGrainsHistOut,'Box','on'); +clearSingleAxis(gui.axes_handles.histIn); +clearSingleAxis(gui.axes_handles.histOut); + +%% info panel +plotInfo = uix.VBox('Parent',gui.panels.Plot.info,'Spacing',3,'Padding',3); +gui.panels.Plot.info.TabTitles = {'Info'}; +gui.panels.Plot.info.TabWidth = 75; + +gui.listbox_handles.info = uicontrol('Parent',plotInfo,... + 'Style','listbox','Tag','Info',... + 'FontSize',10,'String','>>',... + 'HorizontalAlignment','left','Enable','on'); + +% arrange the panels in a 2x2 grid +set(gui.right,'Widths',[-1 -1],'Heights',[-1 -1]); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/GPRGRAVEL/GPRGRAVEL_createMenus.m b/GPRGRAVEL/GPRGRAVEL_createMenus.m new file mode 100644 index 0000000..02640bb --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createMenus.m @@ -0,0 +1,125 @@ +function gui = GPRGRAVEL_createMenus(gui) +%GPRGRAVEL_createMenus creates all GUI menus +% +% Syntax: +% gui = GPRGRAVEL_createMenus(gui) +% +% Inputs: +% gui - figure gui elements structure +% +% Outputs: +% gui +% +% Example: +% gui = GPRGRAVEL_createMenus(gui) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% 1. File +gui.menu_handles.file = uimenu(gui.figh,... + 'Label','File',... + 'Enable','off'); + +% 1.1 Import +gui.menu_handles.file_import = uimenu(gui.menu_handles.file,... + 'Label','Import Data','Enable','off',... + 'Callback',@onMenuImport); + +% 1.2 Export +gui.menu_handles.file_export = uimenu(gui.menu_handles.file,... + 'Label','Export Data','Enable','off',... + 'Callback',@onMenuExport); + +% 1.3 Restart +gui.menu_handles.file_restart = uimenu(gui.menu_handles.file,... + 'Label','Restart',... + 'Separator','on',... + 'Callback',@onMenuRestartQuit); + +% 1.4 Quit +gui.menu_handles.file_quit = uimenu(gui.menu_handles.file,... + 'Label','Quit',... + 'Callback',@onMenuRestartQuit); + +%% 2. Extras +gui.menu_handles.view = uimenu(gui.figh,... + 'Label','View',... + 'Enable','off'); + +% 2.1 Tooltips (on/off) +gui.menu_handles.view_tooltips = uimenu(gui.menu_handles.view,... + 'Label','Tooltips',... + 'Checked','on','Enable','off',... + 'Callback',@onMenuView); + +% 2.2 Figure Toolbar +gui.menu_handles.view_toolbar = uimenu(gui.menu_handles.view,... + 'Label','Figure Toolbar',... + 'Callback',@onMenuView); +% 2.3.1 Figures +gui.menu_handles.view_figures = uimenu(gui.menu_handles.view,... + 'Label','Figures','Separator','on'); +% 2.3.1.1 all grains as voxels +gui.menu_handles.view_figures_voxelgrains = uimenu(gui.menu_handles.view_figures,... + 'Label','Voxelised Grains','Enable','off',... + 'Callback',@onMenuViewFigure); +% 2.3.1.2 only magnetization +gui.menu_handles.view_figures_volume = uimenu(gui.menu_handles.view_figures,... + 'Label','Volume','Enable','off',... + 'Callback',@onMenuViewFigure); +% % 2.3.1.3 only ramp +% gui.menu_handles.view_figures_ramp = uimenu(gui.menu_handles.view_figures,... +% 'Label','Switch-off Ramp',... +% 'Enable','off',... +% 'Callback',@onMenuViewFigure); +% % 2.3.1.4 only pulse +% gui.menu_handles.view_figures_pulse = uimenu(gui.menu_handles.view_figures,... +% 'Label','Pulse',... +% 'Enable','off',... +% 'Callback',@onMenuViewFigure); + +%% 3. Help +gui.menu_handles.help = uimenu(gui.figh,... + 'Label','Help',... + 'Enable','off'); + +% 3.1 About +gui.menu_handles.help_about = uimenu(gui.menu_handles.help,... + 'Label','About',... + 'Callback',@onMenuHelp); + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/GPRGRAVEL/GPRGRAVEL_createPanelControl.m b/GPRGRAVEL/GPRGRAVEL_createPanelControl.m new file mode 100644 index 0000000..e3a0bdb --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createPanelControl.m @@ -0,0 +1,92 @@ +function [gui,myui] = GPRGRAVEL_createPanelControl(gui,myui) +%GPRGRAVEL_createPanelControl creates "Control" panel +% +% Syntax: +% [gui,myui] = GPRGRAVEL_createPanelControl(gui,myui) +% +% Inputs: +% gui - figure gui elements structure +% myui - individual GUI settings structure +% +% Outputs: +% gui +% myui +% +% Example: +% [gui,myui] = GPRGRAVEL_createPanelControl(gui,myui) +% +% Other m-files required: +% findjobj.m +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +gui.panels.Control.HBox = uix.HBox('Parent', gui.panels.Control.main,... + 'Spacing',3,'Padding',3); + +tstr = 'Initialize domain.'; +gui.push_handles.Init = uicontrol('Style','pushbutton',... + 'Parent',gui.panels.Control.HBox,... + 'String','INIT / RESET',... + 'Tag','INIT',... + 'ToolTipString',tstr,... + 'FontSize',myui.fontsize,... + 'BackGroundColor',[102 166 30]./255,... + 'UserData',struct('Tooltipstr',tstr),... + 'Enable','on',... + 'Callback',@onPushRun); + +tstr = 'Start calculation.'; +gui.push_handles.Run = uicontrol('Style','pushbutton',... + 'Parent',gui.panels.Control.HBox,... + 'String','RUN',... + 'Tag','RUN',... + 'ToolTipString',tstr,... + 'FontSize',myui.fontsize,... + 'BackGroundColor',[102 166 30]./255,... + 'UserData',struct('Tooltipstr',tstr),... + 'Enable','off',... + 'Callback',@onPushRun); + +tstr = 'Reset axes grid to equally spaced 2x2.'; +gui.push_handles.Grid = uicontrol('Style','pushbutton',... + 'Parent',gui.panels.Control.HBox,... + 'String','RESET VIEW',... + 'Tag','GRID',... + 'ToolTipString',tstr,... + 'FontSize',myui.fontsize,... + 'UserData',struct('Tooltipstr',tstr),... + 'Enable','on',... + 'Callback',@onPushReset); + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/GPRGRAVEL/GPRGRAVEL_createPanelDomain.m b/GPRGRAVEL/GPRGRAVEL_createPanelDomain.m new file mode 100644 index 0000000..603d317 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createPanelDomain.m @@ -0,0 +1,242 @@ +function [gui,myui] = GPRGRAVEL_createPanelDomain(data,gui,myui) +%GPRGRAVEL_createPanelDomain creates "Domain" settings panel +% +% Syntax: +% [gui,myui] = GPRGRAVEL_createPanelDomain(gui,myui,data) +% +% Inputs: +% data - figure data structure +% gui - figure gui elements structure +% myui - individual GUI settings structure +% +% Outputs: +% gui +% myui +% +% Example: +% [gui,myui] = GPRGRAVEL_createPanelDomain(data,gui,myui) +% +% Other m-files required: +% findjobj.m +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% create all boxes +gui.panels.Domain.VBox = uix.VBox('Parent', gui.panels.Domain.main,... + 'Spacing',3,'Padding',3); + +textDomain = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); +setDomain = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); +textDx = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); +setDx = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); +textDip = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); +setDip = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); +textVolSpecies = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); +setVolSpecies = uix.HBox('Parent',gui.panels.Domain.VBox,'Spacing',3); + +%% Domain +gui.text_handles.domainx = uicontrol('Style','Text',... + 'Parent',textDomain,... + 'String','x [m]',... + 'FontSize',myui.fontsize); +gui.text_handles.domainy = uicontrol('Style','Text',... + 'Parent',textDomain,... + 'String','y [m]',... + 'FontSize',myui.fontsize); +gui.text_handles.domainz = uicontrol('Style','Text',... + 'Parent',textDomain,... + 'String','z [m]',... + 'FontSize',myui.fontsize); + +tstr = 'Set domain size.'; +gui.edit_handles.xm = uicontrol('Style','Edit',... + 'Parent',setDomain,... + 'String',sprintf('%4.3f',data.domain.xm),... + 'Tag','domain_xm',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.xm),... + 'Callback',@onEditValue); +gui.edit_handles.ym = uicontrol('Style','Edit',... + 'Parent',setDomain,... + 'String',sprintf('%4.3f',data.domain.ym),... + 'Tag','domain_ym',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.ym),... + 'Callback',@onEditValue); +gui.edit_handles.zm = uicontrol('Style','Edit',... + 'Parent',setDomain,... + 'String',sprintf('%4.3f',data.domain.zm),... + 'Tag','domain_zm',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.zm),... + 'Callback',@onEditValue); +set(setDomain,'Widths',[-1 -1 -1]); + +%% dx & porosity +gui.text_handles.dx = uicontrol('Style','Text',... + 'Parent',textDx,... + 'String','grid dx [m]',... + 'FontSize',myui.fontsize); +gui.text_handles.porosity = uicontrol('Style','Text',... + 'Parent',textDx,... + 'String','porosity [0-1]',... + 'FontSize',myui.fontsize); + +tstr = 'Set domain discretization.'; +gui.edit_handles.dx = uicontrol('Style','Edit',... + 'Parent',setDx,... + 'String',sprintf('%4.3f',data.domain.dx),... + 'Tag','domain_dx',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.dx),... + 'Callback',@onEditValue); +tstr = 'Set domain porosity.'; +gui.edit_handles.porosity = uicontrol('Style','Edit',... + 'Parent',setDx,... + 'String',sprintf('%4.3f',data.domain.porosity),... + 'Tag','domain_porosity',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.porosity),... + 'Callback',@onEditValue); +set(setDx,'Widths',[-1 -1]); + +%% surface dip +gui.text_handles.maskdipx = uicontrol('Style','Text',... + 'Parent',textDip,... + 'String','surface dip x [deg]',... + 'FontSize',myui.fontsize); +gui.text_handles.maskdipy = uicontrol('Style','Text',... + 'Parent',textDip,... + 'String','surface dip y [deg]',... + 'FontSize',myui.fontsize); + +tstr = 'Set dip angle in x-direction'; +gui.edit_handles.maskdipx = uicontrol('Style','Edit',... + 'Parent',setDip,... + 'String',sprintf('%d',data.params.maskdipx(1)),... + 'Tag','params_maskdipx',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.maskdipx 0 89]),... + 'Callback',@onEditValue); +tstr = 'Set dip angle in y-direction'; +gui.edit_handles.maskdipy = uicontrol('Style','Edit',... + 'Parent',setDip,... + 'String',sprintf('%d',data.params.maskdipy(1)),... + 'Tag','params_maskdipy',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.maskdipy 0 89]),... + 'Callback',@onEditValue); +set(setDip,'Widths',[-1 -1]); + +%% volumetric ratios of species +gui.text_handles.volair = uicontrol('Style','Text',... + 'Parent',textVolSpecies,... + 'String','air [0-1]',... + 'FontSize',myui.fontsize); +gui.text_handles.volh2o = uicontrol('Style','Text',... + 'Parent',textVolSpecies,... + 'String','water [0-1]',... + 'FontSize',myui.fontsize); +gui.text_handles.volmtx = uicontrol('Style','Text',... + 'Parent',textVolSpecies,... + 'String','matrix [0-1]',... + 'FontSize',myui.fontsize); + +tstr = 'Set volumetric ratios of species.'; +gui.edit_handles.volair = uicontrol('Style','Edit',... + 'Parent',setVolSpecies,... + 'String',sprintf('%4.3f',data.domain.VolSpeciesAIR),... + 'Tag','domain_VolSpeciesAIR',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.VolSpeciesAIR),... + 'Callback',@onEditValue); +gui.edit_handles.volh2o = uicontrol('Style','Edit',... + 'Parent',setVolSpecies,... + 'String',sprintf('%4.3f',data.domain.VolSpeciesH2O),... + 'Tag','domain_VolSpeciesH2O',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.VolSpeciesH2O),... + 'Callback',@onEditValue); +gui.edit_handles.volmtx = uicontrol('Style','Edit',... + 'Parent',setVolSpecies,... + 'String',sprintf('%4.3f',data.domain.VolSpeciesMTX),... + 'Tag','domain_VolSpeciesMTX',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',data.init.domain.VolSpeciesMTX),... + 'Callback',@onEditValue); +set(setVolSpecies,'Widths',[-1 -1 -1]); + +%% Java Hack to adjust the text fields vertical alignment +jh = findjobj(gui.text_handles.domainx); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.domainy); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.domainz); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.dx); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.porosity); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.maskdipx); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.maskdipy); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.volair); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.volh2o); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.volmtx); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/GPRGRAVEL/GPRGRAVEL_createPanelGrains.m b/GPRGRAVEL/GPRGRAVEL_createPanelGrains.m new file mode 100644 index 0000000..1706cc3 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createPanelGrains.m @@ -0,0 +1,195 @@ +function [gui,myui] = GPRGRAVEL_createPanelGrains(data,gui,myui) +%GPRGRAVEL_createPanelGrains creates "Grains" settings panel +% +% Syntax: +% [gui,myui] = GPRGRAVEL_createPanelGrains(gui,myui,data) +% +% Inputs: +% data - figure data structure +% gui - figure gui elements structure +% myui - individual GUI settings structure +% +% Outputs: +% gui +% myui +% +% Example: +% [gui,myui] = GPRGRAVEL_createPanelGrains(data,gui,myui) +% +% Other m-files required: +% findjobj.m +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% create all boxes +gui.panels.Grains.VBox = uix.VBox('Parent', gui.panels.Grains.main,... + 'Spacing',3,'Padding',3); + +getGSD = uix.HBox('Parent',gui.panels.Grains.VBox,'Spacing',3); +setShape = uix.HBox('Parent',gui.panels.Grains.VBox,'Spacing',3); +textEllipse = uix.HBox('Parent',gui.panels.Grains.VBox,'Spacing',3); +setEllipse = uix.HBox('Parent',gui.panels.Grains.VBox,'Spacing',3); +textOrient = uix.HBox('Parent',gui.panels.Grains.VBox,'Spacing',3); +setOrient = uix.HBox('Parent',gui.panels.Grains.VBox,'Spacing',3); + +%% load GSD +gui.text_handles.gsd = uicontrol('Style','Text',... + 'Parent',getGSD,... + 'String','GSD',... + 'FontSize',myui.fontsize); +tstr = 'grain size distribution file'; +gui.edit_handles.gsdfile = uicontrol('Style','Edit',... + 'Parent',getGSD,... + 'String','...',... + 'Tag','grains_gsdfile',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on'); +tstr = 'Load GSD File.'; +gui.push_handles.LoadGSD = uicontrol('Style','pushbutton',... + 'Parent',getGSD,... + 'String','Load',... + 'Tag','Load',... + 'ToolTipString',tstr,... + 'FontSize',myui.fontsize,... + 'UserData',struct('Tooltipstr',tstr),... + 'Callback',@onPushLoadGSD); +set(getGSD,'Widths',[75 -1 50]); + +%% Grain Shape +gui.text_handles.shape = uicontrol('Style','Text',... + 'Parent',setShape,... + 'String','grain shape',... + 'FontSize',myui.fontsize); +% uix.Empty('Parent',setShape); +tstr = 'Choose grain shape.'; +gui.popup_handles.Shape = uicontrol('Style', 'Popup',... + 'Parent',setShape,... + 'String',{'sphere','ellipsoid'},... + 'Tag','shape',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'UserData',struct('Tooltipstr',tstr),... + 'Callback',@onPopupShape); +set(setShape,'Widths',[75 -1]); + +%% ellipse settings - axes +gui.text_handles.ellipsex = uicontrol('Style','Text',... + 'Parent',textEllipse,... + 'String','x-axis [-]',... + 'FontSize',myui.fontsize); +gui.text_handles.ellipsey = uicontrol('Style','Text',... + 'Parent',textEllipse,... + 'String','y-axis [-]',... + 'FontSize',myui.fontsize); +gui.text_handles.ellipsez = uicontrol('Style','Text',... + 'Parent',textEllipse,... + 'String','z-axis [-]',... + 'FontSize',myui.fontsize); + +tstr = 'Set ellipsoid axes ratios'; +gui.edit_handles.axesx = uicontrol('Style','Edit',... + 'Parent',setEllipse,... + 'String',sprintf('%4.3f',data.grains.axes(1)),... + 'Tag','grains_axesx',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.grains.axes(1) 0 1]),... + 'Callback',@onEditValue); +gui.edit_handles.axesy = uicontrol('Style','Edit',... + 'Parent',setEllipse,... + 'String',sprintf('%4.3f',data.grains.axes(2)),... + 'Tag','grains_axesy',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.grains.axes(2) 0 1]),... + 'Callback',@onEditValue); +gui.edit_handles.axesz = uicontrol('Style','Edit',... + 'Parent',setEllipse,... + 'String',sprintf('%4.3f',data.grains.axes(3)),... + 'Tag','grains_axesz',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.grains.axes(3) 0 1]),... + 'Callback',@onEditValue); +set(setEllipse,'Widths',[-1 -1 -1]); + +%% ellipse settings - orient +gui.text_handles.ellipse1 = uicontrol('Style','Text',... + 'Parent',textOrient,... + 'String','polar angle [deg]',... + 'FontSize',myui.fontsize); +gui.text_handles.ellipse2 = uicontrol('Style','Text',... + 'Parent',textOrient,... + 'String','azimuthal angle [deg]',... + 'FontSize',myui.fontsize); + +tstr = 'Set polar angle'; +gui.edit_handles.orientp = uicontrol('Style','Edit',... + 'Parent',setOrient,... + 'String',sprintf('%4.3f',data.grains.orient(1)),... + 'Tag','grains_orientp',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off'); +tstr = 'Set azimuthal angle'; +gui.edit_handles.orienta = uicontrol('Style','Edit',... + 'Parent',setOrient,... + 'String',sprintf('%4.3f',data.grains.orient(2)),... + 'Tag','grains_orienta',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off'); +set(setOrient,'Widths',[-1 -1]); + + +% Java Hack to adjust the text fields vertical alignment +jh = findjobj(gui.text_handles.gsd); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.shape); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.ellipsex); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.ellipsey); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.ellipsez); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.ellipse1); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.ellipse2); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/GPRGRAVEL/GPRGRAVEL_createPanelParameter.m b/GPRGRAVEL/GPRGRAVEL_createPanelParameter.m new file mode 100644 index 0000000..4bfc1e8 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createPanelParameter.m @@ -0,0 +1,329 @@ +function [gui,myui] = GPRGRAVEL_createPanelParameter(data,gui,myui) +%GPRGRAVEL_createPanelParameter creates "Domain" settings panel +% +% Syntax: +% [gui,myui] = GPRGRAVEL_createPanelParameter(gui,myui,data) +% +% Inputs: +% data - figure data structure +% gui - figure gui elements structure +% myui - individual GUI settings structure +% +% Outputs: +% gui +% myui +% +% Example: +% [gui,myui] = GPRGRAVEL_createPanelParameter(data,gui,myui) +% +% Other m-files required: +% findjobj.m +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% create all boxes +gui.panels.Params.VBox = uix.VBox('Parent', gui.panels.Params.main,... + 'Spacing',0,'Padding',0); + +% targetpbox = uix.HBox('Parent',gui.panels.Params.VBox,'Spacing',0); +% maskpbox = uix.HBox('Parent',gui.panels.Params.VBox,'Spacing',0); +% targetpanel = uipanel('Parent',targetpbox,'Title','Target'); +% maskpanel = uipanel('Parent',maskpbox,'Title','Masks'); +targetpanel = uipanel('Parent',gui.panels.Params.VBox,'Title','Target'); +surfacepanel = uipanel('Parent',gui.panels.Params.VBox,'Title','Surface'); +satprofilepanel = uipanel('Parent',gui.panels.Params.VBox,'Title','Saturation Profile'); +miscpanel = uipanel('Parent',gui.panels.Params.VBox,'Title','Misc'); +set(gui.panels.Params.VBox,'heights',[22*5+3*6+15 -1 22*3+3*5+12 -1]); + +%% Parameter - Target +targetvbox = uix.VBox('Parent', targetpanel,'Spacing',3,'Padding',3); +loadtarget = uix.HBox('Parent',targetvbox,'Spacing',3); +texttarget1 = uix.HBox('Parent',targetvbox,'Spacing',3); +edittarget1 = uix.HBox('Parent',targetvbox,'Spacing',3); +texttarget2 = uix.HBox('Parent',targetvbox,'Spacing',3); +edittarget2 = uix.HBox('Parent',targetvbox,'Spacing',3); + +% load target +gui.text_handles.usetarget = uicontrol('Style','Text',... + 'Parent',loadtarget,... + 'String','Target',... + 'FontSize',myui.fontsize); +tstr = 'grain size distribution file'; +gui.edit_handles.targetfile = uicontrol('Style','Edit',... + 'Parent',loadtarget,... + 'String','none',... + 'Tag','params_targetfile',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on'); +tstr = 'Load Target File.'; +gui.push_handles.LoadTarget = uicontrol('Style','pushbutton',... + 'Parent',loadtarget,... + 'String','Load',... + 'Tag','Load',... + 'ToolTipString',tstr,... + 'FontSize',myui.fontsize,... + 'UserData',struct('Tooltipstr',tstr),... + 'Callback',@onPushLoadTarget); +set(loadtarget,'Widths',[75 -1 50]); + +% target center point +gui.text_handles.targetx = uicontrol('Style','Text',... + 'Parent',texttarget1,... + 'String','cent-x [m]',... + 'FontSize',myui.fontsize); +gui.text_handles.targety = uicontrol('Style','Text',... + 'Parent',texttarget1,... + 'String','cent-y [m]',... + 'FontSize',myui.fontsize); +gui.text_handles.targetz = uicontrol('Style','Text',... + 'Parent',texttarget1,... + 'String','cent-z [m]',... + 'FontSize',myui.fontsize); + +tstr = 'Set target center point'; +gui.edit_handles.targetx = uicontrol('Style','Edit',... + 'Parent',edittarget1,... + 'String',sprintf('%4.3f',data.params.targetCenter(1)),... + 'Tag','params_targetCenterx',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.targetCenter(1) 0 10]),... + 'Callback',@onEditValue); +gui.edit_handles.targety = uicontrol('Style','Edit',... + 'Parent',edittarget1,... + 'String',sprintf('%4.3f',data.params.targetCenter(2)),... + 'Tag','params_targetCentery',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.targetCenter(2) 0 10]),... + 'Callback',@onEditValue); +gui.edit_handles.targetz = uicontrol('Style','Edit',... + 'Parent',edittarget1,... + 'String',sprintf('%4.3f',data.params.targetCenter(3)),... + 'Tag','params_targetCenterz',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.targetCenter(3) 0 10]),... + 'Callback',@onEditValue); +set(edittarget1,'Widths',[-1 -1 -1]); + +% target orientation +gui.text_handles.targetpol = uicontrol('Style','Text',... + 'Parent',texttarget2,... + 'String','polar angle [deg]',... + 'FontSize',myui.fontsize); +gui.text_handles.targetaz = uicontrol('Style','Text',... + 'Parent',texttarget2,... + 'String','azimuthal angle [deg]',... + 'FontSize',myui.fontsize); + +tstr = 'Set polar angle'; +gui.edit_handles.targetp = uicontrol('Style','Edit',... + 'Parent',edittarget2,... + 'String',sprintf('%4.3f',data.params.targetOrient(1)),... + 'Tag','params_targetOrientp',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.targetOrient(1) -180 180]),... + 'Callback',@onEditValue); +tstr = 'Set azimuthal angle'; +gui.edit_handles.targeta = uicontrol('Style','Edit',... + 'Parent',edittarget2,... + 'String',sprintf('%4.3f',data.params.targetOrient(2)),... + 'Tag','params_targetOrienta',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.targetOrient(2) -180 180]),... + 'Callback',@onEditValue); +set(edittarget2,'Widths',[-1 -1]); + +%% Parameter - Surface +surfacevbox = uix.VBox('Parent',surfacepanel,'Spacing',3,'Padding',3); +% textSurface = uix.HBox('Parent',surfacevbox,'Spacing',3); +setSurface = uix.HBox('Parent',surfacevbox,'Spacing',3); + +tstr = ['If activated, the surface is closed an no grain smaller
',... + 'than the threshold radius can stick out.']; +gui.radio_handles.closedSurface = uicontrol('Style','checkbox',... + 'Parent',setSurface,... + 'String','close surface',... + 'Tag','close_surface',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr),... + 'Callback',@onRadioSurface); + +tstr = ['Give threshold radius from which grains cannot stick out of an open surface.

',... + 'HINT: if the largest grain radius is given, the surface is closed for all grains.']; +gui.edit_handles.closeSurfaceR = uicontrol('Style','Edit',... + 'Parent',setSurface,... + 'String',sprintf('%d',data.params.closeSurfaceR),... + 'Tag','params_closeSurfaceR',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.closeSurfaceR 0 1]),... + 'Callback',@onEditValue); + +gui.text_handles.closedSurface = uicontrol('Style','Text',... + 'Parent',setSurface,... + 'String','thresh. radius [m]',... + 'FontSize',myui.fontsize); + +set(setSurface,'Widths',[-1 -1 -1]); + +%% Parameter - Saturation Profile +satprofilevbox = uix.VBox('Parent',satprofilepanel,'Spacing',3,'Padding',3); +setSatProfile = uix.HBox('Parent',satprofilevbox,'Spacing',3); +textSatProfile = uix.HBox('Parent',satprofilevbox,'Spacing',3); +editSatProfile = uix.HBox('Parent',satprofilevbox,'Spacing',3); + +tstr = 'If activated, one can select a saturation profile along z-direction.'; +gui.radio_handles.Satprofile = uicontrol('Style','checkbox',... + 'Parent',setSatProfile,... + 'String','saturation profile',... + 'Tag','useSatProfile',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr),... + 'Callback',@onRadioSatProfile); + +tstr = 'If activated, choose between linear and exponential saturation profile.'; +gui.popup_handles.SatProfileType = uicontrol('Style','popupmenu',... + 'Parent',setSatProfile,... + 'String',{'linear','exponential'},... + 'Tag','sat_profile_type',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr),... + 'Callback',@onPopupSatProfile); + +gui.text_handles.SatProfileTop = uicontrol('Style','Text',... + 'Parent',textSatProfile,... + 'String','saturation @ top [-]',... + 'FontSize',myui.fontsize); +gui.text_handles.SatProfileBottom = uicontrol('Style','Text',... + 'Parent',textSatProfile,... + 'String','saturation @ bottom [-]',... + 'FontSize',myui.fontsize); + +tstr = 'Saturation at top'; +gui.edit_handles.SatProfileTop = uicontrol('Style','Edit',... + 'Parent',editSatProfile,... + 'String',sprintf('%d',data.params.satBounds(1)),... + 'Tag','params_satProfileTop',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.satBounds(1) 0 1]),... + 'Callback',@onEditValue); +tstr = 'Saturation at bottom'; +gui.edit_handles.SatProfileBottom = uicontrol('Style','Edit',... + 'Parent',editSatProfile,... + 'String',sprintf('%d',data.params.satBounds(2)),... + 'Tag','params_satProfileBottom',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.satBounds(2) 0 1]),... + 'Callback',@onEditValue); + +%% Parameter - Misc +miscvbox = uix.VBox('Parent',miscpanel,'Spacing',3,'Padding',3); + +% RNG +miscRNG = uix.HBox('Parent',miscvbox,'Spacing',3); + +tstr = ['If activated, one can enter an arbitrary RNG seed value so that always the same packing is created.']; +gui.radio_handles.customRNG = uicontrol('Style','checkbox',... + 'Parent',miscRNG,... + 'String','fix RNG seed',... + 'Tag','fixRNGseeed',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','on',... + 'UserData',struct('Tooltipstr',tstr),... + 'Callback',@onRadioFixRNG); + +tstr = ['Enter a custom RNG seed value.']; +gui.edit_handles.customRNG = uicontrol('Style','Edit',... + 'Parent',miscRNG,... + 'String',sprintf('%d',data.params.customRNGSEED),... + 'Tag','params_customRNGSEED',... + 'TooltipString',tstr,... + 'FontSize',myui.fontsize,... + 'Enable','off',... + 'UserData',struct('Tooltipstr',tstr,'defaults',[data.params.customRNGSEED 0 1e12]),... + 'Callback',@onEditValue); + +gui.text_handles.customRNG = uicontrol('Style','Text',... + 'Parent',miscRNG,... + 'String','RNG seed',... + 'FontSize',myui.fontsize); + +set(miscRNG,'Widths',[-1 -1 -1]); + + +%% Java Hack to adjust the text fields vertical alignment +jh = findjobj(gui.text_handles.usetarget); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.targetx); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.targety); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.targetz); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.targetpol); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.targetaz); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.closedSurface); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.SatProfileTop); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.SatProfileBottom); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) +jh = findjobj(gui.text_handles.customRNG); +jh.setVerticalAlignment(javax.swing.JLabel.CENTER) + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/GPRGRAVEL/GPRGRAVEL_createStatusbar.m b/GPRGRAVEL/GPRGRAVEL_createStatusbar.m new file mode 100644 index 0000000..f37ca03 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_createStatusbar.m @@ -0,0 +1,97 @@ +function [gui,myui] = GPRGRAVEL_createStatusbar(gui,myui) +%GPRGRAVEL_createStatusbar creates the bottom status bar +% +% Syntax: +% [gui,myui] = GPRGRAVEL_createStatusbar(gui,myui) +% +% Inputs: +% gui - figure gui elements structure +% myui - individual GUI settings structure +% +% Outputs: +% gui +% myui +% +% Example: +% [gui,myui] = GPRGRAVEL_createStatusbar(gui,myui) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% create panels inside the bottom hbox to show persistent status +% information +gui.panels.status.main = uix.Panel('Parent',gui.bottom); +gui.panels.status.Timer = uix.Panel('Parent',gui.bottom); +gui.panels.status.Masks = uix.Panel('Parent',gui.bottom); +gui.panels.status.Targets = uix.Panel('Parent',gui.bottom); +gui.panels.status.SatProfile = uix.Panel('Parent',gui.bottom); +gui.panels.status.Version = uix.Panel('Parent',gui.bottom); + +% adjust the panel widths +set(gui.bottom,'Widths',[300 -1 -1 -1 -1 -1]); + +gui.text_handles.Status = uicontrol('Style','Text',... + 'Parent',gui.panels.status.main,... + 'String','',... + 'HorizontalAlignment','left',... + 'FontSize',8); +gui.text_handles.TimerStat = uicontrol('Style','Text',... + 'Parent',gui.panels.status.Timer,... + 'String','Calc. Time: 0 s',... + 'HorizontalAlignment','left',... + 'FontSize',8); +gui.text_handles.Surface = uicontrol('Style','Text',... + 'Parent',gui.panels.status.Masks,... + 'String','SURFACE: OPEN',... + 'HorizontalAlignment','left',... + 'FontSize',8); +gui.text_handles.Targets = uicontrol('Style','Text',... + 'Parent',gui.panels.status.Targets,... + 'String','TARGETS: OFF',... + 'HorizontalAlignment','left',... + 'FontSize',8); +gui.text_handles.SatProf = uicontrol('Style','Text',... + 'Parent',gui.panels.status.SatProfile,... + 'String','SATURATION Profile: OFF',... + 'HorizontalAlignment','left',... + 'FontSize',8); +gui.text_handles.VersionStat = uicontrol('Style','Text',... + 'Parent',gui.panels.status.Version,... + 'String','Version: ',... + 'HorizontalAlignment','left',... + 'FontSize',8); + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/GPRGRAVEL/GPRGRAVEL_loadDefaults.m b/GPRGRAVEL/GPRGRAVEL_loadDefaults.m new file mode 100644 index 0000000..2fdd4f6 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_loadDefaults.m @@ -0,0 +1,224 @@ +function data = GPRGRAVEL_loadDefaults +%GPRGRAVEL_loadDefaults loads default GUI data values +% +% Syntax: +% GPRGRAVEL_loadDefaults +% +% Inputs: +% none +% +% Outputs: +% out - default data structure +% +% Example: +% out = GPRGRAVEL_loadDefaults +% +% Other m-files required: +% none +% +% Subfunctions: +% getInitData +% getMonitordata +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% aux data +data.info.ToolTips = 1; +data.info.Timer = 0; + +% get init data +% Note to user: use the "getInitData" function to adjust default +% settings and parameter range +init = getInitData; +data.init = init; + +% domain data +data.domain = init.domain; +data.domain.xm = data.domain.xm(1); +data.domain.ym = data.domain.ym(1); +data.domain.zm = data.domain.zm(1); +data.domain.dx = data.domain.dx(1); + +data.domain.VolSpeciesAIR = data.domain.VolSpeciesAIR(1); +data.domain.VolSpeciesH2O = data.domain.VolSpeciesH2O(1); +data.domain.VolSpeciesMTX = data.domain.VolSpeciesMTX(1); +data.domain.porosity = data.domain.porosity(1); + +% grains data +data.grains = init.grains; + +% params data +data.params = init.params; + +% monitor data during calculation +data.monitor = init.monitor; + +end + +% define init values and range +function init = getInitData +% domain dimensions in [m] +init.domain.xm = [0.3 1e-3 1e2]; +init.domain.ym = [0.3 1e-3 1e2]; +init.domain.zm = [0.3 1e-3 1e2]; +% domain discretization in [m] +init.domain.dx = [0.002 1e-4 1e-1]; % [2 mm] + +% epsilon values of the species used +init.domain.dkSpeciesAIR = 1; +init.domain.dkSpeciesMTX = 8.12; +init.domain.dkSpeciesH2O = 80; + +% give volumetric ratios of air, matrix and water +% Mikrit_dct (dkRock = 8.12, dkBulk = 7.90) +% air: 18.55 % | water: 5.00 % | grain: 76.45 % -> phi= 23.55 % +init.domain.VolSpeciesAIR = [30/100 0 1]; +init.domain.VolSpeciesH2O = [20/100 0 1]; +init.domain.VolSpeciesMTX = [50/100 0 1]; +% resulting porosity +init.domain.porosity = [init.domain.VolSpeciesAIR+init.domain.VolSpeciesH2O 0 1]; + +% grain shape ('sphere' or 'ellipse') +init.grains.shape = 'sphere'; +% in case of 'ellipse' give the main radii ratios (x,y,z) +init.grains.axes = [1 0.8 0.6]; +init.grains.axes = init.grains.axes./max(init.grains.axes); % normalized +% phi and theta angles to orient the ellipse +init.grains.orient = [0 0]; + +% use mask(s) +init.params.use_mask = true; +% create a 1-voxel margin on the outside of the inner volume +% if no grain fractions shall be located outside the inner volume +init.params.applyMarginMask = false; +% surface dip in x and y direction +init.params.maskdipx = 0; +init.params.maskdipy = 0; + +% use taget(s) +init.params.useTarget = false; +% target center point +init.params.targetCenter = [init.domain.xm(1)/2 init.domain.ym(1)/2 init.domain.zm(1)/2]; +% phi and theta angles to orient the target +init.params.targetOrient = [0 0]; + +% saturation profile (you can switch it on/off here) +init.params.useSatProfile = false; +init.params.satProfileType = 'linear'; +init.params.satBounds = [0 1]; + +% RNG +init.params.use_customRNG = false; +init.params.customRNGSEED = 123456781; + +% outpout MASKS values +ID_MASKED.Air.Lr = 0; +ID_MASKED.Water.Lr = 99; +ID_MASKED.PML.Lr = 999; +ID_MASKED.Target.Lr = 9999; +ID_MASKED.Air.M5 = 0; +ID_MASKED.Margin.Lr = -1; +ID_MASKED.Matrix.M5 = 1; +ID_MASKED.Water.M5 = 2; +ID_MASKED.PML.M5 = 3; +ID_MASKED.Target.M5 = 4; +ID_MASKED.Margin.M5 = 0; +init.params.ID_MASKED = ID_MASKED; + +% misc parameters +init.params.boolOmitLn = true; % save RAM, do not create Ln matrix +init.params.visualizePacking = false; + +% define porosity at (below) which new grains must touch with existing ones +init.params.requireTouch.por = 0.75; +% define number of voxels that are required +init.params.requireTouch.nVox = 5; + +% every grain smaller than this is not allowed to stick out of +% the surface +init.params.closeSurface = false; +init.params.closeSurfaceR = 0.0099; + +% info dump interval +init.params.dump = 100; % just for backward compatibility +init.params.dumpsPerBin = 10; +init.params.dumpSec = 60; +init.params.updateVisualSec = 120; + +% export options +init.params.exportMAT = true; +init.params.exportH5 = true; +init.params.exportPML = true; +init.params.PMLduplicate = false; +init.params.PMLtruncate = false; +init.params.pml_w = [10,10,50]; + +init.monitor = getMonitordata; + +end + +function monitor = getMonitordata() + +monitor = struct(... + 'nVox',0,... % voxel in current bin + 'nLstVox',0,... % number of voxel in last iteration + 'nVoxAim',0,... % number of voxels to generate in current bin + 'por_cur',0,... % current porosity + 'poro_final',0,... % target porostiy + 'nBin',0,... % total number of bins + 'i',0,... % number of current bin + 'rbin',0,... % grain size of current bin + 'xyzr0',0,... % list of grain centers + 'stat',0,... % statistic structure variable + 'threshMaxTry',0,... % threshold to stop grain packing + 'nMinTouch',1,... % number of voxels for touching grains criterion + 'boolMustTouch',0,... % grains must be placed next to existing ones + 'boolDrawFromGrainList',0,... % grain center positions are drawn from list of vacant positons + 'n',0,... % number of iterations + 'nxyzr0',0,... % buffer size of grain center position list + 'iSwapListBox',0,... % counter for swapping placing method + 'nSwapListBoxMax',0,... % threshold for swapping + 'iRandPos',0,... % counter for random positons + 'nRandPos',0,... % total number of random positions + 'arrPackVel',0,... % current packing velocity + 't1',0,... % timestamp + 'velPackMax',0,... % maximal packing velocity + 'arrFailStat',0,... % statistic of failed grain placing + 'params',0,... % params structure variable + 'paramVerbose',true,... % paramVerbose structure variable + 'domainVOL0',0,... % total number of voxel positions in volume + 'domainVOL0matrix',0,... % total number of matrix voxel to generate + 'binStat',0,... % verbose plot: grain size bins + 'voxHist',0,... % verbose plot: placed voxels + 'log',0 ... % log + ); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/GPRGRAVEL/GPRGRAVEL_setPositionOnScreen.m b/GPRGRAVEL/GPRGRAVEL_setPositionOnScreen.m new file mode 100644 index 0000000..eaaffb1 --- /dev/null +++ b/GPRGRAVEL/GPRGRAVEL_setPositionOnScreen.m @@ -0,0 +1,81 @@ +function pos = GPRGRAVEL_setPositionOnScreen +%GPRGRAVEL_setPositionOnScreen sets GUI position depending on monitor size +% +% Syntax: +% GPRGRAVEL_setPositionOnScreen +% +% Inputs: +% none +% +% Outputs: +% pos - four element vector [x y w h] +% +% Example: +% GPRGRAVEL_setPositionOnScreen +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get the monitor layout +scr = get(0,'MonitorPosition'); +if size(scr,1) > 1 % dual monitor setup + ind = find(scr(:,1)==1 & scr(:,2)==1); + sw = scr(ind,3); % width + sh = scr(ind,4); % height +else % single monitor + sw = scr(3); % width + sh = scr(4); % height +end +% maximal initial GUI width +gw = 1024; +% adjust the GUI width if the screen is not wide enough +if sw < 1024 + gw = 2*sw/3; +end +% GUI height +gh = gw/1.45; + +if numel(scr) > 4 % dual monitor position + % GUI on second screen + if any(scr(:,1)<0) + pos = [-sw+(sw-gw)/2 (sh-gh)/2 gw gh]; + else + pos = [sw+(sw-gw)/2 (sh-gh)/2 gw gh]; + end +else % single monitor position + pos = [(sw-gw)/2 (sh-gh)/2 gw gh]; +end + +end +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/README.md b/README.md new file mode 100644 index 0000000..a8e61b9 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +## GPRGRAVEL + +GPRGRAVEL icon + +A simple **GPR** **GRAVEL** generator + +- - - + +### Table of Contents +1. [About](#about) +2. [Requirements](#requirements) +3. [Installation](#installation) +4. [Usage](#usage) +5. [ToDo](#todo) +6. [Cite as & References](#references) +7. [Changelog](CHANGELOG.md) + +- - - + +### About + +**GPRGRAVEL** is a set of MATLABTM tools to generate grain (gravel) "packings" to be used with 3D FDTD GPR simulations. The "packings" are created based on user defined grain size distributions. Please note that **GPRGRAVEL** creates a "packing" by randomly placing grains at arbitrary positions inside a given container. No gravimetric settlement of the grains is applied. + +#### Basic features: +1. Choose between different grain shapes (*Sphere* or *Ellipsoid*) +2. Set a desired porosity and corresponding water and air fractions +3. Place an object (target) into the domain +4. Set a water saturation profile (*linear* or *exponential*) +5. etc. + +GPRGRAVEL + +- - - + +### Requirements + +In order to work properly you need to meet the following requirements: + +1. The [Mathworks](https://www.mathworks.com) MATLABTM software development environment (tested with R2019a and newer) +2. The GUI Layout Toolbox (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/47982-gui-layout-toolbox)) (required) +3. `findjobj` (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects)) (required) +4. `VoxelSurf` (get it from [FEX](https://de.mathworks.com/matlabcentral/fileexchange/66204-voxelsurf)) (optional) + +#### Operating System + +I tested it successfully under Windows 7 (64bit) and 10 (64bit) with Matlab R2019a and newer. Always with the latest version of the GUI Layout Toolbox (current version is afaik v2.3.5) + +**NOTE:** So far I did not test anything on Linux or a Mac. If you get it to work on either of the two systems (which it basically should I guess) please let me know. + +- - - + +### Installation + +1. It is recommended to install the GUI Layout Toolbox directly into MATLABTM via the mltbx-file (but it should also work via the old-school way of adding the toolbox folders to the MATLABTM path) +2. To use **GPRGRAVEL** you just need to place the `GPRGRAVEL` folder from the git repository on your hard drive and use the start script `startGPRGRAVEL` (within this script all necessary **GPRGRAVEL** folders are added to the MATLABTM path) + +- - - + +### Usage + +1. By executing the start script (see above) +2. Simply type `GPRGRAVEL` on the MATLABTM prompt (make sure the `GPRGRAVEL` folder is on the MATLABTM path) +3. Check the example scripts for the usage of the core functions without the GUI (inside the `scripts` folder) + +- - - + +### ToDo + +In no particular order and without guarantee that it will ever happen :-) : + +1. Add some more auxiliary options to the *Parameter* panel +2. Give the different export options via the GUI itself +3. Finalize the menu import/export routines +4. ... + + +- - - + +### Cite as +If you use GPRGRAVEL for your research, please cite it as: + +Thomas Hiller. (2023, July 14). ThoHiller/gprgravel: v0.1.0 (Version v0.1.0). GitHub. [https://github.com/ThoHiller/gprgravel] + +Note: This repository will be made available via Zenodo and will have a citable DOI. 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. Stadler, S., Schennen, S., Hiller, T. and Igel, J., "Realistic Simulation of GPR for Landmine and IED Detection Including Antenna Models, Soil Dispersion and Heterogeneity", Near Surface Geophysics (*submitted*), 2023. + +- - - +

MATLAB is a registered trademark of The Mathworks, Inc.

\ No newline at end of file diff --git a/callbacks/edits/onEditValue.m b/callbacks/edits/onEditValue.m new file mode 100644 index 0000000..2d8d398 --- /dev/null +++ b/callbacks/edits/onEditValue.m @@ -0,0 +1,231 @@ +function onEditValue(src,~) +%onEditValue updates all edit field values, checks for wrong inputs and +%restores a default value if necessary +% +% Syntax: +% onEditValue(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onEditValue(src) +% +% Other m-files required: +% +% Subfunctions: +% createDataString +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + + % get the value of the field + val = str2double(get(src,'String')); + % get the tag of the edit field + tag = get(src,'Tag'); + % get the user data of the field + ud = get(src,'UserData'); + + % get the default values [default min max] + defaults = ud.defaults; + + % check if the value is numeric + % if not reset to defaults stored in user data + if isnan(val) + set(src,'String',num2str(defaults(1))); + val = str2double(get(src,'String')); + end + % check if the value is out of bounds + % if yes reset to default + if val < defaults(2) || val > defaults(3) + set(src,'String',num2str(defaults(1))); + val = str2double(get(src,'String')); %#ok<*NASGU> + end + + % get the data field to update from the field tag + out = createDataString(tag); + % update the corresponding data field + updstr = [out.updstr,'=val;']; + eval(updstr); + + % update the data inside the GUI + setappdata(fig,'data',data); + + % depending on the particular edit field, further actions are + % necessary + switch tag + % ----------------------------------------------------------------- + % --- DOMAIN ------------------------------------------------------ + % ----------------------------------------------------------------- + case {'domain_xm','domain_ym','domain_zm'} + plotDomaindata(fig); + + case 'domain_porosity' + % if porosity is changed adjust matrix fraction and water + % fraction accordingly + mat = data.domain.VolSpeciesMTX; + air = data.domain.VolSpeciesAIR; + wat = data.domain.VolSpeciesH2O; + if val < air + val = air; + mat = 1 - val; + wat = val - air; + data.domain.porosity = val; + set(gui.edit_handles.porosity,'String',sprintf('%4.3f',val)); + else + mat = 1 - val; + wat = val - air; + end + data.domain.VolSpeciesMTX = mat; + data.domain.VolSpeciesH2O = wat; + set(gui.edit_handles.volmtx,'String',sprintf('%4.3f',mat)); + set(gui.edit_handles.volh2o,'String',sprintf('%4.3f',wat)); + + case 'domain_VolSpeciesAIR' + % if air fraction is changed adjust water fraction accordingly + por = data.domain.porosity; + wat = data.domain.VolSpeciesH2O; + if val > por + val = por; + wat = por - val; + data.domain.VolSpeciesAIR = val; + set(gui.edit_handles.volair,'String',sprintf('%4.3f',val)); + else + wat = por - val; + end + data.domain.VolSpeciesH2O = wat; + set(gui.edit_handles.volh2o,'String',sprintf('%4.3f',wat)); + + % ------------------------------------------------------------- + % --- GRAINS -------------------------------------------------- + % ------------------------------------------------------------- + case 'grains_axesx' + data.grains.axes(1) = val; + case 'grains_axesy' + data.grains.axes(2) = val; + case 'grains_axesz' + data.grains.axes(3) = val; + + % ------------------------------------------------------------- + % --- PARAMS -------------------------------------------------- + % ------------------------------------------------------------- + case {'params_targetCenterx','params_targetCentery',... + 'params_targetCenterz','params_targetOrientp',... + 'params_targetOrienta'} + data.params.targetCenterOld = data.params.targetCenter; + data.params.targetOrientOld = data.params.targetOrient; + switch tag + case 'params_targetCenterx' + data.params.targetCenter(1) = val; + case 'params_targetCentery' + data.params.targetCenter(2) = val; + case 'params_targetCenterz' + data.params.targetCenter(3) = val; + case 'params_targetOrientp' + data.params.targetOrient(1) = val; + case 'params_targetOrienta' + data.params.targetOrient(2) = val; + end + % update the data inside the GUI + setappdata(fig,'data',data); + % move target + data = setTargetPosition(data); + % update the data inside the GUI + setappdata(fig,'data',data); + % update plot + plotDomaindata(fig); + + case 'params_maskdipx' + % maximum angle until surface touches bottom in x-direction + a = atand(data.domain.zm/data.domain.xm); + if a > val + data.params.maskdipx = val; + else + data.params.maskdipx = a; + set(gui.edit_handles.maskdipx,'String',sprintf('%4.2f',a)); + end + % update the data inside the GUI + setappdata(fig,'data',data); + plotDomaindata(fig); + + case 'params_maskdipy' + % maximum angle until surface touches bottom in y-dircetion + b = atand(data.domain.zm/data.domain.ym); + if b > val + data.params.maskdipy = val; + else + data.params.maskdipy = b; + set(gui.edit_handles.maskdipy,'String',sprintf('%4.2f',b)); + end + % update the data inside the GUI + setappdata(fig,'data',data); + plotDomaindata(fig); + + case {'params_satProfileTop','params_satProfileBottom'} + id = findobj('Tag','params_satProfileTop'); + data.params.satBounds(1) = str2double(get(id,'String')); + id = findobj('Tag','params_satProfileBottom'); + data.params.satBounds(2) = str2double(get(id,'String')); + end + + % update GUI data + setappdata(fig,'data',data); +else + warndlg({'onEditValue:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%% helper function to create the update string +function out = createDataString(tag) +% find the underscore +ind = strfind(tag,'_'); +% the panel name is before the underscore +out.panel = tag(1:ind(1)-1); +% the field name afterwards +out.field = tag(ind(1)+1:end); +% replace the underscore with a dot +tag(ind) = '.'; +% create the update string +out.updstr = ['data.',tag]; + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/menus/onMenuExport.m b/callbacks/menus/onMenuExport.m new file mode 100644 index 0000000..4cd9c30 --- /dev/null +++ b/callbacks/menus/onMenuExport.m @@ -0,0 +1,89 @@ +function onMenuExport(src,~) +%onMenuExport handles the extra menu entries +% +% Syntax: +% onMenuExport(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onMenuExport(src) +% +% Other m-files required: +% switchToolTips +% updateStatusInformation +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data +% gui = getappdata(fig,'gui'); +% data = getappdata(fig,'data'); +% +% % gather the output data to save +% savedata.data = data; +% savedata.myui = gui.myui; + +% % session file name +% sfilename = 'GPRGRAVEL'; +% +% % ask for folder and maybe new name +% [sfile,spath] = uiputfile('*.mat',... +% 'Save session file',... +% fullfile(pwd,[sfilename,'.mat'])); +% +% % if user didn't cancel save session +% if sum([sfile spath]) > 0 +% save(fullfile(spath,sfile),'savedata'); +% clear savedata; +% % display info text +% set(gui.text_handles.Status,'String','GPRGRAVEL session successfully saved.'); +% else +% % display info text +% set(gui.text_handles.Status,'String','GPRGRAVEL session not saved'); +% end + +else + warndlg({'onMenuExport:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/menus/onMenuHelp.m b/callbacks/menus/onMenuHelp.m new file mode 100644 index 0000000..7e78b9e --- /dev/null +++ b/callbacks/menus/onMenuHelp.m @@ -0,0 +1,143 @@ +function onMenuHelp(src,~) +%onMenuHelp shows the Help Information +% +% Syntax: +% onMenuHelp(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onMenuHelp(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + + + % GPRGRAVEL logo + mylogo = load('gprgravellogo.mat','logo'); + + % header info + header{1,1} = 'GPRGRAVEL:'; + header{end+1,1} = ' '; + header{end+1,1} = ['author: ',gui.myui.author]; + header{end+1,1} = ' '; + header{end+1,1} = ['version: ',gui.myui.version]; + header{end+1,1} = ' '; + header{end+1,1} = ['date: ',gui.myui.date]; + header{end+1,1} = ' '; + + % info text + info{1,1} = ['GPRGRAVEL is a set of MATLAB tools, that allow some basic',... + ' creation of heterogeneous gravel/sand "packings" to be used with 3D FDTD GPR',... + ' simulations.',... + ' Note that a "packing" is created by randomly placing grains',... + ' at arbitrary positions. No gravimetric settlement of the grains is',... + ' applied.']; + info{end+1,1} = ' '; + info{end+1,1} = 'Have Fun!'; + + % get BLOCHUS GUI position + posf = get(fig,'Position'); + % default widht and height of About Figure + ww = 560; hh = 420; + xp = posf(1) + (posf(3)-ww)/2; + yp = posf(2) + (posf(4)-hh)/2; + % create Figure + hf = figure('Name','About GPRGRAVEL',... + 'NumberTitle','off','Tag','Help','ToolBar','none','MenuBar','none',... + 'Resize','off','Position',[xp yp ww hh],'Visible','off'); + v1 = uix.VBox('Parent',hf,'Padding',10,'Spacing',10); + + % text area + h1 = uix.VBox('Parent',v1); + % button area + h2 = uix.HBox('Parent',v1); + set(v1,'Heights',[-1 30]); + + % text area + h3 = uix.HBox('Parent',h1); + % logo area + h4 = uix.HBox('Parent',h1); + set(h1,'Heights',[-1 -1]); + + % close button at the bottom + uix.Empty('Parent',h2); + p1 = uicontrol('Style','pushbutton','Parent',h2,'String','OK',... + 'FontSize',10,'Callback','closereq()'); + uix.Empty('Parent',h2); + set(h2,'Widths',[-1 50 -1]) + + % header + uix.Empty('Parent',h3); + t1 = uicontrol('Style','Text','Parent',h3,'String',header,... + 'FontSize',10,'HorizontalAlignment','left'); + % logo + c1 = uicontainer('Parent',h3); + ax1 = axes('Parent',c1); + imshow(mylogo.logo,'Parent',ax1); + set(h3,'Widths',[50 -1 -1]); + + % info text + uix.Empty('Parent',h4); + t2 = uicontrol('Style','Text','Parent',h4,'String',info,... + 'FontSize',10,'HorizontalAlignment','left'); + uix.Empty('Parent',h4); + set(h4,'Widths',[20 -1 20]) + + % text hack + jh = findjobj(t1); + jh.setVerticalAlignment(javax.swing.JLabel.CENTER) + + % make the figure content visible + set(hf,'Visible','on'); + +else + warndlg({'onMenuHelp:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/menus/onMenuImport.m b/callbacks/menus/onMenuImport.m new file mode 100644 index 0000000..61d2437 --- /dev/null +++ b/callbacks/menus/onMenuImport.m @@ -0,0 +1,95 @@ +function onMenuImport(src,~) +%onMenuImport handles the extra menu entries +% +% Syntax: +% onMenuImport(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onMenuImport(src) +% +% Other m-files required: +% switchToolTips +% updateStatusInformation +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data +% gui = getappdata(fig,'gui'); +% data = getappdata(fig,'data'); +% +% % after the import these values should be strings +% Sessionpath = -1; +% Sessionfile = -1; +% % 'pathstr' hold s the name of the chosen data path +% [pathstr,~,~] = fileparts(pwd); +% % get the file name +% [Sessionfile,Sessionpath] = uigetfile(pathstr,... +% 'Choose GPRGRAVEL session file'); +% +% % only continue if user didn't cancel +% if sum(Sessionpath) > 0 +% % check if it is a valid session file +% tmp = load(fullfile(Sessionpath,Sessionfile),'savedata'); +% if isfield(tmp,'savedata') && isfield(tmp.savedata,'data') && ... +% isfield(tmp.savedata,'isPulse') && isfield(tmp.savedata,'isPrePol') +% savedata = tmp.savedata; +% +% % plot results (if any) +% if isfield(savedata.data,'results') +% plotResults(fig); +% end +% +% else +% helpdlg({'onMenuImport:';... +% 'This seems to be not a valid GPRGRAVEL session file'},... +% 'No session data found'); +% end +% end + +else + warndlg({'onMenuImport:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/menus/onMenuRestartQuit.m b/callbacks/menus/onMenuRestartQuit.m new file mode 100644 index 0000000..9c2e8cb --- /dev/null +++ b/callbacks/menus/onMenuRestartQuit.m @@ -0,0 +1,70 @@ +function onMenuRestartQuit(src,~) +%onMenuRestartQuit restarts or closes the GUI +% +% Syntax: +% onMenuRestartQuit(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onMenuRestartQuit(src) +% +% Other m-files required: +% BLOCHUS +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get the label (Restart / Quit) + label = get(src,'Label'); + % close the figure + close(fig); + % and restart if necessary + if strcmp(label,'Restart') + GPRGRAVEL; + end + +else + warndlg({'onMenuRestartQuit:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/menus/onMenuView.m b/callbacks/menus/onMenuView.m new file mode 100644 index 0000000..436f002 --- /dev/null +++ b/callbacks/menus/onMenuView.m @@ -0,0 +1,96 @@ +function onMenuView(src,~) +%onMenuView handles the extra menu entries +% +% Syntax: +% onMenuView(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onMenuView(src,~) +% +% Other m-files required: +% switchToolTips +% updateStatusInformation +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + + switch get(src,'Label') + case 'Tooltips' % switch on/off Tooltips + switch get(src,'Checked') + case 'on' % if it is on, switch it off +% switchToolTips(gui,'off'); + set(src,'Checked','off'); + data.info.ToolTips = 0; + case 'off' +% switchToolTips(gui,'on'); + set(src,'Checked','on'); + data.info.ToolTips = 1; + end + + case 'Figure Toolbar' % switch on/off the default Figure Toolbar + switch get(src,'Checked') + case 'on' % if it is on, switch it off + set(src,'Checked','off'); + viewmenufcn('FigureToolbar'); + case 'off' + set(src,'Checked','on'); + viewmenufcn('FigureToolbar'); + end + end + + % update GUI data + setappdata(fig,'gui',gui); + setappdata(fig,'data',data); + % update status bar +% updateStatusInformation(fig); + +else + warndlg({'onMenuView:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/menus/onMenuViewFigure.m b/callbacks/menus/onMenuViewFigure.m new file mode 100644 index 0000000..c343988 --- /dev/null +++ b/callbacks/menus/onMenuViewFigure.m @@ -0,0 +1,283 @@ +function onMenuViewFigure(src,~) +%onMenuViewFigure shows predefined figure layouts +% +% Syntax: +% onMenuViewFigure(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onMenuViewFigure(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + grains = data.grains; + domain = data.domain; + params = data.params; + + % get GUI position + posf = get(fig,'Position'); + % opening the export figure + % expfig = figure; + + % create the axes layout on the export figure and get the axes + % positions + switch get(src,'Label') + case 'Volume' + expfig = findobj('Tag','GPRGRAVELvolume'); + if isempty(expfig) + expfig = figure('Name','GPRGRAVEL: Volume',... + 'NumberTitle','off','Tag','GPRGRAVELvolume'); + set(expfig,'Position',[600 300 800 700]); + else + clf(expfig); + end + ax = axes('Parent',expfig); + + % get monitor data + Lr = data.domain.final{1}.Lr; + % remove grains smaller + threshR = 1e-3; + Lr(Lr. diff --git a/callbacks/popup/onPopupSatProfile.m b/callbacks/popup/onPopupSatProfile.m new file mode 100644 index 0000000..b4acd93 --- /dev/null +++ b/callbacks/popup/onPopupSatProfile.m @@ -0,0 +1,81 @@ +function onPopupSatProfile(src,~) +%onPopupSatProfile switches the saturation profileoptions between +%"linear" and "exponential" +% +% Syntax: +% onPopupSatProfile(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onPopupSatProfile(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + data = getappdata(fig,'data'); + + % get the popup menu entry + val = get(src,'Value'); + + % set the corresponding nucleus + switch val + case 1 + data.params.satProfileType = 'linear'; + case 2 + data.params.satProfileType = 'exponential'; + end + + % update the GUI data + setappdata(fig,'data',data); + % update status + updateStatusInformation(fig); + +else + warndlg({'onPopupSatProfile:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/popup/onPopupShape.m b/callbacks/popup/onPopupShape.m new file mode 100644 index 0000000..c8f93bb --- /dev/null +++ b/callbacks/popup/onPopupShape.m @@ -0,0 +1,89 @@ +function onPopupShape(src,~) +%onPopupShape switches the grain shape between "sphere" and "ellipse" +% +% Syntax: +% onPopupShape(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onPopupShape(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + + % get the popup menu entry + val = get(src,'Value'); + + % set the corresponding nucleus + switch val + case 1 + data.grains.shape = 'sphere'; + set(gui.edit_handles.axesx,'Enable','off'); + set(gui.edit_handles.axesy,'Enable','off'); + set(gui.edit_handles.axesz,'Enable','off'); + set(gui.edit_handles.orientp,'Enable','off'); + set(gui.edit_handles.orienta,'Enable','off'); + case 2 + data.grains.shape = 'ellipse'; + set(gui.edit_handles.axesx,'Enable','on'); + set(gui.edit_handles.axesy,'Enable','on'); + set(gui.edit_handles.axesz,'Enable','on'); + set(gui.edit_handles.orientp,'Enable','on'); + set(gui.edit_handles.orienta,'Enable','on'); + end + + % update the GUI data + setappdata(fig,'data',data); + +else + warndlg({'onPopupShape:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/push/onPushAxView.m b/callbacks/push/onPushAxView.m new file mode 100644 index 0000000..3c97f25 --- /dev/null +++ b/callbacks/push/onPushAxView.m @@ -0,0 +1,116 @@ +function onPushAxView(src,~) +%onPushAxView sets the view of axes plot to predefined sets +% +% Syntax: +% onPushAxView(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onPushAxView(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + % get button tag + str = get(src,'String'); + tag = get(src,'Tag'); + + switch tag + case {'domain','monitor'} + + switch tag + case 'domain' + ax = gui.axes_handles.domain; + case 'monitor' + ax = gui.axes_handles.Volume; + end + + switch str + case 'XZ' + axes(ax) + view([0 0]); + case 'YZ' + axes(ax) + view([90 0]); + case 'XY' + axes(ax) + view([0 90]); + case '3D' + axes(ax) + view([-35 30]); + end + + case 'slice' + data.params.showslice = str; + domain = data.domain; + % update GUI data + setappdata(fig,'data',data); + + switch str + case 'XZ' + set(gui.slider_handles.slider,'Min',1,'Max',domain.ny0,... + 'Value',1,'SliderStep',[1/(domain.ny0-1) 5/(domain.ny0-1)]) + case 'YZ' + set(gui.slider_handles.slider,'Min',1,'Max',domain.nx0,... + 'Value',1,'SliderStep',[1/(domain.nx0-1) 5/(domain.nx0-1)]) + case 'XY' + set(gui.slider_handles.slider,'Min',1,'Max',domain.nz0,... + 'Value',1,'SliderStep',[1/(domain.nz0-1) 5/(domain.nz0-1)]) + end + % update GUI data + setappdata(fig,'gui',gui); + % plot slice + plotSlicedata(fig,str,1); + end + +else + warndlg({'onPushAxView:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/push/onPushLoadGSD.m b/callbacks/push/onPushLoadGSD.m new file mode 100644 index 0000000..29beac1 --- /dev/null +++ b/callbacks/push/onPushLoadGSD.m @@ -0,0 +1,157 @@ +function onPushLoadGSD(src,~) +%onPushLoadGSD starts the import of a user provided GSD file +% +% Syntax: +% onPushLoadGSD(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onPushLoadGSD(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + grains = data.grains; + + % get the standard input path for GSD data if it is not already there + if ~isfield(grains,'GSDpath') + grains.GSDpath = fullfile(data.params.GPRGRAVELpath,'input','GSD'); + end + % get the file to open + [file,path] = uigetfile('.txt','Select the GSD file',grains.GSDpath); + grains.GSDpath = path; + grains.GSDfile = file; + % try to import the data + tmp = importdata(fullfile(grains.GSDpath,grains.GSDfile)); + + % if there is data, proceed + if ~isempty(tmp) + % IMPORTANT: + % if there is no header, assume the data is given as diameters in mm!!! + if isstruct(tmp) + header = tmp.colheaders{1}; + % get unit of data + ind = strfind(header,'#'); + unit = strtrim(header(ind+1:end)); + switch unit + case 'mm' + fac = 1000; + case 'cm' + fac = 100; + case 'm' + fac = 1; + end + tmpd = tmp.data; + else + % conversion factor from mm to m + fac = 1000; + tmpd = tmp; + end + + % assume it is a list of grain sizes + grains.ishistogram = false; + if size(tmpd,2) == 2 + % if not, it is a histogram CDF + grains.ishistogram = true; + end + + % save the data as radius in [m] + if grains.ishistogram + grains.hist_raw = tmpd; + % transform to radius in [m] + grains.hist_raw(:,1) = grains.hist_raw(:,1)/(2*fac); + % get maximum radius + grains.rmax = max(grains.hist_raw(:,1)); + else + % grain diameter in [mm] + dia = tmpd; + % transform to [m] + grains.dia_raw = dia/fac; + % transform to radius in [m] + grains.r_raw = dia/2/fac; + % get maximum radius + grains.rmax = max(grains.r_raw); + end + % update the GSD file name text fiedl + set(gui.edit_handles.gsdfile,'String',grains.GSDfile); + + % delete old voxelised GSD data + if isfield(grains,'binVol') + grains = rmfield(grains,'binVol'); + end + if isfield(grains,'VOLspheres') + grains = rmfield(grains,'VOLspheres'); + end + if isfield(grains,'rbins') + grains = rmfield(grains,'rbins'); + end + if isfield(grains,'nbins') + grains = rmfield(grains,'nbins'); + end + if isfield(grains,'Nbins') + grains = rmfield(grains,'Nbins'); + end + if isfield(grains,'nvoxBins') + grains = rmfield(grains,'nvoxBins'); + end + + % update GUI data + data.grains = grains; + setappdata(fig,'data',data); + % plot the GSD data + plotGSDdata(fig,'input'); + else + warndlg({'onPushLoadGSD:','Please provide grain size data.'},... + 'GPRGRAVEL error'); + end +else + warndlg({'onPushLoadGSD:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/push/onPushLoadTarget.m b/callbacks/push/onPushLoadTarget.m new file mode 100644 index 0000000..fc97e9e --- /dev/null +++ b/callbacks/push/onPushLoadTarget.m @@ -0,0 +1,135 @@ +function onPushLoadTarget(src,~) +%onPushLoadTarget starts the import of a user provided target file +% +% Syntax: +% onPushLoadTarget(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onPushLoadTarget(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + domain = data.domain; + params = data.params; + + % get the standard input path for target data if it is not already there + if ~isfield(params,'targetPath') + params.targetPath = fullfile(data.params.GPRGRAVELpath,'input','Targets'); + end + % get the file to open + [file,path] = uigetfile('.h5','Select the Target h5 file',params.targetPath); + params.targetPath = path; + params.targetFile = file; + % try to import the data + target = h5read(fullfile(params.targetPath,params.targetFile),'/data'); + + % if there is data, proceed + if ~isempty(target) && sum(target(:)) ~= 0 + % target successfully imported + params.useTarget = true; + + target = permute(target,[2 3 1]); + + % IMPORTANT: + % we assume the target grid resolution is 2mm! + [xt,yt,zt] = size(target); + xt = xt*0.002; + yt = yt*0.002; + zt = zt*0.002; + + centD = [domain.xm/2 domain.ym/2 domain.zm/2]; + centT = [xt/2 yt/2 zt/2]; + shift = centD-centT; + shift = floor(shift./domain.dx); + + szT = size(target); + params.targetDIM = szT; + target = target(:); + ind = 1:1:numel(target); ind = ind(:); + ind = ind(target>0); + target = target(target>0); + % set all targets to index 2 + target(:) = 2; + + [ixt,iyt,izt] = ind2sub(szT,ind); + ixt = ixt+shift(1); + iyt = iyt+shift(2); + izt = izt+shift(3); + params.target = target; + params.targetIDX = [ixt iyt izt]; + params.targetCenter = centD; + + % update the GSD file name text fiedl + set(gui.edit_handles.targetfile,'String',params.targetFile); + % activate control fields + set(gui.edit_handles.targetx,'Enable','on'); + set(gui.edit_handles.targety,'Enable','on'); + set(gui.edit_handles.targetz,'Enable','on'); + set(gui.edit_handles.targetp,'Enable','on'); + set(gui.edit_handles.targeta,'Enable','on'); + + % update GUI data + data.domain = domain; + data.params = params; + setappdata(fig,'data',data); + % plot the GSD data + plotDomaindata(fig); + % update status + updateStatusInformation(fig); + else + warndlg({'onPushLoadTarget:','Target data is empty. Check!'},... + 'GPRGRAVEL error'); + end +else + warndlg({'onPushLoadTarget:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/push/onPushRun.m b/callbacks/push/onPushRun.m new file mode 100644 index 0000000..9acf370 --- /dev/null +++ b/callbacks/push/onPushRun.m @@ -0,0 +1,161 @@ +function onPushRun(src,~) +%onPushRun starts the calculation +% +% Syntax: +% onPushRun(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onPushRun(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + data = getappdata(fig,'data'); + + % get data + grains = data.grains; + params = data.params; + domain = data.domain; + + % get the tag of the button + tag = get(src,'tag'); + + % time the calculation + t0 = tic; + switch tag + case 'INIT' % init domain + + % check if there is GSD data, otherwise we cannot start + if isfield(grains,'ishistogram') + + % init the domain box + [domain,params] = prepareDomain(domain,grains,params,src); + % init the voxelised grain size distribution + grains = prepareVoxelGSD(domain,grains,src); + + % update data + data.grains = grains; + data.domain = domain; + data.params = params; + setappdata(fig,'data',data); + + % plot voxelisd GSD + plotGSDdata(fig,'input'); + + % activate the RUN button + set(gui.push_handles.Run,'Enable','on'); + + % activate menu + set(gui.menu_handles.view_figures_voxelgrains,'Enable','on'); + + % init/reset the grid panel + % input GSD + set(gui.panels.Plot.grains,'Selection',1); + % 3D monitor view + onPushAxView(gui.push_handles.DLv); + set(gui.panels.Plot.result,'Selection',1); + clearSingleAxis(gui.axes_handles.Volume); + clearSingleAxis(gui.axes_handles.Slice); + clearSingleAxis(gui.axes_handles.ProfileAir); + clearSingleAxis(gui.axes_handles.ProfileH2O); + clearSingleAxis(gui.axes_handles.histOut); + + else + warndlg({'onPushRun:','LOAD GSD data first.'},... + 'GPRGRAVEL error'); + end + + case 'RUN' % run calculation + + % switch view to output GSD plot + set(gui.panels.Plot.grains,'Selection',2); + set(gui.panels.Plot.result,'Selection',1); + + % start placing the grains + [domain,grains,params] = placeGrains(domain,grains,params,data.monitor,src); + % update data + data.grains = grains; + data.domain = domain; + data.params = params; + setappdata(fig,'data',data); + + % now add the water + [domain,grains,params] = placeWater(domain,grains,params,src); + % update data + data.grains = grains; + data.domain = domain; + data.params = params; + setappdata(fig,'data',data); + + % plot results + onPushAxView(gui.push_handles.XZLs); + data = getappdata(fig,'data'); + plotProfiledata(fig); + + % activate menu + set(gui.menu_handles.view_figures_volume,'Enable','on'); + + % export results + [~,~,~] = exportData(domain,grains,params,src); + + end + + % time the calculation + data.info.Timer = toc(t0); + + % update GUI data + setappdata(fig,'data',data); + % update status bar + updateStatusInformation(fig); + +else + warndlg({'onPushRun:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/callbacks/radio/onRadioFixRNG.m b/callbacks/radio/onRadioFixRNG.m new file mode 100644 index 0000000..f02b946 --- /dev/null +++ b/callbacks/radio/onRadioFixRNG.m @@ -0,0 +1,78 @@ +function onRadioFixRNG(src,~) +%onRadioFixRNG activates/deactivates random seed value input +% +% Syntax: +% onRadioFixRNG +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onRadioFixRNG(src,~) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI handle and data +fig = ancestor(src,'figure','toplevel'); +gui = getappdata(fig,'gui'); +data = getappdata(fig,'data'); + +% on/off +val = get(src,'Value'); + +switch val + case 0 % off + data.params.use_customRNG = false; + data.params.customRNGSEED = data.init.params.customRNGSEED; + set(gui.edit_handles.customRNG,'String',sprintf('%d',data.params.customRNGSEED)); + set(gui.edit_handles.customRNG,'Enable','off'); + + case 1 % on + data.params.use_customRNG = true; + set(gui.edit_handles.customRNG,'String',sprintf('%d',data.params.customRNGSEED)); + set(gui.edit_handles.customRNG,'Enable','on'); +end + +% update GUI data +setappdata(fig,'data',data); +% update status +% updateStatusInformation(fig); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/callbacks/radio/onRadioSatProfile.m b/callbacks/radio/onRadioSatProfile.m new file mode 100644 index 0000000..cb23a5c --- /dev/null +++ b/callbacks/radio/onRadioSatProfile.m @@ -0,0 +1,86 @@ +function onRadioSatProfile(src,~) +%onRadioSatProfile activates/deactivates saturation profile option +% +% Syntax: +% onRadioSatProfile +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onRadioSatProfile(src,~) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI handle and data +fig = ancestor(src,'figure','toplevel'); +gui = getappdata(fig,'gui'); +data = getappdata(fig,'data'); + +% on/off +val = get(src,'Value'); + +switch val + case 0 % off + data.params.useSatProfile = false; + set(gui.popup_handles.SatProfileType,'Enable','off'); + + data.params.satBounds = [0 1]; + set(gui.edit_handles.SatProfileTop,'Enable','off',... + 'String',sprintf('%d',data.params.satBounds(1))); + set(gui.edit_handles.SatProfileBottom,'Enable','off',... + 'String',sprintf('%d',data.params.satBounds(2))); + + case 1 % on + data.params.useSatProfile = true; + set(gui.popup_handles.SatProfileType,'Enable','on'); + + set(gui.edit_handles.SatProfileTop,'Enable','on',... + 'String',sprintf('%d',data.params.satBounds(1))); + set(gui.edit_handles.SatProfileBottom,'Enable','on',... + 'String',sprintf('%d',data.params.satBounds(2))); +end + +% update GUI data +setappdata(fig,'data',data); +% update status +updateStatusInformation(fig); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/callbacks/radio/onRadioSurface.m b/callbacks/radio/onRadioSurface.m new file mode 100644 index 0000000..3e1dd3a --- /dev/null +++ b/callbacks/radio/onRadioSurface.m @@ -0,0 +1,82 @@ +function onRadioSurface(src,~) +%onRadioSurface activates/deactivates open surface +% +% Syntax: +% onRadioSurface +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onRadioSurface(src,~) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI handle and data +fig = ancestor(src,'figure','toplevel'); +gui = getappdata(fig,'gui'); +data = getappdata(fig,'data'); + +% on/off +val = get(src,'Value'); + +switch val + case 0 % off + data.params.closeSurface = false; + data.params.closeSurfaceR = 1; + set(gui.edit_handles.closeSurfaceR,'Enable','off'); + set(gui.edit_handles.closeSurfaceR,'String',sprintf('%4.3f',data.params.closeSurfaceR)); + + case 1 % on + data.params.closeSurface = true; + set(gui.edit_handles.closeSurfaceR,'Enable','on'); + if isfield(data.grains,'rmax') + data.params.closeSurfaceR = data.grains.rmax; + end + set(gui.edit_handles.closeSurfaceR,'Enable','on'); + set(gui.edit_handles.closeSurfaceR,'String',sprintf('%4.3f',data.params.closeSurfaceR)); +end + +% update GUI data +setappdata(fig,'data',data); +% update status +updateStatusInformation(fig); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/callbacks/slider/onSlider.m b/callbacks/slider/onSlider.m new file mode 100644 index 0000000..d9db18b --- /dev/null +++ b/callbacks/slider/onSlider.m @@ -0,0 +1,70 @@ +function onSlider(src,~) +%onSlider handles the slider callback for the Slider panel +% +% Syntax: +% onSlider(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% onSlider(src) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(src,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + data = getappdata(fig,'data'); + % get slider value + val = get(src,'Value'); + % update GUI data + setappdata(fig,'data',data); + % plot slice + plotSlicedata(fig,data.params.showslice,val); + +else + warndlg({'onPushAxView:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/exportData.m b/functions/exportData.m new file mode 100644 index 0000000..dc060e2 --- /dev/null +++ b/functions/exportData.m @@ -0,0 +1,396 @@ +function [domain,grains,params] = exportData(domain,grains,params,varargin) +%exportData export the results +% +% Syntax: +% [domain,grains,params] = exportData(domain,grains,params,varargin) +% +% Inputs: +% domain +% grains +% params +% varargin +% +% Outputs: +% domain +% grains +% params +% +% Example: +% [domain,grains,params] = exportData(domain,grains,params,varargin) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% check if called from GUI +isgui = false; +if nargin > 3 + src = varargin{1}; + % get GUI handle + fig = ancestor(src,'figure','toplevel'); + isgui = true; + % get GUI data + gui = getappdata(fig,'gui'); +else + gui = 0; +end + +%% INITIALIZE +% get the standard output path if it is not already there +if ~isfield(params,'EXPORTpath') + params.EXPORTpath = fullfile(params.GPRGRAVELpath,'output',datestr(now,'yyyymmdd_HHMM')); +end +if ~exist(params.EXPORTpath,'dir') + mkdir(params.EXPORTpath); +end + +%% Calculate summary of the results and export the model + +% get the model cubes +% Lr = domain.final{1}.Lr; -> voxels coded with grain size +% M = domain.final{1}.M; -> voxels boolean coded ean (0 = vacant, 1 = occupied) + +% refresh volumetric fractions +nVox_H2O = sum(domain.final{1}.Lr(domain.kEvalPoro) == params.ID_MASKED.Water.Lr); +nVox_air = sum(domain.final{1}.Lr(domain.kEvalPoro) == params.ID_MASKED.Air.Lr); +nVox_mtx = sum(domain.final{1}.M(domain.kEvalPoro))-nVox_H2O; + +final_vol.air = nVox_air/domain.VOL0; +final_vol.H2O = nVox_H2O/domain.VOL0; +final_vol.mtx = nVox_mtx/domain.VOL0; +domain.final_vol = final_vol; + +%% +if params.exportMAT + data.domain = domain; + data.grains = grains; + data.params = params; + fname = 'GPRGRAVEL.mat'; + + str1 = 'EXPORT - saving data to MAT file ... '; + str2 = 'EXPORT - saving data to MAT file ... done.'; + if isgui + set(gui.text_handles.Status,'String', str1); + else + disp(str1); + end + pause(0.01); + save(fullfile(params.EXPORTpath,fname),'data','-v7.3'); + if isgui + set(gui.text_handles.Status,'String', str2); + else + disp(str2); + end + pause(0.01); +end + +if params.exportH5 + + params.save_h5 = 'GPRGRAVEL_full.h5'; + + % check if a PML should be used + if params.exportPML + % boundary + marg = domain.marg; + % extra region to be cut out + if isfield(params,'cut') + marg1 = params.cut; + else + marg1 = [0 0 0]; + end + % container without boundaries except z+ + % uses Label matrix "Lr" for each radius bin + % M = domain.final{1}.Lr(marg+1:end-marg,marg+1:end-marg,marg+1:end); + kInnerX = marg+1+marg1(1):size(domain.final{1}.Lr,1)-marg-marg1(1); + kInnerY = marg+1+marg1(2):size(domain.final{1}.Lr,2)-marg-marg1(2); + kInnerZ = 1:size(domain.final{1}.Lr,3)-marg-marg1(2); + + if params.applyMarginMask + kInnerX = kInnerX(2:end-1); + kInnerY = kInnerY(2:end-1); + kInnerZ = kInnerZ(1:end-1); + end + + M = domain.final{1}.Lr(kInnerX,kInnerY,kInnerZ); + [nx,ny,nz] = size(M); + + % PML boundaries + if isfield(params,'pml_w') + pml_w = params.pml_w; + else + pml_w = 10; + end + + if length(pml_w) == 1 + pml_w = pml_w * ones(1,3); + end + % create container with PML boundaries (PML = 999) + %M_pml = 999*ones(nx+2*pml_w,ny+2*pml_w,nz+pml_w); + M_pml = 999*ones(nx+2*pml_w(1),ny+2*pml_w(2),nz+pml_w(3)); + + % fill z+ margin with air + M_pml(:,:,1:domain.marg) = 0; + + % account for masked regions in PML + cellMasks = params.masks; + nMask = numel(cellMasks); + + for iMask=1:nMask + curMask = params.masks{iMask}; + + if isfield(curMask,'arrTiltDegXY') + szPML = size(M_pml); + maxX = domain.dx*szPML(1); + maxY = domain.dx*szPML(2); + xPML = domain.dx*((1:szPML(2))-domain.marg+pml_w(2)); + yPML = domain.dx*((1:szPML(1))-domain.marg+pml_w(1)); + zPML = domain.dx*((1:szPML(3))-domain.marg+pml_w(3)); + [tmpY,tmpX,tmpZ] = meshgrid(xPML,yPML,zPML); + clear xPML yPML zPML + + arrSlope = curMask.arrTiltDegXY; + + if isfield(curMask,'zBaseMinTop') + zBase = curMask.zBaseMinTop+abs((maxX-curMask.arrBaseXYZ(1))*tan(arrSlope(1)*pi/180) + abs(maxY-curMask.arrBaseXYZ(2))*tan(arrSlope(2)*pi/180)); + curMask.arrBaseXYZ(3) = zBase; + end + arrBase = curMask.arrBaseXYZ; + + + tmpSel = tmpZ <= (arrBase(3)+(arrBase(1)-tmpX)*tan(arrSlope(1)*pi/180) + (arrBase(2)-tmpY)*tan(arrSlope(2)*pi/180)); + clear tmpZ tmpX tmpZ + + % mark masked region as air + M_pml(tmpSel) = 0; + + clear tmpSel; + end + end + + % copy the original container into the container with PMLs + M_pml(pml_w(1)+1:pml_w(1)+nx,pml_w(2)+1:pml_w(2)+ny,1:nz) = M; +% figure;imagesc(squeeze(M_pml(:,100,:)).');axis equal; + + if isfield(params,'PMLduplicate') + if params.PMLduplicate + % M_pml(1:pml_w,:,:) = repmat(M_pml(pml_w+1,:,:),[pml_w,1,1]); + % M_pml(pml_w+nx+1:end,:,:) = repmat(M_pml(pml_w+nx,:,:),[pml_w,1,1]); + % M_pml(:,1:pml_w,:) = repmat(M_pml(:,pml_w+1,:,:),[1,pml_w,1]); + % M_pml(:,pml_w+ny+1:end,:,:) = repmat(M_pml(:,pml_w+ny,:),[1,pml_w,1]); + % M_pml(:,:,nz+1:end)= repmat(M_pml(:,:,nz),[1,1,pml_w]); + kSelX = pml_w(1)+(1:nx); + kSelY = pml_w(2)+(1:ny); + M_pml(kSelX,kSelY,nz+1:end) = repmat(M_pml(kSelX,kSelY,nz),[1,1,pml_w(3)]); + end + end + + % create the HDF5 output container + % M5 = zeros(size(M_pml),'int16'); % all air + % M5(M_pml~=0) = 1; % mark matrix + % M5(M_pml==99) = 2; % mark water + % M5(M_pml==999) = 3; % mark PML + + M5 = zeros(size(M_pml),'int16'); % all air + M5(M_pml~=0) = 1; % mark matrix + M5(M_pml==params.ID_MASKED.Water.Lr) = params.ID_MASKED.Water.M5; % mark water + M5(M_pml==params.ID_MASKED.PML.Lr) = params.ID_MASKED.PML.M5; % mark PML + M5(M_pml==params.ID_MASKED.Target.Lr) = params.ID_MASKED.Target.M5; % mark Target + + if true + xScale = ((0:size(M5,1))-pml_w(1))*domain.dx; + yScale = ((0:size(M5,2))-pml_w(2))*domain.dx; + zScale = ((0:size(M5,3))-domain.marg)*domain.dx; + + hFigVerbose = figure('Name','hd5_preview'); + subplot(1,2,1); + imagesc(xScale,zScale,squeeze(M5(:,round(size(M5,2)/2),:)).'); + set(gca,'DataAspectRatio',[1 1 1],'YDir','normal'); + xlabel('x (m)'); + ylabel('z (m)'); + grid on; + + subplot(1,2,2); + imagesc(yScale,zScale,squeeze(M5(round(size(M5,1)/2),:,:)).'); + set(gca,'DataAspectRatio',[1 1 1],'YDir','normal'); + xlabel('y (m)'); + ylabel('z (m)'); + grid on; + savefig(hFigVerbose,fullfile(params.EXPORTpath,'hd5_exportPreview.fig')); + print(hFigVerbose,fullfile(params.EXPORTpath,'hd5_exportPreview.png'),'-dpng'); + end + + if isfield(params,'PMLtruncate') + if params.PMLtruncate + M5(:,:,nz+1:end) = []; + end + end + + [nx,ny,nz] = size(M5); + infostr1{1,1} = ['0 = Air (dk = ',sprintf('%6.4f',domain.dkSpeciesAIR),')']; + infostr1{2,1} = ['1 = Matrix (dk = ',sprintf('%6.4f',domain.dkSpeciesMTX),')']; + infostr1{3,1} = ['2 = H2O (dk = ',sprintf('%6.4f',domain.dkSpeciesH2O),')']; + + % calculate bulk dk for PML with CRIM + if isfield(domain,'final_vol') + dk_pml = getDK([domain.dkSpeciesAIR domain.dkSpeciesMTX domain.dkSpeciesH2O],... + [domain.final_vol.air domain.final_vol.mtx domain.final_vol.H2O]); + else + dk_pml = getDK([domain.dkSpeciesAIR domain.dkSpeciesMTX domain.dkSpeciesH2O],... + [domain.VolSpeciesAIR domain.VolSpeciesMTX domain.VolSpeciesH2O]); + end + params.dk_pml = dk_pml; + + infostr1{4,1} = ['3 = PML (dk = ',sprintf('%6.4f',dk_pml),')']; + if params.useTarget + infostr1{5,1} = ['4 = Target (dk = ',sprintf('%6.4f',dk_pml),')']; + end + + infostr2 = 'DIM inkl. PML'; + + % 19.04.22: replaced "nx-1" etc. with "nx" + % infostr3{1,1} = ['x ',sprintf('%3d',nx),' -> ',sprintf('%3d',nx-1),'*',... + % sprintf('%5.3f',domain.dx),' = ',sprintf('%4.2f',domain.dx*(nx-1)),'m']; + infostr3{1,1} = ['x ',sprintf('%3d',nx),' -> ',sprintf('%3d',nx),'*',... + sprintf('%5.3f',domain.dx),' = ',sprintf('%4.2f',domain.dx*(nx)),'m']; + infostr3{2,1} = ['y ',sprintf('%3d',ny),' -> ',sprintf('%3d',ny),'*',... + sprintf('%5.3f',domain.dx),' = ',sprintf('%4.2f',domain.dx*(ny)),'m']; + infostr3{3,1} = ['z ',sprintf('%3d',nz),' -> ',sprintf('%3d',nz),'*',... + sprintf('%5.3f',domain.dx),' = ',sprintf('%4.2f',domain.dx*(nz)),'m']; + else + % boundary + marg = domain.marg; + % container without boundaries except z+ + % uses Label matrix "Lr" for each radius bin + M = domain.final{1}.Lr(marg+1:end-marg,marg+1:end-marg,marg+1:end); + + % create the HDF5 output container + M5 = zeros(size(M),'int16'); % all air + M5(M~=0) = 1; % mark matrix + M5(M==99) = 2; % mark water + + if params.use_target + tdims = size(params.target); + + target = params.target; + target(target~=0) = 3; % mark target + % start point of target inside M (target ids always centered) + xstart = round(domain.marg + (domain.nx0-1-tdims(1))/2); + ystart = round(domain.marg + (domain.ny0-1-tdims(2))/2); + zstart = round(domain.marg + (domain.nz0-1-tdims(3))/2); + % place target into temp. M + M5(xstart:xstart+tdims(1)-1,ystart:ystart+tdims(2)-1,... + zstart:zstart+tdims(3)-1) = target; + end + + [nx,ny,nz] = size(M5); + infostr1{1,1} = ['0 = Air (dk = ',sprintf('%4.2f',domain.dkSpeciesAIR),')']; + infostr1{2,1} = ['1 = Matrix (dk = ',sprintf('%4.2f',domain.dkSpeciesMTX),')']; + infostr1{3,1} = ['2 = H2O (dk = ',sprintf('%4.2f',domain.dkSpeciesH2O),')']; + if params.use_target + infostr1{4,1} = ['3 = Target (dk = ',sprintf('%4.2f',domain.dkSpeciesAIR),')']; + end + + infostr2 = 'DIM'; + + infostr3{1,1} = ['x ',sprintf('%3d',nx),' -> ',sprintf('%3d',nx),'*',... + sprintf('%5.3f',domain.dx),' = ',sprintf('%4.2f',domain.dx*(nx)),'m']; + infostr3{2,1} = ['y ',sprintf('%3d',ny),' -> ',sprintf('%3d',ny),'*',... + sprintf('%5.3f',domain.dx),' = ',sprintf('%4.2f',domain.dx*(ny)),'m']; + infostr3{3,1} = ['z ',sprintf('%3d',nz),' -> ',sprintf('%3d',nz),'*',... + sprintf('%5.3f',domain.dx),' = ',sprintf('%4.2f',domain.dx*(nz)),'m']; + end + + params.arrDomainOut = domain.dx*size(M5); + + if length(domain.final) == 1 + % matrices without margin + Mp = domain.final{1}.Lr(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); + else + Mp = domain.final{2}.Lr; + end + + % calculate porosity (only of the interior box without any margin) + + ind0 = sum(Mp(:)==0); % air + ind99 = sum(Mp(:)==99); % water + % porosity = (ind0+ind99)/(numel(Mp)-domain.VOLmask); + porosity = (ind0+ind99)/(numel(domain.kEvalPoro)); + + if ~isfield(params,'boolPrelimExport') || ~params.boolPrelimExport + infostr4 = sprintf('Porosity = %4.3f%% (Aim: %4.3f%%)\n',porosity*100,domain.porosity*100); + infostr4 = [infostr4 sprintf('H2O = %4.3f%% (Aim: %4.3f%%)\n',100*[domain.final_vol.H2O,domain.VolSpeciesH2O])]; + infostr4 = [infostr4 sprintf('Matrix = %4.3f%% (Aim: %4.3f%%)\n',100*[domain.final_vol.mtx,domain.VolSpeciesMTX])]; + infostr4 = [infostr4 sprintf('Air = %4.3f%% (Aim: %4.3f%%)\n',100*[domain.final_vol.air,domain.VolSpeciesAIR])]; + + dk_AIM = getDK([domain.dkSpeciesAIR domain.dkSpeciesMTX domain.dkSpeciesH2O],... + [domain.VolSpeciesAIR domain.VolSpeciesMTX domain.VolSpeciesH2O]); + infostr4 = [infostr4 sprintf('\nDK = %6.4f (Aim: %6.4f)\n',params.dk_pml,dk_AIM)]; + else + infostr4 = 'prelim Export'; + end + + % export the HDF5 file + % flip z-direction + M5 = flip(M5,3); + % swap dimensions because gprMax is "weird" + M5 = permute(M5,[3 2 1]); + h5name = fullfile(params.EXPORTpath,params.save_h5); + dx = domain.dx*ones(1,3); + h5Title = 'GPRGRAVEL'; % should be changed + h5create(h5name,'/data',size(M5),'Datatype','int16'); + h5write(h5name,'/data',int16(M5)); + h5writeatt(h5name,'/','gprMax','3.1.5'); + h5writeatt(h5name,'/','Title',h5Title); + h5writeatt(h5name,'/','dx_dy_dz',dx); + fprintf('Created %s\n',h5name); + + % write corresponding info file + fileID = fopen(fullfile(params.EXPORTpath,[params.save_h5,'_INFO.txt']),'w'); + for i = 1:numel(infostr1) + fprintf(fileID,'%s\n',infostr1{i}); + end + fprintf(fileID,'\n'); + fprintf(fileID,'%s\n',infostr2); + fprintf(fileID,'\n'); + for i = 1:numel(infostr3) + fprintf(fileID,'%s\n',infostr3{i}); + end + fprintf(fileID,'\n'); + fprintf(fileID,'%s\n',infostr4); + fclose(fileID); + +end + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/getDK.m b/functions/getDK.m new file mode 100644 index 0000000..00cfb9a --- /dev/null +++ b/functions/getDK.m @@ -0,0 +1,62 @@ +function dk = getDK(dk_in,vol_in) +%getDK calculates dk values based on CRIM forumla +% +% Syntax: +% dk = getDK(dk_in,vol_in) +% +% Inputs: +% dk_in - vec (epsilon values of the species) +% vol_in - vec (volume fraction of the species) +% +% Outputs: +% dk +% +% Example: +% dk = getDK(dk_in,vol_in) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +dk = 0; +dblAlpha = 1/2; + +for i = 1:numel(dk_in) + dk = dk + (dk_in(i).^dblAlpha)*vol_in(i); +end + +dk = dk.^(1/dblAlpha); + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/getRotationMatrixFromAngleandAxis.m b/functions/getRotationMatrixFromAngleandAxis.m new file mode 100644 index 0000000..97700d2 --- /dev/null +++ b/functions/getRotationMatrixFromAngleandAxis.m @@ -0,0 +1,111 @@ +function R = getRotationMatrixFromAngleandAxis(phi,n) +%getRotationMatrixFromAngleandAxis calculates rotation matrix R to rotate about +%an axis n by an angle phi +% +% Syntax: +% getRotationMatrixFromAngleandAxis(phi,n) +% +% Inputs: +% phi - rotation angle [rad]; size Nx1 +% n - rotation axis vector [x y z]; size Nx3 +% +% Outputs: +% R - 3x3xN rotation matrix +% +% Example: +% R = getRotationMatrixFromAngleandAxis(pi,[0 0 1]') +% yields R = -1 0 0 +% 0 -1 0 +% 0 0 1 +% so that R*[1 0 0]' = [-1 0 0]' +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also: BLOCHUS +% Author: Thomas Hiller +% email: thomas.hiller[at]leibniz-liag.de +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% for only one axis-angle pair +if numel(phi) == 1 + % make "n" a unit vector + n = n./norm(n); + % get the individual components + nx = n(1); + ny = n(2); + nz = n(3); + % matrix terms needed + omcos = 1-cos(phi); + cosp = cos(phi); + sinp = sin(phi); + + % assemble rotation matrix R + R(1,1) = nx*nx*omcos + cosp; + R(1,2) = nx*ny*omcos - nz*sinp; + R(1,3) = nx*nz*omcos + ny*sinp; + + R(2,1) = ny*nx*omcos + nz*sinp; + R(2,2) = ny*ny*omcos + cosp; + R(2,3) = ny*nz*omcos - nx*sinp; + + R(3,1) = nz*nx*omcos - ny*sinp; + R(3,2) = nz*ny*omcos + nx*sinp; + R(3,3) = nz*nz*omcos + cosp; + +else % for multiple axes and angles + + % n should contain only unit vectors! + % get the individual components + nx = n(:,1); + ny = n(:,2); + nz = n(:,3); + % matrix terms needed + omcos = 1-cos(phi); + cosp = cos(phi); + sinp = sin(phi); + + % assemble rotation matrix R + R(1,1,:) = nx.*nx.*omcos + cosp; + R(1,2,:) = nx.*ny.*omcos - nz.*sinp; + R(1,3,:) = nx.*nz.*omcos + ny.*sinp; + + R(2,1,:) = ny.*nx.*omcos + nz.*sinp; + R(2,2,:) = ny.*ny.*omcos + cosp; + R(2,3,:) = ny.*nz.*omcos - nx.*sinp; + + R(3,1,:) = nz.*nx.*omcos - ny.*sinp; + R(3,2,:) = nz.*ny.*omcos + nx.*sinp; + R(3,3,:) = nz.*nz.*omcos + cosp; +end + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% BLOCHUS +% Copyright (C) 2019 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/getSubBodyCoords.m b/functions/getSubBodyCoords.m new file mode 100644 index 0000000..dd9c5bb --- /dev/null +++ b/functions/getSubBodyCoords.m @@ -0,0 +1,166 @@ +function [pos,block] = getSubBodyCoords(shape,aspect,r,dx,varargin) +%prepareDomain generates the domain data based on the user entries +% +% Syntax: +% prepareDomain +% +% Inputs: +% none +% +% Outputs: +% none +% +% Example: +% prepareDomain +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +use_orient = false; +if nargin > 4 + use_orient = true; + orient = varargin{1}; +end + +switch shape + case 'sphere' + + % radius in lattice units + r2 = ceil(r/dx); + % get the grid points inside the sphere of current size rbins(i) + [xi,yi,zi] = meshgrid(-r2:1:r2,-r2:1:r2,-r2:1:r2); + + dist = sqrt(xi.^2 + yi.^2 + zi.^2); + + if r == 1e-3 + pos = [0 0 0]; + in = false(size(dist)); + in(2,2,2) = true; + else + % if r<=0.02 + pos = [xi(dist<=r2) yi(dist<=r2) zi(dist<=r2)]; + in = dist<=r2; + % else + % pos = [xi(dist1 + block = false(size(xi)); + if use_orient + block(in) = true; + else + block(dist<=1) = true; + end +end + +return + +%% the original way +% % get the grid points inside the sphere of current size rbins(i) +% m = 0; +% sphere1 = zeros((2*r2+1)^3,3); +% for a = -r2:r2 +% for b = -r2:r2 +% for c = -r2:r2 +% dist = sqrt( a^2 + b^2 +c^2 ); +% if dx*dist <= r +% m = m+1; +% sphere1(m,:) = [a b c]; +% end +% end +% end +% end +% sphere1 = sphere1(1:m,:); +% nVol = m; + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/functions/interface/clearSingleAxis.m b/functions/interface/clearSingleAxis.m new file mode 100644 index 0000000..110ed42 --- /dev/null +++ b/functions/interface/clearSingleAxis.m @@ -0,0 +1,93 @@ +function clearSingleAxis(axh) +%clearSingleAxis clears an individual axis +% +% Syntax: +% clearSingleAxis(axh) +% +% Inputs: +% axh - axis handle +% +% Outputs: +% none +% +% Example: +% clearSingleAxis(gca) +% +% Other m-files required: +% clearSingleAxis +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI handle +fig = ancestor(axh,'figure','toplevel'); + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + % get GUI data + gui = getappdata(fig,'gui'); + + % get the parent of the axis and find possible legends + parent = get(axh,'Parent'); + lgh = findobj('Type','legend','Parent',parent); + if ~isempty(lgh) + delete(lgh); + end + + % look for specific tags and clear corresponding objects + ph = findall(axh,'Tag','MarkerLines'); + if ~isempty(ph); set(ph,'HandleVisibility','on'); end + + % clear the axis labels + xlabel(axh,''); + ylabel(axh,''); + zlabel(axh,''); + title(axh,' '); + + % reset axis limits and scale + grid(axh,'off'); + set(axh,'XLim',[0 1],'YLim',[0 1],'ZLim',[0 1]); + set(axh,'XTickMode','auto','XTickLabelMode','auto'); + set(axh,'YTickMode','auto','YTickLabelMode','auto'); + set(axh,'ZTickMode','auto','ZTickLabelMode','auto'); + set(axh,'XScale','lin','YScale','lin','ZScale','lin'); + set(axh,'FontSize',gui.myui.axfontsize); + + % clear the axis itself + cla(axh); + +else + warndlg({'clearSingleAxis:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/findParentOfType.m b/functions/interface/findParentOfType.m new file mode 100644 index 0000000..2ae3b1a --- /dev/null +++ b/functions/interface/findParentOfType.m @@ -0,0 +1,73 @@ +function ph = findParentOfType(h,type) +%findParentOfType is a "hack" because Matlab changed the parent-child +%hierarchy for some graphical objects +%2018: the minimize checkbox is a child of the uix.BoxPanel +%2014: the minimize checkbox is a child of a uicontainer -> child of a HBox -> +%child of a the BoxPanel +% +% Syntax: +% ph = findParentOfType(h,type) +% +% Inputs: +% h - handle +% type - type to look for +% +% Outputs: +% ph - handle of parent object +% +% Example: +% ph = findParentOfType(h,type) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +lookingfor = true; +child = h; +while lookingfor + parent = get(child,'Parent'); + if isa(parent,type) % the parent uix.BoxPanel was found + lookingfor = false; + ph = parent; + elseif isempty(parent) % nothing was found + ph = []; + disp('findParentOfType: No parent of specified type found.'); + break; + else % set the current parent to child and continue + child = parent; + end +end + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/minimizePanel.m b/functions/interface/minimizePanel.m new file mode 100644 index 0000000..2019881 --- /dev/null +++ b/functions/interface/minimizePanel.m @@ -0,0 +1,113 @@ +function minimizePanel(src,~) +%minimizePanel handles the minimization/maximization of all box-panels +% +% Syntax: +% minimizePanel(src) +% +% Inputs: +% src - handle of the calling object +% +% Outputs: +% none +% +% Example: +% minimizePanel(src) +% +% Other m-files required: +% findParentOfType +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI handle and data +fig = ancestor(src,'figure','toplevel'); +gui = getappdata(fig,'gui'); + +% get the corresponding box-panel to be minimized / maximized +panel = findParentOfType(src,'uix.BoxPanel'); +% panel title +paneltitle = get(panel,'Title'); +% check if panel is minimized (true) +isminimized = get(panel,'Minimized'); + +% minimized height (default value for all box-panels) +pheightmin = 22; +% default heights +def_heights = gui.myui.heights; + +if ~isempty(fig) && strcmp(get(fig,'Tag'),'GPRGRAVEL') + + panel_1 = 'Grains'; + panel_2 = 'Domain'; + panel_3 = 'Parameter'; + + 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.panels.main,'Heights'); + % default height of this panel + pheight = def_heights(2,id); + if isminimized % maximize panel + heights(id) = pheight; + set(gui.panels.main,'Heights',heights); + set(panel,'Minimized',false); + else % minimize panel + heights(id) = pheightmin; + set(gui.panels.main,'Heights',heights); + set(panel,'Minimized',true) + end + onFigureSizeChange(fig); + otherwise + helpdlg({'function: minimizePanel',... + 'Something is utterly wrong.'},'Info'); + end +else + warndlg({'minimizePanel:','There is no figure with the GPRGRAVEL Tag open.'},... + 'GPRGRAVEL error'); +end +% update GUI data +setappdata(fig,'gui',gui); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/onFigureSizeChange.m b/functions/interface/onFigureSizeChange.m new file mode 100644 index 0000000..e0ed45f --- /dev/null +++ b/functions/interface/onFigureSizeChange.m @@ -0,0 +1,67 @@ +function onFigureSizeChange(fig,~) +%onFigureSizeChange fixes an ugly Matlab bug when resizing a box-panel +%which holds an axis and a legend. This problem occurs even though the +%axis is inside a uicontainer to group all axes elements. And it only +%occurs for box-panels. If the uicontainer, which holds axis and legend, +%is inside a tab-panel this problem does not occur. They had one job ... m( +% +% Syntax: +% onFigureSizeChange(fig,~) +% +% Inputs: +% fig - handle of the calling figure +% +% Outputs: +% none +% +% Example: +% onFigureSizeChange(h) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% get GUI data +gui = getappdata(fig,'gui'); + +% proceed if there is data +if ~isempty(gui) + if isfield(gui,'panels') + heights = get(gui.panels.main,'Heights'); + set(gui.left,'Heights',-1,'MinimumHeights',sum(heights)+1); + end +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/plotDomaindata.m b/functions/interface/plotDomaindata.m new file mode 100644 index 0000000..19dccde --- /dev/null +++ b/functions/interface/plotDomaindata.m @@ -0,0 +1,121 @@ +function plotDomaindata(fig) +%plotDomaindata plots all relevant domain data +% +% Syntax: +% plotDomaindata(fig) +% +% Inputs: +% fig - figure handle +% +% Outputs: +% none +% +% Example: +% plotDomaindata(fig) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI data +data = getappdata(fig,'data'); +gui = getappdata(fig,'gui'); +grains = data.grains; +domain = data.domain; +params = data.params; + +% get axes +ax = gui.axes_handles.domain; +clearSingleAxis(ax); +hold(ax,'on'); + +xmin = 0; +ymin = 0; +zmin = 0; +xmax = domain.xm; +ymax = domain.ym; +zmax = domain.zm; + +if params.useTarget + axes(ax); + ix = params.targetIDX.*domain.dx; + plot3(ix(:,1),ix(:,2),ix(:,3),'k.','Parent',ax); +end + +% if the surface dips, take care of it +zBase = zmin+[(xmax-xmin)*tand(params.maskdipx(1)) ... + (ymax-ymin)*tand(params.maskdipy(1))]; + +% planes parallel to x +xplane1 = [xmin ymin zBase(1)+zBase(2); xmax ymin zBase(2); xmax ymin zmax; xmin ymin zmax]; +xplane2 = [xmin ymax zBase(1); xmax ymax zmin; xmax ymax zmax; xmin ymax zmax]; +% planes parallel to y +yplane1 = [xmin ymin zBase(1)+zBase(2); xmin ymax zBase(1); xmin ymax zmax; xmin ymin zmax]; +yplane2 = [xmax ymin zBase(2); xmax ymax zmin; xmax ymax zmax; xmax ymin zmax]; +% planes parallel to z +zplane1 = [xmin ymin zBase(1)+zBase(2); xmax ymin zBase(2); xmax ymax zmin; xmin ymax zBase(1)]; +zplane2 = [xmin ymin zmax; xmax ymin zmax; xmax ymax zmax; xmin ymax zmax]; + +% plot the planes +V = [xplane1;xplane2;yplane1;yplane2;zplane1;zplane2]; +F = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16; 17 18 19 20; 21 22 23 24]; +ph = patch('Faces',F,'Vertices',V,'Parent',ax); +ph.FaceAlpha = 0.5; +ph.FaceColor = gui.myui.color.domain; + +% plot the center axes +plot3([xmin xmax],[(ymax-ymin)/2 (ymax-ymin)/2],[(zmax-zmin)/2 (zmax-zmin)/2],... + 'Color','r','Parent',ax); +plot3([(xmax-xmin)/2 (xmax-xmin)/2],[ymin ymax],[(zmax-zmin)/2 (zmax-zmin)/2],... + 'Color','g','Parent',ax); +plot3([(xmax-xmin)/2 (xmax-xmin)/2],[(ymax-ymin)/2 (ymax-ymin)/2],[zmin zmax],... + 'Color','b','Parent',ax); + +if isfield(grains,'rmax') + dx = grains.rmax; +else + dx = 0.05; +end +set(ax,'XLim',[xmin-dx xmax+dx],'XTick',linspace(xmin,xmax,3),... + 'YLim',[ymin-dx ymax+dx],'YTick',linspace(ymin,ymax,3),...... + 'ZLim',[zmin-dx zmax+dx],'ZTick',linspace(zmin,zmax,3)); +set(ax,'XTickLabelMode','auto','YTickLabelMode','auto','ZTickLabelMode','auto'); +set(ax,'ZDir','reverse'); +set(get(ax,'XLabel'),'String','x [m]'); +set(get(ax,'YLabel'),'String','y [m]'); +set(get(ax,'ZLabel'),'String','z [m]'); +set(ax,'FontSize',gui.myui.axfontsize); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/plotGSDdata.m b/functions/interface/plotGSDdata.m new file mode 100644 index 0000000..206ab35 --- /dev/null +++ b/functions/interface/plotGSDdata.m @@ -0,0 +1,123 @@ +function plotGSDdata(fig,type) +%plotGSDdata plots the GSD data +% +% Syntax: +% plotGSDdata(fig,type) +% +% Inputs: +% fig - figure handle +% type - string ('input' or 'output') +% +% Outputs: +% none +% +% Example: +% plotGSDdata(fig,'input') +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI data +data = getappdata(fig,'data'); +gui = getappdata(fig,'gui'); +grains = data.grains; +domain = data.domain; + +switch type + + case 'input' + + ax = gui.axes_handles.histIn; + clearSingleAxis(ax); + hold(ax,'on'); + + if grains.ishistogram + plot(grains.hist_raw(:,1),grains.hist_raw(:,2),'Color',gui.myui.color.grains,'Parent',ax); + else + % create tmporary bins for plotting + % dbins = domain.dx:domain.dx:grains.rmax*2; + dbins = logspace(-5,0,50); + % radius binning vector + rbins = dbins/2; + % --- account for new Matlab behaviour of histogram vs hist + d = diff(dbins)/2; + edges = [dbins(1)-d(1), dbins(1:end-1)+d, dbins(end)+d(end)]; + edges(2:end) = edges(2:end)+eps(edges(2:end)); + N = histcounts(grains.dia_raw,edges,'Normalization','cdf'); + plot(rbins,N,'Color',gui.myui.color.grains,'Parent',ax); + end + + if isfield(grains,'rbins') + line(grains.rbins,cumsum(grains.nvoxBins)/sum(grains.nvoxBins),... + 'marker','+','Color','k','LineStyle','none','Parent',ax); + end + + % plot a line at rmax + plot([grains.rmax grains.rmax],[0 1],'k--','Parent',ax); + text(grains.rmax*2,0.35,['r_{max}=',sprintf('%4.3f',grains.rmax),'m'],'Rotation',90,'FontSize',12,... + 'FontWeight','demi','Parent',ax); + + % axes settings + set(ax,'XLim',[5e-6 1],'XTick',logspace(-5,0,6),'XScale','log'); + % set(ax,'XLim',[0 grains.rmax],'XTick',linspace(0,grains.rmax,6),'XScale','lin'); + set(get(ax,'XLabel'),'String','Radius [m]'); + set(get(ax,'YLabel'),'String','CDF [-]'); + set(ax,'FontSize',gui.myui.axfontsize); + hold(ax,'off'); + + case 'monitor' + % get axes + ax = gui.axes_handles.histOut; + clearSingleAxis(ax); + hold(ax,'on'); + + % get monitor data + monitor = data.monitor; + + plot(monitor.voxHist(1,:),cumsum(grains.nvoxBins)./domain.VOL0matrix,... + 'Color',gui.myui.color.grains,'Parent',ax); + plot(monitor.voxHist(1,:),(domain.VOL0matrix-monitor.voxHist(2,:))./domain.VOL0matrix,... + 'Marker','+','Color','k','LineStyle','none','Parent',ax); + + % axes settings + set(ax,'XLim',[5e-6 1],'XTick',logspace(-5,0,6),'XScale','log'); + % set(ax,'XLim',[0 grains.rmax],'XTick',linspace(0,grains.rmax,6),'XScale','lin'); + set(get(ax,'XLabel'),'String','Radius [m]'); + set(get(ax,'YLabel'),'String','CDF [-]'); + set(ax,'FontSize',gui.myui.axfontsize); + hold(ax,'off'); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/plotMatrixdata.m b/functions/interface/plotMatrixdata.m new file mode 100644 index 0000000..cc490e9 --- /dev/null +++ b/functions/interface/plotMatrixdata.m @@ -0,0 +1,134 @@ +function plotMatrixdata(fig,type) +%plotMatrixdata plots the Matrix data +% +% Syntax: +% plotMatrixdata(fig,type) +% +% Inputs: +% fig - figure handle +% type - string ('input' or 'output') +% +% Outputs: +% none +% +% Example: +% plotMatrixdata(fig,'input') +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI data +data = getappdata(fig,'data'); +gui = getappdata(fig,'gui'); +grains = data.grains; +domain = data.domain; + +switch type + case 'monitor' + % get axis + ax = gui.axes_handles.Volume; + clearSingleAxis(ax); + hold(ax,'on'); + + % get monitor data + monitor = data.monitor; + Lr = monitor.Lr; + Lr(Lr==0) = NaN; + Lr(Lr==9999) = NaN; + + % prepare slices + szL = size(Lr); + + % real coordinates + x = 0:domain.dx:domain.xm; + y = 0:domain.dx:domain.ym; + z = 0:domain.dx:domain.zm; + + % how many margin voxel + mx = szL(1)-numel(x); + my = szL(2)-numel(y); + mz = szL(3)-numel(z); + + % coordinates without margin + xx = -(mx/2*domain.dx):domain.dx:domain.xm+(mx/2*domain.dx); + yy = -(my/2*domain.dx):domain.dx:domain.ym+(my/2*domain.dx); + if mod(mz,2)==0 + zz = -(mz/2*domain.dx):domain.dx:domain.zm+(mz/2*domain.dx); + else + zz = -(floor(mz/2)*domain.dx):domain.dx:domain.zm+(ceil(mz/2)*domain.dx); + end + + % get the 3D grid coordinates + [XXX,YYY,ZZZ] = meshgrid(xx,yy,zz); + + % define the center slices + xslice = xx(ceil(numel(xx)/2)); + yslice = yy(ceil(numel(yy)/2)); + zslice = zz(ceil(numel(zz)/2)); + + % swap xy dimensions + Lr = permute(Lr,[2 1 3]); + % plot the slices + try + slice(XXX,YYY,ZZZ,Lr,xslice,yslice,zslice,'Parent',ax); + catch + disp('plotMatrixdata: No data yet to plot on slice(s).') + end + + % colors + cmap = flipud(copper(numel(grains.rbins))); + cmap = [cmap;0 0 1]; + set(ax,'Colormap',cmap); + set(ax,'CLim',[1e-4 max(grains.rbins)*1.1]); + + % axis properties + rmax = grains.rmax; + axis(ax,'equal'); + shading(ax,'flat'); + set(ax,'XLim',[x(1)-rmax x(end)+rmax],'XTick',linspace(x(1),x(end),3),... + 'YLim',[y(1)-rmax y(end)+rmax],'YTick',linspace(y(1),y(end),3),... + 'ZLim',[z(1)-rmax z(end)+rmax],'ZTick',linspace(z(1),z(end),3)); + set(get(ax,'XLabel'),'String','x [m]'); + set(get(ax,'YLabel'),'String','y [m]'); + set(get(ax,'ZLabel'),'String','z [m]'); + set(ax,'ZDir','reverse'); + set(ax,'FontSize',gui.myui.axfontsize); + hold(ax,'off'); + + case 'result' + + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/plotProfiledata.m b/functions/interface/plotProfiledata.m new file mode 100644 index 0000000..07778f1 --- /dev/null +++ b/functions/interface/plotProfiledata.m @@ -0,0 +1,150 @@ +function plotProfiledata(fig) +%plotProfiledata plots the resulting porosity profile(s) in the profile +%panel +% +% Syntax: +% plotProfiledata(fig,tag) +% +% Inputs: +% fig - figure handle +% +% Outputs: +% none +% +% Example: +% plotProfiledata(fig) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI data +data = getappdata(fig,'data'); +gui = getappdata(fig,'gui'); +domain = data.domain; + +% get axes +ax1 = gui.axes_handles.ProfileAir; +clearSingleAxis(ax1); +hold(ax1,'on'); +ax2 = gui.axes_handles.ProfileH2O; +clearSingleAxis(ax2); +hold(ax2,'on'); + +%% porosity (only air voxel -> M=0) +M = domain.final{2}.M; +% flip upside down because 0 is at surface +M = flip(M,3); + +sz = size(M); +% sum the corresponding air voxel in each dimension +px = 1-squeeze(sum(sum(M,2),3)/sz(2)/sz(3)); +py = 1-squeeze(sum(sum(M,1),3)/sz(1)/sz(3)); +pz = 1-squeeze(sum(sum(M,1),2)/sz(1)/sz(2)); +% the distance vectors +x = 1:1:sz(1); +y = 1:1:sz(2); +z = 1:1:sz(3); +% plot data +plot(px,x./sz(1),'r','DisplayName','yz-slice','Parent',ax1); +plot(py,y./sz(2),'g','DisplayName','xz-slice','Parent',ax1); +plot(pz,z./sz(3),'b','DisplayName','xy-slice','Parent',ax1); + +% add a line for each mean value +plot([mean(px) mean(px)],[0 1],'r.','HandleVisibility','off',... + 'Tag','MarkerLines','Parent',ax1); +plot([mean(py) mean(py)],[0 1],'g:','HandleVisibility','off',... + 'Tag','MarkerLines','Parent',ax1); +plot([mean(pz) mean(pz)],[0 1],'b--','HandleVisibility','off',... + 'Tag','MarkerLines','Parent',ax1); + +% set axis properties +set(ax1,'XLim',[0 max([px(:);py(:);pz(:)])]*1.1,'XTickMode','auto',... + 'XTickLabelMode','auto'); +set(ax1,'YLim',[0 1],'YTick',0:0.2:1,... + 'YTickLabel',{'0 (bot)','0.2','0.4','0.6','0.8','1 (top)'}); +set(get(ax1,'XLabel'),'String','air volume [-]'); +set(get(ax1,'YLabel'),'String','normalized domain dimension'); +set(get(ax1,'Title'),'String',['mean \Phi=',sprintf('%6.4f',mean(px))]); +set(ax1,'FontSize',gui.myui.axfontsize); +hold(ax1,'off'); +legend(ax1,'Location','best'); + +%% porosity (only water voxel -> Lr=99) +M = zeros(size(domain.final{2}.Lr)); +% flip upside down because 0 is at surface +M(domain.final{2}.Lr==99) = 1; +M = flip(M,3); +sz = size(M); +% sum the corresponding water voxel in each dimension +px = squeeze(sum(sum(M,2),3)/sz(2)/sz(3)); +py = squeeze(sum(sum(M,1),3)/sz(1)/sz(3)); +pz = squeeze(sum(sum(M,1),2)/sz(1)/sz(2)); +% the distance vectors +x = 1:1:sz(1); +y = 1:1:sz(2); +z = 1:1:sz(3); + +% get maximum water content for axis limits +max_w = max([px(:);py(:);pz(:)]); +if max_w == 0 + xlims = [-1 1]; +else + xlims = [0 max_w*1.1]; +end + +% plot data +plot(px,x./sz(1),'r','DisplayName','yz-slice','Parent',ax2); +plot(py,y./sz(2),'g','DisplayName','xz-slice','Parent',ax2); +plot(pz,z./sz(3),'b','DisplayName','xy-slice','Parent',ax2); + +% add a line for each mean value +plot([mean(px) mean(px)],[0 1],'r.','HandleVisibility','off',... + 'Tag','MarkerLines','Parent',ax2); +plot([mean(py) mean(py)],[0 1],'g:','HandleVisibility','off',... + 'Tag','MarkerLines','Parent',ax2); +plot([mean(pz) mean(pz)],[0 1],'b--','HandleVisibility','off',... + 'Tag','MarkerLines','Parent',ax2); + +% set axis properties +set(ax2,'XLim',xlims,'XTickMode','auto','XTickLabelMode','auto'); +set(ax2,'YLim',[0 1],'YTick',0:0.2:1,... + 'YTickLabel',{'0 (bot)','0.2','0.4','0.6','0.8','1 (top)'}); +set(get(ax2,'XLabel'),'String','water volume [-]'); +set(get(ax2,'Title'),'String',['mean \Theta=',sprintf('%6.4f',mean(px))]); +set(ax2,'FontSize',gui.myui.axfontsize); +hold(ax2,'off'); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/plotSlicedata.m b/functions/interface/plotSlicedata.m new file mode 100644 index 0000000..4b92bce --- /dev/null +++ b/functions/interface/plotSlicedata.m @@ -0,0 +1,145 @@ +function plotSlicedata(fig,tag,val) +%plotSlicedata plots the resulting gravel "packing" in the slice panel +% +% Syntax: +% plotSlicedata(fig) +% +% Inputs: +% fig - figure handle +% tag - slice view +% val - slice step +% +% Outputs: +% none +% +% Example: +% plotSlicedata(fig) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI data +data = getappdata(fig,'data'); +gui = getappdata(fig,'gui'); +grains = data.grains; +domain = data.domain; + +% get axes +ax = gui.axes_handles.Slice; +clearSingleAxis(ax); +hold(ax,'on'); + +% get final data +Lr = domain.final{1}.Lr; +% remove air +Lr(Lr==0) = NaN; +% remove target +Lr(Lr==9999) = NaN; + +marg = domain.marg; + +% prepare slices +szL = size(Lr); + +x = 0:domain.dx:domain.xm; +y = 0:domain.dx:domain.ym; +z = 0:domain.dx:domain.zm; + +mx = szL(1)-numel(x); +my = szL(2)-numel(y); +mz = szL(3)-numel(z); + +xx = -(mx/2*domain.dx):domain.dx:domain.xm+(mx/2*domain.dx); +yy = -(my/2*domain.dx):domain.dx:domain.ym+(my/2*domain.dx); +if mod(mz,2)==0 + zz = -(mz/2*domain.dx):domain.dx:domain.zm+(mz/2*domain.dx); +else + zz = -(floor(mz/2)*domain.dx):domain.dx:domain.zm+(ceil(mz/2)*domain.dx); +end + +rmax = grains.rmax; +switch tag + case 'XZ' + [XX,YY] = meshgrid(xx,zz); + S = squeeze(Lr(:,marg+val,:)); + xlims = [x(1)-rmax x(end)+rmax]; + xticks = linspace(x(1),x(end),3); + ylims = [z(1)-rmax z(end)+rmax]; + yticks = linspace(z(1),z(end),3); + xlabel = 'x [m]'; + ylabel = 'z [m]'; + ydir = 'reverse'; + case 'YZ' + [XX,YY] = meshgrid(yy,zz); + S = squeeze(Lr(marg+val,:,:)); + xlims = [y(1)-rmax y(end)+rmax]; + xticks = linspace(y(1),y(end),3); + ylims = [z(1)-rmax z(end)+rmax]; + yticks = linspace(z(1),z(end),3); + xlabel = 'y [m]'; + ylabel = 'z [m]'; + ydir = 'reverse'; + case 'XY' + [XX,YY] = meshgrid(xx,yy); + S = squeeze(Lr(:,:,marg+val)); + xlims = [x(1)-rmax x(end)+rmax]; + xticks = linspace(x(1),x(end),3); + ylims = [y(1)-rmax y(end)+rmax]; + yticks = linspace(y(1),y(end),3); + xlabel = 'x [m]'; + ylabel = 'y [m]'; + ydir = 'normal'; +end + +pcolor(XX,YY,S','Parent',ax); + +% colors +cmap = flipud(copper(numel(grains.rbins))); +cmap = [cmap;0 0 1]; +set(ax,'Colormap',cmap); +set(ax,'CLim',[1e-4 max(grains.rbins)*1.1]); +axis(ax,'equal'); +shading(ax,'flat'); +% axes settings +set(ax,'XLim',xlims,'XTick',xticks,'YLim',ylims,'YTick',yticks,'YDir',ydir); +set(get(ax,'XLabel'),'String',xlabel,'FontSize',gui.myui.axfontsize); +set(get(ax,'YLabel'),'String',ylabel,'FontSize',gui.myui.axfontsize); +set(get(ax,'Title'),'String',['slice: ',sprintf('%4.3f',(val-1)*domain.dx),'m'],... + 'FontSize',gui.myui.axfontsize); +set(ax,'FontSize',gui.myui.axfontsize); +hold(ax,'off'); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/setTargetPosition.m b/functions/interface/setTargetPosition.m new file mode 100644 index 0000000..c41b21f --- /dev/null +++ b/functions/interface/setTargetPosition.m @@ -0,0 +1,110 @@ +function [data] = setTargetPosition(data) +%setTargetPosition changes the target position within the domain +% +% Syntax: +% [data] = setTargetPosition(data) +% +% Inputs: +% data - GUI data struct +% +% Outputs: +% data - GUI data struct +% +% Example: +% [data] = setTargetPosition(data) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +domain = data.domain; +params = data.params; + +centOld = params.targetCenterOld; +centNew = params.targetCenter; +% shift vector in real units +shift = centNew-centOld; +% shift vector in voxel units +shiftvox = round(shift./domain.dx); + +params.targetIDX(:,1) = params.targetIDX(:,1)+shiftvox(1); +params.targetIDX(:,2) = params.targetIDX(:,2)+shiftvox(2); +params.targetIDX(:,3) = params.targetIDX(:,3)+shiftvox(3); + +% now rotate the polar angle around the x-axis +phi0 = deg2rad(params.targetOrientOld(1)); +phi1 = deg2rad(params.targetOrient(1)); +if phi0~=phi1 + R0 = getRotationMatrixFromAngleandAxis(-phi0,[0 1 0]); + R1 = getRotationMatrixFromAngleandAxis(phi1,[0 1 0]); + for i1 = 1:numel(params.target) + tmp = [params.targetIDX(i1,1) params.targetIDX(i1,2) params.targetIDX(i1,3)]'; + % move to center + tmp = tmp-centNew'./domain.dx; + % rotate + tmp = R0*tmp; % old angle back + tmp = R1*tmp; % new angle + % move back + tmp = round(tmp+centNew'./domain.dx); + params.targetIDX(i1,1) = tmp(1); + params.targetIDX(i1,2) = tmp(2); + params.targetIDX(i1,3) = tmp(3); + end +end + +% now rotate the azimuthal angle around the z-axis +theta0 = deg2rad(params.targetOrientOld(2)); +theta1 = deg2rad(params.targetOrient(2)); +if theta0~=theta1 + R0 = getRotationMatrixFromAngleandAxis(-theta0,[0 0 1]); + R1 = getRotationMatrixFromAngleandAxis(theta1,[0 0 1]); + for i1 = 1:numel(params.target) + tmp = [params.targetIDX(i1,1) params.targetIDX(i1,2) params.targetIDX(i1,3)]'; + % move to center + tmp = tmp-centNew'./domain.dx; + % rotate + tmp = R0*tmp; % old angle back + tmp = R1*tmp; % new angle + % move back + tmp = round(tmp+centNew'./domain.dx); + params.targetIDX(i1,1) = tmp(1); + params.targetIDX(i1,2) = tmp(2); + params.targetIDX(i1,3) = tmp(3); + end +end + +data.params = params; + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/interface/showLogInfo.m b/functions/interface/showLogInfo.m new file mode 100644 index 0000000..7907942 --- /dev/null +++ b/functions/interface/showLogInfo.m @@ -0,0 +1,62 @@ +function showLogInfo(str,isgui,gui) +%showLogInfo plots the info either to the GUI or to the commandline +% +% Syntax: +% showLogInfo(str,isgui,gui) +% +% Inputs: +% str - info str +% isgui - bool (true | false) +% gui - gui handle +% +% Outputs: +% none +% +% Example: +% showLogInfo(str,isgui,gui) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +if isgui + set(gui.listbox_handles.info,'String', str); + set(gui.listbox_handles.info,'Value',size(get(gui.listbox_handles.info,'String'),1)) +else + disp(str); +end +pause(0.001); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/functions/interface/updateStatusInformation.m b/functions/interface/updateStatusInformation.m new file mode 100644 index 0000000..7c52af5 --- /dev/null +++ b/functions/interface/updateStatusInformation.m @@ -0,0 +1,91 @@ +function updateStatusInformation(fig) +%updateStatusInformation updates all fields inside the bottom status bar +% +% Syntax: +% updateStatusInformation(fig) +% +% Inputs: +% fig - figure handle +% +% Outputs: +% none +% +% Example: +% updateStatusInformation(fig) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% get GUI data +data = getappdata(fig,'data'); +gui = getappdata(fig,'gui'); + +set(gui.text_handles.TimerStat,'String',['Calc. Time: ',sprintf('%5.3f',data.info.Timer),'s']); + +switch get(gui.radio_handles.closedSurface,'Value') + case 1 + set(gui.text_handles.Surface,'String','SURFACE: CLOSED'); + case 0 + set(gui.text_handles.Surface,'String','SURFACE: OPEN'); +end + +if data.params.useTarget + set(gui.text_handles.Targets,'String','TARGETS: ON'); +else + set(gui.text_handles.Targets,'String','TARGETS: OFF'); +end + +if data.params.useSatProfile + str = get(gui.popup_handles.SatProfileType,'String'); + val = get(gui.popup_handles.SatProfileType,'Value'); + set(gui.text_handles.SatProf,'String',['SATURATION Profile: ',str{val}(1:3)]); +else + set(gui.text_handles.SatProf,'String','SATURATION Profile: OFF'); +end + +% switch data.info.ToolTips +% case 1 +% set(gui.text_handles.TooltipsStat,'String','Tooltips: ON'); +% case 0 +% set(gui.text_handles.TooltipsStat,'String','Tooltips: OFF'); +% end + +set(gui.text_handles.VersionStat,'String',['Version: ',gui.myui.version]); + +% Matlab takes some time +pause(0.001); + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/placeGrains.m b/functions/placeGrains.m new file mode 100644 index 0000000..f8bd43d --- /dev/null +++ b/functions/placeGrains.m @@ -0,0 +1,586 @@ +function [domain,grains,params] = placeGrains(domain,grains,params,monitor,varargin) +%placeGrains places all grains within the domain +% +% Syntax: +% [domain,grains] = placeGrains(domain,grains,params,monitor) +% +% Inputs: +% domain +% grains +% params +% monitor +% varargin +% +% Outputs: +% domain +% grains +% params +% +% Example: +% [domain,grains] = placeGrains(domain,grains,params,monitor,src) +% +% Other m-files required: +% getSubBodyCoords +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% check if called from GUI +isgui = false; +if nargin > 4 + src = varargin{1}; + % get GUI handle + fig = ancestor(src,'figure','toplevel'); + isgui = true; + % get GUI data + gui = getappdata(fig,'gui'); +else + gui = 0; +end + +%% INITIALIZE +tic; + +% init the RNG +if params.use_customRNG + rng(params.customRNGSEED) +else + s = rng(); + params.customRNGstate = s; +end + +% reset/empty log field before caluclation +monitor.log = ''; + +% global statistics counters +monitor.stat = [0 0 0 0]; +monitor.threshMaxTry = 2e6; % until 31.01.22 +monitor.nVoxAim = flip(cumsum(flip(grains.nvoxBins))); +monitor.poro_final = domain.VolSpeciesAIR+domain.VolSpeciesH2O; +monitor.domainVOL0 = domain.VOL0; +monitor.domainVOL0matrix = domain.VOL0matrix; + +% get the matrices with the margin +M = domain.final{1}.M; +M_valCtr = domain.final{1}.M_valCtr; +if ~params.boolOmitLn + L1 = domain.final{1}.Ln; +end +L2 = domain.final{1}.Lr; +szM = size(M); + +% margin width +marg = domain.marg; + +% get the coordinate lists +if isfield(domain,'xyzr0') + xyzr0 = domain.xyzr0; + monitor.nxyzr0 = size(xyzr0,1); +end + +monitor.n = find(domain.xyzr0(:,end)>0,1,'last'); +if isempty(monitor.n) + monitor.n = 0; +end +monitor.n = monitor.n+1; +n_start = monitor.n; +if size(xyzr0,1) >= monitor.n + if xyzr0(monitor.n,4) < 0 + monitor.n = n_start+1; + n_start = monitor.n; + end +end + +% open surface switch and threshold radius +closeSurface = params.closeSurface; +closeSurfaceR = params.closeSurfaceR; + +por_RequireTouch = 0.6; +r_RequireTouch = 0; +if isfield(params,'requireTouch') + if isfield(params.requireTouch,'r') + r_RequireTouch = params.requireTouch.r; + por_RequireTouch = 1e-6; + elseif isfield(params.requireTouch,'por') + r_RequireTouch = 0; + por_RequireTouch = params.requireTouch.por; + end + + if isfield(params.requireTouch,'nVox') + monitor.nMinTouch = min([0 params.requireTouch.nVox-1]); + else + monitor.nMinTouch = 0; + end +end + +monitor.nSwapListBoxMax = 1e2; +monitor.threshSwapListBox = 1e3; % swap after these number of successive failures +if isfield(params,'nSwapListBoxMax') + monitor.nSwapListBoxMax = params.nSwapListBoxMax; +end +if isfield(params,'threshSwapListBox') + monitor.threshSwapListBox = params.threshSwapListBox; +end + + +if params.useTarget +% domain.target_MargBox = params.target_MargBox; +end +monitor.binStat = zeros(4,length(grains.rbins)); +monitor.voxHist = zeros(3,length(grains.rbins)); +monitor.voxHist(1,:) = grains.rbins; +monitor.voxHist(3,:) = monitor.nVoxAim; + +% plotting during calculation +% plotting = init_plotting(domain,grains,monitor); +% plotting.threshMaxTry = monitor.threshMaxTry; +% plotting.HullHist = cat(1,linspace(0,1,51),zeros(1,51)); +% plotting.HullLims = [0 0]; + +monitor.boolMustTouch = false; + +% run backwards to start with the largest grains +nBin = numel(grains.rbins); +monitor.threshMaxTry = 2e6; % until 31.01.22 + +% update list of vacant voxels as soon as +% failed attempt counter reaches 10% +nMod_UpdateIndexList = 10*round(monitor.threshMaxTry/(100*10)); + +if isfield(grains,'nVox') + monitor.nVox = grains.nVox; +else + monitor.nVox = [0 0]; +end + +if isfield(grains,'iBin') + iBinStart = grains.iBin; +else + iBinStart = nBin; +end + +monitor.arrPackVel = zeros(2,2); +monitor.arrPackVel(2,:) = [toc monitor.nVox(1)]; +monitor.velPackMax = 0; + +monitor.por_cur = 1-monitor.nVox(1)/domain.VOL0; + +if isfield(domain,'plotting') + plotting = domain.plotting; +end + +monitor.log = [monitor.log sprintf('%s: Switching to tight placement of grains.\n',datestr(now,'dd.mm.yy HH:MM'))]; +grains.nLastFreely = monitor.n-1; + +% count swapping between +% - list-based drawing(to ensure touch) +% - box-based (to ensure free positions) +% +iSwapListBox = 0; +% define max. number of swaps + +boolUpdateBoxList = false; +boolDrawFromGrainList = false; + + +monitor.nLstVox = 0; +monitor.iRandPos = 1; +monitor.nRandPos = 1; + +cc = 0; +%% GRAIN PLACEMENT STARTS +for i = iBinStart:-1:1 + cc = cc + 1; + % reset failure statistics + monitor.arrFailStat = zeros(1,3); + % current radius of sphere in [m] + r = grains.rbins(i); + monitor.rbin = r; + + % info output + str1 = ['RUN - placeGrains: bin class: ',sprintf('%d / %d',cc,numel(grains.rbins))]; + monitor.log = [monitor.log newline sprintf('%s: Init radius bin #%d (r=%6.4f m)\n',datestr(now,'dd.mm.yy HH:MM'),i,r)]; + + if isgui + set(gui.text_handles.Status,'String', str1); + else + disp(str1); + end + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + + if monitor.nVoxAim(i) == 0 + % skip bin if empty + monitor.log = [monitor.log sprintf('%s: bin is empty. Skipping.\n',datestr(now,'dd.mm.yy HH:MM'))]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + break; + end + + monitor.binStat(4,i) = max([monitor.binStat(4,i) monitor.stat(4)]); + monitor.voxHist(2,1:i) = monitor.nVox(1); +% plotting = update_PackingMonitor(M,L2,plotting,monitor); + + switch grains.shape + case 'sphere' + % the actual grain + sphere = getSubBodyCoords(grains.shape,[1 1 1],r,domain.dx); + % a grain that is one lattice unit larger + sphereB = getSubBodyCoords(grains.shape,[1 1 1],r+domain.dx,domain.dx); + case 'ellipse' + % here one can randomize the size of the ellipses + grains.axes = grains.axes./max(grains.axes); + a = grains.axes(1);%0.4 + (1-0.4).*rand(1); + b = grains.axes(2);%0.4 + (1-0.4).*rand(1); + c = grains.axes(3);%0.4 + (1-0.4).*rand(1); + % here one can ranomize the orientation (per radius bin) + orient = grains.orient; % grains.orient(1) = randi([20 60]); + sphere = getSubBodyCoords(grains.shape,[a b c],r,domain.dx,orient); + % a grain that is one lattice unit larger + sphereB = getSubBodyCoords(grains.shape,[a b c],r+domain.dx,domain.dx,orient); + end + tmpOnesA = ones(size(sphere,1),1); + tmpOnesB = ones(size(sphereB,1),1); + + if ~boolDrawFromGrainList + % fprintf('\n%s\ncreating index list after previous r_bin is finished\n',repmat('#',[1,70])); +% monitor.log = [monitor.log sprintf('%s: Creating index list after previous r_bin is finished\n',datestr(now,'dd.mm.yy HH:MM'))]; +% showLogInfo(monitor.log,isgui,gui); +% pause(0.01); + + monitor.binStat(4,i) = max([monitor.binStat(4,i) monitor.stat(4)]); + monitor.voxHist(2,1:i) = monitor.nVox(1); + % plotting = update_PackingMonitor(M,L2,plotting,monitor); + + boolUpdateBoxList = true; + else + monitor.n = find(domain.xyzr0(:,end)>0,1,'last'); + end + + % current bin counter + nb = 1; + + % run as long as a sufficient amount of voxels are placed inside the domain (without margin) + nDumpUpdateCurBin = max([1 round(grains.Nbins(i)/params.dumpsPerBin)]); + while monitor.nVox(1) <= monitor.nVoxAim(i) + % global counter + monitor.stat(1) = monitor.stat(1) + 1; + % current grain counter + monitor.stat(4) = monitor.stat(4) + 1; + + if closeSurface && r <= closeSurfaceR + % mark all invalid grain center positions as occupied + % (otherwise M_valCtr won't be taken into account for packing) + M = M | ~M_valCtr; + + monitor.log = [monitor.log sprintf('%s: Fixing soil surface, new grains must be placed below\n',datestr(now,'dd.mm.yy HH:MM'))]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + if isgui + data = getappdata(fig,'data'); + monitor.Lr = L2; + data.monitor = monitor; + setappdata(fig,'data',data); + plotGSDdata(fig,'monitor'); + plotMatrixdata(fig,'monitor'); + end + + boolUpdateBoxList = true; + closeSurface = false; + end + + if monitor.por_cur <= por_RequireTouch || r <= r_RequireTouch + monitor.boolMustTouch = true; + end + + % reset current voxel increment, + % necessary to prevent from overestimating if + % placing fails + incVoxel = 0; + incMargin = 0; + + if (mod(monitor.stat(4),nMod_UpdateIndexList) == nMod_UpdateIndexList-1 ) + monitor.binStat(4,i) = max([monitor.binStat(4,i) monitor.stat(4)]); + monitor.voxHist(2,1:i) = monitor.nVox(1); +% plotting = update_PackingMonitor(M,L2,plotting,monitor); + end + + % draw a new center position based on the center of an already placed grain + if boolDrawFromGrainList + % draw an already placed grain center point + ind1 = randi([1 monitor.n-1]); + cBase = xyzr0(ind1,1:3); + + % define shift distance + vRad = round((xyzr0(ind1,4) + r) / domain.dx); + + % draw shift direction + vDir = 2*rand(1,3) - 1; + vDir = vDir / sqrt(sum(vDir.^2)); + + %apply shift + center = round(cBase + vDir*vRad); + if any(center < (r/domain.dx)+1) || any([center(1)>szM(1)-marg center(2)>szM(2)-marg center(3)>szM(3)-marg]) % org:(center < 1) + continue; + end + else + % draw grain center from list of vacant/free voxels + if (monitor.iRandPos > monitor.nRandPos) || boolUpdateBoxList + % fprintf('end of list reached at position %d - refreshing index\n',monitor.nRandPos); + monitor.log = [monitor.log sprintf('%s: End of list reached at position %d -> Updating index list\n',datestr(now,'dd.mm.yy HH:MM'),monitor.nRandPos)]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + if isgui + data = getappdata(fig,'data'); + monitor.Lr = L2; + data.monitor = monitor; + setappdata(fig,'data',data); + plotMatrixdata(fig,'monitor'); + end + + [Mindex,~] = updateIndexList('std',M,marg/2,r,xyzr0,domain,grains); + clear MtmpVal; + + % sync with valid grain center positions + Mindex = Mindex(M_valCtr(Mindex) == true); + MvN = numel(Mindex); + + if MvN<=1 + % if this happens you should stop the calculation + disp(' '); + disp('updateIndexList: no free voxels'); + end + monitor.log = [monitor.log sprintf('%s: Current porosity: %3.2f\n',datestr(now,'dd.mm.yy HH:MM'),monitor.por_cur)]; + monitor.log = [monitor.log sprintf('%s: Updated index list: %d free voxels left\n',datestr(now,'dd.mm.yy HH:MM'),MvN)]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + if isgui + data = getappdata(fig,'data'); + monitor.Lr = L2; + data.monitor = monitor; + setappdata(fig,'data',data); + plotMatrixdata(fig,'monitor'); + end + + listRandPos = unique(randi([1,MvN],[1 1e6])); + monitor.iRandPos = 1; + monitor.nRandPos = length(listRandPos); + listRandPos = listRandPos(randperm(monitor.nRandPos)); + boolUpdateBoxList = false; + Mindex = Mindex(listRandPos); + end + + [i1,i2,i3] = ind2sub(size(M),Mindex(monitor.iRandPos)); + center = [i1 i2 i3]; + monitor.iRandPos = monitor.iRandPos+1; + + end + + % move the grain to the current center point + spnew = sphere + [center(1)*tmpOnesA ... + center(2)*tmpOnesA .... + center(3)*tmpOnesA]; + + % also move the larger grain to the current center point + spnewB = sphereB + [center(1)*tmpOnesB ... + center(2)*tmpOnesB .... + center(3)*tmpOnesB]; + + try + % get indices of the current grain into M + index = sub2ind(size(M), spnew(:,1), spnew(:,2), spnew(:,3)); + % indices of the larger grain + indexB = sub2ind(size(M), spnewB(:,1), spnewB(:,2), spnewB(:,3)); + catch + disp('Something went utterly wrong.'); + end + % sub matrices for testing + boolFree = ~any(M(index(:))); +% boolTouch = ~monitor.boolMustTouch || (sum(M(indexB(:)))>monitor.nMinTouch); + if monitor.boolMustTouch + if sum(M(indexB(:)))>monitor.nMinTouch + boolTouch = true; + else + boolTouch = false; + end + else + boolTouch = true; + end + + monitor.arrFailStat(1) = monitor.arrFailStat(1)+1; + if boolFree && boolTouch + + incMargin = ~M_valCtr(index); + incMargin = sum(incMargin(:)); + incVoxel = grains.binVol(i)-incMargin; + + % mark the new grain + M(index) = true; + + % label it with radius + L2(index) = r; + + % append to coordinate list + xyzr0(monitor.n,1:4) = [center, r]; + + % increase current bin counter + nb = nb + 1; + + % increase global counter + monitor.n = monitor.n + 1; + + monitor.binStat(4,i) = max([monitor.binStat(4,i) monitor.stat(4)]); + + % reset the current tries per grain counter + monitor.stat(4) = 0; + else + % count tries where grain intersected already + % existing grain + monitor.stat(3) = monitor.stat(3) + 1; + monitor.arrFailStat(2:3) = monitor.arrFailStat(2:3) + [~boolFree ~boolTouch]; + end + + if size(xyzr0,1)-monitor.n < 10 + tmpAdd = round(0.1*size(xyzr0,1)); + xyzr0 = cat(1,xyzr0,-1*ones(tmpAdd,4)); + monitor.nxyzr0 = size(xyzr0,1); + end + + % update number of used voxels in box / in margin + monitor.nVox = monitor.nVox + [incVoxel incMargin]; + + monitor.por_cur = 1-monitor.nVox(1)/domain.VOL0; + % timing + monitor.t1 = toc; + + if (mod(monitor.stat(1),nDumpUpdateCurBin) == 0) || (mod(round(monitor.t1),params.dumpSec) == 0) || (monitor.stat(1) == 1) + monitor.i = i; % update coutner for current grain size bin +% monitor = printProgress(monitor); + end + + if (mod(round(monitor.t1),params.updateVisualSec) == 0) +% plotting = update_PackingMonitor(M,L2,plotting,monitor); + end + + % the current grain could not be set after 1e5 tries + + if mod(monitor.stat(4),monitor.threshSwapListBox) == monitor.threshSwapListBox-1 &&... + (iSwapListBox < monitor.nSwapListBoxMax) && monitor.boolMustTouch + boolDrawFromGrainList = ~boolDrawFromGrainList; + + if ~boolDrawFromGrainList + strDrawStyle = 'box-based'; + boolUpdateBoxList = true; + else + strDrawStyle = 'grain-based'; + end + monitor.log = [monitor.log sprintf('%s: Switch to %s drawing.\n',datestr(now,'dd.mm.yy HH:MM'),strDrawStyle)]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + end + + if monitor.stat(4) > monitor.threshMaxTry + monitor.log = [monitor.log sprintf('%s: Aborting bin: max. threshold %d/%d is reached.\n',... + datestr(now,'dd.mm.yy HH:MM'),monitor.stat(4),monitor.threshMaxTry)]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + break; + end + + if monitor.por_cur <= monitor.poro_final + monitor.log = [monitor.log sprintf('%s: Aborting bin: porosity of %4.2f%% is reached.\n',... + datestr(now,'dd.mm.yy HH:MM'),monitor.por_cur)]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + break; + end + end + + % the current bin is done (all grains of this size have been placed) + monitor.nLstVox = monitor.nVox(1); + + monitor.log = [monitor.log sprintf('%s: Finished bin: placed %d of %d voxels.\n',... + datestr(now,'dd.mm.yy HH:MM'),monitor.nVox(1),monitor.nVoxAim(i))]; + showLogInfo(monitor.log,isgui,gui); + pause(0.01); + if isgui + data = getappdata(fig,'data'); + monitor.Lr = L2; + data.monitor = monitor; + setappdata(fig,'data',data); + plotGSDdata(fig,'monitor'); + plotMatrixdata(fig,'monitor'); + end + if monitor.stat(4) > monitor.threshMaxTry || monitor.por_cur <= monitor.poro_final + break; + end +end + +monitor.log = [monitor.log sprintf('%s: Finished last bin.\n',datestr(now,'dd.mm.yy HH:MM'))]; +showLogInfo(monitor.log,isgui,gui); +pause(0.01); + +str1 = 'RUN - placeGrains: finished setting grains. '; +if isgui + set(gui.text_handles.Status,'String', str1); +else + disp(str1); +end + +% total run time +t = toc; + +% finalize the output data +domain.xyzr0 = xyzr0; + +% all matrices with margin +domain.final{1}.M = M; +if ~params.boolOmitLn + % reset remaining empty voxels in margin + L1(L1 == -1) = 0; + domain.final{1}.Ln = L1; +end +domain.final{1}.Lr = L2; +domain.porosity_final = 1-sum(M(domain.kEvalPoro))/domain.VOL0; + +% printStat(domain,monitor.stat,t); + +statStruct.porosity_final = domain.porosity_final; +statStruct.runtimeMin = t/60; +statStruct.stat = monitor.stat; +domain.statB = statStruct; +domain.monitor = monitor; + +% domain.plotting = plotting; + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/placeWater.m b/functions/placeWater.m new file mode 100644 index 0000000..907dece --- /dev/null +++ b/functions/placeWater.m @@ -0,0 +1,596 @@ +function [domain,grains,params] = placeWater(domain,grains,params,varargin) +%placeWater places all water voxels within the domain +% +% Syntax: +% [domain,grains,params] = placeGrainsFull(domain,grains,params) +% +% Inputs: +% domain +% grains +% params +% varargin +% +% Outputs: +% domain +% grains +% params +% +% Example: +% [domain,grains,params] = placeWater(domain,grains,params,src) +% +% Other m-files required: +% none +% +% Subfunctions: +% getSatProfile +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% check if called from GUI +isgui = false; +if nargin > 3 + src = varargin{1}; + % get GUI handle + fig = ancestor(src,'figure','toplevel'); + isgui = true; + % get GUI data + gui = getappdata(fig,'gui'); +else + gui = 0; +end + +n = find(domain.xyzr0(:,end)>0,1,'last'); +if isempty(n) + n = 0; +end +n = n+1; +n_start = n; + +log = domain.monitor.log; +log = [log sprintf(' \n')]; +log = [log sprintf('%s: Start placing water voxels.\n',datestr(now,'dd.mm.yy HH:MM'))]; +showLogInfo(log,isgui,gui); +pause(0.01); + +if ~params.useSatProfile % random + % porosity goal + % now we only add water voxels until the final air volume is + % reached + poro_final = domain.VolSpeciesAIR; + + % global grain counter + % n_start = max(max(domain.final{1}.Ln(:))); + + % index of r bin class to set (usually the two smallest ones: + % single voxel and 7 voxel crosses) + idr = 1; + rbins = grains.rbins(idr); + nbins = grains.nbins(idr); + binVol = grains.binVol(idr); + + % get the matrices with the margin + M = domain.final{1}.M; + if ~params.boolOmitLn + L1 = domain.final{1}.Ln; + end + L2 = domain.final{1}.Lr; + M_valCtr = domain.final{1}.M_valCtr; + + % get the coordinate lists + xyzr0 = domain.xyzr0; + % margin width + marg = domain.marg; + + % estimate how many voxel to set globally to reach desired porosity + % v_to_add = numel(domain.final{2}.M(:)) - sum(domain.final{2}.M(:)) - round(numel(domain.final{2}.M(:))*poro_final); + % v_to_add = domain.VOL0 - (sum(domain.final{2}.M(:)) - domain.VOLmask) - round(domain.VOL0*poro_final); + % v_to_add = domain.VOL0 - (sum(domain.final{2}.M(:)) - domain.VOLmask) - round(domain.VOL0*poro_final); + v_to_add = domain.VOL0 - (sum(domain.final{1}.M(domain.kEvalPoro)) - round(domain.VOL0*poro_final)); + + nVoxMatrix = sum(domain.final{1}.M(domain.kEvalPoro)); + nVoxExisting = sum(domain.final{1}.Lr(domain.kEvalPoro) == params.ID_MASKED.Water.Lr); + nVoxWaterTarget = round(domain.VOL0*domain.VolSpeciesH2O); + nVoxWaterToAdd = nVoxWaterTarget-nVoxExisting; + v_to_add = nVoxWaterToAdd; + + % estimate grains to add to reach desired porosity + some extra + g_to_add = round(round(v_to_add/sum(binVol))*1.1); + + nbins = round(g_to_add/10); + + % extend point coordinate matrices accordingly + xyzr0 = [xyzr0; zeros(g_to_add,4)]; + + % make an initial index list + log = [log sprintf('%s: Create initial index list.\n',datestr(now,'dd.mm.yy HH:MM'))]; + showLogInfo(log,isgui,gui); + pause(0.01); + [Mindex,~] = updateIndexList('std',M,marg/2,rbins(1),xyzr0,domain,grains); + + % sync with valid grain center positions + Mindex = Mindex(M_valCtr(Mindex) == true); + clear M_valCtr; + MvN = numel(Mindex); + + % list(1).Mindex = Mindex; + % list(1).MvN = MvN; + + + % start porosity + % poro = domain.porosity_final; + + % continuous grain counter + n = n_start + 1; + % statistics + stat = [0 0 0 0]; + nVoxWaterAdded = 0; + + arrPackVel = zeros(2,2); + arrPackVel(2,:) = [toc nVoxWaterAdded]; + velPackMax = 0; + + % nDumpUpdateCurBin = max([1 round(nVoxWaterToAdd/params.dumpsPerBin)]); + params.dump = 10000; + % while poro > poro_final + while nVoxWaterAdded < nVoxWaterToAdd + + % the larger grains first + for i = numel(rbins):-1:1 + % global counter + % current radius of grain in [m] + r = rbins(i); + % radius in lattice units + r2 = ceil(r/domain.dx); + % current grain + sphere = getSubBodyCoords(grains.shape,grains.axes,r,domain.dx); + % a grain that is one lattice unit larger + sphereB = getSubBodyCoords(grains.shape,grains.axes,2*r,domain.dx); + + tmpOnesA = ones(size(sphere,1),1); + tmpOnesB = ones(size(sphereB,1),1); + + nb = 1; + while nb <= nbins(i) + % global counter + stat(1) = stat(1) + 1; + stat(4) = stat(4) + 1; + + % update indexList every xxx tries + if mod(stat(1),5e5) == 0 + log = [log sprintf('%s: Updating index list.\n',datestr(now,'dd.mm.yy HH:MM'))]; + showLogInfo(log,isgui,gui); + pause(0.01); + [Mindex,MvN] = updateIndexList('std',M,marg/2,rbins(1),xyzr0,domain,grains); + % list(1).Mindex = Mindex; + % list(1).MvN = MvN; + if MvN<=1 + % if this happens you should stop the calculation + disp('placWater: updateIndexList: no free voxels'); + end + end + + % draw a center point out of the list + ind1 = randi([1 MvN]); + [i1,i2,i3] = ind2sub(size(M),Mindex(ind1)); + center = [i1 i2 i3]; + + % move the grain to the current center point + spnew = sphere + [center(1)*tmpOnesA ... + center(2)*tmpOnesA .... + center(3)*tmpOnesA]; + + % also move the larger grain to the current center point + spnewB = sphereB + [center(1)*tmpOnesB ... + center(2)*tmpOnesB .... + center(3)*tmpOnesB]; + + % get indices of the current grain into M + index = sub2ind(size(M), spnew(:,1), spnew(:,2), spnew(:,3)); + % indices of the larger grain + indexB = sub2ind(size(M), spnewB(:,1), spnewB(:,2), spnewB(:,3)); + + % sub matrices for testing + A = M(index); + B = M(indexB); + + % if the current water voxel touches nothing (sum(A)==0) and + % the larger "grain" touches an already existing grain + % (sum(B)>0) then place it + if sum(A(:)) == 0 && sum(B(:))>0 + % mark the new grain + M(index) = true; + % and label it + if ~params.boolOmitLn + L1(index) = n; % with unique counter + end + L2(index) = 99; % water marker + % coordinate lists + % xyzr(n,1:4) = [(center-1-marg)*domain.dx, 99]; + xyzr0(n,1:4) = [center, 99]; + % increase counters + % current bin + nb = nb + 1; + % global counter + n = n + 1; + + % total voxel counter + nVoxWaterAdded = nVoxWaterAdded + numel(index); + % reset the current tries per grain counter + stat(4) = 0; + else + % count tries where grain intersected already + % existing grain + stat(3) = stat(3) + 1; + end + + + % poro = 1-sum(M(domain.kEvalPoro))/domain.VOL0; + % pAir = 1-(nVoxMatrix + nVoxWaterAdded)/domain.VOL0; + + % output some statistics from time to time + if mod(stat(1),params.dump) == 0 + % timing + t1 = toc; + % disp(['current porosity : ',sprintf('%4.3f',poro)]); + % disp(['current water : ',num2str(nb),... + % ' / ',num2str(nbins(i))]); + + CurWater = nVoxWaterAdded/nVoxWaterToAdd; + str = ['RUN - placeWater: water voxels: ',sprintf('%d',round(100*CurWater)),'%']; + if isgui + set(gui.text_handles.Status,'String', str); + else + disp(str); + end + pause(0.001); + + + % fprintf('current water : [%s] %4.2f%%(%4dk/%4dk added)\n',getProgbar(dblProgCurWater,50),100*dblProgCurWater,round([nVoxWaterAdded,nVoxWaterToAdd]/1000)); + % disp(['total tries : ',num2str(stat(1))]); + % disp(['center hits : ',num2str(stat(2))]); + % disp(['occupied hits : ',num2str(stat(3))]); + % disp(['current tries : ',num2str(stat(4))]); + % + % arrPackVel(1,:) = arrPackVel(2,:); + % arrPackVel(2,:) = [t1 nVoxWaterAdded]; + % velPackCur = 1e-3*diff(arrPackVel(:,2))/diff(arrPackVel(:,1)); + % velPackMax = max([velPackMax velPackCur]); + % + % % fprintf('cur. packing vel.: [%s] %4.3fk vox/s (%6.4f%%/min)\n',getProgbar(velPackCur/velPackMax,nBar),[velPackCur,100*60*1e3*velPackCur/domain.VOL0]); + % + % disp(['elapsed time : ',sprintf('%4.2f',t1/60),' min']); + % tEst = (nVoxWaterToAdd-nVoxWaterAdded)/(1e3*velPackCur); + % fprintf('result estimated for %s (%4.2f min)\n',datestr(now+tEst/86400,'HH:MM:SS, dd.mm.yyyy'),tEst/60); + end + + % the current grain could not be set after 1e5 tries + % break -> should actually never happen + if stat(4) > 1e6 + disp(' '); + disp(['current tries : ',num2str(stat(4))]); + disp('stopping here because the current grain could not be placed'); + disp('try a new random seed or adjust the corr_fac in prepareDomain.m.'); + break; + end + if nVoxWaterAdded >= nVoxWaterToAdd + break; + end + end + if stat(4) > 1e6 || nVoxWaterAdded >= nVoxWaterToAdd + break; + end + end + if stat(4) > 1e6 || nVoxWaterAdded >= nVoxWaterToAdd + break; + end + end + % total run time + t = toc; + + % finalize the output data + % and remove possible empty fields + Nxyz = find(xyzr0(:,4)==0,1,'first')-1; + if ~isempty(Nxyz) + xyzr0 = xyzr0(1:Nxyz,:); + end + + % save the number of water voxels + grains.n_water = sum(L2(:)==99); + + domain.xyzr0 = xyzr0; + % all matrices with margin + domain.final{1}.M = M; + if ~params.boolOmitLn + domain.final{1}.Ln = L1; + end + domain.final{1}.Lr = L2; + % matrices without margin + domain.final{2}.M = M(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); + if ~params.boolOmitLn + domain.final{2}.Ln = L1(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); + end + domain.final{2}.Lr = L2(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); + % update final porosity + domain.porosity_final = 1-sum(M(domain.kEvalPoro))/domain.VOL0; + domain.porosity_final_water = sum(M(L2==99))/domain.VOL0; + + + log = [log sprintf(' \n')]; + log = [log sprintf('%s: Final porosity (air): %3.2f\n',datestr(now,'dd.mm.yy HH:MM'),domain.porosity_final)]; + log = [log sprintf('%s: Water Voxels: %d\n',datestr(now,'dd.mm.yy HH:MM'),grains.n_water)]; + log = [log sprintf('%s: Final porosity (h2o): %3.2f\n',datestr(now,'dd.mm.yy HH:MM'),domain.porosity_final_water)]; + showLogInfo(log,isgui,gui); + pause(0.01); + +else % profile + + % get saturation profile + Sat = getSatProfile(domain,params); + params.sat_profile = Sat; + + % margin width + marg = domain.marg; + + % get the matrices with the margin + M = domain.final{1}.M; + if ~params.boolOmitLn + L1 = domain.final{1}.Ln; + end + L2 = domain.final{1}.Lr; + MvC =domain.final{1}.M_valCtr; + % get the coordinate lists + % xyzr = domain.xyzr; + xyzr0 = domain.xyzr0; + + poro = domain.porosity_final; + sliceV = round(numel(domain.final{1}.M(:,:,1))*poro); + % estimate how many water voxel to set globally to create the + % desired profile + v_to_add = round(sum(sliceV*Sat)); + + % estimate water "grains" to add + some extra + g_to_add = round(v_to_add*1.1); + + % extend point coordinate matrices + % xyzr = [xyzr; zeros(g_to_add,4)]; + xyzr0 = [xyzr0; zeros(g_to_add,4)]; + + % global grain counter + % n_start = max(max(domain.final{1}.Ln(:))); + + % n = n_start; + % loop over all interior slices starting at the bottom (highest saturation) + % so we need to flip "Sat" as it is defined from top to bottom +% Sat = fliplr(Sat); + for zi = marg+1:size(M,3)-marg + + % get current depth slice (without margin) + M1 = squeeze(M(marg+1:size(M,1)-marg,marg+1:size(M,2)-marg,zi)); + if ~params.boolOmitLn + L1s = squeeze(L1(marg+1:size(M,1)-marg,marg+1:size(M,2)-marg,zi)); + end + L2s = squeeze(L2(marg+1:size(M,1)-marg,marg+1:size(M,2)-marg,zi)); + MvCs = squeeze(MvC(marg+1:size(MvC,1)-marg,marg+1:size(MvC,2)-marg,zi)); + + % count the empty voxels in the current layer + c0 = sum(M1(:)==0); + + % how many voxel to mark as water in this layer + cw = round(c0*Sat(zi-marg)); + + % if we have to place water voxels in this layer proceed + % the second check test if there are at least some grains in the + % slice, otherwise it won't work for a dipping surface (this needs + % to be corrected in a future version anyway) + if cw > 0 && sum(M1(:))>0 + stat = [0 0]; + + % make a list with all empty voxels + M2 = M1(:); + ic = (1:numel(M2))'; + ic(M2) = []; + + % water voxels set counter + sw = 0; + % neighbor voxels + neigh = zeros(8,2); + while sw < cw + stat(1) = stat(1) + 1; + + if mod(stat(1),c0) == 0 + % disp('making new list') + % make a list with all empty voxels + M2 = M1(:); + ic = (1:numel(M2))'; + ic(M2) = []; + end + + % draw a random empty location + index = randi([1 numel(ic)],1); + + % get the neighbors: + % current center coord + [i1,i2] = ind2sub(size(M1),ic(index)); + % neighbor coords in 2D + neigh(1,1:2) = [i1-1 i2-1]; + neigh(2,1:2) = [i1 i2-1]; + neigh(3,1:2) = [i1+1 i2-1]; + neigh(4,1:2) = [i1-1 i2]; + neigh(5,1:2) = [i1+1 i2]; + neigh(6,1:2) = [i1-1 i2+1]; + neigh(7,1:2) = [i1 i2+1]; + neigh(8,1:2) = [i1+1 i2+1]; + + % remove any neighbor point that is outside of the container + [ix1,~] = find(neigh(:,1)<1 | neigh(:,1)>size(M1,1)); + [ix2,~] = find(neigh(:,2)<1 | neigh(:,2)>size(M1,2)); + ix = unique([ix1;ix2]); + neigh(ix,:) = []; + + % global coordinates of the neighbors + n_ind = sub2ind(size(M1), neigh(:,1), neigh(:,2)); + + % only place it if the current position is not occupied and at + % least one neighbor is not air (empty) + if ~M1(ic(index)) && sum(M1(n_ind))>0 + sw = sw + 1; + + % mark the new grain + M1(ic(index)) = true; + % global counter + n = n + 1; + % and label it + if ~params.boolOmitLn + L1s(ic(index)) = n; + end + L2s(ic(index)) = 99; + + % update coordinate lists + coord = [i1 i2 zi]; + % xyzr(n,1:4) = [(coord-1-marg)*domain.dx, 99]; + xyzr0(n,1:4) = [coord, 99]; + else + stat(2) = stat(2) + 1; + end + + % if mod(stat(1),round(cw))==0 + % clc; + % % timing + % t1 = toc; + % disp(['current slice : ',sprintf('%d',zi-marg),'/',num2str(int32(domain.nz0))]); + % disp(['total tries : ',num2str(stat(1))]); + % disp(['center hits : ',num2str(stat(2))]); + % disp(['placed grains : ',num2str(n-n_start)]); + % disp(['elapsed time : ',sprintf('%4.2f',t1/60),' min']); + % end + end + end + + str = ['RUN - placeWater: slice: ',sprintf('%d / %d',zi-marg,size(M,3)-2*marg)]; + if isgui + set(gui.text_handles.Status,'String', str); + else + disp(str); + end + pause(0.001); + + % insert the current slice back into the larger block + M(marg+1:size(M,1)-marg,marg+1:size(M,2)-marg,zi) = M1; + if ~params.boolOmitLn + L1(marg+1:size(M,1)-marg,marg+1:size(M,2)-marg,zi) = L1s; + end + L2(marg+1:size(M,1)-marg,marg+1:size(M,2)-marg,zi) = L2s; + end + % total run time + t = toc; + + % finalize the output data + % and remove possible empty fields + Nxyz = find(xyzr0(:,4)==0,1,'first')-1; + if ~isempty(Nxyz) + % xyzr = xyzr(1:Nxyz,:); + xyzr0 = xyzr0(1:Nxyz,:); + end + + % save the number of water voxels + grains.n_water = sum(L2(:)==99); + + % finalize the output data + % remove possible empty fields + Nxyz = find(xyzr0(:,4)==0,1,'first')-1; + if ~isempty(Nxyz) + % xyzr = xyzr(1:Nxyz,:); + xyzr0 = xyzr0(1:Nxyz,:); + end + + % domain.xyzr = xyzr; + domain.xyzr0 = xyzr0; + % all matrices with margin + domain.final{1}.M = M; + if ~params.boolOmitLn + domain.final{1}.Ln = L1; + end + domain.final{1}.Lr = L2; + % matrices without margin + domain.final{2}.M = M(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); + if ~params.boolOmitLn + domain.final{2}.Ln = L1(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); + end + domain.final{2}.Lr = L2(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); + % update final porosity + domain.porosity_final = 1-sum(M(domain.kEvalPoro))/domain.VOL0; + domain.porosity_final_water = sum(M(L2==99))/domain.VOL0; + + log = domain.monitor.log; + log = [log sprintf(' \n')]; + log = [log sprintf('%s: Final porosity (air): %3.2f\n',datestr(now,'dd.mm.yy HH:MM'),domain.porosity_final)]; + log = [log sprintf('%s: Water Voxels: %d\n',datestr(now,'dd.mm.yy HH:MM'),grains.n_water)]; + log = [log sprintf('%s: Final porosity (h2o): %3.2f\n',datestr(now,'dd.mm.yy HH:MM'),domain.porosity_final_water)]; + showLogInfo(log,isgui,gui); + pause(0.01); +end + +log = [log sprintf('%s: Finished placing Water.\n',datestr(now,'dd.mm.yy HH:MM'))]; +showLogInfo(log,isgui,gui); +str = 'RUN - FINISHED.'; +if isgui + set(gui.text_handles.Status,'String', str); +else + disp(str); +end +pause(0.001); + + +end + +function Sat = getSatProfile(domain,params) + +switch params.satProfileType + + case 'linear' + % linear 0 -> 1 + slope = (params.satBounds(2)-params.satBounds(1))/(domain.nz0-1); + z = 0:1:domain.nz0-1; + Sat = slope*z+params.satBounds(1); + + case 'exponential' + B = 20; % degree of curvature + + z = linspace(0,1,domain.nz0); + y1 = params.satBounds(1); + y2 = params.satBounds(2); + % normalizes z + r = (z - z(1)) / (z(end) - z(1)); + C = B^(z(end) - z(1)); + Sat = ((y2-y1)*C.^r + y1*C-y2)/(C-1); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/prepareDomain.m b/functions/prepareDomain.m new file mode 100644 index 0000000..f8d05ef --- /dev/null +++ b/functions/prepareDomain.m @@ -0,0 +1,385 @@ +function [domain,params] = prepareDomain(domain,grains,params,varargin) +%prepareDomain generates the domain data based on the user entries +% +% Syntax: +% [domain,params] = prepareDomain(domain,grains,params) +% +% Inputs: +% domain +% grains +% params +% +% Outputs: +% domain +% params +% +% Example: +% [domain,params] = prepareDomain(domain,grains,params) +% +% Other m-files required: +% getSubBodyCoords +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% check if called from GUI +isgui = false; +if nargin > 3 + src = varargin{1}; + % get GUI handle + fig = ancestor(src,'figure','toplevel'); + isgui = true; + % get GUI data + gui = getappdata(fig,'gui'); +end + +str = 'INIT - prepareDomain: init voxel volume'; +if isgui + set(gui.text_handles.Status,'String', str); +else + disp(str); +end +pause(0.001); + +% original volume of the main container [m^3] +domain.Vbox = domain.xm*domain.ym*domain.zm; +% matrix volume [m^3] +domain.Vmatrix = (1 - domain.porosity)*domain.Vbox; + +% number of inner voxels in each direction +domain.nx0 = round(domain.xm/domain.dx) + 1; +domain.ny0 = round(domain.ym/domain.dx) + 1; +domain.nz0 = round(domain.zm/domain.dx) + 1; + +% if there is an inner margin mask increase the number of inner voxels +if params.applyMarginMask + domain.nx0 = domain.nx0 + 2; + domain.ny0 = domain.ny0 + 2; + domain.nz0 = domain.nz0 + 1; +end +% the voxel volume without the margin +domain.VOL0 = domain.nx0*domain.ny0*domain.nz0; + +% margin extends the domain on all sides depending on the largest grain +% radius +domain.marg = 2*ceil((grains.rmax+domain.dx)/domain.dx); +marg = domain.marg; + +% how many elements in each spatial direction (incl. margin on all sides) +domain.nx = domain.nx0 + 2*domain.marg; +domain.ny = domain.ny0 + 2*domain.marg; +domain.nz = domain.nz0 + 2*domain.marg; + +% complete voxel volume +VOL2 = domain.nx*domain.ny*domain.nz; + +Vol0b = (domain.nx0+marg/2)*(domain.ny0+marg/2)*(domain.nz0+marg/2); +% margin volume (NOTE: why is it not VOL2-VOL0?) +VOLmarg = VOL2-Vol0b; + +% take care of target +if params.useTarget + target = params.target; + target_vol = sum(target(:)>1); + params.VOLtarget = target_vol; +else + params.VOLtarget = 0; +end + +% set up matrices for storing the final positions of the grains +% logical matrix to mark occupied voxels +M = false(domain.nx,domain.ny,domain.nz); + +% logical matrix to mark valid grain center positions +M_valCtr = true(domain.nx,domain.ny,domain.nz); + +% Label matrix for each radius bin +L2 = zeros(domain.nx,domain.ny,domain.nz); + +% create indices for margin to check voxel positions +tmpInd = reshape(1:numel(L2),size(L2)); +kInner = tmpInd(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg); +kInner = kInner(:); +kMargin = setdiff(tmpInd,kInner); +% at these voxel no grains centers can be set +M_valCtr(kMargin) = false; + +clear tmpInd kMarginA kMarginB + +%% TARGETS +str = 'INIT - prepareDomain: apply targets'; +if isgui + set(gui.text_handles.Status,'String', str); +else + disp(str); +end +pause(0.001); + +% take care of target +if params.useTarget + index = sub2ind(size(M), params.targetIDX(:,1)+marg,... + params.targetIDX(:,2)+marg, params.targetIDX(:,3)+marg); + % mark target voxels as occupied in M + M(index) = true; + % mark target voxel as invalid for new grain centers + M_valCtr(index) = false; + + % mark target voxels in Lr + L2(index) = params.ID_MASKED.Target.Lr; +else + xstart = round(size(M,1)/2); + ystart = round(size(M,2)/2); + zstart = round(size(M,3)/2); + tdims = zeros(1,3); +end + +%% MASKS +str = 'INIT - prepareDomain: apply mask'; +if isgui + set(gui.text_handles.Status,'String', str); +else + disp(str); +end +pause(0.001); + +% mask regions if defined +if params.use_mask + % check for any dip value + if sum(params.maskdipx+params.maskdipy) > 0 + % create a standard mask + mask = struct('arrTiltDegXY',[params.maskdipx params.maskdipy],... + 'arrBaseXYZ',[0 0 0],... + 'zBaseMinTop',domain.marg*domain.dx); + % several masks may be applied subsequently + % here we only add the one for a tilted surface + else + % create a dummy mask + mask = struct('arrTiltDegXY',[0 0],... + 'arrBaseXYZ',[0 0 0],... + 'zBaseMinTop',domain.marg*domain.dx); + end + params.masks = {mask}; +end + +if params.use_mask + cellMasks = params.masks; + nMask = numel(cellMasks); + + for iMask = 1:nMask + curMask = params.masks{iMask}; + if isfield(curMask,'arrMinMaxXYZ') + arrMinMaxXYZ = curMask.arrMinMaxXYZ; + + kMinMax = round(arrMinMaxXYZ/domain.dx); + + kX = domain.marg+1+(kMinMax(1,1):kMinMax(1,2)); + kY = domain.marg+1+(kMinMax(2,1):kMinMax(2,2)); + kZ = domain.marg+1+(kMinMax(3,1):kMinMax(3,2)); + + if params.applyMarginMask + kX = kX+1; + kY = kY+1; + end + + M_valCtr(kX,kY,kZ) = false; + end + + if isfield(curMask,'arrTiltDegXY') + maxX = domain.dx*domain.nx; + maxY = domain.dx*domain.ny; + [tmpY,tmpX,tmpZ] = meshgrid(domain.dx*(1:domain.ny),... + domain.dx*(1:domain.nx),domain.dx*(1:domain.nz)); + + arrSlope = curMask.arrTiltDegXY; + + if isfield(curMask,'zBaseMinTop') + zBase = curMask.zBaseMinTop+abs((maxX-curMask.arrBaseXYZ(1))*tan(arrSlope(1)*pi/180)... + + abs(maxY-curMask.arrBaseXYZ(2))*tan(arrSlope(2)*pi/180)); + curMask.arrBaseXYZ(3) = zBase; + end + arrBase = curMask.arrBaseXYZ; + + + tmpSel = tmpZ <= (arrBase(3)+(arrBase(1)-tmpX)*tan(arrSlope(1)*pi/180)... + + (arrBase(2)-tmpY)*tan(arrSlope(2)*pi/180)); + clear tmpY tmpX tmpZ + + % mark masked region as invalid for new grain centers + M_valCtr(tmpSel) = false; + + % mark masked region as air in Lr + L2(tmpSel) = params.ID_MASKED.Air.Lr; + clear tmpSel; + end + end +end + +%% MARGIN MASK +str = 'INIT - prepareDomain: apply margin mask'; +if isgui + set(gui.text_handles.Status,'String', str); +else + disp(str); +end +pause(0.001); + +if params.applyMarginMask + % build x- MarginMask + kInnerX = domain.marg+(1:domain.nx0); + kInnerY = domain.marg+(1:domain.ny0); + kInnerZ = domain.marg+(1:domain.nz0); + + % 26.10.22: mask is part of margin + M([domain.marg,domain.nx-domain.marg+1],kInnerY,kInnerZ) = true; + M(kInnerX,[domain.marg,domain.ny-domain.marg+1],kInnerZ) = true; + M(kInnerX,kInnerY,domain.nz-domain.marg+1) = true; +end + +% until 26.10.22 +% now the volume in terms of voxel and accounting for the margin +% domain.VOL = sum(~M(:)); +% sync kInner with valid grain center positions +% (take care of masked regions +% kInner = kInner(M_valCtr(kInner)); +% innerM = M(kInner); +% domain.VOL0 = sum(~innerM(:)); +% domain.VOLmask = sum(innerM(:)); + +% 26.10.22: interpret only voxels as box volume at +% valid grain center positions at start +domain.VOL0 = sum(M_valCtr(:)); +domain.kEvalPoro = find(M_valCtr(:)); + +% VOL0matrix is later needed to find the total number of grains to create +% this particular matrix volume +% domain.VOLmatrix = round((1-domain.porosity)*domain.VOL); +domain.VOL0matrix = round((1-domain.porosity)*domain.VOL0); + +% all matrices with margin +domain.final{1}.M = M; +domain.final{1}.M_valCtr = M_valCtr; +domain.final{1}.Lr = L2; + +domain.porosity_final = 1-sum(domain.final{1}.M(domain.kEvalPoro))/domain.VOL0; + +% allocation for grain center coordinates and radius +% radius is always in real units [m] +% coordinates in real dimensions [m] + +% maximum numbers of grains to place inside the container +nmax = 50000; +nPreOcc = sum(M(:)); + +% xyzr = -1*ones(max([nmax nPreOcc]),4); +% coordinates in lattice units +xyzr0 = -1*ones(max([nmax nPreOcc]),4); + +str = 'INIT - prepareDomain: coord list of pre-allocated voxels:'; +if isgui + set(gui.text_handles.Status,'String', str); +else + disp(str); +end +pause(0.001); + +n = 1; +if nPreOcc > 0 + % detect margin + szM = size(M); + Mmarg = zeros(size(M)); + + dCalc = diff(M,1,1); + dAppl = cat(1,zeros([1,szM(2),szM(3)]),dCalc); + Mmarg(dAppl > 0) = 1; + dAppl = cat(1,dCalc,zeros([1,szM(2),szM(3)])); + Mmarg(dAppl < 0) = 1; + + + dCalc = diff(M,1,2); + dAppl = cat(2,zeros([szM(1),1,szM(3)]),dCalc); + Mmarg(dAppl > 0) = 1; + dAppl = cat(2,dCalc,zeros([szM(1),1,szM(3)])); + Mmarg(dAppl < 0) = 1; + + dCalc = diff(M,1,3); + dAppl = cat(3,zeros([szM(1),szM(2),1]),dCalc); + Mmarg(dAppl > 0) = 1; + dAppl = cat(3,dCalc,zeros([szM(1),szM(2),1])); + Mmarg(dAppl < 0) = 1; + + clear dCalc dAppl + + [xOcc,yOcc,zOcc] = ind2sub(size(M),find(Mmarg)); + clear Mmarg + + xyzOcc = cat(2,xOcc,yOcc,zOcc,zeros(size(xOcc))); + sphere = getSubBodyCoords(grains.shape,grains.axes,domain.dx,domain.dx); + nUpdate = round(size(xyzOcc,1)/1000); + for nn = 1:size(xyzOcc,1) + + spnew = [xyzOcc(nn,1)*ones(length(sphere),1) ... + xyzOcc(nn,2)*ones(length(sphere),1) .... + xyzOcc(nn,3)*ones(length(sphere),1)]; + [ix1,~] = find(spnew(:,1)size(M,1)-marg); + [ix2,~] = find(spnew(:,2)size(M,2)-marg); + + % in z-dimension, accept positions in upper margin + % to create a surface pattern + [ix3,~] = find(spnew(:,3)>size(M,3)-marg); + ix = unique([ix1;ix2;ix3]); + spnew(ix,:) = []; + + % get indices of the current sphere into M + % index = sub2ind(size(M), spnew(:,1), spnew(:,2), spnew(:,3)); + + center = xyzOcc(nn,1:3); + % xyzr(n,1:4) = [(center-1-marg)*domain.dx, domain.dx/2]; + xyzr0(n,1:4) = [center, domain.dx/2]; + n = n + 1; + + if mod(nn,nUpdate) == 0 + str = ['INIT - prepareDomain: coord list of pre-allocated voxels: ',sprintf('%d',round(100*nn/size(xyzOcc,1))),'%']; + if isgui + set(gui.text_handles.Status,'String', str); + else + disp(str); + end + pause(0.001); + end + + end + xyzr0 = unique(xyzr0,'rows'); +end + +domain.xyzr0 = xyzr0; +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/prepareVoxelGSD.m b/functions/prepareVoxelGSD.m new file mode 100644 index 0000000..b040c4f --- /dev/null +++ b/functions/prepareVoxelGSD.m @@ -0,0 +1,269 @@ +function grains = prepareVoxelGSD(domain,grains,varargin) +%prepareVoxelGSD generates the voxelised GSD input data +% +% Syntax: +% grains = prepareVoxelGSD(domain,grains,varargin) +% +% Inputs: +% domain +% grains +% varargin +% +% Outputs: +% grains +% +% Example: +% grains = prepareVoxelGSD(domain,grains,varargin) +% +% Other m-files required: +% getSubBodyCoords +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +% check if called from GUI +isgui = false; +if nargin > 2 + src = varargin{1}; + % get GUI handle + fig = ancestor(src,'figure','toplevel'); + isgui = true; + % get GUI data + gui = getappdata(fig,'gui'); +end + +if grains.ishistogram + % create a diameter binning vector considering the minimum grid + % discretization + dbins = domain.dx:domain.dx:grains.rmax*2; + % radius binning vector + rbins = dbins/2; + nbins = zeros(size(rbins)); + nvoxBins = zeros(size(rbins)); + + % get the voxel volume per individual grain radius + grains.binVol = zeros(1,numel(rbins)); + + % interpolate the input histogram on the radius binning vector + tmpCumVol = interp1(grains.hist_raw(:,1),grains.hist_raw(:,2),rbins); + fracBin = [tmpCumVol(1) diff(tmpCumVol)]; + + remainVox = 0; + cc = 0; + str2 = cell(1,1); + for i = fliplr(1:numel(rbins)) + cc = cc + 1; + sphere = getSubBodyCoords(grains.shape,grains.axes,rbins(i),domain.dx); + grains.binVol(i) = size(sphere,1); + nbins(i) = floor((remainVox + domain.VOL0matrix*fracBin(i))/grains.binVol(i)); + nvoxBins(i) = nbins(i)*grains.binVol(i); + remainVox = domain.VOL0matrix*sum(fracBin(i:end))-sum(nvoxBins(i:end)); + + str1 = ['INIT - prepareVoxelGSD: bin classes done: ',sprintf('%d',round(100*cc/numel(rbins))),'%']; + if cc == 1 + str2{1,1} = [sprintf('%s',datestr(now,'dd.mm.yy HH:MM')),' r bin class ',num2str(i),... + ' (',sprintf('%5.4f',rbins(i)),'m) ',sprintf('%d',nbins(i)),' grains']; + else + str2{end+1,1} = [sprintf('%s',datestr(now,'dd.mm.yy HH:MM')),' r bin class ',num2str(i),... + ' (',sprintf('%5.4f',rbins(i)),'m) ',sprintf('%d',nbins(i)),' grains']; + end + str2{end+1,1} = [sprintf('%s',datestr(now,'dd.mm.yy HH:MM')),' voxel used: ',sprintf('%d / %d',... + nvoxBins(i),round(domain.VOL0matrix*fracBin(i)))]; + str2{end+1,1} = ' '; + + if isgui + set(gui.text_handles.Status,'String', str1); + else + disp(str1); + end + showLogInfo(str2,isgui,gui); + pause(0.01); + + end + + % remove bins with no members + boolOK = nbins~=0; + rbins = rbins(boolOK); + nvoxBins = nvoxBins(boolOK); + grains.binVol = grains.binVol(boolOK); + nbins = nbins(boolOK); + + % TODO: why is this switch-off here? + % if ~any(rbins == domain.dx/2) + % rbins = [domain.dx/2 rbins]; + % nbins = [0 nbins]; + % end + + % ensure smallest bin class + if ~any(rbins == domain.dx) + rbins = [domain.dx rbins]; + nbins = [0 nbins]; + end + + % the voxel volume of all grains from the distribution + grains.VOLspheres = sum(grains.binVol.*nbins); + + % output data + grains.rbins = rbins; + grains.nbins = nbins; + grains.Nbins = nbins; + grains.nvoxBins = nvoxBins; + +else + % create a diameter binning vector considering the minimum grid + % discretization + dbins = domain.dx:domain.dx:grains.rmax*2; + % radius binning vector + rbins = dbins/2; + % get the counts per bin + % nbins = hist(grains.dia_raw,dbins); + % --- account for new Matlab behaviour of histogram vs hist + d = diff(dbins)/2; + edges = [dbins(1)-d(1), dbins(1:end-1)+d, dbins(end)+d(end)]; + edges(2:end) = edges(2:end)+eps(edges(2:end)); + % nbins = histcounts(grains.dia_raw,edges); + N = histcounts(grains.dia_raw,edges,'Normalization','cdf'); + + tmp_hist = [[0 rbins]' [0 N]']; + + do_old = false; + %% OLD WAY + if do_old + % remove bins with no members + rbins = rbins(nbins~=0); + nbins = nbins(nbins~=0); + + if ~any(rbins == domain.dx/2) + rbins = [domain.dx/2 rbins]; + nbins = [0 nbins]; + end + + if ~any(rbins == domain.dx) + rbins = [domain.dx rbins]; + nbins = [0 nbins]; + end + + % get the voxel volume per grain radius + grains.binVol = zeros(1,numel(rbins)); + for i = 1:numel(rbins) + sphere = getSubBodyCoords(grains.shape,grains.axes,rbins(i),domain.dx); + grains.binVol(i) = size(sphere,1); + end + % the voxel volume of all grains from the distribution + grains.VOLspheres = sum(grains.binVol.*nbins); + + % how many copies of the distribution we need to fill the matrix + grains.ncopies = domain.VOL0matrix/grains.VOLspheres; + + grains.rbins = rbins; + grains.nbins = nbins; + grains.Nbins = round(nbins*grains.ncopies); + grains.nvoxBins = grains.Nbins.*grains.binVol; + grains.nbins = grains.Nbins; + + %% NEW WAY - use cumulative histogram + else + nbins = zeros(size(rbins)); + nvoxBins = zeros(size(rbins)); + + % get the voxel volume per individual grain radius + grains.binVol = zeros(1,numel(rbins)); + + % interpolate the input histogram on the radius binning vector + tmpCumVol = interp1(tmp_hist(:,1),tmp_hist(:,2),rbins); + fracBin = [tmpCumVol(1) diff(tmpCumVol)]; + + remainVox = 0; + cc = 0; + for i = fliplr(1:numel(rbins)) + cc = cc + 1; + sphere = getSubBodyCoords(grains.shape,grains.axes,rbins(i),domain.dx); + grains.binVol(i) = size(sphere,1); + nbins(i) = round((remainVox + domain.VOL0matrix*fracBin(i))/grains.binVol(i)); + nvoxBins(i) = nbins(i)*grains.binVol(i); + remainVox = domain.VOL0matrix*sum(fracBin(i:end))-sum(nvoxBins(i:end)); + + str1 = ['INIT - prepareVoxelGSD: bin classes done: ',sprintf('%d',round(100*cc/numel(rbins))),'%']; + if cc == 1 + str2{1,1} = [sprintf('%s',datestr(now,'dd.mm.yy HH:MM')),' r bin class ',num2str(i),... + ' (',sprintf('%5.4f',rbins(i)),'m) ',sprintf('%d',nbins(i)),' grains']; + else + str2{end+1,1} = [sprintf('%s',datestr(now,'dd.mm.yy HH:MM')),' r bin class ',num2str(i),... + ' (',sprintf('%5.4f',rbins(i)),'m) ',sprintf('%d',nbins(i)),' grains']; + end + str2{end+1,1} = [sprintf('%s',datestr(now,'dd.mm.yy HH:MM')),' voxel used: ',sprintf('%d / %d',... + nvoxBins(i),round(domain.VOL0matrix*fracBin(i)))]; + str2{end+1,1} = ' '; + + if isgui + set(gui.text_handles.Status,'String', str1); + else + disp(str1); + end + showLogInfo(str2,isgui,gui); + pause(0.01); + + end + + % remove bins with no members + boolOK = nbins~=0; + rbins = rbins(boolOK); + nvoxBins = nvoxBins(boolOK); + grains.binVol = grains.binVol(boolOK); + nbins = nbins(boolOK); + + % TODO: why is this switch-off here? + % if ~any(rbins == domain.dx/2) + % rbins = [domain.dx/2 rbins]; + % nbins = [0 nbins]; + % end + + % ensure smallest bin class + if ~any(rbins == domain.dx) + rbins = [domain.dx rbins]; + nbins = [0 nbins]; + end + + % the voxel volume of all grains from the distribution + grains.VOLspheres = sum(grains.binVol.*nbins); + + % output data + grains.rbins = rbins; + grains.nbins = nbins; + grains.Nbins = nbins; + grains.nvoxBins = nvoxBins; + disp(sum(nvoxBins)/domain.VOL0); + end +end + +return + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . diff --git a/functions/updateIndexList.m b/functions/updateIndexList.m new file mode 100644 index 0000000..a03b615 --- /dev/null +++ b/functions/updateIndexList.m @@ -0,0 +1,174 @@ +function [indexList,N] = updateIndexList(method,M,marg,r,xyzr0,domain,grains) +%updateIndexList creates a list with free voxel positions within the domain +% +% Syntax: +% updateIndexList(method,M,marg,r,xyzr0,domain,grains) +% +% Inputs: +% method - string ('std' | 'hull' | 'hull_tight') +% M - matrix (marker matrix with occupied voxels) +% marg - scalar (with of margin in voxel units) +% r - scalar (current grain radius) +% xyzr0 - matrix (all already placed grains centers) +% domain - struct with domain data +% grains - struct with grain data +% +% Outputs: +% indexList - List of empty voxels where a grain center could be +% N - length of indexList +% +% Example: +% [list,~] updateIndexList('std',M,marg,r,xyzr0,domain,grains) +% +% Other m-files required: +% none +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +switch method + case 'std' + Mv = true(size(M)); + % now mark all inner voxels within for searching a new center point + r2 = ceil(r/domain.dx); + ma = 2*marg-r2; + marg = ma; + % mark all margin voxels + Mv(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg) = false; + % add all spheres from M + Mv(M) = true; + % indexList = (1:numel(Mv))'; + % indexList = [indexList(~Mv(:));indexList(Mv(:))]; + % N = numel(Mv(:))-sum(Mv(:)); + indexList_tmp = (1:numel(Mv))'; + indexList = indexList_tmp(~Mv(:)); + N = numel(indexList(:)); + + case 'hull' + % old way: mark only voxels in a certain grain hull + Mv = true(size(M)); + % now mark all inner voxels for searching a new center point + r2 = ceil(r/domain.dx); + ma = 2*marg-r2; + marg = ma; + + Mv(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg) = false; + + Nxyz = find(xyzr0(:,4)<0,1,'first')-1; + r_old = 1000; + + for nn = 1:Nxyz + r_now = xyzr0(nn,4); + if r_now < r_old + sphere = getSubBodyCoords(grains.shape,grains.axes,xyzr0(nn,4)+r,domain.dx); + r_old = r_now; + end + + % move the sphere to the current center point + spnew = sphere + [xyzr0(nn,1)*ones(length(sphere),1) ... + xyzr0(nn,2)*ones(length(sphere),1) .... + xyzr0(nn,3)*ones(length(sphere),1)]; + + [ix1,~] = find(spnew(:,1)size(Mv,1)-marg); + [ix2,~] = find(spnew(:,2)size(Mv,2)-marg); + [ix3,~] = find(spnew(:,3)size(Mv,3)-marg); + ix = unique([ix1;ix2;ix3]); + spnew(ix,:) = []; + + % get indices of the current sphere into M + index = sub2ind(size(M), spnew(:,1), spnew(:,2), spnew(:,3)); + % mark the "occupied" region + Mv(index) = true; + end + indexList_tmp = (1:numel(Mv))'; + indexList = indexList_tmp(~Mv(:)); + N = numel(indexList(:)); + + case 'hull_tight' + Mv = true(size(M)); + % now mark all inner voxels for searching a new center point + r2 = ceil(r/domain.dx); + ma = 2*marg-r2; + marg = ma; + + Mv(marg+1:end-marg,marg+1:end-marg,marg+1:end-marg) = false; + + Nxyz = find(xyzr0(:,4)<0,1,'first')-1; + if isempty(Nxyz) + error('There is no more free place left in voxel index list.\n'); + end + r_old = 1000; + + indexList = zeros(Nxyz,2); + for nn = 1:Nxyz + r_now = xyzr0(nn,4); + if r_now < r_old + sphereInner = getSubBodyCoords(grains.shape,grains.axes,xyzr0(nn,4),domain.dx); + sphereOuter = getSubBodyCoords(grains.shape,grains.axes,xyzr0(nn,4)+2*r,domain.dx); + r_old = r_now; + sphere = setdiff(sphereOuter,sphereInner,'rows'); + nVoxInHull = size(sphere,1); + end + + % move the sphere to the current center point + spnew = sphere + [xyzr0(nn,1)*ones(length(sphere),1) ... + xyzr0(nn,2)*ones(length(sphere),1) .... + xyzr0(nn,3)*ones(length(sphere),1)]; + + [ix1,~] = find(spnew(:,1)size(Mv,1)-marg); + [ix2,~] = find(spnew(:,2)size(Mv,2)-marg); + %[ix3,~] = find(spnew(:,3)size(Mv,3)-marg); + + % in z-dimension, accept positions in upper margin + % to create a surface pattern + [ix3,~] = find(spnew(:,3)>size(Mv,3)-marg); + ix = unique([ix1;ix2;ix3]); + spnew(ix,:) = []; + + % get indices of the current sphere into M + index = sub2ind(size(M), spnew(:,1), spnew(:,2), spnew(:,3)); + + % get voxels in surrounding hull + if ~grains.boolPreferClusters + % relate to free voxels + indexList(nn,:) = [nn sum(~M(index))/nVoxInHull]; + else + % relate to filled voxels + indexList(nn,:) = [nn sum(M(index))/nVoxInHull]; + end + end + indexList = indexList(~isnan(indexList(:,2)),:); + N = size(indexList,1); +end + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . \ No newline at end of file diff --git a/gprgravel_gui.png b/gprgravel_gui.png new file mode 100644 index 0000000..b6bf69f Binary files /dev/null and b/gprgravel_gui.png differ diff --git a/input/GSD/histogram.txt b/input/GSD/histogram.txt new file mode 100644 index 0000000..ef47207 --- /dev/null +++ b/input/GSD/histogram.txt @@ -0,0 +1,14 @@ +0.0630 0.0000 +0.1120 0.0088 +0.2000 0.0244 +0.3550 0.0527 +0.6300 0.0928 +1.1200 0.1396 +2.0000 0.2060 +4.0000 0.3310 +8.0000 0.5019 +16.0000 0.7080 +25.0000 0.8302 +31.5000 0.8837 +50.0000 0.9630 +100.0000 1.0000 diff --git a/input/GSD/histogram_with_header.txt b/input/GSD/histogram_with_header.txt new file mode 100644 index 0000000..9671807 --- /dev/null +++ b/input/GSD/histogram_with_header.txt @@ -0,0 +1,15 @@ +# mm - +0.0630 0.0000 +0.1120 0.0088 +0.2000 0.0244 +0.3550 0.0527 +0.6300 0.0928 +1.1200 0.1396 +2.0000 0.2060 +4.0000 0.3310 +8.0000 0.5019 +16.0000 0.7080 +25.0000 0.8302 +31.5000 0.8837 +50.0000 0.9630 +100.0000 1.0000 \ No newline at end of file diff --git a/input/GSD/list.txt b/input/GSD/list.txt new file mode 100644 index 0000000..627fbb2 --- /dev/null +++ b/input/GSD/list.txt @@ -0,0 +1,2188 @@ +# mm +3.747251541 +7.097364911 +5.310748233 +3.682905258 +4.561395568 +3.429751186 +2.488581274 +5.043093034 +2.731434928 +3.206197581 +8.197549435 +3.530218501 +4.889670022 +2.939932378 +4.054514375 +7.242472407 +3.988920713 +3.228874771 +2.972147681 +2.620771173 +9.929256318 +5.809755623 +3.942869648 +2.815596439 +3.842491538 +2.536415589 +5.744318294 +3.026752723 +3.437124224 +11.45276196 +8.942070107 +3.953308968 +3.382903746 +3.648392157 +3.828883505 +4.791033605 +17.82572912 +3.126028425 +4.820391358 +8.369852408 +2.552055642 +2.249949601 +2.983563336 +7.809238607 +7.823075309 +3.024441948 +5.915684575 +2.908673021 +6.769333973 +3.448379145 +6.010599581 +5.262946653 +3.087608637 +4.775464638 +2.462271037 +6.495483023 +2.517292361 +4.673550609 +2.55711403 +10.69976765 +3.066128222 +6.431170952 +3.8619186 +8.46886212 +2.441947288 +5.568227454 +3.487891214 +5.694731766 +22.91127712 +3.845496126 +2.892549303 +2.924548714 +3.2581144 +5.41041777 +3.509004025 +5.209349041 +3.66983976 +3.524397057 +4.406196356 +2.479290545 +3.314995967 +6.02656439 +3.068093214 +5.799114272 +3.494352455 +3.461497419 +2.462971176 +5.209941248 +4.137853178 +4.580134775 +3.121544425 +3.362704334 +2.343735375 +2.373217094 +3.643446685 +4.404386035 +9.261695942 +5.063795925 +16.09804295 +3.581941845 +4.567309766 +2.900904621 +4.517764904 +11.68377204 +2.592848361 +4.964785201 +6.957109109 +2.663395101 +3.008392251 +4.821348592 +2.908806475 +3.274777786 +5.366366078 +4.120424431 +5.131399876 +4.464480201 +6.156175229 +6.590418142 +3.723118997 +10.11109158 +7.945303306 +2.410535969 +8.846385539 +3.078057822 +4.847225567 +3.39041188 +3.643388602 +2.659947888 +3.041772045 +2.680600871 +2.619638546 +2.996328857 +5.100753997 +4.206683499 +3.203160025 +2.819179337 +5.321025945 +5.460358175 +5.430000644 +4.236625589 +3.236875991 +4.012489249 +13.82210208 +3.613609293 +2.985855346 +3.426100404 +2.477616424 +5.904190888 +2.65893709 +5.45988453 +4.455986684 +3.770430225 +3.195695449 +3.498665945 +11.88640504 +3.570492175 +4.43740367 +2.933776176 +5.943485692 +6.450765861 +2.415430766 +4.63340213 +5.296106354 +7.778907425 +4.434089116 +2.7387136 +3.376425797 +3.463717674 +3.347919474 +2.976495125 +3.374834185 +3.420755703 +31.08910458 +6.873779491 +3.252632613 +3.90267741 +4.152221858 +5.512195634 +3.054702957 +3.296733759 +3.647802406 +2.918694981 +4.314614042 +4.163126076 +3.148445257 +4.768778479 +4.835427803 +4.146296061 +3.777772866 +3.502413378 +3.06659181 +2.738049489 +5.207737724 +3.309145258 +2.447218915 +2.188163681 +2.690322231 +2.642538293 +4.472454008 +5.807004416 +3.761190552 +3.810014319 +2.706321548 +3.885397187 +4.484277463 +5.952303686 +16.10633227 +2.721781505 +3.677808759 +3.139833401 +6.15957686 +4.593130761 +2.541087066 +2.916933389 +2.860562031 +3.70651304 +4.622196208 +2.689076942 +4.832493072 +4.580866088 +3.818514167 +6.082386789 +2.23401446 +4.835453454 +3.746516797 +2.287866621 +7.833543092 +2.538805971 +4.285002792 +3.66682642 +2.892676265 +3.913439647 +4.67291006 +2.885009768 +3.070953948 +5.468875435 +2.884082765 +6.303300522 +3.773079079 +2.930120722 +6.127920885 +5.304450009 +2.888471164 +3.903193971 +3.631537873 +10.17796927 +3.411954026 +3.975494336 +12.02451484 +3.819884992 +4.450390959 +10.65652083 +3.70536764 +5.139812525 +2.870291927 +5.069196838 +2.759931252 +10.1055112 +6.64364124 +4.7258353 +5.264861617 +5.057000106 +2.425296076 +2.743030984 +4.773525084 +5.118821475 +2.47257317 +6.399773071 +4.863090015 +2.236741154 +3.500895106 +3.36961559 +3.689045452 +2.658784068 +5.748158089 +2.767133836 +8.142855789 +3.025743522 +3.684303402 +2.499358706 +3.51877259 +9.476831295 +4.774016308 +5.593391424 +3.112423051 +3.742003616 +4.050225262 +4.117836347 +2.137573806 +7.881571082 +3.470362485 +4.654529511 +2.789282822 +2.578411543 +2.85062514 +4.599266218 +4.121275603 +2.440778408 +2.525529534 +5.660598072 +3.113242556 +4.128227444 +3.942069572 +3.292398844 +2.953736917 +24.78673395 +11.09938233 +3.223238251 +5.034120009 +3.141839165 +3.640113271 +4.422055216 +5.423698992 +3.267289552 +3.732517181 +3.40287933 +11.49985979 +6.674227606 +4.780894936 +2.827389229 +11.56780827 +3.740415644 +2.469851548 +2.932025863 +2.877544992 +2.687841018 +3.839191128 +2.851010302 +3.894694684 +10.21547686 +5.179146197 +18.53471482 +12.09876551 +5.284224423 +5.253681893 +5.360351072 +10.37268723 +3.402434845 +4.448990693 +7.289055518 +2.550824836 +8.577053209 +3.605731999 +7.287872218 +7.124474485 +5.684122984 +2.937520306 +3.617561036 +2.340740889 +3.744891289 +6.865268582 +5.498440689 +4.947703748 +6.79407131 +4.766392715 +4.808595448 +3.878397598 +3.564482524 +2.854296821 +6.202233957 +4.413702181 +6.103278439 +5.522233345 +5.377918725 +3.650510929 +3.164543651 +2.877486855 +2.725423807 +5.189133838 +3.687472801 +4.048382061 +2.232975533 +19.64341928 +4.053891885 +8.672863772 +3.399573228 +6.828086958 +23.5733086 +3.951013002 +4.32225598 +5.219025298 +4.578863341 +3.708774918 +2.57215255 +2.633728558 +9.423578138 +3.301348766 +19.35089885 +3.142549227 +4.282486967 +6.095497135 +11.21538889 +6.295081832 +2.646232944 +3.718887374 +10.67980411 +4.680018123 +12.70333553 +6.604840458 +2.61179033 +4.694590717 +3.790489931 +3.384488411 +3.139796512 +8.135978534 +4.458169188 +2.992298916 +5.205937151 +6.136953302 +2.563925639 +21.46841712 +3.579164363 +7.425838247 +5.942077947 +9.449404018 +5.148953192 +4.270990656 +3.233306162 +9.181214335 +3.182524551 +2.716759947 +2.393127007 +4.250414377 +3.567087256 +2.18878124 +3.925681109 +4.162895209 +5.172884948 +6.66635576 +2.990115281 +3.183070117 +2.87541287 +9.016328777 +6.587402206 +8.354366625 +2.760947173 +5.054495168 +5.647462299 +6.529072146 +9.206143715 +2.510586042 +3.341722172 +2.892405463 +3.737414078 +3.057690747 +2.713998717 +5.61394891 +9.148261235 +3.445075506 +8.161282169 +5.184666658 +14.09601653 +2.517105725 +6.914985275 +2.588554616 +2.839171664 +14.83154369 +2.968947651 +6.733646303 +3.364798967 +2.563682316 +4.391234384 +2.723241049 +4.714632828 +5.075458289 +11.45225716 +2.744187326 +5.120435773 +2.337045551 +7.983591115 +2.41391817 +74.1963466 +4.83268515 +8.732034405 +3.216371033 +4.323602093 +3.0458147 +30.36298782 +4.610531325 +19.48981788 +4.788103171 +23.81504616 +6.906477937 +2.851797582 +3.181747083 +4.295127565 +4.210808554 +19.29223587 +8.089915932 +14.58899244 +4.169003028 +2.247421164 +18.97452267 +5.701543779 +2.947806023 +3.194484917 +3.17269317 +3.202779097 +5.29923418 +25.02370768 +4.07198712 +2.93476917 +6.511709819 +2.563046989 +7.128915593 +4.15179212 +4.36129195 +2.201628806 +3.039513188 +4.09860882 +2.588555011 +2.85642892 +6.087898464 +2.823150281 +3.189350891 +3.449821719 +4.032214398 +4.37897628 +11.50408278 +4.134895554 +6.208815985 +2.239717973 +2.755799622 +2.405984563 +3.878898356 +2.808776996 +9.283404996 +7.525215315 +2.697036011 +5.749753703 +6.87929351 +2.403316626 +18.57042932 +2.840413565 +8.454590689 +2.435647379 +14.21041416 +3.290729857 +2.174233154 +9.880744132 +4.872015067 +2.423947689 +30.57718062 +6.459123133 +6.211531691 +4.532521376 +3.774039529 +5.363906634 +2.597656865 +4.500213473 +2.622700359 +4.24599648 +3.030387953 +5.564575315 +2.687998133 +4.978102652 +3.217829303 +2.692635594 +5.315940294 +2.952115885 +8.965939192 +23.90590758 +7.909341868 +2.478338746 +2.744022544 +5.136484328 +3.889716206 +3.555134775 +4.218746846 +18.11960739 +4.415149029 +3.477686417 +2.89566086 +3.539827163 +2.412179831 +11.91667762 +5.902668745 +3.271084664 +4.9434469 +3.395975916 +2.922101828 +14.72062062 +3.906506903 +3.200827074 +3.515889597 +4.245933192 +4.169021725 +13.9079176 +3.089387059 +8.593364246 +2.145148049 +2.814485558 +10.26918175 +7.28098177 +3.956023359 +7.413857066 +4.454856037 +3.418657955 +5.831954625 +2.95053583 +5.112376354 +3.048486138 +5.358143643 +6.027168677 +7.44021392 +4.149686916 +5.29992902 +2.6168778 +2.443482083 +8.901111374 +6.003326109 +4.793460455 +11.01454723 +2.53785258 +3.236527626 +2.785420774 +5.86124321 +7.235166599 +2.623547431 +2.801654303 +15.86999909 +3.534676098 +4.499577011 +4.671251081 +6.488581639 +9.052765952 +11.9148313 +4.658462138 +4.025891774 +6.708399677 +4.100050639 +2.610866178 +6.307513865 +16.70584148 +2.338378734 +7.228598176 +2.680476272 +4.026441998 +3.994619559 +7.40492039 +2.386401153 +2.382329929 +14.79331234 +14.36122287 +2.591301966 +5.601081812 +6.264974862 +6.30943651 +3.800670902 +7.511341463 +5.727562638 +2.245114981 +2.745881383 +4.303374416 +3.134533304 +3.735627478 +6.179146264 +2.856265068 +11.16457528 +3.078210145 +5.58990571 +2.575348341 +2.753343963 +2.252788385 +3.669359065 +4.30525845 +23.75941252 +2.971801917 +2.815819993 +6.119302036 +8.723562842 +25.8119114 +2.694459409 +12.49725138 +4.406805821 +10.28781192 +26.52986927 +3.674771612 +3.940635427 +2.859023321 +6.580393152 +10.23903453 +5.611511526 +6.793801123 +2.919241113 +2.404402303 +3.023027021 +2.680156546 +2.859063342 +25.57960401 +8.906448186 +12.1799468 +10.64674403 +4.538805361 +8.369757627 +3.235672049 +3.32159282 +4.122010214 +3.075132589 +2.789113234 +2.20315335 +8.993199077 +3.069293777 +6.212145809 +3.1886471 +3.526888965 +2.711523239 +2.631213257 +9.191844265 +2.893149916 +3.25382564 +6.038807147 +7.932527542 +2.759348037 +3.528906173 +3.127533194 +2.656306189 +9.872867787 +13.8220843 +3.810170578 +2.797545033 +11.42655213 +6.674456128 +4.606025283 +6.714042391 +2.184387788 +19.05617863 +2.80070108 +2.99971362 +3.395072145 +6.98880789 +16.89979397 +2.847073835 +2.883347001 +3.341758383 +6.170207563 +3.752034268 +3.974445639 +10.57824269 +22.22804226 +6.422991135 +7.272328139 +6.448954832 +5.868063873 +3.384735634 +7.433579104 +3.99498596 +7.616634764 +6.232185286 +5.276098498 +4.374702171 +6.652505624 +6.695730631 +2.417820095 +4.265934298 +5.415504398 +5.048036573 +3.284384826 +4.604202589 +17.67386158 +3.399310101 +2.888568861 +5.125740454 +2.864854665 +3.299203333 +10.52356279 +8.498317325 +10.97660891 +5.074210546 +2.097277915 +2.454533695 +2.745685971 +5.788524939 +4.996545193 +5.982924511 +2.761852684 +4.245354584 +4.842123562 +3.01501037 +10.86133114 +5.708193228 +4.653544812 +16.90700078 +2.714168381 +2.857546079 +2.778517089 +3.49531984 +6.084348043 +3.165742424 +2.3548423 +4.243450606 +3.898298725 +2.303483167 +3.106038869 +3.05998595 +11.77553841 +21.90541213 +2.376661567 +5.727431494 +4.019170793 +8.029163916 +5.422630883 +6.450478324 +3.299541081 +5.318285938 +21.07444423 +4.287455304 +3.26376662 +26.72491408 +5.607492861 +4.298597295 +18.55257076 +10.28977691 +2.986493876 +3.269277019 +3.704367467 +4.714918104 +26.28472245 +4.025259143 +4.605633495 +3.600345443 +3.308196415 +2.913251621 +3.190086201 +2.495048984 +2.808239863 +3.610061443 +2.740696565 +5.361239458 +2.37011844 +6.837601955 +5.776302982 +5.345949107 +4.421313972 +7.086269004 +3.322578119 +5.323016173 +3.120056533 +5.314244815 +4.422496736 +2.740755283 +7.172139313 +2.96686778 +2.916249398 +3.270380663 +3.094030178 +20.23493511 +4.86615079 +2.965071346 +4.761550959 +5.315936565 +6.434206171 +2.433003933 +2.402599291 +4.083311145 +3.725916568 +6.44192609 +4.962144404 +3.034250721 +2.823645705 +9.278178184 +4.841192222 +6.513756056 +9.97260984 +2.596255833 +4.730688784 +2.847888743 +4.716770669 +2.509273656 +4.653459819 +3.329022387 +3.237349931 +4.669342932 +3.444942204 +4.279085562 +2.763309116 +5.61397771 +2.841765196 +2.297123067 +3.933870839 +2.338228807 +2.783512668 +3.140887269 +6.936848325 +4.072584952 +3.247587984 +2.826777333 +11.85556823 +5.358145165 +4.690417512 +2.33847071 +2.143265684 +20.09011874 +9.406784829 +15.7789345 +4.678938329 +2.297044345 +14.16285128 +9.477768365 +3.836394999 +5.350121072 +3.071165628 +3.142450562 +3.120742053 +2.775914178 +2.75447982 +4.021716757 +3.984737735 +5.202037479 +3.439232707 +5.61066676 +2.709621021 +2.542774042 +2.518516539 +4.532139905 +4.911972171 +2.566414573 +7.028084527 +3.141241585 +3.518496825 +3.44191478 +3.160394479 +2.621349093 +2.387525055 +9.621665382 +3.036272808 +2.469472752 +4.676117809 +19.92363491 +14.94665664 +3.906764928 +3.542625918 +2.640290378 +2.38047999 +2.204551711 +5.448792388 +8.076938948 +3.821936507 +3.546637214 +16.50840252 +3.781417313 +29.21901998 +3.468997253 +9.931132044 +2.269570378 +4.488073278 +6.164269422 +2.772896293 +6.17914341 +7.299816626 +3.217305639 +4.008302835 +3.583404578 +2.694162351 +5.813264856 +2.712298258 +6.998908638 +10.02849197 +2.404433571 +4.925582445 +2.466762463 +4.458100923 +2.461797615 +2.610922829 +3.939521035 +4.42104044 +9.381101342 +3.326777375 +2.843667769 +3.937620829 +4.95678249 +8.93447352 +3.725663163 +4.791057729 +5.525394244 +3.997220889 +2.792962055 +3.103038994 +6.368046545 +3.755101093 +5.377997179 +7.665619716 +5.460326604 +3.187585829 +3.322549632 +2.450532749 +3.814824508 +11.94195247 +7.266206236 +12.13236959 +5.342919011 +3.591461809 +9.055302079 +6.012010024 +5.749382847 +9.647835353 +2.606794438 +2.736781212 +2.240747053 +3.223689427 +3.41202241 +3.714723854 +5.633945035 +3.703600635 +4.240212061 +6.661164738 +3.300220798 +2.434069637 +6.1579121 +5.987310315 +2.60643087 +7.611072118 +2.061482507 +3.046672167 +2.730766072 +3.743271653 +4.865370143 +2.764788256 +10.79526648 +4.828893502 +3.084032162 +3.785096495 +2.538004767 +5.160226861 +3.931254519 +2.32189279 +5.097819034 +6.869531796 +7.53941999 +4.635284209 +12.19027301 +3.586058258 +6.1781212 +3.584162186 +5.703354482 +3.314147788 +3.408071694 +2.381316153 +2.525414376 +5.536524956 +3.247372659 +3.800345727 +3.63037787 +3.3433429 +3.343054284 +3.328388836 +2.606117807 +2.638493172 +4.724622034 +7.676209607 +7.537536194 +2.478269341 +2.663970527 +5.043463556 +13.09052452 +3.107491074 +24.82093664 +7.663245199 +2.514007811 +5.769964969 +2.366027404 +3.600108063 +4.895760397 +2.658000944 +10.39100263 +3.182825807 +3.581613855 +2.898167921 +4.694013587 +9.210795386 +4.049221397 +6.955431461 +3.771811195 +4.023719608 +3.114274397 +2.991283447 +6.016231114 +2.907724094 +5.453177195 +8.932576891 +7.272092378 +2.904846989 +8.93659878 +6.63718949 +7.704819887 +4.339417417 +2.686684308 +6.991232518 +3.708184986 +6.714397438 +4.403786099 +7.026606761 +5.535095882 +3.740012834 +4.129181359 +5.763960911 +3.022998367 +2.588493457 +5.482774597 +3.528475347 +8.186819838 +3.922968774 +4.555336102 +8.355869686 +11.83926762 +2.960846918 +5.195941933 +5.230762257 +9.136494467 +9.062886575 +4.144616116 +4.549058971 +3.062168987 +9.555667727 +7.316664955 +4.098410087 +7.69099137 +4.808310543 +2.892373896 +4.255972498 +5.813701015 +2.376227468 +17.89694752 +2.989932241 +2.499926764 +2.309073945 +3.51482393 +2.90781727 +8.252787462 +6.327366976 +3.243550595 +25.28067528 +6.931504587 +3.690397399 +25.64453049 +2.523508853 +5.613570947 +9.133322004 +2.327209912 +3.101740452 +8.754525327 +4.651017629 +4.335268671 +5.400151862 +3.871176173 +2.790978482 +11.67659779 +3.458807173 +5.071670726 +10.42582902 +2.838525034 +3.402792418 +2.620350945 +3.305268358 +2.721572355 +6.020395624 +5.276950458 +2.223173525 +5.599851366 +4.434526366 +5.081669441 +4.299069609 +3.035115289 +5.851855794 +7.135362498 +14.62449698 +3.68968057 +2.535016814 +3.735506991 +2.817438043 +4.803186728 +5.125227215 +7.691404693 +3.519506185 +2.89192714 +6.379526995 +3.630375789 +2.598953818 +4.812926939 +11.52581729 +4.597868676 +5.605541979 +5.618711303 +5.705907272 +2.85106803 +2.996331477 +4.794269462 +4.157058166 +10.30455707 +5.337232483 +2.708437375 +4.396677858 +3.361631537 +3.909768294 +7.105368111 +4.112976454 +4.708386758 +12.18440569 +5.815549177 +2.50599015 +12.05123989 +5.838168839 +4.438724286 +2.902523969 +2.370196681 +22.11121033 +2.446988911 +9.43968336 +20.14096555 +8.354176997 +2.463927089 +5.125098923 +3.445503942 +4.653450776 +3.117100163 +4.08501463 +5.585220637 +7.82628337 +2.746483016 +2.634835133 +8.057487636 +6.132658162 +6.329477285 +5.74280058 +4.301917107 +4.909794231 +23.35693792 +4.928442645 +5.881887058 +2.991166757 +8.303830556 +2.666844968 +4.128704692 +6.848947171 +2.881680288 +3.733950534 +5.237995449 +2.954000559 +2.917963693 +4.654774612 +3.075232882 +5.425356971 +2.939922649 +5.039320066 +3.17875957 +9.479185732 +4.292596849 +6.465848785 +5.41944719 +4.283275564 +11.09828279 +7.148950289 +9.430535617 +3.871440376 +7.280681217 +14.73142026 +2.537087677 +3.229181022 +2.900993958 +5.269244285 +5.711934975 +37.72597475 +5.522312169 +7.437393782 +3.231288453 +3.602372028 +4.171952023 +3.259886051 +8.128109372 +3.859749519 +4.857123268 +4.021307422 +2.925060646 +4.041137489 +5.036737348 +8.956675917 +5.402846715 +4.278602726 +2.284913577 +3.814098305 +3.606826635 +4.561199369 +16.05428079 +2.421808586 +8.692592818 +2.70331766 +3.177199461 +5.172204112 +2.803566176 +4.764524215 +2.39603117 +4.049891768 +3.139943395 +6.765101826 +4.912653653 +3.460183905 +4.976502481 +6.338761887 +5.633213522 +4.5634456 +6.580084218 +16.71888687 +4.075858861 +5.730522631 +3.774215004 +2.871357589 +17.35393947 +3.738329022 +2.731623594 +4.371661605 +4.573131538 +3.356793205 +5.201251074 +3.206067919 +7.050154119 +3.847867433 +4.987939669 +4.946885511 +3.714858885 +4.836455375 +2.876779385 +10.27853236 +4.087371245 +3.289901476 +3.459403929 +8.068427588 +2.397322417 +4.855240031 +2.785906044 +10.89835394 +2.21410485 +2.800687758 +2.643262057 +5.036580711 +12.9575231 +2.561178781 +5.006903298 +2.812691397 +3.271133808 +4.143470869 +6.737799523 +2.750914537 +3.261038657 +3.380788624 +5.714605738 +4.165673999 +3.290536992 +6.409958598 +3.592833415 +3.849921893 +5.588418059 +3.254565752 +2.605977057 +9.791592114 +3.008217477 +7.381030282 +2.694229385 +7.017355866 +3.241313388 +5.531511638 +6.092725036 +4.090598281 +4.817830167 +14.49929931 +3.269657037 +4.994328667 +8.683882357 +5.043971233 +4.035873443 +2.254767361 +6.388107008 +3.314676388 +3.112471174 +6.79961023 +2.914714637 +2.82112838 +2.611301759 +2.387723994 +5.378283281 +9.344674388 +3.679072512 +2.64209574 +6.742994579 +3.13762792 +5.33397735 +4.466626033 +3.059311697 +2.756463555 +4.018451722 +5.842375124 +6.429158741 +13.15251198 +13.12654924 +4.28985537 +7.413760787 +5.024785392 +4.12167125 +8.836135666 +6.156893769 +8.73034903 +4.780154726 +7.138137746 +2.865696306 +3.16097597 +2.157724229 +4.746713368 +2.911735248 +5.883247511 +9.882652 +5.58725551 +5.248732476 +3.630360667 +8.761816741 +2.721174469 +12.24599254 +2.238319437 +10.42257646 +3.342172185 +8.462920703 +4.845623969 +8.956555209 +2.794659968 +4.763450397 +4.28346765 +2.670104167 +3.775033652 +5.849886406 +5.491352433 +13.8180979 +3.127631399 +3.375364804 +4.16265082 +6.758652331 +5.574806446 +5.35664616 +4.416859998 +5.142223594 +3.989564526 +4.1982908 +8.389374093 +2.322828063 +5.6047234 +3.645068293 +11.47412709 +2.514682399 +2.845813195 +2.922952076 +2.542186826 +12.97309834 +4.974514288 +2.588674878 +4.584832457 +4.774462428 +2.954294836 +9.870786932 +7.951979213 +5.694204638 +4.125719909 +12.08662337 +2.899699946 +3.572139331 +4.563360426 +9.498662652 +2.344084253 +4.37562488 +6.810214955 +18.40929132 +4.571246316 +9.617469306 +2.537446044 +3.630416276 +4.359233642 +9.760180548 +6.253822949 +3.065362984 +15.6132804 +2.559810056 +4.323298175 +3.411860976 +2.463905628 +2.431189383 +3.299136738 +4.266056084 +3.178707818 +6.358436693 +3.619993525 +2.7382479 +7.23240946 +5.674518933 +11.48874297 +3.018399848 +7.929440576 +5.903229802 +9.848819931 +7.389085159 +3.744315703 +3.316165934 +5.525485047 +4.08980291 +8.321189922 +7.602388492 +3.115009067 +2.372067483 +4.431151702 +2.841951655 +3.364550214 +4.00182239 +4.544445866 +7.4403209 +4.779996181 +2.342678889 +4.568595977 +3.279438272 +4.47881404 +2.737848205 +10.70150385 +8.121470323 +4.782444051 +3.822814846 +2.523849354 +5.859280344 +5.909094221 +6.413000981 +16.2321952 +4.772389065 +2.547823417 +14.51421836 +2.949555873 +4.654810798 +6.102765175 +5.355314455 +4.30213172 +2.412487341 +8.514307381 +7.073156019 +6.672069127 +10.07990412 +2.325127387 +4.607703282 +3.118413075 +8.422475313 +2.754622962 +2.199942173 +2.976370442 +5.30167593 +7.68163992 +3.108142998 +7.308661505 +2.212710589 +4.648264636 +5.955146308 +11.23497875 +6.664254877 +3.306097228 +4.054741015 +4.032773085 +9.554135712 +3.580835412 +2.410268638 +4.56118584 +5.079981383 +4.07451001 +6.307410441 +2.791787872 +5.709640101 +4.921370896 +3.557366175 +3.400046511 +4.067743048 +2.220411129 +2.942454232 +3.214703888 +5.776865991 +3.240900726 +11.13112338 +6.756830946 +3.364535295 +2.299916807 +2.317558632 +4.576210647 +6.882236502 +10.47330231 +3.377631697 +6.143267777 +3.482024161 +2.565612131 +4.139993055 +4.324657613 +2.236788949 +2.367882385 +2.528441594 +3.378788489 +13.7956525 +3.162957698 +2.688925502 +5.261763331 +3.646025271 +3.16756208 +2.638227537 +2.652616644 +5.392510279 +3.113104273 +11.74081988 +2.225235266 +3.114027543 +8.271085237 +3.274495947 +5.826186673 +4.477394211 +2.589070056 +4.545634181 +3.268281668 +9.837535408 +4.409580794 +2.604414567 +2.51706519 +6.13129661 +3.75512328 +2.728687036 +7.02468824 +4.202249967 +4.461683259 +7.232016531 +8.384602339 +12.81111065 +4.565905324 +7.202174499 +2.392305851 +4.812745566 +4.334973059 +2.510742827 +3.112291042 +13.23333827 +5.198619101 +4.313232778 +2.525880559 +3.51001311 +5.933548239 +4.180842898 +4.174914641 +3.622027208 +2.969609624 +8.756346173 +5.702454248 +24.75432627 +3.029294281 +3.636930859 +4.71476431 +2.858577271 +3.940490817 +3.157720113 +43.65395541 +8.878325831 +4.543651285 +3.057988474 +5.637885518 +4.809154971 +3.272682089 +5.473261607 +5.52471013 +2.191818866 +13.83481432 +4.99067364 +3.666997997 +4.963544135 +4.242971957 +2.470709575 +4.005999934 +12.84579235 +9.079182997 +8.033573659 +2.585752012 +3.46629904 +4.643614377 +4.956011476 +3.586164086 +7.829067799 +4.695282094 +4.604410681 +4.939260316 +4.356557518 +4.349152831 +3.117620798 +2.800484462 +3.291449611 +5.189046645 +5.950407173 +5.614837637 +4.261493128 +2.848748806 +5.366887213 +4.880586041 +5.273399438 +7.053724004 +2.913692557 +2.233485393 +2.546036993 +4.790277589 +5.052366627 +2.619551709 +5.862407525 +10.85905616 +9.740692713 +6.706809856 +3.901664822 +4.487358718 +4.31456218 +2.896158796 +3.530122771 +8.429770035 +4.8001793 +3.213077886 +4.750895306 +6.502505674 +16.73596231 +5.75080462 +2.20346469 +2.769488571 +5.631713614 +3.362010294 +3.342123222 +4.267595279 +2.98887798 +2.945708994 +11.37795723 +11.74477475 +2.388920908 +8.990691632 +4.73952378 +4.161013843 +8.40122035 +3.997145024 +2.376610741 +3.452454651 +4.520347006 +7.923017772 +4.942809691 +5.645576749 +6.30271488 +4.398683583 +2.914429927 +3.59947134 +7.555080576 +2.613564349 +3.054595625 +4.178615433 +2.869370207 +3.132886825 +3.822753104 +12.80745624 +3.09882794 +3.044074295 +4.4822626 +4.065666407 +5.848260476 +5.598245823 +8.085355099 +2.322960505 +5.326107567 +3.403815225 +3.682153479 +3.912822215 +4.10335796 +4.618936677 +9.815032101 +4.226582688 +4.494050445 +3.464662213 +20.95302582 +2.648475065 +4.585621006 +5.760802552 +5.098104613 +3.541946691 +5.032391821 +7.912634878 +5.228383645 +5.51665637 +4.525179806 +4.505868628 +4.029978333 +2.807893878 +2.664412955 +7.942868339 +2.878338434 +4.4920142 +2.930505164 +2.076153574 +4.282123484 +3.082320786 +7.367582708 +6.262558278 +7.906477366 +2.286175145 +6.468926848 +4.475999115 +4.033312088 +8.224751768 +4.652874413 +2.707677984 +2.149188274 +4.049654018 +2.720932403 +10.45949786 +2.835832698 +3.407060414 +9.424323401 +2.998216425 +4.796800936 +8.435137661 +4.537188353 +3.034262374 +7.4960797 +6.121311941 +2.819755798 +4.127293043 +5.30346801 +5.103634547 +6.749717337 +2.696091998 +3.706224273 +2.666269921 +2.641211731 +2.766917117 +4.104609103 +3.598471423 +4.612626158 +15.83995706 +13.42683016 +4.52904744 +3.657997425 +5.99583918 +5.099265424 +4.506173783 +4.125050455 +6.437303826 +4.57814507 +4.042894507 +3.226191433 +3.56924791 +6.468900093 +2.615250122 +6.271460617 +13.30642669 +2.931325492 +3.415013009 +5.31654575 +2.859263953 +2.894037491 +3.76056412 +3.472569086 +7.777848581 +5.709270154 +5.006601736 +3.244792639 +5.984605011 +4.278191561 +4.25832042 +4.563447298 +3.583163887 +11.39184695 +3.212123451 +2.564407331 +3.111198659 +4.417402244 +4.928620309 +2.547076674 +10.2996443 +24.25644272 +6.022902722 +2.93772649 +2.281890536 +4.665510814 +5.358464151 +4.087723238 +2.638153566 +4.241423889 +8.032379014 +7.85151998 +3.203081754 +5.183518573 +5.784168394 +2.918272605 +4.660443552 +2.838489862 +4.640397635 +4.657154061 +6.87573985 +4.601418656 +2.429621079 +2.229175865 +3.069529614 +2.706074322 +3.245883393 +2.626517267 +3.524453549 +2.768562855 +7.374088174 +6.319965261 +4.061245541 +9.279739213 +3.046419013 +6.311845902 +4.18104791 +2.594376247 +3.418347969 +3.083500325 +3.85352231 +3.688344943 +5.360939301 +2.403817937 +3.563258557 +2.87617281 +4.167569899 +2.527597152 +2.738386469 +2.652331593 +10.30406544 +2.528561703 +6.211123963 +2.642168267 +10.7448237 +3.93671784 +2.781502065 +3.030788043 +5.527366082 +6.22372205 +8.262841314 +2.765187182 +4.010993154 +3.788031997 +4.986713869 +4.776938734 +3.238980302 +2.84049203 +4.679792072 +2.779822727 +10.25019148 +2.342775152 +6.250622242 +7.12757049 +6.539864655 +9.021993556 +4.719839514 +4.312103485 +8.286019532 +13.20997417 +4.638078504 +4.544656646 +2.945413541 +3.377008843 +8.830253624 +2.710060796 +7.95475197 +2.419424134 +4.350198731 +5.820250472 +8.255598272 +3.168375107 +9.872523804 +3.965019534 +3.38187225 +5.683749095 +4.461770055 +12.36258892 +2.266240209 +4.898236188 +3.708433208 +7.833741548 +3.494848017 +4.275690667 +5.963767713 +6.156491501 +3.309356644 +4.483424941 +3.295321189 +8.476310215 +4.016633027 +3.68890163 +3.951539217 +2.555536742 +4.589351272 +4.197133122 +2.19660032 +3.226906698 +3.148791932 +3.635304995 +3.054866428 +3.434701513 +16.81279386 +3.426810384 +4.690042264 +5.966054588 +3.206852739 +13.21754579 +3.895953861 +3.032525897 +5.71782031 +4.441436384 +4.775890591 +5.282765323 +4.872733302 +3.867937815 +3.629700576 +11.41511259 +11.21521173 +9.348015215 +2.990954912 +3.000779669 +8.013242456 +3.413927313 +2.530803713 +5.206566597 +5.393833918 +2.551515029 +3.509163423 +4.080563872 +7.60215514 +6.751637919 +5.064119865 +8.681017859 +2.288424854 +3.587845943 +2.64507218 +3.863271403 +2.612548805 +3.526741558 +3.049453308 +4.079279196 +6.718979952 +2.29285644 +4.423253714 +2.879555401 +3.08140338 +3.883239127 +5.930406315 +3.402513571 +2.506037322 +21.20288767 +3.996313028 +6.989703553 +3.1502193 +2.512183236 +2.243213886 +3.516596956 +8.776545557 +6.028012365 +6.22257982 +2.223620852 +4.17037489 +3.803041976 +2.968674947 +9.105537545 +2.899820774 +3.197862388 +3.807301642 +3.417974942 +8.606513665 +3.513341894 +2.56118454 +3.79087691 +3.115166965 +7.126630365 +3.416847976 +2.472170869 +5.392767063 +5.424113432 +4.373800175 +5.052086667 +4.844505376 +3.638913072 +4.564721138 +2.715462857 +3.400280923 +12.87707223 +3.016424561 +2.819168204 +3.254695178 +2.898883696 +3.484861134 +2.696406837 +4.38474964 +2.870169104 +3.924904213 +2.844385871 +3.130172318 +2.6196033 +3.430129284 +3.178726651 +6.56169194 +6.095184005 +8.006182579 +16.73660759 +4.397536125 +6.851443232 +5.780120737 +5.863849105 +5.998157126 +2.304031485 +6.215966587 +3.041487295 +6.281071462 +3.649844775 +7.8463633 +2.97498975 +2.235975305 +4.448792775 +4.810353213 +7.685258439 +3.035713567 +5.065903368 +6.511726069 +8.764424513 +5.20737161 +2.507317704 +4.904086184 +6.212054054 +2.58129192 +5.726131394 +4.647596611 +8.265411851 +6.389520656 +3.02140003 +5.598666088 +4.096816037 +3.483249249 +2.558109181 +2.814917059 +5.412674677 +7.029858893 +4.385781266 +9.017135363 +9.050014701 +3.963545765 +5.349141307 +2.638012447 +2.192131901 +3.209320034 +6.519336364 +2.509642118 +10.65520326 +4.85894005 +4.112478976 +3.158106626 +6.139478733 +4.52477871 +2.776399809 +5.316659097 +6.352919802 +6.714042579 +4.490247146 +3.673942586 +3.751164206 +3.537815872 +3.205361543 +4.218574824 +4.373506221 +5.349923911 +2.87966604 +4.488541793 +3.226212605 +6.208718191 +2.569893035 +3.287456749 +4.955799809 +2.673751491 +5.613877567 +5.024069894 +3.460747351 +2.252321443 +2.694514711 +3.806920628 +2.960471923 +2.851330559 +32 +41 +44 +56 +63 +38 +69 +45 +64 +68 +36 +100 +100 diff --git a/input/GSD/list_with header.txt b/input/GSD/list_with header.txt new file mode 100644 index 0000000..c76709f --- /dev/null +++ b/input/GSD/list_with header.txt @@ -0,0 +1,2187 @@ +3.747251541 +7.097364911 +5.310748233 +3.682905258 +4.561395568 +3.429751186 +2.488581274 +5.043093034 +2.731434928 +3.206197581 +8.197549435 +3.530218501 +4.889670022 +2.939932378 +4.054514375 +7.242472407 +3.988920713 +3.228874771 +2.972147681 +2.620771173 +9.929256318 +5.809755623 +3.942869648 +2.815596439 +3.842491538 +2.536415589 +5.744318294 +3.026752723 +3.437124224 +11.45276196 +8.942070107 +3.953308968 +3.382903746 +3.648392157 +3.828883505 +4.791033605 +17.82572912 +3.126028425 +4.820391358 +8.369852408 +2.552055642 +2.249949601 +2.983563336 +7.809238607 +7.823075309 +3.024441948 +5.915684575 +2.908673021 +6.769333973 +3.448379145 +6.010599581 +5.262946653 +3.087608637 +4.775464638 +2.462271037 +6.495483023 +2.517292361 +4.673550609 +2.55711403 +10.69976765 +3.066128222 +6.431170952 +3.8619186 +8.46886212 +2.441947288 +5.568227454 +3.487891214 +5.694731766 +22.91127712 +3.845496126 +2.892549303 +2.924548714 +3.2581144 +5.41041777 +3.509004025 +5.209349041 +3.66983976 +3.524397057 +4.406196356 +2.479290545 +3.314995967 +6.02656439 +3.068093214 +5.799114272 +3.494352455 +3.461497419 +2.462971176 +5.209941248 +4.137853178 +4.580134775 +3.121544425 +3.362704334 +2.343735375 +2.373217094 +3.643446685 +4.404386035 +9.261695942 +5.063795925 +16.09804295 +3.581941845 +4.567309766 +2.900904621 +4.517764904 +11.68377204 +2.592848361 +4.964785201 +6.957109109 +2.663395101 +3.008392251 +4.821348592 +2.908806475 +3.274777786 +5.366366078 +4.120424431 +5.131399876 +4.464480201 +6.156175229 +6.590418142 +3.723118997 +10.11109158 +7.945303306 +2.410535969 +8.846385539 +3.078057822 +4.847225567 +3.39041188 +3.643388602 +2.659947888 +3.041772045 +2.680600871 +2.619638546 +2.996328857 +5.100753997 +4.206683499 +3.203160025 +2.819179337 +5.321025945 +5.460358175 +5.430000644 +4.236625589 +3.236875991 +4.012489249 +13.82210208 +3.613609293 +2.985855346 +3.426100404 +2.477616424 +5.904190888 +2.65893709 +5.45988453 +4.455986684 +3.770430225 +3.195695449 +3.498665945 +11.88640504 +3.570492175 +4.43740367 +2.933776176 +5.943485692 +6.450765861 +2.415430766 +4.63340213 +5.296106354 +7.778907425 +4.434089116 +2.7387136 +3.376425797 +3.463717674 +3.347919474 +2.976495125 +3.374834185 +3.420755703 +31.08910458 +6.873779491 +3.252632613 +3.90267741 +4.152221858 +5.512195634 +3.054702957 +3.296733759 +3.647802406 +2.918694981 +4.314614042 +4.163126076 +3.148445257 +4.768778479 +4.835427803 +4.146296061 +3.777772866 +3.502413378 +3.06659181 +2.738049489 +5.207737724 +3.309145258 +2.447218915 +2.188163681 +2.690322231 +2.642538293 +4.472454008 +5.807004416 +3.761190552 +3.810014319 +2.706321548 +3.885397187 +4.484277463 +5.952303686 +16.10633227 +2.721781505 +3.677808759 +3.139833401 +6.15957686 +4.593130761 +2.541087066 +2.916933389 +2.860562031 +3.70651304 +4.622196208 +2.689076942 +4.832493072 +4.580866088 +3.818514167 +6.082386789 +2.23401446 +4.835453454 +3.746516797 +2.287866621 +7.833543092 +2.538805971 +4.285002792 +3.66682642 +2.892676265 +3.913439647 +4.67291006 +2.885009768 +3.070953948 +5.468875435 +2.884082765 +6.303300522 +3.773079079 +2.930120722 +6.127920885 +5.304450009 +2.888471164 +3.903193971 +3.631537873 +10.17796927 +3.411954026 +3.975494336 +12.02451484 +3.819884992 +4.450390959 +10.65652083 +3.70536764 +5.139812525 +2.870291927 +5.069196838 +2.759931252 +10.1055112 +6.64364124 +4.7258353 +5.264861617 +5.057000106 +2.425296076 +2.743030984 +4.773525084 +5.118821475 +2.47257317 +6.399773071 +4.863090015 +2.236741154 +3.500895106 +3.36961559 +3.689045452 +2.658784068 +5.748158089 +2.767133836 +8.142855789 +3.025743522 +3.684303402 +2.499358706 +3.51877259 +9.476831295 +4.774016308 +5.593391424 +3.112423051 +3.742003616 +4.050225262 +4.117836347 +2.137573806 +7.881571082 +3.470362485 +4.654529511 +2.789282822 +2.578411543 +2.85062514 +4.599266218 +4.121275603 +2.440778408 +2.525529534 +5.660598072 +3.113242556 +4.128227444 +3.942069572 +3.292398844 +2.953736917 +24.78673395 +11.09938233 +3.223238251 +5.034120009 +3.141839165 +3.640113271 +4.422055216 +5.423698992 +3.267289552 +3.732517181 +3.40287933 +11.49985979 +6.674227606 +4.780894936 +2.827389229 +11.56780827 +3.740415644 +2.469851548 +2.932025863 +2.877544992 +2.687841018 +3.839191128 +2.851010302 +3.894694684 +10.21547686 +5.179146197 +18.53471482 +12.09876551 +5.284224423 +5.253681893 +5.360351072 +10.37268723 +3.402434845 +4.448990693 +7.289055518 +2.550824836 +8.577053209 +3.605731999 +7.287872218 +7.124474485 +5.684122984 +2.937520306 +3.617561036 +2.340740889 +3.744891289 +6.865268582 +5.498440689 +4.947703748 +6.79407131 +4.766392715 +4.808595448 +3.878397598 +3.564482524 +2.854296821 +6.202233957 +4.413702181 +6.103278439 +5.522233345 +5.377918725 +3.650510929 +3.164543651 +2.877486855 +2.725423807 +5.189133838 +3.687472801 +4.048382061 +2.232975533 +19.64341928 +4.053891885 +8.672863772 +3.399573228 +6.828086958 +23.5733086 +3.951013002 +4.32225598 +5.219025298 +4.578863341 +3.708774918 +2.57215255 +2.633728558 +9.423578138 +3.301348766 +19.35089885 +3.142549227 +4.282486967 +6.095497135 +11.21538889 +6.295081832 +2.646232944 +3.718887374 +10.67980411 +4.680018123 +12.70333553 +6.604840458 +2.61179033 +4.694590717 +3.790489931 +3.384488411 +3.139796512 +8.135978534 +4.458169188 +2.992298916 +5.205937151 +6.136953302 +2.563925639 +21.46841712 +3.579164363 +7.425838247 +5.942077947 +9.449404018 +5.148953192 +4.270990656 +3.233306162 +9.181214335 +3.182524551 +2.716759947 +2.393127007 +4.250414377 +3.567087256 +2.18878124 +3.925681109 +4.162895209 +5.172884948 +6.66635576 +2.990115281 +3.183070117 +2.87541287 +9.016328777 +6.587402206 +8.354366625 +2.760947173 +5.054495168 +5.647462299 +6.529072146 +9.206143715 +2.510586042 +3.341722172 +2.892405463 +3.737414078 +3.057690747 +2.713998717 +5.61394891 +9.148261235 +3.445075506 +8.161282169 +5.184666658 +14.09601653 +2.517105725 +6.914985275 +2.588554616 +2.839171664 +14.83154369 +2.968947651 +6.733646303 +3.364798967 +2.563682316 +4.391234384 +2.723241049 +4.714632828 +5.075458289 +11.45225716 +2.744187326 +5.120435773 +2.337045551 +7.983591115 +2.41391817 +74.1963466 +4.83268515 +8.732034405 +3.216371033 +4.323602093 +3.0458147 +30.36298782 +4.610531325 +19.48981788 +4.788103171 +23.81504616 +6.906477937 +2.851797582 +3.181747083 +4.295127565 +4.210808554 +19.29223587 +8.089915932 +14.58899244 +4.169003028 +2.247421164 +18.97452267 +5.701543779 +2.947806023 +3.194484917 +3.17269317 +3.202779097 +5.29923418 +25.02370768 +4.07198712 +2.93476917 +6.511709819 +2.563046989 +7.128915593 +4.15179212 +4.36129195 +2.201628806 +3.039513188 +4.09860882 +2.588555011 +2.85642892 +6.087898464 +2.823150281 +3.189350891 +3.449821719 +4.032214398 +4.37897628 +11.50408278 +4.134895554 +6.208815985 +2.239717973 +2.755799622 +2.405984563 +3.878898356 +2.808776996 +9.283404996 +7.525215315 +2.697036011 +5.749753703 +6.87929351 +2.403316626 +18.57042932 +2.840413565 +8.454590689 +2.435647379 +14.21041416 +3.290729857 +2.174233154 +9.880744132 +4.872015067 +2.423947689 +30.57718062 +6.459123133 +6.211531691 +4.532521376 +3.774039529 +5.363906634 +2.597656865 +4.500213473 +2.622700359 +4.24599648 +3.030387953 +5.564575315 +2.687998133 +4.978102652 +3.217829303 +2.692635594 +5.315940294 +2.952115885 +8.965939192 +23.90590758 +7.909341868 +2.478338746 +2.744022544 +5.136484328 +3.889716206 +3.555134775 +4.218746846 +18.11960739 +4.415149029 +3.477686417 +2.89566086 +3.539827163 +2.412179831 +11.91667762 +5.902668745 +3.271084664 +4.9434469 +3.395975916 +2.922101828 +14.72062062 +3.906506903 +3.200827074 +3.515889597 +4.245933192 +4.169021725 +13.9079176 +3.089387059 +8.593364246 +2.145148049 +2.814485558 +10.26918175 +7.28098177 +3.956023359 +7.413857066 +4.454856037 +3.418657955 +5.831954625 +2.95053583 +5.112376354 +3.048486138 +5.358143643 +6.027168677 +7.44021392 +4.149686916 +5.29992902 +2.6168778 +2.443482083 +8.901111374 +6.003326109 +4.793460455 +11.01454723 +2.53785258 +3.236527626 +2.785420774 +5.86124321 +7.235166599 +2.623547431 +2.801654303 +15.86999909 +3.534676098 +4.499577011 +4.671251081 +6.488581639 +9.052765952 +11.9148313 +4.658462138 +4.025891774 +6.708399677 +4.100050639 +2.610866178 +6.307513865 +16.70584148 +2.338378734 +7.228598176 +2.680476272 +4.026441998 +3.994619559 +7.40492039 +2.386401153 +2.382329929 +14.79331234 +14.36122287 +2.591301966 +5.601081812 +6.264974862 +6.30943651 +3.800670902 +7.511341463 +5.727562638 +2.245114981 +2.745881383 +4.303374416 +3.134533304 +3.735627478 +6.179146264 +2.856265068 +11.16457528 +3.078210145 +5.58990571 +2.575348341 +2.753343963 +2.252788385 +3.669359065 +4.30525845 +23.75941252 +2.971801917 +2.815819993 +6.119302036 +8.723562842 +25.8119114 +2.694459409 +12.49725138 +4.406805821 +10.28781192 +26.52986927 +3.674771612 +3.940635427 +2.859023321 +6.580393152 +10.23903453 +5.611511526 +6.793801123 +2.919241113 +2.404402303 +3.023027021 +2.680156546 +2.859063342 +25.57960401 +8.906448186 +12.1799468 +10.64674403 +4.538805361 +8.369757627 +3.235672049 +3.32159282 +4.122010214 +3.075132589 +2.789113234 +2.20315335 +8.993199077 +3.069293777 +6.212145809 +3.1886471 +3.526888965 +2.711523239 +2.631213257 +9.191844265 +2.893149916 +3.25382564 +6.038807147 +7.932527542 +2.759348037 +3.528906173 +3.127533194 +2.656306189 +9.872867787 +13.8220843 +3.810170578 +2.797545033 +11.42655213 +6.674456128 +4.606025283 +6.714042391 +2.184387788 +19.05617863 +2.80070108 +2.99971362 +3.395072145 +6.98880789 +16.89979397 +2.847073835 +2.883347001 +3.341758383 +6.170207563 +3.752034268 +3.974445639 +10.57824269 +22.22804226 +6.422991135 +7.272328139 +6.448954832 +5.868063873 +3.384735634 +7.433579104 +3.99498596 +7.616634764 +6.232185286 +5.276098498 +4.374702171 +6.652505624 +6.695730631 +2.417820095 +4.265934298 +5.415504398 +5.048036573 +3.284384826 +4.604202589 +17.67386158 +3.399310101 +2.888568861 +5.125740454 +2.864854665 +3.299203333 +10.52356279 +8.498317325 +10.97660891 +5.074210546 +2.097277915 +2.454533695 +2.745685971 +5.788524939 +4.996545193 +5.982924511 +2.761852684 +4.245354584 +4.842123562 +3.01501037 +10.86133114 +5.708193228 +4.653544812 +16.90700078 +2.714168381 +2.857546079 +2.778517089 +3.49531984 +6.084348043 +3.165742424 +2.3548423 +4.243450606 +3.898298725 +2.303483167 +3.106038869 +3.05998595 +11.77553841 +21.90541213 +2.376661567 +5.727431494 +4.019170793 +8.029163916 +5.422630883 +6.450478324 +3.299541081 +5.318285938 +21.07444423 +4.287455304 +3.26376662 +26.72491408 +5.607492861 +4.298597295 +18.55257076 +10.28977691 +2.986493876 +3.269277019 +3.704367467 +4.714918104 +26.28472245 +4.025259143 +4.605633495 +3.600345443 +3.308196415 +2.913251621 +3.190086201 +2.495048984 +2.808239863 +3.610061443 +2.740696565 +5.361239458 +2.37011844 +6.837601955 +5.776302982 +5.345949107 +4.421313972 +7.086269004 +3.322578119 +5.323016173 +3.120056533 +5.314244815 +4.422496736 +2.740755283 +7.172139313 +2.96686778 +2.916249398 +3.270380663 +3.094030178 +20.23493511 +4.86615079 +2.965071346 +4.761550959 +5.315936565 +6.434206171 +2.433003933 +2.402599291 +4.083311145 +3.725916568 +6.44192609 +4.962144404 +3.034250721 +2.823645705 +9.278178184 +4.841192222 +6.513756056 +9.97260984 +2.596255833 +4.730688784 +2.847888743 +4.716770669 +2.509273656 +4.653459819 +3.329022387 +3.237349931 +4.669342932 +3.444942204 +4.279085562 +2.763309116 +5.61397771 +2.841765196 +2.297123067 +3.933870839 +2.338228807 +2.783512668 +3.140887269 +6.936848325 +4.072584952 +3.247587984 +2.826777333 +11.85556823 +5.358145165 +4.690417512 +2.33847071 +2.143265684 +20.09011874 +9.406784829 +15.7789345 +4.678938329 +2.297044345 +14.16285128 +9.477768365 +3.836394999 +5.350121072 +3.071165628 +3.142450562 +3.120742053 +2.775914178 +2.75447982 +4.021716757 +3.984737735 +5.202037479 +3.439232707 +5.61066676 +2.709621021 +2.542774042 +2.518516539 +4.532139905 +4.911972171 +2.566414573 +7.028084527 +3.141241585 +3.518496825 +3.44191478 +3.160394479 +2.621349093 +2.387525055 +9.621665382 +3.036272808 +2.469472752 +4.676117809 +19.92363491 +14.94665664 +3.906764928 +3.542625918 +2.640290378 +2.38047999 +2.204551711 +5.448792388 +8.076938948 +3.821936507 +3.546637214 +16.50840252 +3.781417313 +29.21901998 +3.468997253 +9.931132044 +2.269570378 +4.488073278 +6.164269422 +2.772896293 +6.17914341 +7.299816626 +3.217305639 +4.008302835 +3.583404578 +2.694162351 +5.813264856 +2.712298258 +6.998908638 +10.02849197 +2.404433571 +4.925582445 +2.466762463 +4.458100923 +2.461797615 +2.610922829 +3.939521035 +4.42104044 +9.381101342 +3.326777375 +2.843667769 +3.937620829 +4.95678249 +8.93447352 +3.725663163 +4.791057729 +5.525394244 +3.997220889 +2.792962055 +3.103038994 +6.368046545 +3.755101093 +5.377997179 +7.665619716 +5.460326604 +3.187585829 +3.322549632 +2.450532749 +3.814824508 +11.94195247 +7.266206236 +12.13236959 +5.342919011 +3.591461809 +9.055302079 +6.012010024 +5.749382847 +9.647835353 +2.606794438 +2.736781212 +2.240747053 +3.223689427 +3.41202241 +3.714723854 +5.633945035 +3.703600635 +4.240212061 +6.661164738 +3.300220798 +2.434069637 +6.1579121 +5.987310315 +2.60643087 +7.611072118 +2.061482507 +3.046672167 +2.730766072 +3.743271653 +4.865370143 +2.764788256 +10.79526648 +4.828893502 +3.084032162 +3.785096495 +2.538004767 +5.160226861 +3.931254519 +2.32189279 +5.097819034 +6.869531796 +7.53941999 +4.635284209 +12.19027301 +3.586058258 +6.1781212 +3.584162186 +5.703354482 +3.314147788 +3.408071694 +2.381316153 +2.525414376 +5.536524956 +3.247372659 +3.800345727 +3.63037787 +3.3433429 +3.343054284 +3.328388836 +2.606117807 +2.638493172 +4.724622034 +7.676209607 +7.537536194 +2.478269341 +2.663970527 +5.043463556 +13.09052452 +3.107491074 +24.82093664 +7.663245199 +2.514007811 +5.769964969 +2.366027404 +3.600108063 +4.895760397 +2.658000944 +10.39100263 +3.182825807 +3.581613855 +2.898167921 +4.694013587 +9.210795386 +4.049221397 +6.955431461 +3.771811195 +4.023719608 +3.114274397 +2.991283447 +6.016231114 +2.907724094 +5.453177195 +8.932576891 +7.272092378 +2.904846989 +8.93659878 +6.63718949 +7.704819887 +4.339417417 +2.686684308 +6.991232518 +3.708184986 +6.714397438 +4.403786099 +7.026606761 +5.535095882 +3.740012834 +4.129181359 +5.763960911 +3.022998367 +2.588493457 +5.482774597 +3.528475347 +8.186819838 +3.922968774 +4.555336102 +8.355869686 +11.83926762 +2.960846918 +5.195941933 +5.230762257 +9.136494467 +9.062886575 +4.144616116 +4.549058971 +3.062168987 +9.555667727 +7.316664955 +4.098410087 +7.69099137 +4.808310543 +2.892373896 +4.255972498 +5.813701015 +2.376227468 +17.89694752 +2.989932241 +2.499926764 +2.309073945 +3.51482393 +2.90781727 +8.252787462 +6.327366976 +3.243550595 +25.28067528 +6.931504587 +3.690397399 +25.64453049 +2.523508853 +5.613570947 +9.133322004 +2.327209912 +3.101740452 +8.754525327 +4.651017629 +4.335268671 +5.400151862 +3.871176173 +2.790978482 +11.67659779 +3.458807173 +5.071670726 +10.42582902 +2.838525034 +3.402792418 +2.620350945 +3.305268358 +2.721572355 +6.020395624 +5.276950458 +2.223173525 +5.599851366 +4.434526366 +5.081669441 +4.299069609 +3.035115289 +5.851855794 +7.135362498 +14.62449698 +3.68968057 +2.535016814 +3.735506991 +2.817438043 +4.803186728 +5.125227215 +7.691404693 +3.519506185 +2.89192714 +6.379526995 +3.630375789 +2.598953818 +4.812926939 +11.52581729 +4.597868676 +5.605541979 +5.618711303 +5.705907272 +2.85106803 +2.996331477 +4.794269462 +4.157058166 +10.30455707 +5.337232483 +2.708437375 +4.396677858 +3.361631537 +3.909768294 +7.105368111 +4.112976454 +4.708386758 +12.18440569 +5.815549177 +2.50599015 +12.05123989 +5.838168839 +4.438724286 +2.902523969 +2.370196681 +22.11121033 +2.446988911 +9.43968336 +20.14096555 +8.354176997 +2.463927089 +5.125098923 +3.445503942 +4.653450776 +3.117100163 +4.08501463 +5.585220637 +7.82628337 +2.746483016 +2.634835133 +8.057487636 +6.132658162 +6.329477285 +5.74280058 +4.301917107 +4.909794231 +23.35693792 +4.928442645 +5.881887058 +2.991166757 +8.303830556 +2.666844968 +4.128704692 +6.848947171 +2.881680288 +3.733950534 +5.237995449 +2.954000559 +2.917963693 +4.654774612 +3.075232882 +5.425356971 +2.939922649 +5.039320066 +3.17875957 +9.479185732 +4.292596849 +6.465848785 +5.41944719 +4.283275564 +11.09828279 +7.148950289 +9.430535617 +3.871440376 +7.280681217 +14.73142026 +2.537087677 +3.229181022 +2.900993958 +5.269244285 +5.711934975 +37.72597475 +5.522312169 +7.437393782 +3.231288453 +3.602372028 +4.171952023 +3.259886051 +8.128109372 +3.859749519 +4.857123268 +4.021307422 +2.925060646 +4.041137489 +5.036737348 +8.956675917 +5.402846715 +4.278602726 +2.284913577 +3.814098305 +3.606826635 +4.561199369 +16.05428079 +2.421808586 +8.692592818 +2.70331766 +3.177199461 +5.172204112 +2.803566176 +4.764524215 +2.39603117 +4.049891768 +3.139943395 +6.765101826 +4.912653653 +3.460183905 +4.976502481 +6.338761887 +5.633213522 +4.5634456 +6.580084218 +16.71888687 +4.075858861 +5.730522631 +3.774215004 +2.871357589 +17.35393947 +3.738329022 +2.731623594 +4.371661605 +4.573131538 +3.356793205 +5.201251074 +3.206067919 +7.050154119 +3.847867433 +4.987939669 +4.946885511 +3.714858885 +4.836455375 +2.876779385 +10.27853236 +4.087371245 +3.289901476 +3.459403929 +8.068427588 +2.397322417 +4.855240031 +2.785906044 +10.89835394 +2.21410485 +2.800687758 +2.643262057 +5.036580711 +12.9575231 +2.561178781 +5.006903298 +2.812691397 +3.271133808 +4.143470869 +6.737799523 +2.750914537 +3.261038657 +3.380788624 +5.714605738 +4.165673999 +3.290536992 +6.409958598 +3.592833415 +3.849921893 +5.588418059 +3.254565752 +2.605977057 +9.791592114 +3.008217477 +7.381030282 +2.694229385 +7.017355866 +3.241313388 +5.531511638 +6.092725036 +4.090598281 +4.817830167 +14.49929931 +3.269657037 +4.994328667 +8.683882357 +5.043971233 +4.035873443 +2.254767361 +6.388107008 +3.314676388 +3.112471174 +6.79961023 +2.914714637 +2.82112838 +2.611301759 +2.387723994 +5.378283281 +9.344674388 +3.679072512 +2.64209574 +6.742994579 +3.13762792 +5.33397735 +4.466626033 +3.059311697 +2.756463555 +4.018451722 +5.842375124 +6.429158741 +13.15251198 +13.12654924 +4.28985537 +7.413760787 +5.024785392 +4.12167125 +8.836135666 +6.156893769 +8.73034903 +4.780154726 +7.138137746 +2.865696306 +3.16097597 +2.157724229 +4.746713368 +2.911735248 +5.883247511 +9.882652 +5.58725551 +5.248732476 +3.630360667 +8.761816741 +2.721174469 +12.24599254 +2.238319437 +10.42257646 +3.342172185 +8.462920703 +4.845623969 +8.956555209 +2.794659968 +4.763450397 +4.28346765 +2.670104167 +3.775033652 +5.849886406 +5.491352433 +13.8180979 +3.127631399 +3.375364804 +4.16265082 +6.758652331 +5.574806446 +5.35664616 +4.416859998 +5.142223594 +3.989564526 +4.1982908 +8.389374093 +2.322828063 +5.6047234 +3.645068293 +11.47412709 +2.514682399 +2.845813195 +2.922952076 +2.542186826 +12.97309834 +4.974514288 +2.588674878 +4.584832457 +4.774462428 +2.954294836 +9.870786932 +7.951979213 +5.694204638 +4.125719909 +12.08662337 +2.899699946 +3.572139331 +4.563360426 +9.498662652 +2.344084253 +4.37562488 +6.810214955 +18.40929132 +4.571246316 +9.617469306 +2.537446044 +3.630416276 +4.359233642 +9.760180548 +6.253822949 +3.065362984 +15.6132804 +2.559810056 +4.323298175 +3.411860976 +2.463905628 +2.431189383 +3.299136738 +4.266056084 +3.178707818 +6.358436693 +3.619993525 +2.7382479 +7.23240946 +5.674518933 +11.48874297 +3.018399848 +7.929440576 +5.903229802 +9.848819931 +7.389085159 +3.744315703 +3.316165934 +5.525485047 +4.08980291 +8.321189922 +7.602388492 +3.115009067 +2.372067483 +4.431151702 +2.841951655 +3.364550214 +4.00182239 +4.544445866 +7.4403209 +4.779996181 +2.342678889 +4.568595977 +3.279438272 +4.47881404 +2.737848205 +10.70150385 +8.121470323 +4.782444051 +3.822814846 +2.523849354 +5.859280344 +5.909094221 +6.413000981 +16.2321952 +4.772389065 +2.547823417 +14.51421836 +2.949555873 +4.654810798 +6.102765175 +5.355314455 +4.30213172 +2.412487341 +8.514307381 +7.073156019 +6.672069127 +10.07990412 +2.325127387 +4.607703282 +3.118413075 +8.422475313 +2.754622962 +2.199942173 +2.976370442 +5.30167593 +7.68163992 +3.108142998 +7.308661505 +2.212710589 +4.648264636 +5.955146308 +11.23497875 +6.664254877 +3.306097228 +4.054741015 +4.032773085 +9.554135712 +3.580835412 +2.410268638 +4.56118584 +5.079981383 +4.07451001 +6.307410441 +2.791787872 +5.709640101 +4.921370896 +3.557366175 +3.400046511 +4.067743048 +2.220411129 +2.942454232 +3.214703888 +5.776865991 +3.240900726 +11.13112338 +6.756830946 +3.364535295 +2.299916807 +2.317558632 +4.576210647 +6.882236502 +10.47330231 +3.377631697 +6.143267777 +3.482024161 +2.565612131 +4.139993055 +4.324657613 +2.236788949 +2.367882385 +2.528441594 +3.378788489 +13.7956525 +3.162957698 +2.688925502 +5.261763331 +3.646025271 +3.16756208 +2.638227537 +2.652616644 +5.392510279 +3.113104273 +11.74081988 +2.225235266 +3.114027543 +8.271085237 +3.274495947 +5.826186673 +4.477394211 +2.589070056 +4.545634181 +3.268281668 +9.837535408 +4.409580794 +2.604414567 +2.51706519 +6.13129661 +3.75512328 +2.728687036 +7.02468824 +4.202249967 +4.461683259 +7.232016531 +8.384602339 +12.81111065 +4.565905324 +7.202174499 +2.392305851 +4.812745566 +4.334973059 +2.510742827 +3.112291042 +13.23333827 +5.198619101 +4.313232778 +2.525880559 +3.51001311 +5.933548239 +4.180842898 +4.174914641 +3.622027208 +2.969609624 +8.756346173 +5.702454248 +24.75432627 +3.029294281 +3.636930859 +4.71476431 +2.858577271 +3.940490817 +3.157720113 +43.65395541 +8.878325831 +4.543651285 +3.057988474 +5.637885518 +4.809154971 +3.272682089 +5.473261607 +5.52471013 +2.191818866 +13.83481432 +4.99067364 +3.666997997 +4.963544135 +4.242971957 +2.470709575 +4.005999934 +12.84579235 +9.079182997 +8.033573659 +2.585752012 +3.46629904 +4.643614377 +4.956011476 +3.586164086 +7.829067799 +4.695282094 +4.604410681 +4.939260316 +4.356557518 +4.349152831 +3.117620798 +2.800484462 +3.291449611 +5.189046645 +5.950407173 +5.614837637 +4.261493128 +2.848748806 +5.366887213 +4.880586041 +5.273399438 +7.053724004 +2.913692557 +2.233485393 +2.546036993 +4.790277589 +5.052366627 +2.619551709 +5.862407525 +10.85905616 +9.740692713 +6.706809856 +3.901664822 +4.487358718 +4.31456218 +2.896158796 +3.530122771 +8.429770035 +4.8001793 +3.213077886 +4.750895306 +6.502505674 +16.73596231 +5.75080462 +2.20346469 +2.769488571 +5.631713614 +3.362010294 +3.342123222 +4.267595279 +2.98887798 +2.945708994 +11.37795723 +11.74477475 +2.388920908 +8.990691632 +4.73952378 +4.161013843 +8.40122035 +3.997145024 +2.376610741 +3.452454651 +4.520347006 +7.923017772 +4.942809691 +5.645576749 +6.30271488 +4.398683583 +2.914429927 +3.59947134 +7.555080576 +2.613564349 +3.054595625 +4.178615433 +2.869370207 +3.132886825 +3.822753104 +12.80745624 +3.09882794 +3.044074295 +4.4822626 +4.065666407 +5.848260476 +5.598245823 +8.085355099 +2.322960505 +5.326107567 +3.403815225 +3.682153479 +3.912822215 +4.10335796 +4.618936677 +9.815032101 +4.226582688 +4.494050445 +3.464662213 +20.95302582 +2.648475065 +4.585621006 +5.760802552 +5.098104613 +3.541946691 +5.032391821 +7.912634878 +5.228383645 +5.51665637 +4.525179806 +4.505868628 +4.029978333 +2.807893878 +2.664412955 +7.942868339 +2.878338434 +4.4920142 +2.930505164 +2.076153574 +4.282123484 +3.082320786 +7.367582708 +6.262558278 +7.906477366 +2.286175145 +6.468926848 +4.475999115 +4.033312088 +8.224751768 +4.652874413 +2.707677984 +2.149188274 +4.049654018 +2.720932403 +10.45949786 +2.835832698 +3.407060414 +9.424323401 +2.998216425 +4.796800936 +8.435137661 +4.537188353 +3.034262374 +7.4960797 +6.121311941 +2.819755798 +4.127293043 +5.30346801 +5.103634547 +6.749717337 +2.696091998 +3.706224273 +2.666269921 +2.641211731 +2.766917117 +4.104609103 +3.598471423 +4.612626158 +15.83995706 +13.42683016 +4.52904744 +3.657997425 +5.99583918 +5.099265424 +4.506173783 +4.125050455 +6.437303826 +4.57814507 +4.042894507 +3.226191433 +3.56924791 +6.468900093 +2.615250122 +6.271460617 +13.30642669 +2.931325492 +3.415013009 +5.31654575 +2.859263953 +2.894037491 +3.76056412 +3.472569086 +7.777848581 +5.709270154 +5.006601736 +3.244792639 +5.984605011 +4.278191561 +4.25832042 +4.563447298 +3.583163887 +11.39184695 +3.212123451 +2.564407331 +3.111198659 +4.417402244 +4.928620309 +2.547076674 +10.2996443 +24.25644272 +6.022902722 +2.93772649 +2.281890536 +4.665510814 +5.358464151 +4.087723238 +2.638153566 +4.241423889 +8.032379014 +7.85151998 +3.203081754 +5.183518573 +5.784168394 +2.918272605 +4.660443552 +2.838489862 +4.640397635 +4.657154061 +6.87573985 +4.601418656 +2.429621079 +2.229175865 +3.069529614 +2.706074322 +3.245883393 +2.626517267 +3.524453549 +2.768562855 +7.374088174 +6.319965261 +4.061245541 +9.279739213 +3.046419013 +6.311845902 +4.18104791 +2.594376247 +3.418347969 +3.083500325 +3.85352231 +3.688344943 +5.360939301 +2.403817937 +3.563258557 +2.87617281 +4.167569899 +2.527597152 +2.738386469 +2.652331593 +10.30406544 +2.528561703 +6.211123963 +2.642168267 +10.7448237 +3.93671784 +2.781502065 +3.030788043 +5.527366082 +6.22372205 +8.262841314 +2.765187182 +4.010993154 +3.788031997 +4.986713869 +4.776938734 +3.238980302 +2.84049203 +4.679792072 +2.779822727 +10.25019148 +2.342775152 +6.250622242 +7.12757049 +6.539864655 +9.021993556 +4.719839514 +4.312103485 +8.286019532 +13.20997417 +4.638078504 +4.544656646 +2.945413541 +3.377008843 +8.830253624 +2.710060796 +7.95475197 +2.419424134 +4.350198731 +5.820250472 +8.255598272 +3.168375107 +9.872523804 +3.965019534 +3.38187225 +5.683749095 +4.461770055 +12.36258892 +2.266240209 +4.898236188 +3.708433208 +7.833741548 +3.494848017 +4.275690667 +5.963767713 +6.156491501 +3.309356644 +4.483424941 +3.295321189 +8.476310215 +4.016633027 +3.68890163 +3.951539217 +2.555536742 +4.589351272 +4.197133122 +2.19660032 +3.226906698 +3.148791932 +3.635304995 +3.054866428 +3.434701513 +16.81279386 +3.426810384 +4.690042264 +5.966054588 +3.206852739 +13.21754579 +3.895953861 +3.032525897 +5.71782031 +4.441436384 +4.775890591 +5.282765323 +4.872733302 +3.867937815 +3.629700576 +11.41511259 +11.21521173 +9.348015215 +2.990954912 +3.000779669 +8.013242456 +3.413927313 +2.530803713 +5.206566597 +5.393833918 +2.551515029 +3.509163423 +4.080563872 +7.60215514 +6.751637919 +5.064119865 +8.681017859 +2.288424854 +3.587845943 +2.64507218 +3.863271403 +2.612548805 +3.526741558 +3.049453308 +4.079279196 +6.718979952 +2.29285644 +4.423253714 +2.879555401 +3.08140338 +3.883239127 +5.930406315 +3.402513571 +2.506037322 +21.20288767 +3.996313028 +6.989703553 +3.1502193 +2.512183236 +2.243213886 +3.516596956 +8.776545557 +6.028012365 +6.22257982 +2.223620852 +4.17037489 +3.803041976 +2.968674947 +9.105537545 +2.899820774 +3.197862388 +3.807301642 +3.417974942 +8.606513665 +3.513341894 +2.56118454 +3.79087691 +3.115166965 +7.126630365 +3.416847976 +2.472170869 +5.392767063 +5.424113432 +4.373800175 +5.052086667 +4.844505376 +3.638913072 +4.564721138 +2.715462857 +3.400280923 +12.87707223 +3.016424561 +2.819168204 +3.254695178 +2.898883696 +3.484861134 +2.696406837 +4.38474964 +2.870169104 +3.924904213 +2.844385871 +3.130172318 +2.6196033 +3.430129284 +3.178726651 +6.56169194 +6.095184005 +8.006182579 +16.73660759 +4.397536125 +6.851443232 +5.780120737 +5.863849105 +5.998157126 +2.304031485 +6.215966587 +3.041487295 +6.281071462 +3.649844775 +7.8463633 +2.97498975 +2.235975305 +4.448792775 +4.810353213 +7.685258439 +3.035713567 +5.065903368 +6.511726069 +8.764424513 +5.20737161 +2.507317704 +4.904086184 +6.212054054 +2.58129192 +5.726131394 +4.647596611 +8.265411851 +6.389520656 +3.02140003 +5.598666088 +4.096816037 +3.483249249 +2.558109181 +2.814917059 +5.412674677 +7.029858893 +4.385781266 +9.017135363 +9.050014701 +3.963545765 +5.349141307 +2.638012447 +2.192131901 +3.209320034 +6.519336364 +2.509642118 +10.65520326 +4.85894005 +4.112478976 +3.158106626 +6.139478733 +4.52477871 +2.776399809 +5.316659097 +6.352919802 +6.714042579 +4.490247146 +3.673942586 +3.751164206 +3.537815872 +3.205361543 +4.218574824 +4.373506221 +5.349923911 +2.87966604 +4.488541793 +3.226212605 +6.208718191 +2.569893035 +3.287456749 +4.955799809 +2.673751491 +5.613877567 +5.024069894 +3.460747351 +2.252321443 +2.694514711 +3.806920628 +2.960471923 +2.851330559 +32 +41 +44 +56 +63 +38 +69 +45 +64 +68 +36 +100 +100 diff --git a/input/Targets/MP_015deg_z040cm_Target.h5 b/input/Targets/MP_015deg_z040cm_Target.h5 new file mode 100644 index 0000000..9ad6296 Binary files /dev/null and b/input/Targets/MP_015deg_z040cm_Target.h5 differ diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..caeb9ec Binary files /dev/null and b/logo.png differ diff --git a/startGPRGRAVEL.m b/startGPRGRAVEL.m new file mode 100644 index 0000000..95d9d2a --- /dev/null +++ b/startGPRGRAVEL.m @@ -0,0 +1,64 @@ +function startGPRGRAVEL +%startGPRGRAVEL is the start script that prepares the Matlab path and +%starts the GPRGRAVEL GUI +% +% Syntax: +% startGPRGRAVEL +% +% Inputs: +% none +% +% Outputs: +% none +% +% Example: +% startGPRGRAVEL +% +% Other m-files required: +% GPRGRAVEL.m +% +% Subfunctions: +% none +% +% MAT-files required: +% none +% +% See also GPRGRAVEL +% Author(s): see AUTHORS.md +% License: GNU GPLv3 (at end) + +%------------- BEGIN CODE -------------- + +%% add paths +thisfile = mfilename('fullpath'); +thispath = fileparts(thisfile); +addpath(genpath(fullfile(thispath,'callbacks')),'-end'); +addpath(genpath(fullfile(thispath,'externals')),'-end'); +addpath(genpath(fullfile(thispath,'functions')),'-end'); +addpath(genpath(fullfile(thispath,'GPRGRAVEL')),'-end'); + +%% start GUI +GPRGRAVEL; + +end + +%------------- END OF CODE -------------- + +%% License: +% GNU GPLv3 +% +% GPRGRAVEL +% Copyright (C) 2023 Thomas Hiller +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see .