Browse Source

Added multiple different objective function optimizations

MEDPHYSICS\pferjancic 4 years ago
parent
commit
6cb4184964

+ 18 - 18
WiscPlanPhotonkV125/matlab_frontend/NLP_getFullDose.m

@@ -1,19 +1,19 @@
-
-
-function NLP_getFullDose(NLP_path, NLP_file)
-% this function calculates full dose matrix for Robust optimized plans
-
-% get the NLP result
-load([NLP_path '\' NLP_file]);
-
-path2 = NLP_path(1:end-14);
-D = read_ryan_beamlets([path2 '\batch_dose.bin'],'ryan sum', NLP_result.weights);
-% D = read_ryan_beamlets([path2 '\beamlet_batch_files\beamletbatch0.bin'],'ryan sum', NLP_result.weights);
-
-% orthoslice(D-NLP_result.dose, [0,90])
-
-NLP_result.dose = double(D);
-% NLP_result.weights = double(optResults.weights{end});
-save([NLP_path, NLP_file], 'NLP_result');
-
+
+
+function NLP_getFullDose(NLP_path, NLP_file)
+% this function calculates full dose matrix for Robust optimized plans
+
+% get the NLP result
+load([NLP_path '\' NLP_file]);
+
+path2 = NLP_path(1:end-14);
+D = read_ryan_beamlets([path2 '\batch_dose.bin'],'ryan sum', NLP_result.weights);
+% D = read_ryan_beamlets([path2 '\beamlet_batch_files\beamletbatch0.bin'],'ryan sum', NLP_result.weights);
+
+% orthoslice(D-NLP_result.dose, [0,90])
+
+NLP_result.dose = double(D);
+% NLP_result.weights = double(optResults.weights{end});
+save([NLP_path, NLP_file], 'NLP_result');
+
 end

+ 532 - 512
WiscPlanPhotonkV125/matlab_frontend/NLP_optimizer_v3.m

@@ -1,512 +1,532 @@
-
-
-% paths.patient_dir
-% paths.Goal_dir (previously called DP_dir)
-% paths.patient
-% paths.goalsName
-
-% colorwash(Geometry.data, D_full, [500, 1500], [0,70])
-% orthoslice(D_full, [0,70])
-
-function [D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(varargin)
-% This function performs the beamlet optimization
-% [D_full, w_fin, Geometry, optGoal] = NLP_beamlet_optimizer;
-% 
-% Inputs:
-%       () OR
-%       (Pat_path, path2goal) OR
-%       (Pat_path, path2goal, beamlet_weights)
-%   Pat_path, path2goal = strings to patient folder and optimal goals
-%   beamlet_weights = initial beamlet weights
-%   
-% Outputs:
-%       full dose image dose: [D_full, w_fin, Geometry, optGoal]
-% 
-% Made by Peter Ferjancic 1. May 2018
-% Last updated: 1. April 2019
-
-if nargin<2
-    load('WiscPlan_preferences.mat')
-    [Pat_path] = uigetdir([WiscPlan_preferences.patientDataPath ], 'Select Patient folder');
-    [Goal_file,Goal_path,indx] = uigetfile([Pat_path '\matlab_files\*.mat'], 'Select OptGoal file');
-    
-    path2geometry = [Pat_path, '\matlab_files\Geometry.mat'];
-    path2goal = [Goal_path, Goal_file];
-else
-    Pat_path = varargin{1};
-    path2geometry = [Pat_path, '\matlab_files\Geometry.mat'];
-    path2goal = varargin{2};
-    [Goal_path,Goal_file,ext] = fileparts(path2goal);
-end
-
-dialogue_box = 'yes'
-switch dialogue_box
-    case 'yes'
-        str = inputdlg({'N of iterations for initial calc', 'N of iterations for full calc', ...
-            'Use pre-existing NLP_result to initiate? (y/n)'}, 'input', [1,35], {'100000', '500000', 'n'});
-        N_fcallback1 = str2double(str{1}); % 100000  is a good guesstimate
-        N_fcallback2 = str2double(str{2}); % 500000 is a good guesstimate
-        pre_beamWeights = str{3};
-    case 'no'
-        disp('dialogue box skipped')
-        N_fcallback1 = 100000;
-        N_fcallback2 = 1e6; % 500000;
-        pre_beamWeights = 'n';
-end
-
-
-switch pre_beamWeights
-    case 'y'
-        [NLP_file,NLP_path,indx] = uigetfile([Pat_path '\matlab_files\*.mat'], 'Select NLP_result file');
-        load([NLP_path, NLP_file])
-        w_beamlets = NLP_result.weights;
-        
-        load([Pat_path, '\all_beams.mat'])
-        if numel(all_beams) ~= numel(w_beamlets)
-            error('Provided weight number does not match beamlet number!')
-        end
-    case 'n'
-        disp('Initial beam weights will be calculated.')
-end
-
-%% PROGRAM STARTS HERE
-% - no tocar lo que hay debajo -
-fprintf('starting NLP optimization process... \n')
-
-% % -- LOAD GEOMETRY, GOALS, BEAMLETS --
-load(path2geometry)
-load(path2goal)
-[beamlets, numBeamlet] = get_beamlets(Geometry, Pat_path, OptGoals);
-% [beamlets, beamlets_joined, numBeamlet, numBeam, beam_i_list] = get_beam_lets(Geometry, Pat_path);
-
-
-%% -- OPTIMIZATION TARGETS --
-% -- make the optimization optGoal structure --
-for i_goal = 1:size(OptGoals.goals,1)
-        
-    if isfield(OptGoals.data{i_goal}, 'SupVox_num')
-        SupVox_num = OptGoals.data{i_goal}.SupVox_num;
-    else
-        answer = inputdlg(['# of supervoxels for "' OptGoals.data{i_goal}.name '" with ' num2str(numel(OptGoals.data{i_goal}.ROI_idx)) ' vox: ("0" to skip)'])
-        SupVox_num = str2double(answer{1})
-    end
-    optGoal{i_goal} = OptGoals.data{i_goal};
-    optGoal{i_goal}.sss_scene_list = OptGoals.sss_scene_list;
-    optGoal{i_goal}.maxModulation = OptGoals.maxModulation;
-    optGoal{i_goal}.BeamSmoothMax = OptGoals.BeamSmoothMax;
-    
-    % modulation
-    switch SupVox_num
-        case 0
-        % if not supervoxel, just select provided ROI_idx
-        
-        optGoal{i_goal}.beamlets_pruned = sparse(beamlets(optGoal{i_goal}.ROI_idx, :));
-    
-        otherwise
-        % -- if supervoxel, merge given columns
-        % - make supervoxel map
-        mask = zeros(OptGoals.data{i_goal}.imgDim);
-        mask(OptGoals.data{i_goal}.ROI_idx) = 1;
-        % group superpixels
-        superMask = superpix_group(mask, SupVox_num, 'no'); 
-        
-        superVoxList = unique(superMask);
-        superVoxList = superVoxList(superVoxList>0);
-        
-        optGoal{i_goal}.ROI_idx_old = optGoal{i_goal}.ROI_idx; % copy old index data
-        optGoal{i_goal}.ROI_idx = zeros(numel(superVoxList), 1);
-        optGoal{i_goal}.opt_weight = optGoal{i_goal}.opt_weight * numel(optGoal{i_goal}.ROI_idx_old)/numel(optGoal{i_goal}.ROI_idx);
-        
-        if isfield(OptGoals.data{i_goal}, 'wgt_map')
-            tabula_wgtmap = zeros(size(superMask));
-            tabula_wgtmap(OptGoals.data{i_goal}.ROI_idx) = OptGoals.data{i_goal}.wgt_map;
-        end
-        
-        
-        
-        h_w1 = waitbar(0, 'merging superboxels');
-        for i_supVox = 1:numel(superVoxList)
-            waitbar(i_supVox/numel(superVoxList), h_w1)
-            supVox_idx = superVoxList(i_supVox);
-            idxList = find(superMask == supVox_idx);
-            optGoal{i_goal}.beamlets_pruned(i_supVox,:) = sparse(mean(beamlets(idxList, :),1));
-            
-            if isfield(OptGoals.data{i_goal}, 'wgt_map')
-                optGoal{i_goal}.vox_wgt(i_supVox) = sum(tabula_wgtmap(idxList));
-            end
-            
-            % -- make new indeces
-            optGoal{i_goal}.ROI_idx(i_supVox) = idxList(1);
-        end
-        close(h_w1)
-    end
-end
-
-% -- make them robust --
-RO_params=0;
-optGoal = make_robust_optGoal(optGoal, RO_params, beamlets);
-% save([Goal_path, Goal_file '_robust.mat'], 'optGoal')
-
-% -- get beamlet indeces --
-load([Pat_path, '\all_beams.mat'])
-Nbeamlets = all_beams{1}.Mxp;   % number of beamlets in a beam - usually 64 or 32
-weightTable = zeros(100,Nbeamlets);
-for ind_bmlt = 1:numel(all_beams)
-    bLet_idx.y(ind_bmlt) = floor(all_beams{1, ind_bmlt}.num/Nbeamlets)+1;
-    bLet_idx.x(ind_bmlt) = rem(all_beams{1, ind_bmlt}.num, Nbeamlets)+1;
-    weightTable(bLet_idx.y(ind_bmlt),bLet_idx.x(ind_bmlt)) = 1;
-end
-bLet_idx.idx = find(weightTable>0);
-bLet_idx.Nbeamlets = Nbeamlets;
-disp('.')
-
-% -- CALLBACK OPTIMIZATION FUNCTION --
-fun1 = @(x) get_penalty(x, optGoal_beam, bLet_idx);
-fun2 = @(x) get_penalty(x, optGoal,     bLet_idx);
-
-% -- OPTIMIZATION PARAMETERS --
-% define optimization parameters
-A = [];
-b = [];
-Aeq = [];
-beq = [];
-lb = zeros(1, numBeamlet);
-% lb_beam = zeros(1, numBeam);
-ub = [];
-nonlcon = [];
-
-% define opt limits, and make it fmincon progress
-options = optimoptions('fmincon');
-options.MaxFunctionEvaluations = N_fcallback1;
-options.Display = 'iter';
-options.PlotFcn = 'optimplotfval';
-% options.UseParallel = true;
-options.UseParallel = false;
-% options.OptimalityTolerance = 1e-9;
-
-%% -- INITIALIZE BEAMLET WEIGHTS --
-switch pre_beamWeights
-    case 'y'
-        % should have been assigned previously.
-        disp('Provided beamlet weights used for initial comparison')
-    case 'n'
-        % if initial beamlet weights are not provided, get quick estimate
-%         fprintf('\n running initial optimizer:')
-        % initialize beamlet weights, OR
-        w0 = ones(numBeamlet,1);
-%         w0 = mean(optGoal{1}.D_final(optGoal{1}.ROI_idx) ./ (optGoal{1}.beamlets_pruned*w0+0.1)) * w0; % old
-        w0 = mean(optGoal{1}.D_final(:)) ./ mean(optGoal{1}.beamlets_pruned*w0+0.05) * w0;
-        w_beamlets = double(w0);
-
-        % -- GET BEAM WEIGHTS --
-%         tic
-%         w_beam = fmincon(fun1,w0_beams,A,b,Aeq,beq,lb,ub,nonlcon,options);
-%         fprintf('  done!:')
-%         t=toc;
-%         disp(['Optimization time for beams = ',num2str(t)]);
-% 
-%         w_beamlets = ones(numBeamlet,1);
-%         numBeam=numel(unique(beam_i_list));
-%         for beam_i = 1:numBeam % assign weights to beamlets
-%             % beamlets from same beam get same initial weights
-%             w_beamlets(beam_i_list == beam_i) = w_beam(beam_i);
-%         end
-end
-
-%% FULL OPTIMIZATION
-
-% -- GET FULL BEAMLET WEIGHTS --
-options.MaxFunctionEvaluations = N_fcallback2;
-tic
-fprintf('\n running full optimizer:')
-w_fin = fmincon(fun2,w_beamlets,A,b,Aeq,beq,lb,ub,nonlcon,options);
-fprintf('  done!:')
-t=toc;
-disp(['Optimization time for beamlets = ',num2str(t)]);
-
-
-%% evaluate the results
-D_full = reshape(beamlets * w_fin, size(Geometry.data));
-
-%% save outputs
-NLP_result.dose = D_full;
-NLP_result.weights = w_fin;
-NLP_result.sss_scene_list = optGoal{1}.sss_scene_list;
-NLP_result.maxModulation = OptGoals.maxModulation;
-NLP_result.BeamSmoothMax = OptGoals.BeamSmoothMax;
-save([Pat_path, '\matlab_files\NLP_result_' Goal_file '.mat'], 'NLP_result');
-
-
-plot_DVH(Geometry, D_full)
-colorwash(Geometry.data, D_full, [500, 1500], [0, 90]);
-
-
-end
-
-%% support functions
-% ---- PENALTY FUNCTION ----
-function penalty = get_penalty(x, optGoal, bLet_idx)
-    % this function gets called by the optimizer. It checks the penalty for
-    % all the robust implementation and returns the worst result.
-    
-    NumScenarios = optGoal{1}.NbrRandScenarios * optGoal{1}.NbrSystSetUpScenarios * optGoal{1}.NbrRangeScenarios;
-    fobj = zeros(NumScenarios,1);  
-    sc_i = 1;
-    
-
-    
-    for nrs_i = 1:optGoal{1}.NbrRandScenarios 
-        for sss_i = 1 :optGoal{1}.NbrSystSetUpScenarios % syst. setup scenarios = sss
-            for rgs_i = 1:optGoal{1}.NbrRangeScenarios % range scenario = rs
-                fobj(sc_i)=eval_f(x, optGoal, nrs_i, sss_i, rgs_i, bLet_idx);
-                sc_i = sc_i + 1;
-            end
-        end
-    end
-    % take the worst case penalty of evaluated scenarios
-    penalty=max(fobj);
-    
-    % take the median worst case (stochastic robust)
-%     penalty=median(fobj);
-
-
-    
-end
-% ------ supp: penalty for single scenario ------
-function penalty = eval_f(x, optGoal, nrs_i, sss_i, rgs_i, bLet_idx)
-    penalty = 0;
-    % for each condition
-    for goal_i = 1:numel(optGoal)
-        switch optGoal{goal_i}.function
-            % min, max, min_sq, max_sq, LeastSquare, min_perc_Volume, max_perc_Volume
-            case 'min'
-                % penalize if achieved dose is lower than target dose
-                d_penalty = 1.0e0 * sum(max(0, ...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target) -...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)));
-            case 'max'
-                % penalize if achieved dose is higher than target dose
-                d_penalty = 1.0e0 * sum(max(0, ...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target)));
-            case 'min_sq'
-                % penalize if achieved dose is lower than target dose
-                temp1=min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
-                d_penalty = 1.0e0 * sum(temp1.*temp1);
-            case 'max_sq'
-                % penalize if achieved dose is higher than target dose
-                temp1=max(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
-                d_penalty = 1.0e0 * sum(temp1.*temp1);
-            case 'min_step'
-                % penalize if achieved dose is lower than target dose
-                temp1=-min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
-                d_penalty = 1.0e1 * (sum(temp1.*temp1) + 1.0e3* sum(temp1>0)/numel(temp1));
-            case 'max_step'
-                % penalize if achieved dose is higher than target dose
-                temp1=max(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
-                d_penalty = 1.0e1 * (sum(temp1.*temp1) + 1.0e3* sum(temp1>0)/numel(temp1));
-            case 'LeastSquare'
-                % penalize with sum of squares any deviation from target
-                % dose
-                temp1 = (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x) - ...
-                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target;
-                d_penalty = 1.0e0* sum(temp1.^2);
-            case 'min_perc_Volume'
-                % penalize by amount of volume under threshold
-                perc_vox = numel(find((optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target) -...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x) > 0)) ...
-                    / numel(optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target);
-                d_penalty = 3.0e4 * min(perc_vox-0.05, 0)
-                
-            case 'max_perc_Volume'
-                % penalize by amount of volume under threshold
-                perc_vox = numel(find((optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target) -...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x) < 0)) ...
-                    / numel(optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target);
-                d_penalty = 3.0e4 * min(perc_vox-0.05, 0)
-            case 'min_sq_voxwgt'
-                % penalize if achieved dose is lower than target dose
-                temp1=min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
-                d_penalty = 1.0e0 * sum(temp1.*temp1.* optGoal{goal_i}.vox_wgt');
-            case 'max_sq_voxwgt'
-                % penalize if achieved dose is lower than target dose
-                temp1=min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
-                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
-                d_penalty = 1.0e0 * sum(temp1.*temp1.* optGoal{goal_i}.vox_wgt'); 
-        end
-        penalty = penalty + d_penalty * optGoal{goal_i}.opt_weight;
-    end
-    
-    %% add modulation penalty
-    if true
-        if isfield(optGoal{goal_i}, 'maxModulation')
-            max_modulation = optGoal{goal_i}.maxModulation;
-        else
-            error('no Max modulation parameter enterd!')
-            max_modulation = 5;
-        end
-        
-        mod_pen_weight = 1.0e10;
-        % calc the penalty
-        mod_excess = max(0, x-max_modulation*mean(x));
-%         mod_excess = max(0, x-max_modulation*mean(x(x>1)));
-        mod_pen1 = mod_pen_weight*(sum(mod_excess) + numel(mod_excess)* any(mod_excess));
-        penalty = penalty + mod_pen1;
-    end
-    
-    %% add penlty for single off beamlets - version 2
-    if false
-        if isfield(optGoal{goal_i}, 'BeamSmoothMax')
-            BeamSmoothMax = optGoal{goal_i}.BeamSmoothMax;
-        else
-            error('no Max beam smooth parameter enterd!')
-            BeamSmoothMax = 1e6;
-        end
-        mod_pen_weight = BeamSmoothMax; %1.0e6
-        x_down = zeros(size(x));
-        x_down(2:end) = x(1:end-1);
-        x_down2 = zeros(size(x));
-        x_down2(3:end) = x(1:end-2);
-        x_up = zeros(size(x));
-        x_up(1:end-1) = x(2:end);
-        x_up2 = zeros(size(x));
-        x_up2(1:end-2) = x(3:end);
-        mod_pen2 = mod_pen_weight*sum((x_down+x_up-2*x).^2 + 0.5*(x_down2+x_up2-2*x).^2)/(mean(x)^(2)*numel(x));
-        penalty = penalty + mod_pen2;
-    end
-    %% add penlty for single off beamlets - version 3
-    if true
-        if isfield(optGoal{goal_i}, 'BeamSmoothMax')
-            BeamSmoothMax = optGoal{goal_i}.BeamSmoothMax;
-        else
-            error('no Max beam smooth parameter enterd!')
-            BeamSmoothMax = 1e6;
-        end
-        mod_pen_weight = BeamSmoothMax; %1.0e6
-        
-        % make 2D beamletWeight map
-        maxY = max(bLet_idx.y);
-        tabula = zeros(maxY, bLet_idx.Nbeamlets);
-        tabula(bLet_idx.idx) = x;
-        % for each index calculate laplace
-        myWeights = 1/12*[1,3,1; 1,-12,1; 1,3,1];
-        i=2:maxY-1;
-        j=2:bLet_idx.Nbeamlets-1;
-        tabula2(i,j) = ...
-             myWeights(1)*tabula(i-1,j-1) + myWeights(4)*tabula(i-1,j) + myWeights(7)*tabula(i-1,j+1)...
-            +myWeights(2)*tabula(i,j-1)  + myWeights(8)*tabula(i,j+1) ...
-            +myWeights(3)*tabula(i+1,j-1) + myWeights(6)*tabula(i+1,j) + myWeights(9)*tabula(i+1,j+1)...
-            +myWeights(5)*tabula(i,j);
-        tabula2(1,j) = ...
-             myWeights(2)*tabula(1,j-1) + myWeights(8)*tabula(1,j+1)...
-            +myWeights(3)*tabula(2,j-1) + myWeights(6)*tabula(2,j) + myWeights(9)*tabula(2,j+1)...
-            +myWeights(5)*tabula(1,j);
-        tabula2(maxY,j) =...
-             myWeights(1)*tabula(maxY-1,j-1) + myWeights(4)*tabula(maxY-1,j) + myWeights(7)*tabula(maxY-1,j+1)...
-            +myWeights(2)*tabula(maxY,j-1)  + myWeights(8)*tabula(maxY,j+1) ...
-            +myWeights(5)*tabula(maxY,j);
-        % make sum of squares
-        mod_pen2 = mod_pen_weight*sum((tabula2(:)).^2)/(mean(x.^2)*numel(x));
-        penalty = penalty + mod_pen2;
-    end
-end
-
-% ---- MAKE ROI ROBUST ----
-function optGoal = make_robust_optGoal(optGoal, RO_params, beamlets);
-    % take regular optimal goal and translate it into several robust cases
-    
-    % RO_params - should have the information below
-    % nrs - random scenarios
-    % sss - system setup scenarios
-    % rgs - random range scenarios
-    
-    % X - X>0 moves image right
-    % Y - Y>0 moves image down
-    % Z - in/out.
-    
-    shift_X = 2; % vox of shift
-    shift_Y = 2; % vox of shift
-    shift_Z = 1; % vox of shift
-    nrs_scene_list={[0,0,0]};
-
-    
-    % ----====#### CHANGE ROBUSTNESS HERE ####====----
-    if isfield(optGoal{1}, 'sss_scene_list')
-        sss_scene_list = optGoal{1}.sss_scene_list;
-    else
-        error('New OptGoals should no longer reach this code!')
-        sss_scene_list={[0,0,0], [-shift_Y,0,0], [shift_Y,0,0], [0,-shift_X,0], [0,shift_X,0], [0,0,-shift_Z], [0,0,shift_Z]};
-        optGoal{1}.sss_scene_list = sss_scene_list;
-    end
-%     sss_scene_list={[0,0,0]};
-
-    % ----====#### CHANGE ROBUSTNESS HERE ####====----
-%     [targetIn, meta] = nrrdread('C:\010-work\003_localGit\WiscPlan_v2\data\archive\CDP_data\CDP5_DP_target.nrrd');
-%     [targetIn, meta] = nrrdread('C:\010-work\003_localGit\WiscPlan_v2\data\PD_HD_dicomPhantom\Tomo_DP_target.nrrd');
-%     [targetIn, meta] = nrrdread('C:\010-work\003_localGit\WiscPlan_v2\data\archive\CDP_data\CDP5_DP_target.nrrd');
-    rgs_scene_list={[0,0,0]};
-    for i = 1:numel(optGoal)
-        optGoal{i}.NbrRandScenarios     =numel(nrs_scene_list);
-        optGoal{i}.NbrSystSetUpScenarios=numel(sss_scene_list);
-        optGoal{i}.NbrRangeScenarios    =numel(rgs_scene_list);
-    end
-    for goal_i = 1:numel(optGoal)
-        % get target
-        idx=optGoal{goal_i}.ROI_idx;
-        targetImg1=zeros(optGoal{goal_i}.imgDim);
-        targetImg1(idx)=1;
-        % get beamlets
-        for nrs_i = 1:optGoal{goal_i}.NbrRandScenarios          % num. of random scenarios
-            % modify target and beamlets
-            targetImg2=targetImg1;
-            % beamlets stay the same
-            for sss_i = 1 :optGoal{goal_i}.NbrSystSetUpScenarios   % syst. setup scenarios = sss
-                % modify target and beamlets
-                [targetImg3 idxValid]=get_RO_sss(targetImg2, sss_scene_list{sss_i});
-                % beamlets stay the same
-                for rgs_i = 1:optGoal{goal_i}.NbrRangeScenarios   % range scenario = rgs
-                    % modify target and beamlets
-                    targetImg4=targetImg3;
-                    % beamlets stay the same
-                    %% make new target and beamlets
-                    ROI_idx=[];
-                    ROI_idx=find(targetImg4>0);
-                    target = optGoal{goal_i}.D_final(idxValid);
-                    beamlets_pruned = beamlets(ROI_idx, :);
-                    % save to optGoal output
-                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.ROI_idx            = ROI_idx;
-                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned    = beamlets_pruned;
-                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target             = target;
-                end
-            end
-        end
-    end
-end
-%% ------ supp: RO case SSS ------
-function [targetImg3 ia]=get_RO_sss(targetImg2, sss_scene_shift);
-    % translate the target image 
-    
-    targetImg3 = imtranslate(targetImg2,sss_scene_shift);
-    
-    % now we need to figure out if any target voxels fell out during the
-    % shift
-    imgValid = imtranslate(targetImg3,-sss_scene_shift);
-    imgInvalid = (targetImg2-imgValid);
-    
-    idx_1 = find(targetImg2);
-    idx_2 = find(imgInvalid);
-    
-    [idxValid,ia] = setdiff(idx_1,idx_2);
-    
-    [C,ia, ib] = intersect(idx_1,idxValid);
-    
-end
-
-
-
-
+
+
+% paths.patient_dir
+% paths.Goal_dir (previously called DP_dir)
+% paths.patient
+% paths.goalsName
+
+% colorwash(Geometry.data, D_full, [500, 1500], [0,70])
+% orthoslice(D_full, [0,70])
+
+function [D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(varargin)
+% This function performs the beamlet optimization
+% [D_full, w_fin, Geometry, optGoal] = NLP_beamlet_optimizer;
+% 
+% Inputs:
+%       () OR
+%       (Pat_path, path2goal) OR
+%       (Pat_path, path2goal, beamlet_weights)
+%   Pat_path, path2goal = strings to patient folder and optimal goals
+%   beamlet_weights = initial beamlet weights
+%   
+% Outputs:
+%       full dose image dose: [D_full, w_fin, Geometry, optGoal]
+% 
+% Made by Peter Ferjancic 1. May 2018
+% Last updated: 1. April 2019
+
+if nargin<2
+    load('WiscPlan_preferences.mat')
+    [Pat_path] = uigetdir([WiscPlan_preferences.patientDataPath ], 'Select Patient folder');
+    [Goal_file,Goal_path,indx] = uigetfile([Pat_path '\matlab_files\*.mat'], 'Select OptGoal file');
+    
+    path2geometry = [Pat_path, '\matlab_files\Geometry.mat'];
+    path2goal = [Goal_path, Goal_file];
+else
+    Pat_path = varargin{1};
+    path2geometry = [Pat_path, '\matlab_files\Geometry.mat'];
+    path2goal = varargin{2};
+    [Goal_path,Goal_file,ext] = fileparts(path2goal);
+end
+
+dialogue_box = 'yes'
+switch dialogue_box
+    case 'yes'
+        str = inputdlg({'N of iterations for initial calc', 'N of iterations for full calc', ...
+            'Use pre-existing NLP_result to initiate? (y/n)'}, 'input', [1,35], {'100000', '500000', 'n'});
+        N_fcallback1 = str2double(str{1}); % 100000  is a good guesstimate
+        N_fcallback2 = str2double(str{2}); % 500000 is a good guesstimate
+        pre_beamWeights = str{3};
+    case 'no'
+        disp('dialogue box skipped')
+        N_fcallback1 = 100000;
+        N_fcallback2 = 1e6; % 500000;
+        pre_beamWeights = 'n';
+end
+
+
+switch pre_beamWeights
+    case 'y'
+        [NLP_file,NLP_path,indx] = uigetfile([Pat_path '\matlab_files\*.mat'], 'Select NLP_result file');
+        load([NLP_path, NLP_file])
+        w_beamlets = NLP_result.weights;
+        
+        load([Pat_path, '\all_beams.mat'])
+        if numel(all_beams) ~= numel(w_beamlets)
+            error('Provided weight number does not match beamlet number!')
+        end
+    case 'n'
+        disp('Initial beam weights will be calculated.')
+end
+
+%% PROGRAM STARTS HERE
+% - no tocar lo que hay debajo -
+fprintf('starting NLP optimization process... \n')
+
+% % -- LOAD GEOMETRY, GOALS, BEAMLETS --
+load(path2geometry)
+load(path2goal)
+[beamlets, numBeamlet] = get_beamlets(Geometry, Pat_path, OptGoals);
+% [beamlets, beamlets_joined, numBeamlet, numBeam, beam_i_list] = get_beam_lets(Geometry, Pat_path);
+
+
+%% -- OPTIMIZATION TARGETS --
+% -- make the optimization optGoal structure --
+for i_goal = 1:size(OptGoals.goals,1)
+        
+    if isfield(OptGoals.data{i_goal}, 'SupVox_num')
+        SupVox_num = OptGoals.data{i_goal}.SupVox_num;
+    else
+        answer = inputdlg(['# of supervoxels for "' OptGoals.data{i_goal}.name '" with ' num2str(numel(OptGoals.data{i_goal}.ROI_idx)) ' vox: ("0" to skip)'])
+        SupVox_num = str2double(answer{1})
+    end
+    optGoal{i_goal} = OptGoals.data{i_goal};
+    optGoal{i_goal}.sss_scene_list = OptGoals.sss_scene_list;
+    optGoal{i_goal}.maxModulation = OptGoals.maxModulation;
+    optGoal{i_goal}.BeamSmoothMax = OptGoals.BeamSmoothMax;
+    
+    optGoal{i_goal}.optFuncNum = OptGoals.optFuncNum;
+    
+    % modulation
+    switch SupVox_num
+        case 0
+        % if not supervoxel, just select provided ROI_idx
+        
+        optGoal{i_goal}.beamlets_pruned = sparse(beamlets(optGoal{i_goal}.ROI_idx, :));
+    
+        otherwise
+        % -- if supervoxel, merge given columns
+        % - make supervoxel map
+        mask = zeros(OptGoals.data{i_goal}.imgDim);
+        mask(OptGoals.data{i_goal}.ROI_idx) = 1;
+        % group superpixels
+        superMask = superpix_group(mask, SupVox_num, 'no'); 
+        
+        superVoxList = unique(superMask);
+        superVoxList = superVoxList(superVoxList>0);
+        
+        optGoal{i_goal}.ROI_idx_old = optGoal{i_goal}.ROI_idx; % copy old index data
+        optGoal{i_goal}.ROI_idx = zeros(numel(superVoxList), 1);
+        optGoal{i_goal}.opt_weight = optGoal{i_goal}.opt_weight * numel(optGoal{i_goal}.ROI_idx_old)/numel(optGoal{i_goal}.ROI_idx);
+        
+        if isfield(OptGoals.data{i_goal}, 'wgt_map')
+            tabula_wgtmap = zeros(size(superMask));
+            tabula_wgtmap(OptGoals.data{i_goal}.ROI_idx) = OptGoals.data{i_goal}.wgt_map;
+        end
+        
+        
+        
+        h_w1 = waitbar(0, 'merging superboxels');
+        for i_supVox = 1:numel(superVoxList)
+            waitbar(i_supVox/numel(superVoxList), h_w1)
+            supVox_idx = superVoxList(i_supVox);
+            idxList = find(superMask == supVox_idx);
+            optGoal{i_goal}.beamlets_pruned(i_supVox,:) = sparse(mean(beamlets(idxList, :),1));
+            
+            if isfield(OptGoals.data{i_goal}, 'wgt_map')
+                optGoal{i_goal}.vox_wgt(i_supVox) = sum(tabula_wgtmap(idxList));
+            end
+            
+            % -- make new indeces
+            optGoal{i_goal}.ROI_idx(i_supVox) = idxList(1);
+        end
+        close(h_w1)
+    end
+end
+
+% -- make them robust --
+RO_params=0;
+optGoal = make_robust_optGoal(optGoal, RO_params, beamlets);
+% save([Goal_path, Goal_file '_robust.mat'], 'optGoal')
+
+% -- get beamlet indeces --
+load([Pat_path, '\all_beams.mat'])
+Nbeamlets = all_beams{1}.Mxp;   % number of beamlets in a beam - usually 64 or 32
+weightTable = zeros(100,Nbeamlets);
+for ind_bmlt = 1:numel(all_beams)
+    bLet_idx.y(ind_bmlt) = floor(all_beams{1, ind_bmlt}.num/Nbeamlets)+1;
+    bLet_idx.x(ind_bmlt) = rem(all_beams{1, ind_bmlt}.num, Nbeamlets)+1;
+    weightTable(bLet_idx.y(ind_bmlt),bLet_idx.x(ind_bmlt)) = 1;
+end
+bLet_idx.idx = find(weightTable>0);
+bLet_idx.Nbeamlets = Nbeamlets;
+disp('.')
+
+% -- CALLBACK OPTIMIZATION FUNCTION --
+fun1 = @(x) get_penalty(x, optGoal_beam, bLet_idx);
+fun2 = @(x) get_penalty(x, optGoal,     bLet_idx);
+
+% -- OPTIMIZATION PARAMETERS --
+% define optimization parameters
+A = [];
+b = [];
+Aeq = [];
+beq = [];
+lb = zeros(1, numBeamlet);
+% lb_beam = zeros(1, numBeam);
+ub = [];
+nonlcon = [];
+
+% define opt limits, and make it fmincon progress
+options = optimoptions('fmincon');
+options.MaxFunctionEvaluations = N_fcallback1;
+options.Display = 'iter';
+options.PlotFcn = 'optimplotfval';
+% options.UseParallel = true;
+options.UseParallel = false;
+% options.OptimalityTolerance = 1e-9;
+
+%% -- INITIALIZE BEAMLET WEIGHTS --
+switch pre_beamWeights
+    case 'y'
+        % should have been assigned previously.
+        disp('Provided beamlet weights used for initial comparison')
+    case 'n'
+        % if initial beamlet weights are not provided, get quick estimate
+%         fprintf('\n running initial optimizer:')
+        % initialize beamlet weights, OR
+        w0 = ones(numBeamlet,1);
+%         w0 = mean(optGoal{1}.D_final(optGoal{1}.ROI_idx) ./ (optGoal{1}.beamlets_pruned*w0+0.1)) * w0; % old
+        w0 = mean(optGoal{1}.D_final(:)) ./ mean(optGoal{1}.beamlets_pruned*w0+0.05) * w0;
+        w_beamlets = double(w0);
+
+        % -- GET BEAM WEIGHTS --
+%         tic
+%         w_beam = fmincon(fun1,w0_beams,A,b,Aeq,beq,lb,ub,nonlcon,options);
+%         fprintf('  done!:')
+%         t=toc;
+%         disp(['Optimization time for beams = ',num2str(t)]);
+% 
+%         w_beamlets = ones(numBeamlet,1);
+%         numBeam=numel(unique(beam_i_list));
+%         for beam_i = 1:numBeam % assign weights to beamlets
+%             % beamlets from same beam get same initial weights
+%             w_beamlets(beam_i_list == beam_i) = w_beam(beam_i);
+%         end
+end
+
+%% FULL OPTIMIZATION
+
+% -- GET FULL BEAMLET WEIGHTS --
+options.MaxFunctionEvaluations = N_fcallback2;
+tic
+fprintf('\n running full optimizer:')
+w_fin = fmincon(fun2,w_beamlets,A,b,Aeq,beq,lb,ub,nonlcon,options);
+fprintf('  done!:')
+t=toc;
+disp(['Optimization time for beamlets = ',num2str(t)]);
+
+
+%% evaluate the results
+D_full = reshape(beamlets * w_fin, size(Geometry.data));
+
+%% save outputs
+NLP_result.dose = D_full;
+NLP_result.weights = w_fin;
+NLP_result.sss_scene_list = optGoal{1}.sss_scene_list;
+NLP_result.maxModulation = OptGoals.maxModulation;
+NLP_result.BeamSmoothMax = OptGoals.BeamSmoothMax;
+save([Pat_path, '\matlab_files\NLP_result_' Goal_file '.mat'], 'NLP_result');
+
+
+plot_DVH(Geometry, D_full)
+colorwash(Geometry.data, D_full, [500, 1500], [0, 90]);
+
+
+end
+
+%% support functions
+% ---- PENALTY FUNCTION ----
+function penalty = get_penalty(x, optGoal, bLet_idx)
+    % this function gets called by the optimizer. It checks the penalty for
+    % all the robust implementation and returns the worst result.
+    
+    NumScenarios = optGoal{1}.NbrRandScenarios * optGoal{1}.NbrSystSetUpScenarios * optGoal{1}.NbrRangeScenarios;
+    fobj = zeros(NumScenarios,numel(optGoal)+2);  
+    sc_i = 1;
+    
+
+    
+    for nrs_i = 1:optGoal{1}.NbrRandScenarios 
+        for sss_i = 1 :optGoal{1}.NbrSystSetUpScenarios % syst. setup scenarios = sss
+            for rgs_i = 1:optGoal{1}.NbrRangeScenarios % range scenario = rs
+%                 fobj(sc_i)=eval_f(x, optGoal, nrs_i, sss_i, rgs_i, bLet_idx);
+                fobj(sc_i,:) = eval_f(x, optGoal, nrs_i, sss_i, rgs_i, bLet_idx);
+                sc_i = sc_i + 1;
+            end
+        end
+    end
+    
+        
+    switch optGoal{1}.optFuncNum
+        case 1 % "RO max"
+            penalty=max(sum(fobj,2));
+        case 2 % "RO mean"
+            penalty=mean(sum(fobj,2));
+        case 3 % "RO objective-based"
+            penalty=sum(max(fobj,[],1));
+        case 4 % "Classical"
+            penalty=sum(fobj(1,:));
+    end 
+    % take the worst case penalty of evaluated scenarios
+%     penalty=max(fobj);
+    
+    % take the median worst case (stochastic robust)
+%     penalty=median(fobj);
+
+
+    
+end
+% ------ supp: penalty for single scenario ------
+function penArray = eval_f(x, optGoal, nrs_i, sss_i, rgs_i, bLet_idx)
+%     penalty = 0;
+    penArray = zeros(1,numel(optGoal)+2); % all the optGoals, plus modulation plus smoothing
+    % for each condition
+    for goal_i = 1:numel(optGoal)
+        switch optGoal{goal_i}.function
+            % min, max, min_sq, max_sq, LeastSquare, min_perc_Volume, max_perc_Volume
+            case 'min'
+                % penalize if achieved dose is lower than target dose
+                d_penalty = 1.0e0 * sum(max(0, ...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target) -...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)));
+            case 'max'
+                % penalize if achieved dose is higher than target dose
+                d_penalty = 1.0e0 * sum(max(0, ...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target)));
+            case 'min_sq'
+                % penalize if achieved dose is lower than target dose
+                temp1=min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
+                d_penalty = 1.0e0 * sum(temp1.*temp1);
+            case 'max_sq'
+                % penalize if achieved dose is higher than target dose
+                temp1=max(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
+                d_penalty = 1.0e0 * sum(temp1.*temp1);
+            case 'min_step'
+                % penalize if achieved dose is lower than target dose
+                temp1=-min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
+                d_penalty = 1.0e1 * (sum(temp1.*temp1) + 1.0e3* sum(temp1>0)/numel(temp1));
+            case 'max_step'
+                % penalize if achieved dose is higher than target dose
+                temp1=max(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
+                d_penalty = 1.0e1 * (sum(temp1.*temp1) + 1.0e3* sum(temp1>0)/numel(temp1));
+            case 'LeastSquare'
+                % penalize with sum of squares any deviation from target
+                % dose
+                temp1 = (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x) - ...
+                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target;
+                d_penalty = 1.0e0* sum(temp1.^2);
+            case 'min_perc_Volume'
+                % penalize by amount of volume under threshold
+                perc_vox = numel(find((optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target) -...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x) > 0)) ...
+                    / numel(optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target);
+                d_penalty = 3.0e4 * min(perc_vox-0.05, 0)
+                
+            case 'max_perc_Volume'
+                % penalize by amount of volume under threshold
+                perc_vox = numel(find((optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target) -...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x) < 0)) ...
+                    / numel(optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target);
+                d_penalty = 3.0e4 * min(perc_vox-0.05, 0)
+            case 'min_sq_voxwgt'
+                % penalize if achieved dose is lower than target dose
+                temp1=min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
+                d_penalty = 1.0e0 * sum(temp1.*temp1.* optGoal{goal_i}.vox_wgt');
+            case 'max_sq_voxwgt'
+                % penalize if achieved dose is lower than target dose
+                temp1=min(0, (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned * x)-...
+                    (optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target));
+                d_penalty = 1.0e0 * sum(temp1.*temp1.* optGoal{goal_i}.vox_wgt'); 
+        end
+%         penalty = penalty + d_penalty * optGoal{goal_i}.opt_weight;
+        penArray(goal_i) = d_penalty * optGoal{goal_i}.opt_weight;
+    end
+    
+    %% add modulation penalty
+    if true
+        if isfield(optGoal{goal_i}, 'maxModulation')
+            max_modulation = optGoal{goal_i}.maxModulation;
+        else
+            error('no Max modulation parameter enterd!')
+            max_modulation = 5;
+        end
+        
+        mod_pen_weight = 1.0e10;
+        % calc the penalty
+        mod_excess = max(0, x-max_modulation*mean(x));
+%         mod_excess = max(0, x-max_modulation*mean(x(x>1)));
+        mod_pen1 = mod_pen_weight*(sum(mod_excess) + numel(mod_excess)* any(mod_excess));
+%         penalty = penalty + mod_pen1;
+        penArray(end-1) = mod_pen1;
+    end
+    
+    %% add penlty for single off beamlets - version 2
+    if false
+        if isfield(optGoal{goal_i}, 'BeamSmoothMax')
+            BeamSmoothMax = optGoal{goal_i}.BeamSmoothMax;
+        else
+            error('no Max beam smooth parameter enterd!')
+            BeamSmoothMax = 1e6;
+        end
+        mod_pen_weight = BeamSmoothMax; %1.0e6
+        x_down = zeros(size(x));
+        x_down(2:end) = x(1:end-1);
+        x_down2 = zeros(size(x));
+        x_down2(3:end) = x(1:end-2);
+        x_up = zeros(size(x));
+        x_up(1:end-1) = x(2:end);
+        x_up2 = zeros(size(x));
+        x_up2(1:end-2) = x(3:end);
+        mod_pen2 = mod_pen_weight*sum((x_down+x_up-2*x).^2 + 0.5*(x_down2+x_up2-2*x).^2)/(mean(x)^(2)*numel(x));
+%         penalty = penalty + mod_pen2;
+        penArray(end) = mod_pen2;
+    end
+    %% add penlty for single off beamlets - version 3
+    if true
+        if isfield(optGoal{goal_i}, 'BeamSmoothMax')
+            BeamSmoothMax = optGoal{goal_i}.BeamSmoothMax;
+        else
+            error('no Max beam smooth parameter enterd!')
+            BeamSmoothMax = 1e6;
+        end
+        mod_pen_weight = BeamSmoothMax; %1.0e6
+        
+        % make 2D beamletWeight map
+        maxY = max(bLet_idx.y);
+        tabula = zeros(maxY, bLet_idx.Nbeamlets);
+        tabula(bLet_idx.idx) = x;
+        % for each index calculate laplace
+        myWeights = 1/12*[1,3,1; 1,-12,1; 1,3,1];
+        i=2:maxY-1;
+        j=2:bLet_idx.Nbeamlets-1;
+        tabula2(i,j) = ...
+             myWeights(1)*tabula(i-1,j-1) + myWeights(4)*tabula(i-1,j) + myWeights(7)*tabula(i-1,j+1)...
+            +myWeights(2)*tabula(i,j-1)  + myWeights(8)*tabula(i,j+1) ...
+            +myWeights(3)*tabula(i+1,j-1) + myWeights(6)*tabula(i+1,j) + myWeights(9)*tabula(i+1,j+1)...
+            +myWeights(5)*tabula(i,j);
+        tabula2(1,j) = ...
+             myWeights(2)*tabula(1,j-1) + myWeights(8)*tabula(1,j+1)...
+            +myWeights(3)*tabula(2,j-1) + myWeights(6)*tabula(2,j) + myWeights(9)*tabula(2,j+1)...
+            +myWeights(5)*tabula(1,j);
+        tabula2(maxY,j) =...
+             myWeights(1)*tabula(maxY-1,j-1) + myWeights(4)*tabula(maxY-1,j) + myWeights(7)*tabula(maxY-1,j+1)...
+            +myWeights(2)*tabula(maxY,j-1)  + myWeights(8)*tabula(maxY,j+1) ...
+            +myWeights(5)*tabula(maxY,j);
+        % make sum of squares
+        mod_pen2 = mod_pen_weight*sum((tabula2(:)).^2)/(mean(x.^2)*numel(x));
+%         penalty = penalty + mod_pen2;
+        penArray(end) = mod_pen2;
+    end
+end
+
+% ---- MAKE ROI ROBUST ----
+function optGoal = make_robust_optGoal(optGoal, RO_params, beamlets);
+    % take regular optimal goal and translate it into several robust cases
+    
+    % RO_params - should have the information below
+    % nrs - random scenarios
+    % sss - system setup scenarios
+    % rgs - random range scenarios
+    
+    % X - X>0 moves image right
+    % Y - Y>0 moves image down
+    % Z - in/out.
+    
+    shift_X = 2; % vox of shift
+    shift_Y = 2; % vox of shift
+    shift_Z = 1; % vox of shift
+    nrs_scene_list={[0,0,0]};
+
+    
+    % ----====#### CHANGE ROBUSTNESS HERE ####====----
+    if isfield(optGoal{1}, 'sss_scene_list')
+        sss_scene_list = optGoal{1}.sss_scene_list;
+    else
+        error('New OptGoals should no longer reach this code!')
+        sss_scene_list={[0,0,0], [-shift_Y,0,0], [shift_Y,0,0], [0,-shift_X,0], [0,shift_X,0], [0,0,-shift_Z], [0,0,shift_Z]};
+        optGoal{1}.sss_scene_list = sss_scene_list;
+    end
+%     sss_scene_list={[0,0,0]};
+
+    % ----====#### CHANGE ROBUSTNESS HERE ####====----
+%     [targetIn, meta] = nrrdread('C:\010-work\003_localGit\WiscPlan_v2\data\archive\CDP_data\CDP5_DP_target.nrrd');
+%     [targetIn, meta] = nrrdread('C:\010-work\003_localGit\WiscPlan_v2\data\PD_HD_dicomPhantom\Tomo_DP_target.nrrd');
+%     [targetIn, meta] = nrrdread('C:\010-work\003_localGit\WiscPlan_v2\data\archive\CDP_data\CDP5_DP_target.nrrd');
+    rgs_scene_list={[0,0,0]};
+    for i = 1:numel(optGoal)
+        optGoal{i}.NbrRandScenarios     =numel(nrs_scene_list);
+        optGoal{i}.NbrSystSetUpScenarios=numel(sss_scene_list);
+        optGoal{i}.NbrRangeScenarios    =numel(rgs_scene_list);
+    end
+    for goal_i = 1:numel(optGoal)
+        % get target
+        idx=optGoal{goal_i}.ROI_idx;
+        targetImg1=zeros(optGoal{goal_i}.imgDim);
+        targetImg1(idx)=1;
+        % get beamlets
+        for nrs_i = 1:optGoal{goal_i}.NbrRandScenarios          % num. of random scenarios
+            % modify target and beamlets
+            targetImg2=targetImg1;
+            % beamlets stay the same
+            for sss_i = 1 :optGoal{goal_i}.NbrSystSetUpScenarios   % syst. setup scenarios = sss
+                % modify target and beamlets
+                [targetImg3 idxValid]=get_RO_sss(targetImg2, sss_scene_list{sss_i});
+                % beamlets stay the same
+                for rgs_i = 1:optGoal{goal_i}.NbrRangeScenarios   % range scenario = rgs
+                    % modify target and beamlets
+                    targetImg4=targetImg3;
+                    % beamlets stay the same
+                    %% make new target and beamlets
+                    ROI_idx=[];
+                    ROI_idx=find(targetImg4>0);
+                    target = optGoal{goal_i}.D_final(idxValid);
+                    beamlets_pruned = beamlets(ROI_idx, :);
+                    % save to optGoal output
+                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.ROI_idx            = ROI_idx;
+                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.beamlets_pruned    = beamlets_pruned;
+                    optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rgs{rgs_i}.target             = target;
+                end
+            end
+        end
+    end
+end
+%% ------ supp: RO case SSS ------
+function [targetImg3 ia]=get_RO_sss(targetImg2, sss_scene_shift);
+    % translate the target image 
+    
+    targetImg3 = imtranslate(targetImg2,sss_scene_shift);
+    
+    % now we need to figure out if any target voxels fell out during the
+    % shift
+    imgValid = imtranslate(targetImg3,-sss_scene_shift);
+    imgInvalid = (targetImg2-imgValid);
+    
+    idx_1 = find(targetImg2);
+    idx_2 = find(imgInvalid);
+    
+    [idxValid,ia] = setdiff(idx_1,idx_2);
+    
+    [C,ia, ib] = intersect(idx_1,idxValid);
+    
+end
+
+
+
+

+ 159 - 159
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt2geometry.m

@@ -1,159 +1,159 @@
-function Geometry = dicomrt2geometry(dicomrt_dir)
-%DICOMRT2GEOMETRY Import DicomRT dataset to Ryan's "Geometry" struct
-% Usage:
-%   [ Geometry ] = dicomrt2geometry ( [input_dir] )
-% Input:
-%   input_dir = directory contains DicomRT data
-%   [] = prompt to select input_dir
-% Output:
-%   Geometry = Ryan's Geometry struct used with RDX TPS
-%
-% This function imports DicomRT data set and create RDX TPS compatible Geometry 
-% struct.
-%
-% TODO: Switch from filename based Dicom identification to StudyID based.
-%
-% See also readPinnGeometry.m
-%
-% Author: Xiaohu Mo
-% edits: Peter Ferjancic 2019/01
-
-Geometry = [];
-
-if nargin < 1
-%     dicomrt_dir = uifile('getdir', 'Select the directory contains the DICOM-RT images');
-% !!! Grozomah
-    load('WiscPlan_preferences.mat')
-    
-    if isfield(WiscPlan_preferences, 'inDataPath')
-        if isstring(WiscPlan_preferences.inDataPath) 
-        else
-            WiscPlan_preferences.inDataPath = 'C://';
-        end
-    else
-        WiscPlan_preferences.inDataPath = 'C://';
-    end
-    dicomrt_dir = uigetdir(WiscPlan_preferences.inDataPath, 'Select the directory contains the DICOM-RT images');
-    
-    WiscPlan_preferences.inDataPath = dicomrt_dir;
-    thisDir = mfilename('fullpath');
-    idcs   = strfind(thisDir,'\');
-    prefsdir = thisDir(1:idcs(end-1)-1);
-    save([prefsdir '\WiscPlan_preferences.mat'], 'WiscPlan_preferences')
-end
-
-if exist(dicomrt_dir, 'dir') ~= 7
-    msgbox('Cannot find input directory');
-    return;
-end
-
-%% -----===== Start Importing =====-----
-% set dicom dictionary before any dicominfo or dicomread
-dicomdict('factory');
-
-% change path due to the limitation of DicomRT toolbox
-% will cd back later
-previousPath = pwd;
-cd(dicomrt_dir);
-
-% get the list of filenames
-dirlist = dir(dicomrt_dir);
-filenames = cell(0);
-% remove directories
-for i = 1:numel(dirlist)
-    [tilde, tilde, ext] = fileparts(dirlist(i).name);
-%     if ~dirlist(i).isdir && strcmpi(ext, '.dcm') 
-    if ~dirlist(i).isdir && ~strcmpi(ext, '.txt')   % <--- Grozomah: Fix this back to default!
-        filenames{end+1} = dirlist(i).name;
-    end
-end
-
-% get all dicominfo to a cell array the same size as filelist
-for i = 1:numel(filenames)
-    dcminfo{i} = dicominfo(filenames{i});
-end
-
-% TODO integrity check
-% UID should match
-% should be only one RTSTRUCT file present
-
-%% -----===== Import Dicom CT data set =====-----
-% Create DicomRT ct list file
-fid = fopen('ctlist.txt', 'w');
-for i = 1:numel(dcminfo)
-    if strcmpi(dcminfo{i}.Modality, 'CT')
-        fprintf(fid, '%s\n', filenames{i});
-    end
-end
-fclose(fid);
-
-[cellCt, ct_xmesh, ct_ymesh, ct_zmesh] = dicomrt_loadct('ctlist.txt');
-
-%% -----===== Set Downsampling flag =====-----
-button = questdlg('Do you want to downsample the CT dataset?', 'Downsampling', 'Yes', 'No', 'Yes');
-if strcmpi(button, 'yes')
-    downsample_flag = true;
-else
-    downsample_flag = false;
-end
-
-%% -----===== Import DicomRT structure =====-----
-% File DicomRT structure file
-for i = 1:numel(dcminfo)
-    if strcmpi(dcminfo{i}.Modality, 'RTSTRUCT')
-        rsfilename = fullfile(dicomrt_dir, filenames{i});
-    end
-end
-
-% prompt if can not find RTSTRUCT file in this directory
-if isempty(rsfilename)
-    [temp_FileName temp_PathName] = uifile('get', '*.dcm', 'Please select the DicomRT-Struct file');
-    rsfilename = fullfile(temp_PathName, temp_FileName);
-end
-
-% Import the struct
-cellVoi = dicomrt_loadvoi(rsfilename);
-
-% Downsampling
-if downsample_flag == true
-    if numel(ct_xmesh) < 128
-        downsample_factor = 0.5;
-        dx = ct_xmesh(2)-ct_xmesh(1);
-        dy = ct_ymesh(2)-ct_ymesh(1);
-        ct_xmesh = linspace(ct_xmesh(1)+dx/2, ct_xmesh(end)-dx/2, numel(ct_xmesh)*downsample_factor);
-        ct_ymesh = linspace(ct_ymesh(1)+dy/2, ct_ymesh(end)-dy/2, numel(ct_ymesh)*downsample_factor);
-    else
-        downsample_factor = 0.5;
-        downsample_factor = 1/2;
-        dx = ct_xmesh(2)-ct_xmesh(1);
-        dy = ct_ymesh(2)-ct_ymesh(1);
-        ct_xmesh = linspace(ct_xmesh(1)+dx/2, ct_xmesh(end)-dx/2, numel(ct_xmesh)*downsample_factor);
-        ct_ymesh = linspace(ct_ymesh(1)+dy/2, ct_ymesh(end)-dy/2, numel(ct_ymesh)*downsample_factor);        
-    end
-end
-ROIS = dicomrt_rasterizeVoi(cellVoi, cellCt, ct_xmesh, ct_ymesh, ct_zmesh);
-
-%% -----===== Done Importing =====-----
-% change the path back
-cd(previousPath);
-
-%% -----===== Create Geometry struct =====-----
-Geometry.ROIS = ROIS;
-Geometry.data = cellCt{2};
-% !!! Grozomah - added abs() to prevent errors in later functions
-Geometry.voxel_size = abs([ct_xmesh(2)-ct_xmesh(1) ...
-    ct_ymesh(2)-ct_ymesh(1) ...
-    ct_zmesh(2)-ct_zmesh(1)]);
-Geometry.start = [ct_xmesh(1) ct_ymesh(1) ct_zmesh(1)];
-
-if downsample_flag == true
-    Geometry.data = resamplegrid(Geometry.data, [downsample_factor downsample_factor 1]);
-    % Geometry.data = resamplegrid(Geometry.data, 0.5);
-    % note that ct_xmesh, ct_ymesh, ct_zmesh is already downsampled
-    Geometry.start(1:2) = Geometry.start(1:2) + Geometry.voxel_size(1:2) / 2;
-end
-
-Geometry.rhomw = CT2dens(Geometry.data, 'pinn');
-Geometry.rhomw(Geometry.rhomw < 0.0012) = 0.0012;
-[Geometry.Smw Geometry.Fmw2] = dens2mstp(Geometry.rhomw);
-
+function Geometry = dicomrt2geometry(dicomrt_dir)
+%DICOMRT2GEOMETRY Import DicomRT dataset to Ryan's "Geometry" struct
+% Usage:
+%   [ Geometry ] = dicomrt2geometry ( [input_dir] )
+% Input:
+%   input_dir = directory contains DicomRT data
+%   [] = prompt to select input_dir
+% Output:
+%   Geometry = Ryan's Geometry struct used with RDX TPS
+%
+% This function imports DicomRT data set and create RDX TPS compatible Geometry 
+% struct.
+%
+% TODO: Switch from filename based Dicom identification to StudyID based.
+%
+% See also readPinnGeometry.m
+%
+% Author: Xiaohu Mo
+% edits: Peter Ferjancic 2019/01
+
+Geometry = [];
+
+if nargin < 1
+%     dicomrt_dir = uifile('getdir', 'Select the directory contains the DICOM-RT images');
+% !!! Grozomah
+    load('WiscPlan_preferences.mat')
+    
+    if isfield(WiscPlan_preferences, 'inDataPath')
+        if isstring(WiscPlan_preferences.inDataPath) 
+        else
+            WiscPlan_preferences.inDataPath = 'C://';
+        end
+    else
+        WiscPlan_preferences.inDataPath = 'C://';
+    end
+    dicomrt_dir = uigetdir(WiscPlan_preferences.inDataPath, 'Select the directory contains the DICOM-RT images');
+    
+    WiscPlan_preferences.inDataPath = dicomrt_dir;
+    thisDir = mfilename('fullpath');
+    idcs   = strfind(thisDir,'\');
+    prefsdir = thisDir(1:idcs(end-1)-1);
+    save([prefsdir '\WiscPlan_preferences.mat'], 'WiscPlan_preferences')
+end
+
+if exist(dicomrt_dir, 'dir') ~= 7
+    msgbox('Cannot find input directory');
+    return;
+end
+
+%% -----===== Start Importing =====-----
+% set dicom dictionary before any dicominfo or dicomread
+dicomdict('factory');
+
+% change path due to the limitation of DicomRT toolbox
+% will cd back later
+previousPath = pwd;
+cd(dicomrt_dir);
+
+% get the list of filenames
+dirlist = dir(dicomrt_dir);
+filenames = cell(0);
+% remove directories
+for i = 1:numel(dirlist)
+    [tilde, tilde, ext] = fileparts(dirlist(i).name);
+%     if ~dirlist(i).isdir && strcmpi(ext, '.dcm') 
+    if ~dirlist(i).isdir && ~strcmpi(ext, '.txt')   % <--- Grozomah: Fix this back to default!
+        filenames{end+1} = dirlist(i).name;
+    end
+end
+
+% get all dicominfo to a cell array the same size as filelist
+for i = 1:numel(filenames)
+    dcminfo{i} = dicominfo(filenames{i});
+end
+
+% TODO integrity check
+% UID should match
+% should be only one RTSTRUCT file present
+
+%% -----===== Import Dicom CT data set =====-----
+% Create DicomRT ct list file
+fid = fopen('ctlist.txt', 'w');
+for i = 1:numel(dcminfo)
+    if strcmpi(dcminfo{i}.Modality, 'CT')
+        fprintf(fid, '%s\n', filenames{i});
+    end
+end
+fclose(fid);
+
+[cellCt, ct_xmesh, ct_ymesh, ct_zmesh] = dicomrt_loadct('ctlist.txt');
+
+%% -----===== Set Downsampling flag =====-----
+button = questdlg('Do you want to downsample the CT dataset?', 'Downsampling', 'Yes', 'No', 'Yes');
+if strcmpi(button, 'yes')
+    downsample_flag = true;
+else
+    downsample_flag = false;
+end
+
+%% -----===== Import DicomRT structure =====-----
+% File DicomRT structure file
+for i = 1:numel(dcminfo)
+    if strcmpi(dcminfo{i}.Modality, 'RTSTRUCT')
+        rsfilename = fullfile(dicomrt_dir, filenames{i});
+    end
+end
+
+% prompt if can not find RTSTRUCT file in this directory
+if isempty(rsfilename)
+    [temp_FileName temp_PathName] = uifile('get', '*.dcm', 'Please select the DicomRT-Struct file');
+    rsfilename = fullfile(temp_PathName, temp_FileName);
+end
+
+% Import the struct
+cellVoi = dicomrt_loadvoi(rsfilename);
+
+% Downsampling
+if downsample_flag == true
+    if numel(ct_xmesh) < 128
+        downsample_factor = 0.5;
+        dx = ct_xmesh(2)-ct_xmesh(1);
+        dy = ct_ymesh(2)-ct_ymesh(1);
+        ct_xmesh = linspace(ct_xmesh(1)+dx/2, ct_xmesh(end)-dx/2, numel(ct_xmesh)*downsample_factor);
+        ct_ymesh = linspace(ct_ymesh(1)+dy/2, ct_ymesh(end)-dy/2, numel(ct_ymesh)*downsample_factor);
+    else
+        downsample_factor = 0.5;
+        downsample_factor = 1/2;
+        dx = ct_xmesh(2)-ct_xmesh(1);
+        dy = ct_ymesh(2)-ct_ymesh(1);
+        ct_xmesh = linspace(ct_xmesh(1)+dx/2, ct_xmesh(end)-dx/2, numel(ct_xmesh)*downsample_factor);
+        ct_ymesh = linspace(ct_ymesh(1)+dy/2, ct_ymesh(end)-dy/2, numel(ct_ymesh)*downsample_factor);        
+    end
+end
+ROIS = dicomrt_rasterizeVoi(cellVoi, cellCt, ct_xmesh, ct_ymesh, ct_zmesh);
+
+%% -----===== Done Importing =====-----
+% change the path back
+cd(previousPath);
+
+%% -----===== Create Geometry struct =====-----
+Geometry.ROIS = ROIS;
+Geometry.data = cellCt{2};
+% !!! Grozomah - added abs() to prevent errors in later functions
+Geometry.voxel_size = abs([ct_xmesh(2)-ct_xmesh(1) ...
+    ct_ymesh(2)-ct_ymesh(1) ...
+    ct_zmesh(2)-ct_zmesh(1)]);
+Geometry.start = [ct_xmesh(1) ct_ymesh(1) ct_zmesh(1)];
+
+if downsample_flag == true
+    Geometry.data = resamplegrid(Geometry.data, [downsample_factor downsample_factor 1]);
+    % Geometry.data = resamplegrid(Geometry.data, 0.5);
+    % note that ct_xmesh, ct_ymesh, ct_zmesh is already downsampled
+    Geometry.start(1:2) = Geometry.start(1:2) + Geometry.voxel_size(1:2) / 2;
+end
+
+Geometry.rhomw = CT2dens(Geometry.data, 'pinn');
+Geometry.rhomw(Geometry.rhomw < 0.0012) = 0.0012;
+[Geometry.Smw Geometry.Fmw2] = dens2mstp(Geometry.rhomw);
+

BIN
WiscPlanPhotonkV125/matlab_frontend/goal_def_UI.fig


+ 41 - 1
WiscPlanPhotonkV125/matlab_frontend/goal_def_UI.m

@@ -22,7 +22,7 @@ function varargout = goal_def_UI(varargin)
 
 % Edit the above text to modify the response to help goal_def_test
 
-% Last Modified by GUIDE v2.5 04-Jun-2020 04:51:32
+% Last Modified by GUIDE v2.5 23-Oct-2020 12:55:21
 
 % Begin initialization code - DO NOT EDIT
 gui_Singleton = 1;
@@ -95,6 +95,10 @@ handles.uitable1.Data{7} = 'null';
 handles.uitable1.Data{8} = 0;
 handles.uitable1.Data{9} = 0;
 
+% populate the drop-down
+% handles.popupmenu2.String = {"test 1","test 2"};
+set(handles.optSelect_popup, 'String', {"RO max", "RO mean", "RO objective-based", "Classical"});
+
 % Update handles structure
 guidata(hObject, handles);
 
@@ -241,6 +245,18 @@ OptGoals.goals = [handles.uitable1.Data];
 OptGoals.maxModulation = str2double(handles.maxModulation.String);
 OptGoals.BeamSmoothMax = str2double(handles.BeamSmoothMax.String);
 
+OptGoals.optFunc = handles.optSelect_popup.String{handles.optSelect_popup.Value};
+switch OptGoals.optFunc
+    case "RO max"
+        OptGoals.optFuncNum = 1;
+    case "RO mean"
+        OptGoals.optFuncNum = 2;
+    case "RO objective-based"
+        OptGoals.optFuncNum = 3;
+    case "Classical"
+        OptGoals.optFuncNum = 4;
+end
+
 OptGoals.sss.Y = handles.sss_Y.String;
 OptGoals.sss.X = handles.sss_X.String;
 OptGoals.sss.Z = handles.sss_Z.String;
@@ -454,3 +470,27 @@ function BeamSmoothMax_Callback(hObject, eventdata, handles)
 % Hints: get(hObject,'String') returns contents of BeamSmoothMax as text
 %        str2double(get(hObject,'String')) returns contents of BeamSmoothMax as a double
 end
+
+
+% --- Executes on selection change in optSelect_popup.
+function optSelect_popup_Callback(hObject, eventdata, handles)
+% hObject    handle to optSelect_popup (see GCBO)
+% eventdata  reserved - to be defined in a future version of MATLAB
+% handles    structure with handles and user data (see GUIDATA)
+
+% Hints: contents = cellstr(get(hObject,'String')) returns optSelect_popup contents as cell array
+%        contents{get(hObject,'Value')} returns selected item from optSelect_popup
+end
+
+% --- Executes during object creation, after setting all properties.
+function optSelect_popup_CreateFcn(hObject, eventdata, handles)
+% hObject    handle to optSelect_popup (see GCBO)
+% eventdata  reserved - to be defined in a future version of MATLAB
+% handles    empty - handles not created until after all CreateFcns called
+
+% Hint: popupmenu controls usually have a white background on Windows.
+%       See ISPC and COMPUTER.
+if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+    set(hObject,'BackgroundColor','white');
+end
+end

+ 532 - 532
WiscPlanPhotonkV125/matlab_frontend/helicalDosecalcSetup7.m

@@ -1,532 +1,532 @@
-%%
-
-% This version was modified by Peter Ferjancic to accept .nrrd file format
-% for target. It was also rollbacked on some parameters back to the
-% clinical system settings.
-
-% This file has been modified by Surendra Prajapati especially to run
-% WiscPlan for KV beams. Works for running locally as well as in Server.
-%
-% RTF 11/4/05
-% Sets up the run files needed for running a Condor convolution
-% superposition dose calculation with photon beams.
-
-% Versions of the convolution code that run in both Windows XP, Condor, and
-% directly through Matlab can all be created here.  The only real
-% differences between the files are in the access conventions, which just%
-% This has to do with switching forward slashes with backslashes.
-
-% Surendra edits: num_batches, SAD, pitch, xpmin/max, ypmin/max, Mxp, Nphi 
-% Also edit: 
-% Kernel should always be named Kernels.mat 
-
-function num_batches = helicalDosecalcSetup7(patient_dir)
-% -- INPUT:
-% patient_dir: specify where kernel and [geometry] files are located
-
-iso = [0 0 0]; % Point about which gantry rotations begin
-SAD = 85;  % source-axis distance for the x-ray source ##
-pitch = 0.86; % fraction of beam with couch translates per rotation
-
-%% --- make the figure prompt for number of angles and beamlets
-str = inputdlg({'Enter number of calc cores', 'Enter number of angles (51 default)', ...
-    'Enter number of beamlets (64 default)'}, 'input', [1,35], {'3', '51', '64'});
-num_batches = str2double(str{1}); % number of cores you want to run the beam calculation 
-% -- (3 for a 4-core comp to prevent lockdown)
-N_angles = str2double(str{2}); % 51 for full resolution
-Mxp = str2double(str{3}); % Mxp = 64;  number of MLC leaves;
-Nyp = 1;  % always 1 for Tomo due to binary mlc
-
-% define the overall beam field size for each beam angle
-% beam is 40 cm wide in transverse direction and 1-5 cm (usually 2) in y
-% direction.
-% isocenter is 85 cm from source, ends of jaws are 23 cm from source
-xpmin = -20.0;      % -field width / 2
-xpmax = 20.0;       % +field width / 2
-% ypmin = -0.3125;  % total jaw width is 0.625 cm
-% ypmax = 0.3125;
-% ypmin = -0.5;       % total jaw width is 1 cm
-% ypmax = 0.5;
-ypmin = -1.25;    % total jaw width is 2.5 cm
-ypmax = 1.25;
-% y-prime points in the z-direction in the CT coordinate system
-
-% ============================================= End of user-supplied inputs
-% executable_path = 'C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\WiscPlanEXE\RyanCsphoton.x86.exe';
-
-executable_path = mfilename('fullpath');
-executable_path = [executable_path(1:end-37), 'WiscPlanEXE\RyanCsphoton.x86.exe']
-
-kernel_file = 'Kernels.mat';
-geometry_file = fullfile(patient_dir, 'matlab_files\Geometry.mat');
-
-load(geometry_file);
-ROI_names = cellfun(@(c)c.name, Geometry.ROIS, 'UniformOutput', false);
-[target_idx, okay] = listdlg('ListString', ROI_names, ...
-    'SelectionMode', 'single', 'Name', 'Target Selection', ...
-    'PromptString', 'Please select the target ROI for beamlet calc. ');
-if okay ~= 1
-    msgbox('Plan creation aborted');
-    return;
-end
-
-targetMask = zeros(size(Geometry.data));
-targetMask(Geometry.ROIS{target_idx}.ind) = 1;
-
-% Grozomah - targetMask needs to get a 'double' matrix with the location of
-% the target
-
-targetMaskZ = sum(sum(targetMask,1),2);
-zBow = (find(targetMaskZ>0, 1, 'first')-1)*Geometry.voxel_size(3) + Geometry.start(3) + ypmin;
-zStern = (find(targetMaskZ>0, 1, 'last')+1)*Geometry.voxel_size(3) + Geometry.start(3) + ypmax;
-[subi, subj, subk] = ind2sub(size(Geometry.data), Geometry.ROIS{target_idx}.ind);
-iso = [Geometry.start(1)+Geometry.voxel_size(1)*mean(subi) ...
-    Geometry.start(2)+Geometry.voxel_size(2)*mean(subj) 0];
-
-% shift = [0 8 0] % Y X Z
-% iso = [iso(1)+Geometry.voxel_size(1)*shift(1) ...
-%     iso(2)+Geometry.voxel_size(2)*shift(2) ...
-%     iso(3)+Geometry.voxel_size(3)*shift(3)];
-
-% flags used to select which calculations will be set up
-Condor_flag = 1;
-
-ptvInd = target_idx;  % PTV index in Geometry.ROIS
-
-fieldWidth = ypmax - ypmin;
-
-% total number of rotations required for treatment
-Nrot = ceil(abs(zBow - zStern)/(pitch*fieldWidth));
-
-
-% Nphi = Nrot*51;  % number of angles used in the calculation
-Nphi = Nrot * N_angles;  % Grozomah
-
-% define the limits of the angles that will be used for the calculation
-% ##phimin = 0;  % starting angle in radians
-% ##phimax = 2*pi*Nphi;
-
-phi = [0:Nphi-1]/Nphi *2*pi*Nrot;
-
-condor_folder = patient_dir;
-winxp_folder = 'winxp';
-
-% create names for condor input and output folders
-input_folder = '.';
-output_folder = '.';
-
-% name of the convolution/superposition executable, which will be in the
-% 'code' folder of each respective run type folder
-condor_exectuable_name = 'convolutionCondor';  % relative path on the cluster where code will be
-winxp_executable_name = 'convolution.exe';
-matlab_executable_name = 'convolution_mex';  % name of the Matlab version of the dose calculation code
-
-% set the beam parameters, assuming a helical beam trajectory
-% folders that will be inside the 'input' folder
-beamspec_folder = 'beamspecfiles';    % directory where beam files will be stored
-beamspec_batches_folder = 'beamspecbatches';
-beamspec_batch_base_name = 'beamspecbatch';  % base name for a beamlet batch file
-kernel_folder = 'kernelfiles';  % folder where kernel information will be saved
-kernel_filenames_condor = 'kernelFilenamesCondor.txt';
-kernel_filenames_winxp = 'kernelFilenamesWinXP.txt';
-
-% output folders
-beamlet_batch_base_name = 'beamletbatch';  % base name for a dose batch file
-
-geometry_header_filename = 'geometryHeader.txt';
-geometry_density_filename = 'density.bin';  % save the density, not the Hounsfield units!
-
-% end of user-defined parameters
-
-% check the validity of the user-defined variables
-if xpmin >= xpmax
-    error('xpmin must be less than xpmax.');
-end
-
-if ypmin >= ypmax
-    error('ypmin must be less than ypmax.');b
-end
-
-% if phimin > phimax
-%     error('phimin must be less than or equal to phimax.');
-% end
-
-if Mxp <= 0 || Nyp <= 0 || Nphi <= 0
-    error('Mxp, Nyp, and Nphi must be greater than zero.');
-end
-
-if SAD < 50
-    error('It is recommended that the SAD be greater than 50 cm.');
-end
-
-% the xy plane is perpendicular to the isocenter axis of the linac gantry
-
-% size of each beam aperture, making them vectors so extension to
-% non-uniform aperture sizes becomes obvious
-del_xp = (xpmax - xpmin)/Mxp;
-del_yp = (ypmax - ypmin)/Nyp;
-
-% Calculate the xp and yp offsets, which lie at the centers of the
-% apertures.
-xp = [xpmin:del_xp:xpmax-del_xp] + del_xp/2;
-yp = [ypmin:del_yp:ypmax-del_yp] + del_yp/2;
-
-[M,N,Q] = size(Geometry.rhomw);
-
-START = single(Geometry.start - iso);
-INC = single(Geometry.voxel_size);
-
-% Grozomah ## 
-% START(1) = START(1)/10;
-% START(2) = START(2)/10;
-% INC(1) = INC(1)/10;
-% INC(2) = INC(2)/10;
-
-% END= START+[32,32,40].*INC
-
-% define the tumor mask
-tumorMask = zeros(size(Geometry.rhomw),'single');
-tumorMask(Geometry.ROIS{ptvInd}.ind) = 1;
-
-BW = bwdist(tumorMask);
-tumorMaskExp = tumorMask;
-tumorMaskExp(BW <= 4) = 1;
-
-P = zeros(Mxp,Nphi);
-
-fprintf('Checking beam''s eye view ...\n');
-for p=1:Nphi
-    % ir and jr form the beam's eye view (BEV)
-    ir = [-sin(phi(p)); cos(phi(p)); 0];
-    jr = [0 0 1]';
-    % kr denotes the beam direction
-    kr = [cos(phi(p)); sin(phi(p)); 0];
-    
-    for m=1:Mxp
-        point1 = single(-kr*SAD + [0 0 zBow + pitch*fieldWidth*phi(p)/(2*pi)]');  % source point
-        point2 = single(point1 + (SAD*kr + ir*xp(m))*10);
-        [indVisited,deffVisited] = singleRaytraceClean(tumorMaskExp,START,INC,point1,point2);
-        if ~isempty(indVisited)
-            P(m,p) = max(deffVisited);
-        end
-    end
-end
-fprintf('Finished checking BEV\n');
-
-% load data required for the dose calculator
-load(kernel_file);
-
-Geometry.rhomw(Geometry.rhomw < 0) = 0;
-Geometry.rhomw(Geometry.rhomw < 0.0013) = 0.0013;  % fill blank voxels with air
-
-% convert Geometry and kernels to single
-f = fieldnames(Kernels);
-for k=1:length(f)
-    if isnumeric(getfield(Kernels,f{k}))
-        Kernels = setfield(Kernels,f{k},single(getfield(Kernels,f{k})));    
-    end
-end
-
-f = fieldnames(Geometry);
-for k=1:length(f)
-    if isnumeric(getfield(Geometry,f{k}))
-        Geometry = setfield(Geometry,f{k},single(getfield(Geometry,f{k})));    
-    end
-end
-
-% account for isocenter
-Geometry.start = single(Geometry.start - iso);
-
-% find the total number of beams
-Nbeam = Nphi*Mxp*Nyp;
-
-batch_num = 0;  % start the count for the number of total batches
-
-% fill up a cell array of beam structures, grouped by batch
-clear batches;
-batch_num = 0;
-
-batches = cell(1,Nrot);  % start the batches cell array (cell array of beam batches)
-rotNum = 0;
-
-% calculate beams for all source directions and apertures
-for k=1:Nphi  % loop through all gantry angles
-    % calculate the source location for a helical trajectory
-    beam.SAD = single(SAD);
-    
-    % the kp vector is the beam direction, ip and jp span the beam's eye view
-    beam.ip = single([-sin(phi(k)) cos(phi(k)) 0]);
-    beam.jp = single([0 0 1]);
-    beam.kp = single([cos(phi(k)) sin(phi(k)) 0]);
-    beam.y_vec = single(-beam.kp*SAD + [0 0 zBow + pitch*fieldWidth*phi(k)/(2*pi)]);
-    
-    rotNumOld = rotNum;
-    rotNum = floor(k/51) + 1;  % current rotation number
-    if rotNum - rotNumOld > 0
-        beam_num = 0; % if the rotation number has changed, start the beam count over
-    end
-    
-    for m=1:Mxp  % loop through all apertures in the xp-direction
-        % calculate the beam if the tomotherapy fluence value is non-zero
-        if P(m,k) > 0
-            num = m + (k-1)*Mxp - 1;         % beamlet number (overall)
-            beam_num = beam_num + 1;
-
-            % set the beam aperture parameters
-            beam.del_xp = single(del_xp);
-            beam.del_yp = single(del_yp);
-            beam.xp = single(xp(m));
-            beam.yp = single(0);
-            beam.num = single(num);  % record the beam number to avoid any later ambiguity
-            
-            batches{rotNum}{beam_num} = beam;
-        end
-    end
-end
-% merge/split batches
-all_beams = horzcat(batches{:});
-num_beams_per_batch = ceil(numel(all_beams)/num_batches);
-batches = cell(num_batches,1);
-for k = 1:(num_batches)
-    beams_idx = 1+num_beams_per_batch*(k-1):num_beams_per_batch*k;
-    beams_idx (beams_idx>numel(all_beams)) = [];
-    batches{k} = all_beams(beams_idx);
-end
-% batches{num_batches} = all_beams(1+num_beams_per_batch*(k):end);
-
-
-% Everything else in this file is related to saving the batches in a
-% useable form.
-if Condor_flag == 1
-    % delete the old submission file
-    err = rmdir(fullfile(condor_folder,beamspec_batches_folder),'s');
-    err = rmdir(fullfile(condor_folder,kernel_folder),'s');
-
-    % create folders where batch information will be sent
-    mkdir([condor_folder '/' input_folder '/' beamspec_batches_folder]);
-
-    % save the kernels
-    save_kernels(Kernels,[condor_folder '/' input_folder '/' kernel_folder]);
-    fprintf(['Successfully saved Condor kernels to ' input_folder '/' kernel_folder '\n']);
-
-    % create kernel filenames files
-    kernel_filenames_CHTC = 'kernelFilenamesCHTC.txt';
-    kernel_filenames_condor = 'kernelFilenamesCondor.txt';
-    fid = fopen([condor_folder '/' input_folder '/' kernel_filenames_condor],'w');
-    fid2 = fopen([condor_folder '/' input_folder '/' kernel_filenames_CHTC],'w');
-    
-    fprintf(fid,'kernel_header\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/kernel_header.txt\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'kernel_header.txt'));
-    fprintf(fid2,'kernel_header\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'kernel_header.txt');
-    
-    fprintf(fid,'kernel_radii\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/radii.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'radii.bin'));
-    fprintf(fid2,'kernel_radii\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'radii.bin');
-    
-    fprintf(fid,'kernel_angles\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/angles.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'angles.bin'));
-    fprintf(fid2,'kernel_angles\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'angles.bin');
-      
-    fprintf(fid,'kernel_energies\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/energies.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'energies.bin'));
-    fprintf(fid2,'kernel_energies\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'energies.bin');
-    
-    fprintf(fid,'kernel_primary\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/primary.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'primary.bin'));
-    fprintf(fid2,'kernel_primary\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'primary.bin');  
-    
-    fprintf(fid,'kernel_first_scatter\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/first_scatter.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'first_scatter.bin'));
-    fprintf(fid2,'kernel_first_scatter\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'first_scatter.bin');
-    
-    fprintf(fid,'kernel_second_scatter\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/second_scatter.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'second_scatter.bin'));
-    fprintf(fid2,'kernel_second_scatter\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'second_scatter.bin');
-    
-    fprintf(fid,'kernel_multiple_scatter\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/multiple_scatter.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'multiple_scatter.bin'));
-    fprintf(fid2,'kernel_multiple_scatter\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'multiple_scatter.bin');
-    
-    fprintf(fid,'kernel_brem_annih\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/brem_annih.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'brem_annih.bin'));
-    fprintf(fid2,'kernel_brem_annih\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'brem_annih.bin');
-    
-    fprintf(fid,'kernel_total\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/total.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'total.bin'));
-    fprintf(fid2,'kernel_total\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'total.bin');
-    
-    fprintf(fid,'kernel_fluence\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/fluence.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'fluence.bin'));
-    fprintf(fid2,'kernel_fluence\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'fluence.bin');
-    
-    fprintf(fid,'kernel_mu\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/mu.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'mu.bin'));
-    fprintf(fid2,'kernel_mu\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'mu.bin');
-    
-    fprintf(fid,'kernel_mu_en\n');
-    % fprintf(fid,['./' input_folder '/' kernel_folder '/mu_en.bin\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'mu_en.bin'));
-    fprintf(fid2,'kernel_mu_en\n');
-    fprintf(fid2, '%s/%s\n', kernel_folder,'mu_en.bin');
-    
-    fclose(fid);
-end
-
-% name for the condor submit file that will be used
-condor_submit_file = 'convolutionSubmit.txt';
-
-geometry_filenames_condor = 'geometryFilenamesCondor.txt';
-geometry_filenames_CHTC = 'geometryFilenamesCHTC.txt';
-
-% check the geometry file to ensure that it's not in Hounsfield units
-if length(find(Geometry.rhomw > 20)) || length(find(Geometry.rhomw < 0))
-    error('Double check the Geometry structure, it may still be in Hounsfield units!');
-end
-
-geometry_folder = 'geometryfiles';
-batch_output_folder = 'batchoutput';  % folder to which stdout will be printed
-beamlet_batches_folder = 'beamletbatches';  % folder where resulting beamlet batches will be stored
-
-if Condor_flag == 1
-    mkdir([condor_folder '/' output_folder '/' beamlet_batches_folder]);
-    mkdir([condor_folder '/' output_folder '/' batch_output_folder]);
-
-    save_geometry(Geometry,[condor_folder '/' input_folder '/' geometry_folder],geometry_header_filename,geometry_density_filename);
-    fprintf(['Successfully saved Condor geometry to ' input_folder '/' geometry_folder '\n']);
-
-    % create geometry filenames files
-    fid = fopen([condor_folder '/' input_folder '/' geometry_filenames_condor],'w');
-    fid2 = fopen([condor_folder '/' input_folder '/' geometry_filenames_CHTC],'w');
-    
-    fprintf(fid,'geometry_header\n');
-    % fprintf(fid,['./' input_folder '/' geometry_folder '/' geometry_header_filename '\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,geometry_folder,geometry_header_filename));
-    fprintf(fid2,'geometry_header\n');
-    fprintf(fid2, '%s/%s\n', geometry_folder,'geometryHeader.txt');
-    
-    fprintf(fid,'geometry_density\n');
-    % fprintf(fid,['./' input_folder '/' geometry_folder '/' geometry_density_filename '\n']);
-    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,geometry_folder,geometry_density_filename));
-    fprintf(fid2,'geometry_density\n');
-    fprintf(fid2, '%s/%s\n', geometry_folder,'density.bin');
-    fclose(fid);
-    
-    % write command file
-    % TODO consistent naming throughout script
-    for k = 1:numel(batches)
-        fid = fopen(fullfile(patient_dir,sprintf('run%d.cmd',k-1)), 'w');
-        fprintf(fid, '"%s" "%s" "%s" "%s" "%s"', executable_path,...
-            fullfile(patient_dir, kernel_filenames_condor),...
-            fullfile(patient_dir, geometry_filenames_condor),...
-            fullfile(patient_dir, 'beamspecbatches', sprintf('beamspecbatch%d.txt',k-1)),...
-            fullfile(patient_dir, sprintf('batch_dose%d.bin',k-1)));
-        fclose(fid);
-    end
-
-    % write the condor submit file
-%     beamspec_batch_filename = ['./' input_folder '/' beamspec_batches_folder '/' beamspec_batch_base_name '$(Process).txt'];
-%     beamlet_batch_filename = ['./' output_folder '/' beamlet_batches_folder '/' beamlet_batch_base_name '$(Process).bin'];
-%     fid = fopen([condor_folder '/' condor_submit_file],'w');
-%     fprintf(fid,'###############################################################\n');
-%     fprintf(fid,'# Condor submission script for convolution/superposition code\n');
-%     fprintf(fid,'###############################################################\n\n');
-%     fprintf(fid,'copy_to_spool = false\n');
-%     fprintf(fid,['Executable   = ' code_folder '/' condor_exectuable_name '\n']);
-%     fprintf(fid,['arguments    = ' input_folder '/' kernel_filenames_condor ' ' input_folder '/' geometry_filenames_condor ' ' beamspec_batch_filename ' ' beamlet_batch_filename '\n']);
-%     fprintf(fid,['Output       = ./' output_folder '/' batch_output_folder '/batchout$(Process).txt\n']);
-%     fprintf(fid,['Log          = ./' output_folder '/' batch_output_folder '/log.txt\n']);
-%     fprintf(fid,['Queue  ' num2str(Nrot)]);
-%     fclose(fid);
-
-
- 
-% % write the condor submit file
-%      beamspec_batch_filename = ['./' input_folder '/' beamspec_batches_folder '/' beamspec_batch_base_name '$(Process).txt'];
-%      beamlet_batch_filename = ['./' output_folder '/' beamlet_batches_folder '/' beamlet_batch_base_name '$(Process).bin'];
-     fid = fopen([condor_folder '/' condor_submit_file],'w');
-     fprintf(fid,'###############################################################\n');
-     fprintf(fid,'# Condor submission script for convolution/superposition code\n');
-     fprintf(fid,'###############################################################\n\n');
-     fprintf(fid,'copy_to_spool = false\n');
-     fprintf(fid,['Executable   = ' condor_exectuable_name '\n']);
-     fprintf(fid,['Arguments    = ' kernel_filenames_CHTC ' ' geometry_filenames_CHTC ' ' beamspec_batch_base_name '$(Process).txt ' 'batch_dose$(Process).bin\n']);
-     fprintf(fid,['Transfer_input_files = ' kernel_folder ',' geometry_folder ',' beamspec_batches_folder '/' beamspec_batch_base_name '$(Process).txt' ',' kernel_filenames_CHTC ',' geometry_filenames_CHTC '\n']);
-     fprintf(fid,['Request_memory = 1000' '\n']);
-     fprintf(fid,['Request_disk = 500000' '\n']);
-     fprintf(fid,['Output       = $(Cluster).out' '\n']);
-     fprintf(fid,['Log          = $(Cluster).log' '\n']);
-     fprintf(fid,['Error          = $(Cluster).err' '\n']);
-     fprintf(fid,['Queue  ' num2str(num_batches) '\n']);
-%      fclose(fid);
-end
-
-
-% write the batches to files
-for n=1:numel(batches)
-    batch = batches{n};  % current batch
-
-    if Condor_flag == 1
-        save_beamspec_batch(batch,[condor_folder '/' input_folder '/' beamspec_batches_folder],[beamspec_batch_base_name num2str(n-1) '.txt']);
-    end
-end
-
-
-all_beams{1}.Mxp = Mxp;
-all_beams{1}.N_angles = N_angles;
-all_beams{1}.num_batches = num_batches;
-save([patient_dir '\all_beams.mat'], 'all_beams');
-% for k = 1:numel(batches)
-%         system([fullfile(patient_dir,sprintf('run%d.cmd',k-1)) ' &']);
-%     end 
-
-% Ask for User option to run the dose calculation locally on the computer 
-% or just to get necessary files for CHTC server
-% 'y' means run locally, 'n' means not to run locally on the computer
-
-strBeamlet = '';
-while(1)
-    if strcmpi('y',strBeamlet)
-        break;
-    elseif strcmpi('n',strBeamlet)
-        break;
-    end
-    
-    strBeamlet = input('Run beamlet batches dose calculation locally? y/n \n','s');
-end
-
-t = datetime('now');
-disp(['Calculating ' num2str(size(all_beams, 2)) ' beamlets in ' num2str(size(batches, 1))...
-    ' batches. Start: ' datestr(t)])
-
-if(strcmpi('y',strBeamlet)) 
-    for k = 1:numel(batches)
-        system([fullfile(patient_dir,sprintf('run%d.cmd',k-1)) ' &']);
-    end 
-end
-
-end
-
+%%
+
+% This version was modified by Peter Ferjancic to accept .nrrd file format
+% for target. It was also rollbacked on some parameters back to the
+% clinical system settings.
+
+% This file has been modified by Surendra Prajapati especially to run
+% WiscPlan for KV beams. Works for running locally as well as in Server.
+%
+% RTF 11/4/05
+% Sets up the run files needed for running a Condor convolution
+% superposition dose calculation with photon beams.
+
+% Versions of the convolution code that run in both Windows XP, Condor, and
+% directly through Matlab can all be created here.  The only real
+% differences between the files are in the access conventions, which just%
+% This has to do with switching forward slashes with backslashes.
+
+% Surendra edits: num_batches, SAD, pitch, xpmin/max, ypmin/max, Mxp, Nphi 
+% Also edit: 
+% Kernel should always be named Kernels.mat 
+
+function num_batches = helicalDosecalcSetup7(patient_dir)
+% -- INPUT:
+% patient_dir: specify where kernel and [geometry] files are located
+
+iso = [0 0 0]; % Point about which gantry rotations begin
+SAD = 85;  % source-axis distance for the x-ray source ##
+pitch = 0.86; % fraction of beam with couch translates per rotation
+
+%% --- make the figure prompt for number of angles and beamlets
+str = inputdlg({'Enter number of calc cores', 'Enter number of angles (51 default)', ...
+    'Enter number of beamlets (64 default)'}, 'input', [1,35], {'3', '51', '64'});
+num_batches = str2double(str{1}); % number of cores you want to run the beam calculation 
+% -- (3 for a 4-core comp to prevent lockdown)
+N_angles = str2double(str{2}); % 51 for full resolution
+Mxp = str2double(str{3}); % Mxp = 64;  number of MLC leaves;
+Nyp = 1;  % always 1 for Tomo due to binary mlc
+
+% define the overall beam field size for each beam angle
+% beam is 40 cm wide in transverse direction and 1-5 cm (usually 2) in y
+% direction.
+% isocenter is 85 cm from source, ends of jaws are 23 cm from source
+xpmin = -20.0;      % -field width / 2
+xpmax = 20.0;       % +field width / 2
+% ypmin = -0.3125;  % total jaw width is 0.625 cm
+% ypmax = 0.3125;
+% ypmin = -0.5;       % total jaw width is 1 cm
+% ypmax = 0.5;
+ypmin = -1.25;    % total jaw width is 2.5 cm
+ypmax = 1.25;
+% y-prime points in the z-direction in the CT coordinate system
+
+% ============================================= End of user-supplied inputs
+% executable_path = 'C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\WiscPlanEXE\RyanCsphoton.x86.exe';
+
+executable_path = mfilename('fullpath');
+executable_path = [executable_path(1:end-37), 'WiscPlanEXE\RyanCsphoton.x86.exe']
+
+kernel_file = 'Kernels.mat';
+geometry_file = fullfile(patient_dir, 'matlab_files\Geometry.mat');
+
+load(geometry_file);
+ROI_names = cellfun(@(c)c.name, Geometry.ROIS, 'UniformOutput', false);
+[target_idx, okay] = listdlg('ListString', ROI_names, ...
+    'SelectionMode', 'single', 'Name', 'Target Selection', ...
+    'PromptString', 'Please select the target ROI for beamlet calc. ');
+if okay ~= 1
+    msgbox('Plan creation aborted');
+    return;
+end
+
+targetMask = zeros(size(Geometry.data));
+targetMask(Geometry.ROIS{target_idx}.ind) = 1;
+
+% Grozomah - targetMask needs to get a 'double' matrix with the location of
+% the target
+
+targetMaskZ = sum(sum(targetMask,1),2);
+zBow = (find(targetMaskZ>0, 1, 'first')-1)*Geometry.voxel_size(3) + Geometry.start(3) + ypmin;
+zStern = (find(targetMaskZ>0, 1, 'last')+1)*Geometry.voxel_size(3) + Geometry.start(3) + ypmax;
+[subi, subj, subk] = ind2sub(size(Geometry.data), Geometry.ROIS{target_idx}.ind);
+iso = [Geometry.start(1)+Geometry.voxel_size(1)*mean(subi) ...
+    Geometry.start(2)+Geometry.voxel_size(2)*mean(subj) 0];
+
+% shift = [0 8 0] % Y X Z
+% iso = [iso(1)+Geometry.voxel_size(1)*shift(1) ...
+%     iso(2)+Geometry.voxel_size(2)*shift(2) ...
+%     iso(3)+Geometry.voxel_size(3)*shift(3)];
+
+% flags used to select which calculations will be set up
+Condor_flag = 1;
+
+ptvInd = target_idx;  % PTV index in Geometry.ROIS
+
+fieldWidth = ypmax - ypmin;
+
+% total number of rotations required for treatment
+Nrot = ceil(abs(zBow - zStern)/(pitch*fieldWidth));
+
+
+% Nphi = Nrot*51;  % number of angles used in the calculation
+Nphi = Nrot * N_angles;  % Grozomah
+
+% define the limits of the angles that will be used for the calculation
+% ##phimin = 0;  % starting angle in radians
+% ##phimax = 2*pi*Nphi;
+
+phi = [0:Nphi-1]/Nphi *2*pi*Nrot;
+
+condor_folder = patient_dir;
+winxp_folder = 'winxp';
+
+% create names for condor input and output folders
+input_folder = '.';
+output_folder = '.';
+
+% name of the convolution/superposition executable, which will be in the
+% 'code' folder of each respective run type folder
+condor_exectuable_name = 'convolutionCondor';  % relative path on the cluster where code will be
+winxp_executable_name = 'convolution.exe';
+matlab_executable_name = 'convolution_mex';  % name of the Matlab version of the dose calculation code
+
+% set the beam parameters, assuming a helical beam trajectory
+% folders that will be inside the 'input' folder
+beamspec_folder = 'beamspecfiles';    % directory where beam files will be stored
+beamspec_batches_folder = 'beamspecbatches';
+beamspec_batch_base_name = 'beamspecbatch';  % base name for a beamlet batch file
+kernel_folder = 'kernelfiles';  % folder where kernel information will be saved
+kernel_filenames_condor = 'kernelFilenamesCondor.txt';
+kernel_filenames_winxp = 'kernelFilenamesWinXP.txt';
+
+% output folders
+beamlet_batch_base_name = 'beamletbatch';  % base name for a dose batch file
+
+geometry_header_filename = 'geometryHeader.txt';
+geometry_density_filename = 'density.bin';  % save the density, not the Hounsfield units!
+
+% end of user-defined parameters
+
+% check the validity of the user-defined variables
+if xpmin >= xpmax
+    error('xpmin must be less than xpmax.');
+end
+
+if ypmin >= ypmax
+    error('ypmin must be less than ypmax.');b
+end
+
+% if phimin > phimax
+%     error('phimin must be less than or equal to phimax.');
+% end
+
+if Mxp <= 0 || Nyp <= 0 || Nphi <= 0
+    error('Mxp, Nyp, and Nphi must be greater than zero.');
+end
+
+if SAD < 50
+    error('It is recommended that the SAD be greater than 50 cm.');
+end
+
+% the xy plane is perpendicular to the isocenter axis of the linac gantry
+
+% size of each beam aperture, making them vectors so extension to
+% non-uniform aperture sizes becomes obvious
+del_xp = (xpmax - xpmin)/Mxp;
+del_yp = (ypmax - ypmin)/Nyp;
+
+% Calculate the xp and yp offsets, which lie at the centers of the
+% apertures.
+xp = [xpmin:del_xp:xpmax-del_xp] + del_xp/2;
+yp = [ypmin:del_yp:ypmax-del_yp] + del_yp/2;
+
+[M,N,Q] = size(Geometry.rhomw);
+
+START = single(Geometry.start - iso);
+INC = single(Geometry.voxel_size);
+
+% Grozomah ## 
+% START(1) = START(1)/10;
+% START(2) = START(2)/10;
+% INC(1) = INC(1)/10;
+% INC(2) = INC(2)/10;
+
+% END= START+[32,32,40].*INC
+
+% define the tumor mask
+tumorMask = zeros(size(Geometry.rhomw),'single');
+tumorMask(Geometry.ROIS{ptvInd}.ind) = 1;
+
+BW = bwdist(tumorMask);
+tumorMaskExp = tumorMask;
+tumorMaskExp(BW <= 4) = 1;
+
+P = zeros(Mxp,Nphi);
+
+fprintf('Checking beam''s eye view ...\n');
+for p=1:Nphi
+    % ir and jr form the beam's eye view (BEV)
+    ir = [-sin(phi(p)); cos(phi(p)); 0];
+    jr = [0 0 1]';
+    % kr denotes the beam direction
+    kr = [cos(phi(p)); sin(phi(p)); 0];
+    
+    for m=1:Mxp
+        point1 = single(-kr*SAD + [0 0 zBow + pitch*fieldWidth*phi(p)/(2*pi)]');  % source point
+        point2 = single(point1 + (SAD*kr + ir*xp(m))*10);
+        [indVisited,deffVisited] = singleRaytraceClean(tumorMaskExp,START,INC,point1,point2);
+        if ~isempty(indVisited)
+            P(m,p) = max(deffVisited);
+        end
+    end
+end
+fprintf('Finished checking BEV\n');
+
+% load data required for the dose calculator
+load(kernel_file);
+
+Geometry.rhomw(Geometry.rhomw < 0) = 0;
+Geometry.rhomw(Geometry.rhomw < 0.0013) = 0.0013;  % fill blank voxels with air
+
+% convert Geometry and kernels to single
+f = fieldnames(Kernels);
+for k=1:length(f)
+    if isnumeric(getfield(Kernels,f{k}))
+        Kernels = setfield(Kernels,f{k},single(getfield(Kernels,f{k})));    
+    end
+end
+
+f = fieldnames(Geometry);
+for k=1:length(f)
+    if isnumeric(getfield(Geometry,f{k}))
+        Geometry = setfield(Geometry,f{k},single(getfield(Geometry,f{k})));    
+    end
+end
+
+% account for isocenter
+Geometry.start = single(Geometry.start - iso);
+
+% find the total number of beams
+Nbeam = Nphi*Mxp*Nyp;
+
+batch_num = 0;  % start the count for the number of total batches
+
+% fill up a cell array of beam structures, grouped by batch
+clear batches;
+batch_num = 0;
+
+batches = cell(1,Nrot);  % start the batches cell array (cell array of beam batches)
+rotNum = 0;
+
+% calculate beams for all source directions and apertures
+for k=1:Nphi  % loop through all gantry angles
+    % calculate the source location for a helical trajectory
+    beam.SAD = single(SAD);
+    
+    % the kp vector is the beam direction, ip and jp span the beam's eye view
+    beam.ip = single([-sin(phi(k)) cos(phi(k)) 0]);
+    beam.jp = single([0 0 1]);
+    beam.kp = single([cos(phi(k)) sin(phi(k)) 0]);
+    beam.y_vec = single(-beam.kp*SAD + [0 0 zBow + pitch*fieldWidth*phi(k)/(2*pi)]);
+    
+    rotNumOld = rotNum;
+    rotNum = floor(k/51) + 1;  % current rotation number
+    if rotNum - rotNumOld > 0
+        beam_num = 0; % if the rotation number has changed, start the beam count over
+    end
+    
+    for m=1:Mxp  % loop through all apertures in the xp-direction
+        % calculate the beam if the tomotherapy fluence value is non-zero
+        if P(m,k) > 0
+            num = m + (k-1)*Mxp - 1;         % beamlet number (overall)
+            beam_num = beam_num + 1;
+
+            % set the beam aperture parameters
+            beam.del_xp = single(del_xp);
+            beam.del_yp = single(del_yp);
+            beam.xp = single(xp(m));
+            beam.yp = single(0);
+            beam.num = single(num);  % record the beam number to avoid any later ambiguity
+            
+            batches{rotNum}{beam_num} = beam;
+        end
+    end
+end
+% merge/split batches
+all_beams = horzcat(batches{:});
+num_beams_per_batch = ceil(numel(all_beams)/num_batches);
+batches = cell(num_batches,1);
+for k = 1:(num_batches)
+    beams_idx = 1+num_beams_per_batch*(k-1):num_beams_per_batch*k;
+    beams_idx (beams_idx>numel(all_beams)) = [];
+    batches{k} = all_beams(beams_idx);
+end
+% batches{num_batches} = all_beams(1+num_beams_per_batch*(k):end);
+
+
+% Everything else in this file is related to saving the batches in a
+% useable form.
+if Condor_flag == 1
+    % delete the old submission file
+    err = rmdir(fullfile(condor_folder,beamspec_batches_folder),'s');
+    err = rmdir(fullfile(condor_folder,kernel_folder),'s');
+
+    % create folders where batch information will be sent
+    mkdir([condor_folder '/' input_folder '/' beamspec_batches_folder]);
+
+    % save the kernels
+    save_kernels(Kernels,[condor_folder '/' input_folder '/' kernel_folder]);
+    fprintf(['Successfully saved Condor kernels to ' input_folder '/' kernel_folder '\n']);
+
+    % create kernel filenames files
+    kernel_filenames_CHTC = 'kernelFilenamesCHTC.txt';
+    kernel_filenames_condor = 'kernelFilenamesCondor.txt';
+    fid = fopen([condor_folder '/' input_folder '/' kernel_filenames_condor],'w');
+    fid2 = fopen([condor_folder '/' input_folder '/' kernel_filenames_CHTC],'w');
+    
+    fprintf(fid,'kernel_header\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/kernel_header.txt\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'kernel_header.txt'));
+    fprintf(fid2,'kernel_header\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'kernel_header.txt');
+    
+    fprintf(fid,'kernel_radii\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/radii.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'radii.bin'));
+    fprintf(fid2,'kernel_radii\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'radii.bin');
+    
+    fprintf(fid,'kernel_angles\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/angles.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'angles.bin'));
+    fprintf(fid2,'kernel_angles\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'angles.bin');
+      
+    fprintf(fid,'kernel_energies\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/energies.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'energies.bin'));
+    fprintf(fid2,'kernel_energies\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'energies.bin');
+    
+    fprintf(fid,'kernel_primary\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/primary.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'primary.bin'));
+    fprintf(fid2,'kernel_primary\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'primary.bin');  
+    
+    fprintf(fid,'kernel_first_scatter\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/first_scatter.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'first_scatter.bin'));
+    fprintf(fid2,'kernel_first_scatter\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'first_scatter.bin');
+    
+    fprintf(fid,'kernel_second_scatter\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/second_scatter.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'second_scatter.bin'));
+    fprintf(fid2,'kernel_second_scatter\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'second_scatter.bin');
+    
+    fprintf(fid,'kernel_multiple_scatter\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/multiple_scatter.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'multiple_scatter.bin'));
+    fprintf(fid2,'kernel_multiple_scatter\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'multiple_scatter.bin');
+    
+    fprintf(fid,'kernel_brem_annih\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/brem_annih.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'brem_annih.bin'));
+    fprintf(fid2,'kernel_brem_annih\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'brem_annih.bin');
+    
+    fprintf(fid,'kernel_total\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/total.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'total.bin'));
+    fprintf(fid2,'kernel_total\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'total.bin');
+    
+    fprintf(fid,'kernel_fluence\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/fluence.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'fluence.bin'));
+    fprintf(fid2,'kernel_fluence\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'fluence.bin');
+    
+    fprintf(fid,'kernel_mu\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/mu.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'mu.bin'));
+    fprintf(fid2,'kernel_mu\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'mu.bin');
+    
+    fprintf(fid,'kernel_mu_en\n');
+    % fprintf(fid,['./' input_folder '/' kernel_folder '/mu_en.bin\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,kernel_folder,'mu_en.bin'));
+    fprintf(fid2,'kernel_mu_en\n');
+    fprintf(fid2, '%s/%s\n', kernel_folder,'mu_en.bin');
+    
+    fclose(fid);
+end
+
+% name for the condor submit file that will be used
+condor_submit_file = 'convolutionSubmit.txt';
+
+geometry_filenames_condor = 'geometryFilenamesCondor.txt';
+geometry_filenames_CHTC = 'geometryFilenamesCHTC.txt';
+
+% check the geometry file to ensure that it's not in Hounsfield units
+if length(find(Geometry.rhomw > 20)) || length(find(Geometry.rhomw < 0))
+    error('Double check the Geometry structure, it may still be in Hounsfield units!');
+end
+
+geometry_folder = 'geometryfiles';
+batch_output_folder = 'batchoutput';  % folder to which stdout will be printed
+beamlet_batches_folder = 'beamletbatches';  % folder where resulting beamlet batches will be stored
+
+if Condor_flag == 1
+    mkdir([condor_folder '/' output_folder '/' beamlet_batches_folder]);
+    mkdir([condor_folder '/' output_folder '/' batch_output_folder]);
+
+    save_geometry(Geometry,[condor_folder '/' input_folder '/' geometry_folder],geometry_header_filename,geometry_density_filename);
+    fprintf(['Successfully saved Condor geometry to ' input_folder '/' geometry_folder '\n']);
+
+    % create geometry filenames files
+    fid = fopen([condor_folder '/' input_folder '/' geometry_filenames_condor],'w');
+    fid2 = fopen([condor_folder '/' input_folder '/' geometry_filenames_CHTC],'w');
+    
+    fprintf(fid,'geometry_header\n');
+    % fprintf(fid,['./' input_folder '/' geometry_folder '/' geometry_header_filename '\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,geometry_folder,geometry_header_filename));
+    fprintf(fid2,'geometry_header\n');
+    fprintf(fid2, '%s/%s\n', geometry_folder,'geometryHeader.txt');
+    
+    fprintf(fid,'geometry_density\n');
+    % fprintf(fid,['./' input_folder '/' geometry_folder '/' geometry_density_filename '\n']);
+    fprintf(fid,'%s\n',fullfile(patient_dir,input_folder,geometry_folder,geometry_density_filename));
+    fprintf(fid2,'geometry_density\n');
+    fprintf(fid2, '%s/%s\n', geometry_folder,'density.bin');
+    fclose(fid);
+    
+    % write command file
+    % TODO consistent naming throughout script
+    for k = 1:numel(batches)
+        fid = fopen(fullfile(patient_dir,sprintf('run%d.cmd',k-1)), 'w');
+        fprintf(fid, '"%s" "%s" "%s" "%s" "%s"', executable_path,...
+            fullfile(patient_dir, kernel_filenames_condor),...
+            fullfile(patient_dir, geometry_filenames_condor),...
+            fullfile(patient_dir, 'beamspecbatches', sprintf('beamspecbatch%d.txt',k-1)),...
+            fullfile(patient_dir, sprintf('batch_dose%d.bin',k-1)));
+        fclose(fid);
+    end
+
+    % write the condor submit file
+%     beamspec_batch_filename = ['./' input_folder '/' beamspec_batches_folder '/' beamspec_batch_base_name '$(Process).txt'];
+%     beamlet_batch_filename = ['./' output_folder '/' beamlet_batches_folder '/' beamlet_batch_base_name '$(Process).bin'];
+%     fid = fopen([condor_folder '/' condor_submit_file],'w');
+%     fprintf(fid,'###############################################################\n');
+%     fprintf(fid,'# Condor submission script for convolution/superposition code\n');
+%     fprintf(fid,'###############################################################\n\n');
+%     fprintf(fid,'copy_to_spool = false\n');
+%     fprintf(fid,['Executable   = ' code_folder '/' condor_exectuable_name '\n']);
+%     fprintf(fid,['arguments    = ' input_folder '/' kernel_filenames_condor ' ' input_folder '/' geometry_filenames_condor ' ' beamspec_batch_filename ' ' beamlet_batch_filename '\n']);
+%     fprintf(fid,['Output       = ./' output_folder '/' batch_output_folder '/batchout$(Process).txt\n']);
+%     fprintf(fid,['Log          = ./' output_folder '/' batch_output_folder '/log.txt\n']);
+%     fprintf(fid,['Queue  ' num2str(Nrot)]);
+%     fclose(fid);
+
+
+ 
+% % write the condor submit file
+%      beamspec_batch_filename = ['./' input_folder '/' beamspec_batches_folder '/' beamspec_batch_base_name '$(Process).txt'];
+%      beamlet_batch_filename = ['./' output_folder '/' beamlet_batches_folder '/' beamlet_batch_base_name '$(Process).bin'];
+     fid = fopen([condor_folder '/' condor_submit_file],'w');
+     fprintf(fid,'###############################################################\n');
+     fprintf(fid,'# Condor submission script for convolution/superposition code\n');
+     fprintf(fid,'###############################################################\n\n');
+     fprintf(fid,'copy_to_spool = false\n');
+     fprintf(fid,['Executable   = ' condor_exectuable_name '\n']);
+     fprintf(fid,['Arguments    = ' kernel_filenames_CHTC ' ' geometry_filenames_CHTC ' ' beamspec_batch_base_name '$(Process).txt ' 'batch_dose$(Process).bin\n']);
+     fprintf(fid,['Transfer_input_files = ' kernel_folder ',' geometry_folder ',' beamspec_batches_folder '/' beamspec_batch_base_name '$(Process).txt' ',' kernel_filenames_CHTC ',' geometry_filenames_CHTC '\n']);
+     fprintf(fid,['Request_memory = 1000' '\n']);
+     fprintf(fid,['Request_disk = 500000' '\n']);
+     fprintf(fid,['Output       = $(Cluster).out' '\n']);
+     fprintf(fid,['Log          = $(Cluster).log' '\n']);
+     fprintf(fid,['Error          = $(Cluster).err' '\n']);
+     fprintf(fid,['Queue  ' num2str(num_batches) '\n']);
+%      fclose(fid);
+end
+
+
+% write the batches to files
+for n=1:numel(batches)
+    batch = batches{n};  % current batch
+
+    if Condor_flag == 1
+        save_beamspec_batch(batch,[condor_folder '/' input_folder '/' beamspec_batches_folder],[beamspec_batch_base_name num2str(n-1) '.txt']);
+    end
+end
+
+
+all_beams{1}.Mxp = Mxp;
+all_beams{1}.N_angles = N_angles;
+all_beams{1}.num_batches = num_batches;
+save([patient_dir '\all_beams.mat'], 'all_beams');
+% for k = 1:numel(batches)
+%         system([fullfile(patient_dir,sprintf('run%d.cmd',k-1)) ' &']);
+%     end 
+
+% Ask for User option to run the dose calculation locally on the computer 
+% or just to get necessary files for CHTC server
+% 'y' means run locally, 'n' means not to run locally on the computer
+
+strBeamlet = '';
+while(1)
+    if strcmpi('y',strBeamlet)
+        break;
+    elseif strcmpi('n',strBeamlet)
+        break;
+    end
+    
+    strBeamlet = input('Run beamlet batches dose calculation locally? y/n \n','s');
+end
+
+t = datetime('now');
+disp(['Calculating ' num2str(size(all_beams, 2)) ' beamlets in ' num2str(size(batches, 1))...
+    ' batches. Start: ' datestr(t)])
+
+if(strcmpi('y',strBeamlet)) 
+    for k = 1:numel(batches)
+        system([fullfile(patient_dir,sprintf('run%d.cmd',k-1)) ' &']);
+    end 
+end
+
+end
+