Skip to content
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

Brachytherapy Integration (Update) #718

Merged
merged 80 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
d2a510d
MatRad Brachytherapy
Copani Apr 28, 2021
c0e45f7
Update README.md
Copani Apr 28, 2021
dcc6bbf
Update README.md
Copani Apr 28, 2021
a467b1c
Update README.md
Copani Apr 28, 2021
5181588
Merge branch 'e0404:master' into master
Copani May 7, 2021
c7555ba
BrachyStf 0.1
Copani May 8, 2021
2f79f5f
first (crudely) tested version of stf generation
Copani May 26, 2021
89ea39f
Plan and optimization
Copani Jun 14, 2021
f2b360c
unittests added
Copani Jun 21, 2021
3109979
Complete brachy workflow
Copani Jul 4, 2021
bd430f9
Tested and revised
Copani Aug 3, 2021
1e4ede2
small change
Copani Aug 3, 2021
e6214af
matRad.m back to normal
Copani Aug 3, 2021
1d27de4
Merge branch 'dev' into master
wahln Aug 19, 2021
de76a07
remove matlab drive tags
wahln Dec 2, 2021
b09b54a
Merge branch 'dev' into master
wahln Dec 2, 2021
5f26175
Update AUTHORS.txt
wahln Dec 2, 2021
86f88a2
remove the matRad_brachy script and the hardcoded matRad_changeCST sc…
wahln Dec 2, 2021
1eb0af8
clean up of brachy example script
wahln Dec 2, 2021
808b7ea
clean up and adapt documentation of brachy files
wahln Dec 3, 2021
0a390ed
code cleanup
wahln Dec 3, 2021
6740e9f
remove unnecessary structstruct file
wahln Dec 3, 2021
7793b4a
Merge branch 'master' of https://github.com/Copani/matRad into pr/521
wahln Dec 3, 2021
cbc2bff
Merge branch 'dev' of https://github.com/e0404/matRad into pr/521
wahln Dec 3, 2021
d15ed8c
Merge branch 'dev' of https://github.com/e0404/matRad into pr/521
wahln Dec 3, 2021
ec72098
Interpolation on basedata to replace multipoly regession in anisotrop…
amitantony May 26, 2022
76d0f8a
Uses anisotropy estimation polynomial saved in the basedata (brachy_H…
amitantony Jun 8, 2022
9656a9c
exchanges dependancy on MultiPolyRegress to precomputed polynomial in…
amitantony Jun 10, 2022
aa1899b
update brachy test suite
amitantony Jun 10, 2022
55fe46a
removed example plot files
amitantony Jun 10, 2022
96fe281
Merge branch 'dev' into master
wahln Jul 28, 2022
b5dc34b
Merge branch 'dev_varRBErobOpt' of https://github.com/Gattowski/matRa…
Gattowski Mar 14, 2024
24418fa
Merge branch 'refactor/doseEnginesRobOpt' into dev_varRBErobOpt_BT
Gattowski Mar 14, 2024
c3371ad
renamed: examples/matRad_example8_brachy.m -> examples/matRad_exam…
Gattowski Mar 14, 2024
1caaa7a
moved the brachy test Unit folder
Gattowski Mar 18, 2024
612edce
deleted old unittest folder
Gattowski Mar 18, 2024
5740b75
changes to biomodel,config and widget
Gattowski Mar 27, 2024
3df9ad1
TG43 engine " It just Works "
Gattowski Apr 15, 2024
ebc3409
TG43 engine working apparently
Gattowski Apr 17, 2024
7515d18
removed excess code made stf properly and preparing to move the bracy…
Gattowski Apr 18, 2024
0aa0c9c
engine working properly, code and functions seperated, RT/BT stf merg…
Gattowski May 2, 2024
f850061
trying to fix unitetests
Gattowski May 6, 2024
8abf8ce
brachy engine is functional, brachy example is working and unittests …
Gattowski May 8, 2024
c9ad98a
Added comments on the brachyengine and possible fix on the github run…
Gattowski May 15, 2024
a2d51fd
possible fix on cleanup tests. If it passes 3/3 it's ready for PR.
Gattowski May 15, 2024
cbc8340
testing again the cleanup tests
Gattowski May 15, 2024
f99b33b
fixed cleanup tests if it's git status checks are 3/3 branch is ready…
Gattowski May 15, 2024
07a79b3
clean up tests #1213210310
Gattowski May 15, 2024
6a8a9b0
Merge branch 'refactor/doseEnginesRobOpt' into refactor/doseEnginesRo…
wahln May 15, 2024
26b5904
Merge branch 'dev_varRBErobOpt' into refactor/doseEnginesRobOpt_BT
Gattowski May 23, 2024
a6e41d0
started with adding the brachy folder temp save
Gattowski May 23, 2024
64ed7db
123
Gattowski May 23, 2024
b7a8ab5
test
Gattowski May 23, 2024
67f6a51
test2
Gattowski May 23, 2024
44f4a72
Moved the brachy Unit Tests inside the test folder and formed accordi…
Gattowski May 25, 2024
46f6507
Made the unit tests according the MOxUnit framework
Gattowski May 25, 2024
0d63f61
test
Gattowski May 27, 2024
ec261a7
Fix on push tests, working optimizer and generateSTF switch case incl…
Gattowski Jun 10, 2024
5038b9c
fixing test push results
Gattowski Jun 10, 2024
782965f
adawda dawdawdawda
Gattowski Jun 10, 2024
3e0cfba
test fixup?
Gattowski Jun 10, 2024
6222d6f
test cleanup test
Gattowski Jun 10, 2024
b8d0d2b
Merge pull request #730 from Gattowski/dev_varRBErobOptBT
wahln Jun 20, 2024
d6e8b73
Merge branch 'dev_varRBErobOpt' into feature/brachytherapy
wahln Jun 20, 2024
e36200e
Merge branch 'dev_varRBErobOpt' into feature/brachytherapy
wahln Jun 20, 2024
5e5a2c2
some initial file cleanup
wahln Jun 20, 2024
22abf7e
fix startTime recording for distance transform calculatoin
wahln Jun 20, 2024
fd7311a
some adaptations to the brachy engine and further cleanup
wahln Jun 20, 2024
752f6dd
Merge branch 'dev_varRBErobOpt' into feature/brachytherapy
wahln Jul 3, 2024
a5efbe1
Merge branch 'dev_varRBErobOpt' into feature/brachytherapy
wahln Jul 3, 2024
23bd0ca
Merge branch 'dev' into feature/brachytherapy
wahln Jul 3, 2024
31f0e3c
fix wrongly used coordinates in generateStf
wahln Jul 3, 2024
425e936
fix brachy stf generation test
wahln Jul 3, 2024
def4b4a
Merge branch 'dev_varRBErobOpt' into feature/brachytherapy
wahln Jul 3, 2024
026398c
fix brachy thests
wahln Jul 3, 2024
b01c7c0
fix default iterations variable
wahln Jul 3, 2024
7bf583a
Merge branch 'dev_varRBErobOpt' into feature/brachytherapy
wahln Jul 5, 2024
83e5cbd
Merge branch 'dev_varRBErobOpt' into feature/brachytherapy
wahln Jul 5, 2024
8228330
revert fallback radiation mode in biological model
wahln Jul 9, 2024
7e8c567
Add Marios Dallas to authors
wahln Jul 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
* Lucas Burigo
* Gonzalo Cabal
* Eduadro Cisternas
* Edgardo Doerner
* Louis Charton
* Eric Christiansen
* Marios Dallas
* Edgardo Doerner
* Hubert Gabrys
* Josefine Handrack
* Jennifer Hardt
Expand All @@ -29,6 +30,7 @@
* Martina Palkowitsch
* Giuseppe Pezzano
* Daniel Ramirez
* Claus Sarnighausen
* Carsten Scholz
* Camilo Sevilla
* Alexander Stadler
Expand All @@ -37,4 +39,4 @@
* Jona Welsch
* Hans-Peter Wieser
* Johanna Winter
* Tong Xu
* Tong Xu
237 changes: 237 additions & 0 deletions examples/matRad_example15_brachy.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
%% Example: Brachytheraphy Treatment Plan
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright 2021 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/LICENSE.md. 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.
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%% List of contents
% In this example we will show
% (i) how to load patient data into matRad
% (ii) how to setup an HDR brachy dose calculation and
% (iii) how to inversely optimize holding position intensties
% (iv) how to visually and quantitatively evaluate the result
% (v) how to verify that functions do the right thing

%% I Patient Data Import
% Let's begin with a clear Matlab environment. Then, import the TG119
% phantom into your workspace. The phantom is comprised of a 'ct' and 'cst'
% structure defining the CT images and the structure set. Make sure the
% matRad root directory with all its subdirectories is added to the Matlab
% search path.

matRad_rc;
load 'PROSTATE.mat';

%% I - update/set dose objectives for brachytherapy
% The sixth column represents dose objectives and constraints for
% optimization: First, the objective function for the individual structure
% is chosen, its parameters denote doses that should not be tranceeded
% towards higher or lower doses (SquaredOverdose, SquaredUnderdose) or
% doses that are particularly aimed for (SquaredUnderDose).

disp(cst{6,6}{1});

% Following frequently prescribed planning doses of 15 Gy
% (https://pubmed.ncbi.nlm.nih.gov/22559663/) objectives can be updated to:

% the planning target was changed to the clinical segmentation of the
% prostate bed.
cst{5,3} = 'TARGET';
cst{5,6}{1} = struct(DoseObjectives.matRad_SquaredUnderdosing(100,15));
cst{5,6}{2} = struct(DoseObjectives.matRad_SquaredOverdosing(100,17.5));
cst{6,5}.Priority = 1;

% In this example, the lymph nodes will not be part of the treatment:
cst{7,6} = [];
cst{7,3} = 'OAR';

%A PTV is not needed, but we will use it to control the dose fall off
cst{6,3} = 'OAR';
cst{6,6}{1} = struct(DoseObjectives.matRad_SquaredOverdosing(100,12));
cst{6,5}.Priority = 2;

% Rectum Objective
cst{1,6}{1} = struct(DoseObjectives.matRad_SquaredOverdosing(10,7.5));

% Bladder Objective
cst{8,6}{1} = struct(DoseObjectives.matRad_SquaredOverdosing(10,7.5));

% Body NT objective
cst{9,6}{1} = struct(DoseObjectives.matRad_MeanDose(1));


%% II.1 Treatment Plan
% The next step is to define your treatment plan labeled as 'pln'. This
% matlab structure requires input from the treatment planner and defines
% the most important cornerstones of your treatment plan.

% First of all, we need to define what kind of radiation modality we would
% like to use. Possible values are photons, protons or carbon
% (external beam) or brachy as an invasive tratment option.
% In this case we want to use brachytherapy. Then, we need to define a
% treatment machine to correctly load the corresponding base data.
% matRad includes example base data for HDR and LDR brachytherapy.
% Here we will use HDR. By this means matRad will look for 'brachy_HDR.mat'
% in our root directory and will use the data provided in there for
% dose calculation.

pln.radiationMode = 'brachy';
pln.machine = 'HDR'; % 'LDR' or 'HDR' for brachy

quantityOpt = 'physicalDose';
modelName = 'none';

% retrieve bio model parameters
pln.bioParam = matRad_bioModel(pln.radiationMode,quantityOpt, modelName);

% retrieve scenarios for dose calculation and optimziation
pln.multScen = matRad_multScen(ct,'nomScen');
% dose calculation settings
%Choose BT Engine
pln.propDoseCalc.engine = 'TG43';



%% II.1 - needle and template geometry
% Now we have to set some parameters for the template and the needles.
% Let's start with the needles: Seed distance is the distance between
% two neighbouring seeds or holding points on one needle or catheter. The
% seeds No denotes how many seeds/holding points there are per needle.

pln.propStf.needle.seedDistance = 10; % [mm]
pln.propStf.needle.seedsNo = 6;

%% II.1 - template position
% The implantation is normally done through a 13 x 13 template from the
% patients inferior, which is the negative z axis here.
% The direction of the needles is defined by template normal.
% Neighbour distances are called by bixelWidth, because this field is also
% used for external beam therapy.
% The needles will be positioned right under the target volume pointing up.


pln.propStf.bixelWidth = 5; % [mm] template grid distance
pln.propStf.templateRoot = matRad_getTemplateRoot(ct,cst); % mass center of
% target in x and y and bottom in z

% Here, we define active needles as 1 and inactive needles
% as 0. This is the x-y plane and needles point in z direction.
% A checkerboard pattern is frequantly used. The whole geometry will become
% clearer when it is displayed in 3D view in the next section.

pln.propStf.template.activeNeedles = [0 0 0 1 0 1 0 1 0 1 0 0 0;... % 7.0
0 0 1 0 1 0 0 0 1 0 1 0 0;... % 6.5
0 1 0 1 0 1 0 1 0 1 0 1 0;... % 6.0
1 0 1 0 1 0 0 0 1 0 1 0 1;... % 5.5
0 1 0 1 0 1 0 1 0 1 0 1 0;... % 5.0
1 0 1 0 1 0 0 0 1 0 1 0 1;... % 4.5
0 1 0 1 0 1 0 1 0 1 0 1 0;... % 4.0
1 0 1 0 1 0 0 0 1 0 1 0 1;... % 4.5
0 1 0 1 0 1 0 1 0 1 0 1 0;... % 3.0
1 0 1 0 1 0 1 0 1 0 1 0 1;... % 2.5
0 1 0 1 0 1 0 1 0 1 0 1 0;... % 2.0
1 0 1 0 1 0 0 0 0 0 1 0 1;... % 1.5
0 0 0 0 0 0 0 0 0 0 0 0 0]; % 1.0
%A a B b C c D d E e F f G

pln.propStf.isoCenter = matRad_getIsoCenter(cst,ct,0); % target center



%% II.1 - dose calculation options
% for dose calculation we use eather the 2D or the 1D formalism proposed by
% TG 43. Also, set resolution of dose calculation and optimization.
% If your system gets stuck with the resolution, you can lower it to 10 or
% 20, just to get an initial result. Otherwise, reduce the number of
% needles.
% Calculation time will be reduced by one tenth when we define a dose
% cutoff distance.


pln.propDoseCalc.TG43approximation = '2D'; %'1D' or '2D'

pln.propDoseCalc.doseGrid.resolution.x = 5; % [mm]
pln.propDoseCalc.doseGrid.resolution.y = 5; % [mm]
pln.propDoseCalc.doseGrid.resolution.z = 5; % [mm]



% We can also use other solver for optimization than IPOPT. matRad
% currently supports simulannealbnd from the MATLAB Global Optimization Toolbox. First we
% check if the simulannealbnd-Solver is available, and if it is, we set in in the
% pln.propOpt.optimizer varirable. Otherwise we set to the default
% optimizer 'IPOPT'
if matRad_OptimizerSimulannealbnd.IsAvailable()
pln.propOpt.optimizer = 'simulannealbnd';
else
pln.propOpt.optimizer = 'IPOPT';
end
%% II.1 - book keeping
% Some field names have to be kept although they don't have a direct
% relevance for brachy therapy.
pln.propOpt.bioOptimization = 'none';
pln.propOpt.runDAO = false;
pln.propOpt.runSequencing = false;
pln.propStf.gantryAngles = [];
pln.propStf.couchAngles = [];
pln.propStf.numOfBeams = 0;
pln.numOfFractions = 1;

%% II.1 - view plan
% Et voila! Our treatment plan structure is ready. Lets have a look:
disp(pln);


%% II.2 Steering Seed Positions From STF
% The steering file struct contains all needls/catheter geometry with the
% target volume, number of needles, seeds and the positions of all needles
% The one in the end enables visualization.

stf = matRad_generateStf(ct,cst,pln,1);

%% II.2 - view stf
% The 3D view is interesting, but we also want to know how the stf struct
% looks like.

disp(stf)

%% II.3 - Dose Calculation
% Let's generate dosimetric information by pre-computing a dose influence
% matrix for seed/holding point intensities. Having dose influences
% available allows subsequent inverse optimization.
% Don't get inpatient, this can take a few seconds...

dij = matRad_calcDoseInfluence(ct,cst,stf,pln);

%% III Inverse Optimization for brachy therapy
% The goal of the fluence optimization is to find a set of holding point
% times which yield the best possible dose distribution according to
% the clinical objectives and constraints underlying the radiation
% treatment. Once the optimization has finished, trigger to
% visualize the optimized dose cubes.

resultGUI = matRad_fluenceOptimization(dij,cst,pln);
matRadGUI;

%% IV.1 Plot the Resulting Dose Slice
% Let's plot the transversal iso-center dose slice

slice = round(pln.propStf.isoCenter(1,3)./ct.resolution.z);
figure
imagesc(resultGUI.physicalDose(:,:,slice)),colorbar, colormap(jet);

%% IV.2 Obtain dose statistics
% Two more columns will be added to the cst structure depicting the DVH and
% standard dose statistics such as D95,D98, mean dose, max dose etc.
[dvh,qi] = matRad_indicatorWrapper(cst,pln,resultGUI);

13 changes: 6 additions & 7 deletions matRad.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@
matRad_rc

%% load patient data, i.e. ct, voi, cst

%load HEAD_AND_NECK
load TG119.mat
%load HEAD_AND_NECK
%load PROSTATE.mat
%load LIVER.mat
%load BOXPHANTOM.mat

% meta information for treatment plan
pln.numOfFractions = 30;
pln.radiationMode = 'photons'; % either photons / protons / helium / carbon
pln.machine = 'Generic';
pln.radiationMode = 'photons'; % either photons / protons / helium / carbon / brachy
pln.machine = 'Generic'; % generic for RT / LDR or HDR for BT

% beam geometry settings
pln.propStf.bixelWidth = 5; % [mm] / also corresponds to lateral spot spacing for particles
Expand All @@ -40,7 +39,7 @@
pln.propOpt.runSequencing = false; % 1/true: run sequencing, 0/false: don't / will be ignored for particles and also triggered by runDAO below

quantityOpt = 'physicalDose'; % options: physicalDose, effect, RBExD
modelName = 'none'; % none: for photons, protons, carbon % constRBE: constant RBE for photons and protons
modelName = 'none'; % none: for photons, protons, carbon, brachy % 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 % HEL: data-driven RBE parametrization for helium
% dose calculation settings
Expand All @@ -67,11 +66,11 @@
%% initial visualization and change objective function settings if desired
matRadGUI

%% generate steering file
%% generate steering file
stf = matRad_generateStf(ct,cst,pln);

%% dose calculation
dij = matRad_calcDoseInfluence(ct,cst,stf,pln);
dij = matRad_calcDoseInfluence(ct, cst, stf, pln);

%% inverse planning for imrt
resultGUI = matRad_fluenceOptimization(dij,cst,pln);
Expand Down
Binary file added matRad/basedata/brachy_HDR.mat
Binary file not shown.
Binary file added matRad/basedata/brachy_LDR.mat
Binary file not shown.
49 changes: 45 additions & 4 deletions matRad/bioModels/matRad_BiologicalModel.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
% e.g. pln.bioParam = matRad_BiologicalModel('protons','constRBE','RBExD')
%
% input
% sRadiationMode: radiation modality 'photons' 'protons' 'carbon'
% sRadiationMode: radiation modality 'photons' 'protons' 'carbon' 'brachy'
%
%
% sQuntityOpt: string to denote the quantity used for
% optimization 'physicalDose', 'RBExD', 'effect'
% sModel: string to denote which biological model is used
Expand Down Expand Up @@ -60,7 +62,7 @@
% constant public properties which are visible outside of this class
properties(Constant = true)
AvailableModels = {'none','constRBE','MCN','WED','LEM','HEL'}; % cell array determines available models - if cell is deleted then the corersponding model can not be generated
AvailableradiationModealities = {'photons','protons','helium','carbon'};
AvailableradiationModealities = {'photons','protons','helium','carbon','brachy'};
AvailableQuantitiesForOpt = {'physicalDose','effect','RBExD'};

AvailableAlphaXBetaX = {[0.036 0.024], 'prostate';
Expand All @@ -79,7 +81,8 @@

constRBE_protons = 1.1;
constRBE_photons = 1;



%McNamara variable RBE model for protons
p0_MCN = 0.999064; % according to https://www.ncbi.nlm.nih.gov/pubmed/26459756
p1_MCN = 0.35605;
Expand Down Expand Up @@ -272,6 +275,44 @@
matRad_cfg.dispWarning(['matRad: Invalid biological optimization quantity: ' this.quantityOpt '; using "none" instead.']);
this.quantityOpt = 'physicalDose';
end

case {'brachy'}

setDefaultValues = false;
switch this.quantityOpt

case {'physicalDose'}
if strcmp(this.model,'none')
boolCHECK = true;
this.bioOpt = false;
this.quantityVis = 'physicalDose';
else
setDefaultValues = true;
end

case {'RBExD'}
if sum(strcmp(this.model,{'constRBE', 'none'})) == 1
this.RBE = this.constRBE_photons;
boolCHECK = true;
this.bioOpt = false;
this.quantityVis = 'RBExD';
else
setDefaultValues = true;
end

case {'effect'}
if strcmp( this.model,'none')
boolCHECK = true;
this.bioOpt = true;
this.quantityVis = 'RBExD';
else
setDefaultValues = true;
end

otherwise
matRad_cfg.dispWarning('matRad: Invalid biological optimization quantity: %s; using physical dose instead.',this.quantityOpt);
this.quantityOpt = 'physicalDose';
end

otherwise
matRad_cfg.dispWarning(['matRad: Invalid biological radiation mode: ' this.radiationMode '; using photons instead.']);
Expand Down Expand Up @@ -325,7 +366,7 @@

% setter functions
function this = set.radiationMode(this,value)
if ischar(value) && sum(strcmp(value,{'photons','protons','helium','carbon'})) == 1
if ischar(value) && sum(strcmp(value,{'photons','protons','helium','carbon','brachy'})) == 1
this.radiationMode = value;
else
matRad_cfg = MatRad_Config.instance();
Expand Down
Loading