Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,22 @@

end
end

methods (Static)


function [alphaX, betaX] = getAvailableTissueParameters(pln)

% load machine
machine = matRad_loadMachine(pln);
if isfield(machine.data,'alphaX') && isfield(machine.data,'betaX')
alphaX = machine.data(1).alphaX;
betaX = machine.data(1).betaX;
else
matRad_cfg = MatRad_Config.instance();
matRad_cfg.dispError('The selected biological model requires AlphaX and BetaX to be set in the machine file but none was found.');
end

end
end
end
7 changes: 7 additions & 0 deletions matRad/bioModels/matRad_BiologicalModel.m
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,13 @@
end
end

function [alphaX, betaX] = getAvailableTissueParameters(pln)
% empty values in standard implementation, needs to be
% overwritten in subclasses
alphaX = [];
betaX = [];
end


end

Expand Down
58 changes: 10 additions & 48 deletions matRad/bioModels/matRad_bioModel.m
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
function model = matRad_bioModel(sRadiationMode, sModel)
function model = matRad_bioModel(radiationMode, model, providedQuantities)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% matRad_bioModel
% This is a helper function to instantiate a matRad_BiologicalModel. This
% function currently exists for downwards compatability, as the new
% Biological Models will follow a polymorphic software architecture
%
% call
% matRad_bioModel(sRadiationMode, sModel)
% matRad_bioModel(radiationMode, model)
%
% e.g. pln.bioModel = matRad_bioModel('protons','MCN')
%
% input
% sRadiationMode: radiation modality 'photons' 'protons' 'helium' 'carbon' 'brachy'
% radiationMode: radiation modality 'photons' 'protons' 'helium' 'carbon' 'brachy'
%
% sModel: string to denote which biological model is used
% model: string to denote which biological model is used
% 'none': for photons, protons, carbon 'constRBE': constant RBE for photons and protons
% 'MCN': McNamara-variable RBE model for protons 'WED': Wedenberg-variable RBE model for protons
% 'LEM': Local Effect Model for carbon ions
%
% providedQuantities: optional cell string of provided quantities to
% check if the model can be evaluated
%
% output
% model: instance of a biological model
%
Expand All @@ -36,51 +39,10 @@
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

matRad_cfg = MatRad_Config.instance();

% Look for the correct inputs
p = inputParser;
addRequired(p, 'sRadiationMode', @ischar);
addRequired(p, 'sModel',@ischar);

p.KeepUnmatched = true;

%Check for the available models
mainFolder = fullfile(matRad_cfg.matRadSrcRoot,'bioModels');
userDefinedFolder = fullfile(matRad_cfg.primaryUserFolder, 'bioModels');

if ~exist(userDefinedFolder,"dir")
folders = {mainFolder};
if nargin < 3
model = matRad_BiologicalModel.validate(model,radiationMode);
else
folders = {mainFolder,userDefinedFolder};
end

availableBioModelsClassList = matRad_findSubclasses('matRad_BiologicalModel', 'folders', folders , 'includeSubfolders',true);
modelInfos = matRad_identifyClassesByConstantProperties(availableBioModelsClassList,'model');
modelNames = {modelInfos.model};

if numel(unique({modelInfos.model})) ~= numel(modelInfos)
matRad_cfg.dispError('Multiple biological models with the same name available.');
model = matRad_BiologicalModel.validate(model,radiationMode,providedQuantities);
end

selectedModelIdx = find(strcmp(sModel, modelNames));

% Create first instance of the selected model
if ~isempty(selectedModelIdx)
tmpBioParam = modelInfos(selectedModelIdx).handle();
else
matRad_cfg.dispError('Unrecognized biological model: %s', sModel);
end

% For the time being I do not assigne the model specific parameters, they
% can be assigned by the user later

correctRadiationModality = any(strcmp(tmpBioParam.possibleRadiationModes, sRadiationMode));

if ~correctRadiationModality
matRad_cfg.dispError('Incorrect radiation modality for the required biological model');
end

model = tmpBioParam;

end % end function
82 changes: 70 additions & 12 deletions matRad/gui/widgets/matRad_PlanWidget.m
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,7 @@ function btnSetTissue_Callback(this, hObject, eventdata)

if evalin('base','exist(''cst'')') && evalin('base','exist(''pln'')')
try
matRad_cfg = MatRad_Config.instance();
%parse variables from base-workspace
cst = evalin('base','cst');
pln = evalin('base','pln');
Expand All @@ -1476,9 +1477,27 @@ function btnSetTissue_Callback(this, hObject, eventdata)
fileName = [pln.radiationMode '_' pln.machine];
load(fileName);

% check for available cell types characterized by alphaX and betaX
for i = 1:size(machine.data(1).alphaX,2)
CellType{i} = [num2str(machine.data(1).alphaX(i)) ' ' num2str(machine.data(1).betaX(i))];
%biological model
if isfield(matRad_cfg.defaults.bioModel,pln.radiationMode)
defaultModel = matRad_cfg.defaults.bioModel.(pln.radiationMode);
else
defaultModel = matRad_cfg.defaults.bioModel.fallback;
end
if ~isfield(pln,'bioModel')
pln.bioModel = defaultModel;
end

bioModel = matRad_BiologicalModel.validate(pln.bioModel,pln.radiationMode);

[availableAlphaX, availableBetaX] = bioModel.getAvailableTissueParameters(pln);

if ~isempty(availableAlphaX) && ~isempty(availableBetaX)
for i = 1:size(availableAlphaX,2)
CellType{i} = [num2str(availableAlphaX(i)) ' ' num2str(availableBetaX(i))];
columnformat = {'char',CellType,'numeric'};
end
else
columnformat = {'char','numeric','numeric'};
end

%fill table data array
Expand Down Expand Up @@ -1507,16 +1526,42 @@ function btnSetTissue_Callback(this, hObject, eventdata)
%set focus
figure(figTissue);
else
figTissue = figure('Name','Set Tissue Parameters','Color',[.5 .5 .5],'NumberTitle','off','OuterPosition',...
[ceil(ScreenSize(3)/2) 100 Width Height]);
figTissue = figure('Name','Set Tissue Parameters', ...
'NumberTitle','off', ...
'OuterPosition',[ceil(ScreenSize(3)/2) 100 Width Height],...
'Color',matRad_cfg.gui.backgroundColor);
end

% define the tissue parameter table
cNames = {'VOI','alphaX betaX','alpha beta ratio'};
columnformat = {'char',CellType,'numeric'};
% columnformat = {'char',CellType,'numeric'};

%design table colors
colorMatrix = repmat(matRad_cfg.gui.elementColor,size(data,1),1);
ix2 = 2:2:size(data,1);
if ~isempty(ix2)
shadeColor = rgb2hsv(matRad_cfg.gui.elementColor);
if shadeColor(3) < 0.5
shadeColor(3) = shadeColor(3)*1.5+0.1;
else
shadeColor(3) = shadeColor(3)*0.5-0.1;
end

colorMatrix(ix2,:) = repmat(hsv2rgb(shadeColor),numel(ix2),1);
end


% Create the uitable
tissueTable = uitable('Parent', figTissue, ...
'Data', data, ...
'ColumnEditable',[false true false],...
'ColumnName',cNames, ...
'ColumnFormat',columnformat, ...
'Position',[50 150 10 10], ...
'ForegroundColor',matRad_cfg.gui.textColor,...
'BackgroundColor',colorMatrix,...
'RowStriping','on');

tissueTable = uitable('Parent', figTissue,'Data', data,'ColumnEditable',[false true false],...
'ColumnName',cNames, 'ColumnFormat',columnformat,'Position',[50 150 10 10]);
set(tissueTable,'CellEditCallback',@(hObject,eventdata) tissueTable_CellEditCallback(this,hObject,eventdata));
% set width and height
currTablePos = get(tissueTable,'Position');
Expand All @@ -1525,14 +1570,27 @@ function btnSetTissue_Callback(this, hObject, eventdata)
currTablePos(4) = currTableExt(4);
set(tissueTable,'Position',currTablePos);

themeParams = {'BackgroundColor', matRad_cfg.gui.backgroundColor,...
'ForegroundColor',matRad_cfg.gui.textColor,...
'FontSize',matRad_cfg.gui.fontSize,...
'FontName',matRad_cfg.gui.fontName,...
'FontWeight',matRad_cfg.gui.fontWeight};

% define two buttons with callbacks
uicontrol('Parent', figTissue,'Style', 'pushbutton', 'String', 'Save&Close',...
uicontrol('Parent', figTissue, ...
'Style', 'pushbutton', ...
'String', 'Save&Close',...
'Position', [Width-(0.25*Width) 0.1 * Height 70 30],...
'Callback', @(hpb,eventdata)SaveTissueParameters(this,hpb,eventdata));
'Callback', @(hpb,eventdata)SaveTissueParameters(this,hpb,eventdata),...
themeParams{:});

uicontrol('Parent', figTissue,'Style', 'pushbutton', 'String', 'Cancel&Close',...
uicontrol('Parent', ...
figTissue,'Style', ...
'pushbutton', ...
'String', 'Cancel&Close',...
'Position', [Width-(0.5*Width) 0.1 * Height 80 30],...
'Callback', 'close');
'Callback', 'close', ...
themeParams{:});
catch ME
this.showWarning('Could not set Tissue parameter update! Reason: %s\n',ME.message)
end
Expand Down
29 changes: 28 additions & 1 deletion test/bioModel/test_biologicalModel.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,39 @@
if moxunit_util_platform_is_octave()
assertExceptionThrown(@(model) matRad_bioModel('photons', 'MCN'));
assertExceptionThrown(@(model) matRad_bioModel('protons', 'HEL'));

else
assertExceptionThrown(@(model) matRad_bioModel('photons', 'MCN'), 'matRad:Error');
assertExceptionThrown(@(model) matRad_bioModel('protons', 'HEL'),'matRad:Error');
end

function test_setBiologicalModelProvidedQuantities
bioModel = matRad_bioModel('protons', 'MCN', {'physicalDose','LET'});
assertTrue(isa(bioModel, 'matRad_MCNamara'));

if moxunit_util_platform_is_octave()
assertExceptionThrown(@(model) matRad_bioModel('protons', 'MCN', {'physicalDose'}));
else
assertExceptionThrown(@(model) matRad_bioModel('photons', 'MCN', {'physicalDose'}), 'matRad:Error');
end

function test_tissueParameters_emptyModel
bioModel = matRad_EmptyBiologicalModel();
abx = bioModel.getAvailableTissueParameters(struct());
assertTrue(isempty(abx));

function test_tissueParameters_kernelModel
bioModel = matRad_KernelBasedLEM();
abx = bioModel.getAvailableTissueParameters(struct('machine','Generic','radiationMode','carbon'));
assertTrue(isnumeric(abx));
assertEqual(size(abx,2),2);
assertTrue(size(abx,1) >= 1);

if moxunit_util_platform_is_octave()
assertExceptionThrown(@() bioModel.getAvailableTissueParameters(struct('machine','Generic','radiationMode','photons')));
else
assertExceptionThrown(@() bioModel.getAvailableTissueParameters(struct('machine','Generic','radiationMode','photons')), 'matRad:Error');
end


function test_calcBiologicalQuantitiesForBixel_MCN
bioModel = matRad_bioModel('protons','MCN');
Expand Down
15 changes: 15 additions & 0 deletions test/gui/test_gui_PlanWidget.m
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,21 @@
evalin('base','clear ct cst pln stf dij resultGUI');
delete(h);

function test_PlanWidget_tissuetable
evalin('base','load carbon_testData.mat');

%Modify to have multiple isocenters
h = matRad_PlanWidget();

cb = get(h.handles.btnSetTissue,'Callback');
cb(h.handles.btnSetTissue,[]);

figHandles = get(0,'Children');
assertTrue(strcmp(get(figHandles,'Name'),'Set Tissue Parameters'));

close(figHandles);
delete(h);



%TODO: Test Buttons
Loading