-
Notifications
You must be signed in to change notification settings - Fork 199
Implementation of multi alpha/beta for proton plans with TOPAS #884
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
Are you sure you want to change the base?
Changes from all commits
f0fc4bb
42d0e7c
dba9f96
6d649e8
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 | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -246,14 +246,27 @@ function writeAllFiles(obj,ct,cst,stf,machine,w) | |||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| % Get alpha beta parameters from bioParam struct | ||||||||||||||||||||||||||||||||||
| if isfield(obj.bioParameters, 'tissuseAlphaX') | ||||||||||||||||||||||||||||||||||
| obj.bioParameters.AlphaX = obj.bioModel.tissueAlphaX(1); | ||||||||||||||||||||||||||||||||||
| obj.bioParameters.BetaX = obj.bioModel.tissueBetaX(1); | ||||||||||||||||||||||||||||||||||
| tmpAlphaX = []; | ||||||||||||||||||||||||||||||||||
| tmpBetaX = []; | ||||||||||||||||||||||||||||||||||
| for idx = 1:size(cst, 1) | ||||||||||||||||||||||||||||||||||
| if ~isempty(cst{idx,5}) && isfield(cst{idx,5}, 'alphaX') | ||||||||||||||||||||||||||||||||||
| tmpAlphaX = [tmpAlphaX cst{idx,5}.alphaX]; | ||||||||||||||||||||||||||||||||||
| tmpBetaX = [tmpBetaX cst{idx,5}.betaX]; | ||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||
| if numel(obj.bioParameters.AlphaX)>1 | ||||||||||||||||||||||||||||||||||
| matRad_cfg.dispWarning('!!! Only a unique alpha/beta ratio supported at the moment. Found multiple, only the first one will be used !!!!'); | ||||||||||||||||||||||||||||||||||
| abX = [tmpAlphaX(:) tmpBetaX(:)]; | ||||||||||||||||||||||||||||||||||
| unique_abX = unique(abX, 'rows'); | ||||||||||||||||||||||||||||||||||
| obj.bioParameters.AlphaX = unique_abX(:, 1); | ||||||||||||||||||||||||||||||||||
| obj.bioParameters.BetaX = unique_abX(:, 2); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| % Get alpha beta parameters from bioParam struct | ||||||||||||||||||||||||||||||||||
| if isfield(obj.bioParameters, 'tissueAlphaX') | ||||||||||||||||||||||||||||||||||
| obj.bioParameters.AlphaX = obj.bioModel.tissueAlphaX; | ||||||||||||||||||||||||||||||||||
| obj.bioParameters.BetaX = obj.bioModel.tissueBetaX; | ||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||
| %if numel(obj.bioParameters.AlphaX)>1 | ||||||||||||||||||||||||||||||||||
| % matRad_cfg.dispWarning('!!! Only a unique alpha/beta ratio supported at the moment. Found multiple, only the first one will be used !!!!'); | ||||||||||||||||||||||||||||||||||
| %end | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||
| if obj.scorer.LET | ||||||||||||||||||||||||||||||||||
|
|
@@ -508,10 +521,15 @@ function writeAllFiles(obj,ct,cst,stf,machine,w) | |||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| % Get photon parameters for RBExDose calculation | ||||||||||||||||||||||||||||||||||
| if this.calcBioDose | ||||||||||||||||||||||||||||||||||
| if this.calcBioDose || this.scorer.RBE | ||||||||||||||||||||||||||||||||||
| this.scorer.RBE = true; | ||||||||||||||||||||||||||||||||||
| [dij.ax,dij.bx] = matRad_getPhotonLQMParameters(cst,dij.doseGrid.numOfVoxels,1,VdoseGrid); | ||||||||||||||||||||||||||||||||||
| dij.abx(dij.bx>0) = dij.ax(dij.bx>0)./dij.bx(dij.bx>0); | ||||||||||||||||||||||||||||||||||
| this.calcBioDose = true; | ||||||||||||||||||||||||||||||||||
| [dij.ax,dij.bx] = matRad_getPhotonLQMParameters(cst,dij.doseGrid.numOfVoxels,this.VdoseGrid); | ||||||||||||||||||||||||||||||||||
| dij.abx = zeros(size(dij.ax{1})); | ||||||||||||||||||||||||||||||||||
| ax = dij.ax{1}; | ||||||||||||||||||||||||||||||||||
| bx = dij.bx{1}; | ||||||||||||||||||||||||||||||||||
| dij.abx(bx>0) = ax(bx>0)./bx(bx>0); | ||||||||||||||||||||||||||||||||||
| dij.abx = {dij.abx}; | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+528
to
+532
|
||||||||||||||||||||||||||||||||||
| dij.abx = zeros(size(dij.ax{1})); | |
| ax = dij.ax{1}; | |
| bx = dij.bx{1}; | |
| dij.abx(bx>0) = ax(bx>0)./bx(bx>0); | |
| dij.abx = {dij.abx}; | |
| % Compute alpha/beta (abx) for each CT scenario, matching dij.ax/dij.bx | |
| numCtScen = numel(dij.ax); | |
| dij.abx = cell(numCtScen,1); | |
| for ctScenIdx = 1:numCtScen | |
| ax = dij.ax{ctScenIdx}; | |
| bx = dij.bx{ctScenIdx}; | |
| abx = zeros(size(ax)); | |
| mask = bx > 0; | |
| abx(mask) = ax(mask) ./ bx(mask); | |
| dij.abx{ctScenIdx} = abx; | |
| end |
Copilot
AI
Feb 2, 2026
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.
In the CellType branch, topasCube_values is reshaped to a vector, but then indexed as topasCube_values(mask,d). This will error because the reshaped array is 1-D. Use 1-D indexing (topasCube_values(mask)) and keep the assignment to dij...(...)(mask,d) for the beam column.
Copilot
AI
Feb 2, 2026
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.
In the beta-tally CellType branch, talliesFlags{2} is used to derive the CellType index, but talliesFlags is not defined in this branch (it’s only created in the alpha branch). This can fail depending on tally iteration order. Define talliesFlags = strsplit(topasCubesTallies{j},'_') locally before accessing talliesFlags{2}.
| if contains(topasCubesTallies{j}, 'CellType') | |
| if contains(topasCubesTallies{j}, 'CellType') | |
| talliesFlags = strsplit(topasCubesTallies{j},'_'); |
Copilot
AI
Feb 2, 2026
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.
The new use of str2num(talliesFlags{2}) on topasCubesTallies introduces a code‑injection risk, because talliesFlags is derived from TOPAS tally names that ultimately come from file names in an external simulation folder and may be attacker‑controlled (e.g. when using readExternal on untrusted output). Since str2num evaluates its input via eval, a crafted tally/file name like alpha_CellType=1;system('malicious_command');1 can cause arbitrary MATLAB commands to execute when this code parses the cell‑type index. To fix this, avoid str2num entirely here (e.g. use str2double or explicit numeric parsing on a constrained pattern) and ensure that only strictly numeric indices are accepted from tally names.
Copilot
AI
Feb 2, 2026
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.
In this CellType beta branch, topasCube_values is reshaped to a vector but then indexed as topasCube_values(mask,d), which will error for 1-D data. Additionally, the assignment targets mBetaDose_..., but prepareDij() only allocates mSqrtBetaDose_... and other paths store sqrt(beta) in that field. Use 1-D indexing and align with the existing mSqrtBetaDose_... + sqrt(...) convention.
Copilot
AI
Feb 2, 2026
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.
Typo: inserText is undefined (should be insertText). This will throw at runtime when writing the carbon/helium multi-CellType scorer section.
| fprintf(fID, ['d:Sc/CellLineGeneric_abR2' insertText '/Alphax = Sc/AlphaX' inserText ' /Gy\n']); | |
| fprintf(fID, ['d:Sc/CellLineGeneric_abR2' insertText '/Alphax = Sc/AlphaX' insertText ' /Gy\n']); |
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.
The condition checks
isfield(obj.bioParameters,'tissueAlphaX'), but the values are then read fromobj.bioModel.tissueAlphaX/BetaX(andbioModelis a class, not a struct). As written, this branch will never run, so tabulated-model tissue arrays won’t be used. Consider checkingisprop(obj.bioModel,'tissueAlphaX')(orisa(obj.bioModel,'matRad_LQRBETabulatedModel')) and then copyingobj.bioModel.tissueAlphaX/tissueBetaXintoobj.bioParameters.