- 
                Notifications
    
You must be signed in to change notification settings  - Fork 193
 
Pareto navigation #669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev_varRBErobOpt
Are you sure you want to change the base?
Pareto navigation #669
Changes from 18 commits
fe06707
              823794f
              4cba6b2
              2e806a9
              bc7f21d
              0faf883
              6b8aa22
              21347fe
              22bb7e6
              fed3c63
              778b4cc
              8cb4398
              d134d85
              23eee6a
              b9009b1
              46ec9b3
              267d2b8
              823f44d
              5ddce71
              e8c6218
              b38a859
              f19635f
              8004b74
              13e4615
              ece7b7f
              75f7513
              c7dc07e
              74ae379
              4ceb2bf
              db5d715
              b8df93d
              5baac7a
              41234fe
              94d2d46
              a0336fe
              130bcc7
              f0fd213
              2210d7f
              e93381b
              aa90d6a
              c0b9594
              7e1653f
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| classdef matRad_UIData < handle | ||
| % matRad_UIData implements a class that allows easy storing of | ||
| % variables related to the pareto Navigation | ||
| % | ||
| % References | ||
| % - | ||
| % | ||
| % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
| % | ||
| % Copyright 2020 the matRad development team. | ||
| % | ||
| % This file is part of the matRad project. It is subject to the license | ||
| % terms in the LICENSE file found in the top-level directory of this | ||
| % distribution and at https://github.com/e0404/matRad/LICENSES.txt. No part | ||
| % of the matRad project, including this file, may be copied, modified, | ||
| % propagated, or distributed except according to the terms contained in the | ||
| % LICENSE file. | ||
| % | ||
| % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
| 
     | 
||
| properties | ||
| wRef %weight vector of last calculated plan | ||
| fRef %objective function values of last calculated plan | ||
| fIndsAll % stores all objective function values | ||
| fIndsRed % stores only the "reduced points" | ||
| upboundInit | ||
| upboundRed | ||
| upboundSlider | ||
| lowboundSliderInit | ||
| lowboundSlider | ||
| linestyle | ||
| end | ||
| 
     | 
||
| methods | ||
| function obj = matRad_UIData(wRef,fRef,fInds) | ||
| obj.wRef = wRef; | ||
| obj.fRef = fRef; | ||
| obj.fIndsAll = fInds; | ||
| obj.fIndsRed = fInds; | ||
| obj.upboundInit = max(fInds,[],1); | ||
| obj.upboundRed = max(fInds,[],1); | ||
| obj.upboundSlider= max(fInds,[],1); | ||
| obj.lowboundSliderInit = min(fInds,[],1); | ||
| obj.lowboundSlider = min(fInds,[],1); | ||
| obj.linestyle = 2; | ||
| end | ||
| 
     | 
||
| function [sliderLowBound,sliderUpBound] = restrictObjective(obj,i,bound) | ||
| obj.upboundRed(i) = bound; | ||
| obj.fIndsRed = obj.fIndsRed(obj.fIndsRed(:,i) <= bound,:); | ||
| obj.upboundSlider= max([obj.fIndsRed;obj.fRef],[],1); | ||
| obj.upboundSlider(i) = bound; | ||
| obj.lowboundSlider = min([obj.fIndsRed;obj.fRef],[],1); | ||
| sliderLowBound = obj.lowboundSlider; | ||
| sliderUpBound = obj.upboundSlider; | ||
| end | ||
| 
     | 
||
| function releaseObjectiveBounds(obj) | ||
| obj.upboundRed = obj.upboundInit; | ||
| obj.fIndsRed = obj.fIndsAll; | ||
| obj.upboundSlider = obj.upboundInit; | ||
| obj.lowboundSlider = obj.lowboundSliderInit; | ||
| end | ||
| 
     | 
||
| end | ||
| end | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,227 @@ | ||
| function matRad_UIInterpolation(data,dij,pln,ct,cst,optiProb) | ||
| 
     | 
||
| 
     | 
||
| fInds = data.finds; | ||
| 
     | 
||
| 
     | 
||
| %sort function values according to each dimension - still necessary? | ||
| [A,I] = sort(fInds(:,1),1,'ascend'); | ||
| fIndsSorted = fInds(I,:); | ||
| weights = data.weights(:,I); | ||
| %idx = round(size(fInds,1)/2); | ||
| idx = 4; | ||
| %% | ||
| 
     | 
||
| slice = round(pln.propStf.isoCenter(1,3)./ct.resolution.z); | ||
| %% | ||
| 
     | 
||
| %% | ||
| f = figure('units','normalized','outerposition',[0 0 1 1]); | ||
| DosePlot = axes('Position',[.1 .5 .4 .4]); | ||
| title('Dose Slice') | ||
| DVHPlot = axes('Position',[.6 .5 .35 .4]); | ||
| title('DVH'); | ||
| % | ||
| 
     | 
||
| %Create uipanels | ||
| p = uipanel(f,'Position',[0.05 0.1 0.3 0.35]); | ||
| p2 = uipanel(f,'Position',[0.35 0.3 0.15 0.15]); | ||
| 
     | 
||
| %extract the names of the objectives and corresponding VOI | ||
| names = {}; | ||
| for i = (1:numel(optiProb.objectives)) | ||
| names{end + 1} = optiProb.objectives{i}.name; | ||
| end | ||
| 
     | 
||
| VOIs = {}; | ||
| for i = 1:size(cst,1) | ||
| if ~isempty(cst{i,6}) | ||
| VOIs{end + 1} = cst{i,2}; | ||
| end | ||
| end | ||
| %Generate reference point (should lie somewhere in the middle of | ||
| %objective 1) | ||
| fRef = fIndsSorted(idx,:); | ||
| wRef = weights(:,idx); | ||
| refObj = matRad_UIData(wRef,fRef,fIndsSorted); | ||
| 
     | 
||
| %initial UI elements | ||
| sliders = {}; | ||
| namesui = {}; | ||
| sliderValues = {}; | ||
| fixButtons = {}; | ||
| VOIui = {}; | ||
| 
     | 
||
| %%Create interactive elements | ||
| for i = 1:size(fInds,2) | ||
| VOIui{i} = uicontrol(p,'Style','text',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.02,0.9-(i-1)*0.13, 0.15,0.1],... | ||
| 'String',VOIs{i}); | ||
| 
     | 
||
| namesui{i} = uicontrol(p,'Style','text',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.17,0.9-(i-1)*0.13, 0.22,0.1],... | ||
| 'String',names{i}); | ||
| 
     | 
||
| sliderValues{i} = uicontrol(p,'Style','text',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.9,0.9-(i-1)*0.13, 0.1,0.05],... | ||
| 'String',fIndsSorted(idx,i)); | ||
| 
     | 
||
| sliders{i} = uicontrol(p,'Style','slider',... | ||
| 'Units','normalized',... | ||
| 'Min',min(fIndsSorted(:,i)),'Max',max(fIndsSorted(:,i)),... | ||
| 'Position',[0.4,0.9-(i-1)*0.13, 0.35,0.05]); | ||
| 
     | 
||
| 
     | 
||
| fixButtons{i} = uicontrol(p,'Style','pushbutton',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.78,0.9-(i-1)*0.13, 0.1,0.05],... | ||
| 'String','Fix'); | ||
| 
     | 
||
| sliders{i}.Value = fIndsSorted(idx,i); | ||
| 
     | 
||
| end | ||
| 
     | 
||
| DVHButton = uicontrol(p2,'Style','pushbutton',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.1 0.6 0.35 0.3],... | ||
| 'String','Show DVH'); | ||
| 
     | 
||
| ExportButton = uicontrol(p2,'Style','pushbutton',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.55 0.6 0.35 0.3],... | ||
| 'String','Export to GUI'); | ||
| 
     | 
||
| ResetConstraintButton = uicontrol(p2,'Style','pushbutton',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.2 0.3 0.6 0.2],... | ||
| 'String','Reset Constraints'); | ||
| 
     | 
||
| ParetoSurfaceButton = uicontrol(p2,'Style','pushbutton',... | ||
| 'Units','normalized',... | ||
| 'Position',[0.2 0.05 0.6 0.2],... | ||
| 'String','Show PS'); | ||
| 
     | 
||
| 
     | 
||
| %%Set callback for buttons | ||
| for i = 1:size(fInds,2) | ||
| set(sliders{i},'Callback',{@slider_callback,sliderValues,sliders,i,weights,dij,slice,DosePlot,refObj,optiProb,data.modcst,cst,pln,ct}) | ||
| end | ||
| 
     | 
||
| for i = 1:numel(fixButtons) | ||
| set(fixButtons{i},'Callback',{@FixButton_callback,refObj,sliders,i}) | ||
| end | ||
| 
     | 
||
| set(DVHButton,'Callback',{@DVHButton_callback,cst,refObj,dij,pln}) | ||
| set(ExportButton,'Callback',{@ExportButton_callback,refObj,dij}) | ||
| set(ResetConstraintButton,'Callback',{@ResetConstraintButton_callback,refObj,sliders}) | ||
| set(ParetoSurfaceButton,'Callback',{@ParetoSurfaceButton_callback,refObj}) | ||
| 
     | 
||
| 
     | 
||
| %initial plot of first point | ||
| 
     | 
||
| cubes = reshape(dij.physicalDose{1}*wRef,dij.doseGrid.dimensions); | ||
| 
     | 
||
| cubes = matRad_interp3(dij.doseGrid.x,dij.doseGrid.y',dij.doseGrid.z, ... | ||
| cubes, ... | ||
| dij.ctGrid.x,dij.ctGrid.y',dij.ctGrid.z,'linear',0); | ||
| 
     | 
||
| matRad_plotSliceWrapper(DosePlot,ct,cst,1,cubes,3,slice); | ||
| %zoom(DosePlot,1.1); | ||
| dvh = matRad_calcDVH(cst,cubes,'cum'); | ||
| matRad_showDVH(dvh,cst,pln); | ||
| 
     | 
||
| end | ||
| % End of main file | ||
| function DVHButton_callback(~,~,cst,refObj,dij,pln) | ||
| %Shows the DVH for the current plan | ||
| resultGUI = matRad_calcCubes(refObj.wRef,dij); | ||
| %dvh = matRad_calcDVH(cst,doseCube,'cum'); | ||
| dvh = matRad_calcDVH(cst,resultGUI.physicalDose,'cum'); | ||
| 
     | 
||
| matRad_showDVH(dvh,cst,pln,refObj.linestyle); | ||
| if refObj.linestyle < 4 | ||
| refObj.linestyle = refObj.linestyle + 1; | ||
| else | ||
| refObj.linestyle = 1; | ||
| end | ||
| % | ||
| 
     | 
||
| end | ||
| 
     | 
||
| function ExportButton_callback(~,~,refObj,dij) | ||
| %Export the current plan to the matRadGUi for better inspection | ||
| resultGUI = matRad_calcCubes(refObj.wRef,dij); | ||
| assignin('base',"resultGUI",resultGUI); | ||
| matRadGUI; | ||
| 
     | 
||
| end | ||
| 
     | 
||
| 
     | 
||
| function FixButton_callback(~,~,refObj,sliders,i) | ||
| 
     | 
||
| [lb,ub] = refObj.restrictObjective(i,sliders{i}.Value); %update refObjects bounds | ||
| 
     | 
||
| 
     | 
||
| for i = 1:numel(sliders) | ||
| set(sliders{i},'Min',lb(i)); | ||
| set(sliders{i},'Max',ub(i)); | ||
| end | ||
| end | ||
| 
     | 
||
| 
     | 
||
| function ResetConstraintButton_callback(~,~,refObj,sliders) | ||
| refObj.releaseObjectiveBounds(); | ||
| 
     | 
||
| for i = 1:numel(sliders) | ||
| set(sliders{i},'Min',refObj.lowboundSliderInit(i)); | ||
| set(sliders{i},'Max',refObj.upboundInit(i)); | ||
| end | ||
| end | ||
| 
     | 
||
| function ParetoSurfaceButton_callback(~,~,refObj) | ||
| %TODO: Should only show up in low dimensions | ||
| matRad_plotPS(refObj); | ||
| 
     | 
||
| end | ||
| 
     | 
||
| 
     | 
||
| % Callback subfunctions to support UI actions | ||
| function slider_callback(slider,~,textFields,sliders,idx,weights,dij,slice,DosePlot,refObj,optiProb,cstMod,cst,pln,ct) | ||
| % Update the text for the moved slider | ||
| %Calculate combination weights | ||
| 
     | 
||
| 
     | 
||
| v = matRad_navigationProblem(refObj.fIndsAll',refObj.fRef,slider.Value,idx,refObj.upboundRed); | ||
| %%need to check actual dimensions | ||
| if numel(v) == 0 | ||
| %navigation algorithm didnt find a new point | ||
| for i = 1:numel(sliders) | ||
| set(sliders{i},'Value',refObj.fRef(i)); | ||
| set(textFields{i},'String',refObj.fRef(i)); | ||
| end | ||
| 
     | 
||
| else | ||
| 
     | 
||
| wnew = weights*v;%new weights | ||
| 
     | 
||
| fNew = matRad_objectiveFunctions(optiProb,wnew,dij,cstMod); | ||
| fNew = optiProb.normalizeObjectives(fNew'); | ||
| refObj.fRef = fNew; | ||
| refObj.wRef = wnew; | ||
| 
     | 
||
| %% should be moved to seperate function | ||
| cubes = matRad_calcFastCubes(wnew,dij,pln); | ||
| %#Update the slider and text values for objective functions | ||
| 
     | 
||
| for i = 1:numel(sliders) | ||
| set(sliders{i},'Value',fNew(i)); | ||
| set(textFields{i},'String',fNew(i)); | ||
| end | ||
| 
     | 
||
| %Plot updated plan | ||
| matRad_plotSliceWrapper(DosePlot,ct,cst,1,cubes,3,slice); | ||
| end | ||
| end | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| function cubes = matRad_calcFastCubes(w,dij,pln) | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the speedup you gain by this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could also alternatively cycle through the projections stored in OptimizationProblem? Are they not fast enough? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First option would calculate too many quantities if we have something like RBExD etc. Second option might be possible, but I thought the backprojections are mainly meant for usage in the optimization problem  | 
||
| % matRad computation of cube for plan optimization quantity | ||
| % | ||
| % call | ||
| % resultGUI = matRad_calcCubes(w,dij,pln | ||
| % | ||
| % input | ||
| % w: bixel weight vector | ||
| % dij: dose influence matrix | ||
| % pln: matRad pln struct | ||
| % | ||
| % output | ||
| % cubes: Array storing cubes of optimization quantity | ||
| % | ||
| % References | ||
| % - | ||
| % | ||
| % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
| % | ||
| % Copyright 2015 the matRad development team. | ||
| % | ||
| % This file is part of the matRad project. It is subject to the license | ||
| % terms in the LICENSE file found in the top-level directory of this | ||
| % distribution and at https://github.com/e0404/matRad/LICENSES.txt. No part | ||
| % of the matRad project, including this file, may be copied, modified, | ||
| % propagated, or distributed except according to the terms contained in the | ||
| % LICENSE file. | ||
| % | ||
| % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
| switch pln.bioParam.quantityOpt | ||
| case 'physicalDose' | ||
| cubes = reshape(dij.physicalDose{1}*w,dij.doseGrid.dimensions); | ||
| case 'RBExD' | ||
| if isfield(dij,'mAlphaDose') && isfield(dij,'mSqrtBetaDose') | ||
| %TODO | ||
| matRad_cfg.dispError('TODO'); | ||
                
       | 
||
| else | ||
| cubes = reshape(dij.physicalDose{1}*w,dij.doseGrid.dimensions)*dij.RBE; | ||
| end | ||
| case 'effect' | ||
| cubes = reshape(full(dij.mAlphaDose{1} * wBeam + (dij.mSqrtBetaDose{1} * wBeam).^2),dij.doseGrid.dimensions); | ||
| end | ||
| cubes = matRad_interp3(dij.doseGrid.x,dij.doseGrid.y',dij.doseGrid.z, ... | ||
| cubes, ... | ||
| dij.ctGrid.x,dij.ctGrid.y',dij.ctGrid.z,'linear',0); | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should follow the Widget mechanism (check the gui folder). Create a widget derived from matRad_Widget here, you may ask @amitantony for help with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes :D