0001 function dij = matRad_calcPhotonDose(ct,stf,pln,cst,calcDoseDirect)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 matRad_cfg = MatRad_Config.instance();
0037
0038
0039 matRad_calcDoseInit;
0040
0041 [env, ~] = matRad_getEnvironment();
0042
0043 switch env
0044 case 'MATLAB'
0045 rng('default');
0046 case 'OCTAVE'
0047 rand('seed',0)
0048 end
0049
0050
0051 if sum(strcmp(pln.propOpt.bioOptimization,{'effect','RBExD'}))>0
0052 warndlg('Effect based and RBE optimization not available for photons - physical optimization is carried out instead.');
0053 pln.bioOptimization = 'none';
0054 end
0055
0056
0057 figureWait = waitbar(0,'calculate dose influence matrix for photons...');
0058
0059 set(figureWait,'pointer','watch');
0060
0061
0062 lateralCutoff = matRad_cfg.propDoseCalc.defaultGeometricCutOff;
0063
0064
0065
0066 if ~isfield(pln,'propDoseCalc') || ~isfield(pln.propDoseCalc,'useCustomPrimaryPhotonFluence')
0067 useCustomPrimFluenceBool = matRad_cfg.propDoseCalc.defaultUseCustomPrimaryPhotonFluence;
0068 else
0069 useCustomPrimFluenceBool = pln.propDoseCalc.useCustomPrimaryPhotonFluence;
0070 end
0071
0072
0073
0074 isFieldBasedDoseCalc = strcmp(num2str(pln.propStf.bixelWidth),'field');
0075
0076
0077
0078 if isFieldBasedDoseCalc
0079
0080 intConvResolution = pln.propStf.collimation.convResolution;
0081 fieldWidth = pln.propStf.collimation.fieldWidth;
0082 else
0083 intConvResolution = .5;
0084 fieldWidth = pln.propStf.bixelWidth;
0085 end
0086
0087
0088 fieldLimit = ceil(fieldWidth/(2*intConvResolution));
0089 [F_X,F_Z] = meshgrid(-fieldLimit*intConvResolution: ...
0090 intConvResolution: ...
0091 (fieldLimit-1)*intConvResolution);
0092
0093
0094 sigmaGauss = 2.123;
0095
0096 gaussLimit = ceil(5*sigmaGauss/intConvResolution);
0097 [gaussFilterX,gaussFilterZ] = meshgrid(-gaussLimit*intConvResolution: ...
0098 intConvResolution: ...
0099 (gaussLimit-1)*intConvResolution);
0100 gaussFilter = 1/(2*pi*sigmaGauss^2/intConvResolution^2) * exp(-(gaussFilterX.^2+gaussFilterZ.^2)/(2*sigmaGauss^2) );
0101 gaussConvSize = 2*(fieldLimit + gaussLimit);
0102
0103 if ~isFieldBasedDoseCalc
0104
0105 F = ones(floor(fieldWidth/intConvResolution));
0106
0107 if ~useCustomPrimFluenceBool
0108
0109 F = real(ifft2(fft2(F,gaussConvSize,gaussConvSize).*fft2(gaussFilter,gaussConvSize,gaussConvSize)));
0110 end
0111 end
0112
0113
0114 kernelLimit = ceil(lateralCutoff/intConvResolution);
0115 [kernelX, kernelZ] = meshgrid(-kernelLimit*intConvResolution: ...
0116 intConvResolution: ...
0117 (kernelLimit-1)*intConvResolution);
0118
0119
0120 kernelConvLimit = fieldLimit + gaussLimit + kernelLimit;
0121 [convMx_X, convMx_Z] = meshgrid(-kernelConvLimit*intConvResolution: ...
0122 intConvResolution: ...
0123 (kernelConvLimit-1)*intConvResolution);
0124
0125 kernelConvSize = 2*kernelConvLimit;
0126
0127
0128
0129 effectiveLateralCutoff = lateralCutoff + fieldWidth/2;
0130
0131 counter = 0;
0132 matRad_cfg.dispInfo('matRad: Photon dose calculation...\n');
0133
0134
0135 for i = 1:dij.numOfBeams
0136
0137 matRad_calcDoseInitBeam;
0138
0139
0140 [~,center] = min(sum(reshape([stf(i).ray.rayPos_bev],3,[]).^2));
0141
0142
0143 [~,currSSDIx] = min(abs([machine.data.kernel.SSD]-stf(i).ray(center).SSD));
0144
0145 matRad_cfg.dispInfo('\tSSD = %g mm ...\n',machine.data.kernel(currSSDIx).SSD);
0146
0147 kernelPos = machine.data.kernelPos;
0148 kernel1 = machine.data.kernel(currSSDIx).kernel1;
0149 kernel2 = machine.data.kernel(currSSDIx).kernel2;
0150 kernel3 = machine.data.kernel(currSSDIx).kernel3;
0151
0152
0153 kernel1Mx = interp1(kernelPos,kernel1,sqrt(kernelX.^2+kernelZ.^2),'linear',0);
0154 kernel2Mx = interp1(kernelPos,kernel2,sqrt(kernelX.^2+kernelZ.^2),'linear',0);
0155 kernel3Mx = interp1(kernelPos,kernel3,sqrt(kernelX.^2+kernelZ.^2),'linear',0);
0156
0157
0158 if ~useCustomPrimFluenceBool && ~isFieldBasedDoseCalc
0159
0160
0161 matRad_cfg.dispInfo('\tUniform primary photon fluence -> pre-compute kernel convolution...\n');
0162
0163
0164 convMx1 = real(ifft2(fft2(F,kernelConvSize,kernelConvSize).* fft2(kernel1Mx,kernelConvSize,kernelConvSize)));
0165 convMx2 = real(ifft2(fft2(F,kernelConvSize,kernelConvSize).* fft2(kernel2Mx,kernelConvSize,kernelConvSize)));
0166 convMx3 = real(ifft2(fft2(F,kernelConvSize,kernelConvSize).* fft2(kernel3Mx,kernelConvSize,kernelConvSize)));
0167
0168
0169 if strcmp(env,'MATLAB')
0170 Interp_kernel1 = griddedInterpolant(convMx_X',convMx_Z',convMx1','linear','none');
0171 Interp_kernel2 = griddedInterpolant(convMx_X',convMx_Z',convMx2','linear','none');
0172 Interp_kernel3 = griddedInterpolant(convMx_X',convMx_Z',convMx3','linear','none');
0173 else
0174 Interp_kernel1 = @(x,y)interp2(convMx_X(1,:),convMx_Z(:,1),convMx1,x,y,'linear',NaN);
0175 Interp_kernel2 = @(x,y)interp2(convMx_X(1,:),convMx_Z(:,1),convMx2,x,y,'linear',NaN);
0176 Interp_kernel3 = @(x,y)interp2(convMx_X(1,:),convMx_Z(:,1),convMx3,x,y,'linear',NaN);
0177 end
0178 end
0179
0180 for j = 1:stf(i).numOfRays
0181
0182 counter = counter + 1;
0183 bixelsPerBeam = bixelsPerBeam + 1;
0184
0185
0186 if useCustomPrimFluenceBool || isFieldBasedDoseCalc
0187
0188
0189 if isFieldBasedDoseCalc
0190 F = stf(i).ray(j).shape;
0191 end
0192
0193
0194 primaryFluence = machine.data.primaryFluence;
0195 r = sqrt( (F_X-stf(i).ray(j).rayPos(1)).^2 + (F_Z-stf(i).ray(j).rayPos(3)).^2 );
0196 Psi = interp1(primaryFluence(:,1)',primaryFluence(:,2)',r,'linear',0);
0197
0198
0199 Fx = F .* Psi;
0200
0201
0202 Fx = real( ifft2(fft2(Fx,gaussConvSize,gaussConvSize).* fft2(gaussFilter,gaussConvSize,gaussConvSize)) );
0203
0204
0205 convMx1 = real( ifft2(fft2(Fx,kernelConvSize,kernelConvSize).* fft2(kernel1Mx,kernelConvSize,kernelConvSize)) );
0206 convMx2 = real( ifft2(fft2(Fx,kernelConvSize,kernelConvSize).* fft2(kernel2Mx,kernelConvSize,kernelConvSize)) );
0207 convMx3 = real( ifft2(fft2(Fx,kernelConvSize,kernelConvSize).* fft2(kernel3Mx,kernelConvSize,kernelConvSize)) );
0208
0209
0210 if strcmp(env,'MATLAB')
0211 Interp_kernel1 = griddedInterpolant(convMx_X',convMx_Z',convMx1','linear','none');
0212 Interp_kernel2 = griddedInterpolant(convMx_X',convMx_Z',convMx2','linear','none');
0213 Interp_kernel3 = griddedInterpolant(convMx_X',convMx_Z',convMx3','linear','none');
0214 else
0215 Interp_kernel1 = @(x,y)interp2(convMx_X(1,:),convMx_Z(:,1),convMx1,x,y,'linear',NaN);
0216 Interp_kernel2 = @(x,y)interp2(convMx_X(1,:),convMx_Z(:,1),convMx2,x,y,'linear',NaN);
0217 Interp_kernel3 = @(x,y)interp2(convMx_X(1,:),convMx_Z(:,1),convMx3,x,y,'linear',NaN);
0218 end
0219
0220 end
0221
0222
0223 if mod(bixelsPerBeam,max(1,round(stf(i).totalNumOfBixels/200))) == 0
0224 matRad_progress(bixelsPerBeam/max(1,round(stf(i).totalNumOfBixels/200)),...
0225 floor(stf(i).totalNumOfBixels/max(1,round(stf(i).totalNumOfBixels/200))));
0226 end
0227
0228 if mod(counter,round(dij.totalNumOfBixels/100)) == 0 && ishandle(figureWait)
0229 waitbar(counter/dij.totalNumOfBixels);
0230 end
0231
0232
0233 if ~calcDoseDirect
0234 dij.beamNum(counter) = i;
0235 dij.rayNum(counter) = j;
0236 dij.bixelNum(counter) = 1;
0237 else
0238 k = 1;
0239 end
0240
0241
0242 [ix,rad_distancesSq,isoLatDistsX,isoLatDistsZ] = matRad_calcGeoDists(rot_coordsVdoseGrid, ...
0243 stf(i).sourcePoint_bev, ...
0244 stf(i).ray(j).targetPoint_bev, ...
0245 machine.meta.SAD, ...
0246 find(~isnan(radDepthVdoseGrid{1})), ...
0247 effectiveLateralCutoff);
0248
0249
0250
0251 if isempty(ix)
0252 continue;
0253 end
0254
0255
0256
0257 bixelDose = matRad_calcPhotonDoseBixel(machine.meta.SAD,machine.data.m,...
0258 machine.data.betas, ...
0259 Interp_kernel1,...
0260 Interp_kernel2,...
0261 Interp_kernel3,...
0262 radDepthVdoseGrid{1}(ix),...
0263 geoDistVdoseGrid{1}(ix),...
0264 isoLatDistsX,...
0265 isoLatDistsZ);
0266
0267
0268 if ~isFieldBasedDoseCalc
0269 r0 = 20 + stf(i).bixelWidth;
0270 Type = 'radius';
0271 [ix,bixelDose] = matRad_DijSampling(ix,bixelDose,radDepthVdoseGrid{1}(ix),rad_distancesSq,Type,r0);
0272 end
0273
0274
0275 doseTmpContainer{mod(counter-1,numOfBixelsContainer)+1,1} = sparse(VdoseGrid(ix),1,bixelDose,dij.doseGrid.numOfVoxels,1);
0276
0277 matRad_calcDoseFillDij;
0278
0279 end
0280 end
0281
0282
0283 if ishandle(figureWait)
0284 delete(figureWait);
0285 end
0286