|
72 | 72 | end |
73 | 73 | end |
74 | 74 |
|
75 | | - methods (Access = protected) |
76 | | - function dij = initDoseCalc(this,ct,cst,stf) |
77 | | - |
78 | | - matRad_cfg = MatRad_Config.instance(); |
79 | | - |
80 | | - if this.calcLET == true |
81 | | - matRad_cfg.dispWarning('Engine does not support LET calculation! Disabling!'); |
82 | | - this.calcLET = false; |
83 | | - end |
84 | | - |
85 | | - if this.calcBioDose == true |
86 | | - matRad_cfg.dispWarning('Engine does not support BioDose calculation! Disabling!'); |
87 | | - this.calcBioDose = false; |
88 | | - end |
89 | | - |
90 | | - dij = this.initDoseCalc@DoseEngines.matRad_ParticlePencilBeamEngineAbstract(ct,cst,stf); |
91 | | - end |
92 | | - |
93 | | - function chooseLateralModel(this) |
94 | | - %Now check if we need tho chose the lateral model because it |
95 | | - %was set to auto |
96 | | - matRad_cfg = MatRad_Config.instance(); |
97 | | - if strcmp(this.lateralModel,'auto') |
98 | | - this.lateralModel = 'single'; |
99 | | - elseif ~strcmp(this.lateralModel,'single') |
100 | | - matRad_cfg.dispWarning('Engine only supports analytically computed singleGaussian lateral Model!'); |
101 | | - this.lateralModel = 'single'; |
102 | | - end |
103 | | - matRad_cfg.dispInfo('Using an analytically computed %s Gaussian pencil-beam kernel model!\n'); |
104 | | - end |
105 | | - |
106 | | - function [currBixel] = getBixelIndicesOnRay(this,currBixel,currRay) |
107 | | - |
108 | | - % create offset vector to account for additional offsets modelled in the base data and a potential |
109 | | - % range shifter. In the following, we only perform dose calculation for voxels having a radiological depth |
110 | | - % that is within the limits of the base data set (-> machine.data(i).dephts). By this means, we only allow |
111 | | - % interpolations in this.calcParticleDoseBixel() and avoid extrapolations. |
112 | | - %urrBixel.offsetRadDepth = currBixel.baseData.offset + currBixel.radDepthOffset; |
113 | | - tmpOffset = currBixel.baseData.offset - currBixel.radDepthOffset; |
114 | | - |
115 | | - maxDepth = 1.15 * currBixel.baseData.range; |
116 | | - |
117 | | - % find depth depended lateral cut off |
118 | | - if this.dosimetricLateralCutOff == 1 |
119 | | - currIx = currRay.radDepths <= maxDepth + tmpOffset; |
120 | | - elseif this.dosimetricLateralCutOff < 1 && this.dosimetricLateralCutOff > 0 |
121 | | - currIx = currRay.radDepths <= maxDepth + tmpOffset; |
122 | | - sigmaSq = this.calcSigmaLatMCS(currRay.radDepths(currIx) - tmpOffset, currBixel.baseData.energy).^2 + currBixel.sigmaIniSq; |
123 | | - currIx(currIx) = currRay.radialDist_sq(currIx) < currBixel.baseData.LatCutOff.numSig.^2*sigmaSq; |
124 | | - else |
125 | | - matRad_cfg = MatRad_Config.instance(); |
126 | | - matRad_cfg.dispError('Cutoff must be a value between 0 and 1!') |
127 | | - end |
128 | | - |
129 | | - currBixel.subRayIx = currIx; |
130 | | - currBixel.ix = currRay.ix(currIx); |
131 | | - end |
132 | | - |
133 | | - function X = interpolateKernelsInDepth(this,bixel) |
134 | | - baseData = bixel.baseData; |
135 | | - |
136 | | - % calculate particle dose for bixel k on ray j of beam i |
137 | | - % convert from MeV cm^2/g per primary to Gy mm^2 per 1e6 primaries |
138 | | - conversionFactor = 1.6021766208e-02; |
139 | | - |
140 | | - radDepthOffset = bixel.radDepthOffset; |
141 | | - |
142 | | - if isfield(baseData,'energySpectrum') |
143 | | - energyMean = baseData.energySpectrum.mean; |
144 | | - energySpread = baseData.energySpectrum.sigma/100 * baseData.energySpectrum.mean; |
145 | | - else |
146 | | - energyMean = baseData.energy; |
147 | | - energySpread = baseData.energy * this.sigmaEnergy; |
148 | | - end |
149 | | - |
150 | | - if isfield(baseData,'offset') && ~isfield(baseData,'energySpectrum') |
151 | | - radDepthOffset = radDepthOffset - baseData.offset; |
152 | | - end |
153 | | - |
154 | | - X.Z = conversionFactor * this.calcAnalyticalBragg(energyMean, bixel.radDepths + radDepthOffset, energySpread); |
155 | | - X.sigma = this.calcSigmaLatMCS(bixel.radDepths + radDepthOffset, baseData.energy); |
156 | | - end |
157 | | - |
158 | | - function bixel = calcParticleBixel(this,bixel) |
159 | | - |
160 | | - kernel = this.interpolateKernelsInDepth(bixel); |
161 | | - |
162 | | - %compute lateral sigma |
163 | | - sigmaSq = kernel.sigma.^2 + bixel.sigmaIniSq; |
164 | | - |
165 | | - % calculate dose |
166 | | - bixel.physicalDose = bixel.baseData.LatCutOff.CompFac * exp( -bixel.radialDist_sq ./ (2*sigmaSq)) .* kernel.Z ./(2*pi*sigmaSq); |
167 | | - |
168 | | - % check if we have valid dose values |
169 | | - if any(isnan(bixel.physicalDose)) || any(bixel.physicalDose<0) |
170 | | - matRad_cfg = MatRad_Config.instance(); |
171 | | - matRad_cfg.dispError('Error in particle dose calculation.'); |
172 | | - end |
173 | | - end |
174 | | - |
175 | | - function doseVector = calcAnalyticalBragg(this, primaryEnergy, depthZ, energySpread) |
| 75 | + methods (Access = public) |
| 76 | + function [doseVector,hatD] = calcAnalyticalBragg(this, primaryEnergy, depthZ, energySpread) |
176 | 77 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
177 | 78 | % call |
178 | 79 | % this.calcAnalyticalBragg(PrimaryEnergy, depthz, WidthMod) |
@@ -319,6 +220,107 @@ function chooseLateralModel(this) |
319 | 220 |
|
320 | 221 | sigmaMCS(depthZ==0) = 0; |
321 | 222 | end |
| 223 | + end |
| 224 | + |
| 225 | + methods (Access = protected) |
| 226 | + function dij = initDoseCalc(this,ct,cst,stf) |
| 227 | + |
| 228 | + matRad_cfg = MatRad_Config.instance(); |
| 229 | + |
| 230 | + if this.calcLET == true |
| 231 | + matRad_cfg.dispWarning('Engine does not support LET calculation! Disabling!'); |
| 232 | + this.calcLET = false; |
| 233 | + end |
| 234 | + |
| 235 | + if this.calcBioDose == true |
| 236 | + matRad_cfg.dispWarning('Engine does not support BioDose calculation! Disabling!'); |
| 237 | + this.calcBioDose = false; |
| 238 | + end |
| 239 | + |
| 240 | + dij = this.initDoseCalc@DoseEngines.matRad_ParticlePencilBeamEngineAbstract(ct,cst,stf); |
| 241 | + end |
| 242 | + |
| 243 | + function chooseLateralModel(this) |
| 244 | + %Now check if we need tho chose the lateral model because it |
| 245 | + %was set to auto |
| 246 | + matRad_cfg = MatRad_Config.instance(); |
| 247 | + if strcmp(this.lateralModel,'auto') |
| 248 | + this.lateralModel = 'single'; |
| 249 | + elseif ~strcmp(this.lateralModel,'single') |
| 250 | + matRad_cfg.dispWarning('Engine only supports analytically computed singleGaussian lateral Model!'); |
| 251 | + this.lateralModel = 'single'; |
| 252 | + end |
| 253 | + matRad_cfg.dispInfo('Using an analytically computed %s Gaussian pencil-beam kernel model!\n'); |
| 254 | + end |
| 255 | + |
| 256 | + function [currBixel] = getBixelIndicesOnRay(this,currBixel,currRay) |
| 257 | + |
| 258 | + % create offset vector to account for additional offsets modelled in the base data and a potential |
| 259 | + % range shifter. In the following, we only perform dose calculation for voxels having a radiological depth |
| 260 | + % that is within the limits of the base data set (-> machine.data(i).dephts). By this means, we only allow |
| 261 | + % interpolations in this.calcParticleDoseBixel() and avoid extrapolations. |
| 262 | + %urrBixel.offsetRadDepth = currBixel.baseData.offset + currBixel.radDepthOffset; |
| 263 | + tmpOffset = currBixel.baseData.offset - currBixel.radDepthOffset; |
| 264 | + |
| 265 | + maxDepth = 1.15 * currBixel.baseData.range; |
| 266 | + |
| 267 | + % find depth depended lateral cut off |
| 268 | + if this.dosimetricLateralCutOff == 1 |
| 269 | + currIx = currRay.radDepths <= maxDepth + tmpOffset; |
| 270 | + elseif this.dosimetricLateralCutOff < 1 && this.dosimetricLateralCutOff > 0 |
| 271 | + currIx = currRay.radDepths <= maxDepth + tmpOffset; |
| 272 | + sigmaSq = this.calcSigmaLatMCS(currRay.radDepths(currIx) - tmpOffset, currBixel.baseData.energy).^2 + currBixel.sigmaIniSq; |
| 273 | + currIx(currIx) = currRay.radialDist_sq(currIx) < currBixel.baseData.LatCutOff.numSig.^2*sigmaSq; |
| 274 | + else |
| 275 | + matRad_cfg = MatRad_Config.instance(); |
| 276 | + matRad_cfg.dispError('Cutoff must be a value between 0 and 1!') |
| 277 | + end |
| 278 | + |
| 279 | + currBixel.subRayIx = currIx; |
| 280 | + currBixel.ix = currRay.ix(currIx); |
| 281 | + end |
| 282 | + |
| 283 | + function X = interpolateKernelsInDepth(this,bixel) |
| 284 | + baseData = bixel.baseData; |
| 285 | + |
| 286 | + % calculate particle dose for bixel k on ray j of beam i |
| 287 | + % convert from MeV cm^2/g per primary to Gy mm^2 per 1e6 primaries |
| 288 | + conversionFactor = 1.6021766208e-02; |
| 289 | + |
| 290 | + radDepthOffset = bixel.radDepthOffset; |
| 291 | + |
| 292 | + if isfield(baseData,'energySpectrum') |
| 293 | + energyMean = baseData.energySpectrum.mean; |
| 294 | + energySpread = baseData.energySpectrum.sigma/100 * baseData.energySpectrum.mean; |
| 295 | + else |
| 296 | + energyMean = baseData.energy; |
| 297 | + energySpread = baseData.energy * this.sigmaEnergy; |
| 298 | + end |
| 299 | + |
| 300 | + if isfield(baseData,'offset') && ~isfield(baseData,'energySpectrum') |
| 301 | + radDepthOffset = radDepthOffset - baseData.offset; |
| 302 | + end |
| 303 | + |
| 304 | + X.Z = conversionFactor * this.calcAnalyticalBragg(energyMean, bixel.radDepths + radDepthOffset, energySpread); |
| 305 | + X.sigma = this.calcSigmaLatMCS(bixel.radDepths + radDepthOffset, baseData.energy); |
| 306 | + end |
| 307 | + |
| 308 | + function bixel = calcParticleBixel(this,bixel) |
| 309 | + |
| 310 | + kernel = this.interpolateKernelsInDepth(bixel); |
| 311 | + |
| 312 | + %compute lateral sigma |
| 313 | + sigmaSq = kernel.sigma.^2 + bixel.sigmaIniSq; |
| 314 | + |
| 315 | + % calculate dose |
| 316 | + bixel.physicalDose = bixel.baseData.LatCutOff.CompFac * exp( -bixel.radialDist_sq ./ (2*sigmaSq)) .* kernel.Z ./(2*pi*sigmaSq); |
| 317 | + |
| 318 | + % check if we have valid dose values |
| 319 | + if any(isnan(bixel.physicalDose)) || any(bixel.physicalDose<0) |
| 320 | + matRad_cfg = MatRad_Config.instance(); |
| 321 | + matRad_cfg.dispError('Error in particle dose calculation.'); |
| 322 | + end |
| 323 | + end |
322 | 324 |
|
323 | 325 | function calcLateralParticleCutOff(this,cutOffLevel,~) |
324 | 326 | calcRange = false; |
|
0 commit comments