Browse Source

+ get_beamlets now accounts for shifts when seleting vox of interest
+ resizable OptGoal GUI

pferjancic 4 years ago
parent
commit
c64ace023a
97 changed files with 16118 additions and 16103 deletions
  1. 10 10
      .gitignore
  2. 42 42
      NLP_run_loop.m
  3. 726 726
      ROI_goals_prep.m
  4. 61 61
      WiscPlan-SourceCode/Source-code-photon-windows/calc_deff.cpp
  5. 362 362
      WiscPlan-SourceCode/Source-code-photon-windows/calc_dose.cpp
  6. 390 390
      WiscPlan-SourceCode/Source-code-photon-windows/convolutionCondor.cpp
  7. 138 138
      WiscPlan-SourceCode/Source-code-photon-windows/defs.h
  8. 122 122
      WiscPlan-SourceCode/Source-code-photon-windows/make_poly.cpp
  9. 11 11
      WiscPlan-SourceCode/Source-code-photon-windows/makefile
  10. 825 825
      WiscPlan-SourceCode/Source-code-photon-windows/parse_funcCondor.cpp
  11. 345 345
      WiscPlan-SourceCode/Source-code-photon-windows/raytrace.cpp
  12. 301 301
      WiscPlan-SourceCode/Source-code-photon-windows/terma_dose_masks.cpp
  13. 60 60
      WiscPlan-SourceCode/Source-code-photon-windows/terma_kerma.cpp
  14. 117 117
      WiscPlan-SourceCode/Source-code-photon-windows/util.cpp
  15. 61 61
      WiscPlan-SourceCode/source-code-photon-linux/calc_deff.cpp
  16. 360 360
      WiscPlan-SourceCode/source-code-photon-linux/calc_dose.cpp
  17. 396 396
      WiscPlan-SourceCode/source-code-photon-linux/convolutionCondor.cpp
  18. 138 138
      WiscPlan-SourceCode/source-code-photon-linux/defs.h
  19. 122 122
      WiscPlan-SourceCode/source-code-photon-linux/make_poly.cpp
  20. 12 12
      WiscPlan-SourceCode/source-code-photon-linux/makefile
  21. 825 825
      WiscPlan-SourceCode/source-code-photon-linux/parse_funcCondor.cpp
  22. 345 345
      WiscPlan-SourceCode/source-code-photon-linux/raytrace.cpp
  23. 301 301
      WiscPlan-SourceCode/source-code-photon-linux/terma_dose_masks.cpp
  24. 60 60
      WiscPlan-SourceCode/source-code-photon-linux/terma_kerma.cpp
  25. 117 117
      WiscPlan-SourceCode/source-code-photon-linux/util.cpp
  26. 69 69
      WiscPlanPhotonkV125/DownsampleScript/prepareCtSeries7-1-14.m
  27. 22 22
      WiscPlanPhotonkV125/matlab_frontend/CT2dens.m
  28. 17 17
      WiscPlanPhotonkV125/matlab_frontend/NLP_getFullDose.m
  29. 3 2
      WiscPlanPhotonkV125/matlab_frontend/NLP_optimizer_v3.m
  30. 294 294
      WiscPlanPhotonkV125/matlab_frontend/RDX/loadOptResults.m
  31. 266 266
      WiscPlanPhotonkV125/matlab_frontend/RDX/loadOptSettings.m
  32. 166 166
      WiscPlanPhotonkV125/matlab_frontend/dens2mstp.m
  33. 28 28
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/checkDictUse.m
  34. 159 159
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt2geometry.m
  35. 108 108
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_addmcdose.m
  36. 97 97
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_checkinput.m
  37. 21 21
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_create1dmesh.m
  38. 56 56
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_getPatientPosition.m
  39. 212 212
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_loadct.m
  40. 186 186
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_loadctlist.m
  41. 105 105
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_loadvoi.m
  42. 12 12
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_makevertical.m
  43. 50 50
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_mmdigit.m
  44. 17 17
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_nASCIIlines.m
  45. 18 18
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_restorevarformat.m
  46. 106 106
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_sortct.m
  47. 17 17
      WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_varfilter.m
  48. 42 42
      WiscPlanPhotonkV125/matlab_frontend/dvh.m
  49. 64 64
      WiscPlanPhotonkV125/matlab_frontend/dvhist.m
  50. 88 88
      WiscPlanPhotonkV125/matlab_frontend/get_beam_lets.m
  51. 20 6
      WiscPlanPhotonkV125/matlab_frontend/get_beamlets.m
  52. 14 14
      WiscPlanPhotonkV125/matlab_frontend/get_full_dose.m
  53. BIN
      WiscPlanPhotonkV125/matlab_frontend/goal_def_UI.fig
  54. 1 1
      WiscPlanPhotonkV125/matlab_frontend/goal_def_UI.m
  55. 483 483
      WiscPlanPhotonkV125/matlab_frontend/helicalDosecalcSetup5.m
  56. 523 523
      WiscPlanPhotonkV125/matlab_frontend/helicalDosecalcSetup6.m
  57. 527 527
      WiscPlanPhotonkV125/matlab_frontend/helicalDosecalcSetup7.m
  58. 4 4
      WiscPlanPhotonkV125/matlab_frontend/lab/RDXTPS.m
  59. 180 180
      WiscPlanPhotonkV125/matlab_frontend/lab/RDXTPS_geometry_setup_wizard_ASP.m
  60. 612 612
      WiscPlanPhotonkV125/matlab_frontend/lab/RDX_linlsqOptimization.m
  61. 226 226
      WiscPlanPhotonkV125/matlab_frontend/load2geometry.m
  62. 35 35
      WiscPlanPhotonkV125/matlab_frontend/merge_beamlets.m
  63. 38 38
      WiscPlanPhotonkV125/matlab_frontend/nrrd2ROI.m
  64. 54 54
      WiscPlanPhotonkV125/matlab_frontend/plotting/imagescX.m
  65. 44 44
      WiscPlanPhotonkV125/matlab_frontend/ryan/save_beamspec_batch.m
  66. 35 35
      WiscPlanPhotonkV125/matlab_frontend/ryan/save_geometry.m
  67. 102 102
      WiscPlanPhotonkV125/matlab_frontend/ryan/save_kernels.m
  68. 563 563
      WiscPlanPhotonkV125/matlab_frontend/ryan/singleRaytraceClean.cpp
  69. 13 13
      WiscPlanPhotonkV125/matlab_frontend/sum_dose.m
  70. 79 79
      WiscPlanPhotonkV125/matlab_frontend/superpix_group.m
  71. 482 482
      WiscPlanPhotonkV125/matlab_frontend/utilities/bwdistsc.m
  72. 78 78
      WiscPlanPhotonkV125/matlab_frontend/utilities/uifile.m
  73. 59 59
      data_perturbation/get_perturbed_image_beamlets_p1.m
  74. 20 20
      data_perturbation/get_perturbed_image_beamlets_p2.m
  75. 25 25
      kernels/KERNEL_125_keV/keVoutput/125keVfluence.txt
  76. 27 27
      kernels/KERNEL_125_keV/keVoutput/125keVmu_mu-en.txt
  77. 51 51
      kernels/KERNEL_125_keV/keVoutput/GenerateKernelFile125New.m
  78. 17 17
      optGoals/get_ROI_goals.m
  79. 57 57
      planEvaluation/Compare_optPlans.m
  80. 24 24
      planEvaluation/compare_RO_norm_DVH_colorwash.m
  81. 112 112
      planEvaluation/error_DVHs.m
  82. 67 67
      planEvaluation/plot_DVH.m
  83. 26 26
      readEDKoutputMuNew.m
  84. 27 27
      readEDKoutputPriFracNew.m
  85. 61 61
      src-chtc/calc_deff.cpp
  86. 360 360
      src-chtc/calc_dose.cpp
  87. 396 396
      src-chtc/convolutionCondor.cpp
  88. 138 138
      src-chtc/defs.h
  89. 122 122
      src-chtc/make_poly.cpp
  90. 12 12
      src-chtc/makefile
  91. 825 825
      src-chtc/parse_funcCondor.cpp
  92. 345 345
      src-chtc/raytrace.cpp
  93. 301 301
      src-chtc/terma_dose_masks.cpp
  94. 60 60
      src-chtc/terma_kerma.cpp
  95. 117 117
      src-chtc/util.cpp
  96. 14 14
      view_beamlet.m
  97. 272 272
      vol_prep.m

+ 10 - 10
.gitignore

@@ -1,10 +1,10 @@
-
-*.bin
-
-WiscPlanPhotonkV125/PD_HD_dicomPhantom/opt_output/
-
-WiscPlanPhotonkV125/PatientData/opt_input/
-
-*.img
-
-*.cmd
+
+*.bin
+
+WiscPlanPhotonkV125/PD_HD_dicomPhantom/opt_output/
+
+WiscPlanPhotonkV125/PatientData/opt_input/
+
+*.img
+
+*.cmd

+ 42 - 42
NLP_run_loop.m

@@ -1,42 +1,42 @@
-
-
-% Pat_path = 'F:\021_WiscPlan_data\Uulke_prostate_01';
-% path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_v13_m3_0e4.mat';
-% [D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
-
-Pat_path = 'F:\021_WiscPlan_data\Uulke_prostate_01';
-path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss0.mat';
-[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
-path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss1.mat';
-[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
-path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss2.mat';
-[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
-path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss3.mat';
-[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
-path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss4.mat';
-[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
-path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss5.mat';
-[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
-
-
-
-NLP_path = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\';
-NLP_file = 'NLP_result_OG2_4_boost_v22_sss0.mat';
-NLP_getFullDose(NLP_path, NLP_file)
-NLP_file = 'NLP_result_OG2_4_boost_v22_sss1.mat';
-NLP_getFullDose(NLP_path, NLP_file)
-NLP_file = 'NLP_result_OG2_4_boost_v22_sss2.mat';
-NLP_getFullDose(NLP_path, NLP_file)
-NLP_file = 'NLP_result_OG2_4_boost_v22_sss3.mat';
-NLP_getFullDose(NLP_path, NLP_file)
-NLP_file = 'NLP_result_OG2_4_boost_v22_sss4.mat';
-NLP_getFullDose(NLP_path, NLP_file)
-NLP_file = 'NLP_result_OG2_4_boost_v22_sss5.mat';
-NLP_getFullDose(NLP_path, NLP_file)
-
-
-
-
-
-
-
+
+
+% Pat_path = 'F:\021_WiscPlan_data\Uulke_prostate_01';
+% path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_v13_m3_0e4.mat';
+% [D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
+
+Pat_path = 'F:\021_WiscPlan_data\Uulke_prostate_01';
+path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss0.mat';
+[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
+path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss1.mat';
+[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
+path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss2.mat';
+[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
+path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss3.mat';
+[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
+path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss4.mat';
+[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
+path2goal = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\OG2_4_boost_v22_sss5.mat';
+[D_full, w_fin, Geometry, optGoal] = NLP_optimizer_v3(Pat_path, path2goal);
+
+
+
+NLP_path = 'F:\021_WiscPlan_data\Uulke_prostate_01\matlab_files\';
+NLP_file = 'NLP_result_OG2_4_boost_v22_sss0.mat';
+NLP_getFullDose(NLP_path, NLP_file)
+NLP_file = 'NLP_result_OG2_4_boost_v22_sss1.mat';
+NLP_getFullDose(NLP_path, NLP_file)
+NLP_file = 'NLP_result_OG2_4_boost_v22_sss2.mat';
+NLP_getFullDose(NLP_path, NLP_file)
+NLP_file = 'NLP_result_OG2_4_boost_v22_sss3.mat';
+NLP_getFullDose(NLP_path, NLP_file)
+NLP_file = 'NLP_result_OG2_4_boost_v22_sss4.mat';
+NLP_getFullDose(NLP_path, NLP_file)
+NLP_file = 'NLP_result_OG2_4_boost_v22_sss5.mat';
+NLP_getFullDose(NLP_path, NLP_file)
+
+
+
+
+
+
+

+ 726 - 726
ROI_goals_prep.m

@@ -1,726 +1,726 @@
-
-
-
-function ROI_goals_prep
-% this function creates and saves dose painting plans based on Geometry
-% and beamlets created in WiscPlan. Manually change hardcode of whatever
-% you want the plan to be!
-
-%% ---=== INPUT PARAMS ===---
-patient = 'medivation_01';
-outName = 'ROI_goals_simple';
-
-switch patient
-    case 'medivation_01'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\QTBI-clinical\Medivation\0391811\T2\';
-        paths.CT_in = ['CT_crop_ 1'];
-        paths.target_bin_in  = ['CTV_crop_ 1'];
-        paths.target_fzy_in  = ['CTV_crop_ 1'];
-        paths.body_bin_in    = ['CTV_crop_ 1'];
-        paths.wiscplan = 'F:\21_WiscPlan_data\Medivation_0391811_crop1_2';
-        
-        
-    case 'avastin_009'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
-        paths.CT_in = ['AV009b_1ct_resized'];
-        paths.target_bin_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\AV009b_seg_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009';
-    case 'avastin_009_dumb'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
-        paths.CT_in = ['AV009b_1ct_resized'];
-        paths.target_bin_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\AV009b_seg_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009';
-    case 'avastin_009_DP'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
-        paths.CT_in = ['AV009b_1ct_resized'];
-        paths.target_bin_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\AV009b_seg_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009';
-    case 'gbm_005'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
-        paths.CT_in = ['FET_FGL005_B1_CT2FET'];
-        paths.target_bin_in  = ['\RODP_files\FET_FGL005_B1_thr2_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\FET_FGL005_B1_thr2_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\FET_FGL005_B1_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam';
-    case 'gbm_005_dumb'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
-        paths.CT_in = ['FET_FGL005_B1_CT2FET'];
-        paths.target_bin_in  = ['\RODP_files\FET_FGL005_B1_thr2_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\FET_FGL005_B1_thr2_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\FET_FGL005_B1_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam_2';
-    case 'gbm_005_DP'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
-        paths.CT_in = ['FET_FGL005_B1_CT2FET'];
-        paths.target_bin_in  = ['\RODP_files\FET_FGL005_B1_thr2_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\FET_FGL005_B1_thr2_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\FET_FGL005_B1_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam';
-    case 'gbm_015'
-        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL015\B1\Processed';
-        paths.CT_in = ['FET_FGL015_B1_CT2FET'];
-        paths.target_bin_in  = ['\RODP_files\FET_FGL015_B1_thr2_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\FET_FGL015_B1_thr2_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\FET_FGL015_B1_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_015_64beam';
-    case 'gbm_022'
-        patname = 'FET_FGL022';
-        paths.in = ['\\Mpufs5\data_wnx1\_Data\Glioma_aus\' patname '\B1\Processed'];
-        paths.CT_in = [patname '_B1_CT2FET'];
-        paths.target_bin_in  = ['\RODP_files\' patname '_B1_thr2_binPTV'];
-        paths.target_fzy_in  = ['\RODP_files\' patname '_B1_thr2_fuzzyCTV'];
-        paths.body_bin_in    = ['\RODP_files\' patname '_B1_head_crop_bin'];
-        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_022';
-    otherwise
-        error('invalid case')
-end
-
-%% ---=== LOAD DATA ===---
-
-% load Geometry
-load([paths.wiscplan '\matlab_files\Geometry.mat']);
-fprintf('Loaded geometry ')
-
-% load beamlets
-[beamlets, beamlets_joined, numBeamlet, numBeam, beam_i_list] = get_beam_lets(Geometry, paths.wiscplan);
-fprintf('and beamlets.\n')
-
-%% ---=== GET OPTGOAL ===---
-switch patient
-    case 'medivation_01'
-        ROI_goals.optGoal = make_ROI_goals_medivation_011(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_medivation_011(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-        
-    case 'avastin_009'
-        ROI_goals.optGoal = make_ROI_goals_avastin_009(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_avastin_009(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-    case 'avastin_009_dumb'
-        ROI_goals.optGoal = make_ROI_goals_avastin_009_dumb(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_avastin_009_dumb(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-    case 'avastin_009_DP'
-        ROI_goals.optGoal = make_ROI_goals_avastin_009(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_avastin_009(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-    case 'gbm_005'
-        ROI_goals.optGoal = make_ROI_goals_gbm_005(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_gbm_005(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-    case 'gbm_005_dumb'
-        ROI_goals.optGoal = make_ROI_goals_gbm_005_dumb(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_gbm_005_dumb(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-    case 'gbm_005_DP'
-        ROI_goals.optGoal = make_ROI_goals_gbm_005_DP(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_gbm_005_DP(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume    
-    case 'gbm_015'
-        ROI_goals.optGoal = make_ROI_goals_gbm_015(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_gbm_015(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-        
-    case 'gbm_022'
-        ROI_goals.optGoal = make_ROI_goals_gbm_022(Geometry, beamlets);
-        ROI_goals.optGoal_beam = make_ROI_goals_gbm_022(Geometry, beamlets_joined);
-        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
-        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
-    otherwise
-        error('invalid case')
-end
-
-
-%% ---=== SAVE OPTGOAL ===---
-fprintf('Writing ROI_goals...')
-save([paths.in '\RODP_files\' outName '.mat'], 'ROI_goals')
-fprintf(' done!\n')
-end
-
-function optGoal = make_ROI_goals_medivation_011(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'PTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = 60;
-    goal_1.function = 'min_sq';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target   = ones(numel(ROI_idx), 1) * 60;
-%     goal_1.target   = minDose(ROI_idx);
-    goal_1.opt_weight = 77 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'PTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = 63;
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target   = ones(numel(ROI_idx), 1) * 63;
-%     goal_2.target   = maxDose(ROI_idx);
-    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'ring_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 3}.name;
-    ROI_idx = Geometry.ROIS{1, 3}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target   = ones(numel(ROI_idx), 1) * 20;
-    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-
-
-function optGoal = make_ROI_goals_avastin_009_DP(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
-    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_maxDose.nrrd']);
-    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_minDose.nrrd']);
-    minDose = double(minDose);
-    maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'CTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = minDose(ROI_idx);
-    goal_1.function = 'min_sq';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target_alpha = 1;
-    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
-    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'CTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = maxDose(ROI_idx);
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target_alpha = 1;
-    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
-    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max_sq';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target_alpha = 1;
-    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
-    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-function optGoal = make_ROI_goals_avastin_009_dumb(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
-    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_maxDose.nrrd']);
-    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_minDose.nrrd']);
-    minDose = double(minDose);
-    maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'CTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = 60;
-    goal_1.function = 'min_sq';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-%     goal_1.target_alpha = 1;
-    goal_1.target   = ones(numel(ROI_idx), 1) * 60; % minDose(ROI_idx);
-    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'CTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = 63;
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-%     goal_2.target_alpha = 1;
-    goal_2.target   = ones(numel(ROI_idx), 1) * 63; % maxDose(ROI_idx);
-    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target_alpha = 1;
-    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
-    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-function optGoal = make_ROI_goals_avastin_009(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
-    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_maxDose.nrrd']);
-    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_minDose.nrrd']);
-    minDose = double(minDose);
-    maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'CTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = minDose(ROI_idx);
-    goal_1.function = 'min_sq';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target_alpha = 1;
-    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
-    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'CTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = maxDose(ROI_idx);
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target_alpha = 1;
-    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
-    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max_sq';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target_alpha = 1;
-    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
-    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-function optGoal = make_ROI_goals_gbm_005(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
-    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_minDose.nrrd']);
-    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_maxDose.nrrd']);
-    minDose = double(minDose);
-    maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'CTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = minDose(ROI_idx);
-    goal_1.function = 'min_sq';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target_alpha = 1;
-    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
-    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'CTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = maxDose(ROI_idx);
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target_alpha = 1;
-    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
-    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target_alpha = 1;
-    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
-    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-function optGoal = make_ROI_goals_gbm_005_dumb(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
-%     [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_minDose.nrrd']);
-%     [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_maxDose.nrrd']);
-%     minDose = double(minDose);
-%     maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'PTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = 60;
-    goal_1.function = 'min_sq';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target   = ones(numel(ROI_idx), 1) * 60;
-%     goal_1.target   = minDose(ROI_idx);
-    goal_1.opt_weight = 77 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'PTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = 63;
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target   = ones(numel(ROI_idx), 1) * 63;
-%     goal_2.target   = maxDose(ROI_idx);
-    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target   = ones(numel(ROI_idx), 1) * 20;
-    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-function optGoal = make_ROI_goals_gbm_005_DP(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
-    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_minDose.nrrd']);
-    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_maxDose.nrrd']);
-    minDose = double(minDose);
-    maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'CTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = minDose(ROI_idx);
-    goal_1.function = 'min_sq';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target_alpha = 1;
-    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
-    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'CTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = maxDose(ROI_idx);
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target_alpha = 1;
-    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
-    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target_alpha = 1;
-    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
-%     goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
-    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-function optGoal = make_ROI_goals_gbm_015(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL015\B1\Processed';
-    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL015_B1_thr2_DP_minDose.nrrd']);
-    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL015_B1_thr2_DP_maxDose.nrrd']);
-    minDose = double(minDose);
-    maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'CTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = minDose(ROI_idx);
-    goal_1.function = 'min';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
-    goal_1.opt_weight = 40 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'CTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = maxDose(ROI_idx);
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
-    goal_2.opt_weight = 2 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
-    goal_3.opt_weight = 7 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-function optGoal = make_ROI_goals_gbm_022(Geometry, beamlets, minDose, maxDose)
-    optGoal={};
-    
-    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL022\B1\Processed';
-    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL022_B1_thr2_DP_minDose.nrrd']);
-    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL022_B1_thr2_DP_maxDose.nrrd']);
-    minDose = double(minDose);
-    maxDose = double(maxDose);
-    
-    % -- START DEFINITION OF GOAL --
-    goal_1.name = 'CTV_min';
-    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_1.ROI_idx = ROI_idx;
-    goal_1.imgDim = size(Geometry.data);
-    goal_1.D_final = minDose(ROI_idx);
-    goal_1.function = 'min';
-    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
-    goal_1.opt_weight = 40 / numel(ROI_idx); % normalize to volume of target area
-    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_1;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_2.name = 'CTV_max';
-    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
-    ROI_idx = Geometry.ROIS{1, 1}.ind;
-    goal_2.ROI_idx = ROI_idx;
-    goal_2.imgDim = size(Geometry.data);
-    goal_2.D_final = maxDose(ROI_idx);
-    goal_2.function = 'max_sq';
-    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
-    goal_2.opt_weight = 2 / numel(ROI_idx); % normalize to volume of target area
-    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_2;
-    % -- END DEFINITION OF GOAL --
-    
-    % -- START DEFINITION OF GOAL --
-    goal_3.name = 'head_max';
-    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
-    ROI_idx = Geometry.ROIS{1, 2}.ind;
-    goal_3.ROI_idx = ROI_idx;
-    goal_3.imgDim = size(Geometry.data);
-    goal_3.D_final = 20;
-    goal_3.function = 'max';
-    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
-    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
-    goal_3.opt_weight = 7 / numel(ROI_idx); % normalize to volume of target area
-    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
-    % assign target
-    optGoal{end+1}=goal_3;
-    % -- END DEFINITION OF GOAL --
-   
-end
-
-function beamlets = get_beamlets(beamlet_cell_array, numVox);
-    wbar1 = waitbar(0, 'Creating beamlet array');
-    numBeam = size(beamlet_cell_array,2);
-    batchSize=100;
-    beamlets = sparse(0, 0);
-    for beam_i=1:numBeam
-        % for each beam define how much dose it delivers on each voxel
-        idx=beamlet_cell_array{1, beam_i}.non_zero_indices;
-
-        % break the beamlets into multiple batches
-        if rem(beam_i, batchSize)==1;
-            beamlet_batch = sparse(numVox, batchSize);
-            beam_i_temp=1;
-        end
-
-        beamlet_batch(idx, beam_i_temp) = 1000*beamlet_cell_array{1, beam_i}.non_zero_values;
-        waitbar(beam_i/numBeam, wbar1, ['Adding beamlet array: #', num2str(beam_i)])
-
-        % add the batch to full set when filled
-        if rem(beam_i, batchSize)==0;
-            beamlets =[beamlets, beamlet_batch];
-        end
-        % crop and add the batch to full set when completed
-        if beam_i==numBeam;
-            beamlet_batch=beamlet_batch(:, 1:beam_i_temp);
-            beamlets =[beamlets, beamlet_batch];
-        end
-        beam_i_temp=beam_i_temp+1;
-
-    end
-    close(wbar1)
-
-end
-
+
+
+
+function ROI_goals_prep
+% this function creates and saves dose painting plans based on Geometry
+% and beamlets created in WiscPlan. Manually change hardcode of whatever
+% you want the plan to be!
+
+%% ---=== INPUT PARAMS ===---
+patient = 'medivation_01';
+outName = 'ROI_goals_simple';
+
+switch patient
+    case 'medivation_01'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\QTBI-clinical\Medivation\0391811\T2\';
+        paths.CT_in = ['CT_crop_ 1'];
+        paths.target_bin_in  = ['CTV_crop_ 1'];
+        paths.target_fzy_in  = ['CTV_crop_ 1'];
+        paths.body_bin_in    = ['CTV_crop_ 1'];
+        paths.wiscplan = 'F:\21_WiscPlan_data\Medivation_0391811_crop1_2';
+        
+        
+    case 'avastin_009'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
+        paths.CT_in = ['AV009b_1ct_resized'];
+        paths.target_bin_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\AV009b_seg_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009';
+    case 'avastin_009_dumb'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
+        paths.CT_in = ['AV009b_1ct_resized'];
+        paths.target_bin_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\AV009b_seg_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009';
+    case 'avastin_009_DP'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
+        paths.CT_in = ['AV009b_1ct_resized'];
+        paths.target_bin_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\AV009b_flt_seg_thr2_imclose_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\AV009b_seg_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009';
+    case 'gbm_005'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
+        paths.CT_in = ['FET_FGL005_B1_CT2FET'];
+        paths.target_bin_in  = ['\RODP_files\FET_FGL005_B1_thr2_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\FET_FGL005_B1_thr2_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\FET_FGL005_B1_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam';
+    case 'gbm_005_dumb'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
+        paths.CT_in = ['FET_FGL005_B1_CT2FET'];
+        paths.target_bin_in  = ['\RODP_files\FET_FGL005_B1_thr2_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\FET_FGL005_B1_thr2_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\FET_FGL005_B1_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam_2';
+    case 'gbm_005_DP'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
+        paths.CT_in = ['FET_FGL005_B1_CT2FET'];
+        paths.target_bin_in  = ['\RODP_files\FET_FGL005_B1_thr2_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\FET_FGL005_B1_thr2_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\FET_FGL005_B1_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam';
+    case 'gbm_015'
+        paths.in = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL015\B1\Processed';
+        paths.CT_in = ['FET_FGL015_B1_CT2FET'];
+        paths.target_bin_in  = ['\RODP_files\FET_FGL015_B1_thr2_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\FET_FGL015_B1_thr2_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\FET_FGL015_B1_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_015_64beam';
+    case 'gbm_022'
+        patname = 'FET_FGL022';
+        paths.in = ['\\Mpufs5\data_wnx1\_Data\Glioma_aus\' patname '\B1\Processed'];
+        paths.CT_in = [patname '_B1_CT2FET'];
+        paths.target_bin_in  = ['\RODP_files\' patname '_B1_thr2_binPTV'];
+        paths.target_fzy_in  = ['\RODP_files\' patname '_B1_thr2_fuzzyCTV'];
+        paths.body_bin_in    = ['\RODP_files\' patname '_B1_head_crop_bin'];
+        paths.wiscplan = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_022';
+    otherwise
+        error('invalid case')
+end
+
+%% ---=== LOAD DATA ===---
+
+% load Geometry
+load([paths.wiscplan '\matlab_files\Geometry.mat']);
+fprintf('Loaded geometry ')
+
+% load beamlets
+[beamlets, beamlets_joined, numBeamlet, numBeam, beam_i_list] = get_beam_lets(Geometry, paths.wiscplan);
+fprintf('and beamlets.\n')
+
+%% ---=== GET OPTGOAL ===---
+switch patient
+    case 'medivation_01'
+        ROI_goals.optGoal = make_ROI_goals_medivation_011(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_medivation_011(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+        
+    case 'avastin_009'
+        ROI_goals.optGoal = make_ROI_goals_avastin_009(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_avastin_009(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+    case 'avastin_009_dumb'
+        ROI_goals.optGoal = make_ROI_goals_avastin_009_dumb(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_avastin_009_dumb(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+    case 'avastin_009_DP'
+        ROI_goals.optGoal = make_ROI_goals_avastin_009(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_avastin_009(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+    case 'gbm_005'
+        ROI_goals.optGoal = make_ROI_goals_gbm_005(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_gbm_005(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+    case 'gbm_005_dumb'
+        ROI_goals.optGoal = make_ROI_goals_gbm_005_dumb(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_gbm_005_dumb(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+    case 'gbm_005_DP'
+        ROI_goals.optGoal = make_ROI_goals_gbm_005_DP(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_gbm_005_DP(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume    
+    case 'gbm_015'
+        ROI_goals.optGoal = make_ROI_goals_gbm_015(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_gbm_015(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+        
+    case 'gbm_022'
+        ROI_goals.optGoal = make_ROI_goals_gbm_022(Geometry, beamlets);
+        ROI_goals.optGoal_beam = make_ROI_goals_gbm_022(Geometry, beamlets_joined);
+        ROI_goals.optGoal_idx=[1,3]; % indeces of volumes you want on histogram
+        ROI_goals.targetMinMax_idx=[1,2]; % indeces of limits for min/max target volume
+    otherwise
+        error('invalid case')
+end
+
+
+%% ---=== SAVE OPTGOAL ===---
+fprintf('Writing ROI_goals...')
+save([paths.in '\RODP_files\' outName '.mat'], 'ROI_goals')
+fprintf(' done!\n')
+end
+
+function optGoal = make_ROI_goals_medivation_011(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'PTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = 60;
+    goal_1.function = 'min_sq';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target   = ones(numel(ROI_idx), 1) * 60;
+%     goal_1.target   = minDose(ROI_idx);
+    goal_1.opt_weight = 77 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'PTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = 63;
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target   = ones(numel(ROI_idx), 1) * 63;
+%     goal_2.target   = maxDose(ROI_idx);
+    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'ring_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 3}.name;
+    ROI_idx = Geometry.ROIS{1, 3}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target   = ones(numel(ROI_idx), 1) * 20;
+    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+
+
+function optGoal = make_ROI_goals_avastin_009_DP(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
+    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_maxDose.nrrd']);
+    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_minDose.nrrd']);
+    minDose = double(minDose);
+    maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'CTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = minDose(ROI_idx);
+    goal_1.function = 'min_sq';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target_alpha = 1;
+    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
+    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'CTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = maxDose(ROI_idx);
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target_alpha = 1;
+    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
+    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max_sq';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target_alpha = 1;
+    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
+    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+function optGoal = make_ROI_goals_avastin_009_dumb(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
+    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_maxDose.nrrd']);
+    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_minDose.nrrd']);
+    minDose = double(minDose);
+    maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'CTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = 60;
+    goal_1.function = 'min_sq';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+%     goal_1.target_alpha = 1;
+    goal_1.target   = ones(numel(ROI_idx), 1) * 60; % minDose(ROI_idx);
+    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'CTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = 63;
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+%     goal_2.target_alpha = 1;
+    goal_2.target   = ones(numel(ROI_idx), 1) * 63; % maxDose(ROI_idx);
+    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target_alpha = 1;
+    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
+    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+function optGoal = make_ROI_goals_avastin_009(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Avastin\AV009\PF_RODP_analysis';
+    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_maxDose.nrrd']);
+    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\AV009b_flt_seg_thr3_imclose_DP_minDose.nrrd']);
+    minDose = double(minDose);
+    maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'CTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = minDose(ROI_idx);
+    goal_1.function = 'min_sq';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target_alpha = 1;
+    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
+    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'CTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = maxDose(ROI_idx);
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target_alpha = 1;
+    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
+    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max_sq';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target_alpha = 1;
+    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
+    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+function optGoal = make_ROI_goals_gbm_005(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
+    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_minDose.nrrd']);
+    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_maxDose.nrrd']);
+    minDose = double(minDose);
+    maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'CTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = minDose(ROI_idx);
+    goal_1.function = 'min_sq';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target_alpha = 1;
+    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
+    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'CTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = maxDose(ROI_idx);
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target_alpha = 1;
+    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
+    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target_alpha = 1;
+    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
+    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+function optGoal = make_ROI_goals_gbm_005_dumb(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
+%     [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_minDose.nrrd']);
+%     [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_maxDose.nrrd']);
+%     minDose = double(minDose);
+%     maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'PTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = 60;
+    goal_1.function = 'min_sq';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target   = ones(numel(ROI_idx), 1) * 60;
+%     goal_1.target   = minDose(ROI_idx);
+    goal_1.opt_weight = 77 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'PTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = 63;
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target   = ones(numel(ROI_idx), 1) * 63;
+%     goal_2.target   = maxDose(ROI_idx);
+    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target   = ones(numel(ROI_idx), 1) * 20;
+    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+function optGoal = make_ROI_goals_gbm_005_DP(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed';
+    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_minDose.nrrd']);
+    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL005_B1_seg_thr2.0_DP_maxDose.nrrd']);
+    minDose = double(minDose);
+    maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'CTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = minDose(ROI_idx);
+    goal_1.function = 'min_sq';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target_alpha = 1;
+    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
+    goal_1.opt_weight = 70 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'CTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = maxDose(ROI_idx);
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target_alpha = 1;
+    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
+    goal_2.opt_weight = 1 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target_alpha = 1;
+    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
+%     goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
+    goal_3.opt_weight = 5 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+function optGoal = make_ROI_goals_gbm_015(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL015\B1\Processed';
+    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL015_B1_thr2_DP_minDose.nrrd']);
+    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL015_B1_thr2_DP_maxDose.nrrd']);
+    minDose = double(minDose);
+    maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'CTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = minDose(ROI_idx);
+    goal_1.function = 'min';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
+    goal_1.opt_weight = 40 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'CTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = maxDose(ROI_idx);
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
+    goal_2.opt_weight = 2 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
+    goal_3.opt_weight = 7 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+function optGoal = make_ROI_goals_gbm_022(Geometry, beamlets, minDose, maxDose)
+    optGoal={};
+    
+    DP_dir = '\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL022\B1\Processed';
+    [minDose, minDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL022_B1_thr2_DP_minDose.nrrd']);
+    [maxDose, maxDose_meta] = nrrdread([DP_dir '\RODP_files\FET_FGL022_B1_thr2_DP_maxDose.nrrd']);
+    minDose = double(minDose);
+    maxDose = double(maxDose);
+    
+    % -- START DEFINITION OF GOAL --
+    goal_1.name = 'CTV_min';
+    goal_1.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_1.ROI_idx = ROI_idx;
+    goal_1.imgDim = size(Geometry.data);
+    goal_1.D_final = minDose(ROI_idx);
+    goal_1.function = 'min';
+    goal_1.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_1.target   = minDose(ROI_idx); % minDose(ROI_idx);
+    goal_1.opt_weight = 40 / numel(ROI_idx); % normalize to volume of target area
+    goal_1.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_1;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_2.name = 'CTV_max';
+    goal_2.ROI_name = Geometry.ROIS{1, 1}.name;
+    ROI_idx = Geometry.ROIS{1, 1}.ind;
+    goal_2.ROI_idx = ROI_idx;
+    goal_2.imgDim = size(Geometry.data);
+    goal_2.D_final = maxDose(ROI_idx);
+    goal_2.function = 'max_sq';
+    goal_2.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_2.target   = maxDose(ROI_idx); % maxDose(ROI_idx);
+    goal_2.opt_weight = 2 / numel(ROI_idx); % normalize to volume of target area
+    goal_2.dvh_col = [0.9, 0.2, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_2;
+    % -- END DEFINITION OF GOAL --
+    
+    % -- START DEFINITION OF GOAL --
+    goal_3.name = 'head_max';
+    goal_3.ROI_name = Geometry.ROIS{1, 2}.name;
+    ROI_idx = Geometry.ROIS{1, 2}.ind;
+    goal_3.ROI_idx = ROI_idx;
+    goal_3.imgDim = size(Geometry.data);
+    goal_3.D_final = 20;
+    goal_3.function = 'max';
+    goal_3.beamlets_pruned = beamlets(ROI_idx, :);
+    goal_3.target   = ones(numel(ROI_idx), 1) * goal_3.D_final;
+    goal_3.opt_weight = 7 / numel(ROI_idx); % normalize to volume of target area
+    goal_3.dvh_col = [0.2, 0.9, 0.2]; % color of the final DVH plot
+    % assign target
+    optGoal{end+1}=goal_3;
+    % -- END DEFINITION OF GOAL --
+   
+end
+
+function beamlets = get_beamlets(beamlet_cell_array, numVox);
+    wbar1 = waitbar(0, 'Creating beamlet array');
+    numBeam = size(beamlet_cell_array,2);
+    batchSize=100;
+    beamlets = sparse(0, 0);
+    for beam_i=1:numBeam
+        % for each beam define how much dose it delivers on each voxel
+        idx=beamlet_cell_array{1, beam_i}.non_zero_indices;
+
+        % break the beamlets into multiple batches
+        if rem(beam_i, batchSize)==1;
+            beamlet_batch = sparse(numVox, batchSize);
+            beam_i_temp=1;
+        end
+
+        beamlet_batch(idx, beam_i_temp) = 1000*beamlet_cell_array{1, beam_i}.non_zero_values;
+        waitbar(beam_i/numBeam, wbar1, ['Adding beamlet array: #', num2str(beam_i)])
+
+        % add the batch to full set when filled
+        if rem(beam_i, batchSize)==0;
+            beamlets =[beamlets, beamlet_batch];
+        end
+        % crop and add the batch to full set when completed
+        if beam_i==numBeam;
+            beamlet_batch=beamlet_batch(:, 1:beam_i_temp);
+            beamlets =[beamlets, beamlet_batch];
+        end
+        beam_i_temp=beam_i_temp+1;
+
+    end
+    close(wbar1)
+
+end
+

+ 61 - 61
WiscPlan-SourceCode/Source-code-photon-windows/calc_deff.cpp

@@ -1,61 +1,61 @@
-/* calc_deff.cpp */
-
-/* Calculates the effective depth of each voxel in the tumor mask. */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-//prototype for Siddon raytrace routine (point to point)
-int raytrace(FLOAT_GRID *,FLOAT_GRID *,POINT,POINT);
-
-int calc_deff(FLOAT_GRID *dens, FLOAT_GRID *deff, FLOAT_GRID *terma_mask, BEAM *bm)
-{
- int i, j, k;
-
- // points that will be used for raytrace operation
- POINT p1;
- POINT p2;  
-
- // Raytracing is only done for voxels that non-zero in the terma_mask.
-
- //initialize deff, with -1 signifying voxels of interest in the raytrace
- for (k=0;k<deff->z_count;k++)
-  for (j=0;j<deff->y_count;j++)
-   for (i=0;i<deff->x_count;i++)
-    // we only care about voxels for which the terma_mask is positive
-	if (GRID_VALUE(terma_mask,i,j,k) > 0)
-		GRID_VALUE(deff,i,j,k) = -1.0;
- 
-     // Set the x-ray origin to the the source location 
-     p1.x = bm->y_vec[0];
-     p1.y = bm->y_vec[1];
-     p1.z = bm->y_vec[2];
-
-     // calculate the radiological depth for all voxels in the terma_mask
-
-     for (k=0;k<deff->z_count;k++)
-      for (j=0;j<deff->y_count;j++)
-       for (i=0;i<deff->x_count;i++)
-	    if (GRID_VALUE(deff,i,j,k) == -1.0)
-		{
-	       // The start location is the center of the voxel at (i,j,k).
-	       // Since raytrace works with voxel sides rather than centers,
-	       // need to shift the input by half a voxel in the negative 
-	       // direction for each voxel dimension.
-
-	       p2.x = deff->start.x + ((float) i)*deff->inc.x;
-	       p2.y = deff->start.y + ((float) j)*deff->inc.y;
-           p2.z = deff->start.z + ((float) k)*deff->inc.z;
-
-		   // extend the ray by a factor of 10 to include more voxels in the raytrace
-		   p2.x = p1.x + (p2.x-p1.x)*(float)10.0;
-		   p2.y = p1.y + (p2.y-p1.y)*(float)10.0;
-		   p2.z = p1.z + (p2.z-p1.z)*(float)10.0;
-
-	       // do the raytrace, filling in voxels that are passed on the way
-	       raytrace(dens,deff,p1,p2);
-		} 
-
- return(SUCCESS);
-}
+/* calc_deff.cpp */
+
+/* Calculates the effective depth of each voxel in the tumor mask. */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+//prototype for Siddon raytrace routine (point to point)
+int raytrace(FLOAT_GRID *,FLOAT_GRID *,POINT,POINT);
+
+int calc_deff(FLOAT_GRID *dens, FLOAT_GRID *deff, FLOAT_GRID *terma_mask, BEAM *bm)
+{
+ int i, j, k;
+
+ // points that will be used for raytrace operation
+ POINT p1;
+ POINT p2;  
+
+ // Raytracing is only done for voxels that non-zero in the terma_mask.
+
+ //initialize deff, with -1 signifying voxels of interest in the raytrace
+ for (k=0;k<deff->z_count;k++)
+  for (j=0;j<deff->y_count;j++)
+   for (i=0;i<deff->x_count;i++)
+    // we only care about voxels for which the terma_mask is positive
+	if (GRID_VALUE(terma_mask,i,j,k) > 0)
+		GRID_VALUE(deff,i,j,k) = -1.0;
+ 
+     // Set the x-ray origin to the the source location 
+     p1.x = bm->y_vec[0];
+     p1.y = bm->y_vec[1];
+     p1.z = bm->y_vec[2];
+
+     // calculate the radiological depth for all voxels in the terma_mask
+
+     for (k=0;k<deff->z_count;k++)
+      for (j=0;j<deff->y_count;j++)
+       for (i=0;i<deff->x_count;i++)
+	    if (GRID_VALUE(deff,i,j,k) == -1.0)
+		{
+	       // The start location is the center of the voxel at (i,j,k).
+	       // Since raytrace works with voxel sides rather than centers,
+	       // need to shift the input by half a voxel in the negative 
+	       // direction for each voxel dimension.
+
+	       p2.x = deff->start.x + ((float) i)*deff->inc.x;
+	       p2.y = deff->start.y + ((float) j)*deff->inc.y;
+           p2.z = deff->start.z + ((float) k)*deff->inc.z;
+
+		   // extend the ray by a factor of 10 to include more voxels in the raytrace
+		   p2.x = p1.x + (p2.x-p1.x)*(float)10.0;
+		   p2.y = p1.y + (p2.y-p1.y)*(float)10.0;
+		   p2.z = p1.z + (p2.z-p1.z)*(float)10.0;
+
+	       // do the raytrace, filling in voxels that are passed on the way
+	       raytrace(dens,deff,p1,p2);
+		} 
+
+ return(SUCCESS);
+}

+ 362 - 362
WiscPlan-SourceCode/Source-code-photon-windows/calc_dose.cpp

@@ -1,362 +1,362 @@
-/* calc_dose.cpp */
-
-/* The dose at all voxels in the grid dose_mask is calculated using a convolution
-method that uses a polyenergetic kernel. Inhomogeneities are accounted for by kernel
-scaling, and an inverse square correction is applied after the convolution of the terma
-grid with the kernel, rather than being applied directly to the terma grid before
-the convolution. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <math.h>
-#include <string.h>
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int calc_dose(FLOAT_GRID *density, FLOAT_GRID *terma,FLOAT_GRID *dose, KERNEL *kern, 
-			  BEAM *bm, FLOAT_GRID *dose_mask)
-{
- int M, N, Q;  // dimensions of CT array
- int baseindex;
- float SAD;
- float length;
- float *ip, *jp, *kp;
- float dx, dy, dz;
- float delr;  // convolution step size
- float *x, *y, *z;  // vectors of CT coordinates
- float *phi, *theta, *sinphi, *cosphi, *sintheta, *costheta;
- float one;
- float rho;
-
- one = (float)1.0; 
-
- // copy CT dimensions and voxel sizes for shorter references later
- M = density->x_count;
- N = density->y_count;
- Q = density->z_count;
-
- dx = density->inc.x;
- dy = density->inc.y;
- dz = density->inc.z;
-
- // copy vectors describing the beam's eye view coordinate system as well
- ip = fvector(0,2);   // ip and jp span the beam's eye view
- jp = fvector(0,2);
- kp = fvector(0,2);   // beam direction
- 
- // create the unit vector describing the beam direction
- for (int j=0;j<3;j++) ip[j] = bm->ip[j];
- for (int j=0;j<3;j++) jp[j] = bm->jp[j];
- for (int j=0;j<3;j++) kp[j] = bm->kp[j];
-
- // vectors describing the location of each voxel
- x = fvector(0,M-1);
- y = fvector(0,N-1);
- z = fvector(0,Q-1);
-
- // lookup table for vectors in polar coordinates
- phi = fvector(0,NPHI-1);
- theta = fvector(0,NTHETA-1);
- sinphi = fvector(0,NPHI-1);
- cosphi = fvector(0,NPHI-1);
- sintheta = fvector(0,NTHETA-1);
- costheta = fvector(0,NTHETA-1);
-
- //kernel with fewer elements for faster calculation
- //see defs.h
- KERNEL smallkern;
- smallkern.radial_boundary = (float *)malloc(kern->nradii*sizeof(float));
- smallkern.angular_boundary = (float *)malloc(kern->ntheta*sizeof(float));
- //small kernel dimensions
- smallkern.nradii = N_KERNEL_RADII;	 //same as original kernel
- smallkern.ntheta = NTHETA;	//must divide evenly into N_KERNEL_ANGLES
-
- SAD = bm->SAD;
- 
- for (int i=0;i<N_KERNEL_CATEGORIES;i++)
-  if ( (smallkern.matrix[i] =
-   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
-	return(FAILURE);
-   }
- 
- if ( (smallkern.total_matrix =
-   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for total matrix\n");
-	return(FAILURE);
-   }
-  
- //set up boundaries
- for (int i=0;i<smallkern.ntheta;i++)
-  smallkern.angular_boundary[i]	= ( (float) i + 1) * (float)180.0/(float) smallkern.ntheta;
- for (int i=0;i<smallkern.nradii;i++)
-  smallkern.radial_boundary[i] = kern->radial_boundary[i];
-  
- //initialise 
- for (int i=0;i<smallkern.nradii;i++)
-	 for (int j=0;j<smallkern.ntheta;j++)
-	 {
-		 KERNEL_TOTAL_VALUE(&smallkern,i,j) = (float)0.0;
-		 for (int l=0;l<N_KERNEL_CATEGORIES;l++)
-			 KERNEL_VALUE(&smallkern,l,i,j) = (float)0.0;
-	 }
-
- //create kernel values
-   for (int i=0;i<smallkern.nradii;i++)
-	   for (int j=0;j<smallkern.ntheta;j++)
-	   {   
-		   //first angular index in original kernel for this element 
-		   baseindex = j*N_KERNEL_ANGLES/NTHETA;
-		   //for each category, sum values from original kernel 
-		   for (int l=0;l<N_KERNEL_CATEGORIES;l++)
-			   for (int k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
-				   KERNEL_VALUE(&smallkern,l,i,j) += KERNEL_VALUE(kern,l,i,baseindex+k);
-		   //and for total kernel
-		   for (int k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
-			   KERNEL_TOTAL_VALUE(&smallkern,i,j) += KERNEL_TOTAL_VALUE(kern,i,baseindex+k);
-	   }
- 
- //Make cumulative kernel (with radius)
- //this is what is used for the dose calculation 
- for (int p=0;p<smallkern.ntheta;p++)
-  for (int r=0;r<smallkern.nradii;r++)
-  { 
-   for (int i=0;i<N_KERNEL_CATEGORIES;i++)
-    if (r > 0)
-     KERNEL_VALUE(&smallkern,i,r,p)
-     = KERNEL_VALUE(&smallkern,i,r-1,p) + KERNEL_VALUE(&smallkern,i,r,p);
-   if (r > 0)
-    KERNEL_TOTAL_VALUE(&smallkern,r,p)
-    = KERNEL_TOTAL_VALUE(&smallkern,r-1,p) + KERNEL_TOTAL_VALUE(&smallkern,r,p);
-  }
-
-  // fill the coordinate vectors
- for (int i=0;i<M;i++) x[i] = density->start.x + (float)i*dx;
- for (int j=0;j<N;j++) y[j] = density->start.y + (float)j*dy;
- for (int k=0;k<Q;k++) z[k] = density->start.z + (float)k*dz;
-
- // fill in the polar coordinates vectors
- for (int q=0;q<NPHI;q++) 
- {
-	 phi[q] = ((float)q + (float)0.5)*(float)2.0*(float)PI/(float)NPHI;
-	 sinphi[q] = (float)sin(phi[q]);
-	 cosphi[q] = (float)cos(phi[q]);
- }
-
- // Theta is subtracted from PI is because direction of travel along kernel ray is actually opposite of 
- // direction along which energy is radiating, so need to use a source voxel direction that 
- // is reflected about horizontal.  This can be thought of as the kernel inversion line.
-
- for (int p=0;p<smallkern.ntheta;p++)
-  if (p == 0)
-  {
-   theta[p] = (float)0.5*smallkern.angular_boundary[0]*(float)PI/(float)180.0;
-   sintheta[p] = (float)sin((float)PI - theta[p]);
-   costheta[p] = (float)cos((float)PI - theta[p]);
-  }
-  else
-  {
-   theta[p] = (float)0.5*(smallkern.angular_boundary[p-1] + smallkern.angular_boundary[p])*(float)PI/(float)180.0;
-   sintheta[p] = (float)sin((float)PI - theta[p]);
-   costheta[p] = (float)cos((float)PI - theta[p]);
-  }
- 
- // store the sines and cosines in a lookup table
-
- // the step size for the convolution integration is the smallest voxel side length
- if (dx <= dy && dx <= dz)
-	 delr = (float)2.0*dx;
- else if (dy <= dx && dy <= dz)
-	 delr = (float)2.0*dy;
- else
-	 delr = (float)2.0*dz;
-
- //calculate dose at each point
- //done from deposition (catcher's) point of view
- #pragma omp parallel for
- for (int k=0;k<Q; k++)
-  for (int j=0;j<N; j++)
-   for (int i=0;i<M; i++)
-	if (GRID_VALUE(dose_mask,i,j,k) > 0)  // only calculate dose inside dose mask
-	{
-		int i, j, k, l;
-		int p, q, r;
-		float del_x, del_y, del_z;
-		float current_x, current_y, current_z;
-		float cumval, last_cumval;
-		int inter_i, inter_j, inter_k;
-		float inter_x, inter_y, inter_z;
-		float r_eff, delr_eff, inter_r_eff;
-		int r_index;
-		float t, u, v, f;
-		float kval;
-
-	// do the integral for the point in the ROI
-	for (p=0;p<smallkern.ntheta;p++) //polar
-	 for (q=0;q<NPHI;q++) //azimuthal
-	 {
-	  //initialise position of current voxel
-	  current_x = x[i];
-	  current_y = y[j];
-	  current_z = z[k];
-
-	  //initialise effective radius along kernel direction
-	  r_eff = 0.0;
-	  //initialise cumulative kernel value for this direction
-	  last_cumval = 0.0;
-
-      //Using reciprocity technique where dose at point A due to point B
-	  //is dose at point B due to point A 
-
-      //x ,y, z increments along ray
-	  del_x = delr*(ip[0]*cosphi[q]*sintheta[p] + jp[0]*sinphi[q]*sintheta[p]
-			      + kp[0]*costheta[p]);
-	  del_y = delr*(ip[1]*cosphi[q]*sintheta[p] + jp[1]*sinphi[q]*sintheta[p]
-			      + kp[1]*costheta[p]);
-	  del_z = delr*(ip[2]*cosphi[q]*sintheta[p] + jp[2]*sinphi[q]*sintheta[p]
-			      + kp[2]*costheta[p]);
-
-	  //initialise physical radius
-	  r = 0;
-	  do
-	  {
-	    //interaction point is at mid-point of curent increment
-	    inter_x = current_x + (float)0.5*del_x;
-	    inter_y = current_y + (float)0.5*del_y;
-	    inter_z = current_z + (float)0.5*del_z;
-
-	    //voxel containing interaction point
-	    inter_i = (int) ((inter_x - density->start.x)/dx);
-	    inter_j = (int) ((inter_y - density->start.y)/dy);
-	    inter_k = (int) ((inter_z - density->start.z)/dz);
-	   
-	   // stop the integral if interaction point is outside the dose calculation limits
-	   if (    (inter_i < 0) || (inter_i + 1 >= M)
-	        || (inter_j < 0) || (inter_j + 1 >= N)
-	   	    || (inter_k < 0) || (inter_k + 1 >= Q)
-			|| (GRID_VALUE(dose_mask,inter_i,inter_j,inter_k) <= 0.0))
-		  break;
-
-	   	// Position of the end of the increment.  Interaction point is at the
-	    // midpoint.
-        current_x += del_x;
-	    current_y += del_y;
-	    current_z += del_z;
-        
-        //effective distance increment
-        delr_eff = delr*GRID_VALUE(density,inter_i,inter_j,inter_k);
-		//effective radius of interaction point
-		inter_r_eff = r_eff + (float)0.5*delr_eff;
-	    r_eff += delr_eff;
-
-		// trilinear interpolation method of the terma contribution, f
-
-		// relative differences between the interaction point and the lower voxel bound
-		t = (inter_x - x[inter_i])/dx;
-		u = (inter_y - y[inter_j])/dy;
-		v = (inter_z - z[inter_k])/dz; 
-
-		f = GRID_VALUE(terma,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
-		  + GRID_VALUE(terma,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
-		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
-		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k+1)*t*u*v
-		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
-		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
-		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
-		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); 
-
-		/* 
-		// interpolate density at the interaction point
-		rho = GRID_VALUE(density,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
-		    + GRID_VALUE(density,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
-		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
-		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k+1)*t*u*v
-		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
-		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
-		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
-		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); */
-
-		// perform kernel lookup for r_eff, r_index is the kernel index of the first 
-		// bin boundary below the effective radius of the voxel
-		r_index = binSearch(smallkern.radial_boundary,inter_r_eff,smallkern.nradii);
-
-		// interpolate to obtain the effective cumulative kernel value
-		if (r_index == -1)  // radius is between zero and the first bin boundary
-		{
-			// fractional difference between inter_r_eff and the first bin boundary
-			t = inter_r_eff/smallkern.radial_boundary[0];
-			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,0,p);
-		}
-		else if (r_index >= smallkern.nradii-1)  // overshot the kernel bin boundaries
-		{
-			cumval = KERNEL_TOTAL_VALUE(&smallkern,smallkern.nradii-1,p);
-		}
-		else  // inter_r_eff is between the first upper bin boundary and the last
-		{
-			t = (inter_r_eff - smallkern.radial_boundary[r_index])
-				/(smallkern.radial_boundary[r_index + 1] - smallkern.radial_boundary[r_index]);
-			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,r_index,p)
-				       + t*KERNEL_TOTAL_VALUE(&smallkern,r_index+1,p);
-		}
-
-        kval = cumval - last_cumval;
-
-      	last_cumval = cumval;
-
-		// Kernel value to use is current increment in cumulative value
-        // Note that this is the fractional dose deposited at i,j,k due to
-        // terma in an effective increment (increment*density) along the kernel ray at the 
-		// interaction point. The value comes from the fractional dose deposited in an 
-		// effective increment along the ray	at i,j,k due to terma at the current 
-		// interaction point.
-
-	    //Increment dose value.
-	    //Note that to include the effect of density at i,j,k on ENERGY deposited at i,j,k, 
-	    //there should be a density term, but this cancels on conversion of energy to dose as indicated below
-	    // if (GRID_VALUE(terma,inter_i,inter_j,inter_k) > 0.001)
-	    GRID_VALUE(dose,i,j,k) += f*kval;
-
-	   r++;
-	  }
-	  while (r<10000);
-	 }	//p,q
- 
-      GRID_VALUE(dose,i,j,k)/= NPHI;
-    }
-
- //Inverse square correction to dose
- //This works better than applying the inverse square correction to terma
- //See Papanikolaou and Mackie 1993
- for (int k=0;k<Q;k++)
-  for (int j=0;j<N;j++)
-	for (int i=0;i<M;i++)
-   if (GRID_VALUE(dose,i,j,k) > 0.0)
-   {
-	   // squared difference between the source and the voxel
-	   length = (float)pow(x[i] - bm->y_vec[0],2.0f) + (float)pow(y[j] - bm->y_vec[1],2.0f) 
-		   + (float)pow(z[k] - bm->y_vec[2],2.0f);
-	   
-	   if (length > 0.0)
-	      GRID_VALUE(dose,i,j,k) *= SAD*SAD/length;
-   } 
-
-   // free vectors
-   free_fvector(ip,0,2);
-   free_fvector(jp,0,2);
-   free_fvector(kp,0,2);
-   free_fvector(x,0,M-1);
-   free_fvector(y,0,N-1);
-   free_fvector(z,0,Q-1);
-   
-   free(smallkern.angular_boundary);
-   free(smallkern.radial_boundary);
-   // free(poly_kernel.total_matrix);
-   for (int j=0;j<N_KERNEL_CATEGORIES;j++)
-	   free(smallkern.matrix[j]);
-
-   return(SUCCESS);
-}
+/* calc_dose.cpp */
+
+/* The dose at all voxels in the grid dose_mask is calculated using a convolution
+method that uses a polyenergetic kernel. Inhomogeneities are accounted for by kernel
+scaling, and an inverse square correction is applied after the convolution of the terma
+grid with the kernel, rather than being applied directly to the terma grid before
+the convolution. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <math.h>
+#include <string.h>
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int calc_dose(FLOAT_GRID *density, FLOAT_GRID *terma,FLOAT_GRID *dose, KERNEL *kern, 
+			  BEAM *bm, FLOAT_GRID *dose_mask)
+{
+ int M, N, Q;  // dimensions of CT array
+ int baseindex;
+ float SAD;
+ float length;
+ float *ip, *jp, *kp;
+ float dx, dy, dz;
+ float delr;  // convolution step size
+ float *x, *y, *z;  // vectors of CT coordinates
+ float *phi, *theta, *sinphi, *cosphi, *sintheta, *costheta;
+ float one;
+ float rho;
+
+ one = (float)1.0; 
+
+ // copy CT dimensions and voxel sizes for shorter references later
+ M = density->x_count;
+ N = density->y_count;
+ Q = density->z_count;
+
+ dx = density->inc.x;
+ dy = density->inc.y;
+ dz = density->inc.z;
+
+ // copy vectors describing the beam's eye view coordinate system as well
+ ip = fvector(0,2);   // ip and jp span the beam's eye view
+ jp = fvector(0,2);
+ kp = fvector(0,2);   // beam direction
+ 
+ // create the unit vector describing the beam direction
+ for (int j=0;j<3;j++) ip[j] = bm->ip[j];
+ for (int j=0;j<3;j++) jp[j] = bm->jp[j];
+ for (int j=0;j<3;j++) kp[j] = bm->kp[j];
+
+ // vectors describing the location of each voxel
+ x = fvector(0,M-1);
+ y = fvector(0,N-1);
+ z = fvector(0,Q-1);
+
+ // lookup table for vectors in polar coordinates
+ phi = fvector(0,NPHI-1);
+ theta = fvector(0,NTHETA-1);
+ sinphi = fvector(0,NPHI-1);
+ cosphi = fvector(0,NPHI-1);
+ sintheta = fvector(0,NTHETA-1);
+ costheta = fvector(0,NTHETA-1);
+
+ //kernel with fewer elements for faster calculation
+ //see defs.h
+ KERNEL smallkern;
+ smallkern.radial_boundary = (float *)malloc(kern->nradii*sizeof(float));
+ smallkern.angular_boundary = (float *)malloc(kern->ntheta*sizeof(float));
+ //small kernel dimensions
+ smallkern.nradii = N_KERNEL_RADII;	 //same as original kernel
+ smallkern.ntheta = NTHETA;	//must divide evenly into N_KERNEL_ANGLES
+
+ SAD = bm->SAD;
+ 
+ for (int i=0;i<N_KERNEL_CATEGORIES;i++)
+  if ( (smallkern.matrix[i] =
+   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
+	return(FAILURE);
+   }
+ 
+ if ( (smallkern.total_matrix =
+   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for total matrix\n");
+	return(FAILURE);
+   }
+  
+ //set up boundaries
+ for (int i=0;i<smallkern.ntheta;i++)
+  smallkern.angular_boundary[i]	= ( (float) i + 1) * (float)180.0/(float) smallkern.ntheta;
+ for (int i=0;i<smallkern.nradii;i++)
+  smallkern.radial_boundary[i] = kern->radial_boundary[i];
+  
+ //initialise 
+ for (int i=0;i<smallkern.nradii;i++)
+	 for (int j=0;j<smallkern.ntheta;j++)
+	 {
+		 KERNEL_TOTAL_VALUE(&smallkern,i,j) = (float)0.0;
+		 for (int l=0;l<N_KERNEL_CATEGORIES;l++)
+			 KERNEL_VALUE(&smallkern,l,i,j) = (float)0.0;
+	 }
+
+ //create kernel values
+   for (int i=0;i<smallkern.nradii;i++)
+	   for (int j=0;j<smallkern.ntheta;j++)
+	   {   
+		   //first angular index in original kernel for this element 
+		   baseindex = j*N_KERNEL_ANGLES/NTHETA;
+		   //for each category, sum values from original kernel 
+		   for (int l=0;l<N_KERNEL_CATEGORIES;l++)
+			   for (int k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
+				   KERNEL_VALUE(&smallkern,l,i,j) += KERNEL_VALUE(kern,l,i,baseindex+k);
+		   //and for total kernel
+		   for (int k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
+			   KERNEL_TOTAL_VALUE(&smallkern,i,j) += KERNEL_TOTAL_VALUE(kern,i,baseindex+k);
+	   }
+ 
+ //Make cumulative kernel (with radius)
+ //this is what is used for the dose calculation 
+ for (int p=0;p<smallkern.ntheta;p++)
+  for (int r=0;r<smallkern.nradii;r++)
+  { 
+   for (int i=0;i<N_KERNEL_CATEGORIES;i++)
+    if (r > 0)
+     KERNEL_VALUE(&smallkern,i,r,p)
+     = KERNEL_VALUE(&smallkern,i,r-1,p) + KERNEL_VALUE(&smallkern,i,r,p);
+   if (r > 0)
+    KERNEL_TOTAL_VALUE(&smallkern,r,p)
+    = KERNEL_TOTAL_VALUE(&smallkern,r-1,p) + KERNEL_TOTAL_VALUE(&smallkern,r,p);
+  }
+
+  // fill the coordinate vectors
+ for (int i=0;i<M;i++) x[i] = density->start.x + (float)i*dx;
+ for (int j=0;j<N;j++) y[j] = density->start.y + (float)j*dy;
+ for (int k=0;k<Q;k++) z[k] = density->start.z + (float)k*dz;
+
+ // fill in the polar coordinates vectors
+ for (int q=0;q<NPHI;q++) 
+ {
+	 phi[q] = ((float)q + (float)0.5)*(float)2.0*(float)PI/(float)NPHI;
+	 sinphi[q] = (float)sin(phi[q]);
+	 cosphi[q] = (float)cos(phi[q]);
+ }
+
+ // Theta is subtracted from PI is because direction of travel along kernel ray is actually opposite of 
+ // direction along which energy is radiating, so need to use a source voxel direction that 
+ // is reflected about horizontal.  This can be thought of as the kernel inversion line.
+
+ for (int p=0;p<smallkern.ntheta;p++)
+  if (p == 0)
+  {
+   theta[p] = (float)0.5*smallkern.angular_boundary[0]*(float)PI/(float)180.0;
+   sintheta[p] = (float)sin((float)PI - theta[p]);
+   costheta[p] = (float)cos((float)PI - theta[p]);
+  }
+  else
+  {
+   theta[p] = (float)0.5*(smallkern.angular_boundary[p-1] + smallkern.angular_boundary[p])*(float)PI/(float)180.0;
+   sintheta[p] = (float)sin((float)PI - theta[p]);
+   costheta[p] = (float)cos((float)PI - theta[p]);
+  }
+ 
+ // store the sines and cosines in a lookup table
+
+ // the step size for the convolution integration is the smallest voxel side length
+ if (dx <= dy && dx <= dz)
+	 delr = (float)2.0*dx;
+ else if (dy <= dx && dy <= dz)
+	 delr = (float)2.0*dy;
+ else
+	 delr = (float)2.0*dz;
+
+ //calculate dose at each point
+ //done from deposition (catcher's) point of view
+ #pragma omp parallel for
+ for (int k=0;k<Q; k++)
+  for (int j=0;j<N; j++)
+   for (int i=0;i<M; i++)
+	if (GRID_VALUE(dose_mask,i,j,k) > 0)  // only calculate dose inside dose mask
+	{
+		int i, j, k, l;
+		int p, q, r;
+		float del_x, del_y, del_z;
+		float current_x, current_y, current_z;
+		float cumval, last_cumval;
+		int inter_i, inter_j, inter_k;
+		float inter_x, inter_y, inter_z;
+		float r_eff, delr_eff, inter_r_eff;
+		int r_index;
+		float t, u, v, f;
+		float kval;
+
+	// do the integral for the point in the ROI
+	for (p=0;p<smallkern.ntheta;p++) //polar
+	 for (q=0;q<NPHI;q++) //azimuthal
+	 {
+	  //initialise position of current voxel
+	  current_x = x[i];
+	  current_y = y[j];
+	  current_z = z[k];
+
+	  //initialise effective radius along kernel direction
+	  r_eff = 0.0;
+	  //initialise cumulative kernel value for this direction
+	  last_cumval = 0.0;
+
+      //Using reciprocity technique where dose at point A due to point B
+	  //is dose at point B due to point A 
+
+      //x ,y, z increments along ray
+	  del_x = delr*(ip[0]*cosphi[q]*sintheta[p] + jp[0]*sinphi[q]*sintheta[p]
+			      + kp[0]*costheta[p]);
+	  del_y = delr*(ip[1]*cosphi[q]*sintheta[p] + jp[1]*sinphi[q]*sintheta[p]
+			      + kp[1]*costheta[p]);
+	  del_z = delr*(ip[2]*cosphi[q]*sintheta[p] + jp[2]*sinphi[q]*sintheta[p]
+			      + kp[2]*costheta[p]);
+
+	  //initialise physical radius
+	  r = 0;
+	  do
+	  {
+	    //interaction point is at mid-point of curent increment
+	    inter_x = current_x + (float)0.5*del_x;
+	    inter_y = current_y + (float)0.5*del_y;
+	    inter_z = current_z + (float)0.5*del_z;
+
+	    //voxel containing interaction point
+	    inter_i = (int) ((inter_x - density->start.x)/dx);
+	    inter_j = (int) ((inter_y - density->start.y)/dy);
+	    inter_k = (int) ((inter_z - density->start.z)/dz);
+	   
+	   // stop the integral if interaction point is outside the dose calculation limits
+	   if (    (inter_i < 0) || (inter_i + 1 >= M)
+	        || (inter_j < 0) || (inter_j + 1 >= N)
+	   	    || (inter_k < 0) || (inter_k + 1 >= Q)
+			|| (GRID_VALUE(dose_mask,inter_i,inter_j,inter_k) <= 0.0))
+		  break;
+
+	   	// Position of the end of the increment.  Interaction point is at the
+	    // midpoint.
+        current_x += del_x;
+	    current_y += del_y;
+	    current_z += del_z;
+        
+        //effective distance increment
+        delr_eff = delr*GRID_VALUE(density,inter_i,inter_j,inter_k);
+		//effective radius of interaction point
+		inter_r_eff = r_eff + (float)0.5*delr_eff;
+	    r_eff += delr_eff;
+
+		// trilinear interpolation method of the terma contribution, f
+
+		// relative differences between the interaction point and the lower voxel bound
+		t = (inter_x - x[inter_i])/dx;
+		u = (inter_y - y[inter_j])/dy;
+		v = (inter_z - z[inter_k])/dz; 
+
+		f = GRID_VALUE(terma,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
+		  + GRID_VALUE(terma,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
+		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
+		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k+1)*t*u*v
+		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
+		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
+		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
+		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); 
+
+		/* 
+		// interpolate density at the interaction point
+		rho = GRID_VALUE(density,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
+		    + GRID_VALUE(density,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
+		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
+		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k+1)*t*u*v
+		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
+		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
+		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
+		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); */
+
+		// perform kernel lookup for r_eff, r_index is the kernel index of the first 
+		// bin boundary below the effective radius of the voxel
+		r_index = binSearch(smallkern.radial_boundary,inter_r_eff,smallkern.nradii);
+
+		// interpolate to obtain the effective cumulative kernel value
+		if (r_index == -1)  // radius is between zero and the first bin boundary
+		{
+			// fractional difference between inter_r_eff and the first bin boundary
+			t = inter_r_eff/smallkern.radial_boundary[0];
+			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,0,p);
+		}
+		else if (r_index >= smallkern.nradii-1)  // overshot the kernel bin boundaries
+		{
+			cumval = KERNEL_TOTAL_VALUE(&smallkern,smallkern.nradii-1,p);
+		}
+		else  // inter_r_eff is between the first upper bin boundary and the last
+		{
+			t = (inter_r_eff - smallkern.radial_boundary[r_index])
+				/(smallkern.radial_boundary[r_index + 1] - smallkern.radial_boundary[r_index]);
+			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,r_index,p)
+				       + t*KERNEL_TOTAL_VALUE(&smallkern,r_index+1,p);
+		}
+
+        kval = cumval - last_cumval;
+
+      	last_cumval = cumval;
+
+		// Kernel value to use is current increment in cumulative value
+        // Note that this is the fractional dose deposited at i,j,k due to
+        // terma in an effective increment (increment*density) along the kernel ray at the 
+		// interaction point. The value comes from the fractional dose deposited in an 
+		// effective increment along the ray	at i,j,k due to terma at the current 
+		// interaction point.
+
+	    //Increment dose value.
+	    //Note that to include the effect of density at i,j,k on ENERGY deposited at i,j,k, 
+	    //there should be a density term, but this cancels on conversion of energy to dose as indicated below
+	    // if (GRID_VALUE(terma,inter_i,inter_j,inter_k) > 0.001)
+	    GRID_VALUE(dose,i,j,k) += f*kval;
+
+	   r++;
+	  }
+	  while (r<10000);
+	 }	//p,q
+ 
+      GRID_VALUE(dose,i,j,k)/= NPHI;
+    }
+
+ //Inverse square correction to dose
+ //This works better than applying the inverse square correction to terma
+ //See Papanikolaou and Mackie 1993
+ for (int k=0;k<Q;k++)
+  for (int j=0;j<N;j++)
+	for (int i=0;i<M;i++)
+   if (GRID_VALUE(dose,i,j,k) > 0.0)
+   {
+	   // squared difference between the source and the voxel
+	   length = (float)pow(x[i] - bm->y_vec[0],2.0f) + (float)pow(y[j] - bm->y_vec[1],2.0f) 
+		   + (float)pow(z[k] - bm->y_vec[2],2.0f);
+	   
+	   if (length > 0.0)
+	      GRID_VALUE(dose,i,j,k) *= SAD*SAD/length;
+   } 
+
+   // free vectors
+   free_fvector(ip,0,2);
+   free_fvector(jp,0,2);
+   free_fvector(kp,0,2);
+   free_fvector(x,0,M-1);
+   free_fvector(y,0,N-1);
+   free_fvector(z,0,Q-1);
+   
+   free(smallkern.angular_boundary);
+   free(smallkern.radial_boundary);
+   // free(poly_kernel.total_matrix);
+   for (int j=0;j<N_KERNEL_CATEGORIES;j++)
+	   free(smallkern.matrix[j]);
+
+   return(SUCCESS);
+}

+ 390 - 390
WiscPlan-SourceCode/Source-code-photon-windows/convolutionCondor.cpp

@@ -1,390 +1,390 @@
-/* Cconvolution.cpp */
-
-#include "defs.h"
-
-//function prototypes
-
-int load_kernels(MONO_KERNELS *, char []);
-int load_geometry(FLOAT_GRID *, char []);
-int pop_beam(BEAM *, FILE *);
-int calc_deff(FLOAT_GRID *,FLOAT_GRID *, FLOAT_GRID *, BEAM *);
-int terma_kerma(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,MONO_KERNELS *,FLOAT_GRID *);
-int make_poly_kernel(MONO_KERNELS *, KERNEL *);
-int calc_dose(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,KERNEL *,BEAM *, FLOAT_GRID *);
-int terma_dose_masks(FLOAT_GRID *, FLOAT_GRID *, BEAM *);
-int convolution(MONO_KERNELS *, BEAM *, FLOAT_GRID *, FILE *);
-
-char errstr[200];  // error string that all routines have access to
-
-int main(int argc, char *argv[])
-//  Expects four input arguments: 
-// 1)  kernel_filenames -- contains a list of the kernel files
-// 2)  geometry_filenames  -- contains a list of the geometry files
-// 3)  beamspec batch file -- locations of beamspec files in batch
-// 4)  beamlet batch file -- locations of resulting beamlets in batch
-{
-	int i,j,b,B;
-
-	char tmpstr[200];
-
-	FLOAT_GRID density;
-
-	MONO_KERNELS mono_kernels;
-
-	BEAM beam;
-
-	FILE *beamspec_batch_file;
-	FILE *beamlet_batch_file;
-
-	/*	// print the arguments
-	printf("Input arguments:\n");
-	for (j=1;j<argc;j++)
-	printf("%s\n",argv[j]); */
-
-	if (argc != 5)
-	{
-		printf("Expecting four input command line arguments, received %d.\n",argc);
-		return(FAILURE);
-	}
-
-	if (load_kernels(&mono_kernels,argv[1]) == FAILURE)
-	{
-		sprintf(tmpstr,"Failed at loading the kernels.\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	if (load_geometry(&density,argv[2]) == FAILURE)
-	{
-		sprintf(tmpstr,"Failed at loading the geometry.\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	/* 
-	// diagnostic lines
-	printf("SAD = %lf \n",beam.SAD);
-	printf("xp = %lf \n",beam.xp);
-	printf("yp = %lf \n",beam.yp);
-	printf("del_xp = %lf \n",beam.del_xp);
-	printf("del_yp = %lf \n",beam.del_yp);
-	printf("y_vec = (%lf,%lf,%lf) \n",beam.y_vec[0],beam.y_vec[1],beam.y_vec[2]);
-	printf("ip = (%lf,%lf,%lf) \n",beam.ip[0],beam.ip[1],beam.ip[2]);
-	printf("jp = (%lf,%lf,%lf) \n",beam.jp[0],beam.jp[1],beam.jp[2]);
-	printf("kp = (%lf,%lf,%lf) \n",beam.kp[0],beam.kp[1],beam.kp[2]);
-
-	printf("Xcount = %d, Ycount = %d, Zcount = %d \n",density.x_count,density.y_count,density.z_count);
-	printf("start = (%lf,%lf,%lf) \n",density.start.x,density.start.y,density.start.z);
-	printf("inc = (%lf,%lf,%lf) \n",density.inc.x,density.inc.y,density.inc.z); */
-
-
-	// open the beam specification batch file
-	if ((beamspec_batch_file = fopen(argv[3],"r")) == NULL)
-	{
-		printf("Failed to open beamspec batch file %s\n",argv[3]);
-		return(FAILURE);
-	}
-
-	// open the dose batch file
-	if ((beamlet_batch_file = fopen(argv[4],"wb")) == NULL)
-	{
-		printf("Failed to open beamlet batch file %s\n",argv[4]);
-		return(FAILURE);
-	}
-
-	// get the number of beams from the beamspec batch file
-	if (fgets(tmpstr,100,beamspec_batch_file) == NULL)  // pop off the first line
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	if (fscanf(beamspec_batch_file,"%d\n",&B) != 1)
-	{
-		sprintf(errstr,"Could not read-in number of beams from beamspec file.");
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	// write the number of beamlets in this batch as the first entry
-	fwrite(&B,sizeof(int),1,beamlet_batch_file); 
-
-	// Do convolution calculations for all consistent beamspec and dose
-	// filenames.  If a calculation for a beamlet fails, print an error 
-	// and move on to the next beamspec file.
-	for (b=0;b<B;b++)
-	{
-		// pop off a beam
-		if(pop_beam(&beam,beamspec_batch_file) == FAILURE)
-		{
-			sprintf(tmpstr,"Failed to load beamspec number %d:\n",b);
-			strcat(tmpstr,errstr);
-			strcpy(errstr,tmpstr);
-			printf("%s\n",errstr);
-		}
-		else if (convolution(&mono_kernels,&beam,&density,beamlet_batch_file) == FAILURE)
-		// An error occurred, so print the error string to standard out
-		// but do not terminate the remaining beam batches.
-		{
-			j = 0;
-			fwrite(&beam.num,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.x_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.y_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.z_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&j,sizeof(int),1,beamlet_batch_file);
-			printf("Error in the calculation for beamlet number %d,\n so all zeros were saved for the resulting beamlet file.\n",b);
-			printf("%s\n",errstr);
-		}
-		else
-			printf("Successfully calculated beamlet %d of %s.\n",b,argv[3]); 
-	}
-
-	// close the beamlet file
-	fclose(beamlet_batch_file);
-
-	// free the density grid
-	free(density.matrix);
-
-	// only need to free angular and radial boundaries for the first
-	// kernel, since other kernel boundaries just point to the same place
-	free(mono_kernels.kernel[0].angular_boundary);
-	free(mono_kernels.kernel[0].radial_boundary);
-
-	// free the kernels
-	free(mono_kernels.energy);
-	free(mono_kernels.fluence);
-	free(mono_kernels.mu);
-	free(mono_kernels.mu_en);
- 	for (i=0;i<mono_kernels.nkernels;i++)
-		for (j=0;j<N_KERNEL_CATEGORIES;j++)
-			free(mono_kernels.kernel[i].matrix[j]); 
-
-	return(SUCCESS);
-}
-
-int convolution(MONO_KERNELS *mono_kernels, BEAM *beam, FLOAT_GRID *density, FILE *beamlet_batch_file)
-// routine that actually performs the convolution for a given kernel, beam, and geometry
-{
-	int i,j,M,N,Q,Nind,Ntotal;  // dimensions of the CT density grid
-	int *dose_ind;
-	float *dose_data, doseMax;
-	char tmpstr[200];  // temporary string
-
-	FLOAT_GRID terma_mask;
-	FLOAT_GRID dose_mask;
-	FLOAT_GRID deff;
-	FLOAT_GRID terma;
-	FLOAT_GRID kermac;
-	FLOAT_GRID dose;
-
-	KERNEL poly_kernel;
-
-	// copy the density grid dimensions to the calculation grids
-	copy_grid_geometry(density,&terma_mask);
-	copy_grid_geometry(density,&dose_mask);
-	copy_grid_geometry(density,&deff);
-	copy_grid_geometry(density,&terma);
-	copy_grid_geometry(density,&kermac);
-	copy_grid_geometry(density,&dose);
-
-	// dimensions of all the grids
-	M = density->x_count;
-	N = density->y_count;
-	Q = density->z_count;
-
-	Ntotal = M*N*Q;
-
-	// Allocate memory for all of the grids and fill them all with zeros
-	if ((terma_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for terma_mask.");
-		return(FAILURE);
-	}
-
-	if ((dose_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for dose_mask.");
-		return(FAILURE);
-	}
-
-	if ((deff.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for deff.");
-		return(FAILURE);
-	}
-
-	if ((terma.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for terma.");
-		return(FAILURE);
-	}
-
-	if ((kermac.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for kermac.");
-		return(FAILURE);
-	}
-
-	if ((dose.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for dose.");
-		return(FAILURE);
-	}
-	
-	for (i=0;i<Ntotal;i++)
-	{
-		terma_mask.matrix[i] = 0.0;
-		dose_mask.matrix[i] = 0.0;
-		deff.matrix[i] = 0.0;
-		terma.matrix[i] = 0.0;
-		kermac.matrix[i] = 0.0;
-		dose.matrix[i] = 0.0;
-	} 
-	
-	/* start calculations */
-
-	// If a failure occurs in any calculation, append the error
-	// onto the error string and then return a FAILURE.
-
-	// create terma and dose masks
-	if (SUCCESS != terma_dose_masks(&terma_mask,&dose_mask,beam))
-	{
-		sprintf(tmpstr,"Failed in terma_dose_masks!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-
-	//create polyenergetic kernel from mono kernels and fluence,mu data
-	if (SUCCESS != make_poly_kernel(mono_kernels,&poly_kernel) )
-	{
-		sprintf(tmpstr,"Failed making polyenergetic kernel!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-	
-	//create effective depth array from density array
-	if (SUCCESS != calc_deff(density,&deff,&terma_mask,beam))
-	{
-		sprintf(tmpstr,"Failed in calc_deff!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-
-	//create kerma and terma arrays
-	//note kerma is collision kerma and is used for a kernel hardening correction
-	if (SUCCESS != terma_kerma(&deff,&terma,&kermac,mono_kernels,&terma_mask))
-	{
-		sprintf(tmpstr,"Failed in terma_kerma calculation!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-
-	//use all this stuff to calculate dose
-	if ( (SUCCESS != calc_dose(density,&terma,&dose,&poly_kernel,beam,&dose_mask)) ) 
-	{
-		sprintf(tmpstr,"Failed calculating dose!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-
-	/* //diagnostic lines:
-	FILE *fid;
-	fid = fopen("dose.bin","wb");
-	fwrite(dose.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("terma.bin","wb");
-	fwrite(terma.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("kermac.bin","wb");
-	fwrite(kermac.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("deff.bin","wb");
-	fwrite(deff.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("terma_mask.bin","wb");
-	fwrite(terma_mask.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("dose_mask.bin","wb");
-	fwrite(dose_mask.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("density.bin","wb");
-	fwrite(density->matrix,sizeof(float),Ntotal,fid);
-	fclose(fid); */
-
-    // find maximum dose
-	doseMax = 0.0;
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] > doseMax)
-			doseMax = dose.matrix[i];
-
-	// count the number of non-zero dose values
-	Nind = 0;
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
-			&& dose.matrix[i] > 0.0)
-			Nind++;
-		else
-			dose.matrix[i] = 0.0;  // turn off doses below threshold
-
-	// allocate memory for sparse dose data
-	dose_ind = (int *)malloc(sizeof(int)*Nind);
-	dose_data = (float *)malloc(sizeof(float)*Nind);
-
-	// store the sparse data	
-	j = 0;   // index just for the sparse data
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
-			&& dose.matrix[i] > 0.0)
-		{
-			dose_ind[j] = i;
-			dose_data[j] = dose.matrix[i];
-			j++; 
-		}
-
-	// save dose to a file
-
-	// save the total file size first, then the number of non-zero elements
-	fwrite(&beam->num,sizeof(int),1,beamlet_batch_file);
-	fwrite(&M,sizeof(int),1,beamlet_batch_file);
-	fwrite(&N,sizeof(int),1,beamlet_batch_file);
-	fwrite(&Q,sizeof(int),1,beamlet_batch_file);
-    fwrite(&Nind,sizeof(int),1,beamlet_batch_file);
-	fwrite(dose_ind,sizeof(int),Nind,beamlet_batch_file);
-	fwrite(dose_data,sizeof(float),Nind,beamlet_batch_file);
-
-	free(dose_ind);
-	free(dose_data);
-
-	// free the calculation grids
-	free(terma_mask.matrix);
-	free(dose_mask.matrix);
-	free(deff.matrix);
-	free(terma.matrix);
-	free(kermac.matrix);
-	free(dose.matrix);
-
-	free(poly_kernel.angular_boundary);
-	free(poly_kernel.radial_boundary);
-	// free(poly_kernel.total_matrix);
-	for (j=0;j<N_KERNEL_CATEGORIES;j++)
-		free(poly_kernel.matrix[j]);
-
-	return(SUCCESS);
-}
-
+/* Cconvolution.cpp */
+
+#include "defs.h"
+
+//function prototypes
+
+int load_kernels(MONO_KERNELS *, char []);
+int load_geometry(FLOAT_GRID *, char []);
+int pop_beam(BEAM *, FILE *);
+int calc_deff(FLOAT_GRID *,FLOAT_GRID *, FLOAT_GRID *, BEAM *);
+int terma_kerma(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,MONO_KERNELS *,FLOAT_GRID *);
+int make_poly_kernel(MONO_KERNELS *, KERNEL *);
+int calc_dose(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,KERNEL *,BEAM *, FLOAT_GRID *);
+int terma_dose_masks(FLOAT_GRID *, FLOAT_GRID *, BEAM *);
+int convolution(MONO_KERNELS *, BEAM *, FLOAT_GRID *, FILE *);
+
+char errstr[200];  // error string that all routines have access to
+
+int main(int argc, char *argv[])
+//  Expects four input arguments: 
+// 1)  kernel_filenames -- contains a list of the kernel files
+// 2)  geometry_filenames  -- contains a list of the geometry files
+// 3)  beamspec batch file -- locations of beamspec files in batch
+// 4)  beamlet batch file -- locations of resulting beamlets in batch
+{
+	int i,j,b,B;
+
+	char tmpstr[200];
+
+	FLOAT_GRID density;
+
+	MONO_KERNELS mono_kernels;
+
+	BEAM beam;
+
+	FILE *beamspec_batch_file;
+	FILE *beamlet_batch_file;
+
+	/*	// print the arguments
+	printf("Input arguments:\n");
+	for (j=1;j<argc;j++)
+	printf("%s\n",argv[j]); */
+
+	if (argc != 5)
+	{
+		printf("Expecting four input command line arguments, received %d.\n",argc);
+		return(FAILURE);
+	}
+
+	if (load_kernels(&mono_kernels,argv[1]) == FAILURE)
+	{
+		sprintf(tmpstr,"Failed at loading the kernels.\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	if (load_geometry(&density,argv[2]) == FAILURE)
+	{
+		sprintf(tmpstr,"Failed at loading the geometry.\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	/* 
+	// diagnostic lines
+	printf("SAD = %lf \n",beam.SAD);
+	printf("xp = %lf \n",beam.xp);
+	printf("yp = %lf \n",beam.yp);
+	printf("del_xp = %lf \n",beam.del_xp);
+	printf("del_yp = %lf \n",beam.del_yp);
+	printf("y_vec = (%lf,%lf,%lf) \n",beam.y_vec[0],beam.y_vec[1],beam.y_vec[2]);
+	printf("ip = (%lf,%lf,%lf) \n",beam.ip[0],beam.ip[1],beam.ip[2]);
+	printf("jp = (%lf,%lf,%lf) \n",beam.jp[0],beam.jp[1],beam.jp[2]);
+	printf("kp = (%lf,%lf,%lf) \n",beam.kp[0],beam.kp[1],beam.kp[2]);
+
+	printf("Xcount = %d, Ycount = %d, Zcount = %d \n",density.x_count,density.y_count,density.z_count);
+	printf("start = (%lf,%lf,%lf) \n",density.start.x,density.start.y,density.start.z);
+	printf("inc = (%lf,%lf,%lf) \n",density.inc.x,density.inc.y,density.inc.z); */
+
+
+	// open the beam specification batch file
+	if ((beamspec_batch_file = fopen(argv[3],"r")) == NULL)
+	{
+		printf("Failed to open beamspec batch file %s\n",argv[3]);
+		return(FAILURE);
+	}
+
+	// open the dose batch file
+	if ((beamlet_batch_file = fopen(argv[4],"wb")) == NULL)
+	{
+		printf("Failed to open beamlet batch file %s\n",argv[4]);
+		return(FAILURE);
+	}
+
+	// get the number of beams from the beamspec batch file
+	if (fgets(tmpstr,100,beamspec_batch_file) == NULL)  // pop off the first line
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	if (fscanf(beamspec_batch_file,"%d\n",&B) != 1)
+	{
+		sprintf(errstr,"Could not read-in number of beams from beamspec file.");
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	// write the number of beamlets in this batch as the first entry
+	fwrite(&B,sizeof(int),1,beamlet_batch_file); 
+
+	// Do convolution calculations for all consistent beamspec and dose
+	// filenames.  If a calculation for a beamlet fails, print an error 
+	// and move on to the next beamspec file.
+	for (b=0;b<B;b++)
+	{
+		// pop off a beam
+		if(pop_beam(&beam,beamspec_batch_file) == FAILURE)
+		{
+			sprintf(tmpstr,"Failed to load beamspec number %d:\n",b);
+			strcat(tmpstr,errstr);
+			strcpy(errstr,tmpstr);
+			printf("%s\n",errstr);
+		}
+		else if (convolution(&mono_kernels,&beam,&density,beamlet_batch_file) == FAILURE)
+		// An error occurred, so print the error string to standard out
+		// but do not terminate the remaining beam batches.
+		{
+			j = 0;
+			fwrite(&beam.num,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.x_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.y_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.z_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&j,sizeof(int),1,beamlet_batch_file);
+			printf("Error in the calculation for beamlet number %d,\n so all zeros were saved for the resulting beamlet file.\n",b);
+			printf("%s\n",errstr);
+		}
+		else
+			printf("Successfully calculated beamlet %d of %s.\n",b,argv[3]); 
+	}
+
+	// close the beamlet file
+	fclose(beamlet_batch_file);
+
+	// free the density grid
+	free(density.matrix);
+
+	// only need to free angular and radial boundaries for the first
+	// kernel, since other kernel boundaries just point to the same place
+	free(mono_kernels.kernel[0].angular_boundary);
+	free(mono_kernels.kernel[0].radial_boundary);
+
+	// free the kernels
+	free(mono_kernels.energy);
+	free(mono_kernels.fluence);
+	free(mono_kernels.mu);
+	free(mono_kernels.mu_en);
+ 	for (i=0;i<mono_kernels.nkernels;i++)
+		for (j=0;j<N_KERNEL_CATEGORIES;j++)
+			free(mono_kernels.kernel[i].matrix[j]); 
+
+	return(SUCCESS);
+}
+
+int convolution(MONO_KERNELS *mono_kernels, BEAM *beam, FLOAT_GRID *density, FILE *beamlet_batch_file)
+// routine that actually performs the convolution for a given kernel, beam, and geometry
+{
+	int i,j,M,N,Q,Nind,Ntotal;  // dimensions of the CT density grid
+	int *dose_ind;
+	float *dose_data, doseMax;
+	char tmpstr[200];  // temporary string
+
+	FLOAT_GRID terma_mask;
+	FLOAT_GRID dose_mask;
+	FLOAT_GRID deff;
+	FLOAT_GRID terma;
+	FLOAT_GRID kermac;
+	FLOAT_GRID dose;
+
+	KERNEL poly_kernel;
+
+	// copy the density grid dimensions to the calculation grids
+	copy_grid_geometry(density,&terma_mask);
+	copy_grid_geometry(density,&dose_mask);
+	copy_grid_geometry(density,&deff);
+	copy_grid_geometry(density,&terma);
+	copy_grid_geometry(density,&kermac);
+	copy_grid_geometry(density,&dose);
+
+	// dimensions of all the grids
+	M = density->x_count;
+	N = density->y_count;
+	Q = density->z_count;
+
+	Ntotal = M*N*Q;
+
+	// Allocate memory for all of the grids and fill them all with zeros
+	if ((terma_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for terma_mask.");
+		return(FAILURE);
+	}
+
+	if ((dose_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for dose_mask.");
+		return(FAILURE);
+	}
+
+	if ((deff.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for deff.");
+		return(FAILURE);
+	}
+
+	if ((terma.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for terma.");
+		return(FAILURE);
+	}
+
+	if ((kermac.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for kermac.");
+		return(FAILURE);
+	}
+
+	if ((dose.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for dose.");
+		return(FAILURE);
+	}
+	
+	for (i=0;i<Ntotal;i++)
+	{
+		terma_mask.matrix[i] = 0.0;
+		dose_mask.matrix[i] = 0.0;
+		deff.matrix[i] = 0.0;
+		terma.matrix[i] = 0.0;
+		kermac.matrix[i] = 0.0;
+		dose.matrix[i] = 0.0;
+	} 
+	
+	/* start calculations */
+
+	// If a failure occurs in any calculation, append the error
+	// onto the error string and then return a FAILURE.
+
+	// create terma and dose masks
+	if (SUCCESS != terma_dose_masks(&terma_mask,&dose_mask,beam))
+	{
+		sprintf(tmpstr,"Failed in terma_dose_masks!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+
+	//create polyenergetic kernel from mono kernels and fluence,mu data
+	if (SUCCESS != make_poly_kernel(mono_kernels,&poly_kernel) )
+	{
+		sprintf(tmpstr,"Failed making polyenergetic kernel!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+	
+	//create effective depth array from density array
+	if (SUCCESS != calc_deff(density,&deff,&terma_mask,beam))
+	{
+		sprintf(tmpstr,"Failed in calc_deff!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+
+	//create kerma and terma arrays
+	//note kerma is collision kerma and is used for a kernel hardening correction
+	if (SUCCESS != terma_kerma(&deff,&terma,&kermac,mono_kernels,&terma_mask))
+	{
+		sprintf(tmpstr,"Failed in terma_kerma calculation!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+
+	//use all this stuff to calculate dose
+	if ( (SUCCESS != calc_dose(density,&terma,&dose,&poly_kernel,beam,&dose_mask)) ) 
+	{
+		sprintf(tmpstr,"Failed calculating dose!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+
+	/* //diagnostic lines:
+	FILE *fid;
+	fid = fopen("dose.bin","wb");
+	fwrite(dose.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("terma.bin","wb");
+	fwrite(terma.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("kermac.bin","wb");
+	fwrite(kermac.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("deff.bin","wb");
+	fwrite(deff.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("terma_mask.bin","wb");
+	fwrite(terma_mask.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("dose_mask.bin","wb");
+	fwrite(dose_mask.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("density.bin","wb");
+	fwrite(density->matrix,sizeof(float),Ntotal,fid);
+	fclose(fid); */
+
+    // find maximum dose
+	doseMax = 0.0;
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] > doseMax)
+			doseMax = dose.matrix[i];
+
+	// count the number of non-zero dose values
+	Nind = 0;
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
+			&& dose.matrix[i] > 0.0)
+			Nind++;
+		else
+			dose.matrix[i] = 0.0;  // turn off doses below threshold
+
+	// allocate memory for sparse dose data
+	dose_ind = (int *)malloc(sizeof(int)*Nind);
+	dose_data = (float *)malloc(sizeof(float)*Nind);
+
+	// store the sparse data	
+	j = 0;   // index just for the sparse data
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
+			&& dose.matrix[i] > 0.0)
+		{
+			dose_ind[j] = i;
+			dose_data[j] = dose.matrix[i];
+			j++; 
+		}
+
+	// save dose to a file
+
+	// save the total file size first, then the number of non-zero elements
+	fwrite(&beam->num,sizeof(int),1,beamlet_batch_file);
+	fwrite(&M,sizeof(int),1,beamlet_batch_file);
+	fwrite(&N,sizeof(int),1,beamlet_batch_file);
+	fwrite(&Q,sizeof(int),1,beamlet_batch_file);
+    fwrite(&Nind,sizeof(int),1,beamlet_batch_file);
+	fwrite(dose_ind,sizeof(int),Nind,beamlet_batch_file);
+	fwrite(dose_data,sizeof(float),Nind,beamlet_batch_file);
+
+	free(dose_ind);
+	free(dose_data);
+
+	// free the calculation grids
+	free(terma_mask.matrix);
+	free(dose_mask.matrix);
+	free(deff.matrix);
+	free(terma.matrix);
+	free(kermac.matrix);
+	free(dose.matrix);
+
+	free(poly_kernel.angular_boundary);
+	free(poly_kernel.radial_boundary);
+	// free(poly_kernel.total_matrix);
+	for (j=0;j<N_KERNEL_CATEGORIES;j++)
+		free(poly_kernel.matrix[j]);
+
+	return(SUCCESS);
+}
+

+ 138 - 138
WiscPlan-SourceCode/Source-code-photon-windows/defs.h

@@ -1,138 +1,138 @@
-/* defs.h */
-
-// libraries that will be needed throughout
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <malloc.h>
-
-#define MAX_KERNELS 50	//max number of monoenergetic kernels to use for creating polyenergetic kernel
-#define N_KERNEL_RADII 24  //number of radial increments in mono kernels 
-#define N_KERNEL_ANGLES 48 //number of angular increments in mono kernels
-#define N_KERNEL_CATEGORIES 5  //number of kernel categories (primary, first scatter...)
-
-// upsample factors to determine insideness for voxels on aperture edge:
-#define Mus  5
-#define Nus  5
-#define Qus  5
-
-#define SUCCESS 1
-#define FAILURE 0
-
-#define doseCutoffThreshold 0.005 // doses less than this fraction of the maximum are cut off
-
-#define RSAFE 2.0   // safety margin for dose_mask calculation in cm
-
-#define PI 3.14152654
-
-#define Y_DOSE_EXTENT 8.0  //optionally only calculate this many cm in y-direction (commented out in calc_dose)
-
-#define NPHI 12  //number of azimuthal angles for convolution 
-// #define DELR 0.4 //radial increments for convolution (adaptive to the problem now, in calc_dose)
-#define NTHETA 6  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)
-
-/* #define NPHI 12	//number of azimuthal angles for convolution 
-#define DELR 0.1 //radial increments for convolution
-#define NTHETA 12  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)  */
-
-#define MAXX(x,y) ((x) > (y) ? (x) : (y))
-
-//each kernel file contains 7 entries per voxel, the first five are these categores
-typedef enum
-{
- primary_,
- first_scatter_,
- second_scatter_,
- multiple_scatter_,
- brem_annih_
-} KERNEL_CATEGORIES;
-
-typedef struct
-{
-    float x;
-    float y;
-    float z;
-} POINT;
-
-//standard float precision grid structure, with dynamically allocated matrix 
-//used for density, deff, terma, kerma, dose
-typedef struct
-{
-    POINT start;
-    POINT inc;
-    int x_count;
-    int y_count;
-    int z_count;
-    float *matrix;
-} FLOAT_GRID;
-
-//macro to access grid values
-#define GRID_VALUE(GRID_ptr, i, j, k)\
-    ((GRID_ptr)->matrix[(i) +\
-                        (GRID_ptr)->x_count *\
-                         ((j) + ((k) * (GRID_ptr)->y_count))])
-
-// macro for 3D dot products
-#define DOT3D(vec1,vec2) ((vec1[0])*(vec2[0])+(vec1[1])*(vec2[1])+(vec1[2])*(vec2[2]))
-
-//kernel structure for each monoenergetic kernel and the polyenergetic kernel
-typedef struct
-{
- int nradii;
- int ntheta;
- float *radial_boundary;
- float *angular_boundary;
- float *matrix[N_KERNEL_CATEGORIES];  //kernel values for each category
- float *total_matrix;				   //sum of all categories (used for current convolution)
-} KERNEL;
-
-//macros for accessing kernel values
-#define KERNEL_VALUE(kern_ptr,category,i,j) \
-        (kern_ptr)->matrix[category][(i) + (j)*(kern_ptr)->nradii]
-#define KERNEL_TOTAL_VALUE(kern_ptr,i,j) \
-        (kern_ptr)->total_matrix[(i) + (j)*(kern_ptr)->nradii]
-
-//infor and array of KERNEL structures for monoenergetic kernels 
-typedef struct
-{
- int nkernels;
- float *energy;
- float *fluence;
- float *mu;
- float *mu_en;
- KERNEL kernel[MAX_KERNELS];
-} MONO_KERNELS;
-
-//beam description (center and size)
-typedef struct
-{
- float ip[3];  // first aperture center vector
- float jp[3];  // second aperture center vector
- float kp[3];  // source direction vector
- float y_vec[3];   // source location vector
-
- // aperture parameters
- float xp;
- float yp;
- float del_xp;   // aperture width in ip direction
- float del_yp;   // aperture width in jp direction
-
- // source-axis distance (leave here for now because to ubiquitous)
- float SAD;
-
- // beam number to avoid ambiguity
- int num;
-} BEAM;
-
-/* Prototypes of utility functions */
-float *fvector(int nl, int nh);
-float **fmatrix(int nrl, int nrh, int ncl, int nch);
-
-void free_fvector(float *v, int nl, int nh);
-void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch);
-
-int copy_grid_geometry(FLOAT_GRID *, FLOAT_GRID *);
-int binSearch(float *, float, int);
-
-void nrerror(char error_text[]);
+/* defs.h */
+
+// libraries that will be needed throughout
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <malloc.h>
+
+#define MAX_KERNELS 50	//max number of monoenergetic kernels to use for creating polyenergetic kernel
+#define N_KERNEL_RADII 24  //number of radial increments in mono kernels 
+#define N_KERNEL_ANGLES 48 //number of angular increments in mono kernels
+#define N_KERNEL_CATEGORIES 5  //number of kernel categories (primary, first scatter...)
+
+// upsample factors to determine insideness for voxels on aperture edge:
+#define Mus  5
+#define Nus  5
+#define Qus  5
+
+#define SUCCESS 1
+#define FAILURE 0
+
+#define doseCutoffThreshold 0.005 // doses less than this fraction of the maximum are cut off
+
+#define RSAFE 2.0   // safety margin for dose_mask calculation in cm
+
+#define PI 3.14152654
+
+#define Y_DOSE_EXTENT 8.0  //optionally only calculate this many cm in y-direction (commented out in calc_dose)
+
+#define NPHI 12  //number of azimuthal angles for convolution 
+// #define DELR 0.4 //radial increments for convolution (adaptive to the problem now, in calc_dose)
+#define NTHETA 6  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)
+
+/* #define NPHI 12	//number of azimuthal angles for convolution 
+#define DELR 0.1 //radial increments for convolution
+#define NTHETA 12  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)  */
+
+#define MAXX(x,y) ((x) > (y) ? (x) : (y))
+
+//each kernel file contains 7 entries per voxel, the first five are these categores
+typedef enum
+{
+ primary_,
+ first_scatter_,
+ second_scatter_,
+ multiple_scatter_,
+ brem_annih_
+} KERNEL_CATEGORIES;
+
+typedef struct
+{
+    float x;
+    float y;
+    float z;
+} POINT;
+
+//standard float precision grid structure, with dynamically allocated matrix 
+//used for density, deff, terma, kerma, dose
+typedef struct
+{
+    POINT start;
+    POINT inc;
+    int x_count;
+    int y_count;
+    int z_count;
+    float *matrix;
+} FLOAT_GRID;
+
+//macro to access grid values
+#define GRID_VALUE(GRID_ptr, i, j, k)\
+    ((GRID_ptr)->matrix[(i) +\
+                        (GRID_ptr)->x_count *\
+                         ((j) + ((k) * (GRID_ptr)->y_count))])
+
+// macro for 3D dot products
+#define DOT3D(vec1,vec2) ((vec1[0])*(vec2[0])+(vec1[1])*(vec2[1])+(vec1[2])*(vec2[2]))
+
+//kernel structure for each monoenergetic kernel and the polyenergetic kernel
+typedef struct
+{
+ int nradii;
+ int ntheta;
+ float *radial_boundary;
+ float *angular_boundary;
+ float *matrix[N_KERNEL_CATEGORIES];  //kernel values for each category
+ float *total_matrix;				   //sum of all categories (used for current convolution)
+} KERNEL;
+
+//macros for accessing kernel values
+#define KERNEL_VALUE(kern_ptr,category,i,j) \
+        (kern_ptr)->matrix[category][(i) + (j)*(kern_ptr)->nradii]
+#define KERNEL_TOTAL_VALUE(kern_ptr,i,j) \
+        (kern_ptr)->total_matrix[(i) + (j)*(kern_ptr)->nradii]
+
+//infor and array of KERNEL structures for monoenergetic kernels 
+typedef struct
+{
+ int nkernels;
+ float *energy;
+ float *fluence;
+ float *mu;
+ float *mu_en;
+ KERNEL kernel[MAX_KERNELS];
+} MONO_KERNELS;
+
+//beam description (center and size)
+typedef struct
+{
+ float ip[3];  // first aperture center vector
+ float jp[3];  // second aperture center vector
+ float kp[3];  // source direction vector
+ float y_vec[3];   // source location vector
+
+ // aperture parameters
+ float xp;
+ float yp;
+ float del_xp;   // aperture width in ip direction
+ float del_yp;   // aperture width in jp direction
+
+ // source-axis distance (leave here for now because to ubiquitous)
+ float SAD;
+
+ // beam number to avoid ambiguity
+ int num;
+} BEAM;
+
+/* Prototypes of utility functions */
+float *fvector(int nl, int nh);
+float **fmatrix(int nrl, int nrh, int ncl, int nch);
+
+void free_fvector(float *v, int nl, int nh);
+void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch);
+
+int copy_grid_geometry(FLOAT_GRID *, FLOAT_GRID *);
+int binSearch(float *, float, int);
+
+void nrerror(char error_text[]);

+ 122 - 122
WiscPlan-SourceCode/Source-code-photon-windows/make_poly.cpp

@@ -1,122 +1,122 @@
-/* make_poly.cpp */
-
-/* Creates a poly-energetic kernel given the energy-binned beam fluence and 
-kernels for all of the beam energies. */
-
-#include "defs.h"
-
-//fillers for these entries in kernel structure
-#define UNCERT 1.0
-#define MEAN_RADIUS 0.0
-#define MEAN_ANGLE 0.0
-
-extern char errstr[200];  // error string that all routines have access to
-
-int make_poly_kernel(MONO_KERNELS *mono, KERNEL *poly)
-{
- 
-// There is a problem with the first block of commented statements, likely a memory leak
-
- KERNEL_CATEGORIES category;
- int i, j, e;
- float sum;
-
- poly->nradii = N_KERNEL_RADII;
- poly->ntheta = N_KERNEL_ANGLES;
- 
- poly->radial_boundary = (float *)malloc(poly->nradii*sizeof(float));
- poly->angular_boundary = (float *)malloc(poly->ntheta*sizeof(float));
-
- //copy radial boundaries from first mono kernel
- for (i=0;i<poly->nradii;i++)
-  poly->radial_boundary[i] = mono->kernel[0].radial_boundary[i];
-
- //copy angular boundaries from first mono kernel
- for (i=0;i<poly->ntheta;i++)
-  poly->angular_boundary[i] = mono->kernel[0].angular_boundary[i];
-
- for (i=0;i<N_KERNEL_CATEGORIES;i++)
-  if ( (poly->matrix[i] =
-   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
-	return(FAILURE);
-   }
- if ( (poly->total_matrix =
-   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for total matrix\n");
-	return(FAILURE);
-   } 
-
- for (j=0;j<poly->ntheta;j++)
-  for (i=0;i<poly->nradii;i++)
-  {
-   KERNEL_TOTAL_VALUE(poly,i,j) = 0.0;
-
-   //weight of each mono kernel value in sum is fluence*energy*mu
-   category = primary_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = first_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = second_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = multiple_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = brem_annih_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-  }
-
- return(SUCCESS);
-
-}
+/* make_poly.cpp */
+
+/* Creates a poly-energetic kernel given the energy-binned beam fluence and 
+kernels for all of the beam energies. */
+
+#include "defs.h"
+
+//fillers for these entries in kernel structure
+#define UNCERT 1.0
+#define MEAN_RADIUS 0.0
+#define MEAN_ANGLE 0.0
+
+extern char errstr[200];  // error string that all routines have access to
+
+int make_poly_kernel(MONO_KERNELS *mono, KERNEL *poly)
+{
+ 
+// There is a problem with the first block of commented statements, likely a memory leak
+
+ KERNEL_CATEGORIES category;
+ int i, j, e;
+ float sum;
+
+ poly->nradii = N_KERNEL_RADII;
+ poly->ntheta = N_KERNEL_ANGLES;
+ 
+ poly->radial_boundary = (float *)malloc(poly->nradii*sizeof(float));
+ poly->angular_boundary = (float *)malloc(poly->ntheta*sizeof(float));
+
+ //copy radial boundaries from first mono kernel
+ for (i=0;i<poly->nradii;i++)
+  poly->radial_boundary[i] = mono->kernel[0].radial_boundary[i];
+
+ //copy angular boundaries from first mono kernel
+ for (i=0;i<poly->ntheta;i++)
+  poly->angular_boundary[i] = mono->kernel[0].angular_boundary[i];
+
+ for (i=0;i<N_KERNEL_CATEGORIES;i++)
+  if ( (poly->matrix[i] =
+   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
+	return(FAILURE);
+   }
+ if ( (poly->total_matrix =
+   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for total matrix\n");
+	return(FAILURE);
+   } 
+
+ for (j=0;j<poly->ntheta;j++)
+  for (i=0;i<poly->nradii;i++)
+  {
+   KERNEL_TOTAL_VALUE(poly,i,j) = 0.0;
+
+   //weight of each mono kernel value in sum is fluence*energy*mu
+   category = primary_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = first_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = second_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = multiple_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = brem_annih_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+  }
+
+ return(SUCCESS);
+
+}

+ 11 - 11
WiscPlan-SourceCode/Source-code-photon-windows/makefile

@@ -1,11 +1,11 @@
-CC = g++
-OBJECTS = convolutionCondor.o calc_deff.o parse_funcCondor.o make_poly.o raytrace.o terma_dose_masks.o terma_kerma.o calc_dose.o util.o
-
-Cconvolution : $(OBJECTS)
-	condor_compile $(CC) $(CFLAGS) $(OBJECTS) -o convolutionCondor
-
-%.o : %.cpp
-	$(CC) $(CFLAGS) -c $<
-
-clean : 
-	rm -f $(OBJECTS) convolutionCondor
+CC = g++
+OBJECTS = convolutionCondor.o calc_deff.o parse_funcCondor.o make_poly.o raytrace.o terma_dose_masks.o terma_kerma.o calc_dose.o util.o
+
+Cconvolution : $(OBJECTS)
+	condor_compile $(CC) $(CFLAGS) $(OBJECTS) -o convolutionCondor
+
+%.o : %.cpp
+	$(CC) $(CFLAGS) -c $<
+
+clean : 
+	rm -f $(OBJECTS) convolutionCondor

+ 825 - 825
WiscPlan-SourceCode/Source-code-photon-windows/parse_funcCondor.cpp

@@ -1,825 +1,825 @@
-/* parse_func.cpp */
-
-/* Checks the validity of the arguments input to the convolution routine and 
-transfers the Matlab-style arguments to the C structures defined in defs.h. */
-
-/* This parse function operates on file inputs rather than on Matlab inputs. */
-
-#include "defs.h"
-
-// Markers that are searched for inside the kernel_filenames file, which is 
-// passed to the load_kernels routine. The line after each of these markers
-// in the kernel_filenames file is a filename corresponding to the marker.
-#define kernel_header_line "kernel_header"
-#define kernel_radii_line "kernel_radii"
-#define kernel_angles_line "kernel_angles"
-#define kernel_energies_line "kernel_energies"
-#define kernel_primary_line "kernel_primary"
-#define kernel_first_scatter_line "kernel_first_scatter"
-#define kernel_second_scatter_line "kernel_second_scatter"
-#define kernel_multiple_scatter_line "kernel_multiple_scatter"
-#define kernel_brem_annih_line "kernel_brem_annih"
-#define kernel_total_line "kernel_total"
-#define kernel_fluence_line "kernel_fluence"
-#define kernel_mu_line "kernel_mu"
-#define kernel_mu_en_line "kernel_mu_en"
-
-// Markers that are searched for inside the geometry_filenames, which is 
-// passed to the load_geometry routine. These have the same meaning as
-// the kernel_filenames markers.
-#define geometry_header "./geometry_files/geometry_header.txt"
-#define geometry_density "./geometry_files/density.bin"
-#define beam_data "./geometry_files/beam_data.txt"
-
-#define geometry_header_line "geometry_header"
-#define geometry_density_line "geometry_density"
-#define beam_data_line "beam_data"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int load_kernels(MONO_KERNELS *mono_kernels, char kernel_filenames[])
-/* Ensures that the kernel files have the following format:
-
-               radii: [1xNradii float]
-              angles: [1xNangles float]
-            energies: [1xNenergies float]
-             primary: [Nradii x Nangles x Nenergies float]
-       first_scatter: [Nradii x Nangles x Nenergies float]
-      second_scatter: [Nradii x Nangles x Nenergies float]
-    multiple_scatter: [Nradii x Nangles x Nenergies float]
-          brem_annih: [Nradii x Nangles x Nenergies float]
-               total: [Nradii x Nangles x Nenergies float]
-          mean_radii: [Nradii x Nangles x Nenergies float] (not used)
-         mean_angles: [Nradii x Nangles x Nenergies float] (not used)
-           helpfield: [any x any char] 
-             fluence: [1xNenergies float]
-                  mu: [1xNenergies float]
-               mu_en: [1xNenergies float]
-
-mistakes or inconsistencies will result in errors.
-
-  Results are then stored in mono_kernels.
-
-The names of the files containing all of these parameters are given
-by the kernel_filenames file.
-
-*/
-{
-	int j,k;
-	int Nenergies, Nangles, Nradii;
-	char str[200];
-	// some strings to hold filenames
-	char header_filename[200], radii_filename[200], angles_filename[200];
-	char energies_filename[200], primary_filename[200], first_scatter_filename[200];
-	char second_scatter_filename[200], multiple_scatter_filename[200];
-	char brem_annih_filename[200], total_filename[200], fluence_filename[200];
-	char mu_filename[200], mu_en_filename[200];
-
-	// flags for file readin
-	int header_flag = 0;
-	int radii_flag = 0;
-	int angles_flag = 0;
-	int energies_flag = 0;
-	int primary_flag = 0;
-	int first_flag = 0;
-	int second_flag = 0;
-	int multiple_flag = 0;
-	int brem_annih_flag = 0;
-	int total_flag = 0;
-	int fluence_flag = 0;
-	int mu_flag = 0;
-	int mu_en_flag = 0;
-
-	FILE *fid;  // generic filename
-	FILE *primary, *first, *second, *multiple, *brem_annih, *total;  // kernel files
-
-	// read in the data filenames
-	if ( (fid = fopen(kernel_filenames,"r")) == NULL)  // open the kernel filenames
-	{
-		sprintf(errstr,"Could not open the kernel filenames file");
-		return(FAILURE);
-	}
-
-	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
-	{
-	  if (!strcmp(str,kernel_header_line))
-	    if (fscanf(fid,"%s\n",header_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_header filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      header_flag = 1;
-	  else if (!strcmp(str,kernel_radii_line))
-	    if (fscanf(fid,"%s\n",radii_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_radii filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      radii_flag = 1;
-	  else if (!strcmp(str,kernel_angles_line))
-	    if (fscanf(fid,"%s\n",angles_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_angles filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-            else
-	      angles_flag = 1;
-	  else if (!strcmp(str,kernel_energies_line))
-        if (fscanf(fid,"%s\n",energies_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_energies filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      energies_flag = 1;
-          else if (!strcmp(str,kernel_fluence_line))
-	    if (fscanf(fid,"%s\n",fluence_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_fluence filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      fluence_flag = 1;
-	  else if (!strcmp(str,kernel_primary_line))
-        if (fscanf(fid,"%s\n",primary_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_primary filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      primary_flag = 1;
-	  else if (!strcmp(str,kernel_first_scatter_line))
-        if (fscanf(fid,"%s\n",first_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_first_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      first_flag = 1;
-	  else if (!strcmp(str,kernel_second_scatter_line))
-	    if (fscanf(fid,"%s\n",second_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_second_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      second_flag = 1;
-	  else if (!strcmp(str,kernel_multiple_scatter_line))
-        if (fscanf(fid,"%s\n",multiple_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_multiple_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      multiple_flag = 1;
-	  else if (!strcmp(str,kernel_brem_annih_line))
-	    if (fscanf(fid,"%s\n",brem_annih_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_brem_annih filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else 
-	      brem_annih_flag = 1;
-	  else if (!strcmp(str,kernel_total_line))
-	    if (fscanf(fid,"%s\n",total_filename) != 1)
-	    {
-			sprintf(errstr,"Failed to read-in the kernel_total filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      total_flag = 1;
-	  else if (!strcmp(str,kernel_mu_line))
-	    if (fscanf(fid,"%s\n",mu_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_mu filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      mu_flag = 1;
-	  else if (!strcmp(str,kernel_mu_en_line))
-	    if (fscanf(fid,"%s\n",mu_en_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_mu_en filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      mu_en_flag = 1;
-	  else
-	  {   
-		    sprintf(errstr,"Unrecognized string in the kernel filenames file: %s\n",str);
-			return(FAILURE);   
-	  }
-	}
-
-	// confirm that all of the required filenames have been found
-	if (header_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel header filename.");
-	  return(FAILURE);
-	}
-	else if (radii_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel radii filename.");
-	  return(FAILURE);
-	}
-	else if (angles_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel angles filename.");
-	  return(FAILURE);
-	}
-	else if (energies_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel energies filename.");
-	  return(FAILURE);
-	}
-	else if (primary_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a primary kernel filename.");
-	  return(FAILURE);
-	}
-	else if (first_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a first scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (second_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a second scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (multiple_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a multiple scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (brem_annih_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a brem_annih kernel filename.");
-	  return(FAILURE);
-	}
-	else if (total_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a total kernel filename.");
-	  return(FAILURE);
-	}
-	else if (fluence_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel fluence filename.");
-	  return(FAILURE);
-	}
-	else if (mu_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel mu filename.");
-	  return(FAILURE);
-	}
-	else if (mu_en_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel mu_en filename.");
-	  return(FAILURE);
-	}
-
-	// read in the expected matrix sizes
-	if ( (fid=fopen(header_filename,"r")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel header file in kernel data folder.");
-		return(FAILURE);
-	}
-	else
-	{   
-		fgets(str,100,fid); // pop-off the first line of the header
-		if (fscanf(fid,"%d %d %d\n",&Nradii,&Nangles,&Nenergies) != 3)
-		{
-			sprintf(errstr,"Incorrect amount of data in kernel header file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	mono_kernels->nkernels = Nenergies;
-
-	// read in the energies, fluences, mu, and mu_en values
-	if ( (fid = fopen(energies_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel energies file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->energy = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel energies.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->energy,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of energies in kernel_energies file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	if ( (fid = fopen(fluence_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel fluences file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->fluence = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel fluences.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->fluence,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of fluences in kernel_fluences file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-	
-	if ( (fid = fopen(mu_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel mu file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->mu = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel mu.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->mu,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of mu values in kernel_mu file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	if ( (fid = fopen(mu_en_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel mu_en file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->mu_en = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel mu_en.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->mu_en,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of mu_en values in kernel_mu_en file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	// Only assign memory for bin boundaries for the first kernel. Just point the other
-	// boundary pointers at the values in the first kernel.
-
-	if ( (fid = fopen(radii_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel radii file.");
-		return(FAILURE);
-	}
-	else
-	{
-		mono_kernels->kernel[0].nradii = Nradii;
-		if( (mono_kernels->kernel[0].radial_boundary = (float *)malloc(sizeof(float)*Nradii)) == NULL)
-		{
-			sprintf(errstr,"Failed to allocate memory for radial boundaries.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->kernel[0].radial_boundary,sizeof(float),Nradii,fid) != Nradii)
-		{
-			sprintf(errstr,"Incorrect number of radii values in kernel_radii file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-	
-	if ( (fid = fopen(angles_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel angles file.");
-		return(FAILURE);
-	}
-	else
-	{
-		mono_kernels->kernel[0].ntheta = Nangles;
-		if( (mono_kernels->kernel[0].angular_boundary = (float *)malloc(sizeof(float)*Nangles)) == NULL)
-		{
-			sprintf(errstr,"Failed to allocate memory for angular boundaries.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->kernel[0].angular_boundary,sizeof(float),Nangles,fid) != Nangles)
-		{
-			sprintf(errstr,"Incorrect number of angular values in kernel_angles file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	// allocate space for kernel matrices and copy bin boundaries for other kernel categories
-	for (j=0;j<Nenergies;j++)  // loop through energies
-	{
-		if (j != 0)
-		{
-			mono_kernels->kernel[j].nradii = Nradii;
-			mono_kernels->kernel[j].ntheta = Nangles;
-	
-			mono_kernels->kernel[j].radial_boundary = mono_kernels->kernel[0].radial_boundary;
-			mono_kernels->kernel[j].angular_boundary = mono_kernels->kernel[0].angular_boundary;
-		}
-
-		// allocate space for kernels
-		for (k=0;k<N_KERNEL_CATEGORIES;k++)
-			if ((mono_kernels->kernel[j].matrix[k] 
-				= (float *)malloc(sizeof(float)*Nradii*Nangles*N_KERNEL_CATEGORIES)) == NULL)
-			{
-				sprintf(errstr,"Failed to allocate memory for kernel matrix.");
-				return(FAILURE);
-			}
-	}
-	
-	// load-in the kernels one at a time and fill-up the monoenergetic kernels
-	
-	// open the kernel files
-	if ( (primary = fopen(primary_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing primary kernel.");
-		return(FAILURE);
-	}
-
-	if ( (first = fopen(first_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing first scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (second = fopen(second_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing second scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (multiple = fopen(multiple_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing multiple scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (brem_annih = fopen(brem_annih_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing brem_annih kernel.");
-		return(FAILURE);
-	}
-
-	if ( (total = fopen(total_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing total kernel.");
-		return(FAILURE);
-	}
-
-	// loop through all energies, reading the kernel files in to the kernel structures
-	for (j=0;j<Nenergies;j++)
-	{
-		if ( (int)fread(mono_kernels->kernel[j].matrix[0],sizeof(float),Nradii*Nangles,primary) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[1],sizeof(float),Nradii*Nangles,first) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[2],sizeof(float),Nradii*Nangles,second) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[3],sizeof(float),Nradii*Nangles,multiple) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[4],sizeof(float),Nradii*Nangles,brem_annih) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-	}
-
-	// close the kernel files
-	fclose(primary);
-	fclose(first);
-	fclose(second);
-	fclose(multiple);
-	fclose(brem_annih);
-
-	return(SUCCESS);
-}
-
-int load_geometry(FLOAT_GRID *density, char geometry_filenames[])
-/* Ensure that the GEOMETRY structure has the following format:
-  Geometry = 
-
-         start: [3 element float]
-    voxel_size: [3 element float]
-          data: [M x N x Q float]
-          beam: [1x1 struct] 
-		  
- Geometry.beam = 
-
-    ip: [3 element float]
-    jp: [3 element float]
-    kp: [3 element float]
-     y_vec: [3 element float]
-        xp: [float scalar]
-        yp: [float scalar]
-    del_xp: [float scalar]
-    del_yp: [float scalar]
-	   SAD: [float scalar]
-	
-
-	and load the data into memory.  
-
-The names of the files containing the above data are listed in two files:
-geometry_filenames and beam_filenames.  The beam data are stored in a 
-separate file since many dose calculations are done by changing the 
-beam data and leaving the geometry data constant.  This way one can use
-a separate beam file for each beam but the same geometry file.
-*/
-{
-	int Ntotal;
-	char str[200];   // dummy string
-	char header_filename[200], density_filename[200];
-	// flags for filename readin
-	int header_flag = 0;
-	int density_flag = 0;
-	FILE *fid;          // dummy filename
-
-	// read in the geometry filenames
-	if ( (fid = fopen(geometry_filenames,"r")) == NULL)  // open the geometry filenames
-	{
-	  sprintf(errstr,"Could not open the geometry filenames file\n");
-	  return(FAILURE);
-	}
-
-	// read in the non-beam geometric data
-	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
-	{
-	  if (!strcmp(str,geometry_header_line))
-	    if (fscanf(fid,"%s\n",header_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the geometry_header filename from the geometry filenames file.");
-		}
-	    else
-	      header_flag = 1;
-	  else if (!strcmp(str,geometry_density_line))
-	    if (fscanf(fid,"%s\n",density_filename) != 1)
-		{
-	        sprintf(errstr,"Failed to read-in the geometry_density filename from the geometry filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      density_flag = 1;
-	  else
-	  {   
-			sprintf("Unrecognized string in the geometry filenames file: %s\n",str);
-			return(FAILURE);   
-	  }
-	}
-	
-    // confirm that all of the required filenames have been found
-	if (header_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a geometry header filename.\n");
-	  return(FAILURE);
-	}
-	else if (density_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a geometry density filename.\n");
-	  return(FAILURE);
-	}
-
-	// read in geometric and beam data
-	if( (fid = fopen(header_filename,"r")) == NULL)
-	{
-		sprintf(errstr,"Could not open geometry header file.");
-		return(FAILURE);
-	}
-	else
-	{
-		// pop-off the first line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%d %d %d\n",&density->x_count,&density->y_count,&density->z_count) != 3)
-		{
-			sprintf(errstr,"Could not read-in data grid size.");
-			return(FAILURE);
-		}
-		
-		// pop-off the next line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header  file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%f %f %f\n",&density->start.x,&density->start.y,&density->start.z) != 3)
-		{
-			sprintf(errstr,"Could not read-in density grid start position.");
-			return(FAILURE);
-		}
-
-		// pop-off the next line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%f %f %f\n",&density->inc.x,&density->inc.y,&density->inc.z) != 3)
-		{
-			sprintf(errstr,"Could not read-in voxel size vector.");
-			return(FAILURE);
-		}
-
-		Ntotal = density->x_count*density->y_count*density->z_count;
-	}
-
-	// read-in the CT density data
-	if( (fid = fopen(density_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Could not open CT density file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if( (density->matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-		{
-			sprintf(errstr,"Unable to allocate space for CT density grid.");
-			return(FAILURE);
-		}
-		else if ((int)fread(density->matrix,sizeof(float),Ntotal,fid) != Ntotal)
-		{
-			sprintf(errstr,"Unable to read-in CT density data.");
-			return(FAILURE);
-		}
-	}
-	return(SUCCESS);
-}
-
-int pop_beam(BEAM *bm, FILE *beamspec_batch_file)
-/*  Pops a beam off of the beamspec_batch_file file and loads it into a BEAM structure.
-
-  Ensure that the beam data file has the following format:
- Geometry.beam = 
-
-        ip: [3 element float]
-        jp: [3 element float]
-        kp: [3 element float]
-     y_vec: [3 element float]
-        xp: [float scalar]
-        yp: [float scalar]
-    del_xp: [float scalar]
-    del_yp: [float scalar]
-	   SAD: [float scalar]
-	   num: [int scalar]
-	
-	and load the data into memory.  
-*/
-{
-	char str[200];      // dummy string
-
-	// read-in the beam data
-	// pop-off the first line of the beam data file
-
-	// read-in the CT data grid size
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		return(FAILURE);
-	}
-
-	if (fscanf(beamspec_batch_file,"%d\n",&bm->num) != 1)
-	{
-		sprintf(errstr,"Could not read-in beam data.");
-		return(FAILURE);
-	}
-
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the CT data grid size
-	if (fscanf(beamspec_batch_file,"%f %f %f %f %f\n",&bm->SAD,&bm->xp,&bm->yp,&bm->del_xp,&bm->del_yp) != 5)
-	{
-		sprintf(errstr,"Could not read-in beam data.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the source position vector
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->y_vec[0],&bm->y_vec[1],&bm->y_vec[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in source location vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the beam's eye view vectors, ip first
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->ip[0],&bm->ip[1],&bm->ip[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in ip vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the second beam's eye view vector, jp
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->jp[0],&bm->jp[1],&bm->jp[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in jp vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the third beam's eye view vector, kp
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->kp[0],&bm->kp[1],&bm->kp[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in kp vector.");
-		return(FAILURE);
-	}
-	
-	// ensure that ip,jp,kp are orthonormal and form a right-handed coordinate system
-	if (   (fabs(bm->ip[0]*bm->ip[0] + bm->ip[1]*bm->ip[1] + bm->ip[2]*bm->ip[2] - 1.0) > 1e-6)
-		|| (fabs(bm->jp[0]*bm->jp[0] + bm->jp[1]*bm->jp[1] + bm->jp[2]*bm->jp[2] - 1.0) > 1e-6)
-		|| (fabs(bm->kp[0]*bm->kp[0] + bm->kp[1]*bm->kp[1] + bm->kp[2]*bm->kp[2] - 1.0) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->jp[0] + bm->ip[1]*bm->jp[1] + bm->ip[2]*bm->jp[2]) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->kp[0] + bm->ip[1]*bm->kp[1] + bm->ip[2]*bm->kp[2]) > 1e-6)
-		|| (fabs(bm->jp[0]*bm->kp[0] + bm->jp[1]*bm->kp[1] + bm->jp[2]*bm->kp[2]) > 1e-6))
-	{
-		sprintf(errstr,"Beam's eye view unit vectors ip, jp, and kp must be orthonormal.");
-		return(FAILURE);
-	}
-
-	// check that cross(ip,jp) = kp
-	if (   (fabs(bm->ip[1]*bm->jp[2] - bm->ip[2]*bm->jp[1] - bm->kp[0]) > 1e-6)
-		|| (fabs(bm->ip[2]*bm->jp[0] - bm->ip[0]*bm->jp[2] - bm->kp[1]) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->jp[1] - bm->ip[1]*bm->jp[0] - bm->kp[2]) > 1e-6))
-	{
-		sprintf(errstr,"Must have cross(ip,jp) = kp for beam's eye view");
-		return(FAILURE);
-	}
-
-	return(SUCCESS);
-}
+/* parse_func.cpp */
+
+/* Checks the validity of the arguments input to the convolution routine and 
+transfers the Matlab-style arguments to the C structures defined in defs.h. */
+
+/* This parse function operates on file inputs rather than on Matlab inputs. */
+
+#include "defs.h"
+
+// Markers that are searched for inside the kernel_filenames file, which is 
+// passed to the load_kernels routine. The line after each of these markers
+// in the kernel_filenames file is a filename corresponding to the marker.
+#define kernel_header_line "kernel_header"
+#define kernel_radii_line "kernel_radii"
+#define kernel_angles_line "kernel_angles"
+#define kernel_energies_line "kernel_energies"
+#define kernel_primary_line "kernel_primary"
+#define kernel_first_scatter_line "kernel_first_scatter"
+#define kernel_second_scatter_line "kernel_second_scatter"
+#define kernel_multiple_scatter_line "kernel_multiple_scatter"
+#define kernel_brem_annih_line "kernel_brem_annih"
+#define kernel_total_line "kernel_total"
+#define kernel_fluence_line "kernel_fluence"
+#define kernel_mu_line "kernel_mu"
+#define kernel_mu_en_line "kernel_mu_en"
+
+// Markers that are searched for inside the geometry_filenames, which is 
+// passed to the load_geometry routine. These have the same meaning as
+// the kernel_filenames markers.
+#define geometry_header "./geometry_files/geometry_header.txt"
+#define geometry_density "./geometry_files/density.bin"
+#define beam_data "./geometry_files/beam_data.txt"
+
+#define geometry_header_line "geometry_header"
+#define geometry_density_line "geometry_density"
+#define beam_data_line "beam_data"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int load_kernels(MONO_KERNELS *mono_kernels, char kernel_filenames[])
+/* Ensures that the kernel files have the following format:
+
+               radii: [1xNradii float]
+              angles: [1xNangles float]
+            energies: [1xNenergies float]
+             primary: [Nradii x Nangles x Nenergies float]
+       first_scatter: [Nradii x Nangles x Nenergies float]
+      second_scatter: [Nradii x Nangles x Nenergies float]
+    multiple_scatter: [Nradii x Nangles x Nenergies float]
+          brem_annih: [Nradii x Nangles x Nenergies float]
+               total: [Nradii x Nangles x Nenergies float]
+          mean_radii: [Nradii x Nangles x Nenergies float] (not used)
+         mean_angles: [Nradii x Nangles x Nenergies float] (not used)
+           helpfield: [any x any char] 
+             fluence: [1xNenergies float]
+                  mu: [1xNenergies float]
+               mu_en: [1xNenergies float]
+
+mistakes or inconsistencies will result in errors.
+
+  Results are then stored in mono_kernels.
+
+The names of the files containing all of these parameters are given
+by the kernel_filenames file.
+
+*/
+{
+	int j,k;
+	int Nenergies, Nangles, Nradii;
+	char str[200];
+	// some strings to hold filenames
+	char header_filename[200], radii_filename[200], angles_filename[200];
+	char energies_filename[200], primary_filename[200], first_scatter_filename[200];
+	char second_scatter_filename[200], multiple_scatter_filename[200];
+	char brem_annih_filename[200], total_filename[200], fluence_filename[200];
+	char mu_filename[200], mu_en_filename[200];
+
+	// flags for file readin
+	int header_flag = 0;
+	int radii_flag = 0;
+	int angles_flag = 0;
+	int energies_flag = 0;
+	int primary_flag = 0;
+	int first_flag = 0;
+	int second_flag = 0;
+	int multiple_flag = 0;
+	int brem_annih_flag = 0;
+	int total_flag = 0;
+	int fluence_flag = 0;
+	int mu_flag = 0;
+	int mu_en_flag = 0;
+
+	FILE *fid;  // generic filename
+	FILE *primary, *first, *second, *multiple, *brem_annih, *total;  // kernel files
+
+	// read in the data filenames
+	if ( (fid = fopen(kernel_filenames,"r")) == NULL)  // open the kernel filenames
+	{
+		sprintf(errstr,"Could not open the kernel filenames file");
+		return(FAILURE);
+	}
+
+	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
+	{
+	  if (!strcmp(str,kernel_header_line))
+	    if (fscanf(fid,"%s\n",header_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_header filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      header_flag = 1;
+	  else if (!strcmp(str,kernel_radii_line))
+	    if (fscanf(fid,"%s\n",radii_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_radii filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      radii_flag = 1;
+	  else if (!strcmp(str,kernel_angles_line))
+	    if (fscanf(fid,"%s\n",angles_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_angles filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+            else
+	      angles_flag = 1;
+	  else if (!strcmp(str,kernel_energies_line))
+        if (fscanf(fid,"%s\n",energies_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_energies filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      energies_flag = 1;
+          else if (!strcmp(str,kernel_fluence_line))
+	    if (fscanf(fid,"%s\n",fluence_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_fluence filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      fluence_flag = 1;
+	  else if (!strcmp(str,kernel_primary_line))
+        if (fscanf(fid,"%s\n",primary_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_primary filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      primary_flag = 1;
+	  else if (!strcmp(str,kernel_first_scatter_line))
+        if (fscanf(fid,"%s\n",first_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_first_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      first_flag = 1;
+	  else if (!strcmp(str,kernel_second_scatter_line))
+	    if (fscanf(fid,"%s\n",second_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_second_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      second_flag = 1;
+	  else if (!strcmp(str,kernel_multiple_scatter_line))
+        if (fscanf(fid,"%s\n",multiple_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_multiple_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      multiple_flag = 1;
+	  else if (!strcmp(str,kernel_brem_annih_line))
+	    if (fscanf(fid,"%s\n",brem_annih_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_brem_annih filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else 
+	      brem_annih_flag = 1;
+	  else if (!strcmp(str,kernel_total_line))
+	    if (fscanf(fid,"%s\n",total_filename) != 1)
+	    {
+			sprintf(errstr,"Failed to read-in the kernel_total filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      total_flag = 1;
+	  else if (!strcmp(str,kernel_mu_line))
+	    if (fscanf(fid,"%s\n",mu_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_mu filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      mu_flag = 1;
+	  else if (!strcmp(str,kernel_mu_en_line))
+	    if (fscanf(fid,"%s\n",mu_en_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_mu_en filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      mu_en_flag = 1;
+	  else
+	  {   
+		    sprintf(errstr,"Unrecognized string in the kernel filenames file: %s\n",str);
+			return(FAILURE);   
+	  }
+	}
+
+	// confirm that all of the required filenames have been found
+	if (header_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel header filename.");
+	  return(FAILURE);
+	}
+	else if (radii_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel radii filename.");
+	  return(FAILURE);
+	}
+	else if (angles_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel angles filename.");
+	  return(FAILURE);
+	}
+	else if (energies_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel energies filename.");
+	  return(FAILURE);
+	}
+	else if (primary_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a primary kernel filename.");
+	  return(FAILURE);
+	}
+	else if (first_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a first scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (second_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a second scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (multiple_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a multiple scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (brem_annih_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a brem_annih kernel filename.");
+	  return(FAILURE);
+	}
+	else if (total_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a total kernel filename.");
+	  return(FAILURE);
+	}
+	else if (fluence_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel fluence filename.");
+	  return(FAILURE);
+	}
+	else if (mu_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel mu filename.");
+	  return(FAILURE);
+	}
+	else if (mu_en_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel mu_en filename.");
+	  return(FAILURE);
+	}
+
+	// read in the expected matrix sizes
+	if ( (fid=fopen(header_filename,"r")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel header file in kernel data folder.");
+		return(FAILURE);
+	}
+	else
+	{   
+		fgets(str,100,fid); // pop-off the first line of the header
+		if (fscanf(fid,"%d %d %d\n",&Nradii,&Nangles,&Nenergies) != 3)
+		{
+			sprintf(errstr,"Incorrect amount of data in kernel header file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	mono_kernels->nkernels = Nenergies;
+
+	// read in the energies, fluences, mu, and mu_en values
+	if ( (fid = fopen(energies_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel energies file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->energy = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel energies.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->energy,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of energies in kernel_energies file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	if ( (fid = fopen(fluence_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel fluences file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->fluence = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel fluences.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->fluence,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of fluences in kernel_fluences file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+	
+	if ( (fid = fopen(mu_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel mu file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->mu = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel mu.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->mu,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of mu values in kernel_mu file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	if ( (fid = fopen(mu_en_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel mu_en file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->mu_en = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel mu_en.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->mu_en,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of mu_en values in kernel_mu_en file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	// Only assign memory for bin boundaries for the first kernel. Just point the other
+	// boundary pointers at the values in the first kernel.
+
+	if ( (fid = fopen(radii_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel radii file.");
+		return(FAILURE);
+	}
+	else
+	{
+		mono_kernels->kernel[0].nradii = Nradii;
+		if( (mono_kernels->kernel[0].radial_boundary = (float *)malloc(sizeof(float)*Nradii)) == NULL)
+		{
+			sprintf(errstr,"Failed to allocate memory for radial boundaries.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->kernel[0].radial_boundary,sizeof(float),Nradii,fid) != Nradii)
+		{
+			sprintf(errstr,"Incorrect number of radii values in kernel_radii file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+	
+	if ( (fid = fopen(angles_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel angles file.");
+		return(FAILURE);
+	}
+	else
+	{
+		mono_kernels->kernel[0].ntheta = Nangles;
+		if( (mono_kernels->kernel[0].angular_boundary = (float *)malloc(sizeof(float)*Nangles)) == NULL)
+		{
+			sprintf(errstr,"Failed to allocate memory for angular boundaries.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->kernel[0].angular_boundary,sizeof(float),Nangles,fid) != Nangles)
+		{
+			sprintf(errstr,"Incorrect number of angular values in kernel_angles file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	// allocate space for kernel matrices and copy bin boundaries for other kernel categories
+	for (j=0;j<Nenergies;j++)  // loop through energies
+	{
+		if (j != 0)
+		{
+			mono_kernels->kernel[j].nradii = Nradii;
+			mono_kernels->kernel[j].ntheta = Nangles;
+	
+			mono_kernels->kernel[j].radial_boundary = mono_kernels->kernel[0].radial_boundary;
+			mono_kernels->kernel[j].angular_boundary = mono_kernels->kernel[0].angular_boundary;
+		}
+
+		// allocate space for kernels
+		for (k=0;k<N_KERNEL_CATEGORIES;k++)
+			if ((mono_kernels->kernel[j].matrix[k] 
+				= (float *)malloc(sizeof(float)*Nradii*Nangles*N_KERNEL_CATEGORIES)) == NULL)
+			{
+				sprintf(errstr,"Failed to allocate memory for kernel matrix.");
+				return(FAILURE);
+			}
+	}
+	
+	// load-in the kernels one at a time and fill-up the monoenergetic kernels
+	
+	// open the kernel files
+	if ( (primary = fopen(primary_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing primary kernel.");
+		return(FAILURE);
+	}
+
+	if ( (first = fopen(first_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing first scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (second = fopen(second_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing second scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (multiple = fopen(multiple_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing multiple scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (brem_annih = fopen(brem_annih_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing brem_annih kernel.");
+		return(FAILURE);
+	}
+
+	if ( (total = fopen(total_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing total kernel.");
+		return(FAILURE);
+	}
+
+	// loop through all energies, reading the kernel files in to the kernel structures
+	for (j=0;j<Nenergies;j++)
+	{
+		if ( (int)fread(mono_kernels->kernel[j].matrix[0],sizeof(float),Nradii*Nangles,primary) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[1],sizeof(float),Nradii*Nangles,first) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[2],sizeof(float),Nradii*Nangles,second) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[3],sizeof(float),Nradii*Nangles,multiple) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[4],sizeof(float),Nradii*Nangles,brem_annih) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+	}
+
+	// close the kernel files
+	fclose(primary);
+	fclose(first);
+	fclose(second);
+	fclose(multiple);
+	fclose(brem_annih);
+
+	return(SUCCESS);
+}
+
+int load_geometry(FLOAT_GRID *density, char geometry_filenames[])
+/* Ensure that the GEOMETRY structure has the following format:
+  Geometry = 
+
+         start: [3 element float]
+    voxel_size: [3 element float]
+          data: [M x N x Q float]
+          beam: [1x1 struct] 
+		  
+ Geometry.beam = 
+
+    ip: [3 element float]
+    jp: [3 element float]
+    kp: [3 element float]
+     y_vec: [3 element float]
+        xp: [float scalar]
+        yp: [float scalar]
+    del_xp: [float scalar]
+    del_yp: [float scalar]
+	   SAD: [float scalar]
+	
+
+	and load the data into memory.  
+
+The names of the files containing the above data are listed in two files:
+geometry_filenames and beam_filenames.  The beam data are stored in a 
+separate file since many dose calculations are done by changing the 
+beam data and leaving the geometry data constant.  This way one can use
+a separate beam file for each beam but the same geometry file.
+*/
+{
+	int Ntotal;
+	char str[200];   // dummy string
+	char header_filename[200], density_filename[200];
+	// flags for filename readin
+	int header_flag = 0;
+	int density_flag = 0;
+	FILE *fid;          // dummy filename
+
+	// read in the geometry filenames
+	if ( (fid = fopen(geometry_filenames,"r")) == NULL)  // open the geometry filenames
+	{
+	  sprintf(errstr,"Could not open the geometry filenames file\n");
+	  return(FAILURE);
+	}
+
+	// read in the non-beam geometric data
+	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
+	{
+	  if (!strcmp(str,geometry_header_line))
+	    if (fscanf(fid,"%s\n",header_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the geometry_header filename from the geometry filenames file.");
+		}
+	    else
+	      header_flag = 1;
+	  else if (!strcmp(str,geometry_density_line))
+	    if (fscanf(fid,"%s\n",density_filename) != 1)
+		{
+	        sprintf(errstr,"Failed to read-in the geometry_density filename from the geometry filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      density_flag = 1;
+	  else
+	  {   
+			sprintf("Unrecognized string in the geometry filenames file: %s\n",str);
+			return(FAILURE);   
+	  }
+	}
+	
+    // confirm that all of the required filenames have been found
+	if (header_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a geometry header filename.\n");
+	  return(FAILURE);
+	}
+	else if (density_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a geometry density filename.\n");
+	  return(FAILURE);
+	}
+
+	// read in geometric and beam data
+	if( (fid = fopen(header_filename,"r")) == NULL)
+	{
+		sprintf(errstr,"Could not open geometry header file.");
+		return(FAILURE);
+	}
+	else
+	{
+		// pop-off the first line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%d %d %d\n",&density->x_count,&density->y_count,&density->z_count) != 3)
+		{
+			sprintf(errstr,"Could not read-in data grid size.");
+			return(FAILURE);
+		}
+		
+		// pop-off the next line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header  file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%f %f %f\n",&density->start.x,&density->start.y,&density->start.z) != 3)
+		{
+			sprintf(errstr,"Could not read-in density grid start position.");
+			return(FAILURE);
+		}
+
+		// pop-off the next line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%f %f %f\n",&density->inc.x,&density->inc.y,&density->inc.z) != 3)
+		{
+			sprintf(errstr,"Could not read-in voxel size vector.");
+			return(FAILURE);
+		}
+
+		Ntotal = density->x_count*density->y_count*density->z_count;
+	}
+
+	// read-in the CT density data
+	if( (fid = fopen(density_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Could not open CT density file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if( (density->matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+		{
+			sprintf(errstr,"Unable to allocate space for CT density grid.");
+			return(FAILURE);
+		}
+		else if ((int)fread(density->matrix,sizeof(float),Ntotal,fid) != Ntotal)
+		{
+			sprintf(errstr,"Unable to read-in CT density data.");
+			return(FAILURE);
+		}
+	}
+	return(SUCCESS);
+}
+
+int pop_beam(BEAM *bm, FILE *beamspec_batch_file)
+/*  Pops a beam off of the beamspec_batch_file file and loads it into a BEAM structure.
+
+  Ensure that the beam data file has the following format:
+ Geometry.beam = 
+
+        ip: [3 element float]
+        jp: [3 element float]
+        kp: [3 element float]
+     y_vec: [3 element float]
+        xp: [float scalar]
+        yp: [float scalar]
+    del_xp: [float scalar]
+    del_yp: [float scalar]
+	   SAD: [float scalar]
+	   num: [int scalar]
+	
+	and load the data into memory.  
+*/
+{
+	char str[200];      // dummy string
+
+	// read-in the beam data
+	// pop-off the first line of the beam data file
+
+	// read-in the CT data grid size
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		return(FAILURE);
+	}
+
+	if (fscanf(beamspec_batch_file,"%d\n",&bm->num) != 1)
+	{
+		sprintf(errstr,"Could not read-in beam data.");
+		return(FAILURE);
+	}
+
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the CT data grid size
+	if (fscanf(beamspec_batch_file,"%f %f %f %f %f\n",&bm->SAD,&bm->xp,&bm->yp,&bm->del_xp,&bm->del_yp) != 5)
+	{
+		sprintf(errstr,"Could not read-in beam data.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the source position vector
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->y_vec[0],&bm->y_vec[1],&bm->y_vec[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in source location vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the beam's eye view vectors, ip first
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->ip[0],&bm->ip[1],&bm->ip[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in ip vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the second beam's eye view vector, jp
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->jp[0],&bm->jp[1],&bm->jp[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in jp vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the third beam's eye view vector, kp
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->kp[0],&bm->kp[1],&bm->kp[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in kp vector.");
+		return(FAILURE);
+	}
+	
+	// ensure that ip,jp,kp are orthonormal and form a right-handed coordinate system
+	if (   (fabs(bm->ip[0]*bm->ip[0] + bm->ip[1]*bm->ip[1] + bm->ip[2]*bm->ip[2] - 1.0) > 1e-6)
+		|| (fabs(bm->jp[0]*bm->jp[0] + bm->jp[1]*bm->jp[1] + bm->jp[2]*bm->jp[2] - 1.0) > 1e-6)
+		|| (fabs(bm->kp[0]*bm->kp[0] + bm->kp[1]*bm->kp[1] + bm->kp[2]*bm->kp[2] - 1.0) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->jp[0] + bm->ip[1]*bm->jp[1] + bm->ip[2]*bm->jp[2]) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->kp[0] + bm->ip[1]*bm->kp[1] + bm->ip[2]*bm->kp[2]) > 1e-6)
+		|| (fabs(bm->jp[0]*bm->kp[0] + bm->jp[1]*bm->kp[1] + bm->jp[2]*bm->kp[2]) > 1e-6))
+	{
+		sprintf(errstr,"Beam's eye view unit vectors ip, jp, and kp must be orthonormal.");
+		return(FAILURE);
+	}
+
+	// check that cross(ip,jp) = kp
+	if (   (fabs(bm->ip[1]*bm->jp[2] - bm->ip[2]*bm->jp[1] - bm->kp[0]) > 1e-6)
+		|| (fabs(bm->ip[2]*bm->jp[0] - bm->ip[0]*bm->jp[2] - bm->kp[1]) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->jp[1] - bm->ip[1]*bm->jp[0] - bm->kp[2]) > 1e-6))
+	{
+		sprintf(errstr,"Must have cross(ip,jp) = kp for beam's eye view");
+		return(FAILURE);
+	}
+
+	return(SUCCESS);
+}

+ 345 - 345
WiscPlan-SourceCode/Source-code-photon-windows/raytrace.cpp

@@ -1,345 +1,345 @@
-/* C_RAYTRACE.C ***************************************************************/
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int raytrace(FLOAT_GRID *electron_density_grid,FLOAT_GRID *radiological_depth_grid,
-             POINT point1,POINT point2)
-/*
---------------------------------------------------------------------------------
-   NAME
- 	c_raytrace
- 
-   SYNOPSIS
-        point1 and point2 are the end points of the ray. 
-
-   DESCRIPTION
-        This function traces the ray from point x to point y (in real 
-        coords), assigning depth to any voxels which that ray crosses. The 
-        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
-        1985). This routine will not be understood without thorough reading 
-        of that paper! Point1 and point2 are the start and end points of the 
-        ray, respectively. External structures of type GRID are assumed to 
-        exist, where electron_density_grid are the electron densities, and 
-        radiological_depth_grid is the output grid for these calculations.
-        Voxels in radiological_depth_grid are initially set -ve prior to 
-        calling this function.
- 
-   AUTHOR
-        Written by David C. Murray
-                   University of Waikato
-                   Private Bag 3105
-                   Hamilton
-                   New Zealand
-        and Copyright (1991) to
-                   David C. Murray and Peter W. Hoban,
-                   Cancer Society of New Zealand Inc., and 
-                   University of Waikato.
---------------------------------------------------------------------------------
-*/
-
-{
-/* Variable descriptions:
-   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
-     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
-   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
-   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
-   dx,dy,dz are the widths in cm of the voxels
-*/
-float         x1,y1,z1,
-              x2,y2,z2,
-              xp1,yp1,zp1,
-              dx,dy,dz;
-int           Nx,Ny,Nz;
-
-/*General ray-trace algorithm variables*/
-float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
-float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
-					/*limits of alpha x,y,z parameters*/
-float alpha_min, alpha_max;		/*limits of alpha parameter*/
-int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
-float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
-float *alpha;				/*holds merged set of alpha values*/
-int i_index,j_index,k_index;		/*loop indices for merging alphas*/
-int a;					/*loop counter*/
-int max_index;				/*max index of merged alpha array*/
-float d12;				/*distance between ray end points*/
-float alpha_mid;			/*mid-point of intersection length*/
-float length;				/*intersection length*/
-int i,j,k;				/*indices of voxel with int. length*/
-float rpl = 0.0;			/*radiological path length in cm*/
-float voxel_density;			/*temporary voxel density*/
-float lmax;  // best possible penetration pathlength for a voxel
-float pnorm;  // absolute difference between p1 and p2
-
-/* Assign variables */
-/******************************************************************************/
-x1 = point1.x;
-y1 = point1.y;
-z1 = point1.z;
-x2 = point2.x;
-y2 = point2.y;
-z2 = point2.z;
-Nx = electron_density_grid->x_count + 1;
-Ny = electron_density_grid->y_count + 1;
-Nz = electron_density_grid->z_count + 1;
-dx = electron_density_grid->inc.x;
-dy = electron_density_grid->inc.y;
-dz = electron_density_grid->inc.z;
-
-// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
-xp1 = electron_density_grid->start.x - 0.5*dx;
-yp1 = electron_density_grid->start.y - 0.5*dy;
-zp1 = electron_density_grid->start.z - 0.5*dz;
-
-pnorm = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
-
-// this is the largest pathlength possible for a ray through a voxel:
-lmax = sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
-
-/* Calculate xpN,ypN,zpN */
-/******************************************************************************/
-xpN = xp1 + (Nx-1)*dx;
-ypN = yp1 + (Ny-1)*dy;
-zpN = zp1 + (Nz-1)*dz;
-
-/*Calculate alpha_min and alpha_max*/
-/******************************************************************************/
-/*Avoid division by zero*/
-if (x1==x2)
-  x2 += 0.00001;
-if (y1==y2)
-  y2 += 0.00001;
-if (z1==z2)
-  z2 += 0.00001;
-if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
-{
-	sprintf(errstr,"Error - ray trace region too small.");
-	return(FAILURE);
-}
-
-alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
-if (alpha_z_min>alpha_min) 
-  alpha_min = alpha_z_min;
-if (alpha_min<0)
-  alpha_min = 0;
-alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
-if (alpha_z_max<alpha_max) 
-  alpha_max = alpha_z_max;
-if (alpha_max>1)
-  alpha_max = 1;
-
-// Monitor lines...
-/*
-printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
-                alpha_x_min,alpha_y_min,alpha_z_min);
-printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
-                alpha_x_max,alpha_y_max,alpha_z_max);
-printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
-printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx); */
-
-/*Determine the ranges of i,j,k indices*/
-/******************************************************************************/
-/*The following assignments require conversion from float to integer types*/
-/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
-/*functions convert to the correct value. Note that the range of these*/
-/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
-		
-i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
-                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
-i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
-                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
-j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
-                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
-j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
-                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
-k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
-                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
-k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
-                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
-
-/*Monitor lines...
-fprintf(stdout,"    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
-fprintf(stdout,"    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max);
-*/
-/*Generate sets of alpha values,reversing order if necessary*/
-/******************************************************************************/
-/*allocate array space on stack*/
-if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
-	return(FAILURE);
-}
-
-/* 
-printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
-printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
-printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
- 
-if (i_min <= i_max)
-  if (x2>x1)
-    {
-    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=1;a<=i_max-i_min;a++)
-      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
-    }
-  else
-    {
-    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=i_max-i_min-1;a>=0;a--)
-      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
-    }
-alpha_x[i_max-i_min+1] = 10000.0;
-if (j_min <= j_max)
-  if (y2>y1)
-    {
-    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=1;a<=j_max-j_min;a++)
-      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
-    }
-  else
-    {
-    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=j_max-j_min-1;a>=0;a--)
-      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
-    }
-alpha_y[j_max-j_min+1] = 10001.0;
-if (k_min <= k_max)
-  if (z2>z1)
-    {
-    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=1;a<=k_max-k_min;a++)
-      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
-    }
-  else
-    {
-    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=k_max-k_min-1;a>=0;a--)
-      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
-  }
-alpha_z[k_max-k_min+1] = 10002.0; 
-
-
-/*Monitor lines...
-if (i_max<i_min)
-  fprintf(stdout,"    No alpha_x values\n");
-else
-  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
-                 alpha_x[0],alpha_x[i_max-i_min]);
-if (j_max<j_min)
-  fprintf(stdout,"    No alpha_y values\n");
-else
-  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
-                 alpha_y[0],alpha_y[j_max-j_min]);
-if (k_max<k_min)
-  fprintf(stdout,"    No alpha_z values\n");
-else
-  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
-                 alpha_z[0],alpha_z[k_max-k_min]);
-*/
-/*Generate merged set of alpha values*/
-
-
-/******************************************************************************/
-if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
-	return(FAILURE);
-}
-
-max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
-alpha[0] = alpha_min;
-i_index = 0;
-j_index = 0;
-k_index = 0;
-for (a=1;a<=max_index-1;a++)
-  if (alpha_x[i_index]<alpha_y[j_index])
-    if (alpha_x[i_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_x[i_index];
-      i_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-  else
-    if (alpha_y[j_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_y[j_index];
-      j_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-alpha[max_index] = alpha_max;
-free(alpha_x);				//deallocate temp array storage
-free(alpha_y);
-free(alpha_z);
-/*Monitor lines...
-fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
-for (a=0;a<=max_index;a++)
-  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
-*/
-/*Calculate voxel lengths and indices, and assign radiological depth*/
-/******************************************************************************/
-d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
-					//d12 is distance between ray end pts
-// printf("made it this far in raytrace.\n");
-for (a=1;a<=max_index;a++)
-  {
-  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
-  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
-    {
-    alpha_mid = (alpha[a]+alpha[a-1])/2.0;
-					//alpha_mid is middle of int. length
-    i = (int) floor((x1 + alpha_mid*(x2-x1) - xp1)/dx);
-    j = (int) floor((y1 + alpha_mid*(y2-y1) - yp1)/dy);
-    k = (int) floor((z1 + alpha_mid*(z2-z1) - zp1)/dz);
-					//i,j,k are indices of voxel
-
-    // Remember that this function traces only a single ray.
-    // rpl has been set to zero during initialisation.
-
-    voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
-    rpl += length * voxel_density/2.0;  // add first half of int. length
-    // store pathlength only if the voxel is intersected almost directly
-	// by the ray
-    if (length>=0.75/2*lmax && GRID_VALUE(radiological_depth_grid,i,j,k)<0.0)
-      GRID_VALUE(radiological_depth_grid, i, j, k) = rpl;
-    
-    rpl += length * voxel_density/2.0;  //add second half of int. length  
-    }    
-  } 
-free(alpha); 			//deallocate remaining array storage 
-
-return(SUCCESS);
-
-} 					/*End of s_raytrace routine*/
+/* C_RAYTRACE.C ***************************************************************/
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int raytrace(FLOAT_GRID *electron_density_grid,FLOAT_GRID *radiological_depth_grid,
+             POINT point1,POINT point2)
+/*
+--------------------------------------------------------------------------------
+   NAME
+ 	c_raytrace
+ 
+   SYNOPSIS
+        point1 and point2 are the end points of the ray. 
+
+   DESCRIPTION
+        This function traces the ray from point x to point y (in real 
+        coords), assigning depth to any voxels which that ray crosses. The 
+        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
+        1985). This routine will not be understood without thorough reading 
+        of that paper! Point1 and point2 are the start and end points of the 
+        ray, respectively. External structures of type GRID are assumed to 
+        exist, where electron_density_grid are the electron densities, and 
+        radiological_depth_grid is the output grid for these calculations.
+        Voxels in radiological_depth_grid are initially set -ve prior to 
+        calling this function.
+ 
+   AUTHOR
+        Written by David C. Murray
+                   University of Waikato
+                   Private Bag 3105
+                   Hamilton
+                   New Zealand
+        and Copyright (1991) to
+                   David C. Murray and Peter W. Hoban,
+                   Cancer Society of New Zealand Inc., and 
+                   University of Waikato.
+--------------------------------------------------------------------------------
+*/
+
+{
+/* Variable descriptions:
+   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
+     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
+   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
+   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
+   dx,dy,dz are the widths in cm of the voxels
+*/
+float         x1,y1,z1,
+              x2,y2,z2,
+              xp1,yp1,zp1,
+              dx,dy,dz;
+int           Nx,Ny,Nz;
+
+/*General ray-trace algorithm variables*/
+float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
+float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
+					/*limits of alpha x,y,z parameters*/
+float alpha_min, alpha_max;		/*limits of alpha parameter*/
+int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
+float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
+float *alpha;				/*holds merged set of alpha values*/
+int i_index,j_index,k_index;		/*loop indices for merging alphas*/
+int a;					/*loop counter*/
+int max_index;				/*max index of merged alpha array*/
+float d12;				/*distance between ray end points*/
+float alpha_mid;			/*mid-point of intersection length*/
+float length;				/*intersection length*/
+int i,j,k;				/*indices of voxel with int. length*/
+float rpl = 0.0;			/*radiological path length in cm*/
+float voxel_density;			/*temporary voxel density*/
+float lmax;  // best possible penetration pathlength for a voxel
+float pnorm;  // absolute difference between p1 and p2
+
+/* Assign variables */
+/******************************************************************************/
+x1 = point1.x;
+y1 = point1.y;
+z1 = point1.z;
+x2 = point2.x;
+y2 = point2.y;
+z2 = point2.z;
+Nx = electron_density_grid->x_count + 1;
+Ny = electron_density_grid->y_count + 1;
+Nz = electron_density_grid->z_count + 1;
+dx = electron_density_grid->inc.x;
+dy = electron_density_grid->inc.y;
+dz = electron_density_grid->inc.z;
+
+// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
+xp1 = electron_density_grid->start.x - 0.5*dx;
+yp1 = electron_density_grid->start.y - 0.5*dy;
+zp1 = electron_density_grid->start.z - 0.5*dz;
+
+pnorm = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
+
+// this is the largest pathlength possible for a ray through a voxel:
+lmax = sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
+
+/* Calculate xpN,ypN,zpN */
+/******************************************************************************/
+xpN = xp1 + (Nx-1)*dx;
+ypN = yp1 + (Ny-1)*dy;
+zpN = zp1 + (Nz-1)*dz;
+
+/*Calculate alpha_min and alpha_max*/
+/******************************************************************************/
+/*Avoid division by zero*/
+if (x1==x2)
+  x2 += 0.00001;
+if (y1==y2)
+  y2 += 0.00001;
+if (z1==z2)
+  z2 += 0.00001;
+if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
+{
+	sprintf(errstr,"Error - ray trace region too small.");
+	return(FAILURE);
+}
+
+alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
+if (alpha_z_min>alpha_min) 
+  alpha_min = alpha_z_min;
+if (alpha_min<0)
+  alpha_min = 0;
+alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
+if (alpha_z_max<alpha_max) 
+  alpha_max = alpha_z_max;
+if (alpha_max>1)
+  alpha_max = 1;
+
+// Monitor lines...
+/*
+printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
+                alpha_x_min,alpha_y_min,alpha_z_min);
+printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
+                alpha_x_max,alpha_y_max,alpha_z_max);
+printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
+printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx); */
+
+/*Determine the ranges of i,j,k indices*/
+/******************************************************************************/
+/*The following assignments require conversion from float to integer types*/
+/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
+/*functions convert to the correct value. Note that the range of these*/
+/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
+		
+i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
+                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
+i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
+                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
+j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
+                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
+j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
+                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
+k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
+                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
+k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
+                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
+
+/*Monitor lines...
+fprintf(stdout,"    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
+fprintf(stdout,"    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max);
+*/
+/*Generate sets of alpha values,reversing order if necessary*/
+/******************************************************************************/
+/*allocate array space on stack*/
+if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
+	return(FAILURE);
+}
+
+/* 
+printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
+printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
+printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
+ 
+if (i_min <= i_max)
+  if (x2>x1)
+    {
+    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=1;a<=i_max-i_min;a++)
+      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
+    }
+  else
+    {
+    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=i_max-i_min-1;a>=0;a--)
+      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
+    }
+alpha_x[i_max-i_min+1] = 10000.0;
+if (j_min <= j_max)
+  if (y2>y1)
+    {
+    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=1;a<=j_max-j_min;a++)
+      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
+    }
+  else
+    {
+    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=j_max-j_min-1;a>=0;a--)
+      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
+    }
+alpha_y[j_max-j_min+1] = 10001.0;
+if (k_min <= k_max)
+  if (z2>z1)
+    {
+    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=1;a<=k_max-k_min;a++)
+      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
+    }
+  else
+    {
+    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=k_max-k_min-1;a>=0;a--)
+      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
+  }
+alpha_z[k_max-k_min+1] = 10002.0; 
+
+
+/*Monitor lines...
+if (i_max<i_min)
+  fprintf(stdout,"    No alpha_x values\n");
+else
+  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
+                 alpha_x[0],alpha_x[i_max-i_min]);
+if (j_max<j_min)
+  fprintf(stdout,"    No alpha_y values\n");
+else
+  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
+                 alpha_y[0],alpha_y[j_max-j_min]);
+if (k_max<k_min)
+  fprintf(stdout,"    No alpha_z values\n");
+else
+  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
+                 alpha_z[0],alpha_z[k_max-k_min]);
+*/
+/*Generate merged set of alpha values*/
+
+
+/******************************************************************************/
+if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
+	return(FAILURE);
+}
+
+max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
+alpha[0] = alpha_min;
+i_index = 0;
+j_index = 0;
+k_index = 0;
+for (a=1;a<=max_index-1;a++)
+  if (alpha_x[i_index]<alpha_y[j_index])
+    if (alpha_x[i_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_x[i_index];
+      i_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+  else
+    if (alpha_y[j_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_y[j_index];
+      j_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+alpha[max_index] = alpha_max;
+free(alpha_x);				//deallocate temp array storage
+free(alpha_y);
+free(alpha_z);
+/*Monitor lines...
+fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
+for (a=0;a<=max_index;a++)
+  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
+*/
+/*Calculate voxel lengths and indices, and assign radiological depth*/
+/******************************************************************************/
+d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
+					//d12 is distance between ray end pts
+// printf("made it this far in raytrace.\n");
+for (a=1;a<=max_index;a++)
+  {
+  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
+  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
+    {
+    alpha_mid = (alpha[a]+alpha[a-1])/2.0;
+					//alpha_mid is middle of int. length
+    i = (int) floor((x1 + alpha_mid*(x2-x1) - xp1)/dx);
+    j = (int) floor((y1 + alpha_mid*(y2-y1) - yp1)/dy);
+    k = (int) floor((z1 + alpha_mid*(z2-z1) - zp1)/dz);
+					//i,j,k are indices of voxel
+
+    // Remember that this function traces only a single ray.
+    // rpl has been set to zero during initialisation.
+
+    voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
+    rpl += length * voxel_density/2.0;  // add first half of int. length
+    // store pathlength only if the voxel is intersected almost directly
+	// by the ray
+    if (length>=0.75/2*lmax && GRID_VALUE(radiological_depth_grid,i,j,k)<0.0)
+      GRID_VALUE(radiological_depth_grid, i, j, k) = rpl;
+    
+    rpl += length * voxel_density/2.0;  //add second half of int. length  
+    }    
+  } 
+free(alpha); 			//deallocate remaining array storage 
+
+return(SUCCESS);
+
+} 					/*End of s_raytrace routine*/

+ 301 - 301
WiscPlan-SourceCode/Source-code-photon-windows/terma_dose_masks.cpp

@@ -1,301 +1,301 @@
-/* terma_dose_masks.cpp */
-
-/* All voxels that lie within a cylinder of radius RAPERTURE + RSAFE, centered
-on the central beam axis, are marked in the dose_mask grid.  These voxels will
-be used in the dose calculation.  The voxels that are marked in the terma_mask
-grid are a subset of those that are marked in the dose_mask grid. The terma_mask
-grid contains values that specify the fraction of each voxel that lies inside
-of the beam aperture in the beam's eye view plane, which exists at a distance
-SAD from the x-ray source location. */
-
-/* Determination of voxel "insideness" for the terma_mask:
-If it is discovered that a voxel is intersected by an aperture boundary in the
-beam's eye view plane, then that voxel is broken-up into Mus x Nus x Qus sub-
-voxels (upsampled).  The fraction of the sub-voxels that lie inside the beam
-aperture in the beam's eye view then becomes the insideness for that voxel. */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int terma_dose_masks(FLOAT_GRID *terma_mask, FLOAT_GRID *dose_mask, BEAM *bm)
-// The user must allocate space for terma_mask and dose_mask before calling 
-// this function.
-// The validity of all of the arguments to this function are assumed to be 
-// checked with the parse_func, which acts as a gatekeeper for the convolution
-// program.
-{
-	// scalars
-	int i,j,k,m;     // indices
-	int ius,jus,kus;  // upsample voxel indices
-	int M,N,Q;     // grid dimensions
-	float dx,dy,dz;  // voxel dimensions
-	float xp,yp,SAD; // aperture center in ip,jp,kp coordinate system
-	float xsub,ysub,zsub;  // coordinates of sub-voxels
-	float del_xp,del_yp; // width of beamlet field in plane at SAD
-	float Rmax,Rcurr,Rcyl,Rvox,Rcyl_sqr,Rproj;
-	float eta,gamma,delta;  // dummy variables
-
-	// vectors
-	float *x,*y,*z;  // x,y,z coordinate vectors
-	float *dxus,*dyus,*dzus;  // upsample vectors
-	float *y_vec,*ip,*jp,*kp,*d_hat;  // beam vectors
-
-	// matrices
-	float **c;  // matrix of the 8 corners of voxel grid
-	
-	// Ensure that upsample factors are all greater than zero
-	if (Mus < 1 || Nus < 1 || Qus < 1)
-	{
-		sprintf(errstr,"Upsample factors must all be greater than zero.");
-		return(FAILURE);
-	}
-
-	// record the sizes of terma_mask and dose_mask
-	M = terma_mask->x_count;
-	N = terma_mask->y_count;
-	Q = terma_mask->z_count;
-
-	if (M != dose_mask->x_count || N != dose_mask->y_count 
-		|| Q != dose_mask->z_count)
-	{
-		sprintf(errstr,"dose_mask and terma_mask dimensions are incompatible.");
-		return(FAILURE);
-	}
-
-	dx = terma_mask->inc.x;
-	dy = terma_mask->inc.y;
-	dz = terma_mask->inc.z;
-	
-	// initialize vectors
-	x = fvector(0,M-1);
-	y = fvector(0,N-1);
-	z = fvector(0,Q-1);
-
-	dxus = fvector(0,Mus-1);
-	dyus = fvector(0,Nus-1);
-	dzus = fvector(0,Qus-1);
-
-	y_vec = fvector(0,2);
-	ip = fvector(0,2);
-	jp = fvector(0,2);
-	kp = fvector(0,2);
-	d_hat = fvector(0,2);
-
-	// initialize matrices
-	c = fmatrix(0,7,0,2);
-
-	// fill-in the voxel coordinate vectors
-	for (i=0;i<M;i++) x[i] = terma_mask->start.x + (float)i*dx;
-	for (j=0;j<N;j++) y[j] = terma_mask->start.y + (float)j*dy;
-	for (k=0;k<Q;k++) z[k] = terma_mask->start.z + (float)k*dz;
-
-	// fill-in the upsample vectors
-	// For a voxel at (i,j,k), the xyz coordinates of a sub-voxel (ius,jus,kus)
-	// are (x[i] + dxus[ius], y[j] + dyus[jus], z[k] + dzus[k])
-	dxus[0] = -0.5*dx*(1-1/Mus);
-	for (ius=1;ius<Mus;ius++)  dxus[ius] = dxus[ius-1] + dx/Mus;
-
-	dyus[0] = -0.5*dy*(1-1/Nus);
-	for (jus=1;jus<Nus;jus++) dyus[jus] = dyus[jus-1] + dy/Nus;
-
-	dzus[0] = -0.5*dz*(1-1/Qus);
-	for (kus=1;kus<Qus;kus++) dzus[kus] = dzus[kus-1] + dz/Qus;
-
-	// rewrite beam vectors for quick reference later
-	y_vec[0] = bm->y_vec[0];
-	y_vec[1] = bm->y_vec[1];
-	y_vec[2] = bm->y_vec[2];
-
-	// coordinate system in beam's eye view
-	for (j=0;j<3;j++) ip[j] = bm->ip[j];
-	for (j=0;j<3;j++) jp[j] = bm->jp[j];
-	for (j=0;j<3;j++) kp[j] = bm->kp[j];
-
-	// aperture center in beam's eye view
-	xp = bm->xp;
-	yp = bm->yp;
-
-	// aperture size in beam's eye view
-	del_xp = bm->del_xp;
-	del_yp = bm->del_yp;
-
-	// source-axis distance of the beam
-	SAD = bm->SAD;
-
-	// calculate the max distance between the source vector and each grid corner
-	Rmax = 0.0;
-	
-	// the the matrix c with the coordinates of the eight corners of the grid.
-	for (i=0;i<=1;i++)
-	  for (j=0;j<=1;j++)
-	    for (k=0;k<=1;k++)
-		{ 
-		  //                     0 => lower corners         1 => upper corners
-		  c[i+j*2+k*4][0] = (1-(float)i)*(x[0]-dx/2.0) + (float)i*(x[M-1]+dx/2.0);
-		  c[i+j*2+k*4][1] = (1-(float)j)*(y[0]-dy/2.0) + (float)j*(y[N-1]+dy/2.0);
-		  c[i+j*2+k*4][2] = (1-(float)k)*(z[0]-dz/2.0) + (float)k*(z[Q-1]+dz/2.0);
-		}
-
-	// find which corner is the farthest from the source
-	for (m=0;m<=7;m++)
-	{
-		Rcurr = sqrt(pow(y_vec[0] - c[m][0],2.0f)
-			       + pow(y_vec[1] - c[m][1],2.0f)
-				   + pow(y_vec[2] - c[m][2],2.0f));
-		if (Rcurr > Rmax)
-			Rmax = Rcurr;
-	}
-
-	// Fill the dose_mask
-
-	// Radius of cylinder about y_vec + kp that will contain all voxels
-	// to be used in the dose calculation.
-	Rcyl = sqrt(del_xp*del_xp + del_yp*del_yp)*Rmax/SAD;  // project Rmax to aperture plane
-	Rcyl_sqr = Rcyl*Rcyl + RSAFE*RSAFE;  // add an empirical safety margin to the radius squared
-
-	// calculate the true source direction
-	// d_hat points at the center of the aperture from the source location
-	d_hat[0] = xp*ip[0] + yp*jp[0] + SAD*kp[0];
-	d_hat[1] = xp*ip[1] + yp*jp[1] + SAD*kp[1];
-	d_hat[2] = xp*ip[2] + yp*jp[2] + SAD*kp[2];
-
-	// normalize d_hat so it's a true "hat" vector
-	delta = sqrt(d_hat[0]*d_hat[0] + d_hat[1]*d_hat[1] + d_hat[2]*d_hat[2]);
-	d_hat[0] = d_hat[0]/delta;
-	d_hat[1] = d_hat[1]/delta;
-	d_hat[2] = d_hat[2]/delta;
-
-	for (k=0;k<Q;k++)
-	 for (j=0;j<N;j++)
-	  for (i=0;i<M;i++)
-	  {
-		  // squared distance between the voxel and the source:
-		  eta = (x[i] - y_vec[0])*(x[i] - y_vec[0])
-			  + (y[j] - y_vec[1])*(y[j] - y_vec[1])
-			  + (z[k] - y_vec[2])*(z[k] - y_vec[2]);
-
-		  // squared distance between the voxel and the source along source direction, 
-	      // y_vec + kp:
-		  gamma = pow((x[i] - y_vec[0])*d_hat[0]
-				    + (y[j] - y_vec[1])*d_hat[1]
-				    + (z[k] - y_vec[2])*d_hat[2],2.0f);
-
-		  // printf("%lf %lf\n",eta, gamma);
-
-		  // squared difference between the voxel and the axis of the cylinder
-		  delta = eta - gamma;
-
-		  // If the voxel is inside the cylinder about y_vec + ip of radius Rcyl plus
-		  // a safety margin then mark it in dose_mask.
-		  if (delta <= Rcyl_sqr)
-			  GRID_VALUE(dose_mask,i,j,k) = 1.0;
-		  else
-			  GRID_VALUE(dose_mask,i,j,k) = 0.0;
-	  }
-
-	// Fill the terma_mask, including the insideness of each voxel
-
-	// Each voxel is enclosed with in a sphere of the following radius:
-	Rvox = 0.5*sqrt(dx*dx + dy*dy + dz*dz);
-
-	for (i=0;i<M;i++)
-	 for (j=0;j<N;j++)
-	  for (k=0;k<Q;k++)
-	   // deal only with voxels that are marked in the dose_mask
-	   if (GRID_VALUE(dose_mask,i,j,k) > 0.0)
-	   {
-		 // distance between source and voxel in the kp direction
-	     delta = kp[0]*(x[i] - y_vec[0])
-               + kp[1]*(y[j] - y_vec[1])
-               + kp[2]*(z[k] - y_vec[2]);
-
-		 // voxel's projected offset on the aperture plane in the ip direction:
-		 eta = (SAD/delta)*(  ip[0]*(x[i] - y_vec[0])
-				            + ip[1]*(y[j] - y_vec[1])
-						    + ip[2]*(z[k] - y_vec[2])) - xp;
-		 // voxel's projected offset on the aperture plane in the jp direction:
-		 gamma = (SAD/delta)*(  jp[0]*(x[i] - y_vec[0])
-				              + jp[1]*(y[j] - y_vec[1])
-						      + jp[2]*(z[k] - y_vec[2])) - yp;
-
-		 // take absolute value of offsets
-		 eta = fabs(eta);
-		 gamma = fabs(gamma);
-
-		 Rproj = Rvox*SAD/delta;  // voxel radius projected to plane at SAD
-
-		 // Determine where the voxel lies with respect to the aperture:
-		 if (eta <= 0.5*del_xp+Rproj && gamma <= 0.5*del_yp+Rproj)
-		 // voxel is inside aperture plus a half-voxel margin:
-			if (eta >= 0.5*del_xp-Rproj || gamma >= 0.5*del_yp-Rproj)
-		    // voxel is between the aperture plus/minus a half-voxel margin:
-			// (true at this point if the voxel size is larger than the aperture size)
-			{
-			    // Determine insideness of the voxel by breaking it up
-				// into subvoxels and projecting the parts to the aperture plane.
-				m = 0;  // number of subvoxels inside aperture
-	            // project each subvoxel onto the aperture at SAD
-		        for (ius=0;ius<Mus;ius++)
-			     for (jus=0;jus<Nus;jus++)
-			      for (kus=0;kus<Qus;kus++)
-				  {
-			        // find the center of the subvoxel
-			        xsub = x[i] + dxus[ius];
-			        ysub = y[j] + dyus[jus];
-			        zsub = z[k] + dzus[kus];
-
-			        // project the subvoxel onto the aperture
-			        // distance between source and subvoxel in the kp direction
-			        delta = kp[0]*(xsub - y_vec[0])
-				          + kp[1]*(ysub - y_vec[1])
-					      + kp[2]*(zsub - y_vec[2]);
-
-			        // projected offset on aperture plane in the ip direction:
-			        eta = (SAD/delta)*(  ip[0]*(xsub - y_vec[0])
-				                       + ip[1]*(ysub - y_vec[1])
-								       + ip[2]*(zsub - y_vec[2])) - xp;
-			        // projected offset on aperture plane in the jp direction:
-			        gamma = (SAD/delta)*(  jp[0]*(xsub - y_vec[0])
-				                         + jp[1]*(ysub - y_vec[1])
-								         + jp[2]*(zsub - y_vec[2])) - yp;
-
-		            eta = fabs(eta);
-			        gamma = fabs(gamma);
-
-			        // check if the subvoxel is inside the aperture at SAD
-			        if (eta <= 0.5*del_xp && gamma <= 0.5*del_yp)
-				       m++;
-				  }
-
-		        // the fraction of subvoxels inside the aperture becomes the insidness
-	            GRID_VALUE(terma_mask,i,j,k) = (float)m/(float)(Mus*Nus*Qus);
-			}
-			else
-			// voxel is inside the aperture minus a half-voxel margin
-				GRID_VALUE(terma_mask,i,j,k) = 1.0;
-		 else
-		 // voxel outside the aperture plus the half-voxel margin
-		    GRID_VALUE(terma_mask,i,j,k) = 0.0;
-	   }
-
-	// free vectors
-	free_fvector(x,0,M-1);
-	free_fvector(y,0,N-1);
-	free_fvector(z,0,Q-1);
-
-	free_fvector(dxus,0,Mus-1);
-	free_fvector(dyus,0,Nus-1);
-	free_fvector(dzus,0,Qus-1);
-
-	free_fvector(y_vec,0,2);
-	free_fvector(ip,0,2);
-	free_fvector(jp,0,2);
-	free_fvector(kp,0,2);
-	free_fvector(d_hat,0,2);
-
-	// free matrices
-	free_fmatrix(c,0,7,0,2);
-
-	return(SUCCESS);
-}
+/* terma_dose_masks.cpp */
+
+/* All voxels that lie within a cylinder of radius RAPERTURE + RSAFE, centered
+on the central beam axis, are marked in the dose_mask grid.  These voxels will
+be used in the dose calculation.  The voxels that are marked in the terma_mask
+grid are a subset of those that are marked in the dose_mask grid. The terma_mask
+grid contains values that specify the fraction of each voxel that lies inside
+of the beam aperture in the beam's eye view plane, which exists at a distance
+SAD from the x-ray source location. */
+
+/* Determination of voxel "insideness" for the terma_mask:
+If it is discovered that a voxel is intersected by an aperture boundary in the
+beam's eye view plane, then that voxel is broken-up into Mus x Nus x Qus sub-
+voxels (upsampled).  The fraction of the sub-voxels that lie inside the beam
+aperture in the beam's eye view then becomes the insideness for that voxel. */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int terma_dose_masks(FLOAT_GRID *terma_mask, FLOAT_GRID *dose_mask, BEAM *bm)
+// The user must allocate space for terma_mask and dose_mask before calling 
+// this function.
+// The validity of all of the arguments to this function are assumed to be 
+// checked with the parse_func, which acts as a gatekeeper for the convolution
+// program.
+{
+	// scalars
+	int i,j,k,m;     // indices
+	int ius,jus,kus;  // upsample voxel indices
+	int M,N,Q;     // grid dimensions
+	float dx,dy,dz;  // voxel dimensions
+	float xp,yp,SAD; // aperture center in ip,jp,kp coordinate system
+	float xsub,ysub,zsub;  // coordinates of sub-voxels
+	float del_xp,del_yp; // width of beamlet field in plane at SAD
+	float Rmax,Rcurr,Rcyl,Rvox,Rcyl_sqr,Rproj;
+	float eta,gamma,delta;  // dummy variables
+
+	// vectors
+	float *x,*y,*z;  // x,y,z coordinate vectors
+	float *dxus,*dyus,*dzus;  // upsample vectors
+	float *y_vec,*ip,*jp,*kp,*d_hat;  // beam vectors
+
+	// matrices
+	float **c;  // matrix of the 8 corners of voxel grid
+	
+	// Ensure that upsample factors are all greater than zero
+	if (Mus < 1 || Nus < 1 || Qus < 1)
+	{
+		sprintf(errstr,"Upsample factors must all be greater than zero.");
+		return(FAILURE);
+	}
+
+	// record the sizes of terma_mask and dose_mask
+	M = terma_mask->x_count;
+	N = terma_mask->y_count;
+	Q = terma_mask->z_count;
+
+	if (M != dose_mask->x_count || N != dose_mask->y_count 
+		|| Q != dose_mask->z_count)
+	{
+		sprintf(errstr,"dose_mask and terma_mask dimensions are incompatible.");
+		return(FAILURE);
+	}
+
+	dx = terma_mask->inc.x;
+	dy = terma_mask->inc.y;
+	dz = terma_mask->inc.z;
+	
+	// initialize vectors
+	x = fvector(0,M-1);
+	y = fvector(0,N-1);
+	z = fvector(0,Q-1);
+
+	dxus = fvector(0,Mus-1);
+	dyus = fvector(0,Nus-1);
+	dzus = fvector(0,Qus-1);
+
+	y_vec = fvector(0,2);
+	ip = fvector(0,2);
+	jp = fvector(0,2);
+	kp = fvector(0,2);
+	d_hat = fvector(0,2);
+
+	// initialize matrices
+	c = fmatrix(0,7,0,2);
+
+	// fill-in the voxel coordinate vectors
+	for (i=0;i<M;i++) x[i] = terma_mask->start.x + (float)i*dx;
+	for (j=0;j<N;j++) y[j] = terma_mask->start.y + (float)j*dy;
+	for (k=0;k<Q;k++) z[k] = terma_mask->start.z + (float)k*dz;
+
+	// fill-in the upsample vectors
+	// For a voxel at (i,j,k), the xyz coordinates of a sub-voxel (ius,jus,kus)
+	// are (x[i] + dxus[ius], y[j] + dyus[jus], z[k] + dzus[k])
+	dxus[0] = -0.5*dx*(1-1/Mus);
+	for (ius=1;ius<Mus;ius++)  dxus[ius] = dxus[ius-1] + dx/Mus;
+
+	dyus[0] = -0.5*dy*(1-1/Nus);
+	for (jus=1;jus<Nus;jus++) dyus[jus] = dyus[jus-1] + dy/Nus;
+
+	dzus[0] = -0.5*dz*(1-1/Qus);
+	for (kus=1;kus<Qus;kus++) dzus[kus] = dzus[kus-1] + dz/Qus;
+
+	// rewrite beam vectors for quick reference later
+	y_vec[0] = bm->y_vec[0];
+	y_vec[1] = bm->y_vec[1];
+	y_vec[2] = bm->y_vec[2];
+
+	// coordinate system in beam's eye view
+	for (j=0;j<3;j++) ip[j] = bm->ip[j];
+	for (j=0;j<3;j++) jp[j] = bm->jp[j];
+	for (j=0;j<3;j++) kp[j] = bm->kp[j];
+
+	// aperture center in beam's eye view
+	xp = bm->xp;
+	yp = bm->yp;
+
+	// aperture size in beam's eye view
+	del_xp = bm->del_xp;
+	del_yp = bm->del_yp;
+
+	// source-axis distance of the beam
+	SAD = bm->SAD;
+
+	// calculate the max distance between the source vector and each grid corner
+	Rmax = 0.0;
+	
+	// the the matrix c with the coordinates of the eight corners of the grid.
+	for (i=0;i<=1;i++)
+	  for (j=0;j<=1;j++)
+	    for (k=0;k<=1;k++)
+		{ 
+		  //                     0 => lower corners         1 => upper corners
+		  c[i+j*2+k*4][0] = (1-(float)i)*(x[0]-dx/2.0) + (float)i*(x[M-1]+dx/2.0);
+		  c[i+j*2+k*4][1] = (1-(float)j)*(y[0]-dy/2.0) + (float)j*(y[N-1]+dy/2.0);
+		  c[i+j*2+k*4][2] = (1-(float)k)*(z[0]-dz/2.0) + (float)k*(z[Q-1]+dz/2.0);
+		}
+
+	// find which corner is the farthest from the source
+	for (m=0;m<=7;m++)
+	{
+		Rcurr = sqrt(pow(y_vec[0] - c[m][0],2.0f)
+			       + pow(y_vec[1] - c[m][1],2.0f)
+				   + pow(y_vec[2] - c[m][2],2.0f));
+		if (Rcurr > Rmax)
+			Rmax = Rcurr;
+	}
+
+	// Fill the dose_mask
+
+	// Radius of cylinder about y_vec + kp that will contain all voxels
+	// to be used in the dose calculation.
+	Rcyl = sqrt(del_xp*del_xp + del_yp*del_yp)*Rmax/SAD;  // project Rmax to aperture plane
+	Rcyl_sqr = Rcyl*Rcyl + RSAFE*RSAFE;  // add an empirical safety margin to the radius squared
+
+	// calculate the true source direction
+	// d_hat points at the center of the aperture from the source location
+	d_hat[0] = xp*ip[0] + yp*jp[0] + SAD*kp[0];
+	d_hat[1] = xp*ip[1] + yp*jp[1] + SAD*kp[1];
+	d_hat[2] = xp*ip[2] + yp*jp[2] + SAD*kp[2];
+
+	// normalize d_hat so it's a true "hat" vector
+	delta = sqrt(d_hat[0]*d_hat[0] + d_hat[1]*d_hat[1] + d_hat[2]*d_hat[2]);
+	d_hat[0] = d_hat[0]/delta;
+	d_hat[1] = d_hat[1]/delta;
+	d_hat[2] = d_hat[2]/delta;
+
+	for (k=0;k<Q;k++)
+	 for (j=0;j<N;j++)
+	  for (i=0;i<M;i++)
+	  {
+		  // squared distance between the voxel and the source:
+		  eta = (x[i] - y_vec[0])*(x[i] - y_vec[0])
+			  + (y[j] - y_vec[1])*(y[j] - y_vec[1])
+			  + (z[k] - y_vec[2])*(z[k] - y_vec[2]);
+
+		  // squared distance between the voxel and the source along source direction, 
+	      // y_vec + kp:
+		  gamma = pow((x[i] - y_vec[0])*d_hat[0]
+				    + (y[j] - y_vec[1])*d_hat[1]
+				    + (z[k] - y_vec[2])*d_hat[2],2.0f);
+
+		  // printf("%lf %lf\n",eta, gamma);
+
+		  // squared difference between the voxel and the axis of the cylinder
+		  delta = eta - gamma;
+
+		  // If the voxel is inside the cylinder about y_vec + ip of radius Rcyl plus
+		  // a safety margin then mark it in dose_mask.
+		  if (delta <= Rcyl_sqr)
+			  GRID_VALUE(dose_mask,i,j,k) = 1.0;
+		  else
+			  GRID_VALUE(dose_mask,i,j,k) = 0.0;
+	  }
+
+	// Fill the terma_mask, including the insideness of each voxel
+
+	// Each voxel is enclosed with in a sphere of the following radius:
+	Rvox = 0.5*sqrt(dx*dx + dy*dy + dz*dz);
+
+	for (i=0;i<M;i++)
+	 for (j=0;j<N;j++)
+	  for (k=0;k<Q;k++)
+	   // deal only with voxels that are marked in the dose_mask
+	   if (GRID_VALUE(dose_mask,i,j,k) > 0.0)
+	   {
+		 // distance between source and voxel in the kp direction
+	     delta = kp[0]*(x[i] - y_vec[0])
+               + kp[1]*(y[j] - y_vec[1])
+               + kp[2]*(z[k] - y_vec[2]);
+
+		 // voxel's projected offset on the aperture plane in the ip direction:
+		 eta = (SAD/delta)*(  ip[0]*(x[i] - y_vec[0])
+				            + ip[1]*(y[j] - y_vec[1])
+						    + ip[2]*(z[k] - y_vec[2])) - xp;
+		 // voxel's projected offset on the aperture plane in the jp direction:
+		 gamma = (SAD/delta)*(  jp[0]*(x[i] - y_vec[0])
+				              + jp[1]*(y[j] - y_vec[1])
+						      + jp[2]*(z[k] - y_vec[2])) - yp;
+
+		 // take absolute value of offsets
+		 eta = fabs(eta);
+		 gamma = fabs(gamma);
+
+		 Rproj = Rvox*SAD/delta;  // voxel radius projected to plane at SAD
+
+		 // Determine where the voxel lies with respect to the aperture:
+		 if (eta <= 0.5*del_xp+Rproj && gamma <= 0.5*del_yp+Rproj)
+		 // voxel is inside aperture plus a half-voxel margin:
+			if (eta >= 0.5*del_xp-Rproj || gamma >= 0.5*del_yp-Rproj)
+		    // voxel is between the aperture plus/minus a half-voxel margin:
+			// (true at this point if the voxel size is larger than the aperture size)
+			{
+			    // Determine insideness of the voxel by breaking it up
+				// into subvoxels and projecting the parts to the aperture plane.
+				m = 0;  // number of subvoxels inside aperture
+	            // project each subvoxel onto the aperture at SAD
+		        for (ius=0;ius<Mus;ius++)
+			     for (jus=0;jus<Nus;jus++)
+			      for (kus=0;kus<Qus;kus++)
+				  {
+			        // find the center of the subvoxel
+			        xsub = x[i] + dxus[ius];
+			        ysub = y[j] + dyus[jus];
+			        zsub = z[k] + dzus[kus];
+
+			        // project the subvoxel onto the aperture
+			        // distance between source and subvoxel in the kp direction
+			        delta = kp[0]*(xsub - y_vec[0])
+				          + kp[1]*(ysub - y_vec[1])
+					      + kp[2]*(zsub - y_vec[2]);
+
+			        // projected offset on aperture plane in the ip direction:
+			        eta = (SAD/delta)*(  ip[0]*(xsub - y_vec[0])
+				                       + ip[1]*(ysub - y_vec[1])
+								       + ip[2]*(zsub - y_vec[2])) - xp;
+			        // projected offset on aperture plane in the jp direction:
+			        gamma = (SAD/delta)*(  jp[0]*(xsub - y_vec[0])
+				                         + jp[1]*(ysub - y_vec[1])
+								         + jp[2]*(zsub - y_vec[2])) - yp;
+
+		            eta = fabs(eta);
+			        gamma = fabs(gamma);
+
+			        // check if the subvoxel is inside the aperture at SAD
+			        if (eta <= 0.5*del_xp && gamma <= 0.5*del_yp)
+				       m++;
+				  }
+
+		        // the fraction of subvoxels inside the aperture becomes the insidness
+	            GRID_VALUE(terma_mask,i,j,k) = (float)m/(float)(Mus*Nus*Qus);
+			}
+			else
+			// voxel is inside the aperture minus a half-voxel margin
+				GRID_VALUE(terma_mask,i,j,k) = 1.0;
+		 else
+		 // voxel outside the aperture plus the half-voxel margin
+		    GRID_VALUE(terma_mask,i,j,k) = 0.0;
+	   }
+
+	// free vectors
+	free_fvector(x,0,M-1);
+	free_fvector(y,0,N-1);
+	free_fvector(z,0,Q-1);
+
+	free_fvector(dxus,0,Mus-1);
+	free_fvector(dyus,0,Nus-1);
+	free_fvector(dzus,0,Qus-1);
+
+	free_fvector(y_vec,0,2);
+	free_fvector(ip,0,2);
+	free_fvector(jp,0,2);
+	free_fvector(kp,0,2);
+	free_fvector(d_hat,0,2);
+
+	// free matrices
+	free_fmatrix(c,0,7,0,2);
+
+	return(SUCCESS);
+}

+ 60 - 60
WiscPlan-SourceCode/Source-code-photon-windows/terma_kerma.cpp

@@ -1,60 +1,60 @@
-/* terma_kerma.cpp */
-
-/* Calculates the terma and the kerma of every voxel in the terma_mask.  */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int terma_kerma(FLOAT_GRID *deff, FLOAT_GRID *terma, FLOAT_GRID *kermac,
-				MONO_KERNELS *mono, FLOAT_GRID *terma_mask)
-{													 
- // insideness is accounted for with terma_mask
- int i, j, k, e;
- float kermac0, terma0;
-
- //calculate T and Kc at zero depth for use in hardening correction
- //see Hoban et al 1994 (PMB)
- kermac0 = terma0 = 0.0;
- for (e=0;e<mono->nkernels;e++)
- {
-   kermac0 = mono->fluence[e]*mono->energy[e]*mono->mu_en[e];
-   terma0 = mono->fluence[e]*mono->energy[e]*mono->mu[e];
- }
-
- for (j=0;j<deff->y_count;j++)
-  for (k=0;k<deff->z_count;k++)
-   for (i=0;i<deff->x_count;i++)
-    if (GRID_VALUE(terma_mask,i,j,k) > 0)
-    {
-	  // The amount of each voxel that is inside the field (insideness) was
-	  // was accounted in the calculation of the terma_mask
-
-	  //sum terma and collision kerma over each energy in spectrum 
-	  // (stored in mono kernel structure)
-	  for (e=0;e<mono->nkernels;e++)
-	  {
-       GRID_VALUE(terma,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
-       GRID_VALUE(kermac,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu_en[e]
-                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
-	  }
-	  
-	  //adjust terma and collision kerma according to insideness
-	  GRID_VALUE(terma,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
-	  GRID_VALUE(kermac,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
-
-	  // beam hardening correction
-	  if (terma0 <= 0.0 || kermac0 <= 0.0)
-		nrerror("Input spectrum must not sum to zero."); 
-	  else
-		GRID_VALUE(terma,i,j,k) *= (GRID_VALUE(kermac,i,j,k)/GRID_VALUE(terma,i,j,k))
-								/(kermac0/terma0);
-	}
-	else
-	{
-		GRID_VALUE(terma,i,j,k) = 0.0;
-		GRID_VALUE(kermac,i,j,k) = 0.0;
-	}
-    return(SUCCESS);
-}
+/* terma_kerma.cpp */
+
+/* Calculates the terma and the kerma of every voxel in the terma_mask.  */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int terma_kerma(FLOAT_GRID *deff, FLOAT_GRID *terma, FLOAT_GRID *kermac,
+				MONO_KERNELS *mono, FLOAT_GRID *terma_mask)
+{													 
+ // insideness is accounted for with terma_mask
+ int i, j, k, e;
+ float kermac0, terma0;
+
+ //calculate T and Kc at zero depth for use in hardening correction
+ //see Hoban et al 1994 (PMB)
+ kermac0 = terma0 = 0.0;
+ for (e=0;e<mono->nkernels;e++)
+ {
+   kermac0 = mono->fluence[e]*mono->energy[e]*mono->mu_en[e];
+   terma0 = mono->fluence[e]*mono->energy[e]*mono->mu[e];
+ }
+
+ for (j=0;j<deff->y_count;j++)
+  for (k=0;k<deff->z_count;k++)
+   for (i=0;i<deff->x_count;i++)
+    if (GRID_VALUE(terma_mask,i,j,k) > 0)
+    {
+	  // The amount of each voxel that is inside the field (insideness) was
+	  // was accounted in the calculation of the terma_mask
+
+	  //sum terma and collision kerma over each energy in spectrum 
+	  // (stored in mono kernel structure)
+	  for (e=0;e<mono->nkernels;e++)
+	  {
+       GRID_VALUE(terma,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
+       GRID_VALUE(kermac,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu_en[e]
+                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
+	  }
+	  
+	  //adjust terma and collision kerma according to insideness
+	  GRID_VALUE(terma,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
+	  GRID_VALUE(kermac,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
+
+	  // beam hardening correction
+	  if (terma0 <= 0.0 || kermac0 <= 0.0)
+		nrerror("Input spectrum must not sum to zero."); 
+	  else
+		GRID_VALUE(terma,i,j,k) *= (GRID_VALUE(kermac,i,j,k)/GRID_VALUE(terma,i,j,k))
+								/(kermac0/terma0);
+	}
+	else
+	{
+		GRID_VALUE(terma,i,j,k) = 0.0;
+		GRID_VALUE(kermac,i,j,k) = 0.0;
+	}
+    return(SUCCESS);
+}

+ 117 - 117
WiscPlan-SourceCode/Source-code-photon-windows/util.cpp

@@ -1,117 +1,117 @@
-/* util.c */
-/* Functions that are used for utility throughout the routines used for the C/S 
-calculation.  Most of these functions are from Numerical Recipes in C by Press. */
-
-#include "defs.h"
-
-#define NR_END 1
-#define FREE_ARG char*
-
-extern char errstr[200];  // error string that all routines have access to
-
-void nrerror(char error_text[])
-/* Numerical Recipes standard error handler */
-{
- fprintf(stderr,"Numerical Recipes run-time error...\n");
- fprintf(stderr,"%s\n",error_text);
- fprintf(stderr,"...now exiting to system...\n");
- exit(1);
-}
-
-float *fvector(int nl, int nh)
-/* allocate a float vector with subscript range v[nl..nh] */
-{
- float *v;
- v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
- if (!v) nrerror("allocation failure in fvector()");
- return v-nl+NR_END;
-}
-
-
-void free_fvector(float *v, int nl, int nh)
-/* free a float vector allocated with fvector() */
-{
- free((FREE_ARG) (v+nl-NR_END));
-}
-
-
-float **fmatrix(int nrl, int nrh, int ncl, int nch)
-/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
-{
- int i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
- float **m;
- /* allocate pointers to rows */
- m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
- if (!m) nrerror("allocation failure 1 in matrix()");
- m += NR_END;
- m -= nrl;
- /* allocate rows and set pointers to them */
- m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
- if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
- m[nrl] += NR_END;
- m[nrl] -= ncl;
- for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
- /* return pointer to array of pointers to rows */
- return m;
-}
-
-void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch)
-/* free a float matrix allocated by fmatrix() */
-{
- free((FREE_ARG) (m[nrl]+ncl-NR_END));
- free((FREE_ARG) (m+nrl-NR_END));
-}
-
-int copy_grid_geometry(FLOAT_GRID *grid_old, FLOAT_GRID *grid_new)
-// Copies geometric grid information from grid_old to grid_new
-{
-	grid_new->start.x = grid_old->start.x;
-	grid_new->start.y = grid_old->start.y;
-	grid_new->start.z = grid_old->start.z;
-
-	grid_new->inc.x = grid_old->inc.x;
-	grid_new->inc.y = grid_old->inc.y;
-	grid_new->inc.z = grid_old->inc.z;
-
-	grid_new->x_count = grid_old->x_count;
-	grid_new->y_count = grid_old->y_count;
-	grid_new->z_count = grid_old->z_count;
-
-	return(SUCCESS);
-}
-
-int binSearch(float *a, float searchnum, int M)
-/* Accepts a float array of data of length M ordered lowest to highest and a number called searchnum. 
-Returns the index of the first element of the array, a, that is less than the searchnum. 
-If the searchnum is less than a[0], then -1 is returned, and if the searchnum is greater 
-than or equal to M, then M is returned. */
-{
-    int found, mid, top, bottom;
-
-    bottom = 0;
-    top = M-1;
-
-    found = 0;  // flag that is set to 1 once the proper index is found
- 
-    // Ensure that the search parameter lies inside boundaries
-	if(searchnum >= a[top])
-		return(M); 
-	if(searchnum <= a[bottom])
-		return(-1);
-
-	while(!found)
-	{
-		mid = (top + bottom) / 2;
-		if(searchnum == a[mid])
-			found = 1;
-		else
-			if(searchnum < a[mid])
-				top = mid - 1;
-			else
-				if(searchnum > a[mid + 1])
-					bottom = mid + 1;
-				else
-					found = 1; 
-	}
-	return(mid);
-}
+/* util.c */
+/* Functions that are used for utility throughout the routines used for the C/S 
+calculation.  Most of these functions are from Numerical Recipes in C by Press. */
+
+#include "defs.h"
+
+#define NR_END 1
+#define FREE_ARG char*
+
+extern char errstr[200];  // error string that all routines have access to
+
+void nrerror(char error_text[])
+/* Numerical Recipes standard error handler */
+{
+ fprintf(stderr,"Numerical Recipes run-time error...\n");
+ fprintf(stderr,"%s\n",error_text);
+ fprintf(stderr,"...now exiting to system...\n");
+ exit(1);
+}
+
+float *fvector(int nl, int nh)
+/* allocate a float vector with subscript range v[nl..nh] */
+{
+ float *v;
+ v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
+ if (!v) nrerror("allocation failure in fvector()");
+ return v-nl+NR_END;
+}
+
+
+void free_fvector(float *v, int nl, int nh)
+/* free a float vector allocated with fvector() */
+{
+ free((FREE_ARG) (v+nl-NR_END));
+}
+
+
+float **fmatrix(int nrl, int nrh, int ncl, int nch)
+/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
+{
+ int i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
+ float **m;
+ /* allocate pointers to rows */
+ m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
+ if (!m) nrerror("allocation failure 1 in matrix()");
+ m += NR_END;
+ m -= nrl;
+ /* allocate rows and set pointers to them */
+ m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
+ if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
+ m[nrl] += NR_END;
+ m[nrl] -= ncl;
+ for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
+ /* return pointer to array of pointers to rows */
+ return m;
+}
+
+void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch)
+/* free a float matrix allocated by fmatrix() */
+{
+ free((FREE_ARG) (m[nrl]+ncl-NR_END));
+ free((FREE_ARG) (m+nrl-NR_END));
+}
+
+int copy_grid_geometry(FLOAT_GRID *grid_old, FLOAT_GRID *grid_new)
+// Copies geometric grid information from grid_old to grid_new
+{
+	grid_new->start.x = grid_old->start.x;
+	grid_new->start.y = grid_old->start.y;
+	grid_new->start.z = grid_old->start.z;
+
+	grid_new->inc.x = grid_old->inc.x;
+	grid_new->inc.y = grid_old->inc.y;
+	grid_new->inc.z = grid_old->inc.z;
+
+	grid_new->x_count = grid_old->x_count;
+	grid_new->y_count = grid_old->y_count;
+	grid_new->z_count = grid_old->z_count;
+
+	return(SUCCESS);
+}
+
+int binSearch(float *a, float searchnum, int M)
+/* Accepts a float array of data of length M ordered lowest to highest and a number called searchnum. 
+Returns the index of the first element of the array, a, that is less than the searchnum. 
+If the searchnum is less than a[0], then -1 is returned, and if the searchnum is greater 
+than or equal to M, then M is returned. */
+{
+    int found, mid, top, bottom;
+
+    bottom = 0;
+    top = M-1;
+
+    found = 0;  // flag that is set to 1 once the proper index is found
+ 
+    // Ensure that the search parameter lies inside boundaries
+	if(searchnum >= a[top])
+		return(M); 
+	if(searchnum <= a[bottom])
+		return(-1);
+
+	while(!found)
+	{
+		mid = (top + bottom) / 2;
+		if(searchnum == a[mid])
+			found = 1;
+		else
+			if(searchnum < a[mid])
+				top = mid - 1;
+			else
+				if(searchnum > a[mid + 1])
+					bottom = mid + 1;
+				else
+					found = 1; 
+	}
+	return(mid);
+}

+ 61 - 61
WiscPlan-SourceCode/source-code-photon-linux/calc_deff.cpp

@@ -1,61 +1,61 @@
-/* calc_deff.cpp */
-
-/* Calculates the effective depth of each voxel in the tumor mask. */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-//prototype for Siddon raytrace routine (point to point)
-int raytrace(FLOAT_GRID *,FLOAT_GRID *,POINT,POINT);
-
-int calc_deff(FLOAT_GRID *dens, FLOAT_GRID *deff, FLOAT_GRID *terma_mask, BEAM *bm)
-{
- int i, j, k;
-
- // points that will be used for raytrace operation
- POINT p1;
- POINT p2;  
-
- // Raytracing is only done for voxels that non-zero in the terma_mask.
-
- //initialize deff, with -1 signifying voxels of interest in the raytrace
- for (k=0;k<deff->z_count;k++)
-  for (j=0;j<deff->y_count;j++)
-   for (i=0;i<deff->x_count;i++)
-    // we only care about voxels for which the terma_mask is positive
-	if (GRID_VALUE(terma_mask,i,j,k) > 0)
-		GRID_VALUE(deff,i,j,k) = -1.0;
- 
-     // Set the x-ray origin to the the source location 
-     p1.x = bm->y_vec[0];
-     p1.y = bm->y_vec[1];
-     p1.z = bm->y_vec[2];
-
-     // calculate the radiological depth for all voxels in the terma_mask
-
-     for (k=0;k<deff->z_count;k++)
-      for (j=0;j<deff->y_count;j++)
-       for (i=0;i<deff->x_count;i++)
-	    if (GRID_VALUE(deff,i,j,k) == -1.0)
-		{
-	       // The start location is the center of the voxel at (i,j,k).
-	       // Since raytrace works with voxel sides rather than centers,
-	       // need to shift the input by half a voxel in the negative 
-	       // direction for each voxel dimension.
-
-	       p2.x = deff->start.x + ((float) i)*deff->inc.x;
-	       p2.y = deff->start.y + ((float) j)*deff->inc.y;
-           p2.z = deff->start.z + ((float) k)*deff->inc.z;
-
-		   // extend the ray by a factor of 10 to include more voxels in the raytrace
-		   p2.x = p1.x + (p2.x-p1.x)*(float)10.0;
-		   p2.y = p1.y + (p2.y-p1.y)*(float)10.0;
-		   p2.z = p1.z + (p2.z-p1.z)*(float)10.0;
-
-	       // do the raytrace, filling in voxels that are passed on the way
-	       raytrace(dens,deff,p1,p2);
-		} 
-
- return(SUCCESS);
-}
+/* calc_deff.cpp */
+
+/* Calculates the effective depth of each voxel in the tumor mask. */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+//prototype for Siddon raytrace routine (point to point)
+int raytrace(FLOAT_GRID *,FLOAT_GRID *,POINT,POINT);
+
+int calc_deff(FLOAT_GRID *dens, FLOAT_GRID *deff, FLOAT_GRID *terma_mask, BEAM *bm)
+{
+ int i, j, k;
+
+ // points that will be used for raytrace operation
+ POINT p1;
+ POINT p2;  
+
+ // Raytracing is only done for voxels that non-zero in the terma_mask.
+
+ //initialize deff, with -1 signifying voxels of interest in the raytrace
+ for (k=0;k<deff->z_count;k++)
+  for (j=0;j<deff->y_count;j++)
+   for (i=0;i<deff->x_count;i++)
+    // we only care about voxels for which the terma_mask is positive
+	if (GRID_VALUE(terma_mask,i,j,k) > 0)
+		GRID_VALUE(deff,i,j,k) = -1.0;
+ 
+     // Set the x-ray origin to the the source location 
+     p1.x = bm->y_vec[0];
+     p1.y = bm->y_vec[1];
+     p1.z = bm->y_vec[2];
+
+     // calculate the radiological depth for all voxels in the terma_mask
+
+     for (k=0;k<deff->z_count;k++)
+      for (j=0;j<deff->y_count;j++)
+       for (i=0;i<deff->x_count;i++)
+	    if (GRID_VALUE(deff,i,j,k) == -1.0)
+		{
+	       // The start location is the center of the voxel at (i,j,k).
+	       // Since raytrace works with voxel sides rather than centers,
+	       // need to shift the input by half a voxel in the negative 
+	       // direction for each voxel dimension.
+
+	       p2.x = deff->start.x + ((float) i)*deff->inc.x;
+	       p2.y = deff->start.y + ((float) j)*deff->inc.y;
+           p2.z = deff->start.z + ((float) k)*deff->inc.z;
+
+		   // extend the ray by a factor of 10 to include more voxels in the raytrace
+		   p2.x = p1.x + (p2.x-p1.x)*(float)10.0;
+		   p2.y = p1.y + (p2.y-p1.y)*(float)10.0;
+		   p2.z = p1.z + (p2.z-p1.z)*(float)10.0;
+
+	       // do the raytrace, filling in voxels that are passed on the way
+	       raytrace(dens,deff,p1,p2);
+		} 
+
+ return(SUCCESS);
+}

+ 360 - 360
WiscPlan-SourceCode/source-code-photon-linux/calc_dose.cpp

@@ -1,360 +1,360 @@
-/* calc_dose.cpp */
-
-/* The dose at all voxels in the grid dose_mask is calculated using a convolution
-method that uses a polyenergetic kernel. Inhomogeneities are accounted for by kernel
-scaling, and an inverse square correction is applied after the convolution of the terma
-grid with the kernel, rather than being applied directly to the terma grid before
-the convolution. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <math.h>
-#include <string.h>
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int calc_dose(FLOAT_GRID *density, FLOAT_GRID *terma,FLOAT_GRID *dose, KERNEL *kern, 
-			  BEAM *bm, FLOAT_GRID *dose_mask)
-{
- int i, j, k, l;
- int p, q, r;
- int M, N, Q;  // dimensions of CT array
- int inter_i, inter_j, inter_k;
- int r_index;
- int baseindex;
- float SAD;
- float del_x, del_y, del_z;
- float current_x, current_y, current_z;
- float inter_x, inter_y, inter_z;
- float r_eff, delr_eff, inter_r_eff;
- float kval;
- float cumval, last_cumval;
- float length;
- float *ip, *jp, *kp;
- float dx, dy, dz;
- float delr;  // convolution step size
- float t, u, v, f;
- float *x, *y, *z;  // vectors of CT coordinates
- float *phi, *theta, *sinphi, *cosphi, *sintheta, *costheta;
- float one;
- float rho;
-
- one = (float)1.0; 
-
- // copy CT dimensions and voxel sizes for shorter references later
- M = density->x_count;
- N = density->y_count;
- Q = density->z_count;
-
- dx = density->inc.x;
- dy = density->inc.y;
- dz = density->inc.z;
-
- // copy vectors describing the beam's eye view coordinate system as well
- ip = fvector(0,2);   // ip and jp span the beam's eye view
- jp = fvector(0,2);
- kp = fvector(0,2);   // beam direction
- 
- // create the unit vector describing the beam direction
- for (j=0;j<3;j++) ip[j] = bm->ip[j];
- for (j=0;j<3;j++) jp[j] = bm->jp[j];
- for (j=0;j<3;j++) kp[j] = bm->kp[j];
-
- // vectors describing the location of each voxel
- x = fvector(0,M-1);
- y = fvector(0,N-1);
- z = fvector(0,Q-1);
-
- // lookup table for vectors in polar coordinates
- phi = fvector(0,NPHI-1);
- theta = fvector(0,NTHETA-1);
- sinphi = fvector(0,NPHI-1);
- cosphi = fvector(0,NPHI-1);
- sintheta = fvector(0,NTHETA-1);
- costheta = fvector(0,NTHETA-1);
-
- //kernel with fewer elements for faster calculation
- //see defs.h
- KERNEL smallkern;
- smallkern.radial_boundary = (float *)malloc(kern->nradii*sizeof(float));
- smallkern.angular_boundary = (float *)malloc(kern->ntheta*sizeof(float));
- //small kernel dimensions
- smallkern.nradii = N_KERNEL_RADII;	 //same as original kernel
- smallkern.ntheta = NTHETA;	//must divide evenly into N_KERNEL_ANGLES
-
- SAD = bm->SAD;
- 
- for (i=0;i<N_KERNEL_CATEGORIES;i++)
-  if ( (smallkern.matrix[i] =
-   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
-	return(FAILURE);
-   }
- 
- if ( (smallkern.total_matrix =
-   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for total matrix\n");
-	return(FAILURE);
-   }
-  
- //set up boundaries
- for (i=0;i<smallkern.ntheta;i++)
-  smallkern.angular_boundary[i]	= ( (float) i + 1) * (float)180.0/(float) smallkern.ntheta;
- for (i=0;i<smallkern.nradii;i++)
-  smallkern.radial_boundary[i] = kern->radial_boundary[i];
-  
- //initialise 
-  for (i=0;i<smallkern.nradii;i++)
-   for (j=0;j<smallkern.ntheta;j++)
-   {
-    KERNEL_TOTAL_VALUE(&smallkern,i,j) = (float)0.0;
-    for (l=0;l<N_KERNEL_CATEGORIES;l++)
-      KERNEL_VALUE(&smallkern,l,i,j) = (float)0.0;
-   }
-
- //create kernel values
- for (i=0;i<smallkern.nradii;i++)
-  for (j=0;j<smallkern.ntheta;j++)
-  {   
-   //first angular index in original kernel for this element 
-   baseindex = j*N_KERNEL_ANGLES/NTHETA;
-   //for each category, sum values from original kernel 
-   for (l=0;l<N_KERNEL_CATEGORIES;l++)
-    for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
-     KERNEL_VALUE(&smallkern,l,i,j) += KERNEL_VALUE(kern,l,i,baseindex+k);
-   //and for total kernel
-   for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
-    KERNEL_TOTAL_VALUE(&smallkern,i,j) += KERNEL_TOTAL_VALUE(kern,i,baseindex+k);
-  }
- 
- //Make cumulative kernel (with radius)
- //this is what is used for the dose calculation 
- for (p=0;p<smallkern.ntheta;p++)
-  for (r=0;r<smallkern.nradii;r++)
-  { 
-   for (i=0;i<N_KERNEL_CATEGORIES;i++)
-    if (r > 0)
-     KERNEL_VALUE(&smallkern,i,r,p)
-     = KERNEL_VALUE(&smallkern,i,r-1,p) + KERNEL_VALUE(&smallkern,i,r,p);
-   if (r > 0)
-    KERNEL_TOTAL_VALUE(&smallkern,r,p)
-    = KERNEL_TOTAL_VALUE(&smallkern,r-1,p) + KERNEL_TOTAL_VALUE(&smallkern,r,p);
-  }
-
-  // fill the coordinate vectors
- for (i=0;i<M;i++) x[i] = density->start.x + (float)i*dx;
- for (j=0;j<N;j++) y[j] = density->start.y + (float)j*dy;
- for (k=0;k<Q;k++) z[k] = density->start.z + (float)k*dz;
-
- // fill in the polar coordinates vectors
- for (q=0;q<NPHI;q++) 
- {
-	 phi[q] = ((float)q + (float)0.5)*(float)2.0*(float)PI/(float)NPHI;
-	 sinphi[q] = (float)sin(phi[q]);
-	 cosphi[q] = (float)cos(phi[q]);
- }
-
- // Theta is subtracted from PI is because direction of travel along kernel ray is actually opposite of 
- // direction along which energy is radiating, so need to use a source voxel direction that 
- // is reflected about horizontal.  This can be thought of as the kernel inversion line.
-
- for (p=0;p<smallkern.ntheta;p++)
-  if (p == 0)
-  {
-   theta[p] = (float)0.5*smallkern.angular_boundary[0]*(float)PI/(float)180.0;
-   sintheta[p] = (float)sin((float)PI - theta[p]);
-   costheta[p] = (float)cos((float)PI - theta[p]);
-  }
-  else
-  {
-   theta[p] = (float)0.5*(smallkern.angular_boundary[p-1] + smallkern.angular_boundary[p])*(float)PI/(float)180.0;
-   sintheta[p] = (float)sin((float)PI - theta[p]);
-   costheta[p] = (float)cos((float)PI - theta[p]);
-  }
- 
- // store the sines and cosines in a lookup table
-
- // the step size for the convolution integration is the smallest voxel side length
- if (dx <= dy && dx <= dz)
-	 delr = (float)2.0*dx;
- else if (dy <= dx && dy <= dz)
-	 delr = (float)2.0*dy;
- else
-	 delr = (float)2.0*dz;
-
- //calculate dose at each point
- //done from deposition (catcher's) point of view
- for (k=0;k<Q; k++)
-  for (j=0;j<N; j++)
-   for (i=0;i<M; i++)
-	if (GRID_VALUE(dose_mask,i,j,k) > 0)  // only calculate dose inside dose mask
-	{
-	// do the integral for the point in the ROI
-	for (p=0;p<smallkern.ntheta;p++) //polar
-	 for (q=0;q<NPHI;q++) //azimuthal
-	 {
-	  //initialise position of current voxel
-	  current_x = x[i];
-	  current_y = y[j];
-	  current_z = z[k];
-
-	  //initialise effective radius along kernel direction
-	  r_eff = 0.0;
-	  //initialise cumulative kernel value for this direction
-	  last_cumval = 0.0;
-
-      //Using reciprocity technique where dose at point A due to point B
-	  //is dose at point B due to point A 
-
-      //x ,y, z increments along ray
-	  del_x = delr*(ip[0]*cosphi[q]*sintheta[p] + jp[0]*sinphi[q]*sintheta[p]
-			      + kp[0]*costheta[p]);
-	  del_y = delr*(ip[1]*cosphi[q]*sintheta[p] + jp[1]*sinphi[q]*sintheta[p]
-			      + kp[1]*costheta[p]);
-	  del_z = delr*(ip[2]*cosphi[q]*sintheta[p] + jp[2]*sinphi[q]*sintheta[p]
-			      + kp[2]*costheta[p]);
-
-	  //initialise physical radius
-	  r = 0;
-	  do
-	  {
-	    //interaction point is at mid-point of curent increment
-	    inter_x = current_x + (float)0.5*del_x;
-	    inter_y = current_y + (float)0.5*del_y;
-	    inter_z = current_z + (float)0.5*del_z;
-
-	    //voxel containing interaction point
-	    inter_i = (int) ((inter_x - density->start.x)/dx);
-	    inter_j = (int) ((inter_y - density->start.y)/dy);
-	    inter_k = (int) ((inter_z - density->start.z)/dz);
-	   
-	   // stop the integral if interaction point is outside the dose calculation limits
-	   if (    (inter_i < 0) || (inter_i + 1 >= M)
-	        || (inter_j < 0) || (inter_j + 1 >= N)
-	   	    || (inter_k < 0) || (inter_k + 1 >= Q)
-			|| (GRID_VALUE(dose_mask,inter_i,inter_j,inter_k) <= 0.0))
-		  break;
-
-	   	// Position of the end of the increment.  Interaction point is at the
-	    // midpoint.
-        current_x += del_x;
-	    current_y += del_y;
-	    current_z += del_z;
-        
-        //effective distance increment
-        delr_eff = delr*GRID_VALUE(density,inter_i,inter_j,inter_k);
-		//effective radius of interaction point
-		inter_r_eff = r_eff + (float)0.5*delr_eff;
-	    r_eff += delr_eff;
-
-		// trilinear interpolation method of the terma contribution, f
-
-		// relative differences between the interaction point and the lower voxel bound
-		t = (inter_x - x[inter_i])/dx;
-		u = (inter_y - y[inter_j])/dy;
-		v = (inter_z - z[inter_k])/dz; 
-
-		f = GRID_VALUE(terma,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
-		  + GRID_VALUE(terma,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
-		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
-		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k+1)*t*u*v
-		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
-		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
-		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
-		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); 
-
-		/* 
-		// interpolate density at the interaction point
-		rho = GRID_VALUE(density,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
-		    + GRID_VALUE(density,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
-		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
-		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k+1)*t*u*v
-		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
-		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
-		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
-		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); */
-
-		// perform kernel lookup for r_eff, r_index is the kernel index of the first 
-		// bin boundary below the effective radius of the voxel
-		r_index = binSearch(smallkern.radial_boundary,inter_r_eff,smallkern.nradii);
-
-		// interpolate to obtain the effective cumulative kernel value
-		if (r_index == -1)  // radius is between zero and the first bin boundary
-		{
-			// fractional difference between inter_r_eff and the first bin boundary
-			t = inter_r_eff/smallkern.radial_boundary[0];
-			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,0,p);
-		}
-		else if (r_index >= smallkern.nradii-1)  // overshot the kernel bin boundaries
-		{
-			cumval = KERNEL_TOTAL_VALUE(&smallkern,smallkern.nradii-1,p);
-		}
-		else  // inter_r_eff is between the first upper bin boundary and the last
-		{
-			t = (inter_r_eff - smallkern.radial_boundary[r_index])
-				/(smallkern.radial_boundary[r_index + 1] - smallkern.radial_boundary[r_index]);
-			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,r_index,p)
-				       + t*KERNEL_TOTAL_VALUE(&smallkern,r_index+1,p);
-		}
-
-        kval = cumval - last_cumval;
-
-      	last_cumval = cumval;
-
-		// Kernel value to use is current increment in cumulative value
-        // Note that this is the fractional dose deposited at i,j,k due to
-        // terma in an effective increment (increment*density) along the kernel ray at the 
-		// interaction point. The value comes from the fractional dose deposited in an 
-		// effective increment along the ray	at i,j,k due to terma at the current 
-		// interaction point.
-
-	    //Increment dose value.
-	    //Note that to include the effect of density at i,j,k on ENERGY deposited at i,j,k, 
-	    //there should be a density term, but this cancels on conversion of energy to dose as indicated below
-	    // if (GRID_VALUE(terma,inter_i,inter_j,inter_k) > 0.001)
-	    GRID_VALUE(dose,i,j,k) += f*kval;
-
-	   r++;
-	  }
-	  while (r<10000);
-	 }	//p,q
- 
-      GRID_VALUE(dose,i,j,k)/= NPHI;
-    }
-
- //Inverse square correction to dose
- //This works better than applying the inverse square correction to terma
- //See Papanikolaou and Mackie 1993
- for (k=0;k<Q;k++)
-  for (j=0;j<N;j++)
-	for (i=0;i<M;i++)
-   if (GRID_VALUE(dose,i,j,k) > 0.0)
-   {
-	   // squared difference between the source and the voxel
-	   length = (float)pow(x[i] - bm->y_vec[0],2.0f) + (float)pow(y[j] - bm->y_vec[1],2.0f) 
-		   + (float)pow(z[k] - bm->y_vec[2],2.0f);
-	   
-	   if (length > 0.0)
-	      GRID_VALUE(dose,i,j,k) *= SAD*SAD/length;
-   } 
-
-   // free vectors
-   free_fvector(ip,0,2);
-   free_fvector(jp,0,2);
-   free_fvector(kp,0,2);
-   free_fvector(x,0,M-1);
-   free_fvector(y,0,N-1);
-   free_fvector(z,0,Q-1);
-   
-   free(smallkern.angular_boundary);
-   free(smallkern.radial_boundary);
-   // free(poly_kernel.total_matrix);
-   for (j=0;j<N_KERNEL_CATEGORIES;j++)
-	   free(smallkern.matrix[j]);
-
-   return(SUCCESS);
-}
+/* calc_dose.cpp */
+
+/* The dose at all voxels in the grid dose_mask is calculated using a convolution
+method that uses a polyenergetic kernel. Inhomogeneities are accounted for by kernel
+scaling, and an inverse square correction is applied after the convolution of the terma
+grid with the kernel, rather than being applied directly to the terma grid before
+the convolution. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <math.h>
+#include <string.h>
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int calc_dose(FLOAT_GRID *density, FLOAT_GRID *terma,FLOAT_GRID *dose, KERNEL *kern, 
+			  BEAM *bm, FLOAT_GRID *dose_mask)
+{
+ int i, j, k, l;
+ int p, q, r;
+ int M, N, Q;  // dimensions of CT array
+ int inter_i, inter_j, inter_k;
+ int r_index;
+ int baseindex;
+ float SAD;
+ float del_x, del_y, del_z;
+ float current_x, current_y, current_z;
+ float inter_x, inter_y, inter_z;
+ float r_eff, delr_eff, inter_r_eff;
+ float kval;
+ float cumval, last_cumval;
+ float length;
+ float *ip, *jp, *kp;
+ float dx, dy, dz;
+ float delr;  // convolution step size
+ float t, u, v, f;
+ float *x, *y, *z;  // vectors of CT coordinates
+ float *phi, *theta, *sinphi, *cosphi, *sintheta, *costheta;
+ float one;
+ float rho;
+
+ one = (float)1.0; 
+
+ // copy CT dimensions and voxel sizes for shorter references later
+ M = density->x_count;
+ N = density->y_count;
+ Q = density->z_count;
+
+ dx = density->inc.x;
+ dy = density->inc.y;
+ dz = density->inc.z;
+
+ // copy vectors describing the beam's eye view coordinate system as well
+ ip = fvector(0,2);   // ip and jp span the beam's eye view
+ jp = fvector(0,2);
+ kp = fvector(0,2);   // beam direction
+ 
+ // create the unit vector describing the beam direction
+ for (j=0;j<3;j++) ip[j] = bm->ip[j];
+ for (j=0;j<3;j++) jp[j] = bm->jp[j];
+ for (j=0;j<3;j++) kp[j] = bm->kp[j];
+
+ // vectors describing the location of each voxel
+ x = fvector(0,M-1);
+ y = fvector(0,N-1);
+ z = fvector(0,Q-1);
+
+ // lookup table for vectors in polar coordinates
+ phi = fvector(0,NPHI-1);
+ theta = fvector(0,NTHETA-1);
+ sinphi = fvector(0,NPHI-1);
+ cosphi = fvector(0,NPHI-1);
+ sintheta = fvector(0,NTHETA-1);
+ costheta = fvector(0,NTHETA-1);
+
+ //kernel with fewer elements for faster calculation
+ //see defs.h
+ KERNEL smallkern;
+ smallkern.radial_boundary = (float *)malloc(kern->nradii*sizeof(float));
+ smallkern.angular_boundary = (float *)malloc(kern->ntheta*sizeof(float));
+ //small kernel dimensions
+ smallkern.nradii = N_KERNEL_RADII;	 //same as original kernel
+ smallkern.ntheta = NTHETA;	//must divide evenly into N_KERNEL_ANGLES
+
+ SAD = bm->SAD;
+ 
+ for (i=0;i<N_KERNEL_CATEGORIES;i++)
+  if ( (smallkern.matrix[i] =
+   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
+	return(FAILURE);
+   }
+ 
+ if ( (smallkern.total_matrix =
+   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for total matrix\n");
+	return(FAILURE);
+   }
+  
+ //set up boundaries
+ for (i=0;i<smallkern.ntheta;i++)
+  smallkern.angular_boundary[i]	= ( (float) i + 1) * (float)180.0/(float) smallkern.ntheta;
+ for (i=0;i<smallkern.nradii;i++)
+  smallkern.radial_boundary[i] = kern->radial_boundary[i];
+  
+ //initialise 
+  for (i=0;i<smallkern.nradii;i++)
+   for (j=0;j<smallkern.ntheta;j++)
+   {
+    KERNEL_TOTAL_VALUE(&smallkern,i,j) = (float)0.0;
+    for (l=0;l<N_KERNEL_CATEGORIES;l++)
+      KERNEL_VALUE(&smallkern,l,i,j) = (float)0.0;
+   }
+
+ //create kernel values
+ for (i=0;i<smallkern.nradii;i++)
+  for (j=0;j<smallkern.ntheta;j++)
+  {   
+   //first angular index in original kernel for this element 
+   baseindex = j*N_KERNEL_ANGLES/NTHETA;
+   //for each category, sum values from original kernel 
+   for (l=0;l<N_KERNEL_CATEGORIES;l++)
+    for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
+     KERNEL_VALUE(&smallkern,l,i,j) += KERNEL_VALUE(kern,l,i,baseindex+k);
+   //and for total kernel
+   for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
+    KERNEL_TOTAL_VALUE(&smallkern,i,j) += KERNEL_TOTAL_VALUE(kern,i,baseindex+k);
+  }
+ 
+ //Make cumulative kernel (with radius)
+ //this is what is used for the dose calculation 
+ for (p=0;p<smallkern.ntheta;p++)
+  for (r=0;r<smallkern.nradii;r++)
+  { 
+   for (i=0;i<N_KERNEL_CATEGORIES;i++)
+    if (r > 0)
+     KERNEL_VALUE(&smallkern,i,r,p)
+     = KERNEL_VALUE(&smallkern,i,r-1,p) + KERNEL_VALUE(&smallkern,i,r,p);
+   if (r > 0)
+    KERNEL_TOTAL_VALUE(&smallkern,r,p)
+    = KERNEL_TOTAL_VALUE(&smallkern,r-1,p) + KERNEL_TOTAL_VALUE(&smallkern,r,p);
+  }
+
+  // fill the coordinate vectors
+ for (i=0;i<M;i++) x[i] = density->start.x + (float)i*dx;
+ for (j=0;j<N;j++) y[j] = density->start.y + (float)j*dy;
+ for (k=0;k<Q;k++) z[k] = density->start.z + (float)k*dz;
+
+ // fill in the polar coordinates vectors
+ for (q=0;q<NPHI;q++) 
+ {
+	 phi[q] = ((float)q + (float)0.5)*(float)2.0*(float)PI/(float)NPHI;
+	 sinphi[q] = (float)sin(phi[q]);
+	 cosphi[q] = (float)cos(phi[q]);
+ }
+
+ // Theta is subtracted from PI is because direction of travel along kernel ray is actually opposite of 
+ // direction along which energy is radiating, so need to use a source voxel direction that 
+ // is reflected about horizontal.  This can be thought of as the kernel inversion line.
+
+ for (p=0;p<smallkern.ntheta;p++)
+  if (p == 0)
+  {
+   theta[p] = (float)0.5*smallkern.angular_boundary[0]*(float)PI/(float)180.0;
+   sintheta[p] = (float)sin((float)PI - theta[p]);
+   costheta[p] = (float)cos((float)PI - theta[p]);
+  }
+  else
+  {
+   theta[p] = (float)0.5*(smallkern.angular_boundary[p-1] + smallkern.angular_boundary[p])*(float)PI/(float)180.0;
+   sintheta[p] = (float)sin((float)PI - theta[p]);
+   costheta[p] = (float)cos((float)PI - theta[p]);
+  }
+ 
+ // store the sines and cosines in a lookup table
+
+ // the step size for the convolution integration is the smallest voxel side length
+ if (dx <= dy && dx <= dz)
+	 delr = (float)2.0*dx;
+ else if (dy <= dx && dy <= dz)
+	 delr = (float)2.0*dy;
+ else
+	 delr = (float)2.0*dz;
+
+ //calculate dose at each point
+ //done from deposition (catcher's) point of view
+ for (k=0;k<Q; k++)
+  for (j=0;j<N; j++)
+   for (i=0;i<M; i++)
+	if (GRID_VALUE(dose_mask,i,j,k) > 0)  // only calculate dose inside dose mask
+	{
+	// do the integral for the point in the ROI
+	for (p=0;p<smallkern.ntheta;p++) //polar
+	 for (q=0;q<NPHI;q++) //azimuthal
+	 {
+	  //initialise position of current voxel
+	  current_x = x[i];
+	  current_y = y[j];
+	  current_z = z[k];
+
+	  //initialise effective radius along kernel direction
+	  r_eff = 0.0;
+	  //initialise cumulative kernel value for this direction
+	  last_cumval = 0.0;
+
+      //Using reciprocity technique where dose at point A due to point B
+	  //is dose at point B due to point A 
+
+      //x ,y, z increments along ray
+	  del_x = delr*(ip[0]*cosphi[q]*sintheta[p] + jp[0]*sinphi[q]*sintheta[p]
+			      + kp[0]*costheta[p]);
+	  del_y = delr*(ip[1]*cosphi[q]*sintheta[p] + jp[1]*sinphi[q]*sintheta[p]
+			      + kp[1]*costheta[p]);
+	  del_z = delr*(ip[2]*cosphi[q]*sintheta[p] + jp[2]*sinphi[q]*sintheta[p]
+			      + kp[2]*costheta[p]);
+
+	  //initialise physical radius
+	  r = 0;
+	  do
+	  {
+	    //interaction point is at mid-point of curent increment
+	    inter_x = current_x + (float)0.5*del_x;
+	    inter_y = current_y + (float)0.5*del_y;
+	    inter_z = current_z + (float)0.5*del_z;
+
+	    //voxel containing interaction point
+	    inter_i = (int) ((inter_x - density->start.x)/dx);
+	    inter_j = (int) ((inter_y - density->start.y)/dy);
+	    inter_k = (int) ((inter_z - density->start.z)/dz);
+	   
+	   // stop the integral if interaction point is outside the dose calculation limits
+	   if (    (inter_i < 0) || (inter_i + 1 >= M)
+	        || (inter_j < 0) || (inter_j + 1 >= N)
+	   	    || (inter_k < 0) || (inter_k + 1 >= Q)
+			|| (GRID_VALUE(dose_mask,inter_i,inter_j,inter_k) <= 0.0))
+		  break;
+
+	   	// Position of the end of the increment.  Interaction point is at the
+	    // midpoint.
+        current_x += del_x;
+	    current_y += del_y;
+	    current_z += del_z;
+        
+        //effective distance increment
+        delr_eff = delr*GRID_VALUE(density,inter_i,inter_j,inter_k);
+		//effective radius of interaction point
+		inter_r_eff = r_eff + (float)0.5*delr_eff;
+	    r_eff += delr_eff;
+
+		// trilinear interpolation method of the terma contribution, f
+
+		// relative differences between the interaction point and the lower voxel bound
+		t = (inter_x - x[inter_i])/dx;
+		u = (inter_y - y[inter_j])/dy;
+		v = (inter_z - z[inter_k])/dz; 
+
+		f = GRID_VALUE(terma,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
+		  + GRID_VALUE(terma,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
+		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
+		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k+1)*t*u*v
+		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
+		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
+		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
+		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); 
+
+		/* 
+		// interpolate density at the interaction point
+		rho = GRID_VALUE(density,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
+		    + GRID_VALUE(density,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
+		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
+		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k+1)*t*u*v
+		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
+		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
+		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
+		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); */
+
+		// perform kernel lookup for r_eff, r_index is the kernel index of the first 
+		// bin boundary below the effective radius of the voxel
+		r_index = binSearch(smallkern.radial_boundary,inter_r_eff,smallkern.nradii);
+
+		// interpolate to obtain the effective cumulative kernel value
+		if (r_index == -1)  // radius is between zero and the first bin boundary
+		{
+			// fractional difference between inter_r_eff and the first bin boundary
+			t = inter_r_eff/smallkern.radial_boundary[0];
+			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,0,p);
+		}
+		else if (r_index >= smallkern.nradii-1)  // overshot the kernel bin boundaries
+		{
+			cumval = KERNEL_TOTAL_VALUE(&smallkern,smallkern.nradii-1,p);
+		}
+		else  // inter_r_eff is between the first upper bin boundary and the last
+		{
+			t = (inter_r_eff - smallkern.radial_boundary[r_index])
+				/(smallkern.radial_boundary[r_index + 1] - smallkern.radial_boundary[r_index]);
+			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,r_index,p)
+				       + t*KERNEL_TOTAL_VALUE(&smallkern,r_index+1,p);
+		}
+
+        kval = cumval - last_cumval;
+
+      	last_cumval = cumval;
+
+		// Kernel value to use is current increment in cumulative value
+        // Note that this is the fractional dose deposited at i,j,k due to
+        // terma in an effective increment (increment*density) along the kernel ray at the 
+		// interaction point. The value comes from the fractional dose deposited in an 
+		// effective increment along the ray	at i,j,k due to terma at the current 
+		// interaction point.
+
+	    //Increment dose value.
+	    //Note that to include the effect of density at i,j,k on ENERGY deposited at i,j,k, 
+	    //there should be a density term, but this cancels on conversion of energy to dose as indicated below
+	    // if (GRID_VALUE(terma,inter_i,inter_j,inter_k) > 0.001)
+	    GRID_VALUE(dose,i,j,k) += f*kval;
+
+	   r++;
+	  }
+	  while (r<10000);
+	 }	//p,q
+ 
+      GRID_VALUE(dose,i,j,k)/= NPHI;
+    }
+
+ //Inverse square correction to dose
+ //This works better than applying the inverse square correction to terma
+ //See Papanikolaou and Mackie 1993
+ for (k=0;k<Q;k++)
+  for (j=0;j<N;j++)
+	for (i=0;i<M;i++)
+   if (GRID_VALUE(dose,i,j,k) > 0.0)
+   {
+	   // squared difference between the source and the voxel
+	   length = (float)pow(x[i] - bm->y_vec[0],2.0f) + (float)pow(y[j] - bm->y_vec[1],2.0f) 
+		   + (float)pow(z[k] - bm->y_vec[2],2.0f);
+	   
+	   if (length > 0.0)
+	      GRID_VALUE(dose,i,j,k) *= SAD*SAD/length;
+   } 
+
+   // free vectors
+   free_fvector(ip,0,2);
+   free_fvector(jp,0,2);
+   free_fvector(kp,0,2);
+   free_fvector(x,0,M-1);
+   free_fvector(y,0,N-1);
+   free_fvector(z,0,Q-1);
+   
+   free(smallkern.angular_boundary);
+   free(smallkern.radial_boundary);
+   // free(poly_kernel.total_matrix);
+   for (j=0;j<N_KERNEL_CATEGORIES;j++)
+	   free(smallkern.matrix[j]);
+
+   return(SUCCESS);
+}

+ 396 - 396
WiscPlan-SourceCode/source-code-photon-linux/convolutionCondor.cpp

@@ -1,396 +1,396 @@
-/* Cconvolution.cpp */
-
-#include "defs.h"
-
-//function prototypes
-
-int load_kernels(MONO_KERNELS *, char []);
-int load_geometry(FLOAT_GRID *, char []);
-int pop_beam(BEAM *, FILE *);
-int calc_deff(FLOAT_GRID *,FLOAT_GRID *, FLOAT_GRID *, BEAM *);
-int terma_kerma(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,MONO_KERNELS *,FLOAT_GRID *);
-int make_poly_kernel(MONO_KERNELS *, KERNEL *);
-int calc_dose(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,KERNEL *,BEAM *, FLOAT_GRID *);
-int terma_dose_masks(FLOAT_GRID *, FLOAT_GRID *, BEAM *);
-int convolution(MONO_KERNELS *, BEAM *, FLOAT_GRID *, FILE *);
-
-char errstr[200];  // error string that all routines have access to
-
-int main(int argc, char *argv[])
-//  Expects four input arguments: 
-// 1)  kernel_filenames -- contains a list of the kernel files
-// 2)  geometry_filenames  -- contains a list of the geometry files
-// 3)  beamspec batch file -- locations of beamspec files in batch
-// 4)  beamlet batch file -- locations of resulting beamlets in batch
-{
-	int i,j,b,B;
-
-	char tmpstr[200];
-
-	FLOAT_GRID density;
-
-	MONO_KERNELS mono_kernels;
-
-	BEAM beam;
-
-	FILE *beamspec_batch_file;
-	FILE *beamlet_batch_file;
-
-	/*	// print the arguments
-	printf("Input arguments:\n");
-	for (j=1;j<argc;j++)
-	printf("%s\n",argv[j]); */
-
-	if (argc != 5)
-	{
-		printf("Expecting four input command line arguments, received %d.\n",argc);
-		return(FAILURE);
-	}
-
-	if (load_kernels(&mono_kernels,argv[1]) == FAILURE)
-	{
-		sprintf(tmpstr,"Failed at loading the kernels.\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-        printf("Successfully loaded kernels\n");
-
-	if (load_geometry(&density,argv[2]) == FAILURE)
-	{
-		sprintf(tmpstr,"Failed at loading the geometry.\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-        printf("Successfully loaded geometry files.\n");
-
-	/* 
-	// diagnostic lines
-	printf("SAD = %lf \n",beam.SAD);
-	printf("xp = %lf \n",beam.xp);
-	printf("yp = %lf \n",beam.yp);
-	printf("del_xp = %lf \n",beam.del_xp);
-	printf("del_yp = %lf \n",beam.del_yp);
-	printf("y_vec = (%lf,%lf,%lf) \n",beam.y_vec[0],beam.y_vec[1],beam.y_vec[2]);
-	printf("ip = (%lf,%lf,%lf) \n",beam.ip[0],beam.ip[1],beam.ip[2]);
-	printf("jp = (%lf,%lf,%lf) \n",beam.jp[0],beam.jp[1],beam.jp[2]);
-	printf("kp = (%lf,%lf,%lf) \n",beam.kp[0],beam.kp[1],beam.kp[2]);
-
-	printf("Xcount = %d, Ycount = %d, Zcount = %d \n",density.x_count,density.y_count,density.z_count);
-	printf("start = (%lf,%lf,%lf) \n",density.start.x,density.start.y,density.start.z);
-	printf("inc = (%lf,%lf,%lf) \n",density.inc.x,density.inc.y,density.inc.z); */
-
-
-	// open the beam specification batch file
-	if ((beamspec_batch_file = fopen(argv[3],"r")) == NULL)
-	{
-		printf("Failed to open beamspec batch file %s\n",argv[3]);
-		return(FAILURE);
-	}
-        printf("Successfully loaded beamspec files.\n");
-
-	// open the dose batch file
-	if ((beamlet_batch_file = fopen(argv[4],"wb")) == NULL)
-	{
-		printf("Failed to open beamlet batch file %s\n",argv[4]);
-		return(FAILURE);
-	}
-
-	// get the number of beams from the beamspec batch file
-	if (fgets(tmpstr,100,beamspec_batch_file) == NULL)  // pop off the first line
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	if (fscanf(beamspec_batch_file,"%d\n",&B) != 1)
-	{
-		sprintf(errstr,"Could not read-in number of beams from beamspec file.");
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	// write the number of beamlets in this batch as the first entry
-	fwrite(&B,sizeof(int),1,beamlet_batch_file); 
-
-	// Do convolution calculations for all consistent beamspec and dose
-	// filenames.  If a calculation for a beamlet fails, print an error 
-	// and move on to the next beamspec file.
-	for (b=0;b<B;b++)
-	{
-		// pop off a beam
-		if(pop_beam(&beam,beamspec_batch_file) == FAILURE)
-		{
-			sprintf(tmpstr,"Failed to load beamspec number %d:\n",b);
-			strcat(tmpstr,errstr);
-			strcpy(errstr,tmpstr);
-			printf("%s\n",errstr);
-		}
-		else if (convolution(&mono_kernels,&beam,&density,beamlet_batch_file) == FAILURE)
-		// An error occurred, so print the error string to standard out
-		// but do not terminate the remaining beam batches.
-		{
-			j = 0;
-			fwrite(&beam.num,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.x_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.y_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.z_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&j,sizeof(int),1,beamlet_batch_file);
-			printf("Error in the calculation for beamlet number %d,\n so all zeros were saved for the resulting beamlet file.\n",b);
-			printf("%s\n",errstr);
-		}
-		else
-			printf("Successfully calculated beamlet %d of %s.\n",b,argv[3]); 
-	}
-
-	// close the beamlet file
-	fclose(beamlet_batch_file);
-
-	// free the density grid
-	free(density.matrix);
-
-	// only need to free angular and radial boundaries for the first
-	// kernel, since other kernel boundaries just point to the same place
-	free(mono_kernels.kernel[0].angular_boundary);
-	free(mono_kernels.kernel[0].radial_boundary);
-
-	// free the kernels
-	free(mono_kernels.energy);
-	free(mono_kernels.fluence);
-	free(mono_kernels.mu);
-	free(mono_kernels.mu_en);
- 	for (i=0;i<mono_kernels.nkernels;i++)
-		for (j=0;j<N_KERNEL_CATEGORIES;j++)
-			free(mono_kernels.kernel[i].matrix[j]); 
-
-	return(SUCCESS);
-}
-
-int convolution(MONO_KERNELS *mono_kernels, BEAM *beam, FLOAT_GRID *density, FILE *beamlet_batch_file)
-// routine that actually performs the convolution for a given kernel, beam, and geometry
-{
-	int i,j,M,N,Q,Nind,Ntotal;  // dimensions of the CT density grid
-	int *dose_ind;
-	float *dose_data, doseMax;
-	char tmpstr[200];  // temporary string
-
-	FLOAT_GRID terma_mask;
-	FLOAT_GRID dose_mask;
-	FLOAT_GRID deff;
-	FLOAT_GRID terma;
-	FLOAT_GRID kermac;
-	FLOAT_GRID dose;
-
-	KERNEL poly_kernel;
-
-	// copy the density grid dimensions to the calculation grids
-	copy_grid_geometry(density,&terma_mask);
-	copy_grid_geometry(density,&dose_mask);
-	copy_grid_geometry(density,&deff);
-	copy_grid_geometry(density,&terma);
-	copy_grid_geometry(density,&kermac);
-	copy_grid_geometry(density,&dose);
-
-	// dimensions of all the grids
-	M = density->x_count;
-	N = density->y_count;
-	Q = density->z_count;
-
-	Ntotal = M*N*Q;
-
-	// Allocate memory for all of the grids and fill them all with zeros
-	if ((terma_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for terma_mask.");
-		return(FAILURE);
-	}
-
-	if ((dose_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for dose_mask.");
-		return(FAILURE);
-	}
-
-	if ((deff.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for deff.");
-		return(FAILURE);
-	}
-
-	if ((terma.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for terma.");
-		return(FAILURE);
-	}
-
-	if ((kermac.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for kermac.");
-		return(FAILURE);
-	}
-
-	if ((dose.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for dose.");
-		return(FAILURE);
-	}
-	
-	for (i=0;i<Ntotal;i++)
-	{
-		terma_mask.matrix[i] = 0.0;
-		dose_mask.matrix[i] = 0.0;
-		deff.matrix[i] = 0.0;
-		terma.matrix[i] = 0.0;
-		kermac.matrix[i] = 0.0;
-		dose.matrix[i] = 0.0;
-	} 
-	
-	/* start calculations */
-
-	// If a failure occurs in any calculation, append the error
-	// onto the error string and then return a FAILURE.
-
-	// create terma and dose masks
-	if (SUCCESS != terma_dose_masks(&terma_mask,&dose_mask,beam))
-	{
-		sprintf(tmpstr,"Failed in terma_dose_masks!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-
-	//create polyenergetic kernel from mono kernels and fluence,mu data
-	if (SUCCESS != make_poly_kernel(mono_kernels,&poly_kernel) )
-	{
-		sprintf(tmpstr,"Failed making polyenergetic kernel!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-	
-	//create effective depth array from density array
-	if (SUCCESS != calc_deff(density,&deff,&terma_mask,beam))
-	{
-		sprintf(tmpstr,"Failed in calc_deff!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-        // printf("Successfully calculated deff for beam %d.\n", beam->num);
-
-	//create kerma and terma arrays
-	//note kerma is collision kerma and is used for a kernel hardening correction
-	if (SUCCESS != terma_kerma(&deff,&terma,&kermac,mono_kernels,&terma_mask))
-	{
-		sprintf(tmpstr,"Failed in terma_kerma calculation!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-        // printf("Successfully calculated terma for beam %d.\n", beam->num);
-
-	//use all this stuff to calculate dose
-	if ( (SUCCESS != calc_dose(density,&terma,&dose,&poly_kernel,beam,&dose_mask)) ) 
-	{
-		sprintf(tmpstr,"Failed calculating dose!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-        // printf("Successfully calculated dose for beam %d.\n", beam->num);
-
-	/* //diagnostic lines:
-	FILE *fid;
-	fid = fopen("dose.bin","wb");
-	fwrite(dose.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("terma.bin","wb");
-	fwrite(terma.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("kermac.bin","wb");
-	fwrite(kermac.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("deff.bin","wb");
-	fwrite(deff.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("terma_mask.bin","wb");
-	fwrite(terma_mask.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("dose_mask.bin","wb");
-	fwrite(dose_mask.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("density.bin","wb");
-	fwrite(density->matrix,sizeof(float),Ntotal,fid);
-	fclose(fid); //*/
-
-    // find maximum dose
-	doseMax = 0.0;
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] > doseMax)
-			doseMax = dose.matrix[i];
-
-	// count the number of non-zero dose values
-	Nind = 0;
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
-			&& dose.matrix[i] > 0.0)
-			Nind++;
-		else
-			dose.matrix[i] = 0.0;  // turn off doses below threshold
-
-	// allocate memory for sparse dose data
-	dose_ind = (int *)malloc(sizeof(int)*Nind);
-	dose_data = (float *)malloc(sizeof(float)*Nind);
-
-	// store the sparse data	
-	j = 0;   // index just for the sparse data
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
-			&& dose.matrix[i] > 0.0)
-		{
-			dose_ind[j] = i;
-			dose_data[j] = dose.matrix[i];
-			j++; 
-		}
-
-	// save dose to a file
-
-	// save the total file size first, then the number of non-zero elements
-	fwrite(&beam->num,sizeof(int),1,beamlet_batch_file);
-	fwrite(&M,sizeof(int),1,beamlet_batch_file);
-	fwrite(&N,sizeof(int),1,beamlet_batch_file);
-	fwrite(&Q,sizeof(int),1,beamlet_batch_file);
-    fwrite(&Nind,sizeof(int),1,beamlet_batch_file);
-	fwrite(dose_ind,sizeof(int),Nind,beamlet_batch_file);
-	fwrite(dose_data,sizeof(float),Nind,beamlet_batch_file);
-
-	free(dose_ind);
-	free(dose_data);
-
-	// free the calculation grids
-	free(terma_mask.matrix);
-	free(dose_mask.matrix);
-	free(deff.matrix);
-	free(terma.matrix);
-	free(kermac.matrix);
-	free(dose.matrix);
-
-	free(poly_kernel.angular_boundary);
-	free(poly_kernel.radial_boundary);
-	// free(poly_kernel.total_matrix);
-	for (j=0;j<N_KERNEL_CATEGORIES;j++)
-		free(poly_kernel.matrix[j]);
-
-	return(SUCCESS);
-}
-
+/* Cconvolution.cpp */
+
+#include "defs.h"
+
+//function prototypes
+
+int load_kernels(MONO_KERNELS *, char []);
+int load_geometry(FLOAT_GRID *, char []);
+int pop_beam(BEAM *, FILE *);
+int calc_deff(FLOAT_GRID *,FLOAT_GRID *, FLOAT_GRID *, BEAM *);
+int terma_kerma(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,MONO_KERNELS *,FLOAT_GRID *);
+int make_poly_kernel(MONO_KERNELS *, KERNEL *);
+int calc_dose(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,KERNEL *,BEAM *, FLOAT_GRID *);
+int terma_dose_masks(FLOAT_GRID *, FLOAT_GRID *, BEAM *);
+int convolution(MONO_KERNELS *, BEAM *, FLOAT_GRID *, FILE *);
+
+char errstr[200];  // error string that all routines have access to
+
+int main(int argc, char *argv[])
+//  Expects four input arguments: 
+// 1)  kernel_filenames -- contains a list of the kernel files
+// 2)  geometry_filenames  -- contains a list of the geometry files
+// 3)  beamspec batch file -- locations of beamspec files in batch
+// 4)  beamlet batch file -- locations of resulting beamlets in batch
+{
+	int i,j,b,B;
+
+	char tmpstr[200];
+
+	FLOAT_GRID density;
+
+	MONO_KERNELS mono_kernels;
+
+	BEAM beam;
+
+	FILE *beamspec_batch_file;
+	FILE *beamlet_batch_file;
+
+	/*	// print the arguments
+	printf("Input arguments:\n");
+	for (j=1;j<argc;j++)
+	printf("%s\n",argv[j]); */
+
+	if (argc != 5)
+	{
+		printf("Expecting four input command line arguments, received %d.\n",argc);
+		return(FAILURE);
+	}
+
+	if (load_kernels(&mono_kernels,argv[1]) == FAILURE)
+	{
+		sprintf(tmpstr,"Failed at loading the kernels.\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+        printf("Successfully loaded kernels\n");
+
+	if (load_geometry(&density,argv[2]) == FAILURE)
+	{
+		sprintf(tmpstr,"Failed at loading the geometry.\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+        printf("Successfully loaded geometry files.\n");
+
+	/* 
+	// diagnostic lines
+	printf("SAD = %lf \n",beam.SAD);
+	printf("xp = %lf \n",beam.xp);
+	printf("yp = %lf \n",beam.yp);
+	printf("del_xp = %lf \n",beam.del_xp);
+	printf("del_yp = %lf \n",beam.del_yp);
+	printf("y_vec = (%lf,%lf,%lf) \n",beam.y_vec[0],beam.y_vec[1],beam.y_vec[2]);
+	printf("ip = (%lf,%lf,%lf) \n",beam.ip[0],beam.ip[1],beam.ip[2]);
+	printf("jp = (%lf,%lf,%lf) \n",beam.jp[0],beam.jp[1],beam.jp[2]);
+	printf("kp = (%lf,%lf,%lf) \n",beam.kp[0],beam.kp[1],beam.kp[2]);
+
+	printf("Xcount = %d, Ycount = %d, Zcount = %d \n",density.x_count,density.y_count,density.z_count);
+	printf("start = (%lf,%lf,%lf) \n",density.start.x,density.start.y,density.start.z);
+	printf("inc = (%lf,%lf,%lf) \n",density.inc.x,density.inc.y,density.inc.z); */
+
+
+	// open the beam specification batch file
+	if ((beamspec_batch_file = fopen(argv[3],"r")) == NULL)
+	{
+		printf("Failed to open beamspec batch file %s\n",argv[3]);
+		return(FAILURE);
+	}
+        printf("Successfully loaded beamspec files.\n");
+
+	// open the dose batch file
+	if ((beamlet_batch_file = fopen(argv[4],"wb")) == NULL)
+	{
+		printf("Failed to open beamlet batch file %s\n",argv[4]);
+		return(FAILURE);
+	}
+
+	// get the number of beams from the beamspec batch file
+	if (fgets(tmpstr,100,beamspec_batch_file) == NULL)  // pop off the first line
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	if (fscanf(beamspec_batch_file,"%d\n",&B) != 1)
+	{
+		sprintf(errstr,"Could not read-in number of beams from beamspec file.");
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	// write the number of beamlets in this batch as the first entry
+	fwrite(&B,sizeof(int),1,beamlet_batch_file); 
+
+	// Do convolution calculations for all consistent beamspec and dose
+	// filenames.  If a calculation for a beamlet fails, print an error 
+	// and move on to the next beamspec file.
+	for (b=0;b<B;b++)
+	{
+		// pop off a beam
+		if(pop_beam(&beam,beamspec_batch_file) == FAILURE)
+		{
+			sprintf(tmpstr,"Failed to load beamspec number %d:\n",b);
+			strcat(tmpstr,errstr);
+			strcpy(errstr,tmpstr);
+			printf("%s\n",errstr);
+		}
+		else if (convolution(&mono_kernels,&beam,&density,beamlet_batch_file) == FAILURE)
+		// An error occurred, so print the error string to standard out
+		// but do not terminate the remaining beam batches.
+		{
+			j = 0;
+			fwrite(&beam.num,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.x_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.y_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.z_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&j,sizeof(int),1,beamlet_batch_file);
+			printf("Error in the calculation for beamlet number %d,\n so all zeros were saved for the resulting beamlet file.\n",b);
+			printf("%s\n",errstr);
+		}
+		else
+			printf("Successfully calculated beamlet %d of %s.\n",b,argv[3]); 
+	}
+
+	// close the beamlet file
+	fclose(beamlet_batch_file);
+
+	// free the density grid
+	free(density.matrix);
+
+	// only need to free angular and radial boundaries for the first
+	// kernel, since other kernel boundaries just point to the same place
+	free(mono_kernels.kernel[0].angular_boundary);
+	free(mono_kernels.kernel[0].radial_boundary);
+
+	// free the kernels
+	free(mono_kernels.energy);
+	free(mono_kernels.fluence);
+	free(mono_kernels.mu);
+	free(mono_kernels.mu_en);
+ 	for (i=0;i<mono_kernels.nkernels;i++)
+		for (j=0;j<N_KERNEL_CATEGORIES;j++)
+			free(mono_kernels.kernel[i].matrix[j]); 
+
+	return(SUCCESS);
+}
+
+int convolution(MONO_KERNELS *mono_kernels, BEAM *beam, FLOAT_GRID *density, FILE *beamlet_batch_file)
+// routine that actually performs the convolution for a given kernel, beam, and geometry
+{
+	int i,j,M,N,Q,Nind,Ntotal;  // dimensions of the CT density grid
+	int *dose_ind;
+	float *dose_data, doseMax;
+	char tmpstr[200];  // temporary string
+
+	FLOAT_GRID terma_mask;
+	FLOAT_GRID dose_mask;
+	FLOAT_GRID deff;
+	FLOAT_GRID terma;
+	FLOAT_GRID kermac;
+	FLOAT_GRID dose;
+
+	KERNEL poly_kernel;
+
+	// copy the density grid dimensions to the calculation grids
+	copy_grid_geometry(density,&terma_mask);
+	copy_grid_geometry(density,&dose_mask);
+	copy_grid_geometry(density,&deff);
+	copy_grid_geometry(density,&terma);
+	copy_grid_geometry(density,&kermac);
+	copy_grid_geometry(density,&dose);
+
+	// dimensions of all the grids
+	M = density->x_count;
+	N = density->y_count;
+	Q = density->z_count;
+
+	Ntotal = M*N*Q;
+
+	// Allocate memory for all of the grids and fill them all with zeros
+	if ((terma_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for terma_mask.");
+		return(FAILURE);
+	}
+
+	if ((dose_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for dose_mask.");
+		return(FAILURE);
+	}
+
+	if ((deff.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for deff.");
+		return(FAILURE);
+	}
+
+	if ((terma.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for terma.");
+		return(FAILURE);
+	}
+
+	if ((kermac.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for kermac.");
+		return(FAILURE);
+	}
+
+	if ((dose.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for dose.");
+		return(FAILURE);
+	}
+	
+	for (i=0;i<Ntotal;i++)
+	{
+		terma_mask.matrix[i] = 0.0;
+		dose_mask.matrix[i] = 0.0;
+		deff.matrix[i] = 0.0;
+		terma.matrix[i] = 0.0;
+		kermac.matrix[i] = 0.0;
+		dose.matrix[i] = 0.0;
+	} 
+	
+	/* start calculations */
+
+	// If a failure occurs in any calculation, append the error
+	// onto the error string and then return a FAILURE.
+
+	// create terma and dose masks
+	if (SUCCESS != terma_dose_masks(&terma_mask,&dose_mask,beam))
+	{
+		sprintf(tmpstr,"Failed in terma_dose_masks!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+
+	//create polyenergetic kernel from mono kernels and fluence,mu data
+	if (SUCCESS != make_poly_kernel(mono_kernels,&poly_kernel) )
+	{
+		sprintf(tmpstr,"Failed making polyenergetic kernel!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+	
+	//create effective depth array from density array
+	if (SUCCESS != calc_deff(density,&deff,&terma_mask,beam))
+	{
+		sprintf(tmpstr,"Failed in calc_deff!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+        // printf("Successfully calculated deff for beam %d.\n", beam->num);
+
+	//create kerma and terma arrays
+	//note kerma is collision kerma and is used for a kernel hardening correction
+	if (SUCCESS != terma_kerma(&deff,&terma,&kermac,mono_kernels,&terma_mask))
+	{
+		sprintf(tmpstr,"Failed in terma_kerma calculation!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+        // printf("Successfully calculated terma for beam %d.\n", beam->num);
+
+	//use all this stuff to calculate dose
+	if ( (SUCCESS != calc_dose(density,&terma,&dose,&poly_kernel,beam,&dose_mask)) ) 
+	{
+		sprintf(tmpstr,"Failed calculating dose!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+        // printf("Successfully calculated dose for beam %d.\n", beam->num);
+
+	/* //diagnostic lines:
+	FILE *fid;
+	fid = fopen("dose.bin","wb");
+	fwrite(dose.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("terma.bin","wb");
+	fwrite(terma.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("kermac.bin","wb");
+	fwrite(kermac.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("deff.bin","wb");
+	fwrite(deff.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("terma_mask.bin","wb");
+	fwrite(terma_mask.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("dose_mask.bin","wb");
+	fwrite(dose_mask.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("density.bin","wb");
+	fwrite(density->matrix,sizeof(float),Ntotal,fid);
+	fclose(fid); //*/
+
+    // find maximum dose
+	doseMax = 0.0;
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] > doseMax)
+			doseMax = dose.matrix[i];
+
+	// count the number of non-zero dose values
+	Nind = 0;
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
+			&& dose.matrix[i] > 0.0)
+			Nind++;
+		else
+			dose.matrix[i] = 0.0;  // turn off doses below threshold
+
+	// allocate memory for sparse dose data
+	dose_ind = (int *)malloc(sizeof(int)*Nind);
+	dose_data = (float *)malloc(sizeof(float)*Nind);
+
+	// store the sparse data	
+	j = 0;   // index just for the sparse data
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
+			&& dose.matrix[i] > 0.0)
+		{
+			dose_ind[j] = i;
+			dose_data[j] = dose.matrix[i];
+			j++; 
+		}
+
+	// save dose to a file
+
+	// save the total file size first, then the number of non-zero elements
+	fwrite(&beam->num,sizeof(int),1,beamlet_batch_file);
+	fwrite(&M,sizeof(int),1,beamlet_batch_file);
+	fwrite(&N,sizeof(int),1,beamlet_batch_file);
+	fwrite(&Q,sizeof(int),1,beamlet_batch_file);
+    fwrite(&Nind,sizeof(int),1,beamlet_batch_file);
+	fwrite(dose_ind,sizeof(int),Nind,beamlet_batch_file);
+	fwrite(dose_data,sizeof(float),Nind,beamlet_batch_file);
+
+	free(dose_ind);
+	free(dose_data);
+
+	// free the calculation grids
+	free(terma_mask.matrix);
+	free(dose_mask.matrix);
+	free(deff.matrix);
+	free(terma.matrix);
+	free(kermac.matrix);
+	free(dose.matrix);
+
+	free(poly_kernel.angular_boundary);
+	free(poly_kernel.radial_boundary);
+	// free(poly_kernel.total_matrix);
+	for (j=0;j<N_KERNEL_CATEGORIES;j++)
+		free(poly_kernel.matrix[j]);
+
+	return(SUCCESS);
+}
+

+ 138 - 138
WiscPlan-SourceCode/source-code-photon-linux/defs.h

@@ -1,138 +1,138 @@
-/* defs.h */
-
-// libraries that will be needed throughout
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <malloc.h>
-
-#define MAX_KERNELS 50	//max number of monoenergetic kernels to use for creating polyenergetic kernel
-#define N_KERNEL_RADII 24  //number of radial increments in mono kernels 
-#define N_KERNEL_ANGLES 48 //number of angular increments in mono kernels
-#define N_KERNEL_CATEGORIES 5  //number of kernel categories (primary, first scatter...)
-
-// upsample factors to determine insideness for voxels on aperture edge:
-#define Mus  5
-#define Nus  5
-#define Qus  5
-
-#define SUCCESS 1
-#define FAILURE 0
-
-#define doseCutoffThreshold 0.005 // doses less than this fraction of the maximum are cut off
-
-#define RSAFE 2.0   // safety margin for dose_mask calculation in cm
-
-#define PI 3.14152654
-
-#define Y_DOSE_EXTENT 8.0  //optionally only calculate this many cm in y-direction (commented out in calc_dose)
-
-#define NPHI 12  //number of azimuthal angles for convolution 
-// #define DELR 0.4 //radial increments for convolution (adaptive to the problem now, in calc_dose)
-#define NTHETA 6  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)
-
-/* #define NPHI 12	//number of azimuthal angles for convolution 
-#define DELR 0.1 //radial increments for convolution
-#define NTHETA 12  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)  */
-
-#define MAXX(x,y) ((x) > (y) ? (x) : (y))
-
-//each kernel file contains 7 entries per voxel, the first five are these categores
-typedef enum
-{
- primary_,
- first_scatter_,
- second_scatter_,
- multiple_scatter_,
- brem_annih_
-} KERNEL_CATEGORIES;
-
-typedef struct
-{
-    float x;
-    float y;
-    float z;
-} POINT;
-
-//standard float precision grid structure, with dynamically allocated matrix 
-//used for density, deff, terma, kerma, dose
-typedef struct
-{
-    POINT start;
-    POINT inc;
-    int x_count;
-    int y_count;
-    int z_count;
-    float *matrix;
-} FLOAT_GRID;
-
-//macro to access grid values
-#define GRID_VALUE(GRID_ptr, i, j, k)\
-    ((GRID_ptr)->matrix[(i) +\
-                        (GRID_ptr)->x_count *\
-                         ((j) + ((k) * (GRID_ptr)->y_count))])
-
-// macro for 3D dot products
-#define DOT3D(vec1,vec2) ((vec1[0])*(vec2[0])+(vec1[1])*(vec2[1])+(vec1[2])*(vec2[2]))
-
-//kernel structure for each monoenergetic kernel and the polyenergetic kernel
-typedef struct
-{
- int nradii;
- int ntheta;
- float *radial_boundary;
- float *angular_boundary;
- float *matrix[N_KERNEL_CATEGORIES];  //kernel values for each category
- float *total_matrix;				   //sum of all categories (used for current convolution)
-} KERNEL;
-
-//macros for accessing kernel values
-#define KERNEL_VALUE(kern_ptr,category,i,j) \
-        (kern_ptr)->matrix[category][(i) + (j)*(kern_ptr)->nradii]
-#define KERNEL_TOTAL_VALUE(kern_ptr,i,j) \
-        (kern_ptr)->total_matrix[(i) + (j)*(kern_ptr)->nradii]
-
-//infor and array of KERNEL structures for monoenergetic kernels 
-typedef struct
-{
- int nkernels;
- float *energy;
- float *fluence;
- float *mu;
- float *mu_en;
- KERNEL kernel[MAX_KERNELS];
-} MONO_KERNELS;
-
-//beam description (center and size)
-typedef struct
-{
- float ip[3];  // first aperture center vector
- float jp[3];  // second aperture center vector
- float kp[3];  // source direction vector
- float y_vec[3];   // source location vector
-
- // aperture parameters
- float xp;
- float yp;
- float del_xp;   // aperture width in ip direction
- float del_yp;   // aperture width in jp direction
-
- // source-axis distance (leave here for now because to ubiquitous)
- float SAD;
-
- // beam number to avoid ambiguity
- int num;
-} BEAM;
-
-/* Prototypes of utility functions */
-float *fvector(int nl, int nh);
-float **fmatrix(int nrl, int nrh, int ncl, int nch);
-
-void free_fvector(float *v, int nl, int nh);
-void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch);
-
-int copy_grid_geometry(FLOAT_GRID *, FLOAT_GRID *);
-int binSearch(float *, float, int);
-
-void nrerror(char error_text[]);
+/* defs.h */
+
+// libraries that will be needed throughout
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <malloc.h>
+
+#define MAX_KERNELS 50	//max number of monoenergetic kernels to use for creating polyenergetic kernel
+#define N_KERNEL_RADII 24  //number of radial increments in mono kernels 
+#define N_KERNEL_ANGLES 48 //number of angular increments in mono kernels
+#define N_KERNEL_CATEGORIES 5  //number of kernel categories (primary, first scatter...)
+
+// upsample factors to determine insideness for voxels on aperture edge:
+#define Mus  5
+#define Nus  5
+#define Qus  5
+
+#define SUCCESS 1
+#define FAILURE 0
+
+#define doseCutoffThreshold 0.005 // doses less than this fraction of the maximum are cut off
+
+#define RSAFE 2.0   // safety margin for dose_mask calculation in cm
+
+#define PI 3.14152654
+
+#define Y_DOSE_EXTENT 8.0  //optionally only calculate this many cm in y-direction (commented out in calc_dose)
+
+#define NPHI 12  //number of azimuthal angles for convolution 
+// #define DELR 0.4 //radial increments for convolution (adaptive to the problem now, in calc_dose)
+#define NTHETA 6  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)
+
+/* #define NPHI 12	//number of azimuthal angles for convolution 
+#define DELR 0.1 //radial increments for convolution
+#define NTHETA 12  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)  */
+
+#define MAXX(x,y) ((x) > (y) ? (x) : (y))
+
+//each kernel file contains 7 entries per voxel, the first five are these categores
+typedef enum
+{
+ primary_,
+ first_scatter_,
+ second_scatter_,
+ multiple_scatter_,
+ brem_annih_
+} KERNEL_CATEGORIES;
+
+typedef struct
+{
+    float x;
+    float y;
+    float z;
+} POINT;
+
+//standard float precision grid structure, with dynamically allocated matrix 
+//used for density, deff, terma, kerma, dose
+typedef struct
+{
+    POINT start;
+    POINT inc;
+    int x_count;
+    int y_count;
+    int z_count;
+    float *matrix;
+} FLOAT_GRID;
+
+//macro to access grid values
+#define GRID_VALUE(GRID_ptr, i, j, k)\
+    ((GRID_ptr)->matrix[(i) +\
+                        (GRID_ptr)->x_count *\
+                         ((j) + ((k) * (GRID_ptr)->y_count))])
+
+// macro for 3D dot products
+#define DOT3D(vec1,vec2) ((vec1[0])*(vec2[0])+(vec1[1])*(vec2[1])+(vec1[2])*(vec2[2]))
+
+//kernel structure for each monoenergetic kernel and the polyenergetic kernel
+typedef struct
+{
+ int nradii;
+ int ntheta;
+ float *radial_boundary;
+ float *angular_boundary;
+ float *matrix[N_KERNEL_CATEGORIES];  //kernel values for each category
+ float *total_matrix;				   //sum of all categories (used for current convolution)
+} KERNEL;
+
+//macros for accessing kernel values
+#define KERNEL_VALUE(kern_ptr,category,i,j) \
+        (kern_ptr)->matrix[category][(i) + (j)*(kern_ptr)->nradii]
+#define KERNEL_TOTAL_VALUE(kern_ptr,i,j) \
+        (kern_ptr)->total_matrix[(i) + (j)*(kern_ptr)->nradii]
+
+//infor and array of KERNEL structures for monoenergetic kernels 
+typedef struct
+{
+ int nkernels;
+ float *energy;
+ float *fluence;
+ float *mu;
+ float *mu_en;
+ KERNEL kernel[MAX_KERNELS];
+} MONO_KERNELS;
+
+//beam description (center and size)
+typedef struct
+{
+ float ip[3];  // first aperture center vector
+ float jp[3];  // second aperture center vector
+ float kp[3];  // source direction vector
+ float y_vec[3];   // source location vector
+
+ // aperture parameters
+ float xp;
+ float yp;
+ float del_xp;   // aperture width in ip direction
+ float del_yp;   // aperture width in jp direction
+
+ // source-axis distance (leave here for now because to ubiquitous)
+ float SAD;
+
+ // beam number to avoid ambiguity
+ int num;
+} BEAM;
+
+/* Prototypes of utility functions */
+float *fvector(int nl, int nh);
+float **fmatrix(int nrl, int nrh, int ncl, int nch);
+
+void free_fvector(float *v, int nl, int nh);
+void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch);
+
+int copy_grid_geometry(FLOAT_GRID *, FLOAT_GRID *);
+int binSearch(float *, float, int);
+
+void nrerror(char error_text[]);

+ 122 - 122
WiscPlan-SourceCode/source-code-photon-linux/make_poly.cpp

@@ -1,122 +1,122 @@
-/* make_poly.cpp */
-
-/* Creates a poly-energetic kernel given the energy-binned beam fluence and 
-kernels for all of the beam energies. */
-
-#include "defs.h"
-
-//fillers for these entries in kernel structure
-#define UNCERT 1.0
-#define MEAN_RADIUS 0.0
-#define MEAN_ANGLE 0.0
-
-extern char errstr[200];  // error string that all routines have access to
-
-int make_poly_kernel(MONO_KERNELS *mono, KERNEL *poly)
-{
- 
-// There is a problem with the first block of commented statements, likely a memory leak
-
- KERNEL_CATEGORIES category;
- int i, j, e;
- float sum;
-
- poly->nradii = N_KERNEL_RADII;
- poly->ntheta = N_KERNEL_ANGLES;
- 
- poly->radial_boundary = (float *)malloc(poly->nradii*sizeof(float));
- poly->angular_boundary = (float *)malloc(poly->ntheta*sizeof(float));
-
- //copy radial boundaries from first mono kernel
- for (i=0;i<poly->nradii;i++)
-  poly->radial_boundary[i] = mono->kernel[0].radial_boundary[i];
-
- //copy angular boundaries from first mono kernel
- for (i=0;i<poly->ntheta;i++)
-  poly->angular_boundary[i] = mono->kernel[0].angular_boundary[i];
-
- for (i=0;i<N_KERNEL_CATEGORIES;i++)
-  if ( (poly->matrix[i] =
-   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
-	return(FAILURE);
-   }
- if ( (poly->total_matrix =
-   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for total matrix\n");
-	return(FAILURE);
-   } 
-
- for (j=0;j<poly->ntheta;j++)
-  for (i=0;i<poly->nradii;i++)
-  {
-   KERNEL_TOTAL_VALUE(poly,i,j) = 0.0;
-
-   //weight of each mono kernel value in sum is fluence*energy*mu
-   category = primary_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = first_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = second_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = multiple_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = brem_annih_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-  }
-
- return(SUCCESS);
-
-}
+/* make_poly.cpp */
+
+/* Creates a poly-energetic kernel given the energy-binned beam fluence and 
+kernels for all of the beam energies. */
+
+#include "defs.h"
+
+//fillers for these entries in kernel structure
+#define UNCERT 1.0
+#define MEAN_RADIUS 0.0
+#define MEAN_ANGLE 0.0
+
+extern char errstr[200];  // error string that all routines have access to
+
+int make_poly_kernel(MONO_KERNELS *mono, KERNEL *poly)
+{
+ 
+// There is a problem with the first block of commented statements, likely a memory leak
+
+ KERNEL_CATEGORIES category;
+ int i, j, e;
+ float sum;
+
+ poly->nradii = N_KERNEL_RADII;
+ poly->ntheta = N_KERNEL_ANGLES;
+ 
+ poly->radial_boundary = (float *)malloc(poly->nradii*sizeof(float));
+ poly->angular_boundary = (float *)malloc(poly->ntheta*sizeof(float));
+
+ //copy radial boundaries from first mono kernel
+ for (i=0;i<poly->nradii;i++)
+  poly->radial_boundary[i] = mono->kernel[0].radial_boundary[i];
+
+ //copy angular boundaries from first mono kernel
+ for (i=0;i<poly->ntheta;i++)
+  poly->angular_boundary[i] = mono->kernel[0].angular_boundary[i];
+
+ for (i=0;i<N_KERNEL_CATEGORIES;i++)
+  if ( (poly->matrix[i] =
+   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
+	return(FAILURE);
+   }
+ if ( (poly->total_matrix =
+   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for total matrix\n");
+	return(FAILURE);
+   } 
+
+ for (j=0;j<poly->ntheta;j++)
+  for (i=0;i<poly->nradii;i++)
+  {
+   KERNEL_TOTAL_VALUE(poly,i,j) = 0.0;
+
+   //weight of each mono kernel value in sum is fluence*energy*mu
+   category = primary_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = first_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = second_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = multiple_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = brem_annih_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+  }
+
+ return(SUCCESS);
+
+}

+ 12 - 12
WiscPlan-SourceCode/source-code-photon-linux/makefile

@@ -1,12 +1,12 @@
-CC = g++
-CFLAGS = -O2
-OBJECTS = convolutionCondor.o calc_deff.o parse_funcCondor.o make_poly.o raytrace.o terma_dose_masks.o terma_kerma.o calc_dose.o util.o
-
-Cconvolution : $(OBJECTS)
-	condor_compile $(CC) $(CFLAGS) $(OBJECTS) -o convolutionCondor
-
-%.o : %.cpp
-	$(CC) $(CFLAGS) -c $<
-
-clean : 
-	rm -f $(OBJECTS) convolutionCondor
+CC = g++
+CFLAGS = -O2
+OBJECTS = convolutionCondor.o calc_deff.o parse_funcCondor.o make_poly.o raytrace.o terma_dose_masks.o terma_kerma.o calc_dose.o util.o
+
+Cconvolution : $(OBJECTS)
+	condor_compile $(CC) $(CFLAGS) $(OBJECTS) -o convolutionCondor
+
+%.o : %.cpp
+	$(CC) $(CFLAGS) -c $<
+
+clean : 
+	rm -f $(OBJECTS) convolutionCondor

+ 825 - 825
WiscPlan-SourceCode/source-code-photon-linux/parse_funcCondor.cpp

@@ -1,825 +1,825 @@
-/* parse_func.cpp */
-
-/* Checks the validity of the arguments input to the convolution routine and 
-transfers the Matlab-style arguments to the C structures defined in defs.h. */
-
-/* This parse function operates on file inputs rather than on Matlab inputs. */
-
-#include "defs.h"
-
-// Markers that are searched for inside the kernel_filenames file, which is 
-// passed to the load_kernels routine. The line after each of these markers
-// in the kernel_filenames file is a filename corresponding to the marker.
-#define kernel_header_line "kernel_header"
-#define kernel_radii_line "kernel_radii"
-#define kernel_angles_line "kernel_angles"
-#define kernel_energies_line "kernel_energies"
-#define kernel_primary_line "kernel_primary"
-#define kernel_first_scatter_line "kernel_first_scatter"
-#define kernel_second_scatter_line "kernel_second_scatter"
-#define kernel_multiple_scatter_line "kernel_multiple_scatter"
-#define kernel_brem_annih_line "kernel_brem_annih"
-#define kernel_total_line "kernel_total"
-#define kernel_fluence_line "kernel_fluence"
-#define kernel_mu_line "kernel_mu"
-#define kernel_mu_en_line "kernel_mu_en"
-
-// Markers that are searched for inside the geometry_filenames, which is 
-// passed to the load_geometry routine. These have the same meaning as
-// the kernel_filenames markers.
-#define geometry_header "./geometry_files/geometry_header.txt"
-#define geometry_density "./geometry_files/density.bin"
-#define beam_data "./geometry_files/beam_data.txt"
-
-#define geometry_header_line "geometry_header"
-#define geometry_density_line "geometry_density"
-#define beam_data_line "beam_data"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int load_kernels(MONO_KERNELS *mono_kernels, char kernel_filenames[])
-/* Ensures that the kernel files have the following format:
-
-               radii: [1xNradii float]
-              angles: [1xNangles float]
-            energies: [1xNenergies float]
-             primary: [Nradii x Nangles x Nenergies float]
-       first_scatter: [Nradii x Nangles x Nenergies float]
-      second_scatter: [Nradii x Nangles x Nenergies float]
-    multiple_scatter: [Nradii x Nangles x Nenergies float]
-          brem_annih: [Nradii x Nangles x Nenergies float]
-               total: [Nradii x Nangles x Nenergies float]
-          mean_radii: [Nradii x Nangles x Nenergies float] (not used)
-         mean_angles: [Nradii x Nangles x Nenergies float] (not used)
-           helpfield: [any x any char] 
-             fluence: [1xNenergies float]
-                  mu: [1xNenergies float]
-               mu_en: [1xNenergies float]
-
-mistakes or inconsistencies will result in errors.
-
-  Results are then stored in mono_kernels.
-
-The names of the files containing all of these parameters are given
-by the kernel_filenames file.
-
-*/
-{
-	int j,k;
-	int Nenergies, Nangles, Nradii;
-	char str[200];
-	// some strings to hold filenames
-	char header_filename[200], radii_filename[200], angles_filename[200];
-	char energies_filename[200], primary_filename[200], first_scatter_filename[200];
-	char second_scatter_filename[200], multiple_scatter_filename[200];
-	char brem_annih_filename[200], total_filename[200], fluence_filename[200];
-	char mu_filename[200], mu_en_filename[200];
-
-	// flags for file readin
-	int header_flag = 0;
-	int radii_flag = 0;
-	int angles_flag = 0;
-	int energies_flag = 0;
-	int primary_flag = 0;
-	int first_flag = 0;
-	int second_flag = 0;
-	int multiple_flag = 0;
-	int brem_annih_flag = 0;
-	int total_flag = 0;
-	int fluence_flag = 0;
-	int mu_flag = 0;
-	int mu_en_flag = 0;
-
-	FILE *fid;  // generic filename
-	FILE *primary, *first, *second, *multiple, *brem_annih, *total;  // kernel files
-
-	// read in the data filenames
-	if ( (fid = fopen(kernel_filenames,"r")) == NULL)  // open the kernel filenames
-	{
-		sprintf(errstr,"Could not open the kernel filenames file");
-		return(FAILURE);
-	}
-
-	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
-	{
-	  if (!strcmp(str,kernel_header_line))
-	    if (fscanf(fid,"%s\n",header_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_header filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      header_flag = 1;
-	  else if (!strcmp(str,kernel_radii_line))
-	    if (fscanf(fid,"%s\n",radii_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_radii filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      radii_flag = 1;
-	  else if (!strcmp(str,kernel_angles_line))
-	    if (fscanf(fid,"%s\n",angles_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_angles filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-            else
-	      angles_flag = 1;
-	  else if (!strcmp(str,kernel_energies_line))
-        if (fscanf(fid,"%s\n",energies_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_energies filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      energies_flag = 1;
-          else if (!strcmp(str,kernel_fluence_line))
-	    if (fscanf(fid,"%s\n",fluence_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_fluence filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      fluence_flag = 1;
-	  else if (!strcmp(str,kernel_primary_line))
-        if (fscanf(fid,"%s\n",primary_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_primary filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      primary_flag = 1;
-	  else if (!strcmp(str,kernel_first_scatter_line))
-        if (fscanf(fid,"%s\n",first_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_first_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      first_flag = 1;
-	  else if (!strcmp(str,kernel_second_scatter_line))
-	    if (fscanf(fid,"%s\n",second_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_second_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      second_flag = 1;
-	  else if (!strcmp(str,kernel_multiple_scatter_line))
-        if (fscanf(fid,"%s\n",multiple_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_multiple_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      multiple_flag = 1;
-	  else if (!strcmp(str,kernel_brem_annih_line))
-	    if (fscanf(fid,"%s\n",brem_annih_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_brem_annih filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else 
-	      brem_annih_flag = 1;
-	  else if (!strcmp(str,kernel_total_line))
-	    if (fscanf(fid,"%s\n",total_filename) != 1)
-	    {
-			sprintf(errstr,"Failed to read-in the kernel_total filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      total_flag = 1;
-	  else if (!strcmp(str,kernel_mu_line))
-	    if (fscanf(fid,"%s\n",mu_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_mu filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      mu_flag = 1;
-	  else if (!strcmp(str,kernel_mu_en_line))
-	    if (fscanf(fid,"%s\n",mu_en_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_mu_en filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      mu_en_flag = 1;
-	  else
-	  {   
-		    sprintf(errstr,"Unrecognized string in the kernel filenames file: %s\n",str);
-			return(FAILURE);   
-	  }
-	}
-
-	// confirm that all of the required filenames have been found
-	if (header_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel header filename.");
-	  return(FAILURE);
-	}
-	else if (radii_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel radii filename.");
-	  return(FAILURE);
-	}
-	else if (angles_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel angles filename.");
-	  return(FAILURE);
-	}
-	else if (energies_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel energies filename.");
-	  return(FAILURE);
-	}
-	else if (primary_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a primary kernel filename.");
-	  return(FAILURE);
-	}
-	else if (first_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a first scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (second_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a second scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (multiple_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a multiple scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (brem_annih_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a brem_annih kernel filename.");
-	  return(FAILURE);
-	}
-	else if (total_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a total kernel filename.");
-	  return(FAILURE);
-	}
-	else if (fluence_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel fluence filename.");
-	  return(FAILURE);
-	}
-	else if (mu_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel mu filename.");
-	  return(FAILURE);
-	}
-	else if (mu_en_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel mu_en filename.");
-	  return(FAILURE);
-	}
-
-	// read in the expected matrix sizes
-	if ( (fid=fopen(header_filename,"r")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel header file in kernel data folder.");
-		return(FAILURE);
-	}
-	else
-	{   
-		fgets(str,100,fid); // pop-off the first line of the header
-		if (fscanf(fid,"%d %d %d\n",&Nradii,&Nangles,&Nenergies) != 3)
-		{
-			sprintf(errstr,"Incorrect amount of data in kernel header file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	mono_kernels->nkernels = Nenergies;
-
-	// read in the energies, fluences, mu, and mu_en values
-	if ( (fid = fopen(energies_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel energies file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->energy = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel energies.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->energy,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of energies in kernel_energies file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	if ( (fid = fopen(fluence_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel fluences file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->fluence = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel fluences.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->fluence,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of fluences in kernel_fluences file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-	
-	if ( (fid = fopen(mu_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel mu file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->mu = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel mu.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->mu,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of mu values in kernel_mu file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	if ( (fid = fopen(mu_en_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel mu_en file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->mu_en = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel mu_en.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->mu_en,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of mu_en values in kernel_mu_en file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	// Only assign memory for bin boundaries for the first kernel. Just point the other
-	// boundary pointers at the values in the first kernel.
-
-	if ( (fid = fopen(radii_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel radii file.");
-		return(FAILURE);
-	}
-	else
-	{
-		mono_kernels->kernel[0].nradii = Nradii;
-		if( (mono_kernels->kernel[0].radial_boundary = (float *)malloc(sizeof(float)*Nradii)) == NULL)
-		{
-			sprintf(errstr,"Failed to allocate memory for radial boundaries.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->kernel[0].radial_boundary,sizeof(float),Nradii,fid) != Nradii)
-		{
-			sprintf(errstr,"Incorrect number of radii values in kernel_radii file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-	
-	if ( (fid = fopen(angles_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel angles file.");
-		return(FAILURE);
-	}
-	else
-	{
-		mono_kernels->kernel[0].ntheta = Nangles;
-		if( (mono_kernels->kernel[0].angular_boundary = (float *)malloc(sizeof(float)*Nangles)) == NULL)
-		{
-			sprintf(errstr,"Failed to allocate memory for angular boundaries.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->kernel[0].angular_boundary,sizeof(float),Nangles,fid) != Nangles)
-		{
-			sprintf(errstr,"Incorrect number of angular values in kernel_angles file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	// allocate space for kernel matrices and copy bin boundaries for other kernel categories
-	for (j=0;j<Nenergies;j++)  // loop through energies
-	{
-		if (j != 0)
-		{
-			mono_kernels->kernel[j].nradii = Nradii;
-			mono_kernels->kernel[j].ntheta = Nangles;
-	
-			mono_kernels->kernel[j].radial_boundary = mono_kernels->kernel[0].radial_boundary;
-			mono_kernels->kernel[j].angular_boundary = mono_kernels->kernel[0].angular_boundary;
-		}
-
-		// allocate space for kernels
-		for (k=0;k<N_KERNEL_CATEGORIES;k++)
-			if ((mono_kernels->kernel[j].matrix[k] 
-				= (float *)malloc(sizeof(float)*Nradii*Nangles*N_KERNEL_CATEGORIES)) == NULL)
-			{
-				sprintf(errstr,"Failed to allocate memory for kernel matrix.");
-				return(FAILURE);
-			}
-	}
-	
-	// load-in the kernels one at a time and fill-up the monoenergetic kernels
-	
-	// open the kernel files
-	if ( (primary = fopen(primary_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing primary kernel.");
-		return(FAILURE);
-	}
-
-	if ( (first = fopen(first_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing first scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (second = fopen(second_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing second scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (multiple = fopen(multiple_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing multiple scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (brem_annih = fopen(brem_annih_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing brem_annih kernel.");
-		return(FAILURE);
-	}
-
-	if ( (total = fopen(total_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing total kernel.");
-		return(FAILURE);
-	}
-
-	// loop through all energies, reading the kernel files in to the kernel structures
-	for (j=0;j<Nenergies;j++)
-	{
-		if ( (int)fread(mono_kernels->kernel[j].matrix[0],sizeof(float),Nradii*Nangles,primary) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[1],sizeof(float),Nradii*Nangles,first) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[2],sizeof(float),Nradii*Nangles,second) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[3],sizeof(float),Nradii*Nangles,multiple) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[4],sizeof(float),Nradii*Nangles,brem_annih) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-	}
-
-	// close the kernel files
-	fclose(primary);
-	fclose(first);
-	fclose(second);
-	fclose(multiple);
-	fclose(brem_annih);
-
-	return(SUCCESS);
-}
-
-int load_geometry(FLOAT_GRID *density, char geometry_filenames[])
-/* Ensure that the GEOMETRY structure has the following format:
-  Geometry = 
-
-         start: [3 element float]
-    voxel_size: [3 element float]
-          data: [M x N x Q float]
-          beam: [1x1 struct] 
-		  
- Geometry.beam = 
-
-    ip: [3 element float]
-    jp: [3 element float]
-    kp: [3 element float]
-     y_vec: [3 element float]
-        xp: [float scalar]
-        yp: [float scalar]
-    del_xp: [float scalar]
-    del_yp: [float scalar]
-	   SAD: [float scalar]
-	
-
-	and load the data into memory.  
-
-The names of the files containing the above data are listed in two files:
-geometry_filenames and beam_filenames.  The beam data are stored in a 
-separate file since many dose calculations are done by changing the 
-beam data and leaving the geometry data constant.  This way one can use
-a separate beam file for each beam but the same geometry file.
-*/
-{
-	int Ntotal;
-	char str[200];   // dummy string
-	char header_filename[200], density_filename[200];
-	// flags for filename readin
-	int header_flag = 0;
-	int density_flag = 0;
-	FILE *fid;          // dummy filename
-
-	// read in the geometry filenames
-	if ( (fid = fopen(geometry_filenames,"r")) == NULL)  // open the geometry filenames
-	{
-	  sprintf(errstr,"Could not open the geometry filenames file\n");
-	  return(FAILURE);
-	}
-
-	// read in the non-beam geometric data
-	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
-	{
-	  if (!strcmp(str,geometry_header_line))
-	    if (fscanf(fid,"%s\n",header_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the geometry_header filename from the geometry filenames file.");
-		}
-	    else
-	      header_flag = 1;
-	  else if (!strcmp(str,geometry_density_line))
-	    if (fscanf(fid,"%s\n",density_filename) != 1)
-		{
-	        sprintf(errstr,"Failed to read-in the geometry_density filename from the geometry filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      density_flag = 1;
-	  else
-	  {   
-			sprintf("Unrecognized string in the geometry filenames file: %s\n",str);
-			return(FAILURE);   
-	  }
-	}
-	
-    // confirm that all of the required filenames have been found
-	if (header_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a geometry header filename.\n");
-	  return(FAILURE);
-	}
-	else if (density_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a geometry density filename.\n");
-	  return(FAILURE);
-	}
-
-	// read in geometric and beam data
-	if( (fid = fopen(header_filename,"r")) == NULL)
-	{
-		sprintf(errstr,"Could not open geometry header file.");
-		return(FAILURE);
-	}
-	else
-	{
-		// pop-off the first line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%d %d %d\n",&density->x_count,&density->y_count,&density->z_count) != 3)
-		{
-			sprintf(errstr,"Could not read-in data grid size.");
-			return(FAILURE);
-		}
-		
-		// pop-off the next line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header  file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%f %f %f\n",&density->start.x,&density->start.y,&density->start.z) != 3)
-		{
-			sprintf(errstr,"Could not read-in density grid start position.");
-			return(FAILURE);
-		}
-
-		// pop-off the next line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%f %f %f\n",&density->inc.x,&density->inc.y,&density->inc.z) != 3)
-		{
-			sprintf(errstr,"Could not read-in voxel size vector.");
-			return(FAILURE);
-		}
-
-		Ntotal = density->x_count*density->y_count*density->z_count;
-	}
-
-	// read-in the CT density data
-	if( (fid = fopen(density_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Could not open CT density file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if( (density->matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-		{
-			sprintf(errstr,"Unable to allocate space for CT density grid.");
-			return(FAILURE);
-		}
-		else if ((int)fread(density->matrix,sizeof(float),Ntotal,fid) != Ntotal)
-		{
-			sprintf(errstr,"Unable to read-in CT density data.");
-			return(FAILURE);
-		}
-	}
-	return(SUCCESS);
-}
-
-int pop_beam(BEAM *bm, FILE *beamspec_batch_file)
-/*  Pops a beam off of the beamspec_batch_file file and loads it into a BEAM structure.
-
-  Ensure that the beam data file has the following format:
- Geometry.beam = 
-
-        ip: [3 element float]
-        jp: [3 element float]
-        kp: [3 element float]
-     y_vec: [3 element float]
-        xp: [float scalar]
-        yp: [float scalar]
-    del_xp: [float scalar]
-    del_yp: [float scalar]
-	   SAD: [float scalar]
-	   num: [int scalar]
-	
-	and load the data into memory.  
-*/
-{
-	char str[200];      // dummy string
-
-	// read-in the beam data
-	// pop-off the first line of the beam data file
-
-	// read-in the CT data grid size
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		return(FAILURE);
-	}
-
-	if (fscanf(beamspec_batch_file,"%d\n",&bm->num) != 1)
-	{
-		sprintf(errstr,"Could not read-in beam data.");
-		return(FAILURE);
-	}
-
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the CT data grid size
-	if (fscanf(beamspec_batch_file,"%f %f %f %f %f\n",&bm->SAD,&bm->xp,&bm->yp,&bm->del_xp,&bm->del_yp) != 5)
-	{
-		sprintf(errstr,"Could not read-in beam data.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the source position vector
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->y_vec[0],&bm->y_vec[1],&bm->y_vec[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in source location vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the beam's eye view vectors, ip first
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->ip[0],&bm->ip[1],&bm->ip[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in ip vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the second beam's eye view vector, jp
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->jp[0],&bm->jp[1],&bm->jp[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in jp vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the third beam's eye view vector, kp
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->kp[0],&bm->kp[1],&bm->kp[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in kp vector.");
-		return(FAILURE);
-	}
-	
-	// ensure that ip,jp,kp are orthonormal and form a right-handed coordinate system
-	if (   (fabs(bm->ip[0]*bm->ip[0] + bm->ip[1]*bm->ip[1] + bm->ip[2]*bm->ip[2] - 1.0) > 1e-6)
-		|| (fabs(bm->jp[0]*bm->jp[0] + bm->jp[1]*bm->jp[1] + bm->jp[2]*bm->jp[2] - 1.0) > 1e-6)
-		|| (fabs(bm->kp[0]*bm->kp[0] + bm->kp[1]*bm->kp[1] + bm->kp[2]*bm->kp[2] - 1.0) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->jp[0] + bm->ip[1]*bm->jp[1] + bm->ip[2]*bm->jp[2]) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->kp[0] + bm->ip[1]*bm->kp[1] + bm->ip[2]*bm->kp[2]) > 1e-6)
-		|| (fabs(bm->jp[0]*bm->kp[0] + bm->jp[1]*bm->kp[1] + bm->jp[2]*bm->kp[2]) > 1e-6))
-	{
-		sprintf(errstr,"Beam's eye view unit vectors ip, jp, and kp must be orthonormal.");
-		return(FAILURE);
-	}
-
-	// check that cross(ip,jp) = kp
-	if (   (fabs(bm->ip[1]*bm->jp[2] - bm->ip[2]*bm->jp[1] - bm->kp[0]) > 1e-6)
-		|| (fabs(bm->ip[2]*bm->jp[0] - bm->ip[0]*bm->jp[2] - bm->kp[1]) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->jp[1] - bm->ip[1]*bm->jp[0] - bm->kp[2]) > 1e-6))
-	{
-		sprintf(errstr,"Must have cross(ip,jp) = kp for beam's eye view");
-		return(FAILURE);
-	}
-
-	return(SUCCESS);
-}
+/* parse_func.cpp */
+
+/* Checks the validity of the arguments input to the convolution routine and 
+transfers the Matlab-style arguments to the C structures defined in defs.h. */
+
+/* This parse function operates on file inputs rather than on Matlab inputs. */
+
+#include "defs.h"
+
+// Markers that are searched for inside the kernel_filenames file, which is 
+// passed to the load_kernels routine. The line after each of these markers
+// in the kernel_filenames file is a filename corresponding to the marker.
+#define kernel_header_line "kernel_header"
+#define kernel_radii_line "kernel_radii"
+#define kernel_angles_line "kernel_angles"
+#define kernel_energies_line "kernel_energies"
+#define kernel_primary_line "kernel_primary"
+#define kernel_first_scatter_line "kernel_first_scatter"
+#define kernel_second_scatter_line "kernel_second_scatter"
+#define kernel_multiple_scatter_line "kernel_multiple_scatter"
+#define kernel_brem_annih_line "kernel_brem_annih"
+#define kernel_total_line "kernel_total"
+#define kernel_fluence_line "kernel_fluence"
+#define kernel_mu_line "kernel_mu"
+#define kernel_mu_en_line "kernel_mu_en"
+
+// Markers that are searched for inside the geometry_filenames, which is 
+// passed to the load_geometry routine. These have the same meaning as
+// the kernel_filenames markers.
+#define geometry_header "./geometry_files/geometry_header.txt"
+#define geometry_density "./geometry_files/density.bin"
+#define beam_data "./geometry_files/beam_data.txt"
+
+#define geometry_header_line "geometry_header"
+#define geometry_density_line "geometry_density"
+#define beam_data_line "beam_data"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int load_kernels(MONO_KERNELS *mono_kernels, char kernel_filenames[])
+/* Ensures that the kernel files have the following format:
+
+               radii: [1xNradii float]
+              angles: [1xNangles float]
+            energies: [1xNenergies float]
+             primary: [Nradii x Nangles x Nenergies float]
+       first_scatter: [Nradii x Nangles x Nenergies float]
+      second_scatter: [Nradii x Nangles x Nenergies float]
+    multiple_scatter: [Nradii x Nangles x Nenergies float]
+          brem_annih: [Nradii x Nangles x Nenergies float]
+               total: [Nradii x Nangles x Nenergies float]
+          mean_radii: [Nradii x Nangles x Nenergies float] (not used)
+         mean_angles: [Nradii x Nangles x Nenergies float] (not used)
+           helpfield: [any x any char] 
+             fluence: [1xNenergies float]
+                  mu: [1xNenergies float]
+               mu_en: [1xNenergies float]
+
+mistakes or inconsistencies will result in errors.
+
+  Results are then stored in mono_kernels.
+
+The names of the files containing all of these parameters are given
+by the kernel_filenames file.
+
+*/
+{
+	int j,k;
+	int Nenergies, Nangles, Nradii;
+	char str[200];
+	// some strings to hold filenames
+	char header_filename[200], radii_filename[200], angles_filename[200];
+	char energies_filename[200], primary_filename[200], first_scatter_filename[200];
+	char second_scatter_filename[200], multiple_scatter_filename[200];
+	char brem_annih_filename[200], total_filename[200], fluence_filename[200];
+	char mu_filename[200], mu_en_filename[200];
+
+	// flags for file readin
+	int header_flag = 0;
+	int radii_flag = 0;
+	int angles_flag = 0;
+	int energies_flag = 0;
+	int primary_flag = 0;
+	int first_flag = 0;
+	int second_flag = 0;
+	int multiple_flag = 0;
+	int brem_annih_flag = 0;
+	int total_flag = 0;
+	int fluence_flag = 0;
+	int mu_flag = 0;
+	int mu_en_flag = 0;
+
+	FILE *fid;  // generic filename
+	FILE *primary, *first, *second, *multiple, *brem_annih, *total;  // kernel files
+
+	// read in the data filenames
+	if ( (fid = fopen(kernel_filenames,"r")) == NULL)  // open the kernel filenames
+	{
+		sprintf(errstr,"Could not open the kernel filenames file");
+		return(FAILURE);
+	}
+
+	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
+	{
+	  if (!strcmp(str,kernel_header_line))
+	    if (fscanf(fid,"%s\n",header_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_header filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      header_flag = 1;
+	  else if (!strcmp(str,kernel_radii_line))
+	    if (fscanf(fid,"%s\n",radii_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_radii filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      radii_flag = 1;
+	  else if (!strcmp(str,kernel_angles_line))
+	    if (fscanf(fid,"%s\n",angles_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_angles filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+            else
+	      angles_flag = 1;
+	  else if (!strcmp(str,kernel_energies_line))
+        if (fscanf(fid,"%s\n",energies_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_energies filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      energies_flag = 1;
+          else if (!strcmp(str,kernel_fluence_line))
+	    if (fscanf(fid,"%s\n",fluence_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_fluence filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      fluence_flag = 1;
+	  else if (!strcmp(str,kernel_primary_line))
+        if (fscanf(fid,"%s\n",primary_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_primary filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      primary_flag = 1;
+	  else if (!strcmp(str,kernel_first_scatter_line))
+        if (fscanf(fid,"%s\n",first_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_first_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      first_flag = 1;
+	  else if (!strcmp(str,kernel_second_scatter_line))
+	    if (fscanf(fid,"%s\n",second_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_second_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      second_flag = 1;
+	  else if (!strcmp(str,kernel_multiple_scatter_line))
+        if (fscanf(fid,"%s\n",multiple_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_multiple_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      multiple_flag = 1;
+	  else if (!strcmp(str,kernel_brem_annih_line))
+	    if (fscanf(fid,"%s\n",brem_annih_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_brem_annih filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else 
+	      brem_annih_flag = 1;
+	  else if (!strcmp(str,kernel_total_line))
+	    if (fscanf(fid,"%s\n",total_filename) != 1)
+	    {
+			sprintf(errstr,"Failed to read-in the kernel_total filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      total_flag = 1;
+	  else if (!strcmp(str,kernel_mu_line))
+	    if (fscanf(fid,"%s\n",mu_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_mu filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      mu_flag = 1;
+	  else if (!strcmp(str,kernel_mu_en_line))
+	    if (fscanf(fid,"%s\n",mu_en_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_mu_en filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      mu_en_flag = 1;
+	  else
+	  {   
+		    sprintf(errstr,"Unrecognized string in the kernel filenames file: %s\n",str);
+			return(FAILURE);   
+	  }
+	}
+
+	// confirm that all of the required filenames have been found
+	if (header_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel header filename.");
+	  return(FAILURE);
+	}
+	else if (radii_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel radii filename.");
+	  return(FAILURE);
+	}
+	else if (angles_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel angles filename.");
+	  return(FAILURE);
+	}
+	else if (energies_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel energies filename.");
+	  return(FAILURE);
+	}
+	else if (primary_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a primary kernel filename.");
+	  return(FAILURE);
+	}
+	else if (first_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a first scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (second_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a second scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (multiple_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a multiple scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (brem_annih_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a brem_annih kernel filename.");
+	  return(FAILURE);
+	}
+	else if (total_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a total kernel filename.");
+	  return(FAILURE);
+	}
+	else if (fluence_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel fluence filename.");
+	  return(FAILURE);
+	}
+	else if (mu_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel mu filename.");
+	  return(FAILURE);
+	}
+	else if (mu_en_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel mu_en filename.");
+	  return(FAILURE);
+	}
+
+	// read in the expected matrix sizes
+	if ( (fid=fopen(header_filename,"r")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel header file in kernel data folder.");
+		return(FAILURE);
+	}
+	else
+	{   
+		fgets(str,100,fid); // pop-off the first line of the header
+		if (fscanf(fid,"%d %d %d\n",&Nradii,&Nangles,&Nenergies) != 3)
+		{
+			sprintf(errstr,"Incorrect amount of data in kernel header file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	mono_kernels->nkernels = Nenergies;
+
+	// read in the energies, fluences, mu, and mu_en values
+	if ( (fid = fopen(energies_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel energies file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->energy = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel energies.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->energy,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of energies in kernel_energies file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	if ( (fid = fopen(fluence_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel fluences file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->fluence = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel fluences.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->fluence,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of fluences in kernel_fluences file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+	
+	if ( (fid = fopen(mu_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel mu file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->mu = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel mu.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->mu,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of mu values in kernel_mu file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	if ( (fid = fopen(mu_en_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel mu_en file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->mu_en = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel mu_en.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->mu_en,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of mu_en values in kernel_mu_en file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	// Only assign memory for bin boundaries for the first kernel. Just point the other
+	// boundary pointers at the values in the first kernel.
+
+	if ( (fid = fopen(radii_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel radii file.");
+		return(FAILURE);
+	}
+	else
+	{
+		mono_kernels->kernel[0].nradii = Nradii;
+		if( (mono_kernels->kernel[0].radial_boundary = (float *)malloc(sizeof(float)*Nradii)) == NULL)
+		{
+			sprintf(errstr,"Failed to allocate memory for radial boundaries.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->kernel[0].radial_boundary,sizeof(float),Nradii,fid) != Nradii)
+		{
+			sprintf(errstr,"Incorrect number of radii values in kernel_radii file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+	
+	if ( (fid = fopen(angles_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel angles file.");
+		return(FAILURE);
+	}
+	else
+	{
+		mono_kernels->kernel[0].ntheta = Nangles;
+		if( (mono_kernels->kernel[0].angular_boundary = (float *)malloc(sizeof(float)*Nangles)) == NULL)
+		{
+			sprintf(errstr,"Failed to allocate memory for angular boundaries.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->kernel[0].angular_boundary,sizeof(float),Nangles,fid) != Nangles)
+		{
+			sprintf(errstr,"Incorrect number of angular values in kernel_angles file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	// allocate space for kernel matrices and copy bin boundaries for other kernel categories
+	for (j=0;j<Nenergies;j++)  // loop through energies
+	{
+		if (j != 0)
+		{
+			mono_kernels->kernel[j].nradii = Nradii;
+			mono_kernels->kernel[j].ntheta = Nangles;
+	
+			mono_kernels->kernel[j].radial_boundary = mono_kernels->kernel[0].radial_boundary;
+			mono_kernels->kernel[j].angular_boundary = mono_kernels->kernel[0].angular_boundary;
+		}
+
+		// allocate space for kernels
+		for (k=0;k<N_KERNEL_CATEGORIES;k++)
+			if ((mono_kernels->kernel[j].matrix[k] 
+				= (float *)malloc(sizeof(float)*Nradii*Nangles*N_KERNEL_CATEGORIES)) == NULL)
+			{
+				sprintf(errstr,"Failed to allocate memory for kernel matrix.");
+				return(FAILURE);
+			}
+	}
+	
+	// load-in the kernels one at a time and fill-up the monoenergetic kernels
+	
+	// open the kernel files
+	if ( (primary = fopen(primary_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing primary kernel.");
+		return(FAILURE);
+	}
+
+	if ( (first = fopen(first_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing first scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (second = fopen(second_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing second scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (multiple = fopen(multiple_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing multiple scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (brem_annih = fopen(brem_annih_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing brem_annih kernel.");
+		return(FAILURE);
+	}
+
+	if ( (total = fopen(total_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing total kernel.");
+		return(FAILURE);
+	}
+
+	// loop through all energies, reading the kernel files in to the kernel structures
+	for (j=0;j<Nenergies;j++)
+	{
+		if ( (int)fread(mono_kernels->kernel[j].matrix[0],sizeof(float),Nradii*Nangles,primary) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[1],sizeof(float),Nradii*Nangles,first) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[2],sizeof(float),Nradii*Nangles,second) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[3],sizeof(float),Nradii*Nangles,multiple) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[4],sizeof(float),Nradii*Nangles,brem_annih) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+	}
+
+	// close the kernel files
+	fclose(primary);
+	fclose(first);
+	fclose(second);
+	fclose(multiple);
+	fclose(brem_annih);
+
+	return(SUCCESS);
+}
+
+int load_geometry(FLOAT_GRID *density, char geometry_filenames[])
+/* Ensure that the GEOMETRY structure has the following format:
+  Geometry = 
+
+         start: [3 element float]
+    voxel_size: [3 element float]
+          data: [M x N x Q float]
+          beam: [1x1 struct] 
+		  
+ Geometry.beam = 
+
+    ip: [3 element float]
+    jp: [3 element float]
+    kp: [3 element float]
+     y_vec: [3 element float]
+        xp: [float scalar]
+        yp: [float scalar]
+    del_xp: [float scalar]
+    del_yp: [float scalar]
+	   SAD: [float scalar]
+	
+
+	and load the data into memory.  
+
+The names of the files containing the above data are listed in two files:
+geometry_filenames and beam_filenames.  The beam data are stored in a 
+separate file since many dose calculations are done by changing the 
+beam data and leaving the geometry data constant.  This way one can use
+a separate beam file for each beam but the same geometry file.
+*/
+{
+	int Ntotal;
+	char str[200];   // dummy string
+	char header_filename[200], density_filename[200];
+	// flags for filename readin
+	int header_flag = 0;
+	int density_flag = 0;
+	FILE *fid;          // dummy filename
+
+	// read in the geometry filenames
+	if ( (fid = fopen(geometry_filenames,"r")) == NULL)  // open the geometry filenames
+	{
+	  sprintf(errstr,"Could not open the geometry filenames file\n");
+	  return(FAILURE);
+	}
+
+	// read in the non-beam geometric data
+	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
+	{
+	  if (!strcmp(str,geometry_header_line))
+	    if (fscanf(fid,"%s\n",header_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the geometry_header filename from the geometry filenames file.");
+		}
+	    else
+	      header_flag = 1;
+	  else if (!strcmp(str,geometry_density_line))
+	    if (fscanf(fid,"%s\n",density_filename) != 1)
+		{
+	        sprintf(errstr,"Failed to read-in the geometry_density filename from the geometry filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      density_flag = 1;
+	  else
+	  {   
+			sprintf("Unrecognized string in the geometry filenames file: %s\n",str);
+			return(FAILURE);   
+	  }
+	}
+	
+    // confirm that all of the required filenames have been found
+	if (header_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a geometry header filename.\n");
+	  return(FAILURE);
+	}
+	else if (density_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a geometry density filename.\n");
+	  return(FAILURE);
+	}
+
+	// read in geometric and beam data
+	if( (fid = fopen(header_filename,"r")) == NULL)
+	{
+		sprintf(errstr,"Could not open geometry header file.");
+		return(FAILURE);
+	}
+	else
+	{
+		// pop-off the first line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%d %d %d\n",&density->x_count,&density->y_count,&density->z_count) != 3)
+		{
+			sprintf(errstr,"Could not read-in data grid size.");
+			return(FAILURE);
+		}
+		
+		// pop-off the next line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header  file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%f %f %f\n",&density->start.x,&density->start.y,&density->start.z) != 3)
+		{
+			sprintf(errstr,"Could not read-in density grid start position.");
+			return(FAILURE);
+		}
+
+		// pop-off the next line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%f %f %f\n",&density->inc.x,&density->inc.y,&density->inc.z) != 3)
+		{
+			sprintf(errstr,"Could not read-in voxel size vector.");
+			return(FAILURE);
+		}
+
+		Ntotal = density->x_count*density->y_count*density->z_count;
+	}
+
+	// read-in the CT density data
+	if( (fid = fopen(density_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Could not open CT density file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if( (density->matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+		{
+			sprintf(errstr,"Unable to allocate space for CT density grid.");
+			return(FAILURE);
+		}
+		else if ((int)fread(density->matrix,sizeof(float),Ntotal,fid) != Ntotal)
+		{
+			sprintf(errstr,"Unable to read-in CT density data.");
+			return(FAILURE);
+		}
+	}
+	return(SUCCESS);
+}
+
+int pop_beam(BEAM *bm, FILE *beamspec_batch_file)
+/*  Pops a beam off of the beamspec_batch_file file and loads it into a BEAM structure.
+
+  Ensure that the beam data file has the following format:
+ Geometry.beam = 
+
+        ip: [3 element float]
+        jp: [3 element float]
+        kp: [3 element float]
+     y_vec: [3 element float]
+        xp: [float scalar]
+        yp: [float scalar]
+    del_xp: [float scalar]
+    del_yp: [float scalar]
+	   SAD: [float scalar]
+	   num: [int scalar]
+	
+	and load the data into memory.  
+*/
+{
+	char str[200];      // dummy string
+
+	// read-in the beam data
+	// pop-off the first line of the beam data file
+
+	// read-in the CT data grid size
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		return(FAILURE);
+	}
+
+	if (fscanf(beamspec_batch_file,"%d\n",&bm->num) != 1)
+	{
+		sprintf(errstr,"Could not read-in beam data.");
+		return(FAILURE);
+	}
+
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the CT data grid size
+	if (fscanf(beamspec_batch_file,"%f %f %f %f %f\n",&bm->SAD,&bm->xp,&bm->yp,&bm->del_xp,&bm->del_yp) != 5)
+	{
+		sprintf(errstr,"Could not read-in beam data.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the source position vector
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->y_vec[0],&bm->y_vec[1],&bm->y_vec[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in source location vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the beam's eye view vectors, ip first
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->ip[0],&bm->ip[1],&bm->ip[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in ip vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the second beam's eye view vector, jp
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->jp[0],&bm->jp[1],&bm->jp[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in jp vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the third beam's eye view vector, kp
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->kp[0],&bm->kp[1],&bm->kp[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in kp vector.");
+		return(FAILURE);
+	}
+	
+	// ensure that ip,jp,kp are orthonormal and form a right-handed coordinate system
+	if (   (fabs(bm->ip[0]*bm->ip[0] + bm->ip[1]*bm->ip[1] + bm->ip[2]*bm->ip[2] - 1.0) > 1e-6)
+		|| (fabs(bm->jp[0]*bm->jp[0] + bm->jp[1]*bm->jp[1] + bm->jp[2]*bm->jp[2] - 1.0) > 1e-6)
+		|| (fabs(bm->kp[0]*bm->kp[0] + bm->kp[1]*bm->kp[1] + bm->kp[2]*bm->kp[2] - 1.0) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->jp[0] + bm->ip[1]*bm->jp[1] + bm->ip[2]*bm->jp[2]) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->kp[0] + bm->ip[1]*bm->kp[1] + bm->ip[2]*bm->kp[2]) > 1e-6)
+		|| (fabs(bm->jp[0]*bm->kp[0] + bm->jp[1]*bm->kp[1] + bm->jp[2]*bm->kp[2]) > 1e-6))
+	{
+		sprintf(errstr,"Beam's eye view unit vectors ip, jp, and kp must be orthonormal.");
+		return(FAILURE);
+	}
+
+	// check that cross(ip,jp) = kp
+	if (   (fabs(bm->ip[1]*bm->jp[2] - bm->ip[2]*bm->jp[1] - bm->kp[0]) > 1e-6)
+		|| (fabs(bm->ip[2]*bm->jp[0] - bm->ip[0]*bm->jp[2] - bm->kp[1]) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->jp[1] - bm->ip[1]*bm->jp[0] - bm->kp[2]) > 1e-6))
+	{
+		sprintf(errstr,"Must have cross(ip,jp) = kp for beam's eye view");
+		return(FAILURE);
+	}
+
+	return(SUCCESS);
+}

+ 345 - 345
WiscPlan-SourceCode/source-code-photon-linux/raytrace.cpp

@@ -1,345 +1,345 @@
-/* C_RAYTRACE.C ***************************************************************/
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int raytrace(FLOAT_GRID *electron_density_grid,FLOAT_GRID *radiological_depth_grid,
-             POINT point1,POINT point2)
-/*
---------------------------------------------------------------------------------
-   NAME
- 	c_raytrace
- 
-   SYNOPSIS
-        point1 and point2 are the end points of the ray. 
-
-   DESCRIPTION
-        This function traces the ray from point x to point y (in real 
-        coords), assigning depth to any voxels which that ray crosses. The 
-        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
-        1985). This routine will not be understood without thorough reading 
-        of that paper! Point1 and point2 are the start and end points of the 
-        ray, respectively. External structures of type GRID are assumed to 
-        exist, where electron_density_grid are the electron densities, and 
-        radiological_depth_grid is the output grid for these calculations.
-        Voxels in radiological_depth_grid are initially set -ve prior to 
-        calling this function.
- 
-   AUTHOR
-        Written by David C. Murray
-                   University of Waikato
-                   Private Bag 3105
-                   Hamilton
-                   New Zealand
-        and Copyright (1991) to
-                   David C. Murray and Peter W. Hoban,
-                   Cancer Society of New Zealand Inc., and 
-                   University of Waikato.
---------------------------------------------------------------------------------
-*/
-
-{
-/* Variable descriptions:
-   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
-     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
-   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
-   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
-   dx,dy,dz are the widths in cm of the voxels
-*/
-float         x1,y1,z1,
-              x2,y2,z2,
-              xp1,yp1,zp1,
-              dx,dy,dz;
-int           Nx,Ny,Nz;
-
-/*General ray-trace algorithm variables*/
-float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
-float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
-					/*limits of alpha x,y,z parameters*/
-float alpha_min, alpha_max;		/*limits of alpha parameter*/
-int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
-float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
-float *alpha;				/*holds merged set of alpha values*/
-int i_index,j_index,k_index;		/*loop indices for merging alphas*/
-int a;					/*loop counter*/
-int max_index;				/*max index of merged alpha array*/
-float d12;				/*distance between ray end points*/
-float alpha_mid;			/*mid-point of intersection length*/
-float length;				/*intersection length*/
-int i,j,k;				/*indices of voxel with int. length*/
-float rpl = 0.0;			/*radiological path length in cm*/
-float voxel_density;			/*temporary voxel density*/
-float lmax;  // best possible penetration pathlength for a voxel
-float pnorm;  // absolute difference between p1 and p2
-
-/* Assign variables */
-/******************************************************************************/
-x1 = point1.x;
-y1 = point1.y;
-z1 = point1.z;
-x2 = point2.x;
-y2 = point2.y;
-z2 = point2.z;
-Nx = electron_density_grid->x_count + 1;
-Ny = electron_density_grid->y_count + 1;
-Nz = electron_density_grid->z_count + 1;
-dx = electron_density_grid->inc.x;
-dy = electron_density_grid->inc.y;
-dz = electron_density_grid->inc.z;
-
-// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
-xp1 = electron_density_grid->start.x - 0.5*dx;
-yp1 = electron_density_grid->start.y - 0.5*dy;
-zp1 = electron_density_grid->start.z - 0.5*dz;
-
-pnorm = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
-
-// this is the largest pathlength possible for a ray through a voxel:
-lmax = sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
-
-/* Calculate xpN,ypN,zpN */
-/******************************************************************************/
-xpN = xp1 + (Nx-1)*dx;
-ypN = yp1 + (Ny-1)*dy;
-zpN = zp1 + (Nz-1)*dz;
-
-/*Calculate alpha_min and alpha_max*/
-/******************************************************************************/
-/*Avoid division by zero*/
-if (x1==x2)
-  x2 += 0.00001;
-if (y1==y2)
-  y2 += 0.00001;
-if (z1==z2)
-  z2 += 0.00001;
-if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
-{
-	sprintf(errstr,"Error - ray trace region too small.");
-	return(FAILURE);
-}
-
-alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
-if (alpha_z_min>alpha_min) 
-  alpha_min = alpha_z_min;
-if (alpha_min<0)
-  alpha_min = 0;
-alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
-if (alpha_z_max<alpha_max) 
-  alpha_max = alpha_z_max;
-if (alpha_max>1)
-  alpha_max = 1;
-
-// Monitor lines...
-/*
-printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
-                alpha_x_min,alpha_y_min,alpha_z_min);
-printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
-                alpha_x_max,alpha_y_max,alpha_z_max);
-printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
-printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx); */
-
-/*Determine the ranges of i,j,k indices*/
-/******************************************************************************/
-/*The following assignments require conversion from float to integer types*/
-/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
-/*functions convert to the correct value. Note that the range of these*/
-/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
-		
-i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
-                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
-i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
-                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
-j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
-                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
-j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
-                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
-k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
-                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
-k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
-                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
-
-/*Monitor lines...
-fprintf(stdout,"    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
-fprintf(stdout,"    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max);
-*/
-/*Generate sets of alpha values,reversing order if necessary*/
-/******************************************************************************/
-/*allocate array space on stack*/
-if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
-	return(FAILURE);
-}
-
-/* 
-printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
-printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
-printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
- 
-if (i_min <= i_max)
-  if (x2>x1)
-    {
-    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=1;a<=i_max-i_min;a++)
-      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
-    }
-  else
-    {
-    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=i_max-i_min-1;a>=0;a--)
-      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
-    }
-alpha_x[i_max-i_min+1] = 10000.0;
-if (j_min <= j_max)
-  if (y2>y1)
-    {
-    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=1;a<=j_max-j_min;a++)
-      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
-    }
-  else
-    {
-    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=j_max-j_min-1;a>=0;a--)
-      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
-    }
-alpha_y[j_max-j_min+1] = 10001.0;
-if (k_min <= k_max)
-  if (z2>z1)
-    {
-    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=1;a<=k_max-k_min;a++)
-      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
-    }
-  else
-    {
-    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=k_max-k_min-1;a>=0;a--)
-      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
-  }
-alpha_z[k_max-k_min+1] = 10002.0; 
-
-
-/*Monitor lines...
-if (i_max<i_min)
-  fprintf(stdout,"    No alpha_x values\n");
-else
-  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
-                 alpha_x[0],alpha_x[i_max-i_min]);
-if (j_max<j_min)
-  fprintf(stdout,"    No alpha_y values\n");
-else
-  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
-                 alpha_y[0],alpha_y[j_max-j_min]);
-if (k_max<k_min)
-  fprintf(stdout,"    No alpha_z values\n");
-else
-  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
-                 alpha_z[0],alpha_z[k_max-k_min]);
-*/
-/*Generate merged set of alpha values*/
-
-
-/******************************************************************************/
-if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
-	return(FAILURE);
-}
-
-max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
-alpha[0] = alpha_min;
-i_index = 0;
-j_index = 0;
-k_index = 0;
-for (a=1;a<=max_index-1;a++)
-  if (alpha_x[i_index]<alpha_y[j_index])
-    if (alpha_x[i_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_x[i_index];
-      i_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-  else
-    if (alpha_y[j_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_y[j_index];
-      j_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-alpha[max_index] = alpha_max;
-free(alpha_x);				//deallocate temp array storage
-free(alpha_y);
-free(alpha_z);
-/*Monitor lines...
-fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
-for (a=0;a<=max_index;a++)
-  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
-*/
-/*Calculate voxel lengths and indices, and assign radiological depth*/
-/******************************************************************************/
-d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
-					//d12 is distance between ray end pts
-// printf("made it this far in raytrace.\n");
-for (a=1;a<=max_index;a++)
-  {
-  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
-  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
-    {
-    alpha_mid = (alpha[a]+alpha[a-1])/2.0;
-					//alpha_mid is middle of int. length
-    i = (int) floor((x1 + alpha_mid*(x2-x1) - xp1)/dx);
-    j = (int) floor((y1 + alpha_mid*(y2-y1) - yp1)/dy);
-    k = (int) floor((z1 + alpha_mid*(z2-z1) - zp1)/dz);
-					//i,j,k are indices of voxel
-
-    // Remember that this function traces only a single ray.
-    // rpl has been set to zero during initialisation.
-
-    voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
-    rpl += length * voxel_density/2.0;  // add first half of int. length
-    // store pathlength only if the voxel is intersected almost directly
-	// by the ray
-    if (length>=0.75/2*lmax && GRID_VALUE(radiological_depth_grid,i,j,k)<0.0)
-      GRID_VALUE(radiological_depth_grid, i, j, k) = rpl;
-    
-    rpl += length * voxel_density/2.0;  //add second half of int. length  
-    }    
-  } 
-free(alpha); 			//deallocate remaining array storage 
-
-return(SUCCESS);
-
-} 					/*End of s_raytrace routine*/
+/* C_RAYTRACE.C ***************************************************************/
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int raytrace(FLOAT_GRID *electron_density_grid,FLOAT_GRID *radiological_depth_grid,
+             POINT point1,POINT point2)
+/*
+--------------------------------------------------------------------------------
+   NAME
+ 	c_raytrace
+ 
+   SYNOPSIS
+        point1 and point2 are the end points of the ray. 
+
+   DESCRIPTION
+        This function traces the ray from point x to point y (in real 
+        coords), assigning depth to any voxels which that ray crosses. The 
+        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
+        1985). This routine will not be understood without thorough reading 
+        of that paper! Point1 and point2 are the start and end points of the 
+        ray, respectively. External structures of type GRID are assumed to 
+        exist, where electron_density_grid are the electron densities, and 
+        radiological_depth_grid is the output grid for these calculations.
+        Voxels in radiological_depth_grid are initially set -ve prior to 
+        calling this function.
+ 
+   AUTHOR
+        Written by David C. Murray
+                   University of Waikato
+                   Private Bag 3105
+                   Hamilton
+                   New Zealand
+        and Copyright (1991) to
+                   David C. Murray and Peter W. Hoban,
+                   Cancer Society of New Zealand Inc., and 
+                   University of Waikato.
+--------------------------------------------------------------------------------
+*/
+
+{
+/* Variable descriptions:
+   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
+     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
+   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
+   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
+   dx,dy,dz are the widths in cm of the voxels
+*/
+float         x1,y1,z1,
+              x2,y2,z2,
+              xp1,yp1,zp1,
+              dx,dy,dz;
+int           Nx,Ny,Nz;
+
+/*General ray-trace algorithm variables*/
+float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
+float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
+					/*limits of alpha x,y,z parameters*/
+float alpha_min, alpha_max;		/*limits of alpha parameter*/
+int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
+float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
+float *alpha;				/*holds merged set of alpha values*/
+int i_index,j_index,k_index;		/*loop indices for merging alphas*/
+int a;					/*loop counter*/
+int max_index;				/*max index of merged alpha array*/
+float d12;				/*distance between ray end points*/
+float alpha_mid;			/*mid-point of intersection length*/
+float length;				/*intersection length*/
+int i,j,k;				/*indices of voxel with int. length*/
+float rpl = 0.0;			/*radiological path length in cm*/
+float voxel_density;			/*temporary voxel density*/
+float lmax;  // best possible penetration pathlength for a voxel
+float pnorm;  // absolute difference between p1 and p2
+
+/* Assign variables */
+/******************************************************************************/
+x1 = point1.x;
+y1 = point1.y;
+z1 = point1.z;
+x2 = point2.x;
+y2 = point2.y;
+z2 = point2.z;
+Nx = electron_density_grid->x_count + 1;
+Ny = electron_density_grid->y_count + 1;
+Nz = electron_density_grid->z_count + 1;
+dx = electron_density_grid->inc.x;
+dy = electron_density_grid->inc.y;
+dz = electron_density_grid->inc.z;
+
+// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
+xp1 = electron_density_grid->start.x - 0.5*dx;
+yp1 = electron_density_grid->start.y - 0.5*dy;
+zp1 = electron_density_grid->start.z - 0.5*dz;
+
+pnorm = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
+
+// this is the largest pathlength possible for a ray through a voxel:
+lmax = sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
+
+/* Calculate xpN,ypN,zpN */
+/******************************************************************************/
+xpN = xp1 + (Nx-1)*dx;
+ypN = yp1 + (Ny-1)*dy;
+zpN = zp1 + (Nz-1)*dz;
+
+/*Calculate alpha_min and alpha_max*/
+/******************************************************************************/
+/*Avoid division by zero*/
+if (x1==x2)
+  x2 += 0.00001;
+if (y1==y2)
+  y2 += 0.00001;
+if (z1==z2)
+  z2 += 0.00001;
+if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
+{
+	sprintf(errstr,"Error - ray trace region too small.");
+	return(FAILURE);
+}
+
+alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
+if (alpha_z_min>alpha_min) 
+  alpha_min = alpha_z_min;
+if (alpha_min<0)
+  alpha_min = 0;
+alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
+if (alpha_z_max<alpha_max) 
+  alpha_max = alpha_z_max;
+if (alpha_max>1)
+  alpha_max = 1;
+
+// Monitor lines...
+/*
+printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
+                alpha_x_min,alpha_y_min,alpha_z_min);
+printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
+                alpha_x_max,alpha_y_max,alpha_z_max);
+printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
+printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx); */
+
+/*Determine the ranges of i,j,k indices*/
+/******************************************************************************/
+/*The following assignments require conversion from float to integer types*/
+/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
+/*functions convert to the correct value. Note that the range of these*/
+/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
+		
+i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
+                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
+i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
+                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
+j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
+                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
+j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
+                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
+k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
+                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
+k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
+                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
+
+/*Monitor lines...
+fprintf(stdout,"    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
+fprintf(stdout,"    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max);
+*/
+/*Generate sets of alpha values,reversing order if necessary*/
+/******************************************************************************/
+/*allocate array space on stack*/
+if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
+	return(FAILURE);
+}
+
+/* 
+printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
+printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
+printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
+ 
+if (i_min <= i_max)
+  if (x2>x1)
+    {
+    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=1;a<=i_max-i_min;a++)
+      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
+    }
+  else
+    {
+    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=i_max-i_min-1;a>=0;a--)
+      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
+    }
+alpha_x[i_max-i_min+1] = 10000.0;
+if (j_min <= j_max)
+  if (y2>y1)
+    {
+    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=1;a<=j_max-j_min;a++)
+      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
+    }
+  else
+    {
+    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=j_max-j_min-1;a>=0;a--)
+      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
+    }
+alpha_y[j_max-j_min+1] = 10001.0;
+if (k_min <= k_max)
+  if (z2>z1)
+    {
+    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=1;a<=k_max-k_min;a++)
+      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
+    }
+  else
+    {
+    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=k_max-k_min-1;a>=0;a--)
+      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
+  }
+alpha_z[k_max-k_min+1] = 10002.0; 
+
+
+/*Monitor lines...
+if (i_max<i_min)
+  fprintf(stdout,"    No alpha_x values\n");
+else
+  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
+                 alpha_x[0],alpha_x[i_max-i_min]);
+if (j_max<j_min)
+  fprintf(stdout,"    No alpha_y values\n");
+else
+  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
+                 alpha_y[0],alpha_y[j_max-j_min]);
+if (k_max<k_min)
+  fprintf(stdout,"    No alpha_z values\n");
+else
+  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
+                 alpha_z[0],alpha_z[k_max-k_min]);
+*/
+/*Generate merged set of alpha values*/
+
+
+/******************************************************************************/
+if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
+	return(FAILURE);
+}
+
+max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
+alpha[0] = alpha_min;
+i_index = 0;
+j_index = 0;
+k_index = 0;
+for (a=1;a<=max_index-1;a++)
+  if (alpha_x[i_index]<alpha_y[j_index])
+    if (alpha_x[i_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_x[i_index];
+      i_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+  else
+    if (alpha_y[j_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_y[j_index];
+      j_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+alpha[max_index] = alpha_max;
+free(alpha_x);				//deallocate temp array storage
+free(alpha_y);
+free(alpha_z);
+/*Monitor lines...
+fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
+for (a=0;a<=max_index;a++)
+  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
+*/
+/*Calculate voxel lengths and indices, and assign radiological depth*/
+/******************************************************************************/
+d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
+					//d12 is distance between ray end pts
+// printf("made it this far in raytrace.\n");
+for (a=1;a<=max_index;a++)
+  {
+  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
+  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
+    {
+    alpha_mid = (alpha[a]+alpha[a-1])/2.0;
+					//alpha_mid is middle of int. length
+    i = (int) floor((x1 + alpha_mid*(x2-x1) - xp1)/dx);
+    j = (int) floor((y1 + alpha_mid*(y2-y1) - yp1)/dy);
+    k = (int) floor((z1 + alpha_mid*(z2-z1) - zp1)/dz);
+					//i,j,k are indices of voxel
+
+    // Remember that this function traces only a single ray.
+    // rpl has been set to zero during initialisation.
+
+    voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
+    rpl += length * voxel_density/2.0;  // add first half of int. length
+    // store pathlength only if the voxel is intersected almost directly
+	// by the ray
+    if (length>=0.75/2*lmax && GRID_VALUE(radiological_depth_grid,i,j,k)<0.0)
+      GRID_VALUE(radiological_depth_grid, i, j, k) = rpl;
+    
+    rpl += length * voxel_density/2.0;  //add second half of int. length  
+    }    
+  } 
+free(alpha); 			//deallocate remaining array storage 
+
+return(SUCCESS);
+
+} 					/*End of s_raytrace routine*/

+ 301 - 301
WiscPlan-SourceCode/source-code-photon-linux/terma_dose_masks.cpp

@@ -1,301 +1,301 @@
-/* terma_dose_masks.cpp */
-
-/* All voxels that lie within a cylinder of radius RAPERTURE + RSAFE, centered
-on the central beam axis, are marked in the dose_mask grid.  These voxels will
-be used in the dose calculation.  The voxels that are marked in the terma_mask
-grid are a subset of those that are marked in the dose_mask grid. The terma_mask
-grid contains values that specify the fraction of each voxel that lies inside
-of the beam aperture in the beam's eye view plane, which exists at a distance
-SAD from the x-ray source location. */
-
-/* Determination of voxel "insideness" for the terma_mask:
-If it is discovered that a voxel is intersected by an aperture boundary in the
-beam's eye view plane, then that voxel is broken-up into Mus x Nus x Qus sub-
-voxels (upsampled).  The fraction of the sub-voxels that lie inside the beam
-aperture in the beam's eye view then becomes the insideness for that voxel. */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int terma_dose_masks(FLOAT_GRID *terma_mask, FLOAT_GRID *dose_mask, BEAM *bm)
-// The user must allocate space for terma_mask and dose_mask before calling 
-// this function.
-// The validity of all of the arguments to this function are assumed to be 
-// checked with the parse_func, which acts as a gatekeeper for the convolution
-// program.
-{
-	// scalars
-	int i,j,k,m;     // indices
-	int ius,jus,kus;  // upsample voxel indices
-	int M,N,Q;     // grid dimensions
-	float dx,dy,dz;  // voxel dimensions
-	float xp,yp,SAD; // aperture center in ip,jp,kp coordinate system
-	float xsub,ysub,zsub;  // coordinates of sub-voxels
-	float del_xp,del_yp; // width of beamlet field in plane at SAD
-	float Rmax,Rcurr,Rcyl,Rvox,Rcyl_sqr,Rproj;
-	float eta,gamma,delta;  // dummy variables
-
-	// vectors
-	float *x,*y,*z;  // x,y,z coordinate vectors
-	float *dxus,*dyus,*dzus;  // upsample vectors
-	float *y_vec,*ip,*jp,*kp,*d_hat;  // beam vectors
-
-	// matrices
-	float **c;  // matrix of the 8 corners of voxel grid
-	
-	// Ensure that upsample factors are all greater than zero
-	if (Mus < 1 || Nus < 1 || Qus < 1)
-	{
-		sprintf(errstr,"Upsample factors must all be greater than zero.");
-		return(FAILURE);
-	}
-
-	// record the sizes of terma_mask and dose_mask
-	M = terma_mask->x_count;
-	N = terma_mask->y_count;
-	Q = terma_mask->z_count;
-
-	if (M != dose_mask->x_count || N != dose_mask->y_count 
-		|| Q != dose_mask->z_count)
-	{
-		sprintf(errstr,"dose_mask and terma_mask dimensions are incompatible.");
-		return(FAILURE);
-	}
-
-	dx = terma_mask->inc.x;
-	dy = terma_mask->inc.y;
-	dz = terma_mask->inc.z;
-	
-	// initialize vectors
-	x = fvector(0,M-1);
-	y = fvector(0,N-1);
-	z = fvector(0,Q-1);
-
-	dxus = fvector(0,Mus-1);
-	dyus = fvector(0,Nus-1);
-	dzus = fvector(0,Qus-1);
-
-	y_vec = fvector(0,2);
-	ip = fvector(0,2);
-	jp = fvector(0,2);
-	kp = fvector(0,2);
-	d_hat = fvector(0,2);
-
-	// initialize matrices
-	c = fmatrix(0,7,0,2);
-
-	// fill-in the voxel coordinate vectors
-	for (i=0;i<M;i++) x[i] = terma_mask->start.x + (float)i*dx;
-	for (j=0;j<N;j++) y[j] = terma_mask->start.y + (float)j*dy;
-	for (k=0;k<Q;k++) z[k] = terma_mask->start.z + (float)k*dz;
-
-	// fill-in the upsample vectors
-	// For a voxel at (i,j,k), the xyz coordinates of a sub-voxel (ius,jus,kus)
-	// are (x[i] + dxus[ius], y[j] + dyus[jus], z[k] + dzus[k])
-	dxus[0] = -0.5*dx*(1-1/Mus);
-	for (ius=1;ius<Mus;ius++)  dxus[ius] = dxus[ius-1] + dx/Mus;
-
-	dyus[0] = -0.5*dy*(1-1/Nus);
-	for (jus=1;jus<Nus;jus++) dyus[jus] = dyus[jus-1] + dy/Nus;
-
-	dzus[0] = -0.5*dz*(1-1/Qus);
-	for (kus=1;kus<Qus;kus++) dzus[kus] = dzus[kus-1] + dz/Qus;
-
-	// rewrite beam vectors for quick reference later
-	y_vec[0] = bm->y_vec[0];
-	y_vec[1] = bm->y_vec[1];
-	y_vec[2] = bm->y_vec[2];
-
-	// coordinate system in beam's eye view
-	for (j=0;j<3;j++) ip[j] = bm->ip[j];
-	for (j=0;j<3;j++) jp[j] = bm->jp[j];
-	for (j=0;j<3;j++) kp[j] = bm->kp[j];
-
-	// aperture center in beam's eye view
-	xp = bm->xp;
-	yp = bm->yp;
-
-	// aperture size in beam's eye view
-	del_xp = bm->del_xp;
-	del_yp = bm->del_yp;
-
-	// source-axis distance of the beam
-	SAD = bm->SAD;
-
-	// calculate the max distance between the source vector and each grid corner
-	Rmax = 0.0;
-	
-	// the the matrix c with the coordinates of the eight corners of the grid.
-	for (i=0;i<=1;i++)
-	  for (j=0;j<=1;j++)
-	    for (k=0;k<=1;k++)
-		{ 
-		  //                     0 => lower corners         1 => upper corners
-		  c[i+j*2+k*4][0] = (1-(float)i)*(x[0]-dx/2.0) + (float)i*(x[M-1]+dx/2.0);
-		  c[i+j*2+k*4][1] = (1-(float)j)*(y[0]-dy/2.0) + (float)j*(y[N-1]+dy/2.0);
-		  c[i+j*2+k*4][2] = (1-(float)k)*(z[0]-dz/2.0) + (float)k*(z[Q-1]+dz/2.0);
-		}
-
-	// find which corner is the farthest from the source
-	for (m=0;m<=7;m++)
-	{
-		Rcurr = sqrt(pow(y_vec[0] - c[m][0],2.0f)
-			       + pow(y_vec[1] - c[m][1],2.0f)
-				   + pow(y_vec[2] - c[m][2],2.0f));
-		if (Rcurr > Rmax)
-			Rmax = Rcurr;
-	}
-
-	// Fill the dose_mask
-
-	// Radius of cylinder about y_vec + kp that will contain all voxels
-	// to be used in the dose calculation.
-	Rcyl = sqrt(del_xp*del_xp + del_yp*del_yp)*Rmax/SAD;  // project Rmax to aperture plane
-	Rcyl_sqr = Rcyl*Rcyl + RSAFE*RSAFE;  // add an empirical safety margin to the radius squared
-
-	// calculate the true source direction
-	// d_hat points at the center of the aperture from the source location
-	d_hat[0] = xp*ip[0] + yp*jp[0] + SAD*kp[0];
-	d_hat[1] = xp*ip[1] + yp*jp[1] + SAD*kp[1];
-	d_hat[2] = xp*ip[2] + yp*jp[2] + SAD*kp[2];
-
-	// normalize d_hat so it's a true "hat" vector
-	delta = sqrt(d_hat[0]*d_hat[0] + d_hat[1]*d_hat[1] + d_hat[2]*d_hat[2]);
-	d_hat[0] = d_hat[0]/delta;
-	d_hat[1] = d_hat[1]/delta;
-	d_hat[2] = d_hat[2]/delta;
-
-	for (k=0;k<Q;k++)
-	 for (j=0;j<N;j++)
-	  for (i=0;i<M;i++)
-	  {
-		  // squared distance between the voxel and the source:
-		  eta = (x[i] - y_vec[0])*(x[i] - y_vec[0])
-			  + (y[j] - y_vec[1])*(y[j] - y_vec[1])
-			  + (z[k] - y_vec[2])*(z[k] - y_vec[2]);
-
-		  // squared distance between the voxel and the source along source direction, 
-	      // y_vec + kp:
-		  gamma = pow((x[i] - y_vec[0])*d_hat[0]
-				    + (y[j] - y_vec[1])*d_hat[1]
-				    + (z[k] - y_vec[2])*d_hat[2],2.0f);
-
-		  // printf("%lf %lf\n",eta, gamma);
-
-		  // squared difference between the voxel and the axis of the cylinder
-		  delta = eta - gamma;
-
-		  // If the voxel is inside the cylinder about y_vec + ip of radius Rcyl plus
-		  // a safety margin then mark it in dose_mask.
-		  if (delta <= Rcyl_sqr)
-			  GRID_VALUE(dose_mask,i,j,k) = 1.0;
-		  else
-			  GRID_VALUE(dose_mask,i,j,k) = 0.0;
-	  }
-
-	// Fill the terma_mask, including the insideness of each voxel
-
-	// Each voxel is enclosed with in a sphere of the following radius:
-	Rvox = 0.5*sqrt(dx*dx + dy*dy + dz*dz);
-
-	for (i=0;i<M;i++)
-	 for (j=0;j<N;j++)
-	  for (k=0;k<Q;k++)
-	   // deal only with voxels that are marked in the dose_mask
-	   if (GRID_VALUE(dose_mask,i,j,k) > 0.0)
-	   {
-		 // distance between source and voxel in the kp direction
-	     delta = kp[0]*(x[i] - y_vec[0])
-               + kp[1]*(y[j] - y_vec[1])
-               + kp[2]*(z[k] - y_vec[2]);
-
-		 // voxel's projected offset on the aperture plane in the ip direction:
-		 eta = (SAD/delta)*(  ip[0]*(x[i] - y_vec[0])
-				            + ip[1]*(y[j] - y_vec[1])
-						    + ip[2]*(z[k] - y_vec[2])) - xp;
-		 // voxel's projected offset on the aperture plane in the jp direction:
-		 gamma = (SAD/delta)*(  jp[0]*(x[i] - y_vec[0])
-				              + jp[1]*(y[j] - y_vec[1])
-						      + jp[2]*(z[k] - y_vec[2])) - yp;
-
-		 // take absolute value of offsets
-		 eta = fabs(eta);
-		 gamma = fabs(gamma);
-
-		 Rproj = Rvox*SAD/delta;  // voxel radius projected to plane at SAD
-
-		 // Determine where the voxel lies with respect to the aperture:
-		 if (eta <= 0.5*del_xp+Rproj && gamma <= 0.5*del_yp+Rproj)
-		 // voxel is inside aperture plus a half-voxel margin:
-			if (eta >= 0.5*del_xp-Rproj || gamma >= 0.5*del_yp-Rproj)
-		    // voxel is between the aperture plus/minus a half-voxel margin:
-			// (true at this point if the voxel size is larger than the aperture size)
-			{
-			    // Determine insideness of the voxel by breaking it up
-				// into subvoxels and projecting the parts to the aperture plane.
-				m = 0;  // number of subvoxels inside aperture
-	            // project each subvoxel onto the aperture at SAD
-		        for (ius=0;ius<Mus;ius++)
-			     for (jus=0;jus<Nus;jus++)
-			      for (kus=0;kus<Qus;kus++)
-				  {
-			        // find the center of the subvoxel
-			        xsub = x[i] + dxus[ius];
-			        ysub = y[j] + dyus[jus];
-			        zsub = z[k] + dzus[kus];
-
-			        // project the subvoxel onto the aperture
-			        // distance between source and subvoxel in the kp direction
-			        delta = kp[0]*(xsub - y_vec[0])
-				          + kp[1]*(ysub - y_vec[1])
-					      + kp[2]*(zsub - y_vec[2]);
-
-			        // projected offset on aperture plane in the ip direction:
-			        eta = (SAD/delta)*(  ip[0]*(xsub - y_vec[0])
-				                       + ip[1]*(ysub - y_vec[1])
-								       + ip[2]*(zsub - y_vec[2])) - xp;
-			        // projected offset on aperture plane in the jp direction:
-			        gamma = (SAD/delta)*(  jp[0]*(xsub - y_vec[0])
-				                         + jp[1]*(ysub - y_vec[1])
-								         + jp[2]*(zsub - y_vec[2])) - yp;
-
-		            eta = fabs(eta);
-			        gamma = fabs(gamma);
-
-			        // check if the subvoxel is inside the aperture at SAD
-			        if (eta <= 0.5*del_xp && gamma <= 0.5*del_yp)
-				       m++;
-				  }
-
-		        // the fraction of subvoxels inside the aperture becomes the insidness
-	            GRID_VALUE(terma_mask,i,j,k) = (float)m/(float)(Mus*Nus*Qus);
-			}
-			else
-			// voxel is inside the aperture minus a half-voxel margin
-				GRID_VALUE(terma_mask,i,j,k) = 1.0;
-		 else
-		 // voxel outside the aperture plus the half-voxel margin
-		    GRID_VALUE(terma_mask,i,j,k) = 0.0;
-	   }
-
-	// free vectors
-	free_fvector(x,0,M-1);
-	free_fvector(y,0,N-1);
-	free_fvector(z,0,Q-1);
-
-	free_fvector(dxus,0,Mus-1);
-	free_fvector(dyus,0,Nus-1);
-	free_fvector(dzus,0,Qus-1);
-
-	free_fvector(y_vec,0,2);
-	free_fvector(ip,0,2);
-	free_fvector(jp,0,2);
-	free_fvector(kp,0,2);
-	free_fvector(d_hat,0,2);
-
-	// free matrices
-	free_fmatrix(c,0,7,0,2);
-
-	return(SUCCESS);
-}
+/* terma_dose_masks.cpp */
+
+/* All voxels that lie within a cylinder of radius RAPERTURE + RSAFE, centered
+on the central beam axis, are marked in the dose_mask grid.  These voxels will
+be used in the dose calculation.  The voxels that are marked in the terma_mask
+grid are a subset of those that are marked in the dose_mask grid. The terma_mask
+grid contains values that specify the fraction of each voxel that lies inside
+of the beam aperture in the beam's eye view plane, which exists at a distance
+SAD from the x-ray source location. */
+
+/* Determination of voxel "insideness" for the terma_mask:
+If it is discovered that a voxel is intersected by an aperture boundary in the
+beam's eye view plane, then that voxel is broken-up into Mus x Nus x Qus sub-
+voxels (upsampled).  The fraction of the sub-voxels that lie inside the beam
+aperture in the beam's eye view then becomes the insideness for that voxel. */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int terma_dose_masks(FLOAT_GRID *terma_mask, FLOAT_GRID *dose_mask, BEAM *bm)
+// The user must allocate space for terma_mask and dose_mask before calling 
+// this function.
+// The validity of all of the arguments to this function are assumed to be 
+// checked with the parse_func, which acts as a gatekeeper for the convolution
+// program.
+{
+	// scalars
+	int i,j,k,m;     // indices
+	int ius,jus,kus;  // upsample voxel indices
+	int M,N,Q;     // grid dimensions
+	float dx,dy,dz;  // voxel dimensions
+	float xp,yp,SAD; // aperture center in ip,jp,kp coordinate system
+	float xsub,ysub,zsub;  // coordinates of sub-voxels
+	float del_xp,del_yp; // width of beamlet field in plane at SAD
+	float Rmax,Rcurr,Rcyl,Rvox,Rcyl_sqr,Rproj;
+	float eta,gamma,delta;  // dummy variables
+
+	// vectors
+	float *x,*y,*z;  // x,y,z coordinate vectors
+	float *dxus,*dyus,*dzus;  // upsample vectors
+	float *y_vec,*ip,*jp,*kp,*d_hat;  // beam vectors
+
+	// matrices
+	float **c;  // matrix of the 8 corners of voxel grid
+	
+	// Ensure that upsample factors are all greater than zero
+	if (Mus < 1 || Nus < 1 || Qus < 1)
+	{
+		sprintf(errstr,"Upsample factors must all be greater than zero.");
+		return(FAILURE);
+	}
+
+	// record the sizes of terma_mask and dose_mask
+	M = terma_mask->x_count;
+	N = terma_mask->y_count;
+	Q = terma_mask->z_count;
+
+	if (M != dose_mask->x_count || N != dose_mask->y_count 
+		|| Q != dose_mask->z_count)
+	{
+		sprintf(errstr,"dose_mask and terma_mask dimensions are incompatible.");
+		return(FAILURE);
+	}
+
+	dx = terma_mask->inc.x;
+	dy = terma_mask->inc.y;
+	dz = terma_mask->inc.z;
+	
+	// initialize vectors
+	x = fvector(0,M-1);
+	y = fvector(0,N-1);
+	z = fvector(0,Q-1);
+
+	dxus = fvector(0,Mus-1);
+	dyus = fvector(0,Nus-1);
+	dzus = fvector(0,Qus-1);
+
+	y_vec = fvector(0,2);
+	ip = fvector(0,2);
+	jp = fvector(0,2);
+	kp = fvector(0,2);
+	d_hat = fvector(0,2);
+
+	// initialize matrices
+	c = fmatrix(0,7,0,2);
+
+	// fill-in the voxel coordinate vectors
+	for (i=0;i<M;i++) x[i] = terma_mask->start.x + (float)i*dx;
+	for (j=0;j<N;j++) y[j] = terma_mask->start.y + (float)j*dy;
+	for (k=0;k<Q;k++) z[k] = terma_mask->start.z + (float)k*dz;
+
+	// fill-in the upsample vectors
+	// For a voxel at (i,j,k), the xyz coordinates of a sub-voxel (ius,jus,kus)
+	// are (x[i] + dxus[ius], y[j] + dyus[jus], z[k] + dzus[k])
+	dxus[0] = -0.5*dx*(1-1/Mus);
+	for (ius=1;ius<Mus;ius++)  dxus[ius] = dxus[ius-1] + dx/Mus;
+
+	dyus[0] = -0.5*dy*(1-1/Nus);
+	for (jus=1;jus<Nus;jus++) dyus[jus] = dyus[jus-1] + dy/Nus;
+
+	dzus[0] = -0.5*dz*(1-1/Qus);
+	for (kus=1;kus<Qus;kus++) dzus[kus] = dzus[kus-1] + dz/Qus;
+
+	// rewrite beam vectors for quick reference later
+	y_vec[0] = bm->y_vec[0];
+	y_vec[1] = bm->y_vec[1];
+	y_vec[2] = bm->y_vec[2];
+
+	// coordinate system in beam's eye view
+	for (j=0;j<3;j++) ip[j] = bm->ip[j];
+	for (j=0;j<3;j++) jp[j] = bm->jp[j];
+	for (j=0;j<3;j++) kp[j] = bm->kp[j];
+
+	// aperture center in beam's eye view
+	xp = bm->xp;
+	yp = bm->yp;
+
+	// aperture size in beam's eye view
+	del_xp = bm->del_xp;
+	del_yp = bm->del_yp;
+
+	// source-axis distance of the beam
+	SAD = bm->SAD;
+
+	// calculate the max distance between the source vector and each grid corner
+	Rmax = 0.0;
+	
+	// the the matrix c with the coordinates of the eight corners of the grid.
+	for (i=0;i<=1;i++)
+	  for (j=0;j<=1;j++)
+	    for (k=0;k<=1;k++)
+		{ 
+		  //                     0 => lower corners         1 => upper corners
+		  c[i+j*2+k*4][0] = (1-(float)i)*(x[0]-dx/2.0) + (float)i*(x[M-1]+dx/2.0);
+		  c[i+j*2+k*4][1] = (1-(float)j)*(y[0]-dy/2.0) + (float)j*(y[N-1]+dy/2.0);
+		  c[i+j*2+k*4][2] = (1-(float)k)*(z[0]-dz/2.0) + (float)k*(z[Q-1]+dz/2.0);
+		}
+
+	// find which corner is the farthest from the source
+	for (m=0;m<=7;m++)
+	{
+		Rcurr = sqrt(pow(y_vec[0] - c[m][0],2.0f)
+			       + pow(y_vec[1] - c[m][1],2.0f)
+				   + pow(y_vec[2] - c[m][2],2.0f));
+		if (Rcurr > Rmax)
+			Rmax = Rcurr;
+	}
+
+	// Fill the dose_mask
+
+	// Radius of cylinder about y_vec + kp that will contain all voxels
+	// to be used in the dose calculation.
+	Rcyl = sqrt(del_xp*del_xp + del_yp*del_yp)*Rmax/SAD;  // project Rmax to aperture plane
+	Rcyl_sqr = Rcyl*Rcyl + RSAFE*RSAFE;  // add an empirical safety margin to the radius squared
+
+	// calculate the true source direction
+	// d_hat points at the center of the aperture from the source location
+	d_hat[0] = xp*ip[0] + yp*jp[0] + SAD*kp[0];
+	d_hat[1] = xp*ip[1] + yp*jp[1] + SAD*kp[1];
+	d_hat[2] = xp*ip[2] + yp*jp[2] + SAD*kp[2];
+
+	// normalize d_hat so it's a true "hat" vector
+	delta = sqrt(d_hat[0]*d_hat[0] + d_hat[1]*d_hat[1] + d_hat[2]*d_hat[2]);
+	d_hat[0] = d_hat[0]/delta;
+	d_hat[1] = d_hat[1]/delta;
+	d_hat[2] = d_hat[2]/delta;
+
+	for (k=0;k<Q;k++)
+	 for (j=0;j<N;j++)
+	  for (i=0;i<M;i++)
+	  {
+		  // squared distance between the voxel and the source:
+		  eta = (x[i] - y_vec[0])*(x[i] - y_vec[0])
+			  + (y[j] - y_vec[1])*(y[j] - y_vec[1])
+			  + (z[k] - y_vec[2])*(z[k] - y_vec[2]);
+
+		  // squared distance between the voxel and the source along source direction, 
+	      // y_vec + kp:
+		  gamma = pow((x[i] - y_vec[0])*d_hat[0]
+				    + (y[j] - y_vec[1])*d_hat[1]
+				    + (z[k] - y_vec[2])*d_hat[2],2.0f);
+
+		  // printf("%lf %lf\n",eta, gamma);
+
+		  // squared difference between the voxel and the axis of the cylinder
+		  delta = eta - gamma;
+
+		  // If the voxel is inside the cylinder about y_vec + ip of radius Rcyl plus
+		  // a safety margin then mark it in dose_mask.
+		  if (delta <= Rcyl_sqr)
+			  GRID_VALUE(dose_mask,i,j,k) = 1.0;
+		  else
+			  GRID_VALUE(dose_mask,i,j,k) = 0.0;
+	  }
+
+	// Fill the terma_mask, including the insideness of each voxel
+
+	// Each voxel is enclosed with in a sphere of the following radius:
+	Rvox = 0.5*sqrt(dx*dx + dy*dy + dz*dz);
+
+	for (i=0;i<M;i++)
+	 for (j=0;j<N;j++)
+	  for (k=0;k<Q;k++)
+	   // deal only with voxels that are marked in the dose_mask
+	   if (GRID_VALUE(dose_mask,i,j,k) > 0.0)
+	   {
+		 // distance between source and voxel in the kp direction
+	     delta = kp[0]*(x[i] - y_vec[0])
+               + kp[1]*(y[j] - y_vec[1])
+               + kp[2]*(z[k] - y_vec[2]);
+
+		 // voxel's projected offset on the aperture plane in the ip direction:
+		 eta = (SAD/delta)*(  ip[0]*(x[i] - y_vec[0])
+				            + ip[1]*(y[j] - y_vec[1])
+						    + ip[2]*(z[k] - y_vec[2])) - xp;
+		 // voxel's projected offset on the aperture plane in the jp direction:
+		 gamma = (SAD/delta)*(  jp[0]*(x[i] - y_vec[0])
+				              + jp[1]*(y[j] - y_vec[1])
+						      + jp[2]*(z[k] - y_vec[2])) - yp;
+
+		 // take absolute value of offsets
+		 eta = fabs(eta);
+		 gamma = fabs(gamma);
+
+		 Rproj = Rvox*SAD/delta;  // voxel radius projected to plane at SAD
+
+		 // Determine where the voxel lies with respect to the aperture:
+		 if (eta <= 0.5*del_xp+Rproj && gamma <= 0.5*del_yp+Rproj)
+		 // voxel is inside aperture plus a half-voxel margin:
+			if (eta >= 0.5*del_xp-Rproj || gamma >= 0.5*del_yp-Rproj)
+		    // voxel is between the aperture plus/minus a half-voxel margin:
+			// (true at this point if the voxel size is larger than the aperture size)
+			{
+			    // Determine insideness of the voxel by breaking it up
+				// into subvoxels and projecting the parts to the aperture plane.
+				m = 0;  // number of subvoxels inside aperture
+	            // project each subvoxel onto the aperture at SAD
+		        for (ius=0;ius<Mus;ius++)
+			     for (jus=0;jus<Nus;jus++)
+			      for (kus=0;kus<Qus;kus++)
+				  {
+			        // find the center of the subvoxel
+			        xsub = x[i] + dxus[ius];
+			        ysub = y[j] + dyus[jus];
+			        zsub = z[k] + dzus[kus];
+
+			        // project the subvoxel onto the aperture
+			        // distance between source and subvoxel in the kp direction
+			        delta = kp[0]*(xsub - y_vec[0])
+				          + kp[1]*(ysub - y_vec[1])
+					      + kp[2]*(zsub - y_vec[2]);
+
+			        // projected offset on aperture plane in the ip direction:
+			        eta = (SAD/delta)*(  ip[0]*(xsub - y_vec[0])
+				                       + ip[1]*(ysub - y_vec[1])
+								       + ip[2]*(zsub - y_vec[2])) - xp;
+			        // projected offset on aperture plane in the jp direction:
+			        gamma = (SAD/delta)*(  jp[0]*(xsub - y_vec[0])
+				                         + jp[1]*(ysub - y_vec[1])
+								         + jp[2]*(zsub - y_vec[2])) - yp;
+
+		            eta = fabs(eta);
+			        gamma = fabs(gamma);
+
+			        // check if the subvoxel is inside the aperture at SAD
+			        if (eta <= 0.5*del_xp && gamma <= 0.5*del_yp)
+				       m++;
+				  }
+
+		        // the fraction of subvoxels inside the aperture becomes the insidness
+	            GRID_VALUE(terma_mask,i,j,k) = (float)m/(float)(Mus*Nus*Qus);
+			}
+			else
+			// voxel is inside the aperture minus a half-voxel margin
+				GRID_VALUE(terma_mask,i,j,k) = 1.0;
+		 else
+		 // voxel outside the aperture plus the half-voxel margin
+		    GRID_VALUE(terma_mask,i,j,k) = 0.0;
+	   }
+
+	// free vectors
+	free_fvector(x,0,M-1);
+	free_fvector(y,0,N-1);
+	free_fvector(z,0,Q-1);
+
+	free_fvector(dxus,0,Mus-1);
+	free_fvector(dyus,0,Nus-1);
+	free_fvector(dzus,0,Qus-1);
+
+	free_fvector(y_vec,0,2);
+	free_fvector(ip,0,2);
+	free_fvector(jp,0,2);
+	free_fvector(kp,0,2);
+	free_fvector(d_hat,0,2);
+
+	// free matrices
+	free_fmatrix(c,0,7,0,2);
+
+	return(SUCCESS);
+}

+ 60 - 60
WiscPlan-SourceCode/source-code-photon-linux/terma_kerma.cpp

@@ -1,60 +1,60 @@
-/* terma_kerma.cpp */
-
-/* Calculates the terma and the kerma of every voxel in the terma_mask.  */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int terma_kerma(FLOAT_GRID *deff, FLOAT_GRID *terma, FLOAT_GRID *kermac,
-				MONO_KERNELS *mono, FLOAT_GRID *terma_mask)
-{													 
- // insideness is accounted for with terma_mask
- int i, j, k, e;
- float kermac0, terma0;
-
- //calculate T and Kc at zero depth for use in hardening correction
- //see Hoban et al 1994 (PMB)
- kermac0 = terma0 = 0.0;
- for (e=0;e<mono->nkernels;e++)
- {
-   kermac0 = mono->fluence[e]*mono->energy[e]*mono->mu_en[e];
-   terma0 = mono->fluence[e]*mono->energy[e]*mono->mu[e];
- }
-
- for (j=0;j<deff->y_count;j++)
-  for (k=0;k<deff->z_count;k++)
-   for (i=0;i<deff->x_count;i++)
-    if (GRID_VALUE(terma_mask,i,j,k) > 0)
-    {
-	  // The amount of each voxel that is inside the field (insideness) was
-	  // was accounted in the calculation of the terma_mask
-
-	  //sum terma and collision kerma over each energy in spectrum 
-	  // (stored in mono kernel structure)
-	  for (e=0;e<mono->nkernels;e++)
-	  {
-       GRID_VALUE(terma,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
-       GRID_VALUE(kermac,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu_en[e]
-                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
-	  }
-	  
-	  //adjust terma and collision kerma according to insideness
-	  GRID_VALUE(terma,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
-	  GRID_VALUE(kermac,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
-
-	  // beam hardening correction
-	  if (terma0 <= 0.0 || kermac0 <= 0.0)
-		nrerror("Input spectrum must not sum to zero."); 
-	  else
-		GRID_VALUE(terma,i,j,k) *= (GRID_VALUE(kermac,i,j,k)/GRID_VALUE(terma,i,j,k))
-								/(kermac0/terma0);
-	}
-	else
-	{
-		GRID_VALUE(terma,i,j,k) = 0.0;
-		GRID_VALUE(kermac,i,j,k) = 0.0;
-	}
-    return(SUCCESS);
-}
+/* terma_kerma.cpp */
+
+/* Calculates the terma and the kerma of every voxel in the terma_mask.  */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int terma_kerma(FLOAT_GRID *deff, FLOAT_GRID *terma, FLOAT_GRID *kermac,
+				MONO_KERNELS *mono, FLOAT_GRID *terma_mask)
+{													 
+ // insideness is accounted for with terma_mask
+ int i, j, k, e;
+ float kermac0, terma0;
+
+ //calculate T and Kc at zero depth for use in hardening correction
+ //see Hoban et al 1994 (PMB)
+ kermac0 = terma0 = 0.0;
+ for (e=0;e<mono->nkernels;e++)
+ {
+   kermac0 = mono->fluence[e]*mono->energy[e]*mono->mu_en[e];
+   terma0 = mono->fluence[e]*mono->energy[e]*mono->mu[e];
+ }
+
+ for (j=0;j<deff->y_count;j++)
+  for (k=0;k<deff->z_count;k++)
+   for (i=0;i<deff->x_count;i++)
+    if (GRID_VALUE(terma_mask,i,j,k) > 0)
+    {
+	  // The amount of each voxel that is inside the field (insideness) was
+	  // was accounted in the calculation of the terma_mask
+
+	  //sum terma and collision kerma over each energy in spectrum 
+	  // (stored in mono kernel structure)
+	  for (e=0;e<mono->nkernels;e++)
+	  {
+       GRID_VALUE(terma,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
+       GRID_VALUE(kermac,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu_en[e]
+                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
+	  }
+	  
+	  //adjust terma and collision kerma according to insideness
+	  GRID_VALUE(terma,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
+	  GRID_VALUE(kermac,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
+
+	  // beam hardening correction
+	  if (terma0 <= 0.0 || kermac0 <= 0.0)
+		nrerror("Input spectrum must not sum to zero."); 
+	  else
+		GRID_VALUE(terma,i,j,k) *= (GRID_VALUE(kermac,i,j,k)/GRID_VALUE(terma,i,j,k))
+								/(kermac0/terma0);
+	}
+	else
+	{
+		GRID_VALUE(terma,i,j,k) = 0.0;
+		GRID_VALUE(kermac,i,j,k) = 0.0;
+	}
+    return(SUCCESS);
+}

+ 117 - 117
WiscPlan-SourceCode/source-code-photon-linux/util.cpp

@@ -1,117 +1,117 @@
-/* util.c */
-/* Functions that are used for utility throughout the routines used for the C/S 
-calculation.  Most of these functions are from Numerical Recipes in C by Press. */
-
-#include "defs.h"
-
-#define NR_END 1
-#define FREE_ARG char*
-
-extern char errstr[200];  // error string that all routines have access to
-
-void nrerror(char error_text[])
-/* Numerical Recipes standard error handler */
-{
- fprintf(stderr,"Numerical Recipes run-time error...\n");
- fprintf(stderr,"%s\n",error_text);
- fprintf(stderr,"...now exiting to system...\n");
- exit(1);
-}
-
-float *fvector(int nl, int nh)
-/* allocate a float vector with subscript range v[nl..nh] */
-{
- float *v;
- v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
- if (!v) nrerror("allocation failure in fvector()");
- return v-nl+NR_END;
-}
-
-
-void free_fvector(float *v, int nl, int nh)
-/* free a float vector allocated with fvector() */
-{
- free((FREE_ARG) (v+nl-NR_END));
-}
-
-
-float **fmatrix(int nrl, int nrh, int ncl, int nch)
-/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
-{
- int i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
- float **m;
- /* allocate pointers to rows */
- m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
- if (!m) nrerror("allocation failure 1 in matrix()");
- m += NR_END;
- m -= nrl;
- /* allocate rows and set pointers to them */
- m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
- if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
- m[nrl] += NR_END;
- m[nrl] -= ncl;
- for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
- /* return pointer to array of pointers to rows */
- return m;
-}
-
-void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch)
-/* free a float matrix allocated by fmatrix() */
-{
- free((FREE_ARG) (m[nrl]+ncl-NR_END));
- free((FREE_ARG) (m+nrl-NR_END));
-}
-
-int copy_grid_geometry(FLOAT_GRID *grid_old, FLOAT_GRID *grid_new)
-// Copies geometric grid information from grid_old to grid_new
-{
-	grid_new->start.x = grid_old->start.x;
-	grid_new->start.y = grid_old->start.y;
-	grid_new->start.z = grid_old->start.z;
-
-	grid_new->inc.x = grid_old->inc.x;
-	grid_new->inc.y = grid_old->inc.y;
-	grid_new->inc.z = grid_old->inc.z;
-
-	grid_new->x_count = grid_old->x_count;
-	grid_new->y_count = grid_old->y_count;
-	grid_new->z_count = grid_old->z_count;
-
-	return(SUCCESS);
-}
-
-int binSearch(float *a, float searchnum, int M)
-/* Accepts a float array of data of length M ordered lowest to highest and a number called searchnum. 
-Returns the index of the first element of the array, a, that is less than the searchnum. 
-If the searchnum is less than a[0], then -1 is returned, and if the searchnum is greater 
-than or equal to M, then M is returned. */
-{
-    int found, mid, top, bottom;
-
-    bottom = 0;
-    top = M-1;
-
-    found = 0;  // flag that is set to 1 once the proper index is found
- 
-    // Ensure that the search parameter lies inside boundaries
-	if(searchnum >= a[top])
-		return(M); 
-	if(searchnum <= a[bottom])
-		return(-1);
-
-	while(!found)
-	{
-		mid = (top + bottom) / 2;
-		if(searchnum == a[mid])
-			found = 1;
-		else
-			if(searchnum < a[mid])
-				top = mid - 1;
-			else
-				if(searchnum > a[mid + 1])
-					bottom = mid + 1;
-				else
-					found = 1; 
-	}
-	return(mid);
-}
+/* util.c */
+/* Functions that are used for utility throughout the routines used for the C/S 
+calculation.  Most of these functions are from Numerical Recipes in C by Press. */
+
+#include "defs.h"
+
+#define NR_END 1
+#define FREE_ARG char*
+
+extern char errstr[200];  // error string that all routines have access to
+
+void nrerror(char error_text[])
+/* Numerical Recipes standard error handler */
+{
+ fprintf(stderr,"Numerical Recipes run-time error...\n");
+ fprintf(stderr,"%s\n",error_text);
+ fprintf(stderr,"...now exiting to system...\n");
+ exit(1);
+}
+
+float *fvector(int nl, int nh)
+/* allocate a float vector with subscript range v[nl..nh] */
+{
+ float *v;
+ v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
+ if (!v) nrerror("allocation failure in fvector()");
+ return v-nl+NR_END;
+}
+
+
+void free_fvector(float *v, int nl, int nh)
+/* free a float vector allocated with fvector() */
+{
+ free((FREE_ARG) (v+nl-NR_END));
+}
+
+
+float **fmatrix(int nrl, int nrh, int ncl, int nch)
+/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
+{
+ int i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
+ float **m;
+ /* allocate pointers to rows */
+ m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
+ if (!m) nrerror("allocation failure 1 in matrix()");
+ m += NR_END;
+ m -= nrl;
+ /* allocate rows and set pointers to them */
+ m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
+ if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
+ m[nrl] += NR_END;
+ m[nrl] -= ncl;
+ for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
+ /* return pointer to array of pointers to rows */
+ return m;
+}
+
+void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch)
+/* free a float matrix allocated by fmatrix() */
+{
+ free((FREE_ARG) (m[nrl]+ncl-NR_END));
+ free((FREE_ARG) (m+nrl-NR_END));
+}
+
+int copy_grid_geometry(FLOAT_GRID *grid_old, FLOAT_GRID *grid_new)
+// Copies geometric grid information from grid_old to grid_new
+{
+	grid_new->start.x = grid_old->start.x;
+	grid_new->start.y = grid_old->start.y;
+	grid_new->start.z = grid_old->start.z;
+
+	grid_new->inc.x = grid_old->inc.x;
+	grid_new->inc.y = grid_old->inc.y;
+	grid_new->inc.z = grid_old->inc.z;
+
+	grid_new->x_count = grid_old->x_count;
+	grid_new->y_count = grid_old->y_count;
+	grid_new->z_count = grid_old->z_count;
+
+	return(SUCCESS);
+}
+
+int binSearch(float *a, float searchnum, int M)
+/* Accepts a float array of data of length M ordered lowest to highest and a number called searchnum. 
+Returns the index of the first element of the array, a, that is less than the searchnum. 
+If the searchnum is less than a[0], then -1 is returned, and if the searchnum is greater 
+than or equal to M, then M is returned. */
+{
+    int found, mid, top, bottom;
+
+    bottom = 0;
+    top = M-1;
+
+    found = 0;  // flag that is set to 1 once the proper index is found
+ 
+    // Ensure that the search parameter lies inside boundaries
+	if(searchnum >= a[top])
+		return(M); 
+	if(searchnum <= a[bottom])
+		return(-1);
+
+	while(!found)
+	{
+		mid = (top + bottom) / 2;
+		if(searchnum == a[mid])
+			found = 1;
+		else
+			if(searchnum < a[mid])
+				top = mid - 1;
+			else
+				if(searchnum > a[mid + 1])
+					bottom = mid + 1;
+				else
+					found = 1; 
+	}
+	return(mid);
+}

+ 69 - 69
WiscPlanPhotonkV125/DownsampleScript/prepareCtSeries7-1-14.m

@@ -1,70 +1,70 @@
-function prepareCtSeries(indir, outdir)
-% Usage:copy and paste the line belwo in MATLAB command line; change the
-% directory and name as needed
-%   prepareCtSeries('C:\WiscPhotonkV\ratDICOMs', 'C:\WiscPhotonkV\ratDICOMs_Downsampled');
-
-% outdir = 'C:\WiscPhotonkV\ratDICOMs_2Downsampled';
-% indir = 'C:\WiscPhotonkV\ratDICOMs';
-
-
-ctvol = readCtSeries(indir);
-% reset orientation (dirty fix)
-ctvol.info.ImageOrientationPatient = [1;0;0;0;1;0];
-ctvol.info.PatientPosition = 'HFS';
-dsvol = simpleDownsampleCtVol(ctvol, [1 1 1]);
-if size(dsvol.data,1) > size(dsvol.data,2)
-    fprintf('Padding unequal dimension CT\n');
-    dsvol.data = padarray(dsvol.data, [0, size(dsvol.data,1) - size(dsvol.data,2), 0], -1000, 'post');
-elseif size(dsvol.data,1) < size(dsvol.data,2)
-    fprintf('Padding unequal dimension CT\n');
-    dsvol.data = padarray(dsvol.data, [size(dsvol.data,2) - size(dsvol.data,1), 0, 0], -1000, 'post');
-end
-writeCtVol(dsvol, outdir)
-
-function s = readCtSlice(filename)
-s.info = dicominfo(filename);
-s.data = single(dicomread(filename)) * s.info.RescaleSlope + s.info.RescaleIntercept;
-
-function ctvol = readCtSeries(indir)
-filelist = dir(indir);
-slices = arrayfun(@(x)readCtSlice(fullfile(indir, x.name)), filelist(3:end));
-[~, ix] = sort(arrayfun(@(x)x.info.ImagePositionPatient(3), slices));
-slices = slices(ix);
-
-ctvol.info = slices(1).info;
-ctvol.info.SliceThickness = slices(2).info.ImagePositionPatient(3) - slices(1).info.ImagePositionPatient(3);
-ctvol.data = cell2mat(reshape({slices.data}, [1 1 numel(slices)]));
-
-% ctinfs = arrayfun(@(x)dicominfo(fullfile(indir, x.name)), filelist(3:end), 'UniformOutput', false);
-% ctimgs = arrayfun(@(x)dicomread(fullfile(indir, x.name)), filelist(3:end), 'UniformOutput', false);
-% [~, ix] = sort(cellfun(@(x)x.ImagePositionPatient(3), ctinfs));
-% ctinfs = ctinfs(ix);
-% ctimgs = ctimgs(ix);
-
-% ctvol.info = ctinfs{1};
-% ctvol.info.SliceThickness = ctinfs{2}.ImagePositionPatient(3) - ctinfs{1}.ImagePositionPatient(3);
-% ctvol.data = cell2mat(reshape(ctimgs, [1 1 numel(ctimgs)]));
-
-function dsvol = simpleDownsampleCtVol(ctvol, dsfactor)
-meanFilter = ones(dsfactor) / prod(dsfactor);
-meanImg = imfilter(ctvol.data, meanFilter, 'same');
-dsvol.data = meanImg(1:dsfactor(1):end, 1:dsfactor(2):end, 1:dsfactor(3):end);
-
-dsvol.info = ctvol.info;
-dsvol.info.PixelSpacing = ctvol.info.PixelSpacing .* reshape(dsfactor(1:2), [], 1);
-dsvol.info.SliceThickness = ctvol.info.SliceThickness * dsfactor(3);
-
-function writeCtVol(ctvol, outdir)
-mkdir(outdir);
-% changes common to all slices
-ctvol.info.SeriesInstanceUID = dicomuid;
-ctvol.info.RescaleIntercept = min(ctvol.data(:));
-ctvol.info.RescaleSlope = (max(ctvol.data(:)) - min(ctvol.data(:))) / 65536;
-ctvol.data = uint16((ctvol.data - ctvol.info.RescaleIntercept) / ctvol.info.RescaleSlope);
-% ctvol.info
-for k = 1:size(ctvol.data, 3)
-    info = rmfield(ctvol.info, 'SliceThickness');
-    info.SOPInstanceUID = dicomuid;
-    info.ImagePositionPatient(3) = ctvol.info.ImagePositionPatient(3) + (k-1) * ctvol.info.SliceThickness;
-    dicomwrite(ctvol.data(:,:,k), fullfile(outdir, sprintf('CT.%s.%d.dcm', info.SeriesInstanceUID, k)), info, 'CreateMode', 'copy');
+function prepareCtSeries(indir, outdir)
+% Usage:copy and paste the line belwo in MATLAB command line; change the
+% directory and name as needed
+%   prepareCtSeries('C:\WiscPhotonkV\ratDICOMs', 'C:\WiscPhotonkV\ratDICOMs_Downsampled');
+
+% outdir = 'C:\WiscPhotonkV\ratDICOMs_2Downsampled';
+% indir = 'C:\WiscPhotonkV\ratDICOMs';
+
+
+ctvol = readCtSeries(indir);
+% reset orientation (dirty fix)
+ctvol.info.ImageOrientationPatient = [1;0;0;0;1;0];
+ctvol.info.PatientPosition = 'HFS';
+dsvol = simpleDownsampleCtVol(ctvol, [1 1 1]);
+if size(dsvol.data,1) > size(dsvol.data,2)
+    fprintf('Padding unequal dimension CT\n');
+    dsvol.data = padarray(dsvol.data, [0, size(dsvol.data,1) - size(dsvol.data,2), 0], -1000, 'post');
+elseif size(dsvol.data,1) < size(dsvol.data,2)
+    fprintf('Padding unequal dimension CT\n');
+    dsvol.data = padarray(dsvol.data, [size(dsvol.data,2) - size(dsvol.data,1), 0, 0], -1000, 'post');
+end
+writeCtVol(dsvol, outdir)
+
+function s = readCtSlice(filename)
+s.info = dicominfo(filename);
+s.data = single(dicomread(filename)) * s.info.RescaleSlope + s.info.RescaleIntercept;
+
+function ctvol = readCtSeries(indir)
+filelist = dir(indir);
+slices = arrayfun(@(x)readCtSlice(fullfile(indir, x.name)), filelist(3:end));
+[~, ix] = sort(arrayfun(@(x)x.info.ImagePositionPatient(3), slices));
+slices = slices(ix);
+
+ctvol.info = slices(1).info;
+ctvol.info.SliceThickness = slices(2).info.ImagePositionPatient(3) - slices(1).info.ImagePositionPatient(3);
+ctvol.data = cell2mat(reshape({slices.data}, [1 1 numel(slices)]));
+
+% ctinfs = arrayfun(@(x)dicominfo(fullfile(indir, x.name)), filelist(3:end), 'UniformOutput', false);
+% ctimgs = arrayfun(@(x)dicomread(fullfile(indir, x.name)), filelist(3:end), 'UniformOutput', false);
+% [~, ix] = sort(cellfun(@(x)x.ImagePositionPatient(3), ctinfs));
+% ctinfs = ctinfs(ix);
+% ctimgs = ctimgs(ix);
+
+% ctvol.info = ctinfs{1};
+% ctvol.info.SliceThickness = ctinfs{2}.ImagePositionPatient(3) - ctinfs{1}.ImagePositionPatient(3);
+% ctvol.data = cell2mat(reshape(ctimgs, [1 1 numel(ctimgs)]));
+
+function dsvol = simpleDownsampleCtVol(ctvol, dsfactor)
+meanFilter = ones(dsfactor) / prod(dsfactor);
+meanImg = imfilter(ctvol.data, meanFilter, 'same');
+dsvol.data = meanImg(1:dsfactor(1):end, 1:dsfactor(2):end, 1:dsfactor(3):end);
+
+dsvol.info = ctvol.info;
+dsvol.info.PixelSpacing = ctvol.info.PixelSpacing .* reshape(dsfactor(1:2), [], 1);
+dsvol.info.SliceThickness = ctvol.info.SliceThickness * dsfactor(3);
+
+function writeCtVol(ctvol, outdir)
+mkdir(outdir);
+% changes common to all slices
+ctvol.info.SeriesInstanceUID = dicomuid;
+ctvol.info.RescaleIntercept = min(ctvol.data(:));
+ctvol.info.RescaleSlope = (max(ctvol.data(:)) - min(ctvol.data(:))) / 65536;
+ctvol.data = uint16((ctvol.data - ctvol.info.RescaleIntercept) / ctvol.info.RescaleSlope);
+% ctvol.info
+for k = 1:size(ctvol.data, 3)
+    info = rmfield(ctvol.info, 'SliceThickness');
+    info.SOPInstanceUID = dicomuid;
+    info.ImagePositionPatient(3) = ctvol.info.ImagePositionPatient(3) + (k-1) * ctvol.info.SliceThickness;
+    dicomwrite(ctvol.data(:,:,k), fullfile(outdir, sprintf('CT.%s.%d.dcm', info.SeriesInstanceUID, k)), info, 'CreateMode', 'copy');
 end

+ 22 - 22
WiscPlanPhotonkV125/matlab_frontend/CT2dens.m

@@ -1,22 +1,22 @@
-function dens = CT2dens(CTimage,imgtype)
-% converts the CT image to physical density based on one of the IVDT tables
-% listed below.
-
-GE_LS_PD_hu = [-1024 -689 -518 -92 -50 0 73 214 225 450 812 1201]; 
-GE_LS_PD_dens = [0.0 0.29 0.46 0.947 0.976 1 1.094 1.144 1.153 1.335 1.561 1.824];
-
-% MVCT_hu = [-1024 -682 -494 -54 44 103 118 132 296 463 717 2584];
-% MVCT_dens = [0.0 0.3 0.41 0.92 1 1.11 1.14 1.16 1.39 1.56 1.82 4.59];
-
-MVCT_hu = [-1024 -662 -490 -33 2 33 93 107 144 148 314 722 2588];
-MVCT_dens = [0 0.29 0.46 0.947 0.976 1 1.051 1.094 1.144 1.153 1.335 1.824 4.59];
-
-if strcmp(imgtype,'pinn') || strcmp(imgtype,'tomo')
-    GE_hu = GE_LS_PD_hu + 1024;
-    dens = interp1(GE_hu,GE_LS_PD_dens,double(CTimage),'linear','extrap');
-elseif strcmp(imgtype,'mvct') || strcmp(imgtype,'reg')
-    mvct_hu = MVCT_hu + 1024;
-    dens = interp1(mvct_hu,MVCT_dens,double(CTimage),'linear','extrap');
-else
-    fprintf('Error: Could not determine density values from CT image.\n');
-end
+function dens = CT2dens(CTimage,imgtype)
+% converts the CT image to physical density based on one of the IVDT tables
+% listed below.
+
+GE_LS_PD_hu = [-1024 -689 -518 -92 -50 0 73 214 225 450 812 1201]; 
+GE_LS_PD_dens = [0.0 0.29 0.46 0.947 0.976 1 1.094 1.144 1.153 1.335 1.561 1.824];
+
+% MVCT_hu = [-1024 -682 -494 -54 44 103 118 132 296 463 717 2584];
+% MVCT_dens = [0.0 0.3 0.41 0.92 1 1.11 1.14 1.16 1.39 1.56 1.82 4.59];
+
+MVCT_hu = [-1024 -662 -490 -33 2 33 93 107 144 148 314 722 2588];
+MVCT_dens = [0 0.29 0.46 0.947 0.976 1 1.051 1.094 1.144 1.153 1.335 1.824 4.59];
+
+if strcmp(imgtype,'pinn') || strcmp(imgtype,'tomo')
+    GE_hu = GE_LS_PD_hu + 1024;
+    dens = interp1(GE_hu,GE_LS_PD_dens,double(CTimage),'linear','extrap');
+elseif strcmp(imgtype,'mvct') || strcmp(imgtype,'reg')
+    mvct_hu = MVCT_hu + 1024;
+    dens = interp1(mvct_hu,MVCT_dens,double(CTimage),'linear','extrap');
+else
+    fprintf('Error: Could not determine density values from CT image.\n');
+end

+ 17 - 17
WiscPlanPhotonkV125/matlab_frontend/NLP_getFullDose.m

@@ -1,18 +1,18 @@
-
-
-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 '\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 '\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

+ 3 - 2
WiscPlanPhotonkV125/matlab_frontend/NLP_optimizer_v3.m

@@ -303,12 +303,12 @@ function penalty = eval_f(x, optGoal, nrs_i, sss_i, rgs_i, bLet_idx)
                 % 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) + numel(temp1)* any(temp1));
+                d_penalty = 1.0e0 * (sum(temp1.*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.0e0 * (sum(temp1) + numel(temp1)* any(temp1));
+                d_penalty = 1.0e0 * (sum(temp1.*temp1+temp1) + 1.0e3* sum(temp1>0)/numel(temp1));
             case 'LeastSquare'
                 % penalize with sum of squares any deviation from target
                 % dose
@@ -439,6 +439,7 @@ function optGoal = make_robust_optGoal(optGoal, RO_params, beamlets);
     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

+ 294 - 294
WiscPlanPhotonkV125/matlab_frontend/RDX/loadOptResults.m

@@ -1,294 +1,294 @@
-function [optSettings, optResults] = loadOptResults(varargin)
-% Loads the weights and dose distribution corresponding to a given input
-% filename.  The input filename has the following format:
-%bemal
-% [S,R] = loadOptResults(optimizerFolder,inputFileName) loads all of the
-% files from
-%        the linlsq optimization associated with inputFileName.  DVHs are
-%        calculated for all of the associated dose files.
-% [S,R] = loadOptResults(optimizerFolder,inputFileName,'last') loads only the last
-%        dose and beamlet weights files, and calculates the DVHs for each
-%        tissue type only for those files.
-%
-% inputFileName has the following format:
-% Niterations
-% 2000
-% Nperbatch
-% 50
-% prescription_filename
-% input0/prescription.txt
-% initial_beam_weights_filename
-% input0/init_beam_weights.img
-% beamlet_header_file
-% beamletbatches0/beamlet_header.txt
-% dose_batch_base_name
-% output0/dosebatch
-% dose_batch_extension
-% img
-% weight_batch_base_name
-% output0/weightbatch
-% weight_batch_extension
-% img
-% obj_func_name
-% output0/objFunc.img
-%
-% Where all paths are relative to the directory containing the
-% inputFileName argument.
-%
-% RTF 1/6/07
-
-warning off;
-
-% constants
-Ndvhbins = 1000; % number of bins to use for the cumulative DVH calculation
-
-if length(varargin) == 1
-    error('Too few input arguments');
-elseif length(varargin) == 2
-    optimizerFolder = varargin{1};
-    optInputFile = varargin{2};
-    readAllOutputFiles = 1;
-elseif length(varargin) == 3
-    optimizerFolder = varargin{1};
-    optInputFile = varargin{2};
-    if strcmp(deblank(lower(varargin{3})),'last')
-        readAllOutputFiles = 0;
-    else
-        readAllOutputFiles = 1;
-    end
-else
-    error('Too many input arguments');
-end
-
-% Extract the folder name that contains the input file
-inputFileNameRev = fliplr(optInputFile);  % flip the input filename around
-% pop off the reversed file name
-[fileNameRev,inputFolderRev] = strtok(inputFileNameRev,{'/','\'});
-inputFolder = fliplr(inputFolderRev);
-if isempty(inputFolder)  % input folder is the current folder
-    inputFolder = [pwd '/'];
-end
-
-% get the patient header
-headerRev = fliplr(optimizerFolder);
-% pop off patient name
-[headerNameRev,optFolderRev] = strtok(headerRev,{'/','\'});
-patientHeader = fliplr(headerNameRev);
-
-[optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile);  % load the optimization settings
-
-if numel(missingInfo)
-    fprintf('Information missing from optimization files:\n');
-    for k=1:numel(missingInfo)
-        fprintf('%s\n',missingInfo{k});
-    end
-    fprintf('\n');
-end
-
-% find the dose grid size
-if isfield(optSettings,'beamletInfo') && isfield(optSettings.beamletInfo,'beamletDim')
-    siz = optSettings.beamletInfo.beamletDim;
-elseif isfield(optSettings,'prescInfo') && isfield(optSettings.prescInfo,'presc') ...
-        && isfield(optSettings.prescInfo.presc,'siz')
-    siz = optSettings.prescInfo.presc.siz;
-else
-    siz = [];
-end
-
-if isfield(optSettings,'optInfo') && isfield(optSettings.optInfo,'Niterations') ...
-        && isfield(optSettings.optInfo,'Nperbatch') && isfield(optSettings.optInfo,'outputFolder')...
-        && isfield(optSettings.optInfo,'doseBatchBaseName') && isfield(optSettings.optInfo,'doseBatchExtension')...
-        && isfield(optSettings.optInfo,'weightBatchBaseName') && isfield(optSettings.optInfo,'weightBatchExtension')
-    % find which dose and weights files are present
-    % must 'ls' the opt_output folder.  One file contains the objective
-    % function, while the others are either dose batches or weight batch
-    % files.
-
-    % xmo: MUST use mod verision of ls in *nix
-    atmp = lsl(optSettings.optInfo.outputFolder);
-    btmp = size(atmp);
-    if btmp(1)>4
-        Nbatches = ceil((btmp(1) - 3)/2);
-    elseif btmp(1)==4
-        Nbatches = 1;
-    else
-        error('No dose batches found');
-    end
-    % Nbatches = ceil(optSettings.optInfo.Niterations/optSettings.optInfo.Nperbatch)+1;  % extra '1' is for initial guess
-    doseFileNames = cell(1,Nbatches);
-    doseFileExist = zeros(1,Nbatches);  % flags to test for existence of files
-    weightFileNames = cell(1,Nbatches);
-    weightFileExist = zeros(1,Nbatches);
-
-    % Dave's new implementation
-    k=0;
-    for t=1:btmp(1)
-        if ~isempty(findstr(optSettings.optInfo.doseBatchBaseName,mat2str(atmp(t,:))));
-            k=k+1;
-            batchname = strtrim(strrep(mat2str(atmp(t,:)),'''',''));
-            str = strrep(strtok(batchname,'.'),optSettings.optInfo.doseBatchBaseName,'');
-            batchNames{k} = str;
-            doseFileNames{k} = [optSettings.optInfo.outputFolder '/' ...
-                strtrim(strrep(mat2str(atmp(t,:)),'''','')) ];
-            weightFileNames{k} = strrep(doseFileNames{k},optSettings.optInfo.doseBatchBaseName,optSettings.optInfo.weightBatchBaseName);
-        end
-    end
-
-    for k=1:Nbatches
-        % ryans implementation
-        %         doseFileNames{k} = [optSettings.optInfo.outputFolder '/' ...
-        %             optSettings.optInfo.doseBatchBaseName ...
-        %             num2str((k-1)*optSettings.optInfo.Nperbatch) '.' ...
-        %             optSettings.optInfo.doseBatchExtension];
-        %         weightFileNames{k} = [optSettings.optInfo.outputFolder '/' ...
-        %             optSettings.optInfo.weightBatchBaseName ...
-        %             num2str((k-1)*optSettings.optInfo.Nperbatch) '.' ...
-        %             optSettings.optInfo.weightBatchExtension];
-
-        fid = fopen(doseFileNames{k},'rb');
-        if fid == -1  % batch file doesn't exist
-            doseFileExist(k) = 0;
-        else
-            fclose(fid);
-            doseFileExist(k) = 1;  % mark that file exists
-        end
-
-        fid = fopen(weightFileNames{k},'rb');
-        if fid == -1  % batch file doesn't exist
-            weightFileExist(k) = 0;
-        else
-            fclose(fid);
-            weightFileExist(k) = 1;  % mark that file exists
-        end
-    end
-    optResults = [];
-
-    % assign names to optResults structure array
-    optResults.batchNames = batchNames;
-
-    if readAllOutputFiles == 1
-        optResults.dose = {};
-        optResults.weights = {};
-        % read in the appropriate dose files
-        for k=1:length(doseFileNames)
-            if doseFileExist(k) == 1
-                fid = fopen(doseFileNames{k},'rb');
-                dose = fread(fid,'float=>float');
-                fclose(fid);
-                if numel(siz) == 3 % reshape dose if siz definedre
-                    dose = reshape(dose,siz);
-                end
-                optResults.dose{k} = dose;
-            end
-        end
-
-        % read in the appropriate weights files
-        for k=1:length(weightFileNames)
-            if weightFileExist(k) == 1
-                fid = fopen(weightFileNames{k},'rb');
-                weights = fread(fid,'float=>float');
-                fclose(fid);
-                optResults.weights{k} = weights;
-            end
-        end
-    else  % read in only the last dose and weights files
-        for k=length(doseFileNames):-1:0
-            if doseFileExist(k) == 1  % found last dose file
-                break;
-            end
-        end
-
-        fid = fopen(doseFileNames{k},'rb');
-        dose = fread(fid,'float=>float');
-        fclose(fid);
-        if numel(siz) == 3
-            dose = reshape(dose,siz);
-        end
-        optResults.dose = dose;
-
-        fid = fopen(weightFileNames{k},'rb');
-        weights = fread(fid,'float=>float');
-        fclose(fid);
-        optResults.weights = weights;
-    end
-
-    % load DVH information
-    if isfield(optSettings,'prescInfo') & isfield(optSettings.prescInfo,'presc') ...
-            & isfield(optSettings.prescInfo.presc,'tissue') ...
-            & isfield(optSettings.prescInfo.presc.tissue,'ind')
-        optResults.presc = optSettings.prescInfo.presc;
-
-        if readAllOutputFiles == 1
-            % calculate a max dose vector
-            for k=1:length(optResults.dose)
-                dmax(k) = 1.1*max(optResults.dose{k}(:));
-            end
-            % calculate DVHs for each tissue, for each batch number
-            for m=1:length(optResults.presc.tissue)
-                tissMask = zeros(optResults.presc.siz,'int8');
-                tissMask(optResults.presc.tissue(m).ind) = 1;
-                for k=1:length(optResults.dose)
-                    dvhbins = [0:Ndvhbins-1]*dmax(k)/Ndvhbins;
-                    optResults.presc.tissue(m).dvhbins{k} = dvhbins;
-                    optResults.presc.tissue(m).dvh{k} ...
-                        = single(dvh(optResults.dose{k},tissMask,dvhbins))';
-                end
-            end
-        else
-            dmax = 1.1*max(optResults.dose(:));
-            % calculate DVHs and EVHs for each tissue
-            for m=1:length(optResults.presc.tissue)
-                tissMask = zeros(optResults.presc.siz,'int8');
-                tissMask(optResults.presc.tissue(m).ind) = 1;
-                dvhbins = [0:Ndvhbins-1]*dmax/Ndvhbins;
-                optResults.presc.tissue(m).dvhbins = dvhbins;
-                optResults.presc.tissue(m).dvh ...
-                    = single(dvh(optResults.dose,tissMask,dvhbins))';
-                % calculate the EDVH if presc is non-zero
-                if sum(optResults.presc.tissue(m).dMinus) > 0
-                    % extract dose voxels
-                    doseRatio = zeros(optResults.presc.siz);
-                    doseRatio(optResults.presc.tissue(m).ind) = ...
-                        optResults.dose(optResults.presc.tissue(m).ind)./ ...
-                        optResults.presc.tissue(m).dMinus*100;
-                    % remove and Infs and NaNs
-                    doseRatio(isinf(doseRatio)) = 0;
-                    doseRatio(isnan(doseRatio)) = 0;
-                    % calculate edvh
-                    edvhbins = [0:Ndvhbins-1]*max(doseRatio(:))/Ndvhbins;
-                    optResults.presc.tissue(m).edvhbins = edvhbins;
-                    optResults.presc.tissue(m).edvh = ...
-                        single(dvh(doseRatio,tissMask,edvhbins))';
-                end
-            end
-        end
-    else
-        fprintf('Unable to load DVH information: not enough prescription fields available.\n\n');
-    end
-else
-    fprintf('Unable to load beamlet weights and dose distributions: not enough fields available.\n\n');
-end
-
-% load the objective function
-if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'outputFolder') ...
-        & isfield(optSettings.optInfo,'objFuncFileName')
-    fid = fopen([optSettings.optInfo.outputFolder '/' optSettings.optInfo.objFuncFileName],'rb');
-    if fid ~= -1
-        optResults.objFunc = fread(fid,'float=>float');
-        fclose(fid);
-    end
-else
-    fprintf('Unable to load objective function file: not enough fields available.');
-end
-
-% sort all the loaded cell arrays based on batchNames
-batch_indices = cellfun(@str2num, optResults.batchNames);
-[delme perm_vector] = sort(batch_indices);
-optResults.batchNames = optResults.batchNames(perm_vector);
-optResults.dose = optResults.dose(perm_vector);
-optResults.weights = optResults.weights(perm_vector);
-
-% save file to matlab_files folder
-savefile = fullfile(optimizerFolder, 'matlab_files', 'optResults.mat');
-save(savefile,'optSettings','optResults');
-
+function [optSettings, optResults] = loadOptResults(varargin)
+% Loads the weights and dose distribution corresponding to a given input
+% filename.  The input filename has the following format:
+%bemal
+% [S,R] = loadOptResults(optimizerFolder,inputFileName) loads all of the
+% files from
+%        the linlsq optimization associated with inputFileName.  DVHs are
+%        calculated for all of the associated dose files.
+% [S,R] = loadOptResults(optimizerFolder,inputFileName,'last') loads only the last
+%        dose and beamlet weights files, and calculates the DVHs for each
+%        tissue type only for those files.
+%
+% inputFileName has the following format:
+% Niterations
+% 2000
+% Nperbatch
+% 50
+% prescription_filename
+% input0/prescription.txt
+% initial_beam_weights_filename
+% input0/init_beam_weights.img
+% beamlet_header_file
+% beamletbatches0/beamlet_header.txt
+% dose_batch_base_name
+% output0/dosebatch
+% dose_batch_extension
+% img
+% weight_batch_base_name
+% output0/weightbatch
+% weight_batch_extension
+% img
+% obj_func_name
+% output0/objFunc.img
+%
+% Where all paths are relative to the directory containing the
+% inputFileName argument.
+%
+% RTF 1/6/07
+
+warning off;
+
+% constants
+Ndvhbins = 1000; % number of bins to use for the cumulative DVH calculation
+
+if length(varargin) == 1
+    error('Too few input arguments');
+elseif length(varargin) == 2
+    optimizerFolder = varargin{1};
+    optInputFile = varargin{2};
+    readAllOutputFiles = 1;
+elseif length(varargin) == 3
+    optimizerFolder = varargin{1};
+    optInputFile = varargin{2};
+    if strcmp(deblank(lower(varargin{3})),'last')
+        readAllOutputFiles = 0;
+    else
+        readAllOutputFiles = 1;
+    end
+else
+    error('Too many input arguments');
+end
+
+% Extract the folder name that contains the input file
+inputFileNameRev = fliplr(optInputFile);  % flip the input filename around
+% pop off the reversed file name
+[fileNameRev,inputFolderRev] = strtok(inputFileNameRev,{'/','\'});
+inputFolder = fliplr(inputFolderRev);
+if isempty(inputFolder)  % input folder is the current folder
+    inputFolder = [pwd '/'];
+end
+
+% get the patient header
+headerRev = fliplr(optimizerFolder);
+% pop off patient name
+[headerNameRev,optFolderRev] = strtok(headerRev,{'/','\'});
+patientHeader = fliplr(headerNameRev);
+
+[optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile);  % load the optimization settings
+
+if numel(missingInfo)
+    fprintf('Information missing from optimization files:\n');
+    for k=1:numel(missingInfo)
+        fprintf('%s\n',missingInfo{k});
+    end
+    fprintf('\n');
+end
+
+% find the dose grid size
+if isfield(optSettings,'beamletInfo') && isfield(optSettings.beamletInfo,'beamletDim')
+    siz = optSettings.beamletInfo.beamletDim;
+elseif isfield(optSettings,'prescInfo') && isfield(optSettings.prescInfo,'presc') ...
+        && isfield(optSettings.prescInfo.presc,'siz')
+    siz = optSettings.prescInfo.presc.siz;
+else
+    siz = [];
+end
+
+if isfield(optSettings,'optInfo') && isfield(optSettings.optInfo,'Niterations') ...
+        && isfield(optSettings.optInfo,'Nperbatch') && isfield(optSettings.optInfo,'outputFolder')...
+        && isfield(optSettings.optInfo,'doseBatchBaseName') && isfield(optSettings.optInfo,'doseBatchExtension')...
+        && isfield(optSettings.optInfo,'weightBatchBaseName') && isfield(optSettings.optInfo,'weightBatchExtension')
+    % find which dose and weights files are present
+    % must 'ls' the opt_output folder.  One file contains the objective
+    % function, while the others are either dose batches or weight batch
+    % files.
+
+    % xmo: MUST use mod verision of ls in *nix
+    atmp = lsl(optSettings.optInfo.outputFolder);
+    btmp = size(atmp);
+    if btmp(1)>4
+        Nbatches = ceil((btmp(1) - 3)/2);
+    elseif btmp(1)==4
+        Nbatches = 1;
+    else
+        error('No dose batches found');
+    end
+    % Nbatches = ceil(optSettings.optInfo.Niterations/optSettings.optInfo.Nperbatch)+1;  % extra '1' is for initial guess
+    doseFileNames = cell(1,Nbatches);
+    doseFileExist = zeros(1,Nbatches);  % flags to test for existence of files
+    weightFileNames = cell(1,Nbatches);
+    weightFileExist = zeros(1,Nbatches);
+
+    % Dave's new implementation
+    k=0;
+    for t=1:btmp(1)
+        if ~isempty(findstr(optSettings.optInfo.doseBatchBaseName,mat2str(atmp(t,:))));
+            k=k+1;
+            batchname = strtrim(strrep(mat2str(atmp(t,:)),'''',''));
+            str = strrep(strtok(batchname,'.'),optSettings.optInfo.doseBatchBaseName,'');
+            batchNames{k} = str;
+            doseFileNames{k} = [optSettings.optInfo.outputFolder '/' ...
+                strtrim(strrep(mat2str(atmp(t,:)),'''','')) ];
+            weightFileNames{k} = strrep(doseFileNames{k},optSettings.optInfo.doseBatchBaseName,optSettings.optInfo.weightBatchBaseName);
+        end
+    end
+
+    for k=1:Nbatches
+        % ryans implementation
+        %         doseFileNames{k} = [optSettings.optInfo.outputFolder '/' ...
+        %             optSettings.optInfo.doseBatchBaseName ...
+        %             num2str((k-1)*optSettings.optInfo.Nperbatch) '.' ...
+        %             optSettings.optInfo.doseBatchExtension];
+        %         weightFileNames{k} = [optSettings.optInfo.outputFolder '/' ...
+        %             optSettings.optInfo.weightBatchBaseName ...
+        %             num2str((k-1)*optSettings.optInfo.Nperbatch) '.' ...
+        %             optSettings.optInfo.weightBatchExtension];
+
+        fid = fopen(doseFileNames{k},'rb');
+        if fid == -1  % batch file doesn't exist
+            doseFileExist(k) = 0;
+        else
+            fclose(fid);
+            doseFileExist(k) = 1;  % mark that file exists
+        end
+
+        fid = fopen(weightFileNames{k},'rb');
+        if fid == -1  % batch file doesn't exist
+            weightFileExist(k) = 0;
+        else
+            fclose(fid);
+            weightFileExist(k) = 1;  % mark that file exists
+        end
+    end
+    optResults = [];
+
+    % assign names to optResults structure array
+    optResults.batchNames = batchNames;
+
+    if readAllOutputFiles == 1
+        optResults.dose = {};
+        optResults.weights = {};
+        % read in the appropriate dose files
+        for k=1:length(doseFileNames)
+            if doseFileExist(k) == 1
+                fid = fopen(doseFileNames{k},'rb');
+                dose = fread(fid,'float=>float');
+                fclose(fid);
+                if numel(siz) == 3 % reshape dose if siz definedre
+                    dose = reshape(dose,siz);
+                end
+                optResults.dose{k} = dose;
+            end
+        end
+
+        % read in the appropriate weights files
+        for k=1:length(weightFileNames)
+            if weightFileExist(k) == 1
+                fid = fopen(weightFileNames{k},'rb');
+                weights = fread(fid,'float=>float');
+                fclose(fid);
+                optResults.weights{k} = weights;
+            end
+        end
+    else  % read in only the last dose and weights files
+        for k=length(doseFileNames):-1:0
+            if doseFileExist(k) == 1  % found last dose file
+                break;
+            end
+        end
+
+        fid = fopen(doseFileNames{k},'rb');
+        dose = fread(fid,'float=>float');
+        fclose(fid);
+        if numel(siz) == 3
+            dose = reshape(dose,siz);
+        end
+        optResults.dose = dose;
+
+        fid = fopen(weightFileNames{k},'rb');
+        weights = fread(fid,'float=>float');
+        fclose(fid);
+        optResults.weights = weights;
+    end
+
+    % load DVH information
+    if isfield(optSettings,'prescInfo') & isfield(optSettings.prescInfo,'presc') ...
+            & isfield(optSettings.prescInfo.presc,'tissue') ...
+            & isfield(optSettings.prescInfo.presc.tissue,'ind')
+        optResults.presc = optSettings.prescInfo.presc;
+
+        if readAllOutputFiles == 1
+            % calculate a max dose vector
+            for k=1:length(optResults.dose)
+                dmax(k) = 1.1*max(optResults.dose{k}(:));
+            end
+            % calculate DVHs for each tissue, for each batch number
+            for m=1:length(optResults.presc.tissue)
+                tissMask = zeros(optResults.presc.siz,'int8');
+                tissMask(optResults.presc.tissue(m).ind) = 1;
+                for k=1:length(optResults.dose)
+                    dvhbins = [0:Ndvhbins-1]*dmax(k)/Ndvhbins;
+                    optResults.presc.tissue(m).dvhbins{k} = dvhbins;
+                    optResults.presc.tissue(m).dvh{k} ...
+                        = single(dvh(optResults.dose{k},tissMask,dvhbins))';
+                end
+            end
+        else
+            dmax = 1.1*max(optResults.dose(:));
+            % calculate DVHs and EVHs for each tissue
+            for m=1:length(optResults.presc.tissue)
+                tissMask = zeros(optResults.presc.siz,'int8');
+                tissMask(optResults.presc.tissue(m).ind) = 1;
+                dvhbins = [0:Ndvhbins-1]*dmax/Ndvhbins;
+                optResults.presc.tissue(m).dvhbins = dvhbins;
+                optResults.presc.tissue(m).dvh ...
+                    = single(dvh(optResults.dose,tissMask,dvhbins))';
+                % calculate the EDVH if presc is non-zero
+                if sum(optResults.presc.tissue(m).dMinus) > 0
+                    % extract dose voxels
+                    doseRatio = zeros(optResults.presc.siz);
+                    doseRatio(optResults.presc.tissue(m).ind) = ...
+                        optResults.dose(optResults.presc.tissue(m).ind)./ ...
+                        optResults.presc.tissue(m).dMinus*100;
+                    % remove and Infs and NaNs
+                    doseRatio(isinf(doseRatio)) = 0;
+                    doseRatio(isnan(doseRatio)) = 0;
+                    % calculate edvh
+                    edvhbins = [0:Ndvhbins-1]*max(doseRatio(:))/Ndvhbins;
+                    optResults.presc.tissue(m).edvhbins = edvhbins;
+                    optResults.presc.tissue(m).edvh = ...
+                        single(dvh(doseRatio,tissMask,edvhbins))';
+                end
+            end
+        end
+    else
+        fprintf('Unable to load DVH information: not enough prescription fields available.\n\n');
+    end
+else
+    fprintf('Unable to load beamlet weights and dose distributions: not enough fields available.\n\n');
+end
+
+% load the objective function
+if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'outputFolder') ...
+        & isfield(optSettings.optInfo,'objFuncFileName')
+    fid = fopen([optSettings.optInfo.outputFolder '/' optSettings.optInfo.objFuncFileName],'rb');
+    if fid ~= -1
+        optResults.objFunc = fread(fid,'float=>float');
+        fclose(fid);
+    end
+else
+    fprintf('Unable to load objective function file: not enough fields available.');
+end
+
+% sort all the loaded cell arrays based on batchNames
+batch_indices = cellfun(@str2num, optResults.batchNames);
+[delme perm_vector] = sort(batch_indices);
+optResults.batchNames = optResults.batchNames(perm_vector);
+optResults.dose = optResults.dose(perm_vector);
+optResults.weights = optResults.weights(perm_vector);
+
+% save file to matlab_files folder
+savefile = fullfile(optimizerFolder, 'matlab_files', 'optResults.mat');
+save(savefile,'optSettings','optResults');
+

+ 266 - 266
WiscPlanPhotonkV125/matlab_frontend/RDX/loadOptSettings.m

@@ -1,266 +1,266 @@
-function [optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile)
-% [optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile) 
-% loads the linear least squares optimization settings from the 
-% optimization input file into  a Matlab structure.  Beamlets are not 
-% loaded, but everything else is. If any inconsistancies are found, such as
-% 
-% missing fields, etc, the inconsistancies are stored in the cell array, 
-% missingInfo.  The optInputFile must be that absolute path of the input 
-% file.
-%
-% RTF 1/19/07
-
-% initialize outputs
-optSettings = [];
-missingInfo = {};
-
-% Open the optimization input file
-fid = fopen([optimizerFolder '/' optInputFile],'r');
-
-if fid == -1
-    error(['Unable to open ' optimizerFolder '/' optInputFile]);
-end
-
-optSettings = [];  % optimization settings structure
-
-% read the file into a cell array, line-by-line
-fileText = {};
-while 1
-    tline = fgetl(fid);
-    if ~ischar(tline)
-        break; 
-    end
-    fileText{end+1} = tline;
-end
-fclose(fid);
-
-% Extract the folder name that contains the input file
-inputFileNameRev = fliplr(optInputFile);  % flip the input filename around
-% pop off the reversed file name
-[fileNameRev,inputFolderRev] = strtok(inputFileNameRev,{'/','\'});
-inputFolder = fliplr(inputFolderRev);
-if isempty(inputFolder)  % input folder is the current folder
-    inputFolder = pwd;
-end
-
-optSettings.optInfo.inputFile = fliplr(fileNameRev);
-%                 Field Name              subfield            conversion  function
-fieldFunctions = {'Niterations'           'optInfo'           'str2num'            
-                  'Nperbatch'             'optInfo'           'str2num'            
-                  'prescFile'             'prescInfo'         ''                   
-                  'initBeamWeightFile'    'initialGuessInfo'  ''                   
-                  'beamletHeaderFileName' 'beamletInfo'       ''                   
-                  'doseBatchBaseName'     'optInfo'           ''                   
-                  'doseBatchExtension'    'optInfo'           ''                   
-                  'weightBatchBaseName'   'optInfo'           ''                   
-                  'weightBatchExtension'  'optInfo'           ''                   
-                  'objFuncFileName'       'optInfo'           ''
-                  'modFactor'             'optInfo'           'str2num'
-                  'calcInitialGuessFlag'  'initialGuessInfo'  'str2num'};
-
-% search for key fields
-for k=1:length(fileText)
-    for m=1:size(fieldFunctions,1)
-        if strcmp(deblank(fileText{k}),fieldFunctions{m,1})
-            eval(['optSettings.' fieldFunctions{m,2} '.' fieldFunctions{m,1} ' = ' fieldFunctions{m,3} '(''' fileText{k+1} ''');']);
-        end
-    end
-end
-
-% search for missing fields
-for k=1:size(fieldFunctions,1)
-    if ~isfield(optSettings,fieldFunctions{k,2}) | ~eval(['isfield(optSettings.' fieldFunctions{k,2} ',''' fieldFunctions{k,1} ''')'])
-        missingInfo{end+1} = ['Missing: optSettings.' fieldFunctions{k,2} '.' fieldFunctions{k,1}];
-    end
-end
-
-% find the output folder
-if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'doseBatchBaseName')
-    doseBatchBaseNameRev = fliplr(optSettings.optInfo.doseBatchBaseName);
-    [fileNameRev,outputFolderRev] = strtok(doseBatchBaseNameRev,{'/','\'});
-    optSettings.optInfo.outputFolder = fliplr(outputFolderRev);
-    optSettings.optInfo.outputFolder(:,end) = [];  % delete last character, which is a '/' or '\'
-    optSettings.optInfo.doseBatchBaseName = fliplr(fileNameRev);
-end
-
-% get the weightBatchBaseName
-if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'weightBatchBaseName')
-    doseBatchBaseNameRev = fliplr(optSettings.optInfo.weightBatchBaseName);
-    [fileNameRev,outputFolderRev] = strtok(doseBatchBaseNameRev,{'/','\'});
-    optSettings.optInfo.weightBatchBaseName = fliplr(fileNameRev);
-end
-
-% find the input folder
-if isfield(optSettings,'prescInfo') & isfield(optSettings.prescInfo,'prescFile')
-    prescFileRev = fliplr(optSettings.prescInfo.prescFile);
-    [fileNameRev,inputFolderRev] = strtok(prescFileRev,{'/','\'});
-    optSettings.optInfo.inputFolder = fliplr(inputFolderRev);
-    optSettings.optInfo.inputFolder(:,end) = [];  % delete last character, which is a '/' or '\'
-    optSettings.prescInfo.prescFile = fliplr(fileNameRev);
-end
-
-% get the initial beam weights file name
-if isfield(optSettings,'initialGuessInfo') & isfield(optSettings.initialGuessInfo,'initBeamWeightFile')
-    initBeamWeightFileRev = fliplr(optSettings.initialGuessInfo.initBeamWeightFile);
-    [fileNameRev,inputFolderRev] = strtok(initBeamWeightFileRev,{'/','\'});
-    optSettings.initialGuessInfo.initBeamWeightFile = fliplr(fileNameRev);
-end
-
-% trim off the objective function filename
-if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'objFuncFileName')
-    prescFileRev = fliplr(optSettings.optInfo.objFuncFileName);
-    [fileNameRev,inputFolderRev] = strtok(prescFileRev,{'/','\'});
-    optSettings.optInfo.objFuncFileName = fliplr(fileNameRev);
-end
-
-% get the beamletFolder and beamletHeader
-if isfield(optSettings,'beamletInfo') & isfield(optSettings.beamletInfo,'beamletHeaderFileName')
-    beamletHeaderFileNameRev = fliplr(optSettings.beamletInfo.beamletHeaderFileName);
-    [fileNameRev,beamletFolderRev] = strtok(beamletHeaderFileNameRev,{'/','\'});
-    optSettings.beamletInfo.beamletFolder = fliplr(beamletFolderRev);
-    optSettings.beamletInfo.beamletFolder(:,end) = [];  % delete last character, which is a '/' or '\'
-    optSettings.beamletInfo.beamletHeaderFileName = fliplr(fileNameRev);
-end
-
-% open the prescription file if it has been specified properly
-if isfield(optSettings,'optInfo') & isfield(optSettings,'prescInfo') ...
-        & isfield(optSettings.optInfo,'inputFolder') & isfield(optSettings.prescInfo,'prescFile')
-    
-    prescFile = [optSettings.optInfo.inputFolder '/' optSettings.prescInfo.prescFile];
-    fid = fopen([prescFile],'r');
-    if fid == -1
-        missingInfo{end+1} = ['Unable to open prescription file: ' prescFile];
-    else
-        % read the entire file into a cell array
-        fileText = {};
-        while 1
-            tline = fgetl(fid);
-            if ~ischar(tline)
-                break;
-            end
-            fileText{end+1} = tline;
-        end
-        fclose(fid);
-
-        if ~strcmp(deblank(fileText{1}),'Ntissue')
-            error('First line of prescription file must be ''Ntissue''');
-        else
-            Ntissue = str2num(fileText{2});
-        end
-
-        k = 5;  % skip up to the 5th line of the file, which is the tissue number
-        
-        % read in the tissues
-        for m=1:Ntissue  % read through the lines for the current tissue
-            tissNum = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).name = fileText{k};
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).alpha = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).betaVPlus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).dVPlus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).vPlus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).betaVMinus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).dVMinus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).vMinus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).betaPlus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).dosePlusFileName = fileText{k};
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).betaMinus = str2num(fileText{k});
-            k = k + 2;
-            optSettings.prescInfo.presc.tissue(m).doseMinusFileName = fileText{k};
-
-            % load-in the dPlus inforomation
-            fid = fopen(optSettings.prescInfo.presc.tissue(m).dosePlusFileName,'rb');
-            siz = fread(fid,3,'int');  % size of the sparse array
-            Nind = fread(fid,1,'int');
-            ind = fread(fid,Nind,'int=>int');
-            dat = fread(fid,Nind,'float=>float');
-            fclose(fid);
-            optSettings.prescInfo.presc.tissue(m).ind = ind + 1;
-            optSettings.prescInfo.presc.tissue(m).dPlus = dat;
-
-            % load-in the dMinus inforomation
-            fid = fopen(optSettings.prescInfo.presc.tissue(m).doseMinusFileName,'rb');
-            siz = fread(fid,3,'int')';  % size of the sparse array
-            Nind = fread(fid,1,'int');
-            ind = fread(fid,Nind,'int=>int');
-            dat = fread(fid,Nind,'float=>float');
-            fclose(fid);
-            optSettings.prescInfo.presc.tissue(m).ind = ind + 1;
-            optSettings.prescInfo.presc.tissue(m).dMinus = dat;
-
-            k = k + 3;  % skip up to the next tissueNum value field
-        end
-        optSettings.prescInfo.presc.siz = siz;  % size of all of the dose grid
-    end
-end
-
-% read in the initial guess information
-if isfield(optSettings,'initialGuessInfo') & isfield(optSettings.initialGuessInfo,'initBeamWeightFile') ...
-        & isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'inputFolder')
-    if ~isfield(optSettings.initialGuessInfo,'calcInitialGuessFlag') ...
-        || (isfield(optSettings.initialGuessInfo,'calcInitialGuessFlag') & optSettings.initialGuessInfo.calcInitialGuessFlag == 0)
-        fid = fopen([optimizerFolder '/' optSettings.optInfo.inputFolder '/' optSettings.initialGuessInfo.initBeamWeightFile]);
-        if fid == -1
-            missingInfo{end+1} = ['Unable to open initial guess file for beam weights: ' optSettings.initialGuessInfo.initBeamWeightFile];
-        else
-            optSettings.initialGuessInfo.w0 = fread(fid,'float');
-            fclose(fid);
-        end
-    end
-end
-
-% read in the beamlet file and folder information
-if isfield(optSettings,'beamletInfo') & isfield(optSettings.beamletInfo,'beamletFolder') ...
-        & isfield(optSettings.beamletInfo,'beamletFolder')
-
-    beamletHeaderFile = [optSettings.beamletInfo.beamletFolder '/' optSettings.beamletInfo.beamletHeaderFileName];
-    fid = fopen(beamletHeaderFile,'r');
-    if fid == -1
-        missingInfo{end+1} = ['Unable to open beamlet header file: ' beamletHeaderFile];
-    else
-        % read the file into a cell array, line-by-line
-        fileText = {};
-        while 1
-            tline = fgetl(fid);
-            if ~ischar(tline)
-                break;
-            end
-            fileText{end+1} = tline;
-        end
-        fclose(fid);
-
-        fieldFunctions = { ...
-            'beamletDim'            'beamletInfo'       'str2num'         
-            'Nbeamlets'             'beamletInfo'       'str2num'                  
-            'Nbeamletbatches'       'beamletInfo'       'str2num'                  
-            'beamletFolder'         'beamletInfo'       ''                   
-            'beamletBatchBaseName'  'beamletInfo'       ''                   
-            'beamletBatchExtension' 'beamletInfo'       '' };
-
-        % search for key fields
-        for k=1:length(fileText)
-            for m=1:size(fieldFunctions,1)
-                if strcmp(deblank(fileText{k}),fieldFunctions{m,1})
-                    eval(['optSettings.' fieldFunctions{m,2} '.' fieldFunctions{m,1} ' = ' fieldFunctions{m,3} '(''' fileText{k+1} ''');']);
-                end
-            end
-        end
-
-        % search for missing fields
-        for k=1:size(fieldFunctions,1)
-            if ~isfield(optSettings,fieldFunctions{k,2}) | ~eval(['isfield(optSettings.' fieldFunctions{k,2} ',''' fieldFunctions{k,1} ''')'])
-                missingInfo{end+1} = ['Missing: optSettings.' fieldFunctions{k,2} '.' fieldFunctions{k,1}];
-            end
-        end
-    end
-end
+function [optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile)
+% [optSettings,missingInfo] = loadOptSettings(optimizerFolder,optInputFile) 
+% loads the linear least squares optimization settings from the 
+% optimization input file into  a Matlab structure.  Beamlets are not 
+% loaded, but everything else is. If any inconsistancies are found, such as
+% 
+% missing fields, etc, the inconsistancies are stored in the cell array, 
+% missingInfo.  The optInputFile must be that absolute path of the input 
+% file.
+%
+% RTF 1/19/07
+
+% initialize outputs
+optSettings = [];
+missingInfo = {};
+
+% Open the optimization input file
+fid = fopen([optimizerFolder '/' optInputFile],'r');
+
+if fid == -1
+    error(['Unable to open ' optimizerFolder '/' optInputFile]);
+end
+
+optSettings = [];  % optimization settings structure
+
+% read the file into a cell array, line-by-line
+fileText = {};
+while 1
+    tline = fgetl(fid);
+    if ~ischar(tline)
+        break; 
+    end
+    fileText{end+1} = tline;
+end
+fclose(fid);
+
+% Extract the folder name that contains the input file
+inputFileNameRev = fliplr(optInputFile);  % flip the input filename around
+% pop off the reversed file name
+[fileNameRev,inputFolderRev] = strtok(inputFileNameRev,{'/','\'});
+inputFolder = fliplr(inputFolderRev);
+if isempty(inputFolder)  % input folder is the current folder
+    inputFolder = pwd;
+end
+
+optSettings.optInfo.inputFile = fliplr(fileNameRev);
+%                 Field Name              subfield            conversion  function
+fieldFunctions = {'Niterations'           'optInfo'           'str2num'            
+                  'Nperbatch'             'optInfo'           'str2num'            
+                  'prescFile'             'prescInfo'         ''                   
+                  'initBeamWeightFile'    'initialGuessInfo'  ''                   
+                  'beamletHeaderFileName' 'beamletInfo'       ''                   
+                  'doseBatchBaseName'     'optInfo'           ''                   
+                  'doseBatchExtension'    'optInfo'           ''                   
+                  'weightBatchBaseName'   'optInfo'           ''                   
+                  'weightBatchExtension'  'optInfo'           ''                   
+                  'objFuncFileName'       'optInfo'           ''
+                  'modFactor'             'optInfo'           'str2num'
+                  'calcInitialGuessFlag'  'initialGuessInfo'  'str2num'};
+
+% search for key fields
+for k=1:length(fileText)
+    for m=1:size(fieldFunctions,1)
+        if strcmp(deblank(fileText{k}),fieldFunctions{m,1})
+            eval(['optSettings.' fieldFunctions{m,2} '.' fieldFunctions{m,1} ' = ' fieldFunctions{m,3} '(''' fileText{k+1} ''');']);
+        end
+    end
+end
+
+% search for missing fields
+for k=1:size(fieldFunctions,1)
+    if ~isfield(optSettings,fieldFunctions{k,2}) | ~eval(['isfield(optSettings.' fieldFunctions{k,2} ',''' fieldFunctions{k,1} ''')'])
+        missingInfo{end+1} = ['Missing: optSettings.' fieldFunctions{k,2} '.' fieldFunctions{k,1}];
+    end
+end
+
+% find the output folder
+if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'doseBatchBaseName')
+    doseBatchBaseNameRev = fliplr(optSettings.optInfo.doseBatchBaseName);
+    [fileNameRev,outputFolderRev] = strtok(doseBatchBaseNameRev,{'/','\'});
+    optSettings.optInfo.outputFolder = fliplr(outputFolderRev);
+    optSettings.optInfo.outputFolder(:,end) = [];  % delete last character, which is a '/' or '\'
+    optSettings.optInfo.doseBatchBaseName = fliplr(fileNameRev);
+end
+
+% get the weightBatchBaseName
+if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'weightBatchBaseName')
+    doseBatchBaseNameRev = fliplr(optSettings.optInfo.weightBatchBaseName);
+    [fileNameRev,outputFolderRev] = strtok(doseBatchBaseNameRev,{'/','\'});
+    optSettings.optInfo.weightBatchBaseName = fliplr(fileNameRev);
+end
+
+% find the input folder
+if isfield(optSettings,'prescInfo') & isfield(optSettings.prescInfo,'prescFile')
+    prescFileRev = fliplr(optSettings.prescInfo.prescFile);
+    [fileNameRev,inputFolderRev] = strtok(prescFileRev,{'/','\'});
+    optSettings.optInfo.inputFolder = fliplr(inputFolderRev);
+    optSettings.optInfo.inputFolder(:,end) = [];  % delete last character, which is a '/' or '\'
+    optSettings.prescInfo.prescFile = fliplr(fileNameRev);
+end
+
+% get the initial beam weights file name
+if isfield(optSettings,'initialGuessInfo') & isfield(optSettings.initialGuessInfo,'initBeamWeightFile')
+    initBeamWeightFileRev = fliplr(optSettings.initialGuessInfo.initBeamWeightFile);
+    [fileNameRev,inputFolderRev] = strtok(initBeamWeightFileRev,{'/','\'});
+    optSettings.initialGuessInfo.initBeamWeightFile = fliplr(fileNameRev);
+end
+
+% trim off the objective function filename
+if isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'objFuncFileName')
+    prescFileRev = fliplr(optSettings.optInfo.objFuncFileName);
+    [fileNameRev,inputFolderRev] = strtok(prescFileRev,{'/','\'});
+    optSettings.optInfo.objFuncFileName = fliplr(fileNameRev);
+end
+
+% get the beamletFolder and beamletHeader
+if isfield(optSettings,'beamletInfo') & isfield(optSettings.beamletInfo,'beamletHeaderFileName')
+    beamletHeaderFileNameRev = fliplr(optSettings.beamletInfo.beamletHeaderFileName);
+    [fileNameRev,beamletFolderRev] = strtok(beamletHeaderFileNameRev,{'/','\'});
+    optSettings.beamletInfo.beamletFolder = fliplr(beamletFolderRev);
+    optSettings.beamletInfo.beamletFolder(:,end) = [];  % delete last character, which is a '/' or '\'
+    optSettings.beamletInfo.beamletHeaderFileName = fliplr(fileNameRev);
+end
+
+% open the prescription file if it has been specified properly
+if isfield(optSettings,'optInfo') & isfield(optSettings,'prescInfo') ...
+        & isfield(optSettings.optInfo,'inputFolder') & isfield(optSettings.prescInfo,'prescFile')
+    
+    prescFile = [optSettings.optInfo.inputFolder '/' optSettings.prescInfo.prescFile];
+    fid = fopen([prescFile],'r');
+    if fid == -1
+        missingInfo{end+1} = ['Unable to open prescription file: ' prescFile];
+    else
+        % read the entire file into a cell array
+        fileText = {};
+        while 1
+            tline = fgetl(fid);
+            if ~ischar(tline)
+                break;
+            end
+            fileText{end+1} = tline;
+        end
+        fclose(fid);
+
+        if ~strcmp(deblank(fileText{1}),'Ntissue')
+            error('First line of prescription file must be ''Ntissue''');
+        else
+            Ntissue = str2num(fileText{2});
+        end
+
+        k = 5;  % skip up to the 5th line of the file, which is the tissue number
+        
+        % read in the tissues
+        for m=1:Ntissue  % read through the lines for the current tissue
+            tissNum = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).name = fileText{k};
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).alpha = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).betaVPlus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).dVPlus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).vPlus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).betaVMinus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).dVMinus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).vMinus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).betaPlus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).dosePlusFileName = fileText{k};
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).betaMinus = str2num(fileText{k});
+            k = k + 2;
+            optSettings.prescInfo.presc.tissue(m).doseMinusFileName = fileText{k};
+
+            % load-in the dPlus inforomation
+            fid = fopen(optSettings.prescInfo.presc.tissue(m).dosePlusFileName,'rb');
+            siz = fread(fid,3,'int');  % size of the sparse array
+            Nind = fread(fid,1,'int');
+            ind = fread(fid,Nind,'int=>int');
+            dat = fread(fid,Nind,'float=>float');
+            fclose(fid);
+            optSettings.prescInfo.presc.tissue(m).ind = ind + 1;
+            optSettings.prescInfo.presc.tissue(m).dPlus = dat;
+
+            % load-in the dMinus inforomation
+            fid = fopen(optSettings.prescInfo.presc.tissue(m).doseMinusFileName,'rb');
+            siz = fread(fid,3,'int')';  % size of the sparse array
+            Nind = fread(fid,1,'int');
+            ind = fread(fid,Nind,'int=>int');
+            dat = fread(fid,Nind,'float=>float');
+            fclose(fid);
+            optSettings.prescInfo.presc.tissue(m).ind = ind + 1;
+            optSettings.prescInfo.presc.tissue(m).dMinus = dat;
+
+            k = k + 3;  % skip up to the next tissueNum value field
+        end
+        optSettings.prescInfo.presc.siz = siz;  % size of all of the dose grid
+    end
+end
+
+% read in the initial guess information
+if isfield(optSettings,'initialGuessInfo') & isfield(optSettings.initialGuessInfo,'initBeamWeightFile') ...
+        & isfield(optSettings,'optInfo') & isfield(optSettings.optInfo,'inputFolder')
+    if ~isfield(optSettings.initialGuessInfo,'calcInitialGuessFlag') ...
+        || (isfield(optSettings.initialGuessInfo,'calcInitialGuessFlag') & optSettings.initialGuessInfo.calcInitialGuessFlag == 0)
+        fid = fopen([optimizerFolder '/' optSettings.optInfo.inputFolder '/' optSettings.initialGuessInfo.initBeamWeightFile]);
+        if fid == -1
+            missingInfo{end+1} = ['Unable to open initial guess file for beam weights: ' optSettings.initialGuessInfo.initBeamWeightFile];
+        else
+            optSettings.initialGuessInfo.w0 = fread(fid,'float');
+            fclose(fid);
+        end
+    end
+end
+
+% read in the beamlet file and folder information
+if isfield(optSettings,'beamletInfo') & isfield(optSettings.beamletInfo,'beamletFolder') ...
+        & isfield(optSettings.beamletInfo,'beamletFolder')
+
+    beamletHeaderFile = [optSettings.beamletInfo.beamletFolder '/' optSettings.beamletInfo.beamletHeaderFileName];
+    fid = fopen(beamletHeaderFile,'r');
+    if fid == -1
+        missingInfo{end+1} = ['Unable to open beamlet header file: ' beamletHeaderFile];
+    else
+        % read the file into a cell array, line-by-line
+        fileText = {};
+        while 1
+            tline = fgetl(fid);
+            if ~ischar(tline)
+                break;
+            end
+            fileText{end+1} = tline;
+        end
+        fclose(fid);
+
+        fieldFunctions = { ...
+            'beamletDim'            'beamletInfo'       'str2num'         
+            'Nbeamlets'             'beamletInfo'       'str2num'                  
+            'Nbeamletbatches'       'beamletInfo'       'str2num'                  
+            'beamletFolder'         'beamletInfo'       ''                   
+            'beamletBatchBaseName'  'beamletInfo'       ''                   
+            'beamletBatchExtension' 'beamletInfo'       '' };
+
+        % search for key fields
+        for k=1:length(fileText)
+            for m=1:size(fieldFunctions,1)
+                if strcmp(deblank(fileText{k}),fieldFunctions{m,1})
+                    eval(['optSettings.' fieldFunctions{m,2} '.' fieldFunctions{m,1} ' = ' fieldFunctions{m,3} '(''' fileText{k+1} ''');']);
+                end
+            end
+        end
+
+        % search for missing fields
+        for k=1:size(fieldFunctions,1)
+            if ~isfield(optSettings,fieldFunctions{k,2}) | ~eval(['isfield(optSettings.' fieldFunctions{k,2} ',''' fieldFunctions{k,1} ''')'])
+                missingInfo{end+1} = ['Missing: optSettings.' fieldFunctions{k,2} '.' fieldFunctions{k,1}];
+            end
+        end
+    end
+end

+ 166 - 166
WiscPlanPhotonkV125/matlab_frontend/dens2mstp.m

@@ -1,166 +1,166 @@
-function [Smw Fmw2] = dens2mstp(dens_ratio)
-% DENS2MSTP Convert physical density to mass stopping power and Fmw2
-%
-% Usage:
-%     [Smw Fmw2] = dens2mstp ( density_matrix )
-% INPUT:
-%     density_matrix = density matrix (g/cm^3) with any dimensionality
-% OUTPUT:
-%     Smw = stopping power ratio
-%     Fmw2 = squared F value ratio to water
-%
-% Given an array of densities relative to water (assumed to be from a CT
-% scan), the mass stopping power ratio (relative to water) array is
-% calculated. The conversion is done by assuming that every voxel in the CT
-% consists of either air, adipose tissue, muscle, or bone. A lookup table
-% of mass stopping power ratios between each material and water is then
-% constructed by computing the average mass stopping power ratio over some
-% proton energy region, usually between 50 MeV and 250 MeV. The mass
-% stopping powers are looked-up in tables obtained from the NIST website.
-%
-% This code was intended to be used as a way of converting CT
-% data to mass stopping power data for proton dose calculations. The energy
-% of the proton beam is assumed to be between 50 MeV and 250 MeV, a regime
-% in which the approximation that stopping power ratios are energy
-% independent holds.
-%
-% Note that the value returned is the stopping power ratio. The stopping power 
-% has units of MeV/cm. This is an important distinction!
-%
-% Copyleft: Ryan Flynn, Xiaohu Mo
-% Version: 1.2
-
-% Set up the boundary points for the density-to-material lookup table.
-air_low = 0;
-air_high = 0.05; fat_low = air_high;
-fat_high = 0.99; wat_low = fat_high;
-wat_high = 1.01; mus_low = wat_high;
-mus_high = 1.25; bon_low = mus_high;
-bon_high = 20.0;
-
-% check the input argument
-if ~isempty(find(dens_ratio < air_low, 1))
-    error('Cannot have negative densities.  Redefine input argument.');
-end
-
-if ~isempty(find(dens_ratio > bon_high, 1))
-    error('Extremely high densities are present in the input array, data may not be scaled properly');
-end
-
-% Product of Fmw and rho for tabluated materials
-fmw_air_to_water = 990.8 * 1.205E-3;
-fmw_fat_to_water = 0.972 * 0.92;
-fmw_mus_to_water = 0.972 * 1.04;
-fmw_bon_to_water = 0.656 * 1.85;
-fmw_wat_to_water = 1.0;
-
-% Stopping power ranges that will be used to calculate the average stopping
-% power ratios between each material and water.
-Tlo = 1;      % lower energy boundary in MeV
-Thi = 250;    % upper energy boundary in MeV
-
-% load the stopping powers
-load('MSTPliquid_water.mat');
-water = MSTP;
-load('MSTPair.mat');
-air = MSTP;
-load('MSTPadipose.mat');
-fat = MSTP;
-load('MSTPskeletal_muscle.mat');
-mus = MSTP;
-load('MSTPcompact_bone.mat');
-bon = MSTP;
-
-% calculate the spacing between energy bins
-dT = [water.T(1) diff(water.T)];
-
-% find the indices of integration that will be used
-indices_low = find(water.T <= Tlo);
-ind_low = indices_low(end);
-
-indices_high = find(water.T >= Thi);
-ind_high = indices_high(1);
-
-% Calculate the average stopping power ratio for the material and water
-% between the energy range specified above.
-smw_air_to_water = sum(air.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
-smw_fat_to_water = sum(fat.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
-smw_wat_to_water = 1.0;
-smw_mus_to_water = sum(mus.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
-smw_bon_to_water = sum(bon.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
-
-% material mask
-region_air = find (dens_ratio >= air_low & dens_ratio < air_high);
-region_fat = find (dens_ratio >= fat_low & dens_ratio < fat_high);
-region_wat = find (dens_ratio >= wat_low & dens_ratio < wat_high);
-region_mus = find (dens_ratio >= mus_low & dens_ratio < mus_high);
-region_bon = find (dens_ratio >= bon_low);
-
-% fill the mass stopping power ratio
-Smw = zeros ( size ( dens_ratio ) );
-Smw ( region_air ) = smw_air_to_water * dens_ratio ( region_air );
-Smw ( region_fat ) = smw_fat_to_water * dens_ratio ( region_fat );
-Smw ( region_wat ) = smw_wat_to_water * dens_ratio ( region_wat );
-Smw ( region_mus ) = smw_mus_to_water * dens_ratio ( region_mus );
-Smw ( region_bon ) = smw_bon_to_water * dens_ratio ( region_bon );
-
-% fill the Fmw2
-% divide by density to appropriately scale Fmw
-Fmw2 = zeros ( size ( dens_ratio ) );
-Fmw2 ( region_air ) = fmw_air_to_water ./ dens_ratio ( region_air );
-Fmw2 ( region_fat ) = fmw_fat_to_water ./ dens_ratio ( region_fat );
-Fmw2 ( region_wat ) = fmw_wat_to_water ./ dens_ratio ( region_wat );
-Fmw2 ( region_mus ) = fmw_mus_to_water ./ dens_ratio ( region_mus );
-Fmw2 ( region_bon ) = fmw_bon_to_water ./ dens_ratio ( region_bon );
-Fmw2 = Fmw2.^2;
-
-
-% % plot the stopping power ratio as a function of energy for bone and water
-% f1 = figure; set(gcf,'color',[1 1 1]);
-% p = plot(water.T(ind_low:ind_high),bone.tot(ind_low:ind_high)./water.tot(ind_low:ind_high));
-% set(p,'LineWidth',2);
-% set(gca,'YLim',[0.9 0.95]);
-% set(gca,'FontSize',14);
-% title('Mass stopping power ratio between bone and water','FontSize',14);
-% xlabel('Energy (MeV)','FontSize',14);
-% ylabel('Ratio','FontSize',14);
-% print -dbitmap MSTP_ratio_with_energy.png;
-% 
-% % plot the density ratio to mass stopping power ratio lookup table:
-% xmax = 2.5;
-% N = 50;
-% dx = xmax/N;
-% x = [0:N-1]*dx;
-% y = zeros(size(x));
-% y(x >= air_low & x <= air_high) = air_to_water;
-% y(x > adipose_low & x <= adipose_high) = adipose_to_water;
-% y(x > muscle_low & x <= muscle_high) = muscle_to_water;
-% y(x > bone_low) = bone_to_water;
-% 
-% z = y.*x;
-% 
-% f2 = figure; set(gcf,'color',[1 1 1]);
-% plot(x(x >= air_low & x <= air_high),y(x >= air_low & x <= air_high),'.b',...
-%     x(x > adipose_low & x <= adipose_high),y(x > adipose_low & x <= adipose_high),'+b',...
-%     x(x > muscle_low & x <= muscle_high),y(x > muscle_low & x <= muscle_high),'xb',...
-%     x(x > bone_low),y(x > bone_low),'*b');
-% l = legend('air','adipose','muscle','bone');
-% set(l,'FontSize',14);
-% set(gca,'FontSize',14);
-% xlabel('Density ratio','FontSize',14);
-% ylabel('Mass stopping power ratio','FontSize',14);
-% title('Change in mass stopping power ratio with density','FontSize',14);
-% print -dbitmap MSTP_ratio_with_density.png;
-% 
-% f3 = figure; set(gcf,'color',[1 1 1]);
-% plot(x(x >= air_low & x <= air_high),z(x >= air_low & x <= air_high),'.b',...
-%     x(x > adipose_low & x <= adipose_high),z(x > adipose_low & x <= adipose_high),'+b',...
-%     x(x > muscle_low & x <= muscle_high),z(x > muscle_low & x <= muscle_high),'xb',...
-%     x(x > bone_low),z(x > bone_low),'*b');
-% l = legend('air','adipose','muscle','bone');
-% set(l,'FontSize',14,'position',[0.6258 0.2433 0.2250 0.2460]);
-% set(gca,'FontSize',14);
-% xlabel('Density ratio','FontSize',14);
-% ylabel('Stopping power ratio','FontSize',14);
-% title('Change in stopping power ratio with density','FontSize',14);
-% print -dbitmap STP_ratio_with_density.png;
+function [Smw Fmw2] = dens2mstp(dens_ratio)
+% DENS2MSTP Convert physical density to mass stopping power and Fmw2
+%
+% Usage:
+%     [Smw Fmw2] = dens2mstp ( density_matrix )
+% INPUT:
+%     density_matrix = density matrix (g/cm^3) with any dimensionality
+% OUTPUT:
+%     Smw = stopping power ratio
+%     Fmw2 = squared F value ratio to water
+%
+% Given an array of densities relative to water (assumed to be from a CT
+% scan), the mass stopping power ratio (relative to water) array is
+% calculated. The conversion is done by assuming that every voxel in the CT
+% consists of either air, adipose tissue, muscle, or bone. A lookup table
+% of mass stopping power ratios between each material and water is then
+% constructed by computing the average mass stopping power ratio over some
+% proton energy region, usually between 50 MeV and 250 MeV. The mass
+% stopping powers are looked-up in tables obtained from the NIST website.
+%
+% This code was intended to be used as a way of converting CT
+% data to mass stopping power data for proton dose calculations. The energy
+% of the proton beam is assumed to be between 50 MeV and 250 MeV, a regime
+% in which the approximation that stopping power ratios are energy
+% independent holds.
+%
+% Note that the value returned is the stopping power ratio. The stopping power 
+% has units of MeV/cm. This is an important distinction!
+%
+% Copyleft: Ryan Flynn, Xiaohu Mo
+% Version: 1.2
+
+% Set up the boundary points for the density-to-material lookup table.
+air_low = 0;
+air_high = 0.05; fat_low = air_high;
+fat_high = 0.99; wat_low = fat_high;
+wat_high = 1.01; mus_low = wat_high;
+mus_high = 1.25; bon_low = mus_high;
+bon_high = 20.0;
+
+% check the input argument
+if ~isempty(find(dens_ratio < air_low, 1))
+    error('Cannot have negative densities.  Redefine input argument.');
+end
+
+if ~isempty(find(dens_ratio > bon_high, 1))
+    error('Extremely high densities are present in the input array, data may not be scaled properly');
+end
+
+% Product of Fmw and rho for tabluated materials
+fmw_air_to_water = 990.8 * 1.205E-3;
+fmw_fat_to_water = 0.972 * 0.92;
+fmw_mus_to_water = 0.972 * 1.04;
+fmw_bon_to_water = 0.656 * 1.85;
+fmw_wat_to_water = 1.0;
+
+% Stopping power ranges that will be used to calculate the average stopping
+% power ratios between each material and water.
+Tlo = 1;      % lower energy boundary in MeV
+Thi = 250;    % upper energy boundary in MeV
+
+% load the stopping powers
+load('MSTPliquid_water.mat');
+water = MSTP;
+load('MSTPair.mat');
+air = MSTP;
+load('MSTPadipose.mat');
+fat = MSTP;
+load('MSTPskeletal_muscle.mat');
+mus = MSTP;
+load('MSTPcompact_bone.mat');
+bon = MSTP;
+
+% calculate the spacing between energy bins
+dT = [water.T(1) diff(water.T)];
+
+% find the indices of integration that will be used
+indices_low = find(water.T <= Tlo);
+ind_low = indices_low(end);
+
+indices_high = find(water.T >= Thi);
+ind_high = indices_high(1);
+
+% Calculate the average stopping power ratio for the material and water
+% between the energy range specified above.
+smw_air_to_water = sum(air.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
+smw_fat_to_water = sum(fat.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
+smw_wat_to_water = 1.0;
+smw_mus_to_water = sum(mus.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
+smw_bon_to_water = sum(bon.tot(ind_low:ind_high)./water.tot(ind_low:ind_high).*dT(ind_low:ind_high))/(Thi-Tlo);
+
+% material mask
+region_air = find (dens_ratio >= air_low & dens_ratio < air_high);
+region_fat = find (dens_ratio >= fat_low & dens_ratio < fat_high);
+region_wat = find (dens_ratio >= wat_low & dens_ratio < wat_high);
+region_mus = find (dens_ratio >= mus_low & dens_ratio < mus_high);
+region_bon = find (dens_ratio >= bon_low);
+
+% fill the mass stopping power ratio
+Smw = zeros ( size ( dens_ratio ) );
+Smw ( region_air ) = smw_air_to_water * dens_ratio ( region_air );
+Smw ( region_fat ) = smw_fat_to_water * dens_ratio ( region_fat );
+Smw ( region_wat ) = smw_wat_to_water * dens_ratio ( region_wat );
+Smw ( region_mus ) = smw_mus_to_water * dens_ratio ( region_mus );
+Smw ( region_bon ) = smw_bon_to_water * dens_ratio ( region_bon );
+
+% fill the Fmw2
+% divide by density to appropriately scale Fmw
+Fmw2 = zeros ( size ( dens_ratio ) );
+Fmw2 ( region_air ) = fmw_air_to_water ./ dens_ratio ( region_air );
+Fmw2 ( region_fat ) = fmw_fat_to_water ./ dens_ratio ( region_fat );
+Fmw2 ( region_wat ) = fmw_wat_to_water ./ dens_ratio ( region_wat );
+Fmw2 ( region_mus ) = fmw_mus_to_water ./ dens_ratio ( region_mus );
+Fmw2 ( region_bon ) = fmw_bon_to_water ./ dens_ratio ( region_bon );
+Fmw2 = Fmw2.^2;
+
+
+% % plot the stopping power ratio as a function of energy for bone and water
+% f1 = figure; set(gcf,'color',[1 1 1]);
+% p = plot(water.T(ind_low:ind_high),bone.tot(ind_low:ind_high)./water.tot(ind_low:ind_high));
+% set(p,'LineWidth',2);
+% set(gca,'YLim',[0.9 0.95]);
+% set(gca,'FontSize',14);
+% title('Mass stopping power ratio between bone and water','FontSize',14);
+% xlabel('Energy (MeV)','FontSize',14);
+% ylabel('Ratio','FontSize',14);
+% print -dbitmap MSTP_ratio_with_energy.png;
+% 
+% % plot the density ratio to mass stopping power ratio lookup table:
+% xmax = 2.5;
+% N = 50;
+% dx = xmax/N;
+% x = [0:N-1]*dx;
+% y = zeros(size(x));
+% y(x >= air_low & x <= air_high) = air_to_water;
+% y(x > adipose_low & x <= adipose_high) = adipose_to_water;
+% y(x > muscle_low & x <= muscle_high) = muscle_to_water;
+% y(x > bone_low) = bone_to_water;
+% 
+% z = y.*x;
+% 
+% f2 = figure; set(gcf,'color',[1 1 1]);
+% plot(x(x >= air_low & x <= air_high),y(x >= air_low & x <= air_high),'.b',...
+%     x(x > adipose_low & x <= adipose_high),y(x > adipose_low & x <= adipose_high),'+b',...
+%     x(x > muscle_low & x <= muscle_high),y(x > muscle_low & x <= muscle_high),'xb',...
+%     x(x > bone_low),y(x > bone_low),'*b');
+% l = legend('air','adipose','muscle','bone');
+% set(l,'FontSize',14);
+% set(gca,'FontSize',14);
+% xlabel('Density ratio','FontSize',14);
+% ylabel('Mass stopping power ratio','FontSize',14);
+% title('Change in mass stopping power ratio with density','FontSize',14);
+% print -dbitmap MSTP_ratio_with_density.png;
+% 
+% f3 = figure; set(gcf,'color',[1 1 1]);
+% plot(x(x >= air_low & x <= air_high),z(x >= air_low & x <= air_high),'.b',...
+%     x(x > adipose_low & x <= adipose_high),z(x > adipose_low & x <= adipose_high),'+b',...
+%     x(x > muscle_low & x <= muscle_high),z(x > muscle_low & x <= muscle_high),'xb',...
+%     x(x > bone_low),z(x > bone_low),'*b');
+% l = legend('air','adipose','muscle','bone');
+% set(l,'FontSize',14,'position',[0.6258 0.2433 0.2250 0.2460]);
+% set(gca,'FontSize',14);
+% xlabel('Density ratio','FontSize',14);
+% ylabel('Stopping power ratio','FontSize',14);
+% title('Change in stopping power ratio with density','FontSize',14);
+% print -dbitmap STP_ratio_with_density.png;

+ 28 - 28
WiscPlanPhotonkV125/matlab_frontend/dicomrt/checkDictUse.m

@@ -1,29 +1,29 @@
-function flg = checkDictUse
-% Since MATLAB 7.3(2006A) and 7.4(2006B) doesnot support dicom dictionary
-% this function checks the matlab version and returns the flag to allow the
-% use of dictionary.
-%
-% DK 
-
-% copyright (c) 2001-2007, Washington University in St. Louis.
-% Permission is granted to use or modify only for non-commercial, 
-% non-treatment-decision applications, and further only if this header is 
-% not removed from any file. No warranty is expressed or implied for any 
-% use whatever: use at your own risk.  Users can request use of CERR for 
-% institutional review board-approved protocols.  Commercial users can 
-% request a license.  Contact Joe Deasy for more information 
-% (radonc.wustl.edu@jdeasy, reversed).
-
-% set flag to 1 so as to always use Dictionary
-flg = 1;
-
-mathVer = version;
-
-% XMO: Old bug code. Does not work for version 7.10
-% if str2num(mathVer(1:3)) > 7.3
-v = sscanf(mathVer, '%d.%d.%s');
-if v(1) + v(2)/10 > 7.3
-    flg = 0;   
-end
-
+function flg = checkDictUse
+% Since MATLAB 7.3(2006A) and 7.4(2006B) doesnot support dicom dictionary
+% this function checks the matlab version and returns the flag to allow the
+% use of dictionary.
+%
+% DK 
+
+% copyright (c) 2001-2007, Washington University in St. Louis.
+% Permission is granted to use or modify only for non-commercial, 
+% non-treatment-decision applications, and further only if this header is 
+% not removed from any file. No warranty is expressed or implied for any 
+% use whatever: use at your own risk.  Users can request use of CERR for 
+% institutional review board-approved protocols.  Commercial users can 
+% request a license.  Contact Joe Deasy for more information 
+% (radonc.wustl.edu@jdeasy, reversed).
+
+% set flag to 1 so as to always use Dictionary
+flg = 1;
+
+mathVer = version;
+
+% XMO: Old bug code. Does not work for version 7.10
+% if str2num(mathVer(1:3)) > 7.3
+v = sscanf(mathVer, '%d.%d.%s');
+if v(1) + v(2)/10 > 7.3
+    flg = 0;   
+end
+
 return

+ 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.25;
-        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.25;
+        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);
+

+ 108 - 108
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_addmcdose.m

@@ -1,109 +1,109 @@
-function [totalMCdose,totalMCerror] = dicomrt_addmcdose(MCdose,MCerror)
-% dicomrt_addmcdose(MCdose,MCerror)
-%
-% Add segment's contribution of Monte Carlo 3D dose distribution calculated for rtplanformc 
-% 
-% MCdose and MCerror are two cell arrays with the following structure
-%
-%   beam name     3d matrix/segment
-%  --------------------------------------
-%  | [beam 1] | [1st segment 3dmatrix ] |
-%  |          | [1st segment 3dmatrix ] |
-%  |          |                         |
-%  |          | [nth segment 3dmatrix ] |
-%  --------------------------------------
-%  |   ...               ...            |
-%  --------------------------------------
-%  | [beam 2] | [1st segment 3dmatrix ] |
-%  |          | [1st segment 3dmatrix ] |
-%  |          |                         |
-%  |          | [nth segment 3dmatrix ] |
-%  --------------------------------------
-%
-% Example:
-%
-% [totalMCdose,totalMCerror]=dicomrt_addmcdose(A,B)
-%
-% add all the 3D MC dose and errors from segments, stored respectively in A and B,  
-% and return them in totalMCdose and totalMCerror
-%
-% See also dicomrt_read3ddose, dicomrt_loaddose, dicomrt_loadmcdose
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-% Check number of argument
-error(nargchk(1,2,nargin))
-
-% Check case and set-up some parameters and variables
-if nargin==1
-    [study_temp,type_dose,label]=dicomrt_checkinput(MCdose,1);
-    MCdose=dicomrt_varfilter(study_temp);
-else
-    [study_temp,type_dose,label]=dicomrt_checkinput(MCdose,1);
-    [studye_temp,type_dose,label]=dicomrt_checkinput(MCerror,1);
-    MCdose=dicomrt_varfilter(study_temp);
-    MCerror=dicomrt_varfilter(studye_temp);    
-end
-
-% Check case
-if nargin==2 & (iscell(MCdose)~=1 | iscell(MCerror)~=1)
-    error('dicomrt_addmcdose: Dose or error matrices do not have the expected format (i.e. cell). Exit now!')
-elseif iscell(MCdose)~=1
-    error('dicomrt_addmcdose: Dose or error matrices do not have the expected format (i.e. cell). Exit now!')
-end
-
-% Add segment's dose
-if nargin == 2 % dose and error to be added
-    for i=1:size(MCdose,1); % loop over beam
-        if iscell(MCdose{i,2})==1 % likely segment contribution
-            for j=1:size(MCdose{i,2},2); % loop over segment
-                % NOTE: the sum of absolute errors is used to calculate the
-                % total absolute error ...
-                if i==1 & j==1
-                    totalMCdose=MCdose{i,2}{j};
-                    totalMCerror_abs=MCerror{i,2}{j}.*MCdose{i,2}{j};
-                else
-                    totalMCdose=totalMCdose+MCdose{i,2}{j};
-                    totalMCerror_abs=totalMCerror_abs+MCerror{i,2}{j}.*MCdose{i,2}{j};
-                end
-            end % end loop over segments
-        else % likely beam contribution
-            if i==1 
-                totalMCdose=MCdose{i,2};
-                totalMCerror_abs=MCerror{i,2}.*MCdose{i,2};
-            else
-                totalMCdose=totalMCdose+MCdose{i,2};
-                totalMCerror_abs=totalMCerror_abs+MCerror{i,2}.*MCdose{i,2};
-            end
-        end 
-    end % end loop over beams
-    % ... now we calculate the relative error for the total dose
-    totalMCerror=totalMCerror_abs./totalMCdose;
-elseif nargin == 1 % only dose to be added
-    for i=1:size(MCdose,1); % loop over beam
-        if iscell(MCdose{i,2})==1 % likely segment contribution
-            for j=1:size(MCdose{i,2},2); % loop over segment
-                % NOTE: the sum of absolute errors is used to calculate the
-                % total absolute error ...
-                if i==1 & j==1
-                    totalMCdose=MCdose{i,2}{j};
-                else
-                    totalMCdose=totalMCdose+MCdose{i,2}{j};
-                end
-            end % end loop over segments
-        else % likely beam contribution
-            if i==1
-                totalMCdose=MCdose{i,2};
-            else
-                totalMCdose=totalMCdose+MCdose{i,2};
-            end
-        end 
-    end % end loop over beams
-end
-
-if nargin == 1
-    totalMCdose=dicomrt_restorevarformat(study_temp,totalMCdose);
-else
-    totalMCdose=dicomrt_restorevarformat(study_temp,totalMCdose);
-    totalMCerror=dicomrt_restorevarformat(studye_temp,totalMCerror);
+function [totalMCdose,totalMCerror] = dicomrt_addmcdose(MCdose,MCerror)
+% dicomrt_addmcdose(MCdose,MCerror)
+%
+% Add segment's contribution of Monte Carlo 3D dose distribution calculated for rtplanformc 
+% 
+% MCdose and MCerror are two cell arrays with the following structure
+%
+%   beam name     3d matrix/segment
+%  --------------------------------------
+%  | [beam 1] | [1st segment 3dmatrix ] |
+%  |          | [1st segment 3dmatrix ] |
+%  |          |                         |
+%  |          | [nth segment 3dmatrix ] |
+%  --------------------------------------
+%  |   ...               ...            |
+%  --------------------------------------
+%  | [beam 2] | [1st segment 3dmatrix ] |
+%  |          | [1st segment 3dmatrix ] |
+%  |          |                         |
+%  |          | [nth segment 3dmatrix ] |
+%  --------------------------------------
+%
+% Example:
+%
+% [totalMCdose,totalMCerror]=dicomrt_addmcdose(A,B)
+%
+% add all the 3D MC dose and errors from segments, stored respectively in A and B,  
+% and return them in totalMCdose and totalMCerror
+%
+% See also dicomrt_read3ddose, dicomrt_loaddose, dicomrt_loadmcdose
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+% Check number of argument
+error(nargchk(1,2,nargin))
+
+% Check case and set-up some parameters and variables
+if nargin==1
+    [study_temp,type_dose,label]=dicomrt_checkinput(MCdose,1);
+    MCdose=dicomrt_varfilter(study_temp);
+else
+    [study_temp,type_dose,label]=dicomrt_checkinput(MCdose,1);
+    [studye_temp,type_dose,label]=dicomrt_checkinput(MCerror,1);
+    MCdose=dicomrt_varfilter(study_temp);
+    MCerror=dicomrt_varfilter(studye_temp);    
+end
+
+% Check case
+if nargin==2 & (iscell(MCdose)~=1 | iscell(MCerror)~=1)
+    error('dicomrt_addmcdose: Dose or error matrices do not have the expected format (i.e. cell). Exit now!')
+elseif iscell(MCdose)~=1
+    error('dicomrt_addmcdose: Dose or error matrices do not have the expected format (i.e. cell). Exit now!')
+end
+
+% Add segment's dose
+if nargin == 2 % dose and error to be added
+    for i=1:size(MCdose,1); % loop over beam
+        if iscell(MCdose{i,2})==1 % likely segment contribution
+            for j=1:size(MCdose{i,2},2); % loop over segment
+                % NOTE: the sum of absolute errors is used to calculate the
+                % total absolute error ...
+                if i==1 & j==1
+                    totalMCdose=MCdose{i,2}{j};
+                    totalMCerror_abs=MCerror{i,2}{j}.*MCdose{i,2}{j};
+                else
+                    totalMCdose=totalMCdose+MCdose{i,2}{j};
+                    totalMCerror_abs=totalMCerror_abs+MCerror{i,2}{j}.*MCdose{i,2}{j};
+                end
+            end % end loop over segments
+        else % likely beam contribution
+            if i==1 
+                totalMCdose=MCdose{i,2};
+                totalMCerror_abs=MCerror{i,2}.*MCdose{i,2};
+            else
+                totalMCdose=totalMCdose+MCdose{i,2};
+                totalMCerror_abs=totalMCerror_abs+MCerror{i,2}.*MCdose{i,2};
+            end
+        end 
+    end % end loop over beams
+    % ... now we calculate the relative error for the total dose
+    totalMCerror=totalMCerror_abs./totalMCdose;
+elseif nargin == 1 % only dose to be added
+    for i=1:size(MCdose,1); % loop over beam
+        if iscell(MCdose{i,2})==1 % likely segment contribution
+            for j=1:size(MCdose{i,2},2); % loop over segment
+                % NOTE: the sum of absolute errors is used to calculate the
+                % total absolute error ...
+                if i==1 & j==1
+                    totalMCdose=MCdose{i,2}{j};
+                else
+                    totalMCdose=totalMCdose+MCdose{i,2}{j};
+                end
+            end % end loop over segments
+        else % likely beam contribution
+            if i==1
+                totalMCdose=MCdose{i,2};
+            else
+                totalMCdose=totalMCdose+MCdose{i,2};
+            end
+        end 
+    end % end loop over beams
+end
+
+if nargin == 1
+    totalMCdose=dicomrt_restorevarformat(study_temp,totalMCdose);
+else
+    totalMCdose=dicomrt_restorevarformat(study_temp,totalMCdose);
+    totalMCerror=dicomrt_restorevarformat(studye_temp,totalMCerror);
 end

+ 97 - 97
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_checkinput.m

@@ -1,98 +1,98 @@
-function [moutput,type,label,PatientPositionCODE]=dicomrt_checkinput(minput,force)
-% dicomrt_checkinput(minput,force)
-%
-% Check the validity of the input variable.
-% Returns the input variable, type, label and patient orientation.
-%
-% minput is the input dataset
-% force is a parameter which force, if existing and different from 0, the function to check 
-%    for PatientPosition.
-%
-% See also: dicomrt_loaddose, dicomrt_loadct, dicomrt_loadmcdose
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-% Check number of argument
-error(nargchk(1,2,nargin))
-
-if nargin==1
-    force=0;
-end
-
-if iscell(minput) == 1 & size(minput,1) == 3 % OK accepted input
-    try 
-        header=minput{1,1}{1};
-    catch
-        header=minput{1,1};
-    end
-    modality=header.Modality;
-    if isequal(modality,'CT') % CT data
-        type='ct';
-        label='CT units [Houns]';
-        PatientPositionCODE=dicomrt_getPatientPosition(header);
-        moutput=minput;
-    elseif isequal(modality,'RTSTRUCT') % VOI data
-        type='voi';
-        label='VOI';
-        PatientPositionCODE=-1; % N/A
-        moutput=minput;
-    elseif isequal(modality,'RTPLAN') % TPS or MC dose
-        RTPLabel=header.RTPlanLabel;
-        if strfind(RTPLabel,'-MCDOSE'); 
-            % this is a MC DOSE
-            if iscell(minput{2,1}) == 1 % this is a MC dose and contains segments contribution
-                disp('Input variable is a MC dose containing segments contribution. Adding segment''s dose');
-                totaldose=dicomrt_addmcdose(minput{2,1}); %add segments' contribution in a 3D minput
-                moutput=minput;
-                moutput{2,1}=totaldose;
-            else
-                moutput=minput;
-            end
-            type='mc';
-            label='MC dose map [Gy]';
-            PatientPositionCODE=dicomrt_getPatientPosition(header);
-        elseif strfind(RTPLabel,'-DDIFF'); 
-            % this is a dose difference
-            moutput=minput;
-            type='ddiff';
-            label='Dose difference';
-            PatientPositionCODE=dicomrt_getPatientPosition(header);
-        elseif strfind(RTPLabel,'-DRATIO'); 
-            % this is a dose ratio
-            moutput=minput;
-            type='dratio';
-            label='Dose ratio';
-            PatientPositionCODE=dicomrt_getPatientPosition(header);
-        else
-            % this is a TPS DOSE
-            moutput=minput;
-            type='RTPLAN';
-            label='RTPLAN dose map [Gy]';
-            PatientPositionCODE=dicomrt_getPatientPosition(header);
-        end
-    end
-elseif isnumeric(minput)==1 % this is a simple 3D matrix
-    moutput=minput;
-    type='other';
-    label=[inputname(1),' matrix'];
-    if force==0
-        warning('dicomrt_checkinput: The input variable is a 3D matrix. Unable to determine Patient Position.');
-        PatientPosition=input('dicomrt_checkinput: Please specify Patient Position: HFS(default),FFS,HFP,FFP: ','s');
-        if isempty(PatientPosition)==1
-            PatientPosition='HFS';
-        end
-        
-        if strcmpi(PatientPosition, 'HFS')
-            PatientPositionCODE = 1;
-        elseif strcmpi(PatientPosition, 'FFS')
-            PatientPositionCODE = 2;
-        elseif strcmpi(PatientPosition, 'HFP')
-            PatientPositionCODE = 3;
-        elseif strcmpi(PatientPosition, 'FFP')
-            PatientPositionCODE = 4;
-        end
-
-    end
-else
-    error('dicomrt_checkinput: Input matrix does not have a supported format. Exit now !');
+function [moutput,type,label,PatientPositionCODE]=dicomrt_checkinput(minput,force)
+% dicomrt_checkinput(minput,force)
+%
+% Check the validity of the input variable.
+% Returns the input variable, type, label and patient orientation.
+%
+% minput is the input dataset
+% force is a parameter which force, if existing and different from 0, the function to check 
+%    for PatientPosition.
+%
+% See also: dicomrt_loaddose, dicomrt_loadct, dicomrt_loadmcdose
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+% Check number of argument
+error(nargchk(1,2,nargin))
+
+if nargin==1
+    force=0;
+end
+
+if iscell(minput) == 1 & size(minput,1) == 3 % OK accepted input
+    try 
+        header=minput{1,1}{1};
+    catch
+        header=minput{1,1};
+    end
+    modality=header.Modality;
+    if isequal(modality,'CT') % CT data
+        type='ct';
+        label='CT units [Houns]';
+        PatientPositionCODE=dicomrt_getPatientPosition(header);
+        moutput=minput;
+    elseif isequal(modality,'RTSTRUCT') % VOI data
+        type='voi';
+        label='VOI';
+        PatientPositionCODE=-1; % N/A
+        moutput=minput;
+    elseif isequal(modality,'RTPLAN') % TPS or MC dose
+        RTPLabel=header.RTPlanLabel;
+        if strfind(RTPLabel,'-MCDOSE'); 
+            % this is a MC DOSE
+            if iscell(minput{2,1}) == 1 % this is a MC dose and contains segments contribution
+                disp('Input variable is a MC dose containing segments contribution. Adding segment''s dose');
+                totaldose=dicomrt_addmcdose(minput{2,1}); %add segments' contribution in a 3D minput
+                moutput=minput;
+                moutput{2,1}=totaldose;
+            else
+                moutput=minput;
+            end
+            type='mc';
+            label='MC dose map [Gy]';
+            PatientPositionCODE=dicomrt_getPatientPosition(header);
+        elseif strfind(RTPLabel,'-DDIFF'); 
+            % this is a dose difference
+            moutput=minput;
+            type='ddiff';
+            label='Dose difference';
+            PatientPositionCODE=dicomrt_getPatientPosition(header);
+        elseif strfind(RTPLabel,'-DRATIO'); 
+            % this is a dose ratio
+            moutput=minput;
+            type='dratio';
+            label='Dose ratio';
+            PatientPositionCODE=dicomrt_getPatientPosition(header);
+        else
+            % this is a TPS DOSE
+            moutput=minput;
+            type='RTPLAN';
+            label='RTPLAN dose map [Gy]';
+            PatientPositionCODE=dicomrt_getPatientPosition(header);
+        end
+    end
+elseif isnumeric(minput)==1 % this is a simple 3D matrix
+    moutput=minput;
+    type='other';
+    label=[inputname(1),' matrix'];
+    if force==0
+        warning('dicomrt_checkinput: The input variable is a 3D matrix. Unable to determine Patient Position.');
+        PatientPosition=input('dicomrt_checkinput: Please specify Patient Position: HFS(default),FFS,HFP,FFP: ','s');
+        if isempty(PatientPosition)==1
+            PatientPosition='HFS';
+        end
+        
+        if strcmpi(PatientPosition, 'HFS')
+            PatientPositionCODE = 1;
+        elseif strcmpi(PatientPosition, 'FFS')
+            PatientPositionCODE = 2;
+        elseif strcmpi(PatientPosition, 'HFP')
+            PatientPositionCODE = 3;
+        elseif strcmpi(PatientPosition, 'FFP')
+            PatientPositionCODE = 4;
+        end
+
+    end
+else
+    error('dicomrt_checkinput: Input matrix does not have a supported format. Exit now !');
 end

+ 21 - 21
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_create1dmesh.m

@@ -1,22 +1,22 @@
-function [mesh] = dicomrt_create1dmesh(start,pix,dim,dir)
-% dicomrt_create1dmesh(start,pix,dim,dir)
-%
-% Create one dimensional mesh.
-%
-% See also dicomrt_loadct, dicomrt_loaddose
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-% set up vector dimensions
-mesh=zeros(dim,1);
-
-% create mesh
-if dir == 0 % positive direction
-    for i=1:dim
-        mesh(i)=start+(pix.*double(i))-pix;
-    end
-else % negative direction
-    for i=1:dim
-        mesh(i)=start-(pix.*double(i))+pix;
-    end
+function [mesh] = dicomrt_create1dmesh(start,pix,dim,dir)
+% dicomrt_create1dmesh(start,pix,dim,dir)
+%
+% Create one dimensional mesh.
+%
+% See also dicomrt_loadct, dicomrt_loaddose
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+% set up vector dimensions
+mesh=zeros(dim,1);
+
+% create mesh
+if dir == 0 % positive direction
+    for i=1:dim
+        mesh(i)=start+(pix.*double(i))-pix;
+    end
+else % negative direction
+    for i=1:dim
+        mesh(i)=start-(pix.*double(i))+pix;
+    end
 end

+ 56 - 56
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_getPatientPosition.m

@@ -1,57 +1,57 @@
-function [PatientPositionCODE] = dicomrt_getPatientPosition(study)
-% dicomrt_getPatientPosition(study)
-%
-% Get Patient Position 
-% Return a number (CODE) which correspond to one of the supported cases
-% 
-% Patient Position codes: 
-%
-% Head First Supine (HFS) - CODE=1
-% Feet First Supine (FFS) - CODE=2 
-% Head First Prone  (HFP) - CODE=3
-% Feet First Prone  (FFP) - CODE=4
-% 
-% Example:
-%
-% [B]=dicomrt_getPatientPosition(A)
-%
-% if patient position is HFS, dicomrt_getPatientPosition returns "1" in B.
-%
-% See also: dicomrt_loaddose, dicomrt_ctcreate, dicomrt_createwphantom
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-if iscell(study) == 1 % this is a rtplan warmed for MC export: Patient Position already assigned
-    if size(study,2) > 2
-        CODE=study{1,2}(9);
-    else % this is CT data
-        study=study{1,1};
-    end
-end
-
-if isstruct(study) == 1 
-    if strcmpi(study.Modality,'RTPLAN')
-        try
-            PatientPosition=getfield(study,'PatientSetupSequence','Item_1','PatientPosition');
-        catch
-            PatientPosition=input('dicomrt_getPatientPosition: Please specify Patient Position: HFS(default),FFS,HFP,FFP: ','s');
-            if isempty(PatientPosition)==1
-                PatientPosition='HFS';
-            end
-        end
-    elseif strcmpi(study.Modality,'CT')
-        PatientPosition=getfield(study,'PatientPosition');
-    else
-        error('dicomrt_getPatientPosition: could not retrieve PatientPosition field. Exit now')
-    end
-        
-    if strcmpi(PatientPosition, 'HFS')
-        PatientPositionCODE = 1;
-    elseif strcmpi(PatientPosition, 'FFS')
-        PatientPositionCODE = 2;
-    elseif strcmpi(PatientPosition, 'HFP')
-        PatientPositionCODE = 3;
-    elseif strcmpi(PatientPosition, 'FFP')
-        PatientPositionCODE = 4;
-    end
+function [PatientPositionCODE] = dicomrt_getPatientPosition(study)
+% dicomrt_getPatientPosition(study)
+%
+% Get Patient Position 
+% Return a number (CODE) which correspond to one of the supported cases
+% 
+% Patient Position codes: 
+%
+% Head First Supine (HFS) - CODE=1
+% Feet First Supine (FFS) - CODE=2 
+% Head First Prone  (HFP) - CODE=3
+% Feet First Prone  (FFP) - CODE=4
+% 
+% Example:
+%
+% [B]=dicomrt_getPatientPosition(A)
+%
+% if patient position is HFS, dicomrt_getPatientPosition returns "1" in B.
+%
+% See also: dicomrt_loaddose, dicomrt_ctcreate, dicomrt_createwphantom
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+if iscell(study) == 1 % this is a rtplan warmed for MC export: Patient Position already assigned
+    if size(study,2) > 2
+        CODE=study{1,2}(9);
+    else % this is CT data
+        study=study{1,1};
+    end
+end
+
+if isstruct(study) == 1 
+    if strcmpi(study.Modality,'RTPLAN')
+        try
+            PatientPosition=getfield(study,'PatientSetupSequence','Item_1','PatientPosition');
+        catch
+            PatientPosition=input('dicomrt_getPatientPosition: Please specify Patient Position: HFS(default),FFS,HFP,FFP: ','s');
+            if isempty(PatientPosition)==1
+                PatientPosition='HFS';
+            end
+        end
+    elseif strcmpi(study.Modality,'CT')
+        PatientPosition=getfield(study,'PatientPosition');
+    else
+        error('dicomrt_getPatientPosition: could not retrieve PatientPosition field. Exit now')
+    end
+        
+    if strcmpi(PatientPosition, 'HFS')
+        PatientPositionCODE = 1;
+    elseif strcmpi(PatientPosition, 'FFS')
+        PatientPositionCODE = 2;
+    elseif strcmpi(PatientPosition, 'HFP')
+        PatientPositionCODE = 3;
+    elseif strcmpi(PatientPosition, 'FFP')
+        PatientPositionCODE = 4;
+    end
 end

+ 212 - 212
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_loadct.m

@@ -1,212 +1,212 @@
-function [ctcell,ct_xmesh,ct_ymesh,ct_zmesh] = dicomrt_loadct(filename,sorting)
-% dicomrt_loadct(filename,sorting)
-%
-% Read dicom CT for a case using MATLAB native function dicomread. Light Version.
-%
-% filename contains a list of CT slices to import
-%
-% CT are stored in a single 3D matrix: case_study
-% x-y-z coordinates of the center of the ct-pixel are stored in ct_xmesh, ct_ymesh and ct_zmesh.
-%
-% NOTE:  CT numbers range from -1000 for air to 1000 for bone with that for water set to 0.
-% CT numbers normalized in this manner are called Hounfield numbers or units (HU):
-%
-% HU = ((mu_tissue-mu_water)/mu_water)*1000
-%
-% Following DICOM RT standard HU = m*(SV)+b where m is RescaleSlope, b RescaleIntercept
-% and SV are pixel (stored) values.
-%
-% Often CT scale is shifted so that HU(water)=1000 (=CToffset) instead of 0.
-%
-% NOTE: as opposed to dicomrt_loadct ct_xmesh, ct_ymesh and ct_zmesh are vectors and not
-% matrices. This allow to run this functions also in "low" memory pcs.
-%
-% See also dicomrt_loaddose, dicomrt_getPatientPosition
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
-
-% Sort CT slices first
-%
-% load ct slices info
-
-% Check number of argument and set-up some parameters and variables
-error(nargchk(1,2,nargin))
-
-if exist('sorting')==0
-    sorting=1; % perform sorting check
-end
-
-% Retrieve the number of images
-nlines=dicomrt_nASCIIlines(filename);
-
-if nlines>1
-    disp('Loading CT slice information ...');
-    [filelist,xlocation,ylocation,zlocation,modifUID,user_request] = dicomrt_loadctlist(filename);
-    if user_request==1;
-        return
-    end
-    disp('CT slice information loaded.');
-
-    if sorting==1
-        % sort ct slices
-        disp('Sorting CT slices ...');
-        [modifZ,user_request]=dicomrt_sortct(filelist,xlocation,ylocation,zlocation,filename);
-        if user_request==1;
-            return
-        end
-        disp('CT slices sorted.');
-    else
-        modifZ=0;
-        modifUID=0;
-    end
-
-    if modifZ~=0 | modifUID~=0 % a modification to the filelist was made by dicomrt_sortct
-        filename_sorted=[filename,'.sort.txt'];
-    else % no modification have been made
-        filename_sorted=filename;
-    end
-else
-    disp('Loading one image. Zmesh will have no sense. Slice position can be loaded using dicominfo.');
-    filename_sorted=filename;
-end
-
-% Now get CT images and create 3D Volume
-
-% Set parameters 
-CToffset=1000;  % CT offset!
-% CToffset=0;  % CT offset!
-nct=0;
-
-% Define cell array to store info
-case_study_info=cell(1);
-
-%loop until the end-of-file is reached and build 3D CT matrix
-disp('Loading ct volume ...');
-
-% Progress bar
-h = waitbar(0,['Loading progress:']);
-set(h,'Name','dicomrt_loadct: loading CT images');
-
-fid=fopen(filename_sorted);
-
-while (feof(fid)~=1);
-    clear info_temp temp
-    nct=nct+1; % counting
-    nctcheck=nct; % check for eof
-    ct_file_location{1,nct}=fgetl(fid);
-    if isnumeric(ct_file_location{1,nct}), nct=nct-1; break, end %end of line reached
-    
-    temp=dicomread(deblank(ct_file_location{1,nct}));
-
-    dictFlg = checkDictUse;
-    if dictFlg
-        info_temp=dicominfo(deblank(ct_file_location{1,nct}),'dictionary', 'ES - IPT4.1CompatibleDictionary.mat');
-    else
-        info_temp=dicominfo(deblank(ct_file_location{1,nct}));
-    end
-
-
-    zmesh(nct)=info_temp.ImagePositionPatient(3);
-    
-    if isfield(info_temp,'RescaleSlope')~=0 | isfield(info_temp,'RescaleIntercept')~=0
-        temp=double(temp)*info_temp.RescaleSlope+info_temp.RescaleIntercept+CToffset;
-    else
-        warning('dicomrt_loadct: no DICOM Rescale data were found. Assuming RescaleSlope = 1, RescaleIntercept = 0 and CToffset = 1000');
-        temp=double(temp);
-    end
-    
-    case_study_info{nct}=info_temp;
-    case_study(:,:,nct)=uint16(temp);
-    waitbar(nct/nlines,h);
-end
-
-% Make zmesh a column vector
-zmesh=dicomrt_makevertical(zmesh);
-
-fclose(fid);
-
-if nctcheck~=nct;
-    warning('dicomrt_loadct: End of file was prematurely reached. Check the expected dimensions of your data. It may be OK to continue');
-end
-
-[PatientPositionCODE]=dicomrt_getPatientPosition(info_temp);
-
-% PatientOrientation     ImageOrientationPatient
-%
-% HFS                    (1,0,0) (0,1,0)
-% FFS                    (1,0,0) (0,1,0)
-% HFP                    (-1,0,0) (0,-1,0)
-% FFP                    (-1,0,0) (0,-1,0)
-%
-%
-if PatientPositionCODE == 1 | PatientPositionCODE == 2
-    min_x=info_temp.ImagePositionPatient(1);
-    pixel_spacing_x=info_temp.PixelSpacing(1);
-
-    min_y=info_temp.ImagePositionPatient(2);
-    pixel_spacing_y=info_temp.PixelSpacing(2);
-
-    [xmesh] = dicomrt_create1dmesh(min_x,pixel_spacing_x,size(temp,2),0);
-    [ymesh] = dicomrt_create1dmesh(min_y,pixel_spacing_y,size(temp,1),0);
-
-else
-    max_x=info_temp.ImagePositionPatient(1);
-    pixel_spacing_x=info_temp.PixelSpacing(1);
-
-    max_y=info_temp.ImagePositionPatient(2);
-    pixel_spacing_y=info_temp.PixelSpacing(2);
-
-    [xmesh] = dicomrt_create1dmesh(max_x,pixel_spacing_x,size(temp,1),1);
-    [ymesh] = dicomrt_create1dmesh(max_y,pixel_spacing_y,size(temp,2),1);
-
-end
-
-ct_zmesh=dicomrt_mmdigit(zmesh*0.1,7);
-ct_ymesh=dicomrt_mmdigit(ymesh*0.1,7);
-ct_xmesh=dicomrt_mmdigit(xmesh*0.1,7);
-
-disp('Loading complete ...');
-
-% 3D CT matrix and mesh matrix imported
-%
-% Some CT images info have private tags or fragmented info.
-% If so, go into manual mode.
-%
-
-% Check support for current Patient Position
-if PatientPositionCODE == 1 % supported Patient Position: HFS
-    disp('dicomrt_loadct: Patient Position is Head First Supine (HFS).');
-elseif PatientPositionCODE == 2 % supported Patient Position: FFS
-    disp('dicomrt_loadct: Patient Position is Feet First Supine (FFS).');
-elseif PatientPositionCODE == 3 % unsupported Patient Position: HFP
-    disp('dicomrt_loadct: Patient Position is Head First Prone (HFP).');
-elseif PatientPositionCODE == 4 % unsupported Patient Position: FFP
-    disp('dicomrt_loadct: Patient Position is Feet First Prone (FFP).');
-else
-    warning('Unable to determine Patient Position');
-    PatientPosition=input('dicomrt_loadct: Please specify Patient Position: HFS(default),FFS,HFP,FFP: ','s');
-    if isempty(PatientPosition)==1
-        PatientPosition='HFS';
-    end
-
-    if strcmpi(PatientPosition, 'HFS')
-        PatientPositionCODE = 1;
-    elseif strcmpi(PatientPosition, 'FFS')
-        PatientPositionCODE = 2;
-    elseif strcmpi(PatientPosition, 'HFP')
-        PatientPositionCODE = 3;
-    elseif strcmpi(PatientPosition, 'FFP')
-        PatientPositionCODE = 4;
-    end
-
-end
-
-% Create cell array
-ctcell=cell(3,1);
-ctcell{1,1}=case_study_info;
-ctcell{2,1}=case_study;
-ctcell{3,1}=[];
-
-% Close progress bar
-close(h);
-pack
+function [ctcell,ct_xmesh,ct_ymesh,ct_zmesh] = dicomrt_loadct(filename,sorting)
+% dicomrt_loadct(filename,sorting)
+%
+% Read dicom CT for a case using MATLAB native function dicomread. Light Version.
+%
+% filename contains a list of CT slices to import
+%
+% CT are stored in a single 3D matrix: case_study
+% x-y-z coordinates of the center of the ct-pixel are stored in ct_xmesh, ct_ymesh and ct_zmesh.
+%
+% NOTE:  CT numbers range from -1000 for air to 1000 for bone with that for water set to 0.
+% CT numbers normalized in this manner are called Hounfield numbers or units (HU):
+%
+% HU = ((mu_tissue-mu_water)/mu_water)*1000
+%
+% Following DICOM RT standard HU = m*(SV)+b where m is RescaleSlope, b RescaleIntercept
+% and SV are pixel (stored) values.
+%
+% Often CT scale is shifted so that HU(water)=1000 (=CToffset) instead of 0.
+%
+% NOTE: as opposed to dicomrt_loadct ct_xmesh, ct_ymesh and ct_zmesh are vectors and not
+% matrices. This allow to run this functions also in "low" memory pcs.
+%
+% See also dicomrt_loaddose, dicomrt_getPatientPosition
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
+
+% Sort CT slices first
+%
+% load ct slices info
+
+% Check number of argument and set-up some parameters and variables
+error(nargchk(1,2,nargin))
+
+if exist('sorting')==0
+    sorting=1; % perform sorting check
+end
+
+% Retrieve the number of images
+nlines=dicomrt_nASCIIlines(filename);
+
+if nlines>1
+    disp('Loading CT slice information ...');
+    [filelist,xlocation,ylocation,zlocation,modifUID,user_request] = dicomrt_loadctlist(filename);
+    if user_request==1;
+        return
+    end
+    disp('CT slice information loaded.');
+
+    if sorting==1
+        % sort ct slices
+        disp('Sorting CT slices ...');
+        [modifZ,user_request]=dicomrt_sortct(filelist,xlocation,ylocation,zlocation,filename);
+        if user_request==1;
+            return
+        end
+        disp('CT slices sorted.');
+    else
+        modifZ=0;
+        modifUID=0;
+    end
+
+    if modifZ~=0 | modifUID~=0 % a modification to the filelist was made by dicomrt_sortct
+        filename_sorted=[filename,'.sort.txt'];
+    else % no modification have been made
+        filename_sorted=filename;
+    end
+else
+    disp('Loading one image. Zmesh will have no sense. Slice position can be loaded using dicominfo.');
+    filename_sorted=filename;
+end
+
+% Now get CT images and create 3D Volume
+
+% Set parameters 
+CToffset=1000;  % CT offset!
+% CToffset=0;  % CT offset!
+nct=0;
+
+% Define cell array to store info
+case_study_info=cell(1);
+
+%loop until the end-of-file is reached and build 3D CT matrix
+disp('Loading ct volume ...');
+
+% Progress bar
+h = waitbar(0,['Loading progress:']);
+set(h,'Name','dicomrt_loadct: loading CT images');
+
+fid=fopen(filename_sorted);
+
+while (feof(fid)~=1);
+    clear info_temp temp
+    nct=nct+1; % counting
+    nctcheck=nct; % check for eof
+    ct_file_location{1,nct}=fgetl(fid);
+    if isnumeric(ct_file_location{1,nct}), nct=nct-1; break, end %end of line reached
+    
+    temp=dicomread(deblank(ct_file_location{1,nct}));
+
+    dictFlg = checkDictUse;
+    if dictFlg
+        info_temp=dicominfo(deblank(ct_file_location{1,nct}),'dictionary', 'ES - IPT4.1CompatibleDictionary.mat');
+    else
+        info_temp=dicominfo(deblank(ct_file_location{1,nct}));
+    end
+
+
+    zmesh(nct)=info_temp.ImagePositionPatient(3);
+    
+    if isfield(info_temp,'RescaleSlope')~=0 | isfield(info_temp,'RescaleIntercept')~=0
+        temp=double(temp)*info_temp.RescaleSlope+info_temp.RescaleIntercept+CToffset;
+    else
+        warning('dicomrt_loadct: no DICOM Rescale data were found. Assuming RescaleSlope = 1, RescaleIntercept = 0 and CToffset = 1000');
+        temp=double(temp);
+    end
+    
+    case_study_info{nct}=info_temp;
+    case_study(:,:,nct)=uint16(temp);
+    waitbar(nct/nlines,h);
+end
+
+% Make zmesh a column vector
+zmesh=dicomrt_makevertical(zmesh);
+
+fclose(fid);
+
+if nctcheck~=nct;
+    warning('dicomrt_loadct: End of file was prematurely reached. Check the expected dimensions of your data. It may be OK to continue');
+end
+
+[PatientPositionCODE]=dicomrt_getPatientPosition(info_temp);
+
+% PatientOrientation     ImageOrientationPatient
+%
+% HFS                    (1,0,0) (0,1,0)
+% FFS                    (1,0,0) (0,1,0)
+% HFP                    (-1,0,0) (0,-1,0)
+% FFP                    (-1,0,0) (0,-1,0)
+%
+%
+if PatientPositionCODE == 1 | PatientPositionCODE == 2
+    min_x=info_temp.ImagePositionPatient(1);
+    pixel_spacing_x=info_temp.PixelSpacing(1);
+
+    min_y=info_temp.ImagePositionPatient(2);
+    pixel_spacing_y=info_temp.PixelSpacing(2);
+
+    [xmesh] = dicomrt_create1dmesh(min_x,pixel_spacing_x,size(temp,2),0);
+    [ymesh] = dicomrt_create1dmesh(min_y,pixel_spacing_y,size(temp,1),0);
+
+else
+    max_x=info_temp.ImagePositionPatient(1);
+    pixel_spacing_x=info_temp.PixelSpacing(1);
+
+    max_y=info_temp.ImagePositionPatient(2);
+    pixel_spacing_y=info_temp.PixelSpacing(2);
+
+    [xmesh] = dicomrt_create1dmesh(max_x,pixel_spacing_x,size(temp,1),1);
+    [ymesh] = dicomrt_create1dmesh(max_y,pixel_spacing_y,size(temp,2),1);
+
+end
+
+ct_zmesh=dicomrt_mmdigit(zmesh*0.1,7);
+ct_ymesh=dicomrt_mmdigit(ymesh*0.1,7);
+ct_xmesh=dicomrt_mmdigit(xmesh*0.1,7);
+
+disp('Loading complete ...');
+
+% 3D CT matrix and mesh matrix imported
+%
+% Some CT images info have private tags or fragmented info.
+% If so, go into manual mode.
+%
+
+% Check support for current Patient Position
+if PatientPositionCODE == 1 % supported Patient Position: HFS
+    disp('dicomrt_loadct: Patient Position is Head First Supine (HFS).');
+elseif PatientPositionCODE == 2 % supported Patient Position: FFS
+    disp('dicomrt_loadct: Patient Position is Feet First Supine (FFS).');
+elseif PatientPositionCODE == 3 % unsupported Patient Position: HFP
+    disp('dicomrt_loadct: Patient Position is Head First Prone (HFP).');
+elseif PatientPositionCODE == 4 % unsupported Patient Position: FFP
+    disp('dicomrt_loadct: Patient Position is Feet First Prone (FFP).');
+else
+    warning('Unable to determine Patient Position');
+    PatientPosition=input('dicomrt_loadct: Please specify Patient Position: HFS(default),FFS,HFP,FFP: ','s');
+    if isempty(PatientPosition)==1
+        PatientPosition='HFS';
+    end
+
+    if strcmpi(PatientPosition, 'HFS')
+        PatientPositionCODE = 1;
+    elseif strcmpi(PatientPosition, 'FFS')
+        PatientPositionCODE = 2;
+    elseif strcmpi(PatientPosition, 'HFP')
+        PatientPositionCODE = 3;
+    elseif strcmpi(PatientPosition, 'FFP')
+        PatientPositionCODE = 4;
+    end
+
+end
+
+% Create cell array
+ctcell=cell(3,1);
+ctcell{1,1}=case_study_info;
+ctcell{2,1}=case_study;
+ctcell{3,1}=[];
+
+% Close progress bar
+close(h);
+pack

+ 186 - 186
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_loadctlist.m

@@ -1,187 +1,187 @@
-function [filelistAXIAL,xlocationAXIAL,ylocationAXIAL,zlocationAXIAL,change,user_option] = dicomrt_loadctlist(filename)
-% dicomrt_loadctlist(filename)
-%
-% Parse CT data set specified in filename. If more than one study are found within the CT data set
-% the user can select a study and dicomrt_loadctlist return a filelist and x,y,z coordinates of the
-% selected CT subset
-%
-% filename contains a list of CT slices to import
-%
-% change is 1 if any change to the filelist have been done, 0 otherwise
-% user_option is 1 if the user select not to continue with the program, 0 otherwise
-%
-% Example:
-% [list,x,y,z,change,user_option]=dicomrt_loadctlist(filename)
-%
-% with filename containint the following:
-% ct1 (group1)
-% ct2 (group2)
-% ct3 (group1)
-% ct4 (group2)
-%
-% if the user select one of them (e.g. group1):
-% list= contain only ct1 and ct3,
-% x= xlocation of ct1 and ct3 ,
-% y= ylocation of ct1 and ct3 ,
-% z= zlocation of ct1 and ct3 ,
-% change= 1,
-% user_option= 0
-%
-% See also dicomrt_loaddose dicomrt_loadct dicomrt_sortct
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
-
-% Retrieve the number of images
-nlines=dicomrt_nASCIIlines(filename);
-
-% Get CT images and create 3D Volume
-fid=fopen(filename);
-nct=0;
-counter=0;
-
-% Initialize variable
-filelist=' ';
-studyUIDlist=' ';
-listUID=' ';
-imagetype=' ';
-user_option=0;
-
-% Progress bar
-h = waitbar(0,['Loading progress:']);
-set(h,'Name','dicomrt_loadctlist: loading CT objects tags');
-
-%loop until the end-of-file is reached and build 3D CT matrix
-while (feof(fid)~=1);
-    nct=nct+1; % counting
-
-    nctcheck=nct; % check for eof
-
-    ct_file_location{1,nct}=fgetl(fid);
-
-    if isnumeric(ct_file_location{1,nct}), nct=nct-1, break, end %end of line reached
-
-    dictFlg = checkDictUse;
-    if dictFlg
-        info_temp=dicominfo(ct_file_location{1,nct}, 'dictionary', 'ES - IPT4.1CompatibleDictionary.mat');
-    else
-        info_temp=dicominfo(ct_file_location{1,nct});
-    end
-
-
-
-    xlocation(nct)=info_temp.ImagePositionPatient(1);
-    ylocation(nct)=info_temp.ImagePositionPatient(2);
-    zlocation(nct)=info_temp.ImagePositionPatient(3);
-
-    xlocation=xlocation';
-    ylocation=ylocation';
-    zlocation=zlocation';
-
-    filelist=char(filelist,info_temp.Filename);
-
-    if isfield(info_temp,'ImageType')~=1
-        warning('dicomrt_loadctlist: no DICOM ImageType was found. Assuming AXIAL CT Images');
-        imagetype='AXIAL';
-    else
-        imagetype=char(imagetype,info_temp.ImageType);
-    end
-
-    listUID=char(listUID,info_temp.StudyInstanceUID);
-
-    studyUID=info_temp.StudyInstanceUID;
-    if isequal(studyUID, studyUIDlist(size(studyUIDlist,1),:))==0
-        studyUIDlist=char(studyUIDlist,studyUID);
-    end
-    waitbar(nct/nlines,h);
-end
-filelist(1,:)=[];
-studyUIDlist(1,:)=[];
-listUID(1,:)=[];
-imagetype(1,:)=[];
-
-if size(studyUIDlist,1)>=2
-    change=1;
-    disp(' ');
-    warning([int2str(size(studyUIDlist,1)),' studies was found among the ct slices you want to import']);
-    disp(' ');
-    leave = input('Do you want to leave (Y/N) ? [N] ','s');
-    if leave == 'Y' | leave == 'y';
-        user_option=1;
-        return
-    else
-        disp('Available studies:');
-        for j=1:size(studyUIDlist,1)
-            disp([int2str(j), ' - ', studyUIDlist(j,:)]);
-        end
-        chooseUID = input(['Select a study to be imported from 1 to ',int2str(size(studyUIDlist,1)),': ']);
-        if isempty(chooseUID)==1 | isnumeric(chooseUID)~=1 | chooseUID>size(studyUIDlist,1)
-            error('dicomrt_loadctlist: There is no default to this answer or the number to entered is invalid. Exit now !');
-            user_option=1;
-        else
-            filelistUID=' ';
-            imagetypeUID=' ';
-            for k=1:size(filelist,1)
-                if listUID(k,:)==studyUIDlist(chooseUID,:);
-                    counter=counter+1;
-                    filelistUID=char(filelistUID,filelist(k,:));
-                    imagetypeUID=char(imagetypeUID,imagetype(k,:));
-                    xlocationUID(counter)=xlocation(k);
-                    ylocationUID(counter)=ylocation(k);
-                    zlocationUID(counter)=zlocation(k);
-                end
-            end
-            filelistUID(1,:)=[];
-            imagetypeUID(1,:)=[];
-            counter=0; % reset counter
-        end
-    end
-else
-    filelistUID=filelist;
-    imagetypeUID=imagetype;
-    xlocationUID=xlocation;
-    ylocationUID=ylocation;
-    zlocationUID=zlocation;
-end
-
-% Check for scout images (not AXIAL)
-imagetypeAXIAL=' ';
-filelistAXIAL=' ';
-
-for i=1:size(filelistUID,1)
-    if isempty(findstr('AXIAL',imagetypeUID(i,:)))==1 % Scout image found
-        disp(['The following image :',filelistUID(i,:),' is not AXIAL. Skipped ...']);
-        change=1; % just make sure we return alterations to the filelist
-    else
-        counter=counter+1;
-        imagetypeAXIAL=char(imagetypeAXIAL,imagetypeUID(i,:));
-        filelistAXIAL=char(filelistAXIAL,filelistUID(i,:));
-        xlocationAXIAL(counter)=xlocationUID(i);
-        ylocationAXIAL(counter)=ylocationUID(i);
-        zlocationAXIAL(counter)=zlocationUID(i);
-    end
-end
-
-if exist('change')~=1
-    change=0;
-end
-
-filelistAXIAL(1,:)=[];
-imagetypeAXIAL(1,:)=[];
-
-if change ==1 % export changes to file
-    newfilename=[filename,'.sort.txt'];
-    newfile=fopen(newfilename,'w');
-
-    for i=1:size(filelistAXIAL,1)
-        fprintf(newfile,'%c',deblank(filelistAXIAL(i,:))); fprintf(newfile,'\n');
-    end
-
-    disp(['A new file list has been written by dicomrt_loadctlist with name: ',newfilename]);
-    disp('This file will be used to import ct data instead');
-
-    fclose(newfile);
-end
-
-% Close progress bar
-close(h);
+function [filelistAXIAL,xlocationAXIAL,ylocationAXIAL,zlocationAXIAL,change,user_option] = dicomrt_loadctlist(filename)
+% dicomrt_loadctlist(filename)
+%
+% Parse CT data set specified in filename. If more than one study are found within the CT data set
+% the user can select a study and dicomrt_loadctlist return a filelist and x,y,z coordinates of the
+% selected CT subset
+%
+% filename contains a list of CT slices to import
+%
+% change is 1 if any change to the filelist have been done, 0 otherwise
+% user_option is 1 if the user select not to continue with the program, 0 otherwise
+%
+% Example:
+% [list,x,y,z,change,user_option]=dicomrt_loadctlist(filename)
+%
+% with filename containint the following:
+% ct1 (group1)
+% ct2 (group2)
+% ct3 (group1)
+% ct4 (group2)
+%
+% if the user select one of them (e.g. group1):
+% list= contain only ct1 and ct3,
+% x= xlocation of ct1 and ct3 ,
+% y= ylocation of ct1 and ct3 ,
+% z= zlocation of ct1 and ct3 ,
+% change= 1,
+% user_option= 0
+%
+% See also dicomrt_loaddose dicomrt_loadct dicomrt_sortct
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
+
+% Retrieve the number of images
+nlines=dicomrt_nASCIIlines(filename);
+
+% Get CT images and create 3D Volume
+fid=fopen(filename);
+nct=0;
+counter=0;
+
+% Initialize variable
+filelist=' ';
+studyUIDlist=' ';
+listUID=' ';
+imagetype=' ';
+user_option=0;
+
+% Progress bar
+h = waitbar(0,['Loading progress:']);
+set(h,'Name','dicomrt_loadctlist: loading CT objects tags');
+
+%loop until the end-of-file is reached and build 3D CT matrix
+while (feof(fid)~=1);
+    nct=nct+1; % counting
+
+    nctcheck=nct; % check for eof
+
+    ct_file_location{1,nct}=fgetl(fid);
+
+    if isnumeric(ct_file_location{1,nct}), nct=nct-1, break, end %end of line reached
+
+    dictFlg = checkDictUse;
+    if dictFlg
+        info_temp=dicominfo(ct_file_location{1,nct}, 'dictionary', 'ES - IPT4.1CompatibleDictionary.mat');
+    else
+        info_temp=dicominfo(ct_file_location{1,nct});
+    end
+
+
+
+    xlocation(nct)=info_temp.ImagePositionPatient(1);
+    ylocation(nct)=info_temp.ImagePositionPatient(2);
+    zlocation(nct)=info_temp.ImagePositionPatient(3);
+
+    xlocation=xlocation';
+    ylocation=ylocation';
+    zlocation=zlocation';
+
+    filelist=char(filelist,info_temp.Filename);
+
+    if isfield(info_temp,'ImageType')~=1
+        warning('dicomrt_loadctlist: no DICOM ImageType was found. Assuming AXIAL CT Images');
+        imagetype='AXIAL';
+    else
+        imagetype=char(imagetype,info_temp.ImageType);
+    end
+
+    listUID=char(listUID,info_temp.StudyInstanceUID);
+
+    studyUID=info_temp.StudyInstanceUID;
+    if isequal(studyUID, studyUIDlist(size(studyUIDlist,1),:))==0
+        studyUIDlist=char(studyUIDlist,studyUID);
+    end
+    waitbar(nct/nlines,h);
+end
+filelist(1,:)=[];
+studyUIDlist(1,:)=[];
+listUID(1,:)=[];
+imagetype(1,:)=[];
+
+if size(studyUIDlist,1)>=2
+    change=1;
+    disp(' ');
+    warning([int2str(size(studyUIDlist,1)),' studies was found among the ct slices you want to import']);
+    disp(' ');
+    leave = input('Do you want to leave (Y/N) ? [N] ','s');
+    if leave == 'Y' | leave == 'y';
+        user_option=1;
+        return
+    else
+        disp('Available studies:');
+        for j=1:size(studyUIDlist,1)
+            disp([int2str(j), ' - ', studyUIDlist(j,:)]);
+        end
+        chooseUID = input(['Select a study to be imported from 1 to ',int2str(size(studyUIDlist,1)),': ']);
+        if isempty(chooseUID)==1 | isnumeric(chooseUID)~=1 | chooseUID>size(studyUIDlist,1)
+            error('dicomrt_loadctlist: There is no default to this answer or the number to entered is invalid. Exit now !');
+            user_option=1;
+        else
+            filelistUID=' ';
+            imagetypeUID=' ';
+            for k=1:size(filelist,1)
+                if listUID(k,:)==studyUIDlist(chooseUID,:);
+                    counter=counter+1;
+                    filelistUID=char(filelistUID,filelist(k,:));
+                    imagetypeUID=char(imagetypeUID,imagetype(k,:));
+                    xlocationUID(counter)=xlocation(k);
+                    ylocationUID(counter)=ylocation(k);
+                    zlocationUID(counter)=zlocation(k);
+                end
+            end
+            filelistUID(1,:)=[];
+            imagetypeUID(1,:)=[];
+            counter=0; % reset counter
+        end
+    end
+else
+    filelistUID=filelist;
+    imagetypeUID=imagetype;
+    xlocationUID=xlocation;
+    ylocationUID=ylocation;
+    zlocationUID=zlocation;
+end
+
+% Check for scout images (not AXIAL)
+imagetypeAXIAL=' ';
+filelistAXIAL=' ';
+
+for i=1:size(filelistUID,1)
+    if isempty(findstr('AXIAL',imagetypeUID(i,:)))==1 % Scout image found
+        disp(['The following image :',filelistUID(i,:),' is not AXIAL. Skipped ...']);
+        change=1; % just make sure we return alterations to the filelist
+    else
+        counter=counter+1;
+        imagetypeAXIAL=char(imagetypeAXIAL,imagetypeUID(i,:));
+        filelistAXIAL=char(filelistAXIAL,filelistUID(i,:));
+        xlocationAXIAL(counter)=xlocationUID(i);
+        ylocationAXIAL(counter)=ylocationUID(i);
+        zlocationAXIAL(counter)=zlocationUID(i);
+    end
+end
+
+if exist('change')~=1
+    change=0;
+end
+
+filelistAXIAL(1,:)=[];
+imagetypeAXIAL(1,:)=[];
+
+if change ==1 % export changes to file
+    newfilename=[filename,'.sort.txt'];
+    newfile=fopen(newfilename,'w');
+
+    for i=1:size(filelistAXIAL,1)
+        fprintf(newfile,'%c',deblank(filelistAXIAL(i,:))); fprintf(newfile,'\n');
+    end
+
+    disp(['A new file list has been written by dicomrt_loadctlist with name: ',newfilename]);
+    disp('This file will be used to import ct data instead');
+
+    fclose(newfile);
+end
+
+% Close progress bar
+close(h);
 clear info_temp

+ 105 - 105
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_loadvoi.m

@@ -1,105 +1,105 @@
-function [cellVOI] = dicomrt_loadvoi(rtstruct_filename)
-% dicomrt_loadvoi(rtstruct_filename)
-%
-% Load Volumes Of Interests (VOIs) from dicom-rt export file.
-%
-% A=dicomrt_dvhcal('rtstruct_filename') load into A the VOIs
-% extracted from the file 'rtstruct_filename'
-%
-% VOIs are stored in a cell array with the following structure:
-%
-%  -----------------------------
-%  | [OAR 1] | [xyz contour 1] |
-%  |         -------------------
-%  |         | [xyz contour 2] |
-%  |         -------------------
-%  |         |     ...         |
-%  |         -------------------
-%  |         | [xyz contour n] |
-%  -----------------------------
-%  |   ...   |     ...         |
-%  -----------------------------
-%  | [OAR n] | [xyz contour 1] |
-%  |         -------------------
-%  |         | [xyz contour 2] |
-%  |         -------------------
-%  |         |     ...         |
-%  |         -------------------
-%  |         | [xyz contour n] |
-%  -----------------------------
-%
-%
-% See also dicomrt_loaddose, dicomrt_loadct, dicomrt_dvhcal
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
-
-% Get info file
-
-dictFlg = checkDictUse;
-if dictFlg
-    rtstruct=dicominfo(rtstruct_filename,'dictionary', 'ES - IPT4.1CompatibleDictionary.mat');
-else
-    rtstruct=dicominfo(rtstruct_filename);
-end
-
-
-%rtstruct=rtstruct_filename;
-% Get number of VOIs
-ROIContourSequence=fieldnames(rtstruct.ROIContourSequence);
-
-% Define cell array
-VOI=cell(size(ROIContourSequence,1),2);
-
-% Progress bar
-h = waitbar(0,['Loading progress:']);
-set(h,'Name','dicomrt_loadvoi: loading RTSTRUCT objects');
-
-for i=1:size(ROIContourSequence,1) % for i=1:(number of VOIs) ...
-    voilabel=getfield(rtstruct.StructureSetROISequence,char(ROIContourSequence(i)),'ROIName');
-    VOI{i,1}=voilabel; % get VOI's name
-
-    try
-        ncont_temp=fieldnames(getfield(rtstruct.ROIContourSequence,char(ROIContourSequence(i)), ...
-            'ContourSequence')); % get contour list per each VOI (temporary variable)
-    catch
-        warning(['ContourSequence not found for ROI: ', voilabel]);
-        ncont_temp = [];
-    end
-
-    switch isempty(ncont_temp)
-        case 0
-            for j=1:size(ncont_temp,1) % for j=1:(number of contours) ...
-                if j==1
-                    VOI{i,2}=cell(size(ncont_temp,1),1);
-                end
-                try
-                    NumberOfContourPoints=getfield(rtstruct.ROIContourSequence,char(ROIContourSequence(i)), ...
-                        'ContourSequence', char(ncont_temp(j)),'NumberOfContourPoints');
-                    ContourData=getfield(rtstruct.ROIContourSequence,char(ROIContourSequence(i)), ...
-                        'ContourSequence',char(ncont_temp(j)),'ContourData');
-                    x=dicomrt_mmdigit(ContourData(1:3:NumberOfContourPoints*3)*0.1,7);
-                    y=dicomrt_mmdigit(ContourData(2:3:NumberOfContourPoints*3)*0.1,7);
-                    z=dicomrt_mmdigit(ContourData(3:3:NumberOfContourPoints*3)*0.1,7);
-                    VOI{i,2}{j,1}=cat(2,x,y,z); % this is the same as VOI{i,2}{j,1}=[x,y,z];
-                end
-            end
-        case 1
-            % set dummy values. This will be deleted later dugin the import
-            NumberOfContourPoints=1;
-            ContourData=[0,0,0];
-            x=0;
-            y=0;
-            z=0;
-            VOI{i,2}{1,1}=cat(2,x,y,z);
-    end
-    waitbar(i/size(ROIContourSequence,1),h);
-    ncont_temp=[];
-end
-% VOI cell generation complete
-% Store VOI in a cell array
-cellVOI=cell(3,1);
-cellVOI{1,1}=rtstruct;
-cellVOI{2,1}=VOI;
-cellVOI{3,1}=[];
-% Close progress bar
-close(h);
+function [cellVOI] = dicomrt_loadvoi(rtstruct_filename)
+% dicomrt_loadvoi(rtstruct_filename)
+%
+% Load Volumes Of Interests (VOIs) from dicom-rt export file.
+%
+% A=dicomrt_dvhcal('rtstruct_filename') load into A the VOIs
+% extracted from the file 'rtstruct_filename'
+%
+% VOIs are stored in a cell array with the following structure:
+%
+%  -----------------------------
+%  | [OAR 1] | [xyz contour 1] |
+%  |         -------------------
+%  |         | [xyz contour 2] |
+%  |         -------------------
+%  |         |     ...         |
+%  |         -------------------
+%  |         | [xyz contour n] |
+%  -----------------------------
+%  |   ...   |     ...         |
+%  -----------------------------
+%  | [OAR n] | [xyz contour 1] |
+%  |         -------------------
+%  |         | [xyz contour 2] |
+%  |         -------------------
+%  |         |     ...         |
+%  |         -------------------
+%  |         | [xyz contour n] |
+%  -----------------------------
+%
+%
+% See also dicomrt_loaddose, dicomrt_loadct, dicomrt_dvhcal
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
+
+% Get info file
+
+dictFlg = checkDictUse;
+if dictFlg
+    rtstruct=dicominfo(rtstruct_filename,'dictionary', 'ES - IPT4.1CompatibleDictionary.mat');
+else
+    rtstruct=dicominfo(rtstruct_filename);
+end
+
+
+%rtstruct=rtstruct_filename;
+% Get number of VOIs
+ROIContourSequence=fieldnames(rtstruct.ROIContourSequence);
+
+% Define cell array
+VOI=cell(size(ROIContourSequence,1),2);
+
+% Progress bar
+h = waitbar(0,['Loading progress:']);
+set(h,'Name','dicomrt_loadvoi: loading RTSTRUCT objects');
+
+for i=1:size(ROIContourSequence,1) % for i=1:(number of VOIs) ...
+    voilabel=getfield(rtstruct.StructureSetROISequence,char(ROIContourSequence(i)),'ROIName');
+    VOI{i,1}=voilabel; % get VOI's name
+
+    try
+        ncont_temp=fieldnames(getfield(rtstruct.ROIContourSequence,char(ROIContourSequence(i)), ...
+            'ContourSequence')); % get contour list per each VOI (temporary variable)
+    catch
+        warning(['ContourSequence not found for ROI: ', voilabel]);
+        ncont_temp = [];
+    end
+
+    switch isempty(ncont_temp)
+        case 0
+            for j=1:size(ncont_temp,1) % for j=1:(number of contours) ...
+                if j==1
+                    VOI{i,2}=cell(size(ncont_temp,1),1);
+                end
+                try
+                    NumberOfContourPoints=getfield(rtstruct.ROIContourSequence,char(ROIContourSequence(i)), ...
+                        'ContourSequence', char(ncont_temp(j)),'NumberOfContourPoints');
+                    ContourData=getfield(rtstruct.ROIContourSequence,char(ROIContourSequence(i)), ...
+                        'ContourSequence',char(ncont_temp(j)),'ContourData');
+                    x=dicomrt_mmdigit(ContourData(1:3:NumberOfContourPoints*3)*0.1,7);
+                    y=dicomrt_mmdigit(ContourData(2:3:NumberOfContourPoints*3)*0.1,7);
+                    z=dicomrt_mmdigit(ContourData(3:3:NumberOfContourPoints*3)*0.1,7);
+                    VOI{i,2}{j,1}=cat(2,x,y,z); % this is the same as VOI{i,2}{j,1}=[x,y,z];
+                end
+            end
+        case 1
+            % set dummy values. This will be deleted later dugin the import
+            NumberOfContourPoints=1;
+            ContourData=[0,0,0];
+            x=0;
+            y=0;
+            z=0;
+            VOI{i,2}{1,1}=cat(2,x,y,z);
+    end
+    waitbar(i/size(ROIContourSequence,1),h);
+    ncont_temp=[];
+end
+% VOI cell generation complete
+% Store VOI in a cell array
+cellVOI=cell(3,1);
+cellVOI{1,1}=rtstruct;
+cellVOI{2,1}=VOI;
+cellVOI{3,1}=[];
+% Close progress bar
+close(h);

+ 12 - 12
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_makevertical.m

@@ -1,12 +1,12 @@
-function [Vout] = dicomrt_makevertical(Vin)
-% dicomrt_makevertical(Vin)
-%
-% Returns a vector in vertical form.
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-if size(Vin,1)<size(Vin,2)
-    Vin=Vin';
-end
-
-Vout=Vin;
+function [Vout] = dicomrt_makevertical(Vin)
+% dicomrt_makevertical(Vin)
+%
+% Returns a vector in vertical form.
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+if size(Vin,1)<size(Vin,2)
+    Vin=Vin';
+end
+
+Vout=Vin;

+ 50 - 50
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_mmdigit.m

@@ -1,50 +1,50 @@
-function y=dicomrt_mmdigit(x,n,b,t)
-% dicomrt_mmdigit(x,n,b,t)
-%
-% Round values to given significant digits
-%
-% x is the array to be rounded
-% n is the number of significant places
-% b is the base (b=10 default)
-% t is the type of algorithm to use to round (t='round' default)
-%   permitted types are also: 'fix', 'ceil' and 'round'
-%
-% If x is immaginary real and immaginary parts are rounded separately
-%
-% From "Mastering MATLAB 6" Duane Hanselman and Bruce Littlefield, 
-%       Prentice Hall, 2001 ISBN 0-13-019468-9
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-if nargin<2
-    error('dicomrt_mmdigit: Not enough input arguments')
-elseif nargin==2
-    b=10;
-    t='round';
-elseif nargin==3
-    t='round';
-end
-n=round(abs(n(1)));
-if isempty(b),b=10;
-else          b=round(abs(b(1)));
-end
-if isreal(x)
-    y=abs(x)+(x==0);
-    e=floor(log(y)./log(b)+1);
-    p=repmat(b,size(x)).^(n-e);
-    if strncmpi(t,'round',1)
-        y=round(p.*x)./p;
-    elseif strncmpi(t,'fix',1)
-        y=fix(p.*x)./p;
-    elseif strncmpi(t,'ceil',1)
-        y=ceil(p.*x)./p;
-     elseif strncmpi(t,'floor',1)
-        y=floor(p.*x)./p;
-    else
-        error('dicomrt_mmdigit: Unknown rounding request');
-    end
-else % complex input
-    y=complex(mmdigit(real(x),n,b,t),mmdigit(imag(x),n,b,t));
-end
-    
-    
+function y=dicomrt_mmdigit(x,n,b,t)
+% dicomrt_mmdigit(x,n,b,t)
+%
+% Round values to given significant digits
+%
+% x is the array to be rounded
+% n is the number of significant places
+% b is the base (b=10 default)
+% t is the type of algorithm to use to round (t='round' default)
+%   permitted types are also: 'fix', 'ceil' and 'round'
+%
+% If x is immaginary real and immaginary parts are rounded separately
+%
+% From "Mastering MATLAB 6" Duane Hanselman and Bruce Littlefield, 
+%       Prentice Hall, 2001 ISBN 0-13-019468-9
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+if nargin<2
+    error('dicomrt_mmdigit: Not enough input arguments')
+elseif nargin==2
+    b=10;
+    t='round';
+elseif nargin==3
+    t='round';
+end
+n=round(abs(n(1)));
+if isempty(b),b=10;
+else          b=round(abs(b(1)));
+end
+if isreal(x)
+    y=abs(x)+(x==0);
+    e=floor(log(y)./log(b)+1);
+    p=repmat(b,size(x)).^(n-e);
+    if strncmpi(t,'round',1)
+        y=round(p.*x)./p;
+    elseif strncmpi(t,'fix',1)
+        y=fix(p.*x)./p;
+    elseif strncmpi(t,'ceil',1)
+        y=ceil(p.*x)./p;
+     elseif strncmpi(t,'floor',1)
+        y=floor(p.*x)./p;
+    else
+        error('dicomrt_mmdigit: Unknown rounding request');
+    end
+else % complex input
+    y=complex(mmdigit(real(x),n,b,t),mmdigit(imag(x),n,b,t));
+end
+    
+    

+ 17 - 17
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_nASCIIlines.m

@@ -1,17 +1,17 @@
-function [nlines] = dicomrt_nASCIIlines(filename)
-% dicomrt_nASCIIlines(filename)
-%
-% Returns the number of lines in an ASCII file.
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-fid=fopen(filename);
-nlines = 0;
-while 1
-    if feof(fid)
-        break;
-    end
-    nlines = nlines+1;
-    fgetl(fid);    
-end
-fclose(fid);
+function [nlines] = dicomrt_nASCIIlines(filename)
+% dicomrt_nASCIIlines(filename)
+%
+% Returns the number of lines in an ASCII file.
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+fid=fopen(filename);
+nlines = 0;
+while 1
+    if feof(fid)
+        break;
+    end
+    nlines = nlines+1;
+    fgetl(fid);    
+end
+fclose(fid);

+ 18 - 18
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_restorevarformat.m

@@ -1,18 +1,18 @@
-function [moutput]=dicomrt_restorevarformat(morig,data)
-% dicomrt_restorevarformat(morig,data)
-%
-% Restore original variable data.
-%
-% The 3D dataset stored in "data" is associated with the frame given by the
-% original dataset "morig" and returned in "moutput".
-%
-% Seel also: dicomrt_varfilter
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
-
-if iscell(morig)==1
-    morig{2,1}=data;
-    moutput=morig;
-else
-    moutput=data;
-end
+function [moutput]=dicomrt_restorevarformat(morig,data)
+% dicomrt_restorevarformat(morig,data)
+%
+% Restore original variable data.
+%
+% The 3D dataset stored in "data" is associated with the frame given by the
+% original dataset "morig" and returned in "moutput".
+%
+% Seel also: dicomrt_varfilter
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
+
+if iscell(morig)==1
+    morig{2,1}=data;
+    moutput=morig;
+else
+    moutput=data;
+end

+ 106 - 106
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_sortct.m

@@ -1,106 +1,106 @@
-function [change,error_handle]=dicomrt_sortct(filelist,xlocation,ylocation,zlocation,filename)
-% dicomrt_sortct(filelist,xlocation,ylocation,zlocation,filename)
-%
-% Sort CT data set specified in filename. 
-%
-% See also dicomrt_loaddose, dicomrt_loadct, dicomrt_loadctlist
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
-
-% Set parameters
-counter=0;
-error_handle=0;
-match=0;
-
-% sort ct slices with respect to their z location
-[zlocation_sorted,sorted_index]=sort(zlocation);
-
-% Progress bar
-h = waitbar(0,['Sorting progress:']);
-set(h,'Name','dicomrt_sortct: sorting CT images');
-
-diff_location=dicomrt_mmdigit(zlocation_sorted-zlocation,6);
-
-if find(diff_location) % ct slices are not sorted
-    disp('Message: slices are not sorted!');
-    change=1;
-    % sort filelist accordingly
-    filelist_sorted=' ';
-    for i=1:length(sorted_index)
-        counter=counter+1;
-        filelist_sorted=char(filelist_sorted,filelist(sorted_index(i),:));
-        xlocation_sorted(i)=xlocation(sorted_index(i));
-        ylocation_sorted(i)=ylocation(sorted_index(i));
-        waitbar(i/length(sorted_index),h);
-    end
-    
-    xlocation_sorted=xlocation_sorted';
-    ylocation_sorted=ylocation_sorted';
-    filelist_sorted(1,:)=[];
-    disp('Message: ct slices are now sorted!');
-    % finds duplicates
-    duplicate_index=0;
-    [duplicate]=diff(zlocation_sorted);
-    [duplicate_index]=find(duplicate==0);
-    if length(duplicate_index)~=0
-        warning('dicomrt_sortct: Images with the same zlocation were found. You can exit now or proceed to delete duplicates.');
-        leaveoption=input('Exit now ? (Y/N) [N]','s');
-        if leaveoption == 'Y' | leaveoption == 'y';
-            disp('OK. Check your file list and try again. ');
-            error_handle=1;return;
-        else
-            duplicates_name=' ';
-            filelist_sorted_scrub=' ';
-            for i=1:length(duplicate_index)
-                duplicates_name=char(duplicates_name,filelist_sorted(duplicate_index(i),:));
-                filelist_sorted(duplicate_index(i),1:10)='duplicate-'; % mark duplicates
-                xlocation_sorted(duplicate_index(i))=pi;
-                ylocation_sorted(duplicate_index(i))=pi;
-            end
-            for i=1:length(filelist_sorted)
-                if isequal(filelist_sorted(i,1:10),'duplicate-')~=1
-                    filelist_sorted_scrub=char(filelist_sorted_scrub,filelist_sorted(i,:));
-                else
-                end
-            end % at this point duplicates are deleted in new filelist
-                        filelist_sorted_scrub(1,:)=[];
-            disp('The following duplicates has been deleted from file list:');
-            duplicates_name(1,:)=[];
-            duplicates_name
-            %
-            % now sorting xlocation and ylocation accordingly to what done before
-            % (prepare for scout images identification)
-            %
-            for i=1:length(xlocation_sorted)
-                if xlocation_sorted(i)~=pi
-                    xlocation_sorted_scrub=xlocation_sorted(i);
-                end
-            end
-            for i=1:length(ylocation_sorted)
-                if ylocation_sorted(i)~=pi
-                    ylocation_sorted_scrub=ylocation_sorted(i);
-                end
-            end
-        end
-    else
-        filelist_sorted_scrub=filelist_sorted;
-    end
-    
-    % Export sorted/scrubed filelist
-    newfilename=[filename,'.sort.txt'];
-    newfile=fopen(newfilename,'w');
-    
-    for i=1:size(filelist_sorted_scrub,1)
-        fprintf(newfile,'%s',filelist_sorted_scrub(i,:)); fprintf(newfile,'\n');
-    end
-    
-    fclose(newfile);
-    disp(['A new file list has been written by dicomrt_sortct with name: ',newfilename]);
-    disp('This file will be used to import ct data instead');
-    
-else % ct slices are already sorted
-    change=0;
-end
-
-% Close progress bar
-close(h);
+function [change,error_handle]=dicomrt_sortct(filelist,xlocation,ylocation,zlocation,filename)
+% dicomrt_sortct(filelist,xlocation,ylocation,zlocation,filename)
+%
+% Sort CT data set specified in filename. 
+%
+% See also dicomrt_loaddose, dicomrt_loadct, dicomrt_loadctlist
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org) 
+
+% Set parameters
+counter=0;
+error_handle=0;
+match=0;
+
+% sort ct slices with respect to their z location
+[zlocation_sorted,sorted_index]=sort(zlocation);
+
+% Progress bar
+h = waitbar(0,['Sorting progress:']);
+set(h,'Name','dicomrt_sortct: sorting CT images');
+
+diff_location=dicomrt_mmdigit(zlocation_sorted-zlocation,6);
+
+if find(diff_location) % ct slices are not sorted
+    disp('Message: slices are not sorted!');
+    change=1;
+    % sort filelist accordingly
+    filelist_sorted=' ';
+    for i=1:length(sorted_index)
+        counter=counter+1;
+        filelist_sorted=char(filelist_sorted,filelist(sorted_index(i),:));
+        xlocation_sorted(i)=xlocation(sorted_index(i));
+        ylocation_sorted(i)=ylocation(sorted_index(i));
+        waitbar(i/length(sorted_index),h);
+    end
+    
+    xlocation_sorted=xlocation_sorted';
+    ylocation_sorted=ylocation_sorted';
+    filelist_sorted(1,:)=[];
+    disp('Message: ct slices are now sorted!');
+    % finds duplicates
+    duplicate_index=0;
+    [duplicate]=diff(zlocation_sorted);
+    [duplicate_index]=find(duplicate==0);
+    if length(duplicate_index)~=0
+        warning('dicomrt_sortct: Images with the same zlocation were found. You can exit now or proceed to delete duplicates.');
+        leaveoption=input('Exit now ? (Y/N) [N]','s');
+        if leaveoption == 'Y' | leaveoption == 'y';
+            disp('OK. Check your file list and try again. ');
+            error_handle=1;return;
+        else
+            duplicates_name=' ';
+            filelist_sorted_scrub=' ';
+            for i=1:length(duplicate_index)
+                duplicates_name=char(duplicates_name,filelist_sorted(duplicate_index(i),:));
+                filelist_sorted(duplicate_index(i),1:10)='duplicate-'; % mark duplicates
+                xlocation_sorted(duplicate_index(i))=pi;
+                ylocation_sorted(duplicate_index(i))=pi;
+            end
+            for i=1:length(filelist_sorted)
+                if isequal(filelist_sorted(i,1:10),'duplicate-')~=1
+                    filelist_sorted_scrub=char(filelist_sorted_scrub,filelist_sorted(i,:));
+                else
+                end
+            end % at this point duplicates are deleted in new filelist
+                        filelist_sorted_scrub(1,:)=[];
+            disp('The following duplicates has been deleted from file list:');
+            duplicates_name(1,:)=[];
+            duplicates_name
+            %
+            % now sorting xlocation and ylocation accordingly to what done before
+            % (prepare for scout images identification)
+            %
+            for i=1:length(xlocation_sorted)
+                if xlocation_sorted(i)~=pi
+                    xlocation_sorted_scrub=xlocation_sorted(i);
+                end
+            end
+            for i=1:length(ylocation_sorted)
+                if ylocation_sorted(i)~=pi
+                    ylocation_sorted_scrub=ylocation_sorted(i);
+                end
+            end
+        end
+    else
+        filelist_sorted_scrub=filelist_sorted;
+    end
+    
+    % Export sorted/scrubed filelist
+    newfilename=[filename,'.sort.txt'];
+    newfile=fopen(newfilename,'w');
+    
+    for i=1:size(filelist_sorted_scrub,1)
+        fprintf(newfile,'%s',filelist_sorted_scrub(i,:)); fprintf(newfile,'\n');
+    end
+    
+    fclose(newfile);
+    disp(['A new file list has been written by dicomrt_sortct with name: ',newfilename]);
+    disp('This file will be used to import ct data instead');
+    
+else % ct slices are already sorted
+    change=0;
+end
+
+% Close progress bar
+close(h);

+ 17 - 17
WiscPlanPhotonkV125/matlab_frontend/dicomrt/dicomrt_varfilter.m

@@ -1,17 +1,17 @@
-function [moutput]=dicomrt_varfilter(minput)
-% dicomrt_varfilter(minput)
-%
-% Filter input variable data.
-%
-% If input variable data is a cell array this function returns the 
-% array part of it: minput{2,1}.
-%
-% See also: dicomrt_restorevarformat
-%
-% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
-
-if iscell(minput)==1
-    moutput=minput{2,1};
-else
-    moutput=minput;
-end
+function [moutput]=dicomrt_varfilter(minput)
+% dicomrt_varfilter(minput)
+%
+% Filter input variable data.
+%
+% If input variable data is a cell array this function returns the 
+% array part of it: minput{2,1}.
+%
+% See also: dicomrt_restorevarformat
+%
+% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)
+
+if iscell(minput)==1
+    moutput=minput{2,1};
+else
+    moutput=minput;
+end

+ 42 - 42
WiscPlanPhotonkV125/matlab_frontend/dvh.m

@@ -1,42 +1,42 @@
-function DVH = dvh(dose,mask,d_bins)
-% A dose volume histogram is calculated for a region of interest (roi)
-% using dose bins specified by the user.
-%
-% Inputs:  dose = dose distribution
-%          mask = mask of zeros and ones that specifies the roi
-%          d_bins = dose bin boundaries, must be a vector
-% 
-% Output:  d_hist = dose volume histogram defined as:
-%          d_hist(j) = percentage of voxels in the region of interested 
-%                      receiving a dose of d_bins(j) or greater.
-
-% ensure that d_bins is a vector
-if prod(size(d_bins)) > length(d_bins)
-    error('Third input argument must be a vector.');
-end
-
-% ensure that the mask is just ones and zeros
-if ~isempty(find(mask~=0 & mask~=1))
-    error('Mask must consist of zeros and ones only.');
-end
-
-% ensure that the mask and the dose matrix are the same size
-if size(dose,1) ~= size(mask,1) | size(dose,2) ~= size(mask,2) ...
-        | size(dose,3) ~= size(mask,3)
-    error('The dose matrix and the mask must be the same size.');
-end
-
-Nbins = length(d_bins);  % number of bins in the dvh
-Nvoxels = sum(mask(:));  % number of voxels in the mask
-
-d_hist = zeros(1,length(d_bins));
-DVH = zeros(size(d_hist));
-
-ind = find(mask == 1);  % indices that lie in the roi
-
-if ~isempty(ind)   
-    dose_vector = dose(ind);  % vector of dose
-    d_hist = histc(dose(ind),d_bins);  % create the differential histogram
-    d_hist = 100*d_hist/length(ind); % renomalize
-    DVH = flipud(cumsum(flipud(d_hist)));
-end
+function DVH = dvh(dose,mask,d_bins)
+% A dose volume histogram is calculated for a region of interest (roi)
+% using dose bins specified by the user.
+%
+% Inputs:  dose = dose distribution
+%          mask = mask of zeros and ones that specifies the roi
+%          d_bins = dose bin boundaries, must be a vector
+% 
+% Output:  d_hist = dose volume histogram defined as:
+%          d_hist(j) = percentage of voxels in the region of interested 
+%                      receiving a dose of d_bins(j) or greater.
+
+% ensure that d_bins is a vector
+if prod(size(d_bins)) > length(d_bins)
+    error('Third input argument must be a vector.');
+end
+
+% ensure that the mask is just ones and zeros
+if ~isempty(find(mask~=0 & mask~=1))
+    error('Mask must consist of zeros and ones only.');
+end
+
+% ensure that the mask and the dose matrix are the same size
+if size(dose,1) ~= size(mask,1) | size(dose,2) ~= size(mask,2) ...
+        | size(dose,3) ~= size(mask,3)
+    error('The dose matrix and the mask must be the same size.');
+end
+
+Nbins = length(d_bins);  % number of bins in the dvh
+Nvoxels = sum(mask(:));  % number of voxels in the mask
+
+d_hist = zeros(1,length(d_bins));
+DVH = zeros(size(d_hist));
+
+ind = find(mask == 1);  % indices that lie in the roi
+
+if ~isempty(ind)   
+    dose_vector = dose(ind);  % vector of dose
+    d_hist = histc(dose(ind),d_bins);  % create the differential histogram
+    d_hist = 100*d_hist/length(ind); % renomalize
+    DVH = flipud(cumsum(flipud(d_hist)));
+end

+ 64 - 64
WiscPlanPhotonkV125/matlab_frontend/dvhist.m

@@ -1,64 +1,64 @@
-function [dvh, dosebins] = dvhist(varargin)
-% DVHIST Plot a DVH and/or compute the statistics of the plan
-%
-% Usage:
-%   [dvh, dosebins, stats] = dvhist (dosemap, contour)
-%
-% INPUT:
-%   dosemap = dose distribution, 2D or 3D
-%   contour = index vector or logical matrix specifying the ROI
-%   mode = 'relative' (default) or 'absolute'
-%
-% OUTPUT:
-%   [] = plot the DVH
-%   dvh = vector of dvh, ordinate of dvh
-%   dosebins = dose bin locations, abscissa of the dvh
-%
-% See also: N/A
-%
-% TODO: change the way handles displayname or easier to plot output
-%
-% Copyleft (c) Xiaohu Mo
-% Version: 1.3c
-
-if nargin == 2
-    % (dosemap, contour)
-    dosemap = varargin{1};
-    contour = varargin{2};
-elseif nargin == 4
-    % (dosemap, Geometry, ROIindex)
-    dosemap = varargin{1};
-    Geometry = varargin{2};
-    ROIind = varargin{3};
-    nfraction = varargin{4};
-    contour = Geometry.ROIS{ROIind}.ind;
-else
-    error('unknown inputs');
-end
-
-
-if isempty(contour)
-    error('contour is empty');
-else
-    dosevec = dosemap(contour);
-end
-
-
-% calculate DVH
-if isempty(find(dosevec, 1))
-    % if no voxel has dose, hist return -Nbins/2 ~ Nbins/2, affects plotting
-    dvh = [100 0];
-    dosebins = [0 1E-3];
-else
-    % Use histogram to calculate DVH
-    [pdf dosebins] = hist(dosevec, 999);
-    % clip negative bins
-    pdf = pdf(dosebins >= 0);
-    dosebins = dosebins(dosebins >= 0);
-    dvh = fliplr(cumsum(fliplr(pdf))) / numel(dosevec) * 100;
-end
-% append the last bin
-dosebins = [dosebins dosebins(end)+0.1];
-dvh = [dvh 0];
-
-end
+function [dvh, dosebins] = dvhist(varargin)
+% DVHIST Plot a DVH and/or compute the statistics of the plan
+%
+% Usage:
+%   [dvh, dosebins, stats] = dvhist (dosemap, contour)
+%
+% INPUT:
+%   dosemap = dose distribution, 2D or 3D
+%   contour = index vector or logical matrix specifying the ROI
+%   mode = 'relative' (default) or 'absolute'
+%
+% OUTPUT:
+%   [] = plot the DVH
+%   dvh = vector of dvh, ordinate of dvh
+%   dosebins = dose bin locations, abscissa of the dvh
+%
+% See also: N/A
+%
+% TODO: change the way handles displayname or easier to plot output
+%
+% Copyleft (c) Xiaohu Mo
+% Version: 1.3c
+
+if nargin == 2
+    % (dosemap, contour)
+    dosemap = varargin{1};
+    contour = varargin{2};
+elseif nargin == 4
+    % (dosemap, Geometry, ROIindex)
+    dosemap = varargin{1};
+    Geometry = varargin{2};
+    ROIind = varargin{3};
+    nfraction = varargin{4};
+    contour = Geometry.ROIS{ROIind}.ind;
+else
+    error('unknown inputs');
+end
+
+
+if isempty(contour)
+    error('contour is empty');
+else
+    dosevec = dosemap(contour);
+end
+
+
+% calculate DVH
+if isempty(find(dosevec, 1))
+    % if no voxel has dose, hist return -Nbins/2 ~ Nbins/2, affects plotting
+    dvh = [100 0];
+    dosebins = [0 1E-3];
+else
+    % Use histogram to calculate DVH
+    [pdf dosebins] = hist(dosevec, 999);
+    % clip negative bins
+    pdf = pdf(dosebins >= 0);
+    dosebins = dosebins(dosebins >= 0);
+    dvh = fliplr(cumsum(fliplr(pdf))) / numel(dosevec) * 100;
+end
+% append the last bin
+dosebins = [dosebins dosebins(end)+0.1];
+dvh = [dvh 0];
+
+end

+ 88 - 88
WiscPlanPhotonkV125/matlab_frontend/get_beam_lets.m

@@ -1,89 +1,89 @@
-
-
-function [beamlets, beamlets_joined, numBeamlet, numBeam, beam_i_list] = get_beam_lets(Geometry, patient_dir)
-% this function loads and returns beamlets and joined beams
-
-beamlet_batch_filename = [patient_dir '\' 'batch_dose.bin'];
-beamlet_cell_array = read_ryan_beamlets(beamlet_batch_filename, 'ryan');
-
-numVox  = numel(Geometry.data);
-numBeamlet = size(beamlet_cell_array,2);
-
-if size(Geometry.data, 1)<129
-    batchSize = 400;
-else
-    batchSize = 200;
-end
-
-beamlets = get_beamlets(beamlet_cell_array, numVox, batchSize);
-% join beamlets into beams
-load([patient_dir '\all_beams.mat'])
-beamletOrigin=[0 0 0];
-beam_i=0;
-beam_i_list=[];
-for beamlet_i = 1:numel(all_beams)
-    newBeamletOrigin = all_beams{beamlet_i}.ip;
-    if any(newBeamletOrigin ~= beamletOrigin)
-        beam_i = beam_i+1;
-        beamletOrigin = newBeamletOrigin;
-    end
-    beam_i_list=[beam_i_list, beam_i];
-end
-
-
-wbar2 = waitbar(0, 'merging beamlets into beams');
-numBeam=numel(unique(beam_i_list));
-beamlets_joined=sparse(size(beamlets,1), numBeam);
-for beam_i = 1:numel(unique(beam_i_list))
-    beam_full = sum(beamlets(:,beam_i_list == beam_i), 2); 
-    beamlets_joined(:,beam_i) = beam_full;
-    waitbar(beam_i/numBeam, wbar2)
-end
-
-close(wbar2)
-end
-
-% ---- GET BEAMLETS ----
-function beamlets = get_beamlets(beamlet_cell_array, numVox, batchSize);
-    wbar1 = waitbar(0, 'Creating beamlet array');
-    numBeam = size(beamlet_cell_array,2);
-    beamlets = sparse(0, 0);
-    for beam_i=1:numBeam
-        % for each beam define how much dose it delivers on each voxel
-        idx=beamlet_cell_array{1, beam_i}.non_zero_indices;
-
-        % break the beamlets into multiple batches
-        if rem(beam_i, batchSize)==1;
-            beamlet_batch = sparse(numVox, batchSize);
-            beam_i_temp=1;
-        end
-
-        beamlet_batch(idx, beam_i_temp) = 1000*beamlet_cell_array{1, beam_i}.non_zero_values;
-        waitbar(beam_i/numBeam, wbar1, ['Adding beamlet array: #', num2str(beam_i)])
-
-        % add the batch to full set when filled
-        if rem(beam_i, batchSize)==0;
-            beamlets =[beamlets, beamlet_batch];
-        end
-        % crop and add the batch to full set when completed
-        if beam_i==numBeam;
-            beamlet_batch=beamlet_batch(:, 1:beam_i_temp);
-            beamlets =[beamlets, beamlet_batch];
-        end
-        beam_i_temp=beam_i_temp+1;
-
-    end
-    close(wbar1)
-
-end
-function show_joint_beamlets(beamlets, IMGsize, Beam_list)
-    % this function overlays and plots multiple beamlets. The goal is to
-    % check whether some beamlets are part of the same beam manually.
-    
-    beam=sum(beamlets(:, Beam_list), 2);
-    
-    beamImg=reshape(full(beam), IMGsize);
-        
-    orthoslice(beamImg)
-    
+
+
+function [beamlets, beamlets_joined, numBeamlet, numBeam, beam_i_list] = get_beam_lets(Geometry, patient_dir)
+% this function loads and returns beamlets and joined beams
+
+beamlet_batch_filename = [patient_dir '\' 'batch_dose.bin'];
+beamlet_cell_array = read_ryan_beamlets(beamlet_batch_filename, 'ryan');
+
+numVox  = numel(Geometry.data);
+numBeamlet = size(beamlet_cell_array,2);
+
+if size(Geometry.data, 1)<129
+    batchSize = 400;
+else
+    batchSize = 200;
+end
+
+beamlets = get_beamlets(beamlet_cell_array, numVox, batchSize);
+% join beamlets into beams
+load([patient_dir '\all_beams.mat'])
+beamletOrigin=[0 0 0];
+beam_i=0;
+beam_i_list=[];
+for beamlet_i = 1:numel(all_beams)
+    newBeamletOrigin = all_beams{beamlet_i}.ip;
+    if any(newBeamletOrigin ~= beamletOrigin)
+        beam_i = beam_i+1;
+        beamletOrigin = newBeamletOrigin;
+    end
+    beam_i_list=[beam_i_list, beam_i];
+end
+
+
+wbar2 = waitbar(0, 'merging beamlets into beams');
+numBeam=numel(unique(beam_i_list));
+beamlets_joined=sparse(size(beamlets,1), numBeam);
+for beam_i = 1:numel(unique(beam_i_list))
+    beam_full = sum(beamlets(:,beam_i_list == beam_i), 2); 
+    beamlets_joined(:,beam_i) = beam_full;
+    waitbar(beam_i/numBeam, wbar2)
+end
+
+close(wbar2)
+end
+
+% ---- GET BEAMLETS ----
+function beamlets = get_beamlets(beamlet_cell_array, numVox, batchSize);
+    wbar1 = waitbar(0, 'Creating beamlet array');
+    numBeam = size(beamlet_cell_array,2);
+    beamlets = sparse(0, 0);
+    for beam_i=1:numBeam
+        % for each beam define how much dose it delivers on each voxel
+        idx=beamlet_cell_array{1, beam_i}.non_zero_indices;
+
+        % break the beamlets into multiple batches
+        if rem(beam_i, batchSize)==1;
+            beamlet_batch = sparse(numVox, batchSize);
+            beam_i_temp=1;
+        end
+
+        beamlet_batch(idx, beam_i_temp) = 1000*beamlet_cell_array{1, beam_i}.non_zero_values;
+        waitbar(beam_i/numBeam, wbar1, ['Adding beamlet array: #', num2str(beam_i)])
+
+        % add the batch to full set when filled
+        if rem(beam_i, batchSize)==0;
+            beamlets =[beamlets, beamlet_batch];
+        end
+        % crop and add the batch to full set when completed
+        if beam_i==numBeam;
+            beamlet_batch=beamlet_batch(:, 1:beam_i_temp);
+            beamlets =[beamlets, beamlet_batch];
+        end
+        beam_i_temp=beam_i_temp+1;
+
+    end
+    close(wbar1)
+
+end
+function show_joint_beamlets(beamlets, IMGsize, Beam_list)
+    % this function overlays and plots multiple beamlets. The goal is to
+    % check whether some beamlets are part of the same beam manually.
+    
+    beam=sum(beamlets(:, Beam_list), 2);
+    
+    beamImg=reshape(full(beam), IMGsize);
+        
+    orthoslice(beamImg)
+    
 end

+ 20 - 6
WiscPlanPhotonkV125/matlab_frontend/get_beamlets.m

@@ -3,12 +3,26 @@
 function [beamlets, numBeamlet] = get_beamlets(Geometry, patient_dir, OptGoals)
 % this function loads and returns beamlets and joined beams
 
-ROI_idxList = [];
+% ROI_idxList = [];
+% for i = 1:numel(OptGoals.data)
+%     ROI_idxList = [ROI_idxList; OptGoals.data{i}.ROI_idx];
+% end
+% ROI_idxList = unique(ROI_idxList);
+
+tabula = zeros(size(Geometry.data));
 for i = 1:numel(OptGoals.data)
-    ROI_idxList = [ROI_idxList; OptGoals.data{i}.ROI_idx];
+    tabula(OptGoals.data{i}.ROI_idx) = 1;
+end
+ROI_idxList = find(tabula>0);
+
+for i_sss = OptGoals.sss_scene_list
+    tabula2 = imtranslate(tabula, i_sss{1});
+    ROI_idxList2 = find(tabula2>0);
+    ROI_idxList = [ROI_idxList; ROI_idxList2];
 end
 ROI_idxList = unique(ROI_idxList);
 
+
 %% add idx lists for each goal!
 
 beamlet_batch_filename = [patient_dir '\' 'batch_dose.bin'];
@@ -55,13 +69,13 @@ function beamlets = get_beamlets2(beamlet_cell_array, numVox, batchSize, ROI_idx
     beamlets = sparse(0, 0);
     for beam_i=1:numBeam
         % for each beam define how much dose it delivers on each voxel
-%         idx=beamlet_cell_array{1, beam_i}.non_zero_indices;
-%         [ROI_idxIntersect, ia, ~] = intersect (idx, ROI_idxList);
+        idx=beamlet_cell_array{1, beam_i}.non_zero_indices;
+        [ROI_idxIntersect, ia, ~] = intersect (idx, ROI_idxList);
 %         if ~isequal(ROI_idxIntersect,idx)
 %             warning('this')
 %         end
         
-        ROI_idxIntersect = beamlet_cell_array{1, beam_i}.non_zero_indices;
+%         ROI_idxIntersect = beamlet_cell_array{1, beam_i}.non_zero_indices;
         
         if isempty(ROI_idxIntersect)
             warning(['Beamlet ' num2str(beam_i) ' is empty!'])
@@ -74,7 +88,7 @@ function beamlets = get_beamlets2(beamlet_cell_array, numVox, batchSize, ROI_idx
         end
 
 %         beamlet_batch(idx, beam_i_temp) = 1000*beamlet_cell_array{1, beam_i}.non_zero_values;
-        beamlet_batch(ROI_idxIntersect, beam_i_temp) = beamlet_cell_array{1, beam_i}.non_zero_values;
+        beamlet_batch(ROI_idxIntersect, beam_i_temp) = beamlet_cell_array{1, beam_i}.non_zero_values(ia);
         waitbar(beam_i/numBeam, wbar1, ['Adding beamlet array: #', num2str(beam_i)])
 
         % add the batch to full set when filled

+ 14 - 14
WiscPlanPhotonkV125/matlab_frontend/get_full_dose.m

@@ -1,15 +1,15 @@
-function get_full_dose(path_in)
-% path_in='C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\PatientData';
-optResultsFile = [path_in, '\matlab_files\optResults.mat'];
-
-load(optResultsFile);
-D = read_ryan_beamlets([path_in '\beamlet_batch_files\beamletbatch0.bin'],'ryan sum', optResults.weights{end});
-optResults.batchNames{end+1} = optResults.batchNames{end};
-optResults.dose{end+1} = D;
-optResults.weights{end+1} = optResults.weights{end};
-save(optResultsFile, 'optResults', 'optSettings');
-
-%% save also in alter format
-NLP_result.dose = double(D);
-NLP_result.weights = double(optResults.weights{end});
+function get_full_dose(path_in)
+% path_in='C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\PatientData';
+optResultsFile = [path_in, '\matlab_files\optResults.mat'];
+
+load(optResultsFile);
+D = read_ryan_beamlets([path_in '\beamlet_batch_files\beamletbatch0.bin'],'ryan sum', optResults.weights{end});
+optResults.batchNames{end+1} = optResults.batchNames{end};
+optResults.dose{end+1} = D;
+optResults.weights{end+1} = optResults.weights{end};
+save(optResultsFile, 'optResults', 'optSettings');
+
+%% save also in alter format
+NLP_result.dose = double(D);
+NLP_result.weights = double(optResults.weights{end});
 save([path_in, '\matlab_files\Classical_opt.mat'], 'NLP_result');

BIN
WiscPlanPhotonkV125/matlab_frontend/goal_def_UI.fig


+ 1 - 1
WiscPlanPhotonkV125/matlab_frontend/goal_def_UI.m

@@ -123,7 +123,7 @@ function removeRow_Callback(hObject, eventdata, handles)
 % Removes row number selected by Remove_row_N
 newTable = handles.uitable1.Data;
 rowToDelete = str2double(handles.Remove_row_N.String);
-if rowToDelete>size(newTable, 2)
+if rowToDelete>size(newTable, 1)
     disp(['No row ' num2str(rowToDelete)])
 else
     newTable(rowToDelete,:) = [];

+ 483 - 483
WiscPlanPhotonkV125/matlab_frontend/helicalDosecalcSetup5.m

@@ -1,483 +1,483 @@
-%%
-% 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 
-% SAD < 20 was edited from SAD < 50 for clinical system (error message)
-% 
-
-% specify where kernel and geometry files are located
-patient_dir = 'C:\localGit\wiscPlanv2\WiscPlanPhotonkV125\PatientData';
-num_batches = 2; % number of cores you want to run the beam calculation
-
-iso = [0 0 0]; % Point about which gantry rotations begin
-SAD = 35;  % source-axis distance for the x-ray source
-pitch = 0.86; % fraction of beam with couch translates per rotation
-
-% define the overall beam field size for each beam angle
-xpmin = -0.5;     % -field width / 2
-xpmax = 0.5;      % +field width / 2
-ypmin = -0.5;   % -jaw width / 2
-ypmax = 0.5;    % +jaw width / 2
-% y-prime points in the z-direction in the CT coordinate system
-
-% Number of beamlets in the BEV for each direction
-Mxp = 20;        % number of leaves; leaf size is 1/20cm= 0.5mm
-Nyp = 1;        % always 1 for Tomo due to binary mlc
-
-% ============================================= End of user-supplied inputs
-executable_path = 'C:\localGit\wiscPlanv2\WiscPlanPhotonkV125\WiscPlanEXE\RyanCsphoton.x86.exe';
-kernel_file = 'Kernels.mat';
-geometry_file = fullfile(patient_dir, 'matlab_files\Geometry.mat');
-% tumor bow and stern locations
-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. ');
-if okay ~= 1
-    msgbox('Plan creation aborted');
-    return;
-end
-targetMask = zeros(size(Geometry.data));
-targetMask(Geometry.ROIS{target_idx}.ind) = 1;
-targetMaskZ = sum(sum(targetMask,1),2);
-zBow = find(targetMaskZ>0, 1, 'first')*Geometry.voxel_size(3) + Geometry.start(3) + ypmin;
-zStern = find(targetMaskZ>0, 1, 'last')*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];
-
-% 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
-
-load(geometry_file);
-
-% 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 < 20
-    error('It is recommended that the SAD be greater than 20 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);
-
-% 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-1)
-    batches{k} = all_beams(1+num_beams_per_batch*(k-1):num_beams_per_batch*k);
-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
-
-% 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
-
-if(strcmpi('y',strBeamlet)) 
-    for k = 1:numel(batches)
-        system([fullfile(patient_dir,sprintf('run%d.cmd',k-1)) ' &']);
-    end 
-end
-
-
+%%
+% 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 
+% SAD < 20 was edited from SAD < 50 for clinical system (error message)
+% 
+
+% specify where kernel and geometry files are located
+patient_dir = 'C:\localGit\wiscPlanv2\WiscPlanPhotonkV125\PatientData';
+num_batches = 2; % number of cores you want to run the beam calculation
+
+iso = [0 0 0]; % Point about which gantry rotations begin
+SAD = 35;  % source-axis distance for the x-ray source
+pitch = 0.86; % fraction of beam with couch translates per rotation
+
+% define the overall beam field size for each beam angle
+xpmin = -0.5;     % -field width / 2
+xpmax = 0.5;      % +field width / 2
+ypmin = -0.5;   % -jaw width / 2
+ypmax = 0.5;    % +jaw width / 2
+% y-prime points in the z-direction in the CT coordinate system
+
+% Number of beamlets in the BEV for each direction
+Mxp = 20;        % number of leaves; leaf size is 1/20cm= 0.5mm
+Nyp = 1;        % always 1 for Tomo due to binary mlc
+
+% ============================================= End of user-supplied inputs
+executable_path = 'C:\localGit\wiscPlanv2\WiscPlanPhotonkV125\WiscPlanEXE\RyanCsphoton.x86.exe';
+kernel_file = 'Kernels.mat';
+geometry_file = fullfile(patient_dir, 'matlab_files\Geometry.mat');
+% tumor bow and stern locations
+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. ');
+if okay ~= 1
+    msgbox('Plan creation aborted');
+    return;
+end
+targetMask = zeros(size(Geometry.data));
+targetMask(Geometry.ROIS{target_idx}.ind) = 1;
+targetMaskZ = sum(sum(targetMask,1),2);
+zBow = find(targetMaskZ>0, 1, 'first')*Geometry.voxel_size(3) + Geometry.start(3) + ypmin;
+zStern = find(targetMaskZ>0, 1, 'last')*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];
+
+% 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
+
+load(geometry_file);
+
+% 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 < 20
+    error('It is recommended that the SAD be greater than 20 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);
+
+% 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-1)
+    batches{k} = all_beams(1+num_beams_per_batch*(k-1):num_beams_per_batch*k);
+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
+
+% 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
+
+if(strcmpi('y',strBeamlet)) 
+    for k = 1:numel(batches)
+        system([fullfile(patient_dir,sprintf('run%d.cmd',k-1)) ' &']);
+    end 
+end
+
+

+ 523 - 523
WiscPlanPhotonkV125/matlab_frontend/helicalDosecalcSetup6.m

@@ -1,523 +1,523 @@
-%%
-
-% This version was modified by Peter Ferjancic to accept .nrrd file format
-% for target.
-
-% 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 
-% SAD < 20 was edited from SAD < 50 for clinical system (error message)
-% 
-
-function helicalDosecalcSetup6()
-
-
-% specify where kernel and [geometry] files are located
-patient_dir = 'C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\PatientData';
-num_batches = 4; % number of cores you want to run the beam calculation
-
-iso = [0 0 0]; % Point about which gantry rotations begin
-% SAD = 35;  % source-axis distance for the x-ray source
-SAD = 60;  % source-axis distance for the x-ray source ##
-pitch = 0.86; % fraction of beam with couch translates per rotation
-
-% define the overall beam field size for each beam angle
-xpmin = -0.5;     % -field width / 2
-xpmax = 0.5;      % +field width / 2
-ypmin = -0.5;   % -jaw width / 2
-ypmax = 0.5;    % +jaw width / 2
-
-
-% ##
-xpmin = -5.0;     % -field width / 2
-xpmax = 5.0;      % +field width / 2
-ypmin = -1.0;   % -jaw width / 2
-ypmax = 1.0;    % +jaw width / 2
-
-% y-prime points in the z-direction in the CT coordinate system
-
-% Number of beamlets in the BEV for each direction
-Mxp = 20;        % number of leaves; leaf size is 1/20cm= 0.5mm
-Nyp = 1;        % always 1 for Tomo due to binary mlc
-% 
-% Mxp = 20;        % ## Grozomah
-
-% ============================================= End of user-supplied inputs
-executable_path = 'C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\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. ');
-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')*Geometry.voxel_size(3) + Geometry.start(3) + ypmin;
-zStern = find(targetMaskZ>0, 1, 'last')*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];
-
-% 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*21;  % Grozomah
-
-% load(geometry_file);
-
-% 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 < 20
-    error('It is recommended that the SAD be greater than 20 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-1)
-    batches{k} = all_beams(1+num_beams_per_batch*(k-1):num_beams_per_batch*k);
-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
-
-% 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
-
-
-disp(['Calculating ' num2str(size(all_beams, 2)) ' beamlets in ' num2str(size(batches, 1))...
-    ' batches. '])
-
-
-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.
+
+% 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 
+% SAD < 20 was edited from SAD < 50 for clinical system (error message)
+% 
+
+function helicalDosecalcSetup6()
+
+
+% specify where kernel and [geometry] files are located
+patient_dir = 'C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\PatientData';
+num_batches = 4; % number of cores you want to run the beam calculation
+
+iso = [0 0 0]; % Point about which gantry rotations begin
+% SAD = 35;  % source-axis distance for the x-ray source
+SAD = 60;  % source-axis distance for the x-ray source ##
+pitch = 0.86; % fraction of beam with couch translates per rotation
+
+% define the overall beam field size for each beam angle
+xpmin = -0.5;     % -field width / 2
+xpmax = 0.5;      % +field width / 2
+ypmin = -0.5;   % -jaw width / 2
+ypmax = 0.5;    % +jaw width / 2
+
+
+% ##
+xpmin = -5.0;     % -field width / 2
+xpmax = 5.0;      % +field width / 2
+ypmin = -1.0;   % -jaw width / 2
+ypmax = 1.0;    % +jaw width / 2
+
+% y-prime points in the z-direction in the CT coordinate system
+
+% Number of beamlets in the BEV for each direction
+Mxp = 20;        % number of leaves; leaf size is 1/20cm= 0.5mm
+Nyp = 1;        % always 1 for Tomo due to binary mlc
+% 
+% Mxp = 20;        % ## Grozomah
+
+% ============================================= End of user-supplied inputs
+executable_path = 'C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\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. ');
+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')*Geometry.voxel_size(3) + Geometry.start(3) + ypmin;
+zStern = find(targetMaskZ>0, 1, 'last')*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];
+
+% 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*21;  % Grozomah
+
+% load(geometry_file);
+
+% 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 < 20
+    error('It is recommended that the SAD be greater than 20 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-1)
+    batches{k} = all_beams(1+num_beams_per_batch*(k-1):num_beams_per_batch*k);
+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
+
+% 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
+
+
+disp(['Calculating ' num2str(size(all_beams, 2)) ' beamlets in ' num2str(size(batches, 1))...
+    ' batches. '])
+
+
+if(strcmpi('y',strBeamlet)) 
+    for k = 1:numel(batches)
+        system([fullfile(patient_dir,sprintf('run%d.cmd',k-1)) ' &']);
+    end 
+end
+
+end
+

+ 527 - 527
WiscPlanPhotonkV125/matlab_frontend/helicalDosecalcSetup7.m

@@ -1,527 +1,527 @@
-%%
-
-% 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];
-
-% 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];
+
+% 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
+

+ 4 - 4
WiscPlanPhotonkV125/matlab_frontend/lab/RDXTPS.m

@@ -1,4 +1,4 @@
-function RDXTPS()
-%RDXTPS calls XTPS constructor and provide an entrance point for deploytool
-
-XTPS();
+function RDXTPS()
+%RDXTPS calls XTPS constructor and provide an entrance point for deploytool
+
+XTPS();

+ 180 - 180
WiscPlanPhotonkV125/matlab_frontend/lab/RDXTPS_geometry_setup_wizard_ASP.m

@@ -1,180 +1,180 @@
-function [Geometry patient_dir] = RDXTPS_geometry_setup_wizard_ASP()
-%PLAN_SETUP_WIZARD Wizard to guide through plan creating
-% 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
-
-total_num_steps = 4;
-hWaitbar = waitbar(0);
-set(hWaitbar, 'Unit', 'normalized');
-op = get(hWaitbar, 'OuterPosition');
-set(hWaitbar, 'OuterPosition', op + [0 0.2 0 0]);
-
-%% -----===== DicomRT Import =====-----
-waitbar(0/total_num_steps, hWaitbar, 'Step 1: Import DicomRT');
-% try
-    Geometry = dicomrt2geometry();
-% catch EXCEPTION_DICOMRT2GEOMETRY
-%     msgbox('Failed to import DicomRT');
-%     delete(hWaitbar);
-%     rethrow(EXCEPTION_DICOMRT2GEOMETRY);
-% end
-
-if isempty(Geometry)
-    msgbox('Failed to import DicomRT');
-    delete(hWaitbar);
-    return;
-end
-
-
-%% -----===== BTV and Ring creation =====-----
-waitbar(1/total_num_steps, hWaitbar, 'Step 2: Assign target and BTV margin');
-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. ');
-if okay ~= 1
-    msgbox('Plan creation aborted');
-    delete(hWaitbar);
-    return;
-end
-
-[BTV_margin_answer] = inputdlg({sprintf('Please enter the BTV margin (cm):\n(default 0.6 cm or 1 sigma, enter 0 to skip)')}, ...
-    'BTV margin specification', 1, {'0.6'});
-if isempty(BTV_margin_answer)
-    BTV_margin = 0.6;
-else
-    BTV_margin = str2double(BTV_margin_answer{1});
-end
-
-% target_idx and BTV_margin are set. Expand PTV to BTV
-PTVmask = false(size(Geometry.rhomw));
-% for target_idx = target_indices
-        PTVmask(Geometry.ROIS{target_idx}.ind) = 1;
-% end
-if BTV_margin > 0
-    if exist('BTV_margin', 'var') && BTV_margin >= min(Geometry.voxel_size)
-        bwD = bwdistsc(PTVmask, Geometry.voxel_size);
-        Geometry.BTV = bwD <= BTV_margin;
-    end
-end
-
-% Create btv
-Geometry.ROIS{end+1} = Geometry.ROIS{end};
-Geometry.ROIS{end}.name = 'BTV';
-Geometry.ROIS{end}.num_curves = 0;
-Geometry.ROIS{end}.curves = {};
-Geometry.ROIS{end}.ind = find(Geometry.BTV);
-Geometry.ROIS{end}.visible = false;
-
-% Create ring
-[ring_margin_answer] = inputdlg({sprintf('Please enter the ring margin (cm):')}, ...
-    'Ring margin specification', 1, {'1'});
-if isempty(ring_margin_answer)
-    ring_margin = 1;
-else
-    ring_margin = str2double(ring_margin_answer{1});
-end
-bwD = bwdistsc(PTVmask, Geometry.voxel_size);
-Geometry.Ring = bwD <= ring_margin; % default ring radius 3 cm
-Geometry.Ring = xor(Geometry.Ring, PTVmask);
-Geometry.ROIS{end+1} = Geometry.ROIS{end};
-Geometry.ROIS{end}.name = 'Ring';
-Geometry.ROIS{end}.num_curves = 0;
-Geometry.ROIS{end}.curves = {};
-Geometry.ROIS{end}.ind = find(Geometry.Ring);
-Geometry.ROIS{end}.visible = false;
-
-% Create high comformity ring structure for adaptive step size
-[HCRing_margin_answer] = inputdlg({sprintf('Please enter the HC ring margin (cm):\n(default 1.2 cm or 2 sigma, enter 0 to skip)')}, ...
-    'HCRing margin specification', 1, {'1.2'});
-if isempty(HCRing_margin_answer)
-    HCRing_margin = 1.2;
-else
-    HCRing_margin = str2double(HCRing_margin_answer{1});
-end
-
-if HCRing_margin > 0
-    bwD = bwdistsc(~Geometry.BTV, Geometry.voxel_size);
-    % shrinked BTV from original BTV, such that original_BTV > target_VOI > shrinked_BTV
-    Geometry.SBTV = bwD >= HCRing_margin;
-    Geometry.HCRing = xor(Geometry.BTV, Geometry.SBTV);
-end
-
-%% -----===== Save geometry files =====-----
-waitbar(2/total_num_steps, hWaitbar, 'Step 3: Save geometry files');
-
-load('WiscPlan_preferences.mat')
-patient_dir = uigetdir(WiscPlan_preferences.patientDataPath, 'Save the patient data to directory');
-
-Geometry.data_dir = patient_dir;
-
-WiscPlan_preferences.patientDataPath = patient_dir;
-thisDir = mfilename('fullpath');
-idcs   = strfind(thisDir,'\');
-prefsdir = thisDir(1:idcs(end-1)-1);
-save([prefsdir '\WiscPlan_preferences.mat'], 'WiscPlan_preferences');
-
-
-% patient_dir = uifile('getdir', 'Save the patient data to directory');
-% !!! Grozomah
-% patient_dir = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
-
-% make directories
-mkdir(patient_dir);
-mkdir(fullfile(patient_dir, 'beamlet_batch_files'));
-mkdir(fullfile(patient_dir, 'geometry_files'));
-mkdir(fullfile(patient_dir, 'matlab_files'));
-mkdir(fullfile(patient_dir, 'opt_input'));
-mkdir(fullfile(patient_dir, 'opt_output'));
-
-Geometry.patient_dir = patient_dir;
-
-waitbar(2.33/total_num_steps, hWaitbar, 'Step 3: Save matlab geometry files');
-% Save matlab geometry file
-save(fullfile(patient_dir, 'matlab_files', 'Geometry.mat'), 'Geometry');
-
-waitbar(2.66/total_num_steps, hWaitbar, 'Step 3: Save raw geometry files');
-% Write binary geometry files
-fid = fopen(fullfile(patient_dir, 'geometry_files', 'rhomw.bin'), 'w');
-fwrite(fid, Geometry.rhomw, 'single');
-fclose(fid);
-
-fid = fopen(fullfile(patient_dir, 'geometry_files', 'Smw.bin'), 'w');
-fwrite(fid, Geometry.Smw, 'single');
-fclose(fid);
-
-fid = fopen(fullfile(patient_dir, 'geometry_files', 'Fmw2.bin'), 'w');
-fwrite(fid, Geometry.Fmw2, 'single');
-fclose(fid);
-
-% fid = fopen(fullfile(patient_dir, 'geometry_files', 'target_mask.bin'), 'w');
-% fwrite(fid, Geometry.BTV, 'single');
-% fclose(fid);
-
-% fid = fopen(fullfile(patient_dir, 'geometry_files', 'target_mask_SBTV.bin'), 'w');
-% fwrite(fid, Geometry.SBTV, 'single');
-% fclose(fid);
-% 
-% fid = fopen(fullfile(patient_dir, 'geometry_files', 'target_mask_HCRing.bin'), 'w');
-% fwrite(fid, Geometry.HCRing, 'single');
-% fclose(fid);
-
-% hWaitbar = waitbar(1/total_num_steps, 'Step 4, Create optimization geometry');
-
-delete(hWaitbar);
-msgbox(['Plan geometry created successfully in ' '"' patient_dir '"']);
+function [Geometry patient_dir] = RDXTPS_geometry_setup_wizard_ASP()
+%PLAN_SETUP_WIZARD Wizard to guide through plan creating
+% 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
+
+total_num_steps = 4;
+hWaitbar = waitbar(0);
+set(hWaitbar, 'Unit', 'normalized');
+op = get(hWaitbar, 'OuterPosition');
+set(hWaitbar, 'OuterPosition', op + [0 0.2 0 0]);
+
+%% -----===== DicomRT Import =====-----
+waitbar(0/total_num_steps, hWaitbar, 'Step 1: Import DicomRT');
+% try
+    Geometry = dicomrt2geometry();
+% catch EXCEPTION_DICOMRT2GEOMETRY
+%     msgbox('Failed to import DicomRT');
+%     delete(hWaitbar);
+%     rethrow(EXCEPTION_DICOMRT2GEOMETRY);
+% end
+
+if isempty(Geometry)
+    msgbox('Failed to import DicomRT');
+    delete(hWaitbar);
+    return;
+end
+
+
+%% -----===== BTV and Ring creation =====-----
+waitbar(1/total_num_steps, hWaitbar, 'Step 2: Assign target and BTV margin');
+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. ');
+if okay ~= 1
+    msgbox('Plan creation aborted');
+    delete(hWaitbar);
+    return;
+end
+
+[BTV_margin_answer] = inputdlg({sprintf('Please enter the BTV margin (cm):\n(default 0.6 cm or 1 sigma, enter 0 to skip)')}, ...
+    'BTV margin specification', 1, {'0.6'});
+if isempty(BTV_margin_answer)
+    BTV_margin = 0.6;
+else
+    BTV_margin = str2double(BTV_margin_answer{1});
+end
+
+% target_idx and BTV_margin are set. Expand PTV to BTV
+PTVmask = false(size(Geometry.rhomw));
+% for target_idx = target_indices
+        PTVmask(Geometry.ROIS{target_idx}.ind) = 1;
+% end
+if BTV_margin > 0
+    if exist('BTV_margin', 'var') && BTV_margin >= min(Geometry.voxel_size)
+        bwD = bwdistsc(PTVmask, Geometry.voxel_size);
+        Geometry.BTV = bwD <= BTV_margin;
+    end
+end
+
+% Create btv
+Geometry.ROIS{end+1} = Geometry.ROIS{end};
+Geometry.ROIS{end}.name = 'BTV';
+Geometry.ROIS{end}.num_curves = 0;
+Geometry.ROIS{end}.curves = {};
+Geometry.ROIS{end}.ind = find(Geometry.BTV);
+Geometry.ROIS{end}.visible = false;
+
+% Create ring
+[ring_margin_answer] = inputdlg({sprintf('Please enter the ring margin (cm):')}, ...
+    'Ring margin specification', 1, {'1'});
+if isempty(ring_margin_answer)
+    ring_margin = 1;
+else
+    ring_margin = str2double(ring_margin_answer{1});
+end
+bwD = bwdistsc(PTVmask, Geometry.voxel_size);
+Geometry.Ring = bwD <= ring_margin; % default ring radius 3 cm
+Geometry.Ring = xor(Geometry.Ring, PTVmask);
+Geometry.ROIS{end+1} = Geometry.ROIS{end};
+Geometry.ROIS{end}.name = 'Ring';
+Geometry.ROIS{end}.num_curves = 0;
+Geometry.ROIS{end}.curves = {};
+Geometry.ROIS{end}.ind = find(Geometry.Ring);
+Geometry.ROIS{end}.visible = false;
+
+% Create high comformity ring structure for adaptive step size
+[HCRing_margin_answer] = inputdlg({sprintf('Please enter the HC ring margin (cm):\n(default 1.2 cm or 2 sigma, enter 0 to skip)')}, ...
+    'HCRing margin specification', 1, {'1.2'});
+if isempty(HCRing_margin_answer)
+    HCRing_margin = 1.2;
+else
+    HCRing_margin = str2double(HCRing_margin_answer{1});
+end
+
+if HCRing_margin > 0
+    bwD = bwdistsc(~Geometry.BTV, Geometry.voxel_size);
+    % shrinked BTV from original BTV, such that original_BTV > target_VOI > shrinked_BTV
+    Geometry.SBTV = bwD >= HCRing_margin;
+    Geometry.HCRing = xor(Geometry.BTV, Geometry.SBTV);
+end
+
+%% -----===== Save geometry files =====-----
+waitbar(2/total_num_steps, hWaitbar, 'Step 3: Save geometry files');
+
+load('WiscPlan_preferences.mat')
+patient_dir = uigetdir(WiscPlan_preferences.patientDataPath, 'Save the patient data to directory');
+
+Geometry.data_dir = patient_dir;
+
+WiscPlan_preferences.patientDataPath = patient_dir;
+thisDir = mfilename('fullpath');
+idcs   = strfind(thisDir,'\');
+prefsdir = thisDir(1:idcs(end-1)-1);
+save([prefsdir '\WiscPlan_preferences.mat'], 'WiscPlan_preferences');
+
+
+% patient_dir = uifile('getdir', 'Save the patient data to directory');
+% !!! Grozomah
+% patient_dir = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
+
+% make directories
+mkdir(patient_dir);
+mkdir(fullfile(patient_dir, 'beamlet_batch_files'));
+mkdir(fullfile(patient_dir, 'geometry_files'));
+mkdir(fullfile(patient_dir, 'matlab_files'));
+mkdir(fullfile(patient_dir, 'opt_input'));
+mkdir(fullfile(patient_dir, 'opt_output'));
+
+Geometry.patient_dir = patient_dir;
+
+waitbar(2.33/total_num_steps, hWaitbar, 'Step 3: Save matlab geometry files');
+% Save matlab geometry file
+save(fullfile(patient_dir, 'matlab_files', 'Geometry.mat'), 'Geometry');
+
+waitbar(2.66/total_num_steps, hWaitbar, 'Step 3: Save raw geometry files');
+% Write binary geometry files
+fid = fopen(fullfile(patient_dir, 'geometry_files', 'rhomw.bin'), 'w');
+fwrite(fid, Geometry.rhomw, 'single');
+fclose(fid);
+
+fid = fopen(fullfile(patient_dir, 'geometry_files', 'Smw.bin'), 'w');
+fwrite(fid, Geometry.Smw, 'single');
+fclose(fid);
+
+fid = fopen(fullfile(patient_dir, 'geometry_files', 'Fmw2.bin'), 'w');
+fwrite(fid, Geometry.Fmw2, 'single');
+fclose(fid);
+
+% fid = fopen(fullfile(patient_dir, 'geometry_files', 'target_mask.bin'), 'w');
+% fwrite(fid, Geometry.BTV, 'single');
+% fclose(fid);
+
+% fid = fopen(fullfile(patient_dir, 'geometry_files', 'target_mask_SBTV.bin'), 'w');
+% fwrite(fid, Geometry.SBTV, 'single');
+% fclose(fid);
+% 
+% fid = fopen(fullfile(patient_dir, 'geometry_files', 'target_mask_HCRing.bin'), 'w');
+% fwrite(fid, Geometry.HCRing, 'single');
+% fclose(fid);
+
+% hWaitbar = waitbar(1/total_num_steps, 'Step 4, Create optimization geometry');
+
+delete(hWaitbar);
+msgbox(['Plan geometry created successfully in ' '"' patient_dir '"']);

+ 612 - 612
WiscPlanPhotonkV125/matlab_frontend/lab/RDX_linlsqOptimization.m

@@ -1,612 +1,612 @@
-function [weights, dose] = RDX_linlsqOptimization(optSettings)
-% Input:  optSettings structure, defined as follows:
-% optSettings
-%  .prescInfo
-%      .savePresc = 'yes' or 'no' (defaults to 'no')
-%      .presc (prescription structure, which has the form:
-%              .presc.siz = [M N Q] size of each beamlet
-%              .presc.tissue = Structure array of tissue-specific
-%                  prescription.  savePrescription subfunction has details.
-%              Defaults to an empty matrix. 
-%      .prescFileName (defaults to 'prescription.txt')
-% 
-%  .beamletInfo
-%      .saveBeamlets = 'yes' or 'no' (defaults to 'no')
-%      .saveBeamletHeader = 'yes' or 'no' (defaults to 'no')
-%      .beamletFolder (defaults to 'beamlets')
-%      .beamlets (cell array of Matlab-style sparse beamlets stored as:
-%                 .beamlets{n}.Dij{m}, where Dij contains the sparse data)
-%                 Defaults to an empty matrix.
-%      .beamletBatchBaseName  (defaults to 'beamletbatch')
-%      .beamletBatchExtension (defaults to 'bin')
-%      .beamletHeaderFileName (defaults to 'beamlet_header.txt')
-%      .Nbeamlets             (defaults to 1)
-%      .Nbeamletbatches       (defaults to 1)
-%      .beamletDim            (defaults to [1 1 1])
-%
-%  .optInfo
-%      .saveOptInfo = 'yes' or 'no' (defaults to 'no')
-%      .optRun = 'yes' or 'no'  (defaults to 'no')
-%      .waitForResults = 'yes' or 'no'  (defaults to 'no')
-%      .optFolder (Folder containing optimizer's Visual C++ code)
-%                 Defaults to 'C:\rtflynn\library\matlabAdditions\optimization\linlsq\linlsqOpt'
-%      .inputFolder (defaults to 'input')
-%      .outputFolder (defaults to 'output')
-%      .inputFile (defaults to optInput.txt)
-%      .Niterations (Defaults to 100)
-%      .Nperbatch   (Defaults to 50)
-%      .doseBatchBaseName (defaults to 'dosebatch')
-%      .doseBatchExtension (defaults to 'img')
-%      .weightBatchBaseName (defaults to 'weightbatch')
-%      .weightBatchExtension (defaults to 'img')
-%      .optExeName (defaults to 'linlsqOpt.exe')
-%      .objFuncFileName (defaults to 'objFunc.bin')
-%      .modFactor (defaults to 1e10)
-% 
-%  .initialGuessInfo
-%      .saveInitialGuess = 'yes' or 'no' (defaults to 'no')
-%      .w0 (initial guess for all beamlet weights, defaults to empty matrix)
-%      .initBeamWeightFile (defaults to 'init_beam_weight_file')
-%      .calcInitialGuessFlag (defaults to 1)  % if 1, optimizer calculates
-%            the initial guess
-%
-% Outputs:
-% w              optimized beamlet weights
-% dose           optimized dose distribution
-%
-% Outputs are empty matrices unless the 'waitForResults' flag is set to
-% 'yes'.  Otherwise, load results at a later time.
-%
-% Ryan Flynn, David Westerly
-% Xiaohu Mo
-% Fixed pathsep (/\) portability issue
-
-% Check input structure for inconistencies, set defaults for fields that
-% were optional and not included.
-optSettings = parseInput(optSettings);
-
-% From this point on, it is assumed that all fields that are required for
-% any functions for the rest of this script are present.
-
-origDir = pwd;  % copy the directory path from which this script was called
-
-warning off;
-
-% Change to the directory containing the linlsqOpt source code.
-cd(optSettings.optInfo.optFolder);
-
-% save prescription info
-savePrescription(optSettings);
-
-% save beamlet info
-saveBeamlets(optSettings);
-
-% save initial guess info
-saveInitialGuess(optSettings);
-
-% save optimization info
-saveOptInfo(optSettings);
-
-% run optimizer
-[weights, dose] = runOptimizer(optSettings);
-
-cd(origDir);   % go back to the original directory
-
-
-function optSettings = parseInput(optSettings)
-% Checks the optSettings input structure for inconsistencies and applies
-% defaults to optional fields that were not included in the input
-% structure.  
-
-% set optimizer defaults
-optSettingsDefault.prescInfo.savePresc = 'no';
-optSettingsDefault.prescInfo.presc = [];
-optSettingsDefault.prescInfo.prescFileName = 'prescription.txt';
-optSettingsDefault.beamletInfo.saveBeamlets = 'no';
-optSettingsDefault.beamletInfo.saveBeamletHeader = 'no';
-optSettingsDefault.beamletInfo.beamletFolder = 'beamlets';
-optSettingsDefault.beamletInfo.beamlets = [];
-optSettingsDefault.beamletInfo.beamletBatchBaseName = 'beamletbatch';
-optSettingsDefault.beamletInfo.beamletBatchExtension = 'bin';
-optSettingsDefault.beamletInfo.beamletHeaderFileName = 'beamlet_header.txt';
-optSettingsDefault.beamletInfo.Nbeamlets = 1;
-optSettingsDefault.beamletInfo.Nbeamletbatches = 1;
-optSettingsDefault.beamletInfo.beamletDim = [1 1 1];
-optSettingsDefault.optInfo.saveOptInfo = 'no';
-optSettingsDefault.optInfo.optRun = 'no';
-optSettingsDefault.optInfo.waitForResults = 'no';
-optSettingsDefault.optInfo.optFolder = ...
-    'F:\Treatment_Planning\optimizer';
-optSettingsDefault.optInfo.inputFolder = 'input';
-optSettingsDefault.optInfo.outputFolder = 'output';
-optSettingsDefault.optInfo.inputFile = 'optInput.txt';
-optSettingsDefault.optInfo.Niterations = 100;
-optSettingsDefault.optInfo.Nperbatch = 50;
-optSettingsDefault.optInfo.doseBatchBaseName = 'dosebatch';
-optSettingsDefault.optInfo.doseBatchExtension = 'img';
-optSettingsDefault.optInfo.weightBatchBaseName = 'weightbatch';
-optSettingsDefault.optInfo.weightBatchExtension = 'img';
-optSettingsDefault.optInfo.optExeName = 'linlsqOptimizer.exe';
-optSettingsDefault.optInfo.objFuncFileName = 'objFunc.bin';
-optSettingsDefault.optInfo.modFactor = 1e10;  % modulation factor
-optSettingsDefault.initialGuessInfo.saveInitialGuess = 'no';
-optSettingsDefault.initialGuessInfo.w0 = [];
-optSettingsDefault.initialGuessInfo.initBeamWeightFile = 'init_beam_weight_file.img';
-optSettingsDefault.initialGuessInfo.calcInitialGuessFlag = 1;
-
-% Traverse the optSettings structure tree, and, whenever a leaf is missing
-% in the tree, fill it in with its default value.
-nodeVec = [1 1];   % vector corresponding to nodes in the structure tree
-while length(nodeVec) > 1  % traverse as long as we're not back at the top of the tree
-    % Create a field access string, which is used to access the node
-    % referred to by nodeVec.
-    fldAccStr = 'optSettingsDefault';   
-    for k=2:length(nodeVec)  
-        eval(['fieldNames = fieldnames(' fldAccStr ');']);
-        fldAccStr = [fldAccStr '.' fieldNames{nodeVec(k)}];
-    end
-    
-    % Check if the field is a number or a string (leaf).
-    eval(['numFlag = isnumeric(' fldAccStr ');']);
-    eval(['charFlag = ischar(' fldAccStr ');']);
-    
-    if numFlag == 1 | charFlag == 1  % found a leaf
-        % Traverse input structure, searching for leaves that exist in the
-        % default structure but do not exist in the input structure.  This
-        % is done by working down the input tree until either a node or a
-        % leaf is missing from the input
-        fldAccStrInp = 'optSettings';
-        fldAccStrDummy = 'optSettingsDefault';
-        for k=2:length(nodeVec)
-            eval(['fieldNamesDummy = fieldnames(' fldAccStrDummy ');']);
-            eval(['fieldFlag = isfield(' fldAccStrInp ',''' fieldNamesDummy{nodeVec(k)} ''');']);
-            if fieldFlag == 1 
-                fldAccStrInp = [fldAccStrInp '.' fieldNamesDummy{nodeVec(k)}];
-                fldAccStrDummy = [fldAccStrDummy '.' fieldNamesDummy{nodeVec(k)}];
-            else  % Leaf cannot exist, so set it to its default.
-                [tok,rem] = strtok(fldAccStr,'.');
-                fldAccStrInp = ['optSettings' rem];
-                eval([fldAccStrInp ' = ' fldAccStr ';']);
-                break;
-            end
-        end
-        
-        % go to the next node vector
-        while length(nodeVec) > 1
-            fldAccStr = 'optSettingsDefault';
-            for k=2:length(nodeVec)
-                eval(['fieldNames = fieldnames(' fldAccStr ');']);
-                fldAccStr = [fldAccStr '.' fieldNames{nodeVec(k)}];
-            end
-            % Go to next leaf or nodes on the same level, if one exists.
-            if nodeVec(end) + 1 <= length(fieldNames)
-                nodeVec(end) = nodeVec(end) + 1;
-                break;
-            else % No more leaves or nodes on this level, so go up a level.
-                nodeVec(:,end) = []; 
-            end
-        end
-    else  % found another field that is not a leaf
-        nodeVec = [nodeVec 1];  % go down a level in the tree
-    end
-end
-
-% If beamlets were included with optSettings, ensure that the
-% Nbeamletbatches, Nbeamlets, and beamletDim fields are consistent
-if ~isempty(optSettings.beamletInfo.beamlets)
-    % get the beamlet dimensions
-    [Xcount,Ycount,Zcount] = size(full(optSettings.beamletInfo.beamlets{1}.Dij{1}));
-    optSettings.beamletInfo.beamletDim = [Xcount Ycount Zcount];
-    optSettings.beamletInfo.Nbeamletbatches = numel(optSettings.beamletInfo.beamlets);
-    optSettings.beamletInfo.Nbeamlets = 0;
-    for k=1:optSettings.beamletInfo.Nbeamletbatches
-        optSettings.beamletInfo.Nbeamlets = optSettings.beamletInfo.Nbeamlets ...
-            + numel(optSettings.beamletInfo.beamlets{k}.Dij);
-    end
-else
-    % If optSettings.prescInfo.presc.siz was defined, then that field
-    % should contain beamlet dimensions.
-    if isfield(optSettings.prescInfo.presc,'siz')
-        optSettings.beamletInfo.beamletDim = optSettings.prescInfo.presc.siz;
-    end
-end
-
-function savePrescription(optSettings)
-% If the savePresc field is 'yes', saves a prescription structure to a file 
-% format that is useable by the linear least squares optimizer.
-%% .prescInfo
-%%     .savePresc = 'yes' or 'no'
-%      .presc (prescription structure, which has the form:
-%              .presc.siz = [M N Q] size of each beamlet
-%              .presc.tissue = structure array of tissue-specific
-%                  prescription.  savePrescription subfunction has details.
-%      .prescFile (defaults to 'prescription.txt')
-
-infValue = 10e10;   % value of infinity
-
-% Check the savePresc flag.  If 'no', do not save prescription
-if strcmp(lower(optSettings.prescInfo.savePresc),'no')
-    return;
-end
-
-% create input and output folders
-success = mkdir(optSettings.optInfo.inputFolder); 
-
-% delete old output folder if it exists first
-success = rmdir(optSettings.optInfo.outputFolder,'s');
-success = mkdir(optSettings.optInfo.outputFolder); 
-
-% Check the prescription structure to ensure all proper fields are present.
-prescTissueFields = {'name' 'alpha' 'betaVPlus' 'dVPlus' 'vPlus' 'betaVMinus' ...
-            'dVMinus' 'vMinus' 'betaPlus' 'betaMinus' 'ind' 'dPlus' 'dMinus'};
-            
-if isempty(optSettings.prescInfo.presc)
-    error('optSettings.prescInfo.presc not defined -- define it or set optSettings.prescInfo.savePresc to ''no''');
-end
-            
-if ~isfield(optSettings.prescInfo.presc,'siz')
-    error('Missing ''siz'' field from optSettings.prescInfo.presc structure');
-end
-
-% siz is present, so make sure it is a 3 element vector
-if numel(optSettings.prescInfo.presc.siz) ~= 3
-    error('The ''siz'' field from optSettings.prescInfo.presc structure must be a 3-element vector');
-end
-
-if ~isfield(optSettings.prescInfo.presc,'tissue')
-    error('Missing ''tissue'' field from prescInfo.presc structure');
-end
-
-% search for subfields of tissue field
-for k=1:numel(prescTissueFields)
-    if ~isfield(optSettings.prescInfo.presc.tissue,prescTissueFields{k})
-        error(['Missing ''' prescTissueFields{k} ''' field from optSettings.prescInfo.presc.tissue structure']); 
-    end
-end
-
-% write the prescription file
-fid = fopen([optSettings.optInfo.inputFolder filesep optSettings.prescInfo.prescFileName],'w');
-
-if fid == -1
-    error('Failed to open prescription file.');
-end
-
-fprintf(fid,'Ntissue\n');
-fprintf(fid,[num2str(numel(optSettings.prescInfo.presc.tissue)) '\n\n']);
-
-for k=1:numel(optSettings.prescInfo.presc.tissue)   % write prescription parameters for each tissue type
-    % write the current tissue number
-    fprintf(fid,'tissueNum\n');
-    fprintf(fid,[num2str(k-1) '\n']);
-    fprintf(fid,'name\n');
-    fprintf(fid,[optSettings.prescInfo.presc.tissue(k).name '\n']);
-    
-    % throughout writing process, always check for infinities before printing values
-    
-    % write the tissue importance
-    fprintf(fid,'alpha\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).alpha)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).alpha) '\n']);
-    end
-
-    fprintf(fid,'betaVPlus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).betaVPlus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaVPlus) '\n']);
-    end
-    
-    fprintf(fid,'dVPlus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).dVPlus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).dVPlus) '\n']);
-    end
-    
-    fprintf(fid,'vPlus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).vPlus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).vPlus) '\n']);
-    end
-    
-    fprintf(fid,'betaVMinus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).betaVMinus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaVMinus) '\n']);
-    end
-    
-    fprintf(fid,'dVMinus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).dVMinus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).dVMinus) '\n']);
-    end
-    
-    fprintf(fid,'vMinus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).vMinus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).vMinus) '\n']);
-    end
-    
-    
-    fprintf(fid,'betaPlus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).betaPlus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaPlus) '\n']);
-    end
-    
-    % create a name for the underdose penalty prescription file
-    dose_presc_filename = [regexprep(optSettings.prescInfo.presc.tissue(k).name,{' ','\','/'},'') 'DosePlus.bin'];
-    fprintf(fid,'dosePlusFilename\n');
-    fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.inputFolder, dose_presc_filename));
-    
-    % save the mask as a sparse matrix
-    fid2 = fopen([optSettings.optInfo.inputFolder filesep dose_presc_filename],'wb');
-    fwrite(fid2,optSettings.prescInfo.presc.siz,'int');
-    fwrite(fid2,length(optSettings.prescInfo.presc.tissue(k).ind),'int');
-    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).ind-1,'int');
-    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).dPlus,'single');
-    fclose(fid2);
-    
-    fprintf(fid,'betaMinus\n');
-    if isinf(optSettings.prescInfo.presc.tissue(k).betaMinus)
-        fprintf(fid,[num2str(infValue) '\n']);
-    else
-        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaMinus) '\n']);
-    end
-    
-    % create a name for the overdose penalty prescription file
-    dose_presc_filename = [regexprep(optSettings.prescInfo.presc.tissue(k).name,{' ','\','/'},'') 'DoseMinus.bin'];
-    fprintf(fid,'doseMinusFilename\n');
-    fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.inputFolder, dose_presc_filename));
-    
-    % save the mask as a sparse matrix
-    fid2 = fopen([optSettings.optInfo.inputFolder filesep dose_presc_filename],'wb');
-    fwrite(fid2,optSettings.prescInfo.presc.siz,'int');
-    fwrite(fid2,length(optSettings.prescInfo.presc.tissue(k).ind),'int');
-    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).ind-1,'int');
-    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).dMinus,'single');
-    fclose(fid2);
-    
-    fprintf(fid,'\n');
-end
-
-fclose(fid);
-
-function saveBeamlets(optSettings)
-% Saves a set of beamlets to filename.  Dij is a cell array of beamlets,
-% each of which must be sparse 2D Matlab matrices.
-%
-%% .beamletInfo
-%%     .saveBeamlets = 'yes' or 'no' (if 'yes', beamlets saved)
-%%     .beamletFolder (required, folder containing beamlets their header)
-%      .beamlets (cell array of Matlab-style sparse beamlets stored as:
-%                 .beamlets{n}.Dij{m}, where Dij contains the sparse data)
-%      .beamletBatchBaseName (defaults to 'beamletbatch')
-%      .beamletBatchExtension (defaults to 'bin')
-%      .beamletHeaderFileName (defaults to 'beamlet_header.txt')
-%      .Nbeamlets
-%      .Nbeamletbatches
-%      .beamletDim
-
-% Check if the beamlet header will need to be saved
-if strcmp(lower(optSettings.beamletInfo.saveBeamletHeader),'no') ...
-    && strcmp(lower(optSettings.beamletInfo.saveBeamlets),'no')
-    return;
-end
-
-if strcmp(lower(optSettings.beamletInfo.saveBeamlets),'yes')
-    % delete all of the old beamlets and header info
-    success = rmdir([optSettings.optInfo.optFolder '/' optSettings.beamletInfo.beamletFolder],'s');
-    mkdir([optSettings.optInfo.optFolder '/' optSettings.beamletInfo.beamletFolder]);
-end
-
-% create a folder for the beamlets if it doesn't already exist
-mkdir(optSettings.beamletInfo.beamletFolder);
-
-% create the beamlet header file
-fid = fopen([optSettings.beamletInfo.beamletFolder '/' optSettings.beamletInfo.beamletHeaderFileName],'w');
-if fid == -1
-    error('Failed to open beamlet header file.');
-end
-
-fprintf(fid,'beamletDim\n');
-fprintf(fid,'%g %g %g\n',optSettings.beamletInfo.beamletDim);
-fprintf(fid,'Nbeamlets\n');
-fprintf(fid,'%g\n',optSettings.beamletInfo.Nbeamlets);
-fprintf(fid,'Nbeamletbatches\n');
-fprintf(fid,'%g\n',optSettings.beamletInfo.Nbeamletbatches);
-fprintf(fid,'beamletFolder\n');
-fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.beamletInfo.beamletFolder));
-fprintf(fid,'beamletBatchBaseName\n');
-fprintf(fid,[optSettings.beamletInfo.beamletBatchBaseName '\n']);
-fprintf(fid,'beamletBatchExtension\n');
-fprintf(fid,[optSettings.beamletInfo.beamletBatchExtension '\n']);
-fclose(fid);
-
-% Check if the beamlets need to be saved
-if strcmp(lower(optSettings.beamletInfo.saveBeamlets),'no')
-    return;
-end
-
-if isempty(optSettings.beamletInfo.beamlets)
-    error('No beamlets to save -- supply beamlets or set saveBeamlets to ''no''');
-end
-
-% Save the beamlets
-beamletNum = 0;
-for k=1:optSettings.beamletInfo.Nbeamletbatches
-    beamletFileName = [optSettings.beamletInfo.beamletFolder '/' ...
-        optSettings.beamletInfo.beamletBatchBaseName num2str(k-1) '.' ...
-        optSettings.beamletInfo.beamletBatchExtension];
-    fid = fopen(beamletFileName,'wb');
-    if fid == -1
-        error(['Failed to open ' beamletFileName]);
-    end
-    Nbib = numel(optSettings.beamletInfo.beamlets{k}.Dij);  % number of beamlet in batch
-    fwrite(fid,Nbib,'int');
-    for m=1:Nbib
-        % dimensions of current beamlet
-        [Nx,Ny,Nz] = size(full(optSettings.beamletInfo.beamlets{k}.Dij{m}));
-        if Nx - optSettings.beamletInfo.beamletDim(1) ~= 0 ...
-        || Ny - optSettings.beamletInfo.beamletDim(2) ~= 0 ...
-        || Nz - optSettings.beamletInfo.beamletDim(3) ~= 0
-            error(['Dimensions of optSettings.beamletInfo.beamlets{' ...
-                num2str(k) '}.Dij{' num2str(m) '} are not (' ...
-                num2str(optSettings.beamletInfo.beamletDim(1)) ',' ...
-                num2str(optSettings.beamletInfo.beamletDim(2)) ',' ...
-                num2str(optSettings.beamletInfo.beamletDim(3)) ')']);
-        end
-        % save the beamlet
-        fwrite(fid,beamletNum,'int');  % beamlet number
-        fwrite(fid,optSettings.beamletInfo.beamletDim,'int');  % beamlet dimensions
-        ind = find(optSettings.beamletInfo.beamlets{k}.Dij{m}); % beamlet indices
-        ind = ind - 1;  % convert Matlab indices to C indices
-        fwrite(fid,numel(ind),'int');  % number of non-zero indices
-        fwrite(fid,ind,'int');         % non-zero indices
-        fwrite(fid,nonzeros(optSettings.beamletInfo.beamlets{k}.Dij{m}),'float');
-        beamletNum = beamletNum + 1;
-    end
-    fclose(fid);  % close the current beamlet batch
-end
-
-function saveInitialGuess(optSettings)
-% save the initial guess
-
-% exit if the initial guess is not to be saved
-if strcmp(lower(optSettings.initialGuessInfo.saveInitialGuess),'no')
-    return;
-end
-
-% create input and output folders
-success = mkdir(optSettings.optInfo.inputFolder); 
-success = mkdir(optSettings.optInfo.outputFolder); 
-
-initBeamWeightFile = [optSettings.optInfo.optFolder filesep optSettings.optInfo.inputFolder ...
-    filesep optSettings.initialGuessInfo.initBeamWeightFile];
-
-fid = fopen(initBeamWeightFile,'wb');
-if fid == -1
-    error(['Failed to open initial beam weight file: ' initBeamWeightFile]);
-end
-fwrite(fid,optSettings.initialGuessInfo.w0,'float');
-fclose(fid);
-
-function saveOptInfo(optSettings)
-
-% Exit if optimization info is not supposed to be saved
-if strcmp(lower(optSettings.optInfo.saveOptInfo),'no')
-    return;
-end
-
-% create input and output folders
-success = mkdir(optSettings.optInfo.inputFolder); 
-success = mkdir(optSettings.optInfo.outputFolder); 
-
-% create the optimization input file
-optInfoFileName = optSettings.optInfo.inputFile;
-fid = fopen(optInfoFileName,'w');
-if fid == -1
-    error(['Failed to open optimization input file: ' optInfoFileName]);
-end
-
-fprintf(fid,'Niterations\n');
-fprintf(fid,'%d\n',optSettings.optInfo.Niterations);
-fprintf(fid,'Nperbatch\n');
-fprintf(fid,'%d\n',optSettings.optInfo.Nperbatch);
-fprintf(fid,'prescFile\n');
-fprintf(fid,'%s\n',fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.inputFolder, optSettings.prescInfo.prescFileName));
-fprintf(fid,'initBeamWeightFile\n');
-if optSettings.initialGuessInfo.calcInitialGuessFlag == 0
-    % supply the initial guess file
-    fprintf(fid,'%s\n',[optSettings.optInfo.optFolder '/' optSettings.initialGuessInfo.initBeamWeightFile]);
-else % no need to supply file, as optimizer will calculate initial guess
-    fprintf(fid,'%s\n','optimizerCalculatesInitialGuess');
-end
-fprintf(fid,'beamletHeaderFileName\n');
-fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.beamletInfo.beamletFolder, optSettings.beamletInfo.beamletHeaderFileName));
-fprintf(fid,'doseBatchBaseName\n');
-fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.outputFolder, optSettings.optInfo.doseBatchBaseName));
-fprintf(fid,'doseBatchExtension\n');
-fprintf(fid,[optSettings.optInfo.doseBatchExtension '\n']);
-fprintf(fid,'weightBatchBaseName\n');
-fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.outputFolder, optSettings.optInfo.weightBatchBaseName));
-fprintf(fid,'weightBatchExtension\n');
-fprintf(fid,[optSettings.optInfo.weightBatchExtension '\n']);
-fprintf(fid,'objFuncFileName\n');
-fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.outputFolder, optSettings.optInfo.objFuncFileName));
-fprintf(fid,'modFactor\n');
-fprintf(fid,[num2str(optSettings.optInfo.modFactor) '\n']);
-fprintf(fid,'calcInitialGuessFlag\n');
-fprintf(fid,[num2str(optSettings.initialGuessInfo.calcInitialGuessFlag) '\n']);
-fclose(fid);
-
-function [weights, dose] = runOptimizer(optSettings)
-
-dose = [];
-weights = [];
-
-% Exit function of optimizer is not to be run.
-if strcmp(lower(optSettings.optInfo.optRun),'no')
-    return;
-end
-
-currDir = pwd;  % save a copy of the current directory path
-
-% copy the most recent build of optimizer to the optFolder
-exeDebugFile = [optSettings.optInfo.optFolder '\Debug\' optSettings.optInfo.optExeName];
-exeFile = [optSettings.optInfo.optFolder filesep optSettings.optInfo.optExeName];
-success = copyfile(exeDebugFile,exeFile);
-
-if success == 0
-    error(['Error copying ' exeDebugFile ' to ' exeFile]);
-end
-
-% do the optimization
-delete('optDone.txt');   % delete the old dose file if it exists
-fprintf('Running optimizer...\n');
-% run the optimization from the console
-eval(['! ' optSettings.optInfo.optExeName ' ' optSettings.optInfo.inputFile ' &']); 
-
-% Exit if the user did not wish to wait for results
-if strcmp(lower(optSettings.optInfo.waitForResults),'no')
-    return;
-end
-
-% Check for the flag indicating that the optimization is finished
-while ~exist('optDone.txt','file')
-    pause(1);   % pause before resuming
-end
-
-% Optimization finished, so load the beamlet weights
-fid = fopen([optSettings.optInfo.outputFolder '/' ...
-    optSettings.optInfo.weightBatchBaseName num2str(optSettings.optInfo.Niterations) '.' ...
-    optSettings.optInfo.weightBatchExtension],'rb');
-if fid == -1
-    error('Unable to open optimized weight results.');
-end
-
-weights = fread(fid,'float');
-fclose(fid);
-
-% load the dose distribution
-fid = fopen([optSettings.optInfo.outputFolder '/' ...
-    optSettings.optInfo.doseBatchBaseName num2str(optSettings.optInfo.Niterations) '.' ...
-    optSettings.optInfo.doseBatchExtension],'rb');
-if fid == -1
-    error('Unable to open optimized dose results.');
-end
-
-dose = fread(fid,'float');
-try
-    dose = reshape(dose,optSettings.beamletInfo.beamletDim);
-catch
-    error(['Unable to reshape optimized dose distribution. Ensure ' ...
-     'that optSettings.beamletInfo.beamletDim field matches dose grid dimensions']);
-end
+function [weights, dose] = RDX_linlsqOptimization(optSettings)
+% Input:  optSettings structure, defined as follows:
+% optSettings
+%  .prescInfo
+%      .savePresc = 'yes' or 'no' (defaults to 'no')
+%      .presc (prescription structure, which has the form:
+%              .presc.siz = [M N Q] size of each beamlet
+%              .presc.tissue = Structure array of tissue-specific
+%                  prescription.  savePrescription subfunction has details.
+%              Defaults to an empty matrix. 
+%      .prescFileName (defaults to 'prescription.txt')
+% 
+%  .beamletInfo
+%      .saveBeamlets = 'yes' or 'no' (defaults to 'no')
+%      .saveBeamletHeader = 'yes' or 'no' (defaults to 'no')
+%      .beamletFolder (defaults to 'beamlets')
+%      .beamlets (cell array of Matlab-style sparse beamlets stored as:
+%                 .beamlets{n}.Dij{m}, where Dij contains the sparse data)
+%                 Defaults to an empty matrix.
+%      .beamletBatchBaseName  (defaults to 'beamletbatch')
+%      .beamletBatchExtension (defaults to 'bin')
+%      .beamletHeaderFileName (defaults to 'beamlet_header.txt')
+%      .Nbeamlets             (defaults to 1)
+%      .Nbeamletbatches       (defaults to 1)
+%      .beamletDim            (defaults to [1 1 1])
+%
+%  .optInfo
+%      .saveOptInfo = 'yes' or 'no' (defaults to 'no')
+%      .optRun = 'yes' or 'no'  (defaults to 'no')
+%      .waitForResults = 'yes' or 'no'  (defaults to 'no')
+%      .optFolder (Folder containing optimizer's Visual C++ code)
+%                 Defaults to 'C:\rtflynn\library\matlabAdditions\optimization\linlsq\linlsqOpt'
+%      .inputFolder (defaults to 'input')
+%      .outputFolder (defaults to 'output')
+%      .inputFile (defaults to optInput.txt)
+%      .Niterations (Defaults to 100)
+%      .Nperbatch   (Defaults to 50)
+%      .doseBatchBaseName (defaults to 'dosebatch')
+%      .doseBatchExtension (defaults to 'img')
+%      .weightBatchBaseName (defaults to 'weightbatch')
+%      .weightBatchExtension (defaults to 'img')
+%      .optExeName (defaults to 'linlsqOpt.exe')
+%      .objFuncFileName (defaults to 'objFunc.bin')
+%      .modFactor (defaults to 1e10)
+% 
+%  .initialGuessInfo
+%      .saveInitialGuess = 'yes' or 'no' (defaults to 'no')
+%      .w0 (initial guess for all beamlet weights, defaults to empty matrix)
+%      .initBeamWeightFile (defaults to 'init_beam_weight_file')
+%      .calcInitialGuessFlag (defaults to 1)  % if 1, optimizer calculates
+%            the initial guess
+%
+% Outputs:
+% w              optimized beamlet weights
+% dose           optimized dose distribution
+%
+% Outputs are empty matrices unless the 'waitForResults' flag is set to
+% 'yes'.  Otherwise, load results at a later time.
+%
+% Ryan Flynn, David Westerly
+% Xiaohu Mo
+% Fixed pathsep (/\) portability issue
+
+% Check input structure for inconistencies, set defaults for fields that
+% were optional and not included.
+optSettings = parseInput(optSettings);
+
+% From this point on, it is assumed that all fields that are required for
+% any functions for the rest of this script are present.
+
+origDir = pwd;  % copy the directory path from which this script was called
+
+warning off;
+
+% Change to the directory containing the linlsqOpt source code.
+cd(optSettings.optInfo.optFolder);
+
+% save prescription info
+savePrescription(optSettings);
+
+% save beamlet info
+saveBeamlets(optSettings);
+
+% save initial guess info
+saveInitialGuess(optSettings);
+
+% save optimization info
+saveOptInfo(optSettings);
+
+% run optimizer
+[weights, dose] = runOptimizer(optSettings);
+
+cd(origDir);   % go back to the original directory
+
+
+function optSettings = parseInput(optSettings)
+% Checks the optSettings input structure for inconsistencies and applies
+% defaults to optional fields that were not included in the input
+% structure.  
+
+% set optimizer defaults
+optSettingsDefault.prescInfo.savePresc = 'no';
+optSettingsDefault.prescInfo.presc = [];
+optSettingsDefault.prescInfo.prescFileName = 'prescription.txt';
+optSettingsDefault.beamletInfo.saveBeamlets = 'no';
+optSettingsDefault.beamletInfo.saveBeamletHeader = 'no';
+optSettingsDefault.beamletInfo.beamletFolder = 'beamlets';
+optSettingsDefault.beamletInfo.beamlets = [];
+optSettingsDefault.beamletInfo.beamletBatchBaseName = 'beamletbatch';
+optSettingsDefault.beamletInfo.beamletBatchExtension = 'bin';
+optSettingsDefault.beamletInfo.beamletHeaderFileName = 'beamlet_header.txt';
+optSettingsDefault.beamletInfo.Nbeamlets = 1;
+optSettingsDefault.beamletInfo.Nbeamletbatches = 1;
+optSettingsDefault.beamletInfo.beamletDim = [1 1 1];
+optSettingsDefault.optInfo.saveOptInfo = 'no';
+optSettingsDefault.optInfo.optRun = 'no';
+optSettingsDefault.optInfo.waitForResults = 'no';
+optSettingsDefault.optInfo.optFolder = ...
+    'F:\Treatment_Planning\optimizer';
+optSettingsDefault.optInfo.inputFolder = 'input';
+optSettingsDefault.optInfo.outputFolder = 'output';
+optSettingsDefault.optInfo.inputFile = 'optInput.txt';
+optSettingsDefault.optInfo.Niterations = 100;
+optSettingsDefault.optInfo.Nperbatch = 50;
+optSettingsDefault.optInfo.doseBatchBaseName = 'dosebatch';
+optSettingsDefault.optInfo.doseBatchExtension = 'img';
+optSettingsDefault.optInfo.weightBatchBaseName = 'weightbatch';
+optSettingsDefault.optInfo.weightBatchExtension = 'img';
+optSettingsDefault.optInfo.optExeName = 'linlsqOptimizer.exe';
+optSettingsDefault.optInfo.objFuncFileName = 'objFunc.bin';
+optSettingsDefault.optInfo.modFactor = 1e10;  % modulation factor
+optSettingsDefault.initialGuessInfo.saveInitialGuess = 'no';
+optSettingsDefault.initialGuessInfo.w0 = [];
+optSettingsDefault.initialGuessInfo.initBeamWeightFile = 'init_beam_weight_file.img';
+optSettingsDefault.initialGuessInfo.calcInitialGuessFlag = 1;
+
+% Traverse the optSettings structure tree, and, whenever a leaf is missing
+% in the tree, fill it in with its default value.
+nodeVec = [1 1];   % vector corresponding to nodes in the structure tree
+while length(nodeVec) > 1  % traverse as long as we're not back at the top of the tree
+    % Create a field access string, which is used to access the node
+    % referred to by nodeVec.
+    fldAccStr = 'optSettingsDefault';   
+    for k=2:length(nodeVec)  
+        eval(['fieldNames = fieldnames(' fldAccStr ');']);
+        fldAccStr = [fldAccStr '.' fieldNames{nodeVec(k)}];
+    end
+    
+    % Check if the field is a number or a string (leaf).
+    eval(['numFlag = isnumeric(' fldAccStr ');']);
+    eval(['charFlag = ischar(' fldAccStr ');']);
+    
+    if numFlag == 1 | charFlag == 1  % found a leaf
+        % Traverse input structure, searching for leaves that exist in the
+        % default structure but do not exist in the input structure.  This
+        % is done by working down the input tree until either a node or a
+        % leaf is missing from the input
+        fldAccStrInp = 'optSettings';
+        fldAccStrDummy = 'optSettingsDefault';
+        for k=2:length(nodeVec)
+            eval(['fieldNamesDummy = fieldnames(' fldAccStrDummy ');']);
+            eval(['fieldFlag = isfield(' fldAccStrInp ',''' fieldNamesDummy{nodeVec(k)} ''');']);
+            if fieldFlag == 1 
+                fldAccStrInp = [fldAccStrInp '.' fieldNamesDummy{nodeVec(k)}];
+                fldAccStrDummy = [fldAccStrDummy '.' fieldNamesDummy{nodeVec(k)}];
+            else  % Leaf cannot exist, so set it to its default.
+                [tok,rem] = strtok(fldAccStr,'.');
+                fldAccStrInp = ['optSettings' rem];
+                eval([fldAccStrInp ' = ' fldAccStr ';']);
+                break;
+            end
+        end
+        
+        % go to the next node vector
+        while length(nodeVec) > 1
+            fldAccStr = 'optSettingsDefault';
+            for k=2:length(nodeVec)
+                eval(['fieldNames = fieldnames(' fldAccStr ');']);
+                fldAccStr = [fldAccStr '.' fieldNames{nodeVec(k)}];
+            end
+            % Go to next leaf or nodes on the same level, if one exists.
+            if nodeVec(end) + 1 <= length(fieldNames)
+                nodeVec(end) = nodeVec(end) + 1;
+                break;
+            else % No more leaves or nodes on this level, so go up a level.
+                nodeVec(:,end) = []; 
+            end
+        end
+    else  % found another field that is not a leaf
+        nodeVec = [nodeVec 1];  % go down a level in the tree
+    end
+end
+
+% If beamlets were included with optSettings, ensure that the
+% Nbeamletbatches, Nbeamlets, and beamletDim fields are consistent
+if ~isempty(optSettings.beamletInfo.beamlets)
+    % get the beamlet dimensions
+    [Xcount,Ycount,Zcount] = size(full(optSettings.beamletInfo.beamlets{1}.Dij{1}));
+    optSettings.beamletInfo.beamletDim = [Xcount Ycount Zcount];
+    optSettings.beamletInfo.Nbeamletbatches = numel(optSettings.beamletInfo.beamlets);
+    optSettings.beamletInfo.Nbeamlets = 0;
+    for k=1:optSettings.beamletInfo.Nbeamletbatches
+        optSettings.beamletInfo.Nbeamlets = optSettings.beamletInfo.Nbeamlets ...
+            + numel(optSettings.beamletInfo.beamlets{k}.Dij);
+    end
+else
+    % If optSettings.prescInfo.presc.siz was defined, then that field
+    % should contain beamlet dimensions.
+    if isfield(optSettings.prescInfo.presc,'siz')
+        optSettings.beamletInfo.beamletDim = optSettings.prescInfo.presc.siz;
+    end
+end
+
+function savePrescription(optSettings)
+% If the savePresc field is 'yes', saves a prescription structure to a file 
+% format that is useable by the linear least squares optimizer.
+%% .prescInfo
+%%     .savePresc = 'yes' or 'no'
+%      .presc (prescription structure, which has the form:
+%              .presc.siz = [M N Q] size of each beamlet
+%              .presc.tissue = structure array of tissue-specific
+%                  prescription.  savePrescription subfunction has details.
+%      .prescFile (defaults to 'prescription.txt')
+
+infValue = 10e10;   % value of infinity
+
+% Check the savePresc flag.  If 'no', do not save prescription
+if strcmp(lower(optSettings.prescInfo.savePresc),'no')
+    return;
+end
+
+% create input and output folders
+success = mkdir(optSettings.optInfo.inputFolder); 
+
+% delete old output folder if it exists first
+success = rmdir(optSettings.optInfo.outputFolder,'s');
+success = mkdir(optSettings.optInfo.outputFolder); 
+
+% Check the prescription structure to ensure all proper fields are present.
+prescTissueFields = {'name' 'alpha' 'betaVPlus' 'dVPlus' 'vPlus' 'betaVMinus' ...
+            'dVMinus' 'vMinus' 'betaPlus' 'betaMinus' 'ind' 'dPlus' 'dMinus'};
+            
+if isempty(optSettings.prescInfo.presc)
+    error('optSettings.prescInfo.presc not defined -- define it or set optSettings.prescInfo.savePresc to ''no''');
+end
+            
+if ~isfield(optSettings.prescInfo.presc,'siz')
+    error('Missing ''siz'' field from optSettings.prescInfo.presc structure');
+end
+
+% siz is present, so make sure it is a 3 element vector
+if numel(optSettings.prescInfo.presc.siz) ~= 3
+    error('The ''siz'' field from optSettings.prescInfo.presc structure must be a 3-element vector');
+end
+
+if ~isfield(optSettings.prescInfo.presc,'tissue')
+    error('Missing ''tissue'' field from prescInfo.presc structure');
+end
+
+% search for subfields of tissue field
+for k=1:numel(prescTissueFields)
+    if ~isfield(optSettings.prescInfo.presc.tissue,prescTissueFields{k})
+        error(['Missing ''' prescTissueFields{k} ''' field from optSettings.prescInfo.presc.tissue structure']); 
+    end
+end
+
+% write the prescription file
+fid = fopen([optSettings.optInfo.inputFolder filesep optSettings.prescInfo.prescFileName],'w');
+
+if fid == -1
+    error('Failed to open prescription file.');
+end
+
+fprintf(fid,'Ntissue\n');
+fprintf(fid,[num2str(numel(optSettings.prescInfo.presc.tissue)) '\n\n']);
+
+for k=1:numel(optSettings.prescInfo.presc.tissue)   % write prescription parameters for each tissue type
+    % write the current tissue number
+    fprintf(fid,'tissueNum\n');
+    fprintf(fid,[num2str(k-1) '\n']);
+    fprintf(fid,'name\n');
+    fprintf(fid,[optSettings.prescInfo.presc.tissue(k).name '\n']);
+    
+    % throughout writing process, always check for infinities before printing values
+    
+    % write the tissue importance
+    fprintf(fid,'alpha\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).alpha)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).alpha) '\n']);
+    end
+
+    fprintf(fid,'betaVPlus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).betaVPlus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaVPlus) '\n']);
+    end
+    
+    fprintf(fid,'dVPlus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).dVPlus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).dVPlus) '\n']);
+    end
+    
+    fprintf(fid,'vPlus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).vPlus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).vPlus) '\n']);
+    end
+    
+    fprintf(fid,'betaVMinus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).betaVMinus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaVMinus) '\n']);
+    end
+    
+    fprintf(fid,'dVMinus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).dVMinus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).dVMinus) '\n']);
+    end
+    
+    fprintf(fid,'vMinus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).vMinus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).vMinus) '\n']);
+    end
+    
+    
+    fprintf(fid,'betaPlus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).betaPlus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaPlus) '\n']);
+    end
+    
+    % create a name for the underdose penalty prescription file
+    dose_presc_filename = [regexprep(optSettings.prescInfo.presc.tissue(k).name,{' ','\','/'},'') 'DosePlus.bin'];
+    fprintf(fid,'dosePlusFilename\n');
+    fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.inputFolder, dose_presc_filename));
+    
+    % save the mask as a sparse matrix
+    fid2 = fopen([optSettings.optInfo.inputFolder filesep dose_presc_filename],'wb');
+    fwrite(fid2,optSettings.prescInfo.presc.siz,'int');
+    fwrite(fid2,length(optSettings.prescInfo.presc.tissue(k).ind),'int');
+    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).ind-1,'int');
+    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).dPlus,'single');
+    fclose(fid2);
+    
+    fprintf(fid,'betaMinus\n');
+    if isinf(optSettings.prescInfo.presc.tissue(k).betaMinus)
+        fprintf(fid,[num2str(infValue) '\n']);
+    else
+        fprintf(fid,[num2str(optSettings.prescInfo.presc.tissue(k).betaMinus) '\n']);
+    end
+    
+    % create a name for the overdose penalty prescription file
+    dose_presc_filename = [regexprep(optSettings.prescInfo.presc.tissue(k).name,{' ','\','/'},'') 'DoseMinus.bin'];
+    fprintf(fid,'doseMinusFilename\n');
+    fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.inputFolder, dose_presc_filename));
+    
+    % save the mask as a sparse matrix
+    fid2 = fopen([optSettings.optInfo.inputFolder filesep dose_presc_filename],'wb');
+    fwrite(fid2,optSettings.prescInfo.presc.siz,'int');
+    fwrite(fid2,length(optSettings.prescInfo.presc.tissue(k).ind),'int');
+    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).ind-1,'int');
+    fwrite(fid2,optSettings.prescInfo.presc.tissue(k).dMinus,'single');
+    fclose(fid2);
+    
+    fprintf(fid,'\n');
+end
+
+fclose(fid);
+
+function saveBeamlets(optSettings)
+% Saves a set of beamlets to filename.  Dij is a cell array of beamlets,
+% each of which must be sparse 2D Matlab matrices.
+%
+%% .beamletInfo
+%%     .saveBeamlets = 'yes' or 'no' (if 'yes', beamlets saved)
+%%     .beamletFolder (required, folder containing beamlets their header)
+%      .beamlets (cell array of Matlab-style sparse beamlets stored as:
+%                 .beamlets{n}.Dij{m}, where Dij contains the sparse data)
+%      .beamletBatchBaseName (defaults to 'beamletbatch')
+%      .beamletBatchExtension (defaults to 'bin')
+%      .beamletHeaderFileName (defaults to 'beamlet_header.txt')
+%      .Nbeamlets
+%      .Nbeamletbatches
+%      .beamletDim
+
+% Check if the beamlet header will need to be saved
+if strcmp(lower(optSettings.beamletInfo.saveBeamletHeader),'no') ...
+    && strcmp(lower(optSettings.beamletInfo.saveBeamlets),'no')
+    return;
+end
+
+if strcmp(lower(optSettings.beamletInfo.saveBeamlets),'yes')
+    % delete all of the old beamlets and header info
+    success = rmdir([optSettings.optInfo.optFolder '/' optSettings.beamletInfo.beamletFolder],'s');
+    mkdir([optSettings.optInfo.optFolder '/' optSettings.beamletInfo.beamletFolder]);
+end
+
+% create a folder for the beamlets if it doesn't already exist
+mkdir(optSettings.beamletInfo.beamletFolder);
+
+% create the beamlet header file
+fid = fopen([optSettings.beamletInfo.beamletFolder '/' optSettings.beamletInfo.beamletHeaderFileName],'w');
+if fid == -1
+    error('Failed to open beamlet header file.');
+end
+
+fprintf(fid,'beamletDim\n');
+fprintf(fid,'%g %g %g\n',optSettings.beamletInfo.beamletDim);
+fprintf(fid,'Nbeamlets\n');
+fprintf(fid,'%g\n',optSettings.beamletInfo.Nbeamlets);
+fprintf(fid,'Nbeamletbatches\n');
+fprintf(fid,'%g\n',optSettings.beamletInfo.Nbeamletbatches);
+fprintf(fid,'beamletFolder\n');
+fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.beamletInfo.beamletFolder));
+fprintf(fid,'beamletBatchBaseName\n');
+fprintf(fid,[optSettings.beamletInfo.beamletBatchBaseName '\n']);
+fprintf(fid,'beamletBatchExtension\n');
+fprintf(fid,[optSettings.beamletInfo.beamletBatchExtension '\n']);
+fclose(fid);
+
+% Check if the beamlets need to be saved
+if strcmp(lower(optSettings.beamletInfo.saveBeamlets),'no')
+    return;
+end
+
+if isempty(optSettings.beamletInfo.beamlets)
+    error('No beamlets to save -- supply beamlets or set saveBeamlets to ''no''');
+end
+
+% Save the beamlets
+beamletNum = 0;
+for k=1:optSettings.beamletInfo.Nbeamletbatches
+    beamletFileName = [optSettings.beamletInfo.beamletFolder '/' ...
+        optSettings.beamletInfo.beamletBatchBaseName num2str(k-1) '.' ...
+        optSettings.beamletInfo.beamletBatchExtension];
+    fid = fopen(beamletFileName,'wb');
+    if fid == -1
+        error(['Failed to open ' beamletFileName]);
+    end
+    Nbib = numel(optSettings.beamletInfo.beamlets{k}.Dij);  % number of beamlet in batch
+    fwrite(fid,Nbib,'int');
+    for m=1:Nbib
+        % dimensions of current beamlet
+        [Nx,Ny,Nz] = size(full(optSettings.beamletInfo.beamlets{k}.Dij{m}));
+        if Nx - optSettings.beamletInfo.beamletDim(1) ~= 0 ...
+        || Ny - optSettings.beamletInfo.beamletDim(2) ~= 0 ...
+        || Nz - optSettings.beamletInfo.beamletDim(3) ~= 0
+            error(['Dimensions of optSettings.beamletInfo.beamlets{' ...
+                num2str(k) '}.Dij{' num2str(m) '} are not (' ...
+                num2str(optSettings.beamletInfo.beamletDim(1)) ',' ...
+                num2str(optSettings.beamletInfo.beamletDim(2)) ',' ...
+                num2str(optSettings.beamletInfo.beamletDim(3)) ')']);
+        end
+        % save the beamlet
+        fwrite(fid,beamletNum,'int');  % beamlet number
+        fwrite(fid,optSettings.beamletInfo.beamletDim,'int');  % beamlet dimensions
+        ind = find(optSettings.beamletInfo.beamlets{k}.Dij{m}); % beamlet indices
+        ind = ind - 1;  % convert Matlab indices to C indices
+        fwrite(fid,numel(ind),'int');  % number of non-zero indices
+        fwrite(fid,ind,'int');         % non-zero indices
+        fwrite(fid,nonzeros(optSettings.beamletInfo.beamlets{k}.Dij{m}),'float');
+        beamletNum = beamletNum + 1;
+    end
+    fclose(fid);  % close the current beamlet batch
+end
+
+function saveInitialGuess(optSettings)
+% save the initial guess
+
+% exit if the initial guess is not to be saved
+if strcmp(lower(optSettings.initialGuessInfo.saveInitialGuess),'no')
+    return;
+end
+
+% create input and output folders
+success = mkdir(optSettings.optInfo.inputFolder); 
+success = mkdir(optSettings.optInfo.outputFolder); 
+
+initBeamWeightFile = [optSettings.optInfo.optFolder filesep optSettings.optInfo.inputFolder ...
+    filesep optSettings.initialGuessInfo.initBeamWeightFile];
+
+fid = fopen(initBeamWeightFile,'wb');
+if fid == -1
+    error(['Failed to open initial beam weight file: ' initBeamWeightFile]);
+end
+fwrite(fid,optSettings.initialGuessInfo.w0,'float');
+fclose(fid);
+
+function saveOptInfo(optSettings)
+
+% Exit if optimization info is not supposed to be saved
+if strcmp(lower(optSettings.optInfo.saveOptInfo),'no')
+    return;
+end
+
+% create input and output folders
+success = mkdir(optSettings.optInfo.inputFolder); 
+success = mkdir(optSettings.optInfo.outputFolder); 
+
+% create the optimization input file
+optInfoFileName = optSettings.optInfo.inputFile;
+fid = fopen(optInfoFileName,'w');
+if fid == -1
+    error(['Failed to open optimization input file: ' optInfoFileName]);
+end
+
+fprintf(fid,'Niterations\n');
+fprintf(fid,'%d\n',optSettings.optInfo.Niterations);
+fprintf(fid,'Nperbatch\n');
+fprintf(fid,'%d\n',optSettings.optInfo.Nperbatch);
+fprintf(fid,'prescFile\n');
+fprintf(fid,'%s\n',fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.inputFolder, optSettings.prescInfo.prescFileName));
+fprintf(fid,'initBeamWeightFile\n');
+if optSettings.initialGuessInfo.calcInitialGuessFlag == 0
+    % supply the initial guess file
+    fprintf(fid,'%s\n',[optSettings.optInfo.optFolder '/' optSettings.initialGuessInfo.initBeamWeightFile]);
+else % no need to supply file, as optimizer will calculate initial guess
+    fprintf(fid,'%s\n','optimizerCalculatesInitialGuess');
+end
+fprintf(fid,'beamletHeaderFileName\n');
+fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.beamletInfo.beamletFolder, optSettings.beamletInfo.beamletHeaderFileName));
+fprintf(fid,'doseBatchBaseName\n');
+fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.outputFolder, optSettings.optInfo.doseBatchBaseName));
+fprintf(fid,'doseBatchExtension\n');
+fprintf(fid,[optSettings.optInfo.doseBatchExtension '\n']);
+fprintf(fid,'weightBatchBaseName\n');
+fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.outputFolder, optSettings.optInfo.weightBatchBaseName));
+fprintf(fid,'weightBatchExtension\n');
+fprintf(fid,[optSettings.optInfo.weightBatchExtension '\n']);
+fprintf(fid,'objFuncFileName\n');
+fprintf(fid,'%s\n', fullfile(optSettings.optInfo.optFolder, optSettings.optInfo.outputFolder, optSettings.optInfo.objFuncFileName));
+fprintf(fid,'modFactor\n');
+fprintf(fid,[num2str(optSettings.optInfo.modFactor) '\n']);
+fprintf(fid,'calcInitialGuessFlag\n');
+fprintf(fid,[num2str(optSettings.initialGuessInfo.calcInitialGuessFlag) '\n']);
+fclose(fid);
+
+function [weights, dose] = runOptimizer(optSettings)
+
+dose = [];
+weights = [];
+
+% Exit function of optimizer is not to be run.
+if strcmp(lower(optSettings.optInfo.optRun),'no')
+    return;
+end
+
+currDir = pwd;  % save a copy of the current directory path
+
+% copy the most recent build of optimizer to the optFolder
+exeDebugFile = [optSettings.optInfo.optFolder '\Debug\' optSettings.optInfo.optExeName];
+exeFile = [optSettings.optInfo.optFolder filesep optSettings.optInfo.optExeName];
+success = copyfile(exeDebugFile,exeFile);
+
+if success == 0
+    error(['Error copying ' exeDebugFile ' to ' exeFile]);
+end
+
+% do the optimization
+delete('optDone.txt');   % delete the old dose file if it exists
+fprintf('Running optimizer...\n');
+% run the optimization from the console
+eval(['! ' optSettings.optInfo.optExeName ' ' optSettings.optInfo.inputFile ' &']); 
+
+% Exit if the user did not wish to wait for results
+if strcmp(lower(optSettings.optInfo.waitForResults),'no')
+    return;
+end
+
+% Check for the flag indicating that the optimization is finished
+while ~exist('optDone.txt','file')
+    pause(1);   % pause before resuming
+end
+
+% Optimization finished, so load the beamlet weights
+fid = fopen([optSettings.optInfo.outputFolder '/' ...
+    optSettings.optInfo.weightBatchBaseName num2str(optSettings.optInfo.Niterations) '.' ...
+    optSettings.optInfo.weightBatchExtension],'rb');
+if fid == -1
+    error('Unable to open optimized weight results.');
+end
+
+weights = fread(fid,'float');
+fclose(fid);
+
+% load the dose distribution
+fid = fopen([optSettings.optInfo.outputFolder '/' ...
+    optSettings.optInfo.doseBatchBaseName num2str(optSettings.optInfo.Niterations) '.' ...
+    optSettings.optInfo.doseBatchExtension],'rb');
+if fid == -1
+    error('Unable to open optimized dose results.');
+end
+
+dose = fread(fid,'float');
+try
+    dose = reshape(dose,optSettings.beamletInfo.beamletDim);
+catch
+    error(['Unable to reshape optimized dose distribution. Ensure ' ...
+     'that optSettings.beamletInfo.beamletDim field matches dose grid dimensions']);
+end

+ 226 - 226
WiscPlanPhotonkV125/matlab_frontend/load2geometry.m

@@ -1,226 +1,226 @@
-
-
-function [Geometry] = load2geometry
-    
-    %% -----===== Get CT files =====-----
-    
-    load('WiscPlan_preferences.mat')
-    if ~isfield(WiscPlan_preferences,'inDataPath')
-        Geometry.data_dir = uigetdir('C:', 'Select the directory with patient data');
-    elseif WiscPlan_preferences.inDataPath ~= 0
-        Geometry.data_dir = uigetdir(WiscPlan_preferences.inDataPath, 'Select the directory with patient data');
-    else
-        Geometry.data_dir = uigetdir('C:', 'Select the directory with patient data');
-    end
-    WiscPlan_preferences.inDataPath = Geometry.data_dir;
-    thisDir = mfilename('fullpath');
-    idcs   = strfind(thisDir,'\');
-    prefsdir = thisDir(1:idcs(end)-1);
-    save([prefsdir '\WiscPlan_preferences.mat'], 'WiscPlan_preferences')
-    
-%     Geometry.data_dir = uigetdir('C:\Box Sync\Optimal Stopping\Data\CDP', 'Select folder with patient data');
-%     Geometry.data_dir = uigetdir('\\Mpufs5\data_wnx1\_Data\QTBI-clinical\Medivation\0391811\T2', 'Select folder with patient data');
-    
-
-    [IMG_in, IMG_path, filterIdx] = uigetfile([{'*.nrrd'; '*.am'}], 'Select CT image', Geometry.data_dir);
-%     'C:\Box Sync\Optimal Stopping\Data\CDP\CDP001\'
-    
-    total_num_steps = 4;
-    hWaitbar = waitbar(0);
-    
-    % --  geometry explained --
-    % geometry_file important parts:
-    % Geometry.ROIS - actually only to get the binary mask of the target
-    % Geometry.data - CT image in HU
-    % Geometry.voxel_size - size of voxels in cm
-    % Geometry.start - image coordinate origin
-    
-    % these are derived from above:
-    % +Geometry.rhomw - CT image with values in relative water density 
-    % +Geometry.Smw - very similair to rhomw
-    % +Geometry.Fmw2
-    % +Geometry.BTV 
-    % +Geometry.ring - a ring around PTV used to pull down IMRT optimization
-    % --------------------------
-    
-    switch filterIdx
-        case 0
-            warning('No file selected, aborting!')
-            return 
-        case 1
-            [Geometry.data, meta]=nrrdread([IMG_path, IMG_in]);
-            
-            % offset the CT, because that is what WiscPlan wants
-            Geometry.data = Geometry.data + 1000;
-            
-            disp('NRRD file loaded!')
-            Geometry.rhomw = CT2dens(Geometry.data, 'pinn');
-            Geometry.rhomw(Geometry.rhomw < 0.0012) = 0.0012;
-            [Geometry.Smw Geometry.Fmw2] = dens2mstp(Geometry.rhomw);
-            
-            disp(['current voxel size: ' num2str(meta.spacedirections(1)) ' ' ...
-                num2str(meta.spacedirections(2)) ' ' num2str(meta.spacedirections(3)) ' cm.'])
-            
-            x = input('Is this correct? (y/n)', 's')
-            switch x
-                case 'n'
-                    rescale_f = input('specify resampling factor')
-                case 'y'
-                    rescale_f = 1;
-            end
-            
-            Geometry.voxel_size = meta.spacedirections * rescale_f;
-            Geometry.start=meta.spaceorigin;
-        case 2
-            imgIn=am2mat([IMG_path, IMG_in]);
-            Geometry.data = permute(imgIn.data, [2,1,3]);
-            % offset the CT, because that is what WiscPlan wants
-            Geometry.data = Geometry.data + 1000;
-            
-            disp('NRRD file loaded!')
-            Geometry.rhomw = CT2dens(Geometry.data, 'pinn');
-            Geometry.rhomw(Geometry.rhomw < 0.0012) = 0.0012;
-            [Geometry.Smw Geometry.Fmw2] = dens2mstp(Geometry.rhomw);
-            
-            Geometry.voxel_size = imgIn.voxel_size;
-            Geometry.start=imgIn.start;
-        case 3
-            % something selected
-            error('please do not select *all* in file selection')
-        otherwise
-%             error('You should never see this.')
-    end
-    
-    
-    % Geometry.ROIS
-    
-    %% -----===== Get mask/contour files =====-----
-    [TRGT_in, TRGT_path, filterIdx2] = uigetfile([{'*.nrrd'; '*.am'}], 'Select file with Target', Geometry.data_dir);
-    
-    switch filterIdx2
-        case 0
-            warning('No file selected!')
-        case 1
-            [TRGT_img, meta]=nrrdread([TRGT_path, TRGT_in]);
-            disp('NRRD file loaded!')
-            Geometry.ROIS{1}.ind = find(TRGT_img>0);
-            Geometry.ROIS{1}.name= 'Target';
-        case 2
-            TRGT_in=am2mat([TRGT_path, TRGT_in]);
-            disp('AM file loaded!')
-            TRGT_img = permute(TRGT_in.data, [2,1,3]);
-            Geometry.ROIS{1}.ind = find(TRGT_img>0);
-            Geometry.ROIS{1}.name= 'Target';
-        case 3
-            error('please do not select *all* in file selection')
-            % something selected
-        otherwise
-%             error('You should never see this.')
-    end
-    
-    
-        %% -----===== Save geometry files =====-----
-    patient_dir = uifile('getdir', 'Save the patient data to directory');
-    Geometry.patient_dir = patient_dir;
-    
-%     patient_dir = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\';
-    
-    % make directories
-    mkdir(Geometry.patient_dir);
-    mkdir(fullfile(Geometry.patient_dir, 'beamlet_batch_files'));
-    mkdir(fullfile(Geometry.patient_dir, 'geometry_files'));
-    mkdir(fullfile(Geometry.patient_dir, 'matlab_files'));
-    mkdir(fullfile(Geometry.patient_dir, 'opt_input'));
-    mkdir(fullfile(Geometry.patient_dir, 'opt_output'));
-
-    %% -----===== BTV and Ring creation =====-----
-    waitbar(1/total_num_steps, hWaitbar, 'Step 2: Assign target and BTV margin');
-    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. ');
-    if okay ~= 1
-        msgbox('Plan creation aborted');
-        delete(hWaitbar);
-        return;
-    end
-
-    [BTV_margin_answer] = inputdlg({sprintf('Please enter the BTV margin (cm):\n(default 0.6 cm or 1 sigma, enter 0 to skip)')}, ...
-        'BTV margin specification', 1, {'0.6'});
-    if isempty(BTV_margin_answer)
-        BTV_margin = 0.6;
-    else
-        BTV_margin = str2double(BTV_margin_answer{1});
-    end
-
-    % target_idx and BTV_margin are set. Expand PTV to BTV
-    PTVmask = false(size(Geometry.rhomw));
-    % for target_idx = target_indices
-            PTVmask(Geometry.ROIS{target_idx}.ind) = 1;
-    % end
-    if BTV_margin > 0
-        if exist('BTV_margin', 'var') && BTV_margin >= min(Geometry.voxel_size)
-            bwD = bwdistsc(PTVmask, Geometry.voxel_size);
-            Geometry.BTV = bwD <= BTV_margin;
-        elseif BTV_margin < min(Geometry.voxel_size)
-            warning('BTV margin too small!')
-            Geometry.BTV = zeros(size(Geometry.data));
-        end
-    end
-
-    % Create btv
-    Geometry.ROIS{end+1} = Geometry.ROIS{end};
-    Geometry.ROIS{end}.name = 'BTV';
-    Geometry.ROIS{end}.num_curves = 0;
-    Geometry.ROIS{end}.curves = {};
-    Geometry.ROIS{end}.ind = find(Geometry.BTV);
-    Geometry.ROIS{end}.visible = false;
-
-    % Create ring
-    [ring_margin_answer] = inputdlg({sprintf('Please enter the ring margin (cm):')}, ...
-        'Ring margin specification', 1, {'1'});
-    if isempty(ring_margin_answer)
-        ring_margin = 1;
-    else
-        ring_margin = str2double(ring_margin_answer{1});
-    end
-    bwD = bwdistsc(PTVmask, Geometry.voxel_size);
-    Geometry.Ring = bwD <= ring_margin; % default ring radius 3 cm
-    Geometry.Ring = xor(Geometry.Ring, PTVmask);
-    Geometry.ROIS{end+1} = Geometry.ROIS{end};
-    Geometry.ROIS{end}.name = 'Ring';
-    Geometry.ROIS{end}.num_curves = 0;
-    Geometry.ROIS{end}.curves = {};
-    Geometry.ROIS{end}.ind = find(Geometry.Ring);
-    Geometry.ROIS{end}.visible = false;
-
-    
-    %% -----===== Save the matlab files =====-----
-    waitbar(2.33/total_num_steps, hWaitbar, 'Step 3: Save matlab geometry files');
-    % Save matlab geometry file
-    save(fullfile(Geometry.patient_dir, 'matlab_files', 'Geometry.mat'), 'Geometry');
-
-    waitbar(2.66/total_num_steps, hWaitbar, 'Step 3: Save raw geometry files');
-    % Write binary geometry files
-    fid = fopen(fullfile(Geometry.patient_dir, 'geometry_files', 'rhomw.bin'), 'w');
-    fwrite(fid, Geometry.rhomw, 'single');
-    fclose(fid);
-    
-    fid = fopen(fullfile(Geometry.patient_dir, 'geometry_files', 'Smw.bin'), 'w');
-    fwrite(fid, Geometry.Smw, 'single');
-    fclose(fid);
-
-    fid = fopen(fullfile(Geometry.patient_dir, 'geometry_files', 'Fmw2.bin'), 'w');
-    fwrite(fid, Geometry.Fmw2, 'single');
-    fclose(fid);
-
-    delete(hWaitbar);
-    waitfor(msgbox(['Plan geometry created successfully in ' '"' Geometry.patient_dir '"']));
-    
-
-end
-
-
-
-
+
+
+function [Geometry] = load2geometry
+    
+    %% -----===== Get CT files =====-----
+    
+    load('WiscPlan_preferences.mat')
+    if ~isfield(WiscPlan_preferences,'inDataPath')
+        Geometry.data_dir = uigetdir('C:', 'Select the directory with patient data');
+    elseif WiscPlan_preferences.inDataPath ~= 0
+        Geometry.data_dir = uigetdir(WiscPlan_preferences.inDataPath, 'Select the directory with patient data');
+    else
+        Geometry.data_dir = uigetdir('C:', 'Select the directory with patient data');
+    end
+    WiscPlan_preferences.inDataPath = Geometry.data_dir;
+    thisDir = mfilename('fullpath');
+    idcs   = strfind(thisDir,'\');
+    prefsdir = thisDir(1:idcs(end)-1);
+    save([prefsdir '\WiscPlan_preferences.mat'], 'WiscPlan_preferences')
+    
+%     Geometry.data_dir = uigetdir('C:\Box Sync\Optimal Stopping\Data\CDP', 'Select folder with patient data');
+%     Geometry.data_dir = uigetdir('\\Mpufs5\data_wnx1\_Data\QTBI-clinical\Medivation\0391811\T2', 'Select folder with patient data');
+    
+
+    [IMG_in, IMG_path, filterIdx] = uigetfile([{'*.nrrd'; '*.am'}], 'Select CT image', Geometry.data_dir);
+%     'C:\Box Sync\Optimal Stopping\Data\CDP\CDP001\'
+    
+    total_num_steps = 4;
+    hWaitbar = waitbar(0);
+    
+    % --  geometry explained --
+    % geometry_file important parts:
+    % Geometry.ROIS - actually only to get the binary mask of the target
+    % Geometry.data - CT image in HU
+    % Geometry.voxel_size - size of voxels in cm
+    % Geometry.start - image coordinate origin
+    
+    % these are derived from above:
+    % +Geometry.rhomw - CT image with values in relative water density 
+    % +Geometry.Smw - very similair to rhomw
+    % +Geometry.Fmw2
+    % +Geometry.BTV 
+    % +Geometry.ring - a ring around PTV used to pull down IMRT optimization
+    % --------------------------
+    
+    switch filterIdx
+        case 0
+            warning('No file selected, aborting!')
+            return 
+        case 1
+            [Geometry.data, meta]=nrrdread([IMG_path, IMG_in]);
+            
+            % offset the CT, because that is what WiscPlan wants
+            Geometry.data = Geometry.data + 1000;
+            
+            disp('NRRD file loaded!')
+            Geometry.rhomw = CT2dens(Geometry.data, 'pinn');
+            Geometry.rhomw(Geometry.rhomw < 0.0012) = 0.0012;
+            [Geometry.Smw Geometry.Fmw2] = dens2mstp(Geometry.rhomw);
+            
+            disp(['current voxel size: ' num2str(meta.spacedirections(1)) ' ' ...
+                num2str(meta.spacedirections(2)) ' ' num2str(meta.spacedirections(3)) ' cm.'])
+            
+            x = input('Is this correct? (y/n)', 's')
+            switch x
+                case 'n'
+                    rescale_f = input('specify resampling factor')
+                case 'y'
+                    rescale_f = 1;
+            end
+            
+            Geometry.voxel_size = meta.spacedirections * rescale_f;
+            Geometry.start=meta.spaceorigin;
+        case 2
+            imgIn=am2mat([IMG_path, IMG_in]);
+            Geometry.data = permute(imgIn.data, [2,1,3]);
+            % offset the CT, because that is what WiscPlan wants
+            Geometry.data = Geometry.data + 1000;
+            
+            disp('NRRD file loaded!')
+            Geometry.rhomw = CT2dens(Geometry.data, 'pinn');
+            Geometry.rhomw(Geometry.rhomw < 0.0012) = 0.0012;
+            [Geometry.Smw Geometry.Fmw2] = dens2mstp(Geometry.rhomw);
+            
+            Geometry.voxel_size = imgIn.voxel_size;
+            Geometry.start=imgIn.start;
+        case 3
+            % something selected
+            error('please do not select *all* in file selection')
+        otherwise
+%             error('You should never see this.')
+    end
+    
+    
+    % Geometry.ROIS
+    
+    %% -----===== Get mask/contour files =====-----
+    [TRGT_in, TRGT_path, filterIdx2] = uigetfile([{'*.nrrd'; '*.am'}], 'Select file with Target', Geometry.data_dir);
+    
+    switch filterIdx2
+        case 0
+            warning('No file selected!')
+        case 1
+            [TRGT_img, meta]=nrrdread([TRGT_path, TRGT_in]);
+            disp('NRRD file loaded!')
+            Geometry.ROIS{1}.ind = find(TRGT_img>0);
+            Geometry.ROIS{1}.name= 'Target';
+        case 2
+            TRGT_in=am2mat([TRGT_path, TRGT_in]);
+            disp('AM file loaded!')
+            TRGT_img = permute(TRGT_in.data, [2,1,3]);
+            Geometry.ROIS{1}.ind = find(TRGT_img>0);
+            Geometry.ROIS{1}.name= 'Target';
+        case 3
+            error('please do not select *all* in file selection')
+            % something selected
+        otherwise
+%             error('You should never see this.')
+    end
+    
+    
+        %% -----===== Save geometry files =====-----
+    patient_dir = uifile('getdir', 'Save the patient data to directory');
+    Geometry.patient_dir = patient_dir;
+    
+%     patient_dir = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\';
+    
+    % make directories
+    mkdir(Geometry.patient_dir);
+    mkdir(fullfile(Geometry.patient_dir, 'beamlet_batch_files'));
+    mkdir(fullfile(Geometry.patient_dir, 'geometry_files'));
+    mkdir(fullfile(Geometry.patient_dir, 'matlab_files'));
+    mkdir(fullfile(Geometry.patient_dir, 'opt_input'));
+    mkdir(fullfile(Geometry.patient_dir, 'opt_output'));
+
+    %% -----===== BTV and Ring creation =====-----
+    waitbar(1/total_num_steps, hWaitbar, 'Step 2: Assign target and BTV margin');
+    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. ');
+    if okay ~= 1
+        msgbox('Plan creation aborted');
+        delete(hWaitbar);
+        return;
+    end
+
+    [BTV_margin_answer] = inputdlg({sprintf('Please enter the BTV margin (cm):\n(default 0.6 cm or 1 sigma, enter 0 to skip)')}, ...
+        'BTV margin specification', 1, {'0.6'});
+    if isempty(BTV_margin_answer)
+        BTV_margin = 0.6;
+    else
+        BTV_margin = str2double(BTV_margin_answer{1});
+    end
+
+    % target_idx and BTV_margin are set. Expand PTV to BTV
+    PTVmask = false(size(Geometry.rhomw));
+    % for target_idx = target_indices
+            PTVmask(Geometry.ROIS{target_idx}.ind) = 1;
+    % end
+    if BTV_margin > 0
+        if exist('BTV_margin', 'var') && BTV_margin >= min(Geometry.voxel_size)
+            bwD = bwdistsc(PTVmask, Geometry.voxel_size);
+            Geometry.BTV = bwD <= BTV_margin;
+        elseif BTV_margin < min(Geometry.voxel_size)
+            warning('BTV margin too small!')
+            Geometry.BTV = zeros(size(Geometry.data));
+        end
+    end
+
+    % Create btv
+    Geometry.ROIS{end+1} = Geometry.ROIS{end};
+    Geometry.ROIS{end}.name = 'BTV';
+    Geometry.ROIS{end}.num_curves = 0;
+    Geometry.ROIS{end}.curves = {};
+    Geometry.ROIS{end}.ind = find(Geometry.BTV);
+    Geometry.ROIS{end}.visible = false;
+
+    % Create ring
+    [ring_margin_answer] = inputdlg({sprintf('Please enter the ring margin (cm):')}, ...
+        'Ring margin specification', 1, {'1'});
+    if isempty(ring_margin_answer)
+        ring_margin = 1;
+    else
+        ring_margin = str2double(ring_margin_answer{1});
+    end
+    bwD = bwdistsc(PTVmask, Geometry.voxel_size);
+    Geometry.Ring = bwD <= ring_margin; % default ring radius 3 cm
+    Geometry.Ring = xor(Geometry.Ring, PTVmask);
+    Geometry.ROIS{end+1} = Geometry.ROIS{end};
+    Geometry.ROIS{end}.name = 'Ring';
+    Geometry.ROIS{end}.num_curves = 0;
+    Geometry.ROIS{end}.curves = {};
+    Geometry.ROIS{end}.ind = find(Geometry.Ring);
+    Geometry.ROIS{end}.visible = false;
+
+    
+    %% -----===== Save the matlab files =====-----
+    waitbar(2.33/total_num_steps, hWaitbar, 'Step 3: Save matlab geometry files');
+    % Save matlab geometry file
+    save(fullfile(Geometry.patient_dir, 'matlab_files', 'Geometry.mat'), 'Geometry');
+
+    waitbar(2.66/total_num_steps, hWaitbar, 'Step 3: Save raw geometry files');
+    % Write binary geometry files
+    fid = fopen(fullfile(Geometry.patient_dir, 'geometry_files', 'rhomw.bin'), 'w');
+    fwrite(fid, Geometry.rhomw, 'single');
+    fclose(fid);
+    
+    fid = fopen(fullfile(Geometry.patient_dir, 'geometry_files', 'Smw.bin'), 'w');
+    fwrite(fid, Geometry.Smw, 'single');
+    fclose(fid);
+
+    fid = fopen(fullfile(Geometry.patient_dir, 'geometry_files', 'Fmw2.bin'), 'w');
+    fwrite(fid, Geometry.Fmw2, 'single');
+    fclose(fid);
+
+    delete(hWaitbar);
+    waitfor(msgbox(['Plan geometry created successfully in ' '"' Geometry.patient_dir '"']));
+    
+
+end
+
+
+
+

+ 35 - 35
WiscPlanPhotonkV125/matlab_frontend/merge_beamlets.m

@@ -1,35 +1,35 @@
-function B = merge_beamlets(num_batches, pat_dir)
-
-% num_batches = 4;
-
-
-B = [];
-for k = 1:num_batches
-    batch_doses = read_ryan_beamlets([pat_dir, '\batch_dose' num2str(k-1) '.bin']);
-    B = [B batch_doses];
-end
-write_ryan_beamlets([pat_dir '\batch_dose_unshifted.bin'],B);
-
-% apply the shift (0.5 vox up and left) to make dose match geometry
-f = waitbar(0, 'Correcting beamlet shift');
-for beam_i = 1:numel(B)
-    new_dose_list = B{beam_i};
-    waitbar(beam_i/numel(B),f, ['Correcting beamlet shift: ' num2str(beam_i)])
-    
-    tabula = zeros(B{1, beam_i}.y_count, B{1, beam_i}.x_count, B{1, beam_i}.z_count);
-    tabula(B{1, beam_i}.non_zero_indices) = B{1, beam_i}.non_zero_values;
-    
-    shifted_img = imtranslate(tabula, [-0.5,-0.5,-0.5]);
-    nonzero_idx = find(shifted_img>0.005*max(shifted_img(:)));
-
-    B{beam_i}.non_zero_indices = nonzero_idx;
-    B{beam_i}.non_zero_values = shifted_img(nonzero_idx);
-end
-close(f)
-
-for k = 1:numel(B)
-    B{k}.num = k-1;
-end
-write_ryan_beamlets([pat_dir '\batch_dose.bin'],B);
-
-write_ryan_beamlets([pat_dir '\batch_dose_backup.bin'],B);
+function B = merge_beamlets(num_batches, pat_dir)
+
+% num_batches = 4;
+
+
+B = [];
+for k = 1:num_batches
+    batch_doses = read_ryan_beamlets([pat_dir, '\batch_dose' num2str(k-1) '.bin']);
+    B = [B batch_doses];
+end
+write_ryan_beamlets([pat_dir '\batch_dose_unshifted.bin'],B);
+
+% apply the shift (0.5 vox up and left) to make dose match geometry
+f = waitbar(0, 'Correcting beamlet shift');
+for beam_i = 1:numel(B)
+    new_dose_list = B{beam_i};
+    waitbar(beam_i/numel(B),f, ['Correcting beamlet shift: ' num2str(beam_i)])
+    
+    tabula = zeros(B{1, beam_i}.y_count, B{1, beam_i}.x_count, B{1, beam_i}.z_count);
+    tabula(B{1, beam_i}.non_zero_indices) = B{1, beam_i}.non_zero_values;
+    
+    shifted_img = imtranslate(tabula, [-0.5,-0.5,-0.5]);
+    nonzero_idx = find(shifted_img>0.005*max(shifted_img(:)));
+
+    B{beam_i}.non_zero_indices = nonzero_idx;
+    B{beam_i}.non_zero_values = shifted_img(nonzero_idx);
+end
+close(f)
+
+for k = 1:numel(B)
+    B{k}.num = k-1;
+end
+write_ryan_beamlets([pat_dir '\batch_dose.bin'],B);
+
+write_ryan_beamlets([pat_dir '\batch_dose_backup.bin'],B);

+ 38 - 38
WiscPlanPhotonkV125/matlab_frontend/nrrd2ROI.m

@@ -1,39 +1,39 @@
-function Geometry=nrrd2ROI(Geometry, patient_dir)
-
-    %% -----===== Get ROI mask =====-----
-    while true
-        newRoi = questdlg('Do you want to load another ROI?','New ROI','Yes','No','No');
-        switch newRoi
-            case 'Yes'
-                
-                [ROI_in, ROI_path, filterIdx] = uigetfile([{'*.nrrd'; '*.am'}], 'Select ROI image', Geometry.data_dir);
-                switch filterIdx
-                    case 0
-                        warning('No file selected, aborting!')
-                        return 
-                    case 1
-                        [ROI_img, meta]=nrrdread([ROI_path, ROI_in]);
-                        disp('NRRD file loaded!')
-                    case 2
-                        ROI_img = am2mat([ROI_path, ROI_in]);
-                        ROI_img = permute(ROI_img.data, [2,1,3]);
-                        disp('AM file loaded!')
-                    case 3
-                        error('please do not select *all* in file selection')
-                    otherwise
-                        error('You should never see this.')
-                end
-                
-                WiscPlan_preferences.patientDataPath = Geometry.patient_dir;
-                save(which('WiscPlan_preferences.mat'), 'WiscPlan_preferences');
-                
-                Geometry.ROIS{end+1}.ind = find(ROI_img>0);
-                str = inputdlg('Enter ROI name:')
-                Geometry.ROIS{end}.name= str{1};
-                save(fullfile(Geometry.patient_dir, 'matlab_files', 'Geometry.mat'), 'Geometry');
-
-            case 'No'
-                break
-        end
-    end
+function Geometry=nrrd2ROI(Geometry, patient_dir)
+
+    %% -----===== Get ROI mask =====-----
+    while true
+        newRoi = questdlg('Do you want to load another ROI?','New ROI','Yes','No','No');
+        switch newRoi
+            case 'Yes'
+                
+                [ROI_in, ROI_path, filterIdx] = uigetfile([{'*.nrrd'; '*.am'}], 'Select ROI image', Geometry.data_dir);
+                switch filterIdx
+                    case 0
+                        warning('No file selected, aborting!')
+                        return 
+                    case 1
+                        [ROI_img, meta]=nrrdread([ROI_path, ROI_in]);
+                        disp('NRRD file loaded!')
+                    case 2
+                        ROI_img = am2mat([ROI_path, ROI_in]);
+                        ROI_img = permute(ROI_img.data, [2,1,3]);
+                        disp('AM file loaded!')
+                    case 3
+                        error('please do not select *all* in file selection')
+                    otherwise
+                        error('You should never see this.')
+                end
+                
+                WiscPlan_preferences.patientDataPath = Geometry.patient_dir;
+                save(which('WiscPlan_preferences.mat'), 'WiscPlan_preferences');
+                
+                Geometry.ROIS{end+1}.ind = find(ROI_img>0);
+                str = inputdlg('Enter ROI name:')
+                Geometry.ROIS{end}.name= str{1};
+                save(fullfile(Geometry.patient_dir, 'matlab_files', 'Geometry.mat'), 'Geometry');
+
+            case 'No'
+                break
+        end
+    end
 end

+ 54 - 54
WiscPlanPhotonkV125/matlab_frontend/plotting/imagescX.m

@@ -1,54 +1,54 @@
-function [ cdata ] = imagescX ( img, cmap, clim )
-% imagesc_fixed Plot image independent of colormap used in figure
-% Usage:
-%     imagesc_fixed ( img, cmap, clim )
-% INPUT:
-%     img = 2D matrix of image
-%     cmap = colormap, defaults to 'jet'
-% OUTPUT:
-%     [] = plot the image to current axes
-%     cdata = RGB matrix
-%
-% Development status: Partially functional
-% Copyleft (c) Xiaohu Mo
-% Version: 0.7
-
-if nargin < 2
-    cmap = jet(256);
-end
-
-img = squeeze(img);
-if ndims(img) > 2
-    cdata = [];
-    return;
-end
-
-if isinteger(img)
-    img = single(img);
-end
-
-cmap_len = size(cmap, 1);
-
-if nargin < 3
-    cmin = min(img(:));
-    cmax = max(img(:));
-else
-    cmin = clim(1);
-    cmax = clim(2);
-end
-
-% calculate color
-% TODO cmap_len - 1 or not? See doc caxis
-img_indexed = fix((img-cmin)/(cmax-cmin)*(cmap_len-1)) + 1;
-img_indexed(img_indexed < 1) = 1;
-img_indexed(img_indexed > cmap_len) = cmap_len;
-img_indexed(isnan(img_indexed)) = 1; % TODO when cmax == cmin
-
-cdata = zeros(size(img,1), size(img,2), 3);
-cdata(:,:,1) = reshape(cmap(img_indexed, 1), size(img));
-cdata(:,:,2) = reshape(cmap(img_indexed, 2), size(img));
-cdata(:,:,3) = reshape(cmap(img_indexed, 3), size(img));
-
-if nargout == 0
-    image('CData', cdata);
-end
+function [ cdata ] = imagescX ( img, cmap, clim )
+% imagesc_fixed Plot image independent of colormap used in figure
+% Usage:
+%     imagesc_fixed ( img, cmap, clim )
+% INPUT:
+%     img = 2D matrix of image
+%     cmap = colormap, defaults to 'jet'
+% OUTPUT:
+%     [] = plot the image to current axes
+%     cdata = RGB matrix
+%
+% Development status: Partially functional
+% Copyleft (c) Xiaohu Mo
+% Version: 0.7
+
+if nargin < 2
+    cmap = jet(256);
+end
+
+img = squeeze(img);
+if ndims(img) > 2
+    cdata = [];
+    return;
+end
+
+if isinteger(img)
+    img = single(img);
+end
+
+cmap_len = size(cmap, 1);
+
+if nargin < 3
+    cmin = min(img(:));
+    cmax = max(img(:));
+else
+    cmin = clim(1);
+    cmax = clim(2);
+end
+
+% calculate color
+% TODO cmap_len - 1 or not? See doc caxis
+img_indexed = fix((img-cmin)/(cmax-cmin)*(cmap_len-1)) + 1;
+img_indexed(img_indexed < 1) = 1;
+img_indexed(img_indexed > cmap_len) = cmap_len;
+img_indexed(isnan(img_indexed)) = 1; % TODO when cmax == cmin
+
+cdata = zeros(size(img,1), size(img,2), 3);
+cdata(:,:,1) = reshape(cmap(img_indexed, 1), size(img));
+cdata(:,:,2) = reshape(cmap(img_indexed, 2), size(img));
+cdata(:,:,3) = reshape(cmap(img_indexed, 3), size(img));
+
+if nargout == 0
+    image('CData', cdata);
+end

+ 44 - 44
WiscPlanPhotonkV125/matlab_frontend/ryan/save_beamspec_batch.m

@@ -1,45 +1,45 @@
-function save_beamspec_batch(batch,batch_folder,batch_file_name)
-% Saves a beamspec batch to batch_folder/batch_filename. The batch is a
-% cell array of beam structures.
-%
-% Each beam structure has the following fields:
-% beam = 
-% 
-%        num: 1
-%      y_vec: [86.6025 50.0000 0]
-%        SAD: 100
-%         ip: [0.5000 -0.8660 0]
-%         jp: [0 0 1]
-%         kp: [-0.8660 -0.5000 0]
-%         xp: 0.5000
-%         yp: 0
-%     del_yp: 1
-%     del_xp: 2
-
-warning off MATLAB:MKDIR:DirectoryExists
-
-mkdir(batch_folder);
-
-N = prod(size(batch));  % number of beamspecs in the batch
-
-fid = fopen([batch_folder '/' batch_file_name],'w');
-
-fprintf(fid,'beamnum:\n %g\n\n',N);  % write the total number of beams that are in this batch
-
-for k=1:N
-    % save each beam structure
-    beam = batch{k};        % current beam structure
-    fprintf(fid,'num\n');
-    fprintf(fid,'%g\n',double(beam.num));
-    fprintf(fid,'SAD xp yp del_xp del_yp\n');
-    fprintf(fid,'%4.20E %4.20E %4.20E %4.20E %4.20E\n',double(beam.SAD),double(beam.xp),double(beam.yp),double(beam.del_xp),double(beam.del_yp));
-    fprintf(fid,'y_vec\n');
-    fprintf(fid,'%4.20E %4.20E %4.20E\n',double(beam.y_vec(1)),double(beam.y_vec(2)),double(beam.y_vec(3)));
-    fprintf(fid,'ip\n');
-    fprintf(fid,'%4.20E %4.20E %4.20E\n',double(beam.ip(1)),double(beam.ip(2)),double(beam.ip(3)));
-    fprintf(fid,'jp\n');
-    fprintf(fid,'%4.20E %4.20E %4.20E\n',double(beam.jp(1)),double(beam.jp(2)),double(beam.jp(3)));
-    fprintf(fid,'kp\n');
-    fprintf(fid,'%4.20E %4.20E %4.20E\n\n',double(beam.kp(1)),double(beam.kp(2)),double(beam.kp(3)));
-end
+function save_beamspec_batch(batch,batch_folder,batch_file_name)
+% Saves a beamspec batch to batch_folder/batch_filename. The batch is a
+% cell array of beam structures.
+%
+% Each beam structure has the following fields:
+% beam = 
+% 
+%        num: 1
+%      y_vec: [86.6025 50.0000 0]
+%        SAD: 100
+%         ip: [0.5000 -0.8660 0]
+%         jp: [0 0 1]
+%         kp: [-0.8660 -0.5000 0]
+%         xp: 0.5000
+%         yp: 0
+%     del_yp: 1
+%     del_xp: 2
+
+warning off MATLAB:MKDIR:DirectoryExists
+
+mkdir(batch_folder);
+
+N = prod(size(batch));  % number of beamspecs in the batch
+
+fid = fopen([batch_folder '/' batch_file_name],'w');
+
+fprintf(fid,'beamnum:\n %g\n\n',N);  % write the total number of beams that are in this batch
+
+for k=1:N
+    % save each beam structure
+    beam = batch{k};        % current beam structure
+    fprintf(fid,'num\n');
+    fprintf(fid,'%g\n',double(beam.num));
+    fprintf(fid,'SAD xp yp del_xp del_yp\n');
+    fprintf(fid,'%4.20E %4.20E %4.20E %4.20E %4.20E\n',double(beam.SAD),double(beam.xp),double(beam.yp),double(beam.del_xp),double(beam.del_yp));
+    fprintf(fid,'y_vec\n');
+    fprintf(fid,'%4.20E %4.20E %4.20E\n',double(beam.y_vec(1)),double(beam.y_vec(2)),double(beam.y_vec(3)));
+    fprintf(fid,'ip\n');
+    fprintf(fid,'%4.20E %4.20E %4.20E\n',double(beam.ip(1)),double(beam.ip(2)),double(beam.ip(3)));
+    fprintf(fid,'jp\n');
+    fprintf(fid,'%4.20E %4.20E %4.20E\n',double(beam.jp(1)),double(beam.jp(2)),double(beam.jp(3)));
+    fprintf(fid,'kp\n');
+    fprintf(fid,'%4.20E %4.20E %4.20E\n\n',double(beam.kp(1)),double(beam.kp(2)),double(beam.kp(3)));
+end
 fclose(fid);

+ 35 - 35
WiscPlanPhotonkV125/matlab_frontend/ryan/save_geometry.m

@@ -1,36 +1,36 @@
-function save_geometry2(Geometry,geometry_folder,header_filename,density_filename)
-% saves the Geometry file without the beam data in its matlab format to 
-% files that are readable by a C-version of the convolution code.  
-% The results are all saved in binary files so that no truncation errors 
-% occur in the numbers.
-
-warning off MATLAB:MKDIR:DirectoryExists
-
-% load GeometryCT.mat;  % load the Matlab kernels, which look like:
-% Geometry = 
-% 
-%          start: [-24.0128 -24.0128 -1.5000]
-%     voxel_size: [0.3752 0.3752 0.3000]
-%           data: [128x128x10 float]
-%           beam: [1x1 struct]  % the beam field is not used by this file
-%
-
-mkdir(geometry_folder);
-
-% density grid dimensions
-[Xcount,Ycount,Zcount] = size(Geometry.data);
-
-% create the geometry header file
-fid = fopen([geometry_folder '/' header_filename],'w');
-fprintf(fid,'Xcount Ycount Zcount\n');
-fprintf(fid,'%g %g %g\n',Xcount,Ycount,Zcount);
-fprintf(fid,'Xstart Ystart Zstart\n');
-fprintf(fid,'%4.20E %4.20E %4.20E\n',double(Geometry.start(1)),double(Geometry.start(2)),double(Geometry.start(3)));
-fprintf(fid,'dx dy dz\n');
-fprintf(fid,'%4.20E %4.20E %4.20E\n',double(Geometry.voxel_size(1)),double(Geometry.voxel_size(2)),double(Geometry.voxel_size(3)));
-fclose(fid);
-
-% save the density data to a binary file
-fid = fopen([geometry_folder '/' density_filename],'wb');
-fwrite(fid,Geometry.rhomw,'float');
+function save_geometry2(Geometry,geometry_folder,header_filename,density_filename)
+% saves the Geometry file without the beam data in its matlab format to 
+% files that are readable by a C-version of the convolution code.  
+% The results are all saved in binary files so that no truncation errors 
+% occur in the numbers.
+
+warning off MATLAB:MKDIR:DirectoryExists
+
+% load GeometryCT.mat;  % load the Matlab kernels, which look like:
+% Geometry = 
+% 
+%          start: [-24.0128 -24.0128 -1.5000]
+%     voxel_size: [0.3752 0.3752 0.3000]
+%           data: [128x128x10 float]
+%           beam: [1x1 struct]  % the beam field is not used by this file
+%
+
+mkdir(geometry_folder);
+
+% density grid dimensions
+[Xcount,Ycount,Zcount] = size(Geometry.data);
+
+% create the geometry header file
+fid = fopen([geometry_folder '/' header_filename],'w');
+fprintf(fid,'Xcount Ycount Zcount\n');
+fprintf(fid,'%g %g %g\n',Xcount,Ycount,Zcount);
+fprintf(fid,'Xstart Ystart Zstart\n');
+fprintf(fid,'%4.20E %4.20E %4.20E\n',double(Geometry.start(1)),double(Geometry.start(2)),double(Geometry.start(3)));
+fprintf(fid,'dx dy dz\n');
+fprintf(fid,'%4.20E %4.20E %4.20E\n',double(Geometry.voxel_size(1)),double(Geometry.voxel_size(2)),double(Geometry.voxel_size(3)));
+fclose(fid);
+
+% save the density data to a binary file
+fid = fopen([geometry_folder '/' density_filename],'wb');
+fwrite(fid,Geometry.rhomw,'float');
 fclose(fid);

+ 102 - 102
WiscPlanPhotonkV125/matlab_frontend/ryan/save_kernels.m

@@ -1,102 +1,102 @@
-function save_kernels(Kernels,kernel_folder)
-% saves the Kernels in their matlab format to files that are readable by a
-% C-version of the convolution code.  The results are all saved in binary
-% files so for easy readin.  Since there are so many files that will be
-% created the option of changing the filenames from outside the function
-% was not included.
-
-warning off MATLAB:MKDIR:DirectoryExists
-
-% The kernels have the following structure:
-% Kernels = 
-% 
-%                radii: [1x24 float]
-%               angles: [1x48 float]
-%             energies: [1x14 float]
-%              primary: [24x48x14 float]
-%        first_scatter: [24x48x14 float]
-%       second_scatter: [24x48x14 float]
-%     multiple_scatter: [24x48x14 float]
-%           brem_annih: [24x48x14 float]
-%                total: [24x48x14 float]
-%           mean_radii: [24x48x14 float]
-%          mean_angles: [24x48x14 float]
-%            helpfield: [21x72 char]            % not saved
-%              fluence: [1x14 float]
-%                   mu: [1x14 float]
-%                mu_en: [1x14 float]
-
-mkdir(kernel_folder);
-
-% kernel filenames:
-
-kernel_header = 'kernel_header.txt';  % header file for the kernels
-kernel_radii = 'radii.bin';
-kernel_angles = 'angles.bin';
-kernel_energies = 'energies.bin';
-kernel_primary = 'primary.bin';
-kernel_first_scatter = 'first_scatter.bin';
-kernel_second_scatter = 'second_scatter.bin';
-kernel_multiple_scatter = 'multiple_scatter.bin';
-kernel_brem_annih = 'brem_annih.bin';
-kernel_total = 'total.bin';
-kernel_fluence = 'fluence.bin';
-kernel_mu = 'mu.bin';
-kernel_mu_en = 'mu_en.bin';
-
-[Nradii,Nangles,Nenergies] = size(Kernels.total);
-
-% create the header file
-fid = fopen([kernel_folder '/' kernel_header],'w');
-fprintf(fid,'Nradii Nangles Nenergies\n');
-fprintf(fid,'%g %g %g\n',Nradii,Nangles,Nenergies);
-fclose(fid);
-
-% start saving the rest of the data
-fid = fopen([kernel_folder '/' kernel_radii],'wb');
-fwrite(fid,Kernels.radii,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_angles],'wb');
-fwrite(fid,Kernels.angles,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_energies],'wb');
-fwrite(fid,Kernels.energies,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_primary],'wb');
-fwrite(fid,Kernels.primary,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_first_scatter],'wb');
-fwrite(fid,Kernels.first_scatter,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_second_scatter],'wb');
-fwrite(fid,Kernels.second_scatter,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_multiple_scatter],'wb');
-fwrite(fid,Kernels.multiple_scatter,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_brem_annih],'wb');
-fwrite(fid,Kernels.brem_annih,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_total],'wb');
-fwrite(fid,Kernels.total,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_fluence],'wb');
-fwrite(fid,Kernels.fluence,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_mu],'wb');
-fwrite(fid,Kernels.mu,'float');
-fclose(fid);
-
-fid = fopen([kernel_folder '/' kernel_mu_en],'wb');
-fwrite(fid,Kernels.mu_en,'float');
-fclose(fid);
+function save_kernels(Kernels,kernel_folder)
+% saves the Kernels in their matlab format to files that are readable by a
+% C-version of the convolution code.  The results are all saved in binary
+% files so for easy readin.  Since there are so many files that will be
+% created the option of changing the filenames from outside the function
+% was not included.
+
+warning off MATLAB:MKDIR:DirectoryExists
+
+% The kernels have the following structure:
+% Kernels = 
+% 
+%                radii: [1x24 float]
+%               angles: [1x48 float]
+%             energies: [1x14 float]
+%              primary: [24x48x14 float]
+%        first_scatter: [24x48x14 float]
+%       second_scatter: [24x48x14 float]
+%     multiple_scatter: [24x48x14 float]
+%           brem_annih: [24x48x14 float]
+%                total: [24x48x14 float]
+%           mean_radii: [24x48x14 float]
+%          mean_angles: [24x48x14 float]
+%            helpfield: [21x72 char]            % not saved
+%              fluence: [1x14 float]
+%                   mu: [1x14 float]
+%                mu_en: [1x14 float]
+
+mkdir(kernel_folder);
+
+% kernel filenames:
+
+kernel_header = 'kernel_header.txt';  % header file for the kernels
+kernel_radii = 'radii.bin';
+kernel_angles = 'angles.bin';
+kernel_energies = 'energies.bin';
+kernel_primary = 'primary.bin';
+kernel_first_scatter = 'first_scatter.bin';
+kernel_second_scatter = 'second_scatter.bin';
+kernel_multiple_scatter = 'multiple_scatter.bin';
+kernel_brem_annih = 'brem_annih.bin';
+kernel_total = 'total.bin';
+kernel_fluence = 'fluence.bin';
+kernel_mu = 'mu.bin';
+kernel_mu_en = 'mu_en.bin';
+
+[Nradii,Nangles,Nenergies] = size(Kernels.total);
+
+% create the header file
+fid = fopen([kernel_folder '/' kernel_header],'w');
+fprintf(fid,'Nradii Nangles Nenergies\n');
+fprintf(fid,'%g %g %g\n',Nradii,Nangles,Nenergies);
+fclose(fid);
+
+% start saving the rest of the data
+fid = fopen([kernel_folder '/' kernel_radii],'wb');
+fwrite(fid,Kernels.radii,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_angles],'wb');
+fwrite(fid,Kernels.angles,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_energies],'wb');
+fwrite(fid,Kernels.energies,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_primary],'wb');
+fwrite(fid,Kernels.primary,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_first_scatter],'wb');
+fwrite(fid,Kernels.first_scatter,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_second_scatter],'wb');
+fwrite(fid,Kernels.second_scatter,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_multiple_scatter],'wb');
+fwrite(fid,Kernels.multiple_scatter,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_brem_annih],'wb');
+fwrite(fid,Kernels.brem_annih,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_total],'wb');
+fwrite(fid,Kernels.total,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_fluence],'wb');
+fwrite(fid,Kernels.fluence,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_mu],'wb');
+fwrite(fid,Kernels.mu,'float');
+fclose(fid);
+
+fid = fopen([kernel_folder '/' kernel_mu_en],'wb');
+fwrite(fid,Kernels.mu_en,'float');
+fclose(fid);

+ 563 - 563
WiscPlanPhotonkV125/matlab_frontend/ryan/singleRaytraceClean.cpp

@@ -1,563 +1,563 @@
-/* singleRaytraceClean.cpp */
-
-/*  Does a raytracing operation between point1 and point2 in a density grid
-defined by DENS, START, and INC.  The visited voxels and their corresponding
-radiological depths are returned as the INDVISITED and DEFFVISITED vectors,
-respectively  */
-
-#include "mex.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <math.h>
-#include <string.h>
-
-#define SUCCESS 1
-#define FAILURE 0
-
-// macro for returning 3D grid index
-#define GRIDIND3D(x,y,z,dim) ((x) + dim[0]*(y) + dim[0]*dim[1]*(z))
-
-// 3D point
-typedef struct
-{
-    float x;
-    float y;
-    float z;
-} POINT;
-
-// 3D grid
-typedef struct
-{
-    POINT start;
-    POINT inc;
-    int x_count;
-    int y_count;
-    int z_count;
-    float *matrix;
-} FLOAT_GRID;
-
-// macro to access grid values
-#define GRID_VALUE(GRID_ptr, i, j, k)\
-    ((GRID_ptr)->matrix[(i) +\
-           (GRID_ptr)->x_count *\
-                ((j) + ((k) * (GRID_ptr)->y_count))])
-
-// User inputs
-#define DENS            (prhs[0])   // electron density grid
-#define START			(prhs[1])   // 3-element start vector
-#define INC		        (prhs[2])   // 3-element voxel size vector
-#define POINT1			(prhs[3])   // starting point for raytrace
-#define POINT2			(prhs[4])   // ending point for raytrace
-#define INDVISITED      (plhs[0])   // indices of visited voxels
-#define DEFFVISITED     (plhs[1])   // deff values of visited voxels
-
-// Prototypes
-int raytrace(FLOAT_GRID *,POINT,POINT,int *, float *, int *);
-double round(double);
-
-char errstr[200];  // error string that all routines have access to
-
-void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
-{
-	// scalars
-	int k,M,N,Q;
-
-	// pointers to vectors that do not need to be freed
-	const int *densDim,*startDim,*incDim,*p1Dim,*p2Dim;
-	float *densPtr,*startPtr,*incPtr,*p1Ptr,*p2Ptr;
-	int *indVisitedPtr;
-	float *deffVisitedPtr;
-
-	int dims[2];
-	int *indVisited; 
-	float *deffVisited;  // indices and deffs visited along ray
-	int maxVisited;
-	int Nvisited;
-
-	// point structures that will be used for raytrace operation
-	POINT p1;
-	POINT p2;
-
-	// grid structures for raytracing operation
-	FLOAT_GRID dens;
-	
-	// get dimensions of the input mxArrays
-	densDim = mxGetDimensions(DENS);
-	startDim = mxGetDimensions(START);
-	incDim = mxGetDimensions(INC);
-	p1Dim = mxGetDimensions(POINT1);
-	p2Dim = mxGetDimensions(POINT2);
-
-	// Check validity of input arguments.
-	if (  ((mxGetNumberOfDimensions(DENS) != 2) && (mxGetNumberOfDimensions(DENS) != 3))
-	   || (mxGetClassID(DENS) != mxSINGLE_CLASS))
-		mexErrMsgTxt("DENS must be a 3-D float array.");
-	
-	if (  (mxGetNumberOfDimensions(START) != 2)
-	   || (mxGetClassID(START) != mxSINGLE_CLASS)
-	   || (startDim[0]*startDim[1] != 3))
-		mexErrMsgTxt("START must be a 3-element float vector.");
-	
-	if (  (mxGetNumberOfDimensions(INC) != 2)
-	   || (mxGetClassID(INC) != mxSINGLE_CLASS)
-	   || (incDim[0]*incDim[1] != 3))
-		mexErrMsgTxt("INC must be a 3-element float vector.");
-
-	if (  (mxGetNumberOfDimensions(POINT1) != 2)
-	   || (mxGetClassID(POINT1) != mxSINGLE_CLASS)
-	   || (p1Dim[0]*p1Dim[1] != 3))
-		mexErrMsgTxt("POINT1 must be a 3-element float vector.");
-
-	if (  (mxGetNumberOfDimensions(POINT2) != 2)
-	   || (mxGetClassID(POINT2) != mxSINGLE_CLASS)
-	   || (p2Dim[0]*p2Dim[1] != 3))
-		mexErrMsgTxt("POINT2 must be a 3-element float vector.");
-
-	// assign data pointers
-	densPtr = (float *)mxGetData(DENS);
-	startPtr = (float *)mxGetData(START);
-	incPtr = (float *)mxGetData(INC);
-	p1Ptr = (float *)mxGetData(POINT1);
-	p2Ptr = (float *)mxGetData(POINT2);
-	
-	// get grid dimensions
-	M = densDim[0];
-	N = densDim[1];
-	if (mxGetNumberOfDimensions(DENS) == 3)
-		Q = densDim[2];
-	else  // handle 2D data as 3D data with the third dimension having 1 increment
-		Q = 1;
-
-	// printf("(M,N,Q) = (%d,%d,%d)\n",M,N,Q);
-
-
-	// the maximum number of voxels that can be visited along a single line
-	maxVisited = (int)(2*sqrt((double)(M*M+N*N+Q*Q)) + 1);  
-	indVisited = (int *)malloc(sizeof(int)*maxVisited);
-	deffVisited = (float *)malloc(sizeof(int)*maxVisited);
-
-	for (k=0;k<maxVisited;k++)
-	{
-		indVisited[k] = 0;
-		deffVisited[k] = 0.0;
-	}
-
-	// Assign dens and deff parameters to structures for input to raytrace
-	// Don't forget, dens.matrix and densPtr point to the same data, and
-	//               deff.matrix and deffPtr point to the same data.
-	dens.matrix = densPtr;
-	dens.start.x = startPtr[0];
-	dens.start.y = startPtr[1];
-	dens.start.z = startPtr[2];
-	dens.inc.x = incPtr[0];
-	dens.inc.y = incPtr[1];
-	dens.inc.z = incPtr[2];
-	dens.x_count = M;
-	dens.y_count = N;
-	dens.z_count = Q;
-
-	// assign values to p1 and p2
-	p1.x = p1Ptr[0];
-	p1.y = p1Ptr[1];
-	p1.z = p1Ptr[2];
-
-	p2.x = p2Ptr[0];
-	p2.y = p2Ptr[1];
-	p2.z = p2Ptr[2];
-
-	// do the raytrace, filling in voxels that are passed on the way
-	if (raytrace(&dens,p1,p2,indVisited,deffVisited,&Nvisited) == FAILURE)
-		mexErrMsgTxt(errstr);
-
-	dims[0] = 1;
-	dims[1] = Nvisited;
-	// dims[1] = 1;
-	// set up output vectors
-	INDVISITED = mxCreateNumericArray(2,dims,mxINT32_CLASS,mxREAL);
-	DEFFVISITED = mxCreateNumericArray(2,dims,mxSINGLE_CLASS,mxREAL);
- 
-	indVisitedPtr = (int *)mxGetData(INDVISITED);
-	deffVisitedPtr = (float *)mxGetData(DEFFVISITED);
-
-	// copy results array to Matlab outputs
-	for (k=0;k<Nvisited;k++)
-	{
-		indVisitedPtr[k] = indVisited[k];
-		deffVisitedPtr[k] = deffVisited[k];
-	}
-}
-
-extern char errstr[200];  // error string that all routines have access to
-
-int raytrace(FLOAT_GRID *electron_density_grid,POINT point1,POINT point2,
-			int *indVisited, float *deffVisited, int *Nvisited)
-/*
---------------------------------------------------------------------------------
-   NAME
- 	c_raytrace
- 
-   SYNOPSIS
-        point1 and point2 are the end points of the ray. 
-
-   DESCRIPTION
-        This function traces the ray from point x to point y (in real 
-        coords), assigning depth to any voxels which that ray crosses. The 
-        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
-        1985). This routine will not be understood without thorough reading 
-        of that paper! Point1 and point2 are the start and end points of the 
-        ray, respectively. External structures of type GRID are assumed to 
-        exist, where electron_density_grid are the electron densities, and 
-        radiological_depth_grid is the output grid for these calculations.
-        Voxels in radiological_depth_grid are initially set -ve prior to 
-        calling this function.
- 
-   AUTHOR
-        Written by David C. Murray
-                   University of Waikato
-                   Private Bag 3105
-                   Hamilton
-                   New Zealand
-        and Copyright (1991) to
-                   David C. Murray and Peter W. Hoban,
-                   Cancer Society of New Zealand Inc., and 
-                   University of Waikato.
---------------------------------------------------------------------------------
-*/
-
-{
-/* Variable descriptions:
-   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
-     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
-   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
-   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
-   dx,dy,dz are the widths in cm of the voxels
-*/
-float         x1,y1,z1,
-              x2,y2,z2,
-              xp1,yp1,zp1,
-              dx,dy,dz;
-int           Nx,Ny,Nz;
-
-/*General ray-trace algorithm variables*/
-float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
-float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
-					/*limits of alpha x,y,z parameters*/
-float alpha_min, alpha_max;		/*limits of alpha parameter*/
-int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
-float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
-float *alpha;				/*holds merged set of alpha values*/
-int i_index,j_index,k_index;		/*loop indices for merging alphas*/
-int a;					/*loop counter*/
-int max_index;				/*max index of merged alpha array*/
-float d12;				/*distance between ray end points*/
-float alpha_mid;			/*mid-point of intersection length*/
-float length;				/*intersection length*/
-int i,j,k;				/*indices of voxel with int. length*/
-float rpl = 0.0;			/*radiological path length in cm*/
-float voxel_density;			/*temporary voxel density*/
-float lmax;  // best possible penetration pathlength for a voxel
-float pnorm;  // absolute difference between p1 and p2
-
-/* Assign variables */
-/******************************************************************************/
-x1 = point1.x;
-y1 = point1.y;
-z1 = point1.z;
-x2 = point2.x;
-y2 = point2.y;
-z2 = point2.z;
-Nx = electron_density_grid->x_count + 1;
-Ny = electron_density_grid->y_count + 1;
-Nz = electron_density_grid->z_count + 1;
-dx = electron_density_grid->inc.x;
-dy = electron_density_grid->inc.y;
-dz = electron_density_grid->inc.z;
-
-// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
-xp1 = electron_density_grid->start.x - (float)0.5*dx;
-yp1 = electron_density_grid->start.y - (float)0.5*dy;
-zp1 = electron_density_grid->start.z - (float)0.5*dz;
-
-pnorm = (float)sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
-
-// this is the largest pathlength possible for a ray through a voxel:
-lmax = (float)sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
-
-/* Calculate xpN,ypN,zpN */
-/******************************************************************************/
-xpN = xp1 + (Nx-1)*dx;
-ypN = yp1 + (Ny-1)*dy;
-zpN = zp1 + (Nz-1)*dz;
-
-/*Calculate alpha_min and alpha_max*/
-/******************************************************************************/
-/*Avoid division by zero*/
-if (x1==x2)
-  x2 += 0.00001;
-if (y1==y2)
-  y2 += 0.00001;
-if (z1==z2)
-  z2 += 0.00001;
-if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
-{
-	sprintf(errstr,"Error - ray trace region too small.");
-	return(FAILURE);
-}
-
-alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
-if (alpha_z_min>alpha_min) 
-  alpha_min = alpha_z_min;
-if (alpha_min<0)
-  alpha_min = 0;
-alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
-if (alpha_z_max<alpha_max) 
-  alpha_max = alpha_z_max;
-if (alpha_max>1)
-  alpha_max = 1;
-
-// Monitor lines...
-/*
-printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
-                alpha_x_min,alpha_y_min,alpha_z_min);
-printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
-                alpha_x_max,alpha_y_max,alpha_z_max);
-printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
-printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx);  */
-
-/*Determine the ranges of i,j,k indices*/
-/******************************************************************************/
-/*The following assignments require conversion from float to integer types*/
-/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
-/*functions convert to the correct value. Note that the range of these*/
-/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
-		
-i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
-                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
-i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
-                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
-j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
-                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
-j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
-                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
-k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
-                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
-k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
-                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
-// Monitor lines...
-/* printf("    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
-printf("    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max); */
-
-// return if the indices do not make sense
-if (   i_max - i_min + 1 < 0 || i_max - i_min + 1 > Nx
-	|| j_max - j_min + 1 < 0 || j_max - j_min + 1 > Ny
-	|| k_max - k_min + 1 < 0 || k_max - k_min + 1 > Nz)
-{
-	*Nvisited = 0; // no voxels were visited
-	return(SUCCESS);
-}
-
-/*Generate sets of alpha values,reversing order if necessary*/
-/******************************************************************************/
-/*allocate array space on stack*/
-if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
-	return(FAILURE);
-}
- 
-/*
-printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
-printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
-printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
-
-if (i_min <= i_max)
-  if (x2>x1)
-    {
-    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=1;a<=i_max-i_min;a++)
-      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
-    }
-  else
-    {
-    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=i_max-i_min-1;a>=0;a--)
-      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
-    }
-alpha_x[i_max-i_min+1] = 10000.0;
-if (j_min <= j_max)
-  if (y2>y1)
-    {
-    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=1;a<=j_max-j_min;a++)
-      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
-    }
-  else
-    {
-    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=j_max-j_min-1;a>=0;a--)
-      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
-    }
-alpha_y[j_max-j_min+1] = 10001.0;
-if (k_min <= k_max)
-  if (z2>z1)
-    {
-    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=1;a<=k_max-k_min;a++)
-      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
-    }
-  else
-    {
-    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=k_max-k_min-1;a>=0;a--)
-      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
-  }
-alpha_z[k_max-k_min+1] = 10002.0; 
-
-
-/* Monitor lines...
-if (i_max<i_min)
-  fprintf(stdout,"    No alpha_x values\n");
-else
-  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
-                 alpha_x[0],alpha_x[i_max-i_min]);
-if (j_max<j_min)
-  fprintf(stdout,"    No alpha_y values\n");
-else
-  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
-                 alpha_y[0],alpha_y[j_max-j_min]);
-if (k_max<k_min)
-  fprintf(stdout,"    No alpha_z values\n");
-else
-  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
-                 alpha_z[0],alpha_z[k_max-k_min]);
-*/
-/*Generate merged set of alpha values*/
-
-
-/******************************************************************************/
-if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
-	return(FAILURE);
-}
-
-max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
-alpha[0] = alpha_min;
-i_index = 0;
-j_index = 0;
-k_index = 0;
-for (a=1;a<=max_index-1;a++)
-  if (alpha_x[i_index]<alpha_y[j_index])
-    if (alpha_x[i_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_x[i_index];
-      i_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-  else
-    if (alpha_y[j_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_y[j_index];
-      j_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-alpha[max_index] = alpha_max;
-free(alpha_x);				//deallocate temp array storage
-free(alpha_y);
-free(alpha_z);
-/*Monitor lines...
-fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
-for (a=0;a<=max_index;a++)
-  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
-*/
-/*Calculate voxel lengths and indices, and assign radiological depth*/
-/******************************************************************************/
-d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
-					//d12 is distance between ray end pts
-
-*Nvisited = 0;  // start counter for number of voxel visited
-
-for (a=1;a<=max_index;a++)
-  {
-  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
-  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
-    {
-    alpha_mid = (alpha[a]+alpha[a-1])/2.0;  //alpha_mid is middle of int. length
-
-	//i,j,k are indices of voxel
-	i = (int) round((x1 + alpha_mid*(x2-x1) - xp1)/dx - 0.5);
-    j = (int) round((y1 + alpha_mid*(y2-y1) - yp1)/dy - 0.5);
-    k = (int) round((z1 + alpha_mid*(z2-z1) - zp1)/dz - 0.5);
-
-    // Remember that this function traces only a single ray.
-    // rpl has been set to zero during initialisation.
-
-	if (i>=0 && i<Nx-1 && j>=0 && j<Ny-1 && k>=0 && k<Nz-1)
-	{
-		voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
-		rpl += length * voxel_density/2.0;  // add first half of int. length
-		// store pathlength only if the voxel is intersected almost directly
-		// by the ray
-
-		// Include the visited indices in Matlab notation, since that's 
-		// how the data will eventually be returned.
-
-		indVisited[*Nvisited] = i + j*electron_density_grid->x_count
-		    + k*electron_density_grid->x_count*electron_density_grid->y_count+1;
-		deffVisited[*Nvisited] = rpl; // radiological depth at visited location
-
-		(*Nvisited)++;
-		rpl += length * voxel_density/2.0;  //add second half of int. length
-	}
-    }
-  } 
-
-free(alpha); 			//deallocate remaining array storage 
-
-return(SUCCESS);
-
-} 					/*End of s_raytrace routine*/
-
-double round(double x)
-// Rounds x to the nearest integer.
-{
-	static double xfl;
-	xfl = floor((double)x);
-	if ( ((double)x - xfl) >= 0.5)
-		return(xfl + 1.0);  // round up
-	else
-		return(xfl);        // round down
-}
+/* singleRaytraceClean.cpp */
+
+/*  Does a raytracing operation between point1 and point2 in a density grid
+defined by DENS, START, and INC.  The visited voxels and their corresponding
+radiological depths are returned as the INDVISITED and DEFFVISITED vectors,
+respectively  */
+
+#include "mex.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <math.h>
+#include <string.h>
+
+#define SUCCESS 1
+#define FAILURE 0
+
+// macro for returning 3D grid index
+#define GRIDIND3D(x,y,z,dim) ((x) + dim[0]*(y) + dim[0]*dim[1]*(z))
+
+// 3D point
+typedef struct
+{
+    float x;
+    float y;
+    float z;
+} POINT;
+
+// 3D grid
+typedef struct
+{
+    POINT start;
+    POINT inc;
+    int x_count;
+    int y_count;
+    int z_count;
+    float *matrix;
+} FLOAT_GRID;
+
+// macro to access grid values
+#define GRID_VALUE(GRID_ptr, i, j, k)\
+    ((GRID_ptr)->matrix[(i) +\
+           (GRID_ptr)->x_count *\
+                ((j) + ((k) * (GRID_ptr)->y_count))])
+
+// User inputs
+#define DENS            (prhs[0])   // electron density grid
+#define START			(prhs[1])   // 3-element start vector
+#define INC		        (prhs[2])   // 3-element voxel size vector
+#define POINT1			(prhs[3])   // starting point for raytrace
+#define POINT2			(prhs[4])   // ending point for raytrace
+#define INDVISITED      (plhs[0])   // indices of visited voxels
+#define DEFFVISITED     (plhs[1])   // deff values of visited voxels
+
+// Prototypes
+int raytrace(FLOAT_GRID *,POINT,POINT,int *, float *, int *);
+double round(double);
+
+char errstr[200];  // error string that all routines have access to
+
+void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+	// scalars
+	int k,M,N,Q;
+
+	// pointers to vectors that do not need to be freed
+	const int *densDim,*startDim,*incDim,*p1Dim,*p2Dim;
+	float *densPtr,*startPtr,*incPtr,*p1Ptr,*p2Ptr;
+	int *indVisitedPtr;
+	float *deffVisitedPtr;
+
+	int dims[2];
+	int *indVisited; 
+	float *deffVisited;  // indices and deffs visited along ray
+	int maxVisited;
+	int Nvisited;
+
+	// point structures that will be used for raytrace operation
+	POINT p1;
+	POINT p2;
+
+	// grid structures for raytracing operation
+	FLOAT_GRID dens;
+	
+	// get dimensions of the input mxArrays
+	densDim = mxGetDimensions(DENS);
+	startDim = mxGetDimensions(START);
+	incDim = mxGetDimensions(INC);
+	p1Dim = mxGetDimensions(POINT1);
+	p2Dim = mxGetDimensions(POINT2);
+
+	// Check validity of input arguments.
+	if (  ((mxGetNumberOfDimensions(DENS) != 2) && (mxGetNumberOfDimensions(DENS) != 3))
+	   || (mxGetClassID(DENS) != mxSINGLE_CLASS))
+		mexErrMsgTxt("DENS must be a 3-D float array.");
+	
+	if (  (mxGetNumberOfDimensions(START) != 2)
+	   || (mxGetClassID(START) != mxSINGLE_CLASS)
+	   || (startDim[0]*startDim[1] != 3))
+		mexErrMsgTxt("START must be a 3-element float vector.");
+	
+	if (  (mxGetNumberOfDimensions(INC) != 2)
+	   || (mxGetClassID(INC) != mxSINGLE_CLASS)
+	   || (incDim[0]*incDim[1] != 3))
+		mexErrMsgTxt("INC must be a 3-element float vector.");
+
+	if (  (mxGetNumberOfDimensions(POINT1) != 2)
+	   || (mxGetClassID(POINT1) != mxSINGLE_CLASS)
+	   || (p1Dim[0]*p1Dim[1] != 3))
+		mexErrMsgTxt("POINT1 must be a 3-element float vector.");
+
+	if (  (mxGetNumberOfDimensions(POINT2) != 2)
+	   || (mxGetClassID(POINT2) != mxSINGLE_CLASS)
+	   || (p2Dim[0]*p2Dim[1] != 3))
+		mexErrMsgTxt("POINT2 must be a 3-element float vector.");
+
+	// assign data pointers
+	densPtr = (float *)mxGetData(DENS);
+	startPtr = (float *)mxGetData(START);
+	incPtr = (float *)mxGetData(INC);
+	p1Ptr = (float *)mxGetData(POINT1);
+	p2Ptr = (float *)mxGetData(POINT2);
+	
+	// get grid dimensions
+	M = densDim[0];
+	N = densDim[1];
+	if (mxGetNumberOfDimensions(DENS) == 3)
+		Q = densDim[2];
+	else  // handle 2D data as 3D data with the third dimension having 1 increment
+		Q = 1;
+
+	// printf("(M,N,Q) = (%d,%d,%d)\n",M,N,Q);
+
+
+	// the maximum number of voxels that can be visited along a single line
+	maxVisited = (int)(2*sqrt((double)(M*M+N*N+Q*Q)) + 1);  
+	indVisited = (int *)malloc(sizeof(int)*maxVisited);
+	deffVisited = (float *)malloc(sizeof(int)*maxVisited);
+
+	for (k=0;k<maxVisited;k++)
+	{
+		indVisited[k] = 0;
+		deffVisited[k] = 0.0;
+	}
+
+	// Assign dens and deff parameters to structures for input to raytrace
+	// Don't forget, dens.matrix and densPtr point to the same data, and
+	//               deff.matrix and deffPtr point to the same data.
+	dens.matrix = densPtr;
+	dens.start.x = startPtr[0];
+	dens.start.y = startPtr[1];
+	dens.start.z = startPtr[2];
+	dens.inc.x = incPtr[0];
+	dens.inc.y = incPtr[1];
+	dens.inc.z = incPtr[2];
+	dens.x_count = M;
+	dens.y_count = N;
+	dens.z_count = Q;
+
+	// assign values to p1 and p2
+	p1.x = p1Ptr[0];
+	p1.y = p1Ptr[1];
+	p1.z = p1Ptr[2];
+
+	p2.x = p2Ptr[0];
+	p2.y = p2Ptr[1];
+	p2.z = p2Ptr[2];
+
+	// do the raytrace, filling in voxels that are passed on the way
+	if (raytrace(&dens,p1,p2,indVisited,deffVisited,&Nvisited) == FAILURE)
+		mexErrMsgTxt(errstr);
+
+	dims[0] = 1;
+	dims[1] = Nvisited;
+	// dims[1] = 1;
+	// set up output vectors
+	INDVISITED = mxCreateNumericArray(2,dims,mxINT32_CLASS,mxREAL);
+	DEFFVISITED = mxCreateNumericArray(2,dims,mxSINGLE_CLASS,mxREAL);
+ 
+	indVisitedPtr = (int *)mxGetData(INDVISITED);
+	deffVisitedPtr = (float *)mxGetData(DEFFVISITED);
+
+	// copy results array to Matlab outputs
+	for (k=0;k<Nvisited;k++)
+	{
+		indVisitedPtr[k] = indVisited[k];
+		deffVisitedPtr[k] = deffVisited[k];
+	}
+}
+
+extern char errstr[200];  // error string that all routines have access to
+
+int raytrace(FLOAT_GRID *electron_density_grid,POINT point1,POINT point2,
+			int *indVisited, float *deffVisited, int *Nvisited)
+/*
+--------------------------------------------------------------------------------
+   NAME
+ 	c_raytrace
+ 
+   SYNOPSIS
+        point1 and point2 are the end points of the ray. 
+
+   DESCRIPTION
+        This function traces the ray from point x to point y (in real 
+        coords), assigning depth to any voxels which that ray crosses. The 
+        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
+        1985). This routine will not be understood without thorough reading 
+        of that paper! Point1 and point2 are the start and end points of the 
+        ray, respectively. External structures of type GRID are assumed to 
+        exist, where electron_density_grid are the electron densities, and 
+        radiological_depth_grid is the output grid for these calculations.
+        Voxels in radiological_depth_grid are initially set -ve prior to 
+        calling this function.
+ 
+   AUTHOR
+        Written by David C. Murray
+                   University of Waikato
+                   Private Bag 3105
+                   Hamilton
+                   New Zealand
+        and Copyright (1991) to
+                   David C. Murray and Peter W. Hoban,
+                   Cancer Society of New Zealand Inc., and 
+                   University of Waikato.
+--------------------------------------------------------------------------------
+*/
+
+{
+/* Variable descriptions:
+   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
+     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
+   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
+   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
+   dx,dy,dz are the widths in cm of the voxels
+*/
+float         x1,y1,z1,
+              x2,y2,z2,
+              xp1,yp1,zp1,
+              dx,dy,dz;
+int           Nx,Ny,Nz;
+
+/*General ray-trace algorithm variables*/
+float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
+float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
+					/*limits of alpha x,y,z parameters*/
+float alpha_min, alpha_max;		/*limits of alpha parameter*/
+int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
+float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
+float *alpha;				/*holds merged set of alpha values*/
+int i_index,j_index,k_index;		/*loop indices for merging alphas*/
+int a;					/*loop counter*/
+int max_index;				/*max index of merged alpha array*/
+float d12;				/*distance between ray end points*/
+float alpha_mid;			/*mid-point of intersection length*/
+float length;				/*intersection length*/
+int i,j,k;				/*indices of voxel with int. length*/
+float rpl = 0.0;			/*radiological path length in cm*/
+float voxel_density;			/*temporary voxel density*/
+float lmax;  // best possible penetration pathlength for a voxel
+float pnorm;  // absolute difference between p1 and p2
+
+/* Assign variables */
+/******************************************************************************/
+x1 = point1.x;
+y1 = point1.y;
+z1 = point1.z;
+x2 = point2.x;
+y2 = point2.y;
+z2 = point2.z;
+Nx = electron_density_grid->x_count + 1;
+Ny = electron_density_grid->y_count + 1;
+Nz = electron_density_grid->z_count + 1;
+dx = electron_density_grid->inc.x;
+dy = electron_density_grid->inc.y;
+dz = electron_density_grid->inc.z;
+
+// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
+xp1 = electron_density_grid->start.x - (float)0.5*dx;
+yp1 = electron_density_grid->start.y - (float)0.5*dy;
+zp1 = electron_density_grid->start.z - (float)0.5*dz;
+
+pnorm = (float)sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
+
+// this is the largest pathlength possible for a ray through a voxel:
+lmax = (float)sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
+
+/* Calculate xpN,ypN,zpN */
+/******************************************************************************/
+xpN = xp1 + (Nx-1)*dx;
+ypN = yp1 + (Ny-1)*dy;
+zpN = zp1 + (Nz-1)*dz;
+
+/*Calculate alpha_min and alpha_max*/
+/******************************************************************************/
+/*Avoid division by zero*/
+if (x1==x2)
+  x2 += 0.00001;
+if (y1==y2)
+  y2 += 0.00001;
+if (z1==z2)
+  z2 += 0.00001;
+if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
+{
+	sprintf(errstr,"Error - ray trace region too small.");
+	return(FAILURE);
+}
+
+alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
+if (alpha_z_min>alpha_min) 
+  alpha_min = alpha_z_min;
+if (alpha_min<0)
+  alpha_min = 0;
+alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
+if (alpha_z_max<alpha_max) 
+  alpha_max = alpha_z_max;
+if (alpha_max>1)
+  alpha_max = 1;
+
+// Monitor lines...
+/*
+printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
+                alpha_x_min,alpha_y_min,alpha_z_min);
+printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
+                alpha_x_max,alpha_y_max,alpha_z_max);
+printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
+printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx);  */
+
+/*Determine the ranges of i,j,k indices*/
+/******************************************************************************/
+/*The following assignments require conversion from float to integer types*/
+/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
+/*functions convert to the correct value. Note that the range of these*/
+/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
+		
+i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
+                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
+i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
+                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
+j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
+                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
+j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
+                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
+k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
+                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
+k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
+                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
+// Monitor lines...
+/* printf("    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
+printf("    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max); */
+
+// return if the indices do not make sense
+if (   i_max - i_min + 1 < 0 || i_max - i_min + 1 > Nx
+	|| j_max - j_min + 1 < 0 || j_max - j_min + 1 > Ny
+	|| k_max - k_min + 1 < 0 || k_max - k_min + 1 > Nz)
+{
+	*Nvisited = 0; // no voxels were visited
+	return(SUCCESS);
+}
+
+/*Generate sets of alpha values,reversing order if necessary*/
+/******************************************************************************/
+/*allocate array space on stack*/
+if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
+	return(FAILURE);
+}
+ 
+/*
+printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
+printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
+printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
+
+if (i_min <= i_max)
+  if (x2>x1)
+    {
+    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=1;a<=i_max-i_min;a++)
+      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
+    }
+  else
+    {
+    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=i_max-i_min-1;a>=0;a--)
+      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
+    }
+alpha_x[i_max-i_min+1] = 10000.0;
+if (j_min <= j_max)
+  if (y2>y1)
+    {
+    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=1;a<=j_max-j_min;a++)
+      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
+    }
+  else
+    {
+    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=j_max-j_min-1;a>=0;a--)
+      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
+    }
+alpha_y[j_max-j_min+1] = 10001.0;
+if (k_min <= k_max)
+  if (z2>z1)
+    {
+    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=1;a<=k_max-k_min;a++)
+      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
+    }
+  else
+    {
+    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=k_max-k_min-1;a>=0;a--)
+      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
+  }
+alpha_z[k_max-k_min+1] = 10002.0; 
+
+
+/* Monitor lines...
+if (i_max<i_min)
+  fprintf(stdout,"    No alpha_x values\n");
+else
+  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
+                 alpha_x[0],alpha_x[i_max-i_min]);
+if (j_max<j_min)
+  fprintf(stdout,"    No alpha_y values\n");
+else
+  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
+                 alpha_y[0],alpha_y[j_max-j_min]);
+if (k_max<k_min)
+  fprintf(stdout,"    No alpha_z values\n");
+else
+  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
+                 alpha_z[0],alpha_z[k_max-k_min]);
+*/
+/*Generate merged set of alpha values*/
+
+
+/******************************************************************************/
+if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
+	return(FAILURE);
+}
+
+max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
+alpha[0] = alpha_min;
+i_index = 0;
+j_index = 0;
+k_index = 0;
+for (a=1;a<=max_index-1;a++)
+  if (alpha_x[i_index]<alpha_y[j_index])
+    if (alpha_x[i_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_x[i_index];
+      i_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+  else
+    if (alpha_y[j_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_y[j_index];
+      j_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+alpha[max_index] = alpha_max;
+free(alpha_x);				//deallocate temp array storage
+free(alpha_y);
+free(alpha_z);
+/*Monitor lines...
+fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
+for (a=0;a<=max_index;a++)
+  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
+*/
+/*Calculate voxel lengths and indices, and assign radiological depth*/
+/******************************************************************************/
+d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
+					//d12 is distance between ray end pts
+
+*Nvisited = 0;  // start counter for number of voxel visited
+
+for (a=1;a<=max_index;a++)
+  {
+  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
+  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
+    {
+    alpha_mid = (alpha[a]+alpha[a-1])/2.0;  //alpha_mid is middle of int. length
+
+	//i,j,k are indices of voxel
+	i = (int) round((x1 + alpha_mid*(x2-x1) - xp1)/dx - 0.5);
+    j = (int) round((y1 + alpha_mid*(y2-y1) - yp1)/dy - 0.5);
+    k = (int) round((z1 + alpha_mid*(z2-z1) - zp1)/dz - 0.5);
+
+    // Remember that this function traces only a single ray.
+    // rpl has been set to zero during initialisation.
+
+	if (i>=0 && i<Nx-1 && j>=0 && j<Ny-1 && k>=0 && k<Nz-1)
+	{
+		voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
+		rpl += length * voxel_density/2.0;  // add first half of int. length
+		// store pathlength only if the voxel is intersected almost directly
+		// by the ray
+
+		// Include the visited indices in Matlab notation, since that's 
+		// how the data will eventually be returned.
+
+		indVisited[*Nvisited] = i + j*electron_density_grid->x_count
+		    + k*electron_density_grid->x_count*electron_density_grid->y_count+1;
+		deffVisited[*Nvisited] = rpl; // radiological depth at visited location
+
+		(*Nvisited)++;
+		rpl += length * voxel_density/2.0;  //add second half of int. length
+	}
+    }
+  } 
+
+free(alpha); 			//deallocate remaining array storage 
+
+return(SUCCESS);
+
+} 					/*End of s_raytrace routine*/
+
+double round(double x)
+// Rounds x to the nearest integer.
+{
+	static double xfl;
+	xfl = floor((double)x);
+	if ( ((double)x - xfl) >= 0.5)
+		return(xfl + 1.0);  // round up
+	else
+		return(xfl);        // round down
+}

+ 13 - 13
WiscPlanPhotonkV125/matlab_frontend/sum_dose.m

@@ -1,14 +1,14 @@
-function D = sum_dose(B, w)
-if nargin < 2
-    w = ones(size(B));
-end
-D = zeros(B{1}.x_count, B{1}.y_count, B{1}.z_count);
-for k = 1:numel(B)
-    if ~isempty(B{k}.non_zero_indices)
-        D(B{k}.non_zero_indices) = D(B{k}.non_zero_indices) + w(k) * B{k}.non_zero_values;
-    end
-end
-
-
-% imagesc(squeeze(D(26,:,:)))
+function D = sum_dose(B, w)
+if nargin < 2
+    w = ones(size(B));
+end
+D = zeros(B{1}.x_count, B{1}.y_count, B{1}.z_count);
+for k = 1:numel(B)
+    if ~isempty(B{k}.non_zero_indices)
+        D(B{k}.non_zero_indices) = D(B{k}.non_zero_indices) + w(k) * B{k}.non_zero_values;
+    end
+end
+
+
+% imagesc(squeeze(D(26,:,:)))
 % drawnow;

+ 79 - 79
WiscPlanPhotonkV125/matlab_frontend/superpix_group.m

@@ -1,80 +1,80 @@
-
-
-function superMask = superpix_group(mask, N_svox_in, orthoPlot)
-% this function contains supervoxel grouping
-fprintf(['\n' 'Creating ' num2str(N_svox_in) ' SupVox:\n' ])
-canvas2 = sqrt(bwdist(1-mask));
-% orthoslice (canvas2)
-
-% find box crop of ROI
-ymin = 0;
-ymax = 0;
-for yi = 1:size(mask,1)
-    data = mask(yi, :,:);
-    if max(data(:)) >0
-        if ymin == 0
-            ymin = yi;
-        end
-        ymax = yi;
-    end
-end
-xmin = 0;
-xmax = 0;
-for xi = 1:size(mask,2)
-    data = mask(:,xi,:);
-    if max(data(:)) >0
-        if xmin == 0
-            xmin = xi;
-        end
-        xmax = xi;
-    end
-end
-zmin = 0;
-zmax = 0;
-for zi = 1:size(mask,3)
-    data = mask(:,:,zi);
-    if max(data(:)) >0
-        if zmin == 0
-            zmin = zi;
-        end
-        zmax = zi;
-    end
-end
-
-canvas3 = canvas2(ymin:ymax, xmin:xmax, zmin:zmax);
-
-N_svox = N_svox_in; % number of supervoxels to give as param to parse
-converge_factor = 1;
-while true
-    [L,NumLabels] = superpixels3(canvas3,N_svox);
-
-    superMask = zeros(size(mask));
-    superMask(ymin:ymax, xmin:xmax, zmin:zmax) = L;
-    superMask(logical(1-mask)) = 0;
-
-    numSupVox = numel(unique(superMask))-1; % number of created supervoxels
-    fprintf([num2str(numSupVox) ' areas created' ])
-    
-    if abs(numSupVox-N_svox_in)/N_svox_in < 0.2/sqrt(converge_factor)
-        
-        switch orthoPlot
-            case 'yes'
-                orthoslice(superMask)
-            case 'no'
-                fprintf('\n supervoxel volume created! (orthoslice skipped)')
-        end
-        break
-    end
-    N_svox2 = N_svox * N_svox_in/numSupVox;
-    N_svox = round(converge_factor * N_svox2 + (1-converge_factor)*N_svox);
-    converge_factor = converge_factor * 0.95;
-    fprintf([' - not ok. ' num2str(numSupVox/N_svox_in) ' of target. New start size: ' num2str(N_svox) '\n'])
-    
-    if converge_factor < 0.01
-%         orthoslice(superMask)
-        break
-    end
-end 
-fprintf([' -  ok.\n'])
-
+
+
+function superMask = superpix_group(mask, N_svox_in, orthoPlot)
+% this function contains supervoxel grouping
+fprintf(['\n' 'Creating ' num2str(N_svox_in) ' SupVox:\n' ])
+canvas2 = sqrt(bwdist(1-mask));
+% orthoslice (canvas2)
+
+% find box crop of ROI
+ymin = 0;
+ymax = 0;
+for yi = 1:size(mask,1)
+    data = mask(yi, :,:);
+    if max(data(:)) >0
+        if ymin == 0
+            ymin = yi;
+        end
+        ymax = yi;
+    end
+end
+xmin = 0;
+xmax = 0;
+for xi = 1:size(mask,2)
+    data = mask(:,xi,:);
+    if max(data(:)) >0
+        if xmin == 0
+            xmin = xi;
+        end
+        xmax = xi;
+    end
+end
+zmin = 0;
+zmax = 0;
+for zi = 1:size(mask,3)
+    data = mask(:,:,zi);
+    if max(data(:)) >0
+        if zmin == 0
+            zmin = zi;
+        end
+        zmax = zi;
+    end
+end
+
+canvas3 = canvas2(ymin:ymax, xmin:xmax, zmin:zmax);
+
+N_svox = N_svox_in; % number of supervoxels to give as param to parse
+converge_factor = 1;
+while true
+    [L,NumLabels] = superpixels3(canvas3,N_svox);
+
+    superMask = zeros(size(mask));
+    superMask(ymin:ymax, xmin:xmax, zmin:zmax) = L;
+    superMask(logical(1-mask)) = 0;
+
+    numSupVox = numel(unique(superMask))-1; % number of created supervoxels
+    fprintf([num2str(numSupVox) ' areas created' ])
+    
+    if abs(numSupVox-N_svox_in)/N_svox_in < 0.2/sqrt(converge_factor)
+        
+        switch orthoPlot
+            case 'yes'
+                orthoslice(superMask)
+            case 'no'
+                fprintf('\n supervoxel volume created! (orthoslice skipped)')
+        end
+        break
+    end
+    N_svox2 = N_svox * N_svox_in/numSupVox;
+    N_svox = round(converge_factor * N_svox2 + (1-converge_factor)*N_svox);
+    converge_factor = converge_factor * 0.95;
+    fprintf([' - not ok. ' num2str(numSupVox/N_svox_in) ' of target. New start size: ' num2str(N_svox) '\n'])
+    
+    if converge_factor < 0.01
+%         orthoslice(superMask)
+        break
+    end
+end 
+fprintf([' -  ok.\n'])
+
 end

+ 482 - 482
WiscPlanPhotonkV125/matlab_frontend/utilities/bwdistsc.m

@@ -1,483 +1,483 @@
-function D=bwdistsc(bw,aspect)
-% D=BWDISTSC(BW,ASPECT)
-% BWDISTSC computes Euclidean distance transform of the binary 3D image 
-% BW. For each pixel in BW, the distance transform assignes a number
-% that is the distance between that pixel and the nearest nonzero pixel 
-% of BW. BW may be a single 2D image, 3D array or a cell array of 
-% 2D slices. ASPECT is 3-component vector defining aspect ratio in 
-% the dataset BW. If ASPECT is not specified, isotropic aspect 
-% ratio [1 1 1] is assumed.
-%
-% BWDISTSC uses fast optimized scanning algorithm and cell-arrays to 
-% represent internal data, so that it is less demanding to physical 
-% memory. In many cases BWDISTSC is actually faster than MATLAB's 
-% optimized kd-tree algorithm used for Euclidean distance 
-% transform in 3D. 
-%
-% BWDISTSC tries to use MATLAB bwdist for 2D scans if possible, which 
-% is significantly faster. Otherwise BWDISTSC uses internal algorithm 
-% to perform 2D scans.
-%
-%     Yuriy Mishchenko  JFRC HHMI Chklovskii Lab  JUL 2007
-
-% This code is free for use or modifications, just please give credit 
-% where appropriate. And if you modify code or fix bugs, please drop 
-% me a message at gmyuriy@hotmail.com.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Scan algorithms below use following Lema:                     %
-% LEMA: let F(X,z) be lower envelope of a family of parabola:   %
-% F(X,z)=min_{i} [G_i(X)+(z-k_i)^2];                            %
-% and let H_k(X,z)=A(X)+(z-k)^2 be a parabola.                  %
-% Then for H_k(X,z)==F(X,z) at each X there exist at most       %
-% two solutions k1<k2 such that H_k12(X,z)=F(X,z), and          %
-% H_k(X,z)<F(X,z) is restricted to at most k1<k2.               %
-% Here X is any-dimensional coordinate.                         %
-%                                                               %
-% Thus, simply scan away from any z such that H_k(X,z)<F(X,z)   %
-% in either direction as long as H_k(X,z)<F(X,z) and update     %
-% F(X,z). Note that need to properly choose starting point;     %
-% starting point is any z such that H_k(X,z)<F(X,z); z==k is    %
-% usually, but not always the starting point!!!                 %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% parse inputs
-if(nargin<2 || isempty(aspect)) aspect=[1 1 1]; end
-
-% determine geometry of data
-if(iscell(bw)) shape=[size(bw{1}),length(bw)]; else shape=size(bw); end
-
-% fix to handle 1D & 2D images
-if(length(shape)<3) shape(length(shape)+1:3)=1; end
-if(length(aspect)<3) aspect(length(aspect)+1:3)=1; end
-
-% allocate space
-D=cell(1,shape(3)); for k=1:shape(3) D{k}=zeros(shape(1:2)); end
-
-%%%%%%%%%%%%% scan along XY %%%%%%%%%%%%%%%%
-for k=1:shape(3)    
-    if(iscell(bw)) bwXY=bw{k}; else bwXY=bw(:,:,k); end
-        
-    % initialize arrays
-    DXY=zeros(shape(1:2));
-    D1=zeros(shape(1:2));
-    DK=zeros(shape(1:2));
-
-    % if can, use 2D bwdist from image processing toolbox    
-    if(exist('bwdist') && aspect(1)==aspect(2))
-        D1=aspect(1)^2*bwdist(bwXY).^2;
-    else    % if not, use full XY-scan
-        %%%%%%%%%%%%%%% X-SCAN %%%%%%%%%%%%%%%        
-        % reference nearest bwXY "on"-pixel in x direction downward:
-        
-        %  scan bottow-up, copy x-reference from previous row unless 
-        %  there is bwXY "on"-pixel in that point in current row
-        xlower=repmat(Inf,shape(1:2)); 
-        
-        xlower(1,find(bwXY(1,:)))=1;    % fill in first row
-        for i=2:shape(1)
-            xlower(i,:)=xlower(i-1,:);  % copy previous row
-            xlower(i,find(bwXY(i,:)))=i;% unless there is pixel
-        end
-        
-        % reference nearest bwXY "on"-pixel in x direction upward:
-        xupper=repmat(Inf,shape(1:2));
-        
-        xupper(end,find(bwXY(end,:)))=shape(1);
-        for i=shape(1)-1:-1:1
-            xupper(i,:)=xupper(i+1,:);
-            xupper(i,find(bwXY(i,:)))=i;
-        end
-                
-        % find points for which distance needs to be updated
-        idx=find(~bwXY); [x,y]=ind2sub(shape(1:2),idx);
-        
-        % set distance as the shortest to upward or to downward
-        DXY(idx)=aspect(1)^2*min((x-xlower(idx)).^2,(x-xupper(idx)).^2);
-        
-        %%%%%%%%%%%%%%% Y-SCAN %%%%%%%%%%%%%%%
-        % this will be the envelop 
-        % envelop is initialized at Inf to ensure single scan direction, 
-        % otherwise may end up in infinite loop when trying to find 
-        % starting point
-        D1=repmat(Inf,shape(1:2));
-        % these will be the references to parabolas defining the envelop
-        DK=repmat(Inf,shape(1:2));
-        % starting points
-        i0=zeros(shape(1),1);
-        % convenience x-coords array 
-        x=(1:shape(1))'; 
-        
-        for i=1:shape(2)
-            % need to select starting point for each X:
-            % * starting point should be below current envelop
-            % * i0==i is not necessarily a starting point
-            % * there is at most one starting point
-            % * there may be no starting point
-            
-            % i0 is the starting points for each X: i0(X) is the first 
-            % y-index such that parabola from line i is below the envelop
-            
-            % first guess is the current y-line
-            i0(:)=i;
-            
-            % some auxiliary datasets
-            d0=DXY(:,i);
-
-            % L0 indicates for which X starting point had been fixed
-            L0=isinf(d0) | (d0==0);
-            
-            while(~isempty(find(~L0,1)))
-                % reference starting points in DXY
-                idx=sub2ind(shape(1:2),x(~L0),i0(~L0));
-                
-                % reduce out trivial points (DXY==0)
-                L=(DXY(idx)==0);
-                L0(~L0)=L;
-                idx=idx(~L);
-                
-                if(isempty(idx)) continue; end
-                
-                % these are current best parabolas for starting points
-                ik=DK(idx);
-                
-                % these are new values from parabola from line #i
-                dtmp=d0(~L0)+aspect(2)^2*(i0(~L0)-i).^2;
-                
-                % these starting points are OK - below the envelop
-                L=D1(idx)>dtmp; D1(idx(L))=dtmp(L);
-                
-                % points which are still above the envelop but ik==i0,
-                % will not get any better, so fix them as well
-                L=L | (ik==i0(~L0));
-                                
-                % all other points are not OK, need new starting point:
-                % starting point should be at least below parabola 
-                % beating us at current choice of i0
-                
-                % solve quadratic equation to find where this happens
-                ik=(ik-i); 
-                di=(D1(idx(~L))-dtmp(~L))./ik(~L)/2/aspect(2)^2;
-
-                % should select next highest index to the equality
-                di=fix(di)+sign(di);
-                
-                % the new starting points
-                idx=find(~L0); 
-                i0(idx(~L))=i0(idx(~L))+di;
-
-                % update L0 to indicate which points we've fixed
-                L0(~L0)=L; L0(idx(~L))=(di==0);
-                
-                % points that went out of boundaries can't get better; 
-                % fix them as well
-                idx=idx(~L);
-                idx=idx((i0(idx)<1) | (i0(idx)>shape(2))); 
-                i0(idx)=i;
-                L0(idx)=1;                
-            end
-
-            % reduce out trivial points DXY(idx)<DXY(:,i)
-            idx=sub2ind(shape(1:2),x,i0);
-            L=(DXY(idx)>0) | (i0==i);
-            idx=idx(L);
-
-            % these will keep track along which X should 
-            % keep updating distances            
-            map_lower=L;
-            map_upper=L;            
-            idx_lower=idx;
-            idx_upper=idx;
-            
-            % set trivial pixels D==0 in line #i:
-            % this has to be done b/s we manually discarded them from L0
-            D1(d0==0,i)=0;
-
-            % scan from starting points for each X,i0 in increments of 1
-            di=0;       % distance from current y-line
-            eols=2;     % end-of-line-scan flag
-            totlen=prod(shape(1:2));
-            while(eols)
-                eols=2;
-                di=di+1;
-                
-                % select X which can be updated for di<0;
-                % i.e. X which had been below envelop all way till now
-                if(~isempty(idx_lower))
-                    % shift y by -1
-                    idx_lower=idx_lower-shape(1);
-                    
-                    % prevent index dropping below 1st
-                    L=(idx_lower>=1);
-                    map_lower(map_lower)=L;
-                    idx_lower=idx_lower(L);
-                    
-                    if(~isempty(idx_lower))
-                        dtmp=d0(map_lower)+...
-                            aspect(2)^2*(i0(map_lower)-di-i).^2;
-                    
-                        % these pixels are to be updated with i0-di
-                        L=D1(idx_lower)>dtmp & DXY(idx_lower)>0;
-                        map_lower(map_lower)=L;
-                        idx_lower=idx_lower(L);
-                        D1(idx_lower)=dtmp(L);
-                        DK(idx_lower)=i;
-                    end
-                else    % if this is empty, get ready to quit
-                    eols=eols-1;
-                end
-
-                % select X which can be updated for di>0;
-                % i.e. X which had been below envelop all way till now
-                if(~isempty(idx_upper))
-                    % shift y by +1
-                    idx_upper=idx_upper+shape(1);
-                    
-                    % prevent index from going over array limits
-                    L=(idx_upper<=totlen);
-                    map_upper(map_upper)=L;
-                    idx_upper=idx_upper(L);
-                    
-                    if(~isempty(idx_upper))                        
-                        dtmp=d0(map_upper)+...
-                            aspect(2)^2*(i0(map_upper)+di-i).^2;
-                    
-                        % check which pixels are to be updated with i0+di
-                        L=D1(idx_upper)>dtmp & DXY(idx_upper)>0;
-                        map_upper(map_upper)=L;
-                        idx_upper=idx_upper(L);
-                        D1(idx_upper)=dtmp(L);
-                        DK(idx_upper)=i;
-                    end
-                else    % if this is empty, get ready to quit
-                    eols=eols-1;
-                end  
-            end
-        end
-    end
-    D{k}=D1; 
-end
-
-%%%%%%%%%%%%% scan along Z %%%%%%%%%%%%%%%%
-% this will be the envelop: 
-% envelop has to be initialized at Inf to ensure single direction of scan, 
-% otherwise may end up in infinite loop when trying to find starting point
-D1=cell(size(D));
-for k=1:shape(3) D1{k}=repmat(Inf,shape(1:2)); end
-% these will be the references to parabolas defining the envelop
-DK=cell(size(D));
-for k=1:shape(3) DK{k}=repmat(Inf,shape(1:2)); end
-
-% start building the envelope 
-for k=1:shape(3)
-    % need to select starting point for each X:
-    % * starting point should be below current envelop
-    % * k0==k is not necessarily a starting point
-    % * there may be no starting point
-    
-    % k0 is the starting points for each XY: k0(XY) is the first
-    % z-index such that parabola from line k is below the envelop
-
-    % initial starting point guess is current slice
-    k0=repmat(k,shape(1:2));
-    
-    % L0 indicates which starting points had been fixed
-    L0=isinf(D{k}) | (D{k}==0);
-    idxtot=find(~L0);
-    
-    while(~isempty(idxtot))
-        % because of using cells need to explicitly scan in Z
-        % to avoid repetitious searches in k0, parse first
-        ss=getregions(k0(idxtot));
-        sslen=length(ss);
-        
-        for kk=1:sslen
-            % these are starting points @kk which had not been set
-            idx=idxtot(ss(kk).PixelIdxList);
-            
-            % reduce out trivial points (D==0)
-            if(kk~=k)
-                L=(D{kk}(idx)==0);
-                L0(idx)=L;
-                idx=idx(~L);
-            end
-
-            if(isempty(idx)) continue; end
-            
-            % these are currently best parabolas for slice kk
-            ik=DK{kk}(idx);            
-            
-            % these are new values for slice kk from parabola from k
-            dtmp=D{k}(idx)+aspect(3)^2*(kk-k)^2;
-            
-            % these points are OK - below current envelop
-            L=D1{kk}(idx)>dtmp; D1{kk}(idx(L))=dtmp(L);            
-            
-            % these points are not OK, but since ik==k0
-            % can't get any better
-            L=L | (ik==kk);            
-                
-            % all other points are not OK, need new starting point:
-            % starting point should be at least below parabola
-            % beating us at current choice of k0
-            
-            % solve quadratic equation to find where this happens
-            ik=(ik-k);
-            dk=(D1{kk}(idx(~L))-dtmp(~L))./ik(~L)/2/aspect(3)^2;
-            dk=fix(dk)+sign(dk);
-            k0(idx(~L))=k0(idx(~L))+dk;
-    
-            % update starting points that had been set
-            L0(idx)=L;
-            L0(idx(~L))=(dk==0);
-    
-            % points that went out of boundaries can't get better
-            idx=idx(~L);
-            idx=idx((k0(idx)<1) | (k0(idx)>shape(3)));
-            L0(idx)=1;
-            k0(idx)=k;
-        end
-
-        idxtot=find(~L0);
-    end
-    
-    % map_lower/map_upper keeps track of which pixels can be yet updated
-    % with new distance, i.e. all such XY that had been below envelop for
-    % all dk up to now for dk<0/dk>0 respectively
-    map_lower=true(shape(1:2));
-    map_upper=true(shape(1:2));
-
-    % parse different values in k0 to avoid repetitious searching below
-    ss=getregions(k0); 
-    sslen=length(ss);
-
-    % reduce out trivially faulty starting points
-    for kk=1:sslen
-        if(kk==k) continue; end
-        
-        idx=ss(kk).PixelIdxList;
-        
-        L=D{kk}(idx)>D{k}(idx);
-        map_lower(idx)=L;
-        map_upper(idx)=L;
-    end
-    
-    % these are maintained to keep fast track of whether maps are empty
-    idx_lower=find(map_lower);
-    idx_upper=find(map_upper);
-    
-    % set trivial pixels D==0 in slice k:
-    % this has to be done b/s we manually discarded them from L0
-    D1{k}(D{k}==0)=0;        
-
-    % scan away from starting points in increments of 1
-    dk=0;       % distance from current xy-slice
-    eols=2;     % end-of-scan flag
-    while(eols)
-        eols=2;
-        dk=dk+1;
-
-        if(~isempty(idx_lower))
-            % prevent index from going over the boundaries
-            L=(k0(map_lower)-dk>=1);
-            map_lower(map_lower)=L;
-            % need to explicitly scan in Z because of using cell-arrays
-            for kk=1:sslen-dk
-                % get all XY such that k0-dk==kk
-                idx=ss(kk+dk).PixelIdxList; 
-                L=map_lower(idx);
-                idx=idx(L);                
-
-                if(~isempty(idx))
-                    dtmp=D{k}(idx)+aspect(3)^2*(kk-k)^2;
-                    
-                    % these pixels are to be updated with k0-dk
-                    L=D1{kk}(idx)>dtmp & D{kk}(idx)>0;
-                    map_lower(idx)=L;
-                    D1{kk}(idx(L))=dtmp(L);
-                    
-                    % ridiculously, but this is faster than
-                    % direct assignment
-                    dtmp=idx(L);
-                    dtmp(:)=k;
-                    DK{kk}(idx(L))=k;
-                end
-            end
-            idx_lower=idx_lower(map_lower(idx_lower));
-        else
-            eols=eols-1;
-        end
-
-        if(~isempty(idx_upper))
-            % prevent index from going over the boundaries            
-            L=(k0(map_upper)+dk<=shape(3));
-            map_upper(map_upper)=L;
-            % need to explicitly scan in Z because of using cell-arrays
-            for kk=dk+1:min(shape(3),sslen+dk)
-                % get all XY such that k0+dk==kk
-                idx=ss(kk-dk).PixelIdxList;
-                L=map_upper(idx);
-                idx=idx(L);                
-
-                if(~isempty(idx))                    
-                    dtmp=D{k}(idx)+aspect(3)^2*(kk-k)^2;
-    
-                    % these pixels are to be updated with k0+dk
-                    L=D1{kk}(idx)>dtmp & D{kk}(idx)>0;
-                    map_upper(idx)=L;
-                    D1{kk}(idx(L))=dtmp(L);
-                    
-                    dtmp=idx(L); 
-                    dtmp(:)=k;
-                    DK{kk}(idx(L))=dtmp;
-                end
-            end
-            idx_upper=idx_upper(map_upper(idx_upper));
-        else
-            eols=eols-1;
-        end
-    end
-end
-
-% the answer
-if(iscell(bw))
-    D=cell(size(bw));
-    for k=1:shape(3) D{k}=sqrt(D1{k}); end
-else
-    D=zeros(shape);
-    for k=1:shape(3) D(:,:,k)=sqrt(D1{k}); end
-end
-
-
-function s=getregions(map)
-% this function is replacer for regionprops(map,'PixelIdxList');
-% it produces the list of different values along with list of 
-% indexes of pixels in map with these values; 's' is struct-array 
-% such that s(i).PixelIdxList contains list of pixels in map 
-% with value i.
-
-% enable using regionprops if available, faster on 7.3
-fregionprops=1;
-
-% version control for using regionprops
-v=version; v=str2num(v(1:3)); 
-fregionprops=fregionprops & v>=7.3;
-
-% in later matlab regionprops is actually faster than this code
-if(exist('regionprops') & fregionprops)
-    s=regionprops(map,'PixelIdxList');
-    return
-end
-
-idx=(1:prod(size(map)))';
-dtmp=double(map(:));
-
-[dtmp,ind]=sort(dtmp); 
-idx=idx(ind);
-ind=[0;find([diff(dtmp(:));1])];
-
-s=[];
-for i=2:length(ind)
-    if(dtmp(ind(i)))==0 continue; end
-    s(dtmp(ind(i))).PixelIdxList=idx(ind(i-1)+1:ind(i));
+function D=bwdistsc(bw,aspect)
+% D=BWDISTSC(BW,ASPECT)
+% BWDISTSC computes Euclidean distance transform of the binary 3D image 
+% BW. For each pixel in BW, the distance transform assignes a number
+% that is the distance between that pixel and the nearest nonzero pixel 
+% of BW. BW may be a single 2D image, 3D array or a cell array of 
+% 2D slices. ASPECT is 3-component vector defining aspect ratio in 
+% the dataset BW. If ASPECT is not specified, isotropic aspect 
+% ratio [1 1 1] is assumed.
+%
+% BWDISTSC uses fast optimized scanning algorithm and cell-arrays to 
+% represent internal data, so that it is less demanding to physical 
+% memory. In many cases BWDISTSC is actually faster than MATLAB's 
+% optimized kd-tree algorithm used for Euclidean distance 
+% transform in 3D. 
+%
+% BWDISTSC tries to use MATLAB bwdist for 2D scans if possible, which 
+% is significantly faster. Otherwise BWDISTSC uses internal algorithm 
+% to perform 2D scans.
+%
+%     Yuriy Mishchenko  JFRC HHMI Chklovskii Lab  JUL 2007
+
+% This code is free for use or modifications, just please give credit 
+% where appropriate. And if you modify code or fix bugs, please drop 
+% me a message at gmyuriy@hotmail.com.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Scan algorithms below use following Lema:                     %
+% LEMA: let F(X,z) be lower envelope of a family of parabola:   %
+% F(X,z)=min_{i} [G_i(X)+(z-k_i)^2];                            %
+% and let H_k(X,z)=A(X)+(z-k)^2 be a parabola.                  %
+% Then for H_k(X,z)==F(X,z) at each X there exist at most       %
+% two solutions k1<k2 such that H_k12(X,z)=F(X,z), and          %
+% H_k(X,z)<F(X,z) is restricted to at most k1<k2.               %
+% Here X is any-dimensional coordinate.                         %
+%                                                               %
+% Thus, simply scan away from any z such that H_k(X,z)<F(X,z)   %
+% in either direction as long as H_k(X,z)<F(X,z) and update     %
+% F(X,z). Note that need to properly choose starting point;     %
+% starting point is any z such that H_k(X,z)<F(X,z); z==k is    %
+% usually, but not always the starting point!!!                 %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% parse inputs
+if(nargin<2 || isempty(aspect)) aspect=[1 1 1]; end
+
+% determine geometry of data
+if(iscell(bw)) shape=[size(bw{1}),length(bw)]; else shape=size(bw); end
+
+% fix to handle 1D & 2D images
+if(length(shape)<3) shape(length(shape)+1:3)=1; end
+if(length(aspect)<3) aspect(length(aspect)+1:3)=1; end
+
+% allocate space
+D=cell(1,shape(3)); for k=1:shape(3) D{k}=zeros(shape(1:2)); end
+
+%%%%%%%%%%%%% scan along XY %%%%%%%%%%%%%%%%
+for k=1:shape(3)    
+    if(iscell(bw)) bwXY=bw{k}; else bwXY=bw(:,:,k); end
+        
+    % initialize arrays
+    DXY=zeros(shape(1:2));
+    D1=zeros(shape(1:2));
+    DK=zeros(shape(1:2));
+
+    % if can, use 2D bwdist from image processing toolbox    
+    if(exist('bwdist') && aspect(1)==aspect(2))
+        D1=aspect(1)^2*bwdist(bwXY).^2;
+    else    % if not, use full XY-scan
+        %%%%%%%%%%%%%%% X-SCAN %%%%%%%%%%%%%%%        
+        % reference nearest bwXY "on"-pixel in x direction downward:
+        
+        %  scan bottow-up, copy x-reference from previous row unless 
+        %  there is bwXY "on"-pixel in that point in current row
+        xlower=repmat(Inf,shape(1:2)); 
+        
+        xlower(1,find(bwXY(1,:)))=1;    % fill in first row
+        for i=2:shape(1)
+            xlower(i,:)=xlower(i-1,:);  % copy previous row
+            xlower(i,find(bwXY(i,:)))=i;% unless there is pixel
+        end
+        
+        % reference nearest bwXY "on"-pixel in x direction upward:
+        xupper=repmat(Inf,shape(1:2));
+        
+        xupper(end,find(bwXY(end,:)))=shape(1);
+        for i=shape(1)-1:-1:1
+            xupper(i,:)=xupper(i+1,:);
+            xupper(i,find(bwXY(i,:)))=i;
+        end
+                
+        % find points for which distance needs to be updated
+        idx=find(~bwXY); [x,y]=ind2sub(shape(1:2),idx);
+        
+        % set distance as the shortest to upward or to downward
+        DXY(idx)=aspect(1)^2*min((x-xlower(idx)).^2,(x-xupper(idx)).^2);
+        
+        %%%%%%%%%%%%%%% Y-SCAN %%%%%%%%%%%%%%%
+        % this will be the envelop 
+        % envelop is initialized at Inf to ensure single scan direction, 
+        % otherwise may end up in infinite loop when trying to find 
+        % starting point
+        D1=repmat(Inf,shape(1:2));
+        % these will be the references to parabolas defining the envelop
+        DK=repmat(Inf,shape(1:2));
+        % starting points
+        i0=zeros(shape(1),1);
+        % convenience x-coords array 
+        x=(1:shape(1))'; 
+        
+        for i=1:shape(2)
+            % need to select starting point for each X:
+            % * starting point should be below current envelop
+            % * i0==i is not necessarily a starting point
+            % * there is at most one starting point
+            % * there may be no starting point
+            
+            % i0 is the starting points for each X: i0(X) is the first 
+            % y-index such that parabola from line i is below the envelop
+            
+            % first guess is the current y-line
+            i0(:)=i;
+            
+            % some auxiliary datasets
+            d0=DXY(:,i);
+
+            % L0 indicates for which X starting point had been fixed
+            L0=isinf(d0) | (d0==0);
+            
+            while(~isempty(find(~L0,1)))
+                % reference starting points in DXY
+                idx=sub2ind(shape(1:2),x(~L0),i0(~L0));
+                
+                % reduce out trivial points (DXY==0)
+                L=(DXY(idx)==0);
+                L0(~L0)=L;
+                idx=idx(~L);
+                
+                if(isempty(idx)) continue; end
+                
+                % these are current best parabolas for starting points
+                ik=DK(idx);
+                
+                % these are new values from parabola from line #i
+                dtmp=d0(~L0)+aspect(2)^2*(i0(~L0)-i).^2;
+                
+                % these starting points are OK - below the envelop
+                L=D1(idx)>dtmp; D1(idx(L))=dtmp(L);
+                
+                % points which are still above the envelop but ik==i0,
+                % will not get any better, so fix them as well
+                L=L | (ik==i0(~L0));
+                                
+                % all other points are not OK, need new starting point:
+                % starting point should be at least below parabola 
+                % beating us at current choice of i0
+                
+                % solve quadratic equation to find where this happens
+                ik=(ik-i); 
+                di=(D1(idx(~L))-dtmp(~L))./ik(~L)/2/aspect(2)^2;
+
+                % should select next highest index to the equality
+                di=fix(di)+sign(di);
+                
+                % the new starting points
+                idx=find(~L0); 
+                i0(idx(~L))=i0(idx(~L))+di;
+
+                % update L0 to indicate which points we've fixed
+                L0(~L0)=L; L0(idx(~L))=(di==0);
+                
+                % points that went out of boundaries can't get better; 
+                % fix them as well
+                idx=idx(~L);
+                idx=idx((i0(idx)<1) | (i0(idx)>shape(2))); 
+                i0(idx)=i;
+                L0(idx)=1;                
+            end
+
+            % reduce out trivial points DXY(idx)<DXY(:,i)
+            idx=sub2ind(shape(1:2),x,i0);
+            L=(DXY(idx)>0) | (i0==i);
+            idx=idx(L);
+
+            % these will keep track along which X should 
+            % keep updating distances            
+            map_lower=L;
+            map_upper=L;            
+            idx_lower=idx;
+            idx_upper=idx;
+            
+            % set trivial pixels D==0 in line #i:
+            % this has to be done b/s we manually discarded them from L0
+            D1(d0==0,i)=0;
+
+            % scan from starting points for each X,i0 in increments of 1
+            di=0;       % distance from current y-line
+            eols=2;     % end-of-line-scan flag
+            totlen=prod(shape(1:2));
+            while(eols)
+                eols=2;
+                di=di+1;
+                
+                % select X which can be updated for di<0;
+                % i.e. X which had been below envelop all way till now
+                if(~isempty(idx_lower))
+                    % shift y by -1
+                    idx_lower=idx_lower-shape(1);
+                    
+                    % prevent index dropping below 1st
+                    L=(idx_lower>=1);
+                    map_lower(map_lower)=L;
+                    idx_lower=idx_lower(L);
+                    
+                    if(~isempty(idx_lower))
+                        dtmp=d0(map_lower)+...
+                            aspect(2)^2*(i0(map_lower)-di-i).^2;
+                    
+                        % these pixels are to be updated with i0-di
+                        L=D1(idx_lower)>dtmp & DXY(idx_lower)>0;
+                        map_lower(map_lower)=L;
+                        idx_lower=idx_lower(L);
+                        D1(idx_lower)=dtmp(L);
+                        DK(idx_lower)=i;
+                    end
+                else    % if this is empty, get ready to quit
+                    eols=eols-1;
+                end
+
+                % select X which can be updated for di>0;
+                % i.e. X which had been below envelop all way till now
+                if(~isempty(idx_upper))
+                    % shift y by +1
+                    idx_upper=idx_upper+shape(1);
+                    
+                    % prevent index from going over array limits
+                    L=(idx_upper<=totlen);
+                    map_upper(map_upper)=L;
+                    idx_upper=idx_upper(L);
+                    
+                    if(~isempty(idx_upper))                        
+                        dtmp=d0(map_upper)+...
+                            aspect(2)^2*(i0(map_upper)+di-i).^2;
+                    
+                        % check which pixels are to be updated with i0+di
+                        L=D1(idx_upper)>dtmp & DXY(idx_upper)>0;
+                        map_upper(map_upper)=L;
+                        idx_upper=idx_upper(L);
+                        D1(idx_upper)=dtmp(L);
+                        DK(idx_upper)=i;
+                    end
+                else    % if this is empty, get ready to quit
+                    eols=eols-1;
+                end  
+            end
+        end
+    end
+    D{k}=D1; 
+end
+
+%%%%%%%%%%%%% scan along Z %%%%%%%%%%%%%%%%
+% this will be the envelop: 
+% envelop has to be initialized at Inf to ensure single direction of scan, 
+% otherwise may end up in infinite loop when trying to find starting point
+D1=cell(size(D));
+for k=1:shape(3) D1{k}=repmat(Inf,shape(1:2)); end
+% these will be the references to parabolas defining the envelop
+DK=cell(size(D));
+for k=1:shape(3) DK{k}=repmat(Inf,shape(1:2)); end
+
+% start building the envelope 
+for k=1:shape(3)
+    % need to select starting point for each X:
+    % * starting point should be below current envelop
+    % * k0==k is not necessarily a starting point
+    % * there may be no starting point
+    
+    % k0 is the starting points for each XY: k0(XY) is the first
+    % z-index such that parabola from line k is below the envelop
+
+    % initial starting point guess is current slice
+    k0=repmat(k,shape(1:2));
+    
+    % L0 indicates which starting points had been fixed
+    L0=isinf(D{k}) | (D{k}==0);
+    idxtot=find(~L0);
+    
+    while(~isempty(idxtot))
+        % because of using cells need to explicitly scan in Z
+        % to avoid repetitious searches in k0, parse first
+        ss=getregions(k0(idxtot));
+        sslen=length(ss);
+        
+        for kk=1:sslen
+            % these are starting points @kk which had not been set
+            idx=idxtot(ss(kk).PixelIdxList);
+            
+            % reduce out trivial points (D==0)
+            if(kk~=k)
+                L=(D{kk}(idx)==0);
+                L0(idx)=L;
+                idx=idx(~L);
+            end
+
+            if(isempty(idx)) continue; end
+            
+            % these are currently best parabolas for slice kk
+            ik=DK{kk}(idx);            
+            
+            % these are new values for slice kk from parabola from k
+            dtmp=D{k}(idx)+aspect(3)^2*(kk-k)^2;
+            
+            % these points are OK - below current envelop
+            L=D1{kk}(idx)>dtmp; D1{kk}(idx(L))=dtmp(L);            
+            
+            % these points are not OK, but since ik==k0
+            % can't get any better
+            L=L | (ik==kk);            
+                
+            % all other points are not OK, need new starting point:
+            % starting point should be at least below parabola
+            % beating us at current choice of k0
+            
+            % solve quadratic equation to find where this happens
+            ik=(ik-k);
+            dk=(D1{kk}(idx(~L))-dtmp(~L))./ik(~L)/2/aspect(3)^2;
+            dk=fix(dk)+sign(dk);
+            k0(idx(~L))=k0(idx(~L))+dk;
+    
+            % update starting points that had been set
+            L0(idx)=L;
+            L0(idx(~L))=(dk==0);
+    
+            % points that went out of boundaries can't get better
+            idx=idx(~L);
+            idx=idx((k0(idx)<1) | (k0(idx)>shape(3)));
+            L0(idx)=1;
+            k0(idx)=k;
+        end
+
+        idxtot=find(~L0);
+    end
+    
+    % map_lower/map_upper keeps track of which pixels can be yet updated
+    % with new distance, i.e. all such XY that had been below envelop for
+    % all dk up to now for dk<0/dk>0 respectively
+    map_lower=true(shape(1:2));
+    map_upper=true(shape(1:2));
+
+    % parse different values in k0 to avoid repetitious searching below
+    ss=getregions(k0); 
+    sslen=length(ss);
+
+    % reduce out trivially faulty starting points
+    for kk=1:sslen
+        if(kk==k) continue; end
+        
+        idx=ss(kk).PixelIdxList;
+        
+        L=D{kk}(idx)>D{k}(idx);
+        map_lower(idx)=L;
+        map_upper(idx)=L;
+    end
+    
+    % these are maintained to keep fast track of whether maps are empty
+    idx_lower=find(map_lower);
+    idx_upper=find(map_upper);
+    
+    % set trivial pixels D==0 in slice k:
+    % this has to be done b/s we manually discarded them from L0
+    D1{k}(D{k}==0)=0;        
+
+    % scan away from starting points in increments of 1
+    dk=0;       % distance from current xy-slice
+    eols=2;     % end-of-scan flag
+    while(eols)
+        eols=2;
+        dk=dk+1;
+
+        if(~isempty(idx_lower))
+            % prevent index from going over the boundaries
+            L=(k0(map_lower)-dk>=1);
+            map_lower(map_lower)=L;
+            % need to explicitly scan in Z because of using cell-arrays
+            for kk=1:sslen-dk
+                % get all XY such that k0-dk==kk
+                idx=ss(kk+dk).PixelIdxList; 
+                L=map_lower(idx);
+                idx=idx(L);                
+
+                if(~isempty(idx))
+                    dtmp=D{k}(idx)+aspect(3)^2*(kk-k)^2;
+                    
+                    % these pixels are to be updated with k0-dk
+                    L=D1{kk}(idx)>dtmp & D{kk}(idx)>0;
+                    map_lower(idx)=L;
+                    D1{kk}(idx(L))=dtmp(L);
+                    
+                    % ridiculously, but this is faster than
+                    % direct assignment
+                    dtmp=idx(L);
+                    dtmp(:)=k;
+                    DK{kk}(idx(L))=k;
+                end
+            end
+            idx_lower=idx_lower(map_lower(idx_lower));
+        else
+            eols=eols-1;
+        end
+
+        if(~isempty(idx_upper))
+            % prevent index from going over the boundaries            
+            L=(k0(map_upper)+dk<=shape(3));
+            map_upper(map_upper)=L;
+            % need to explicitly scan in Z because of using cell-arrays
+            for kk=dk+1:min(shape(3),sslen+dk)
+                % get all XY such that k0+dk==kk
+                idx=ss(kk-dk).PixelIdxList;
+                L=map_upper(idx);
+                idx=idx(L);                
+
+                if(~isempty(idx))                    
+                    dtmp=D{k}(idx)+aspect(3)^2*(kk-k)^2;
+    
+                    % these pixels are to be updated with k0+dk
+                    L=D1{kk}(idx)>dtmp & D{kk}(idx)>0;
+                    map_upper(idx)=L;
+                    D1{kk}(idx(L))=dtmp(L);
+                    
+                    dtmp=idx(L); 
+                    dtmp(:)=k;
+                    DK{kk}(idx(L))=dtmp;
+                end
+            end
+            idx_upper=idx_upper(map_upper(idx_upper));
+        else
+            eols=eols-1;
+        end
+    end
+end
+
+% the answer
+if(iscell(bw))
+    D=cell(size(bw));
+    for k=1:shape(3) D{k}=sqrt(D1{k}); end
+else
+    D=zeros(shape);
+    for k=1:shape(3) D(:,:,k)=sqrt(D1{k}); end
+end
+
+
+function s=getregions(map)
+% this function is replacer for regionprops(map,'PixelIdxList');
+% it produces the list of different values along with list of 
+% indexes of pixels in map with these values; 's' is struct-array 
+% such that s(i).PixelIdxList contains list of pixels in map 
+% with value i.
+
+% enable using regionprops if available, faster on 7.3
+fregionprops=1;
+
+% version control for using regionprops
+v=version; v=str2num(v(1:3)); 
+fregionprops=fregionprops & v>=7.3;
+
+% in later matlab regionprops is actually faster than this code
+if(exist('regionprops') & fregionprops)
+    s=regionprops(map,'PixelIdxList');
+    return
+end
+
+idx=(1:prod(size(map)))';
+dtmp=double(map(:));
+
+[dtmp,ind]=sort(dtmp); 
+idx=idx(ind);
+ind=[0;find([diff(dtmp(:));1])];
+
+s=[];
+for i=2:length(ind)
+    if(dtmp(ind(i)))==0 continue; end
+    s(dtmp(ind(i))).PixelIdxList=idx(ind(i-1)+1:ind(i));
 end

+ 78 - 78
WiscPlanPhotonkV125/matlab_frontend/utilities/uifile.m

@@ -1,78 +1,78 @@
-function [varargout] = uifile(mode, varargin)
-%UIFILE Standard get/put dir/file dialog box which remembers last used folder
-% UIFILE is a wrapper for Matlab's UI{GET/PUT}{DIR/FILE} functions with the 
-% ability to remember the last folder opened.  Only successful file
-% selections update the folder remembered.
-%
-% This version saves the last path infomation in system wide temporary folder.
-%
-% Usage:
-%   [...] = uifile('get', ...);
-%   [...] = uifile('put', ...);
-%   [...] = uifile('getdir', ...);
-%   The rest of input and output arguments are the same as MATLAB built-ins.
-%
-% This work is a combination of Chris Cannell's uigetfile2 functions.
-%
-% See also UIGETFILE2, UIGETDIR, UIGETFILE, UIPUTFILE.
-%
-% Written by: Xiaohu Mo
-% xiaohumo@gmail.com
-
-% Argument checking
-if nargin < 1
-    warning('Usage: uifile(''getfile'', ...)');
-    return;
-end
-
-% Name of mat file to save last used directory information
-lastDirMat = fullfile(tempdir, '_matlabLastUsedDir.mat');
-
-% Try load the saved path and set the dir to use
-% default useDir is current path
-useDir = pwd;
-if exist(lastDirMat, 'file')
-    % lastDirMat mat file exists, load it
-    load('-mat', lastDirMat)
-    % check if lastDir variable exists and contains a valid path
-    if exist('lastDir', 'var') && exist(lastDir, 'dir')
-        % set default dialog open directory
-        useDir = lastDir;
-    end
-end
-
-% Save the pwd, cd to useDir, open dialog and change back
-savedPwd = pwd;
-cd(useDir);
-
-% Call uiget/putfile with arguments passed in
-switch lower(mode)
-    case 'get'
-        [varargout{1} varargout{2} varargout{3}] = uigetfile(varargin{1:end});
-    case 'put'
-        [varargout{1} varargout{2} varargout{3}] = uiputfile(varargin{1:end});
-    case 'getdir'
-        [varargout{1}] = uigetdir('', varargin{1:end});
-end
-
-cd(savedPwd);
-
-% If the user did not cancel the file dialog then update lastDirMat
-if ~isequal(varargout{1}, 0)
-    try
-        % save last folder used to lastDirMat mat file
-        switch lower(mode)
-            case 'get'
-                lastDir = varargout{2};
-            case 'put'
-                lastDir = varargout{2};
-            case 'getdir'
-                lastDir = varargout{1};
-        end
-        save(lastDirMat, 'lastDir');
-    catch
-        % error saving lastDirMat mat file
-        % display warning, the folder will not be remembered
-        disp(['Warning: Could not save file ''', lastDirMat, '''']);
-    end
-end
+function [varargout] = uifile(mode, varargin)
+%UIFILE Standard get/put dir/file dialog box which remembers last used folder
+% UIFILE is a wrapper for Matlab's UI{GET/PUT}{DIR/FILE} functions with the 
+% ability to remember the last folder opened.  Only successful file
+% selections update the folder remembered.
+%
+% This version saves the last path infomation in system wide temporary folder.
+%
+% Usage:
+%   [...] = uifile('get', ...);
+%   [...] = uifile('put', ...);
+%   [...] = uifile('getdir', ...);
+%   The rest of input and output arguments are the same as MATLAB built-ins.
+%
+% This work is a combination of Chris Cannell's uigetfile2 functions.
+%
+% See also UIGETFILE2, UIGETDIR, UIGETFILE, UIPUTFILE.
+%
+% Written by: Xiaohu Mo
+% xiaohumo@gmail.com
+
+% Argument checking
+if nargin < 1
+    warning('Usage: uifile(''getfile'', ...)');
+    return;
+end
+
+% Name of mat file to save last used directory information
+lastDirMat = fullfile(tempdir, '_matlabLastUsedDir.mat');
+
+% Try load the saved path and set the dir to use
+% default useDir is current path
+useDir = pwd;
+if exist(lastDirMat, 'file')
+    % lastDirMat mat file exists, load it
+    load('-mat', lastDirMat)
+    % check if lastDir variable exists and contains a valid path
+    if exist('lastDir', 'var') && exist(lastDir, 'dir')
+        % set default dialog open directory
+        useDir = lastDir;
+    end
+end
+
+% Save the pwd, cd to useDir, open dialog and change back
+savedPwd = pwd;
+cd(useDir);
+
+% Call uiget/putfile with arguments passed in
+switch lower(mode)
+    case 'get'
+        [varargout{1} varargout{2} varargout{3}] = uigetfile(varargin{1:end});
+    case 'put'
+        [varargout{1} varargout{2} varargout{3}] = uiputfile(varargin{1:end});
+    case 'getdir'
+        [varargout{1}] = uigetdir('', varargin{1:end});
+end
+
+cd(savedPwd);
+
+% If the user did not cancel the file dialog then update lastDirMat
+if ~isequal(varargout{1}, 0)
+    try
+        % save last folder used to lastDirMat mat file
+        switch lower(mode)
+            case 'get'
+                lastDir = varargout{2};
+            case 'put'
+                lastDir = varargout{2};
+            case 'getdir'
+                lastDir = varargout{1};
+        end
+        save(lastDirMat, 'lastDir');
+    catch
+        % error saving lastDirMat mat file
+        % display warning, the folder will not be remembered
+        disp(['Warning: Could not save file ''', lastDirMat, '''']);
+    end
+end

+ 59 - 59
data_perturbation/get_perturbed_image_beamlets_p1.m

@@ -1,59 +1,59 @@
-%% get_peturbed_image_beamlets
-
-
-
-patientData_path= 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
-load([patientData_path '\matlab_files\Geometry.mat']);
-
-Geometry_old=Geometry;
-clear Geometry
-
-% do the data shift
-shift=[0, 0];
-
-valShift=1.30;
-
-Geometry.data = imtranslate(Geometry_old.data, shift);
-Geometry.rhomw = imtranslate(Geometry_old.rhomw, shift);
-Geometry.Smw = imtranslate(Geometry_old.Smw, shift);
-Geometry.Fmw2 = imtranslate(Geometry_old.Fmw2, shift);
-
-Geometry.BTV = imtranslate(Geometry_old.BTV, shift);
-Geometry.Ring = imtranslate(Geometry_old.Ring, shift);
-
-Geometry.voxel_size = Geometry_old.voxel_size;
-Geometry.start = Geometry_old.start;
-
-
-
-Geometry.data = valShift*Geometry.data;
-Geometry.rhomw = valShift*Geometry.rhomw;
-Geometry.Smw = valShift*Geometry.Smw;
-Geometry.Fmw2 = valShift*Geometry.Fmw2;
-
-
-numROI = size(Geometry_old.ROIS, 2);
-for i=1:numROI
-    ind1 = Geometry_old.ROIS{i}.ind;
-    Geometry.ROIS{i}.name = Geometry_old.ROIS{i}.name;
-    
-    canvas1 = zeros(size(Geometry.data));
-    canvas1(ind1)=1;
-%     canvas2 = imtranslate(canvas1, shift);
-    canvas2 = canvas1;
-    ind2=find(canvas2);
-    Geometry.ROIS{i}.ind = ind2;
-end
-
-
-mkdir([patientData_path '\perturbed_output'])
-mkdir([patientData_path '\perturbed_output\kernelfiles'])
-copyfile([patientData_path '\kernelfiles\*'], [patientData_path '\perturbed_output\kernelfiles\'])
-mkdir([patientData_path '\perturbed_output\matlab_files'])
-
-save([patientData_path '\perturbed_output\matlab_files\Geometry.mat'], 'Geometry')
-
-helicalDosecalcSetup7([patientData_path '\perturbed_output'])
-
-%       merge_beamlets(4, [patientData_path '\perturbed_output']);
-
+%% get_peturbed_image_beamlets
+
+
+
+patientData_path= 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
+load([patientData_path '\matlab_files\Geometry.mat']);
+
+Geometry_old=Geometry;
+clear Geometry
+
+% do the data shift
+shift=[0, 0];
+
+valShift=1.30;
+
+Geometry.data = imtranslate(Geometry_old.data, shift);
+Geometry.rhomw = imtranslate(Geometry_old.rhomw, shift);
+Geometry.Smw = imtranslate(Geometry_old.Smw, shift);
+Geometry.Fmw2 = imtranslate(Geometry_old.Fmw2, shift);
+
+Geometry.BTV = imtranslate(Geometry_old.BTV, shift);
+Geometry.Ring = imtranslate(Geometry_old.Ring, shift);
+
+Geometry.voxel_size = Geometry_old.voxel_size;
+Geometry.start = Geometry_old.start;
+
+
+
+Geometry.data = valShift*Geometry.data;
+Geometry.rhomw = valShift*Geometry.rhomw;
+Geometry.Smw = valShift*Geometry.Smw;
+Geometry.Fmw2 = valShift*Geometry.Fmw2;
+
+
+numROI = size(Geometry_old.ROIS, 2);
+for i=1:numROI
+    ind1 = Geometry_old.ROIS{i}.ind;
+    Geometry.ROIS{i}.name = Geometry_old.ROIS{i}.name;
+    
+    canvas1 = zeros(size(Geometry.data));
+    canvas1(ind1)=1;
+%     canvas2 = imtranslate(canvas1, shift);
+    canvas2 = canvas1;
+    ind2=find(canvas2);
+    Geometry.ROIS{i}.ind = ind2;
+end
+
+
+mkdir([patientData_path '\perturbed_output'])
+mkdir([patientData_path '\perturbed_output\kernelfiles'])
+copyfile([patientData_path '\kernelfiles\*'], [patientData_path '\perturbed_output\kernelfiles\'])
+mkdir([patientData_path '\perturbed_output\matlab_files'])
+
+save([patientData_path '\perturbed_output\matlab_files\Geometry.mat'], 'Geometry')
+
+helicalDosecalcSetup7([patientData_path '\perturbed_output'])
+
+%       merge_beamlets(4, [patientData_path '\perturbed_output']);
+

+ 20 - 20
data_perturbation/get_perturbed_image_beamlets_p2.m

@@ -1,21 +1,21 @@
-
-
-% part 2 of the getting perturbed image 
-
-patientData_path= 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
-
-pertNum='16';
-
-
-merge_beamlets(4, [patientData_path '\perturbed_output']);
-target_filename = [patientData_path '\perturbed_output\batch_dose.bin'];
-
-optResultsFile = [patientData_path, '\matlab_files\optResults.mat'];
-load(optResultsFile);
-D = read_ryan_beamlets([patientData_path '\perturbed_output\batch_dose.bin'],'ryan sum', optResults.weights{end});
-G = Geometry;
-
-save(['C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\dosePert_' pertNum], 'D')
-save(['C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\geomPert_' pertNum], 'G')
-
+
+
+% part 2 of the getting perturbed image 
+
+patientData_path= 'C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
+
+pertNum='16';
+
+
+merge_beamlets(4, [patientData_path '\perturbed_output']);
+target_filename = [patientData_path '\perturbed_output\batch_dose.bin'];
+
+optResultsFile = [patientData_path, '\matlab_files\optResults.mat'];
+load(optResultsFile);
+D = read_ryan_beamlets([patientData_path '\perturbed_output\batch_dose.bin'],'ryan sum', optResults.weights{end});
+G = Geometry;
+
+save(['C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\dosePert_' pertNum], 'D')
+save(['C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\geomPert_' pertNum], 'G')
+
 disp('Perturbed dose saved')

+ 25 - 25
kernels/KERNEL_125_keV/keVoutput/125keVfluence.txt

@@ -1,25 +1,25 @@
-0.005	1.51E-41
-0.010	0.00000117
-0.015	0.00142179
-0.020	0.02004572
-0.025	0.05654530
-0.030	0.08460363
-0.035	0.09667544
-0.040	0.09723721
-0.045	0.09135274
-0.050	0.08324671
-0.055	0.07423294
-0.060	0.09943653
-0.065	0.05839717
-0.070	0.05929673
-0.075	0.03536751
-0.080	0.03107692
-0.085	0.02673942
-0.090	0.02298204
-0.095	0.01901299
-0.100	0.01535332
-0.105	0.01174819
-0.110	0.00843499
-0.115	0.00500424
-0.120	0.00178729
-0.125	1E-41
+0.005	1.51E-41
+0.010	0.00000117
+0.015	0.00142179
+0.020	0.02004572
+0.025	0.05654530
+0.030	0.08460363
+0.035	0.09667544
+0.040	0.09723721
+0.045	0.09135274
+0.050	0.08324671
+0.055	0.07423294
+0.060	0.09943653
+0.065	0.05839717
+0.070	0.05929673
+0.075	0.03536751
+0.080	0.03107692
+0.085	0.02673942
+0.090	0.02298204
+0.095	0.01901299
+0.100	0.01535332
+0.105	0.01174819
+0.110	0.00843499
+0.115	0.00500424
+0.120	0.00178729
+0.125	1E-41

+ 27 - 27
kernels/KERNEL_125_keV/keVoutput/125keVmu_mu-en.txt

@@ -1,27 +1,27 @@
-0.005	42.6950 42.01649
-0.010	5.38860	5.001020
-0.015	1.71270	1.406159
-0.020	0.83902	0.569500
-0.025	0.53004	0.283365
-0.030	0.39241	0.162182
-0.035	0.32069	0.103281
-0.040	0.27900	0.071999
-0.045	0.25242	0.054132
-0.050	0.23431	0.043456
-0.055	0.22118	0.036819
-0.060	0.21123	0.032609
-0.065	0.20335	0.029890
-0.070	0.19692	0.028139
-0.075	0.19151	0.027016
-0.080	0.18685	0.026319
-0.085	0.18276	0.025916
-0.090	0.17912	0.025713
-0.095	0.17583	0.025649
-0.100	0.17283	0.025685
-0.105	0.17006	0.025793
-0.110	0.16748	0.025945
-0.115	0.16508	0.026135
-0.120	0.16282	0.026346
-0.125	0.16069	0.026571
-
-
+0.005	42.6950 42.01649
+0.010	5.38860	5.001020
+0.015	1.71270	1.406159
+0.020	0.83902	0.569500
+0.025	0.53004	0.283365
+0.030	0.39241	0.162182
+0.035	0.32069	0.103281
+0.040	0.27900	0.071999
+0.045	0.25242	0.054132
+0.050	0.23431	0.043456
+0.055	0.22118	0.036819
+0.060	0.21123	0.032609
+0.065	0.20335	0.029890
+0.070	0.19692	0.028139
+0.075	0.19151	0.027016
+0.080	0.18685	0.026319
+0.085	0.18276	0.025916
+0.090	0.17912	0.025713
+0.095	0.17583	0.025649
+0.100	0.17283	0.025685
+0.105	0.17006	0.025793
+0.110	0.16748	0.025945
+0.115	0.16508	0.026135
+0.120	0.16282	0.026346
+0.125	0.16069	0.026571
+
+

+ 51 - 51
kernels/KERNEL_125_keV/keVoutput/GenerateKernelFile125New.m

@@ -1,51 +1,51 @@
-% Surendra Prajapati 2014
-% This code  creates kernel provided the EGS output file --> "... .KeV" 
-% and provided text files that provides fluence(spectrum of source), mu/rho and mu-en/rho
-
-
-close all;
-clear all;
-
-cd('E:\UW MADISON\Wisc Fall 2014\Kernels for 125keV and 250 keV\KERNEL_125_keV\keVoutput')
-
-rad= [0.01,0.03,0.05,0.08,0.11,0.15,0.2,0.3,0.4,0.6,0.8,1.1,1.5,2.0,3.0,4.0,6.0,8.0,10.0,15.0,20.0,30.0,45.0,60.0];
-ang = [3.75:3.75:180];
-energyarr = [5:5:125];
-Kernels.radii = rad;
-Kernels.angles = ang;
-Kernels.energies = energyarr/1000;
-
-for count = 1:length(energyarr)
-    str = strcat(num2str(energyarr(count)),'keV_XCOM_HighRes.keV');
-    %C(count) = texscan(str,'%f %f');
-    [val stdev] = textread(str, '%f %f');
-    Data(:,:,:,count) = reshape(val,5,24,48);
-end
-
-for count = 1:5
-    k = Data(count,:,:,:);
-    temp(:,:,:,count) = reshape(k,24,48,length(energyarr));
-end
-
-Kernels.primary = temp(:,:,:,1);
-Kernels.first_scatter = temp(:,:,:,2);
-Kernels.second_scatter = temp(:,:,:,3);
-Kernels.multiple_scatter = temp(:,:,:,4);
-Kernels.brem_annih = temp(:,:,:,5);
-Kernels.total = Kernels.primary + Kernels.first_scatter + Kernels.second_scatter + Kernels.multiple_scatter + Kernels.brem_annih;
-
-
-A = textread('125keVfluence.txt');
-B = textread('125keVmu_mu-en.txt');
-
-Kernels.fluence = A(:,2)';
-Kernels.mu = B(:,2)';
-Kernels.mu_en = B(:,3)';
-
-save Kernels.mat
-
-% for count = 1:5
-%     k = test_data(count,:,:,:);
-%     temp(:,:,:,count) = reshape(k,24,48,length(energyarr));
-% end
-
+% Surendra Prajapati 2014
+% This code  creates kernel provided the EGS output file --> "... .KeV" 
+% and provided text files that provides fluence(spectrum of source), mu/rho and mu-en/rho
+
+
+close all;
+clear all;
+
+cd('E:\UW MADISON\Wisc Fall 2014\Kernels for 125keV and 250 keV\KERNEL_125_keV\keVoutput')
+
+rad= [0.01,0.03,0.05,0.08,0.11,0.15,0.2,0.3,0.4,0.6,0.8,1.1,1.5,2.0,3.0,4.0,6.0,8.0,10.0,15.0,20.0,30.0,45.0,60.0];
+ang = [3.75:3.75:180];
+energyarr = [5:5:125];
+Kernels.radii = rad;
+Kernels.angles = ang;
+Kernels.energies = energyarr/1000;
+
+for count = 1:length(energyarr)
+    str = strcat(num2str(energyarr(count)),'keV_XCOM_HighRes.keV');
+    %C(count) = texscan(str,'%f %f');
+    [val stdev] = textread(str, '%f %f');
+    Data(:,:,:,count) = reshape(val,5,24,48);
+end
+
+for count = 1:5
+    k = Data(count,:,:,:);
+    temp(:,:,:,count) = reshape(k,24,48,length(energyarr));
+end
+
+Kernels.primary = temp(:,:,:,1);
+Kernels.first_scatter = temp(:,:,:,2);
+Kernels.second_scatter = temp(:,:,:,3);
+Kernels.multiple_scatter = temp(:,:,:,4);
+Kernels.brem_annih = temp(:,:,:,5);
+Kernels.total = Kernels.primary + Kernels.first_scatter + Kernels.second_scatter + Kernels.multiple_scatter + Kernels.brem_annih;
+
+
+A = textread('125keVfluence.txt');
+B = textread('125keVmu_mu-en.txt');
+
+Kernels.fluence = A(:,2)';
+Kernels.mu = B(:,2)';
+Kernels.mu_en = B(:,3)';
+
+save Kernels.mat
+
+% for count = 1:5
+%     k = test_data(count,:,:,:);
+%     temp(:,:,:,count) = reshape(k,24,48,length(energyarr));
+% end
+

+ 17 - 17
optGoals/get_ROI_goals.m

@@ -1,17 +1,17 @@
-
-
-
-function [optGoal, optGoal_beam, optGoal_idx, targetMinMax_idx] = get_ROI_goals(patient)
-% this is a support function for NLP_beamlet_optimizer. It returns the
-% goals planned for specific patients
-
-% load(['C:\010-work\003_localGit\WiscPlan_v2\optGoals\' patient, '.mat']);
-
-load(['\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed\RODP_files\optGoal.mat']);
-
-optGoal = ROI_goals.optGoal;
-optGoal_beam = ROI_goals.optGoal_beam;
-optGoal_idx = ROI_goals.optGoal_idx;
-targetMinMax_idx = ROI_goals.targetMinMax_idx;
-
-end
+
+
+
+function [optGoal, optGoal_beam, optGoal_idx, targetMinMax_idx] = get_ROI_goals(patient)
+% this is a support function for NLP_beamlet_optimizer. It returns the
+% goals planned for specific patients
+
+% load(['C:\010-work\003_localGit\WiscPlan_v2\optGoals\' patient, '.mat']);
+
+load(['\\Mpufs5\data_wnx1\_Data\Glioma_aus\FET_FGL005\B1\Processed\RODP_files\optGoal.mat']);
+
+optGoal = ROI_goals.optGoal;
+optGoal_beam = ROI_goals.optGoal_beam;
+optGoal_idx = ROI_goals.optGoal_idx;
+targetMinMax_idx = ROI_goals.targetMinMax_idx;
+
+end

+ 57 - 57
planEvaluation/Compare_optPlans.m

@@ -1,58 +1,58 @@
-
-
-function Compare_optPlans
-    
-    resultPath = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009\matlab_files\';
-    load([resultPath 'Geometry.mat'])
-    
-    roi_idx = 1;
-    nfrac = 1;
-    
-    load([resultPath 'optResults_backup_Dumb.mat'])
-    dose_WP = optResults.dose{end};
-    [dvh_TP dosebins_TP] = dvhist(dose_WP,Geometry,roi_idx,nfrac);
-    [dvh_TP_head dosebins_TP_head] = dvhist(dose_WP,Geometry,2,nfrac);
-    
-    load([resultPath 'NLP_result_backup_Dumb.mat'])
-    dose_NLP_1 = NLP_result.dose;
-    [dvh_NLP_1 dosebins_NLP_1] = dvhist(dose_NLP_1,Geometry,roi_idx,nfrac);
-    [dvh_NLP_head_1 dosebins_NLP_head_1] = dvhist(dose_NLP_1,Geometry,2,nfrac);
-    
-    load([resultPath 'NLP_result_backup_prob.mat'])
-%     load([resultPath 'NLP_result.mat'])
-    dose_NLP_2 = NLP_result.dose;
-    [dvh_NLP_2 dosebins_NLP_2] = dvhist(dose_NLP_2,Geometry,roi_idx,nfrac);
-    [dvh_NLP_head_2 dosebins_NLP_head_2] = dvhist(dose_NLP_2,Geometry,2,nfrac);
-    
-    load([resultPath 'NLP_result_backup_DP.mat'])
-    dose_NLP_3 = NLP_result.dose;
-    [dvh_NLP_3 dosebins_NLP_3] = dvhist(dose_NLP_3,Geometry,roi_idx,nfrac);
-    [dvh_NLP_head_3 dosebins_NLP_head_3] = dvhist(dose_NLP_3,Geometry,2,nfrac);
-    
-    figure
-    hold on
-%     plot(dosebins_TP, dvh_TP,'Color', [0.9,0.2,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
-%     plot(dosebins_NLP_1, dvh_NLP_1,'Color', [0.9,0.2,0.2],'LineStyle', '-','DisplayName', Geometry.ROIS{roi_idx}.name);
-%     plot(dosebins_NLP_2, dvh_NLP_2,'Color', [0.9,0.2,0.2],'LineStyle', '-.','DisplayName', Geometry.ROIS{roi_idx}.name);
-    plot(dosebins_NLP_3, dvh_NLP_3,'Color', [0.9,0.2,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
-    
-%     plot(dosebins_TP_head, dvh_TP_head,'Color', [0.2,0.9,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
-%     plot(dosebins_NLP_head_1, dvh_NLP_head_1,'Color', [0.2,0.9,0.2],'LineStyle', '-','DisplayName', Geometry.ROIS{roi_idx}.name);
-%     plot(dosebins_NLP_head_2, dvh_NLP_head_2,'Color', [0.5,0.9,0.2],'LineStyle', '-.','DisplayName', Geometry.ROIS{roi_idx}.name);
-    plot(dosebins_NLP_head_3, dvh_NLP_head_3,'Color', [0.5,0.9,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
-    
-    hold off
-%     legend('DP target', 'DP head')
-%     legend('Robust target', 'Robust head')
-%     legend('Prob. target', 'DP target', 'Prob. head', 'DP head')
-%     legend('TP target', 'Robust target', 'TP head', 'Robust head')
-%     legend('Robust target', 'Prob. target', 'Robust head', 'Prob. head')
-    legend('Prob. target', 'DP target', 'Prob. head', 'DP head')
-
-    axis([0 100 0 100])
-    xlabel('Dose', 'Color','w')
-    ylabel('Volume', 'Color','w')
-end
-
-% set(gca,'Color','k') % plot background black
+
+
+function Compare_optPlans
+    
+    resultPath = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_Avastin009\matlab_files\';
+    load([resultPath 'Geometry.mat'])
+    
+    roi_idx = 1;
+    nfrac = 1;
+    
+    load([resultPath 'optResults_backup_Dumb.mat'])
+    dose_WP = optResults.dose{end};
+    [dvh_TP dosebins_TP] = dvhist(dose_WP,Geometry,roi_idx,nfrac);
+    [dvh_TP_head dosebins_TP_head] = dvhist(dose_WP,Geometry,2,nfrac);
+    
+    load([resultPath 'NLP_result_backup_Dumb.mat'])
+    dose_NLP_1 = NLP_result.dose;
+    [dvh_NLP_1 dosebins_NLP_1] = dvhist(dose_NLP_1,Geometry,roi_idx,nfrac);
+    [dvh_NLP_head_1 dosebins_NLP_head_1] = dvhist(dose_NLP_1,Geometry,2,nfrac);
+    
+    load([resultPath 'NLP_result_backup_prob.mat'])
+%     load([resultPath 'NLP_result.mat'])
+    dose_NLP_2 = NLP_result.dose;
+    [dvh_NLP_2 dosebins_NLP_2] = dvhist(dose_NLP_2,Geometry,roi_idx,nfrac);
+    [dvh_NLP_head_2 dosebins_NLP_head_2] = dvhist(dose_NLP_2,Geometry,2,nfrac);
+    
+    load([resultPath 'NLP_result_backup_DP.mat'])
+    dose_NLP_3 = NLP_result.dose;
+    [dvh_NLP_3 dosebins_NLP_3] = dvhist(dose_NLP_3,Geometry,roi_idx,nfrac);
+    [dvh_NLP_head_3 dosebins_NLP_head_3] = dvhist(dose_NLP_3,Geometry,2,nfrac);
+    
+    figure
+    hold on
+%     plot(dosebins_TP, dvh_TP,'Color', [0.9,0.2,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
+%     plot(dosebins_NLP_1, dvh_NLP_1,'Color', [0.9,0.2,0.2],'LineStyle', '-','DisplayName', Geometry.ROIS{roi_idx}.name);
+%     plot(dosebins_NLP_2, dvh_NLP_2,'Color', [0.9,0.2,0.2],'LineStyle', '-.','DisplayName', Geometry.ROIS{roi_idx}.name);
+    plot(dosebins_NLP_3, dvh_NLP_3,'Color', [0.9,0.2,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
+    
+%     plot(dosebins_TP_head, dvh_TP_head,'Color', [0.2,0.9,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
+%     plot(dosebins_NLP_head_1, dvh_NLP_head_1,'Color', [0.2,0.9,0.2],'LineStyle', '-','DisplayName', Geometry.ROIS{roi_idx}.name);
+%     plot(dosebins_NLP_head_2, dvh_NLP_head_2,'Color', [0.5,0.9,0.2],'LineStyle', '-.','DisplayName', Geometry.ROIS{roi_idx}.name);
+    plot(dosebins_NLP_head_3, dvh_NLP_head_3,'Color', [0.5,0.9,0.2],'LineStyle', '--','DisplayName', Geometry.ROIS{roi_idx}.name);
+    
+    hold off
+%     legend('DP target', 'DP head')
+%     legend('Robust target', 'Robust head')
+%     legend('Prob. target', 'DP target', 'Prob. head', 'DP head')
+%     legend('TP target', 'Robust target', 'TP head', 'Robust head')
+%     legend('Robust target', 'Prob. target', 'Robust head', 'Prob. head')
+    legend('Prob. target', 'DP target', 'Prob. head', 'DP head')
+
+    axis([0 100 0 100])
+    xlabel('Dose', 'Color','w')
+    ylabel('Volume', 'Color','w')
+end
+
+% set(gca,'Color','k') % plot background black
 % whitebg('k')

+ 24 - 24
planEvaluation/compare_RO_norm_DVH_colorwash.m

@@ -1,25 +1,25 @@
-
-
-% [D_full, w_fin, Geometry, optGoal] = NLP_beamlet_optimizer;
-
-function compare_RO_norm_DVH_colorwash(D_full)
-
-% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\';
-% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\Tomo_Phantom\';
-% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData_dog5_3\';
-% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData_ozzy1';
-path_in = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam';
-
-
-
-
-load([path_in '\matlab_files\optResults.mat'])
-D_norm = optResults.dose{end};
-
-orthoslice(D_full-D_norm, [-30, 30])
-
-% orthoslice(D_full, [0,70])
-% colorwash(Geometry.data, D_full, [500, 1500], [0,80])
-% colorwash(Geometry.data, D_norm, [500, 1500], [0,80])
-
+
+
+% [D_full, w_fin, Geometry, optGoal] = NLP_beamlet_optimizer;
+
+function compare_RO_norm_DVH_colorwash(D_full)
+
+% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData\';
+% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\Tomo_Phantom\';
+% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData_dog5_3\';
+% path_in='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData_ozzy1';
+path_in = 'C:\010-work\003_localGit\WiscPlan_v2\data\PatData_ausGli_005_16beam';
+
+
+
+
+load([path_in '\matlab_files\optResults.mat'])
+D_norm = optResults.dose{end};
+
+orthoslice(D_full-D_norm, [-30, 30])
+
+% orthoslice(D_full, [0,70])
+% colorwash(Geometry.data, D_full, [500, 1500], [0,80])
+% colorwash(Geometry.data, D_norm, [500, 1500], [0,80])
+
 end

+ 112 - 112
planEvaluation/error_DVHs.m

@@ -1,112 +1,112 @@
-
-close all
-
-pat_path='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
-
-% geometry
-load([pat_path '\matlab_files\Geometry.mat'])
-load([pat_path '\matlab_files\optResults.mat'])
-
-
-CTin=Geometry.data;
-dose_01 = optResults.dose{end};
-% colorwash(CTin, dose_01, [-500, 500], [0,60])
-
-
-
-
-%% Get the original image DVH
-roi_idx = 1;
-color_01 = [0.9,0.1,0.1];
-
-
-ROI_01 = logical(zeros(size(CTin)));
-ROI_01(Geometry.ROIS{1, roi_idx}.ind) = 1;
-%     orthoslice(ROI, [0,1])
-
-%% get the DVH for a shifted image (but no corrections)
-% Shift up
-color_10 = [0.9,0.1,0.9];
-for plotIdx =1:8;
-    
-    shiftAngleList= [0, pi/2, pi, 1.5*pi];
-    shiftAngle = shiftAngleList(1);
-    
-    shiftmag = 0.25 *plotIdx;
-
-    shift = shiftmag * [cos(shiftAngle), sin(shiftAngle)];
-
-    dose_s1 = imtranslate(dose_01, shift, 'FillValues', 0);
-    [dvh_10{plotIdx}, dosebins_10{plotIdx}] = dvhist(dose_s1, ROI_01);
-
-end
-% colorwash(CTin, dose_s1, [-500, 500], [0,60])
-
-
-color_11 = [0.5,0.2,0.3];
-for plotIdx=1:10;
-    shiftmag = 1;
-    shiftAngle= 2*pi*rand();
-
-    shift = shiftmag*rand() * [cos(shiftAngle), sin(shiftAngle)];
-    
-    dose_s1 = imtranslate(dose_01, shift, 'FillValues', 0);
-    [dvh_11{plotIdx}, dosebins_11{plotIdx}] = dvhist(dose_s1, ROI_01);
-end
-
-%% get DVH for shifted CT images
-color_20 = [0.5,0.2,0.8];
-load('dosePert_01.mat')
-[dvh_20{1}, dosebins_20{1}] = dvhist(D, ROI_01);
-load('dosePert_02.mat')
-[dvh_20{2}, dosebins_20{2}] = dvhist(D, ROI_01);
-load('dosePert_03.mat')
-[dvh_20{3}, dosebins_20{3}] = dvhist(D, ROI_01);
-load('dosePert_04.mat')
-[dvh_20{4}, dosebins_20{4}] = dvhist(D, ROI_01);
-
-%% get DVH for shifted CT images
-color_30 = [0.2,0.9,0.2];
-load('dosePert_11.mat')
-[dvh_30{1}, dosebins_30{1}] = dvhist(D, ROI_01);
-load('dosePert_12.mat')
-[dvh_30{2}, dosebins_30{2}] = dvhist(D, ROI_01);
-load('dosePert_13.mat')
-[dvh_30{3}, dosebins_30{3}] = dvhist(D, ROI_01);
-load('dosePert_14.mat')
-[dvh_30{4}, dosebins_30{4}] = dvhist(D, ROI_01);
-load('dosePert_15.mat')
-[dvh_30{5}, dosebins_30{5}] = dvhist(D, ROI_01);
-load('dosePert_16.mat')
-[dvh_30{6}, dosebins_30{6}] = dvhist(D, ROI_01);
-
-%%      Plot stuff
-% colorwash(CTin, D, [-500, 500], [0,60])
-
-%       original image
-[dvh_01, dosebins_01] = dvhist(dose_01, ROI_01);
-figure
-hold on
-% %    ---- shifted dose
-for i=1:size(dosebins_10,2)
-plot(dosebins_10{i}, dvh_10{i}, 'Color', color_10 , 'LineStyle', '--', 'DisplayName', 'test');
-end
-
-for i=1:size(dosebins_11,2)
-plot(dosebins_11{i}, dvh_11{i}, 'Color', color_11 , 'LineStyle', '--', 'DisplayName', 'test');
-end
-
-for i=1:4
-plot(dosebins_20{i}, dvh_20{i}, 'Color', color_20 , 'LineStyle', '--', 'DisplayName', 'test');
-end
-% 
-% for i=1:6
-% plot(dosebins_30{i}, dvh_30{i}, 'Color', color_30 , 'LineStyle', '--', 'DisplayName', 'test');
-% end
-
-plot(dosebins_01, dvh_01, 'Color', color_01 , 'LineStyle', '-', 'DisplayName', 'test');
-hold off
-
-xlabel('Dose (Gy)')
-ylabel('Volume (%)')
-
+
+close all
+
+pat_path='C:\010-work\003_localGit\WiscPlan_v2\data\PatientData';
+
+% geometry
+load([pat_path '\matlab_files\Geometry.mat'])
+load([pat_path '\matlab_files\optResults.mat'])
+
+
+CTin=Geometry.data;
+dose_01 = optResults.dose{end};
+% colorwash(CTin, dose_01, [-500, 500], [0,60])
+
+
+
+
+%% Get the original image DVH
+roi_idx = 1;
+color_01 = [0.9,0.1,0.1];
+
+
+ROI_01 = logical(zeros(size(CTin)));
+ROI_01(Geometry.ROIS{1, roi_idx}.ind) = 1;
+%     orthoslice(ROI, [0,1])
+
+%% get the DVH for a shifted image (but no corrections)
+% Shift up
+color_10 = [0.9,0.1,0.9];
+for plotIdx =1:8;
+    
+    shiftAngleList= [0, pi/2, pi, 1.5*pi];
+    shiftAngle = shiftAngleList(1);
+    
+    shiftmag = 0.25 *plotIdx;
+
+    shift = shiftmag * [cos(shiftAngle), sin(shiftAngle)];
+
+    dose_s1 = imtranslate(dose_01, shift, 'FillValues', 0);
+    [dvh_10{plotIdx}, dosebins_10{plotIdx}] = dvhist(dose_s1, ROI_01);
+
+end
+% colorwash(CTin, dose_s1, [-500, 500], [0,60])
+
+
+color_11 = [0.5,0.2,0.3];
+for plotIdx=1:10;
+    shiftmag = 1;
+    shiftAngle= 2*pi*rand();
+
+    shift = shiftmag*rand() * [cos(shiftAngle), sin(shiftAngle)];
+    
+    dose_s1 = imtranslate(dose_01, shift, 'FillValues', 0);
+    [dvh_11{plotIdx}, dosebins_11{plotIdx}] = dvhist(dose_s1, ROI_01);
+end
+
+%% get DVH for shifted CT images
+color_20 = [0.5,0.2,0.8];
+load('dosePert_01.mat')
+[dvh_20{1}, dosebins_20{1}] = dvhist(D, ROI_01);
+load('dosePert_02.mat')
+[dvh_20{2}, dosebins_20{2}] = dvhist(D, ROI_01);
+load('dosePert_03.mat')
+[dvh_20{3}, dosebins_20{3}] = dvhist(D, ROI_01);
+load('dosePert_04.mat')
+[dvh_20{4}, dosebins_20{4}] = dvhist(D, ROI_01);
+
+%% get DVH for shifted CT images
+color_30 = [0.2,0.9,0.2];
+load('dosePert_11.mat')
+[dvh_30{1}, dosebins_30{1}] = dvhist(D, ROI_01);
+load('dosePert_12.mat')
+[dvh_30{2}, dosebins_30{2}] = dvhist(D, ROI_01);
+load('dosePert_13.mat')
+[dvh_30{3}, dosebins_30{3}] = dvhist(D, ROI_01);
+load('dosePert_14.mat')
+[dvh_30{4}, dosebins_30{4}] = dvhist(D, ROI_01);
+load('dosePert_15.mat')
+[dvh_30{5}, dosebins_30{5}] = dvhist(D, ROI_01);
+load('dosePert_16.mat')
+[dvh_30{6}, dosebins_30{6}] = dvhist(D, ROI_01);
+
+%%      Plot stuff
+% colorwash(CTin, D, [-500, 500], [0,60])
+
+%       original image
+[dvh_01, dosebins_01] = dvhist(dose_01, ROI_01);
+figure
+hold on
+% %    ---- shifted dose
+for i=1:size(dosebins_10,2)
+plot(dosebins_10{i}, dvh_10{i}, 'Color', color_10 , 'LineStyle', '--', 'DisplayName', 'test');
+end
+
+for i=1:size(dosebins_11,2)
+plot(dosebins_11{i}, dvh_11{i}, 'Color', color_11 , 'LineStyle', '--', 'DisplayName', 'test');
+end
+
+for i=1:4
+plot(dosebins_20{i}, dvh_20{i}, 'Color', color_20 , 'LineStyle', '--', 'DisplayName', 'test');
+end
+% 
+% for i=1:6
+% plot(dosebins_30{i}, dvh_30{i}, 'Color', color_30 , 'LineStyle', '--', 'DisplayName', 'test');
+% end
+
+plot(dosebins_01, dvh_01, 'Color', color_01 , 'LineStyle', '-', 'DisplayName', 'test');
+hold off
+
+xlabel('Dose (Gy)')
+ylabel('Volume (%)')
+

+ 67 - 67
planEvaluation/plot_DVH.m

@@ -1,68 +1,68 @@
-% ---- DVH PLOT FUNCTION ----
-function plot_DVH(Geometry, dose)
-    % this function plots the DVHs of the given dose
-    
-    nfrac=1;
-    
-    
-    colorList = jet(numel(Geometry.ROIS));
-    names = {};
-    
-    figure
-    hold on
-    for roi_idx= 1:numel(Geometry.ROIS);
-        % plot the histogram
-        
-        [dvh dosebins] = get_dvh_data(dose, Geometry.ROIS{roi_idx}.ind, nfrac);
-        plot(dosebins, dvh,'Color', colorList(roi_idx, :),'LineStyle', '-','DisplayName', Geometry.ROIS{roi_idx}.name);
-        names{roi_idx} = Geometry.ROIS{roi_idx}.name;
-    end
-    hold off
-    % get % of volume above/below threshold
-%     num_vox = numel(optGoal{targetMinMax_idx(1)}.target);
-%     perc_vox_min = 100* numel(find((dose(optGoal{targetMinMax_idx(1)}.ROI_idx) - optGoal{targetMinMax_idx(1)}.target*0.95) <0)) ...
-%         / num_vox;
-%     perc_vox_max = 100* numel(find((dose(optGoal{targetMinMax_idx(2)}.ROI_idx) - optGoal{targetMinMax_idx(2)}.target*1.07) >0)) ...
-%         / num_vox;
-    title(['NLP optimized DVH'])
-    legend(names)
-    axis([0 110 0 100])
-end
-function plot_DVH_robust(dose, optGoal, optGoal_idx)
-    % this function plots the DVHs of the given dose
-    nfrac=1;
-    
-    figure
-    hold on
-    for goal_i=optGoal_idx
-        % for all the perturbations
-        for nrs_i = 1:optGoal{1}.NbrRandScenarios 
-            for sss_i = 1:optGoal{1}.NbrSystSetUpScenarios % syst. setup scenarios = ss
-                for rrs_i = 1:optGoal{1}.NbrRangeScenarios % range scenario = rs
-                    % plot the histogram
-                    ROI_idx = optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rrs{rrs_i}.ROI_idx;
-                    
-                    [dvh dosebins] = get_dvh_data(dose,ROI_idx,nfrac);
-                    plot(dosebins, dvh,'Color', optGoal{goal_i}.dvh_col,'LineStyle', '-','DisplayName', optGoal{goal_i}.ROI_name);
-                end
-            end
-        end
-    end
-    hold off
-    
-end
-function [dvh dosebins] = get_dvh_data(dose,roi_idx,nfrac);
-    % this function calculates the data for the DVH
-    dosevec = dose(roi_idx);
-    
-    
-    [pdf dosebins] = hist(dosevec, 999);
-    % clip negative bins
-    pdf = pdf(dosebins >= 0);
-    dosebins = dosebins(dosebins >= 0);
-    dvh = fliplr(cumsum(fliplr(pdf))) / numel(dosevec) * 100;
-    % append the last bin
-    dosebins = [dosebins dosebins(end)+0.1];
-    dvh = [dvh 0];
-    
+% ---- DVH PLOT FUNCTION ----
+function plot_DVH(Geometry, dose)
+    % this function plots the DVHs of the given dose
+    
+    nfrac=1;
+    
+    
+    colorList = jet(numel(Geometry.ROIS));
+    names = {};
+    
+    figure
+    hold on
+    for roi_idx= 1:numel(Geometry.ROIS);
+        % plot the histogram
+        
+        [dvh dosebins] = get_dvh_data(dose, Geometry.ROIS{roi_idx}.ind, nfrac);
+        plot(dosebins, dvh,'Color', colorList(roi_idx, :),'LineStyle', '-','DisplayName', Geometry.ROIS{roi_idx}.name);
+        names{roi_idx} = Geometry.ROIS{roi_idx}.name;
+    end
+    hold off
+    % get % of volume above/below threshold
+%     num_vox = numel(optGoal{targetMinMax_idx(1)}.target);
+%     perc_vox_min = 100* numel(find((dose(optGoal{targetMinMax_idx(1)}.ROI_idx) - optGoal{targetMinMax_idx(1)}.target*0.95) <0)) ...
+%         / num_vox;
+%     perc_vox_max = 100* numel(find((dose(optGoal{targetMinMax_idx(2)}.ROI_idx) - optGoal{targetMinMax_idx(2)}.target*1.07) >0)) ...
+%         / num_vox;
+    title(['NLP optimized DVH'])
+    legend(names)
+    axis([0 110 0 100])
+end
+function plot_DVH_robust(dose, optGoal, optGoal_idx)
+    % this function plots the DVHs of the given dose
+    nfrac=1;
+    
+    figure
+    hold on
+    for goal_i=optGoal_idx
+        % for all the perturbations
+        for nrs_i = 1:optGoal{1}.NbrRandScenarios 
+            for sss_i = 1:optGoal{1}.NbrSystSetUpScenarios % syst. setup scenarios = ss
+                for rrs_i = 1:optGoal{1}.NbrRangeScenarios % range scenario = rs
+                    % plot the histogram
+                    ROI_idx = optGoal{goal_i}.nrs{nrs_i}.sss{sss_i}.rrs{rrs_i}.ROI_idx;
+                    
+                    [dvh dosebins] = get_dvh_data(dose,ROI_idx,nfrac);
+                    plot(dosebins, dvh,'Color', optGoal{goal_i}.dvh_col,'LineStyle', '-','DisplayName', optGoal{goal_i}.ROI_name);
+                end
+            end
+        end
+    end
+    hold off
+    
+end
+function [dvh dosebins] = get_dvh_data(dose,roi_idx,nfrac);
+    % this function calculates the data for the DVH
+    dosevec = dose(roi_idx);
+    
+    
+    [pdf dosebins] = hist(dosevec, 999);
+    % clip negative bins
+    pdf = pdf(dosebins >= 0);
+    dosebins = dosebins(dosebins >= 0);
+    dvh = fliplr(cumsum(fliplr(pdf))) / numel(dosevec) * 100;
+    % append the last bin
+    dosebins = [dosebins dosebins(end)+0.1];
+    dvh = [dvh 0];
+    
 end

+ 26 - 26
readEDKoutputMuNew.m

@@ -1,27 +1,27 @@
-% Surendra Prajapati 2014
-% This code extracts the mu/rho (attenuation coefficeint) from the EGS output file --> "... .lst" 
-% remember the "linenum" may change, so double check that
-
-
-close all;
-clear all;
-
-cd('E:\UW MADISON\Wisc Fall 2014\Kernels-revised_9-24-2014\EDKnrcOutputFiles-After09242014')
-
-energyarr = [5:5:250];
-
-for count = 1:length(energyarr)
-        fname = strcat(num2str(energyarr(count)),'keV_XCOM_HighRes.egslst');
-        fid = fopen(fname);
-        linenum = 185;
-        data = textscan(fid, '%s', 1, 'delimiter', '\n', 'headerlines', linenum-1);
-     
-        data2 = data{1};
-        data3 = cell2mat(data2);
-        data3 = data3(33:42);
-        attcoef(count) = str2num(data3);
-        
-        fclose(fid);  
-end
-
+% Surendra Prajapati 2014
+% This code extracts the mu/rho (attenuation coefficeint) from the EGS output file --> "... .lst" 
+% remember the "linenum" may change, so double check that
+
+
+close all;
+clear all;
+
+cd('E:\UW MADISON\Wisc Fall 2014\Kernels-revised_9-24-2014\EDKnrcOutputFiles-After09242014')
+
+energyarr = [5:5:250];
+
+for count = 1:length(energyarr)
+        fname = strcat(num2str(energyarr(count)),'keV_XCOM_HighRes.egslst');
+        fid = fopen(fname);
+        linenum = 185;
+        data = textscan(fid, '%s', 1, 'delimiter', '\n', 'headerlines', linenum-1);
+     
+        data2 = data{1};
+        data3 = cell2mat(data2);
+        data3 = data3(33:42);
+        attcoef(count) = str2num(data3);
+        
+        fclose(fid);  
+end
+
 attcoef = attcoef';

+ 27 - 27
readEDKoutputPriFracNew.m

@@ -1,28 +1,28 @@
-% Surendra Prajapati 2014
-% This code extracts the primary fraction from the EGS output file --> "... .lst" 
-% remember the "linenum" may change, so double check that
-% note: mu-en/rho = mu/rho x primary fraction 
-%
-
-close all;
-clear all;
-
-cd('E:\UW MADISON\Wisc Fall 2014\Kernels-revised_9-24-2014\EDKnrcOutputFiles-After09242014')
-
-energyarr = [5:5:250];
-
-for count = 1:length(energyarr)
-        fname = strcat(num2str(energyarr(count)),'keV_XCOM_HighRes.egslst');
-        fid = fopen(fname);
-        linenum = 230;
-        data = textscan(fid, '%s', 1, 'delimiter', '\n', 'headerlines', linenum-1);
-     
-        data2 = data{1};
-        data3 = cell2mat(data2);
-        data3 = data3(26:33);
-        PriFrac(count) = str2num(data3);
-       
-        fclose(fid);  
-end
-
+% Surendra Prajapati 2014
+% This code extracts the primary fraction from the EGS output file --> "... .lst" 
+% remember the "linenum" may change, so double check that
+% note: mu-en/rho = mu/rho x primary fraction 
+%
+
+close all;
+clear all;
+
+cd('E:\UW MADISON\Wisc Fall 2014\Kernels-revised_9-24-2014\EDKnrcOutputFiles-After09242014')
+
+energyarr = [5:5:250];
+
+for count = 1:length(energyarr)
+        fname = strcat(num2str(energyarr(count)),'keV_XCOM_HighRes.egslst');
+        fid = fopen(fname);
+        linenum = 230;
+        data = textscan(fid, '%s', 1, 'delimiter', '\n', 'headerlines', linenum-1);
+     
+        data2 = data{1};
+        data3 = cell2mat(data2);
+        data3 = data3(26:33);
+        PriFrac(count) = str2num(data3);
+       
+        fclose(fid);  
+end
+
 PriFrac = PriFrac';

+ 61 - 61
src-chtc/calc_deff.cpp

@@ -1,61 +1,61 @@
-/* calc_deff.cpp */
-
-/* Calculates the effective depth of each voxel in the tumor mask. */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-//prototype for Siddon raytrace routine (point to point)
-int raytrace(FLOAT_GRID *,FLOAT_GRID *,POINT,POINT);
-
-int calc_deff(FLOAT_GRID *dens, FLOAT_GRID *deff, FLOAT_GRID *terma_mask, BEAM *bm)
-{
- int i, j, k;
-
- // points that will be used for raytrace operation
- POINT p1;
- POINT p2;  
-
- // Raytracing is only done for voxels that non-zero in the terma_mask.
-
- //initialize deff, with -1 signifying voxels of interest in the raytrace
- for (k=0;k<deff->z_count;k++)
-  for (j=0;j<deff->y_count;j++)
-   for (i=0;i<deff->x_count;i++)
-    // we only care about voxels for which the terma_mask is positive
-	if (GRID_VALUE(terma_mask,i,j,k) > 0)
-		GRID_VALUE(deff,i,j,k) = -1.0;
- 
-     // Set the x-ray origin to the the source location 
-     p1.x = bm->y_vec[0];
-     p1.y = bm->y_vec[1];
-     p1.z = bm->y_vec[2];
-
-     // calculate the radiological depth for all voxels in the terma_mask
-
-     for (k=0;k<deff->z_count;k++)
-      for (j=0;j<deff->y_count;j++)
-       for (i=0;i<deff->x_count;i++)
-	    if (GRID_VALUE(deff,i,j,k) == -1.0)
-		{
-	       // The start location is the center of the voxel at (i,j,k).
-	       // Since raytrace works with voxel sides rather than centers,
-	       // need to shift the input by half a voxel in the negative 
-	       // direction for each voxel dimension.
-
-	       p2.x = deff->start.x + ((float) i)*deff->inc.x;
-	       p2.y = deff->start.y + ((float) j)*deff->inc.y;
-           p2.z = deff->start.z + ((float) k)*deff->inc.z;
-
-		   // extend the ray by a factor of 10 to include more voxels in the raytrace
-		   p2.x = p1.x + (p2.x-p1.x)*(float)10.0;
-		   p2.y = p1.y + (p2.y-p1.y)*(float)10.0;
-		   p2.z = p1.z + (p2.z-p1.z)*(float)10.0;
-
-	       // do the raytrace, filling in voxels that are passed on the way
-	       raytrace(dens,deff,p1,p2);
-		} 
-
- return(SUCCESS);
-}
+/* calc_deff.cpp */
+
+/* Calculates the effective depth of each voxel in the tumor mask. */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+//prototype for Siddon raytrace routine (point to point)
+int raytrace(FLOAT_GRID *,FLOAT_GRID *,POINT,POINT);
+
+int calc_deff(FLOAT_GRID *dens, FLOAT_GRID *deff, FLOAT_GRID *terma_mask, BEAM *bm)
+{
+ int i, j, k;
+
+ // points that will be used for raytrace operation
+ POINT p1;
+ POINT p2;  
+
+ // Raytracing is only done for voxels that non-zero in the terma_mask.
+
+ //initialize deff, with -1 signifying voxels of interest in the raytrace
+ for (k=0;k<deff->z_count;k++)
+  for (j=0;j<deff->y_count;j++)
+   for (i=0;i<deff->x_count;i++)
+    // we only care about voxels for which the terma_mask is positive
+	if (GRID_VALUE(terma_mask,i,j,k) > 0)
+		GRID_VALUE(deff,i,j,k) = -1.0;
+ 
+     // Set the x-ray origin to the the source location 
+     p1.x = bm->y_vec[0];
+     p1.y = bm->y_vec[1];
+     p1.z = bm->y_vec[2];
+
+     // calculate the radiological depth for all voxels in the terma_mask
+
+     for (k=0;k<deff->z_count;k++)
+      for (j=0;j<deff->y_count;j++)
+       for (i=0;i<deff->x_count;i++)
+	    if (GRID_VALUE(deff,i,j,k) == -1.0)
+		{
+	       // The start location is the center of the voxel at (i,j,k).
+	       // Since raytrace works with voxel sides rather than centers,
+	       // need to shift the input by half a voxel in the negative 
+	       // direction for each voxel dimension.
+
+	       p2.x = deff->start.x + ((float) i)*deff->inc.x;
+	       p2.y = deff->start.y + ((float) j)*deff->inc.y;
+           p2.z = deff->start.z + ((float) k)*deff->inc.z;
+
+		   // extend the ray by a factor of 10 to include more voxels in the raytrace
+		   p2.x = p1.x + (p2.x-p1.x)*(float)10.0;
+		   p2.y = p1.y + (p2.y-p1.y)*(float)10.0;
+		   p2.z = p1.z + (p2.z-p1.z)*(float)10.0;
+
+	       // do the raytrace, filling in voxels that are passed on the way
+	       raytrace(dens,deff,p1,p2);
+		} 
+
+ return(SUCCESS);
+}

+ 360 - 360
src-chtc/calc_dose.cpp

@@ -1,360 +1,360 @@
-/* calc_dose.cpp */
-
-/* The dose at all voxels in the grid dose_mask is calculated using a convolution
-method that uses a polyenergetic kernel. Inhomogeneities are accounted for by kernel
-scaling, and an inverse square correction is applied after the convolution of the terma
-grid with the kernel, rather than being applied directly to the terma grid before
-the convolution. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <math.h>
-#include <string.h>
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int calc_dose(FLOAT_GRID *density, FLOAT_GRID *terma,FLOAT_GRID *dose, KERNEL *kern, 
-			  BEAM *bm, FLOAT_GRID *dose_mask)
-{
- int i, j, k, l;
- int p, q, r;
- int M, N, Q;  // dimensions of CT array
- int inter_i, inter_j, inter_k;
- int r_index;
- int baseindex;
- float SAD;
- float del_x, del_y, del_z;
- float current_x, current_y, current_z;
- float inter_x, inter_y, inter_z;
- float r_eff, delr_eff, inter_r_eff;
- float kval;
- float cumval, last_cumval;
- float length;
- float *ip, *jp, *kp;
- float dx, dy, dz;
- float delr;  // convolution step size
- float t, u, v, f;
- float *x, *y, *z;  // vectors of CT coordinates
- float *phi, *theta, *sinphi, *cosphi, *sintheta, *costheta;
- float one;
- float rho;
-
- one = (float)1.0; 
-
- // copy CT dimensions and voxel sizes for shorter references later
- M = density->x_count;
- N = density->y_count;
- Q = density->z_count;
-
- dx = density->inc.x;
- dy = density->inc.y;
- dz = density->inc.z;
-
- // copy vectors describing the beam's eye view coordinate system as well
- ip = fvector(0,2);   // ip and jp span the beam's eye view
- jp = fvector(0,2);
- kp = fvector(0,2);   // beam direction
- 
- // create the unit vector describing the beam direction
- for (j=0;j<3;j++) ip[j] = bm->ip[j];
- for (j=0;j<3;j++) jp[j] = bm->jp[j];
- for (j=0;j<3;j++) kp[j] = bm->kp[j];
-
- // vectors describing the location of each voxel
- x = fvector(0,M-1);
- y = fvector(0,N-1);
- z = fvector(0,Q-1);
-
- // lookup table for vectors in polar coordinates
- phi = fvector(0,NPHI-1);
- theta = fvector(0,NTHETA-1);
- sinphi = fvector(0,NPHI-1);
- cosphi = fvector(0,NPHI-1);
- sintheta = fvector(0,NTHETA-1);
- costheta = fvector(0,NTHETA-1);
-
- //kernel with fewer elements for faster calculation
- //see defs.h
- KERNEL smallkern;
- smallkern.radial_boundary = (float *)malloc(kern->nradii*sizeof(float));
- smallkern.angular_boundary = (float *)malloc(kern->ntheta*sizeof(float));
- //small kernel dimensions
- smallkern.nradii = N_KERNEL_RADII;	 //same as original kernel
- smallkern.ntheta = NTHETA;	//must divide evenly into N_KERNEL_ANGLES
-
- SAD = bm->SAD;
- 
- for (i=0;i<N_KERNEL_CATEGORIES;i++)
-  if ( (smallkern.matrix[i] =
-   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
-	return(FAILURE);
-   }
- 
- if ( (smallkern.total_matrix =
-   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for total matrix\n");
-	return(FAILURE);
-   }
-  
- //set up boundaries
- for (i=0;i<smallkern.ntheta;i++)
-  smallkern.angular_boundary[i]	= ( (float) i + 1) * (float)180.0/(float) smallkern.ntheta;
- for (i=0;i<smallkern.nradii;i++)
-  smallkern.radial_boundary[i] = kern->radial_boundary[i];
-  
- //initialise 
-  for (i=0;i<smallkern.nradii;i++)
-   for (j=0;j<smallkern.ntheta;j++)
-   {
-    KERNEL_TOTAL_VALUE(&smallkern,i,j) = (float)0.0;
-    for (l=0;l<N_KERNEL_CATEGORIES;l++)
-      KERNEL_VALUE(&smallkern,l,i,j) = (float)0.0;
-   }
-
- //create kernel values
- for (i=0;i<smallkern.nradii;i++)
-  for (j=0;j<smallkern.ntheta;j++)
-  {   
-   //first angular index in original kernel for this element 
-   baseindex = j*N_KERNEL_ANGLES/NTHETA;
-   //for each category, sum values from original kernel 
-   for (l=0;l<N_KERNEL_CATEGORIES;l++)
-    for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
-     KERNEL_VALUE(&smallkern,l,i,j) += KERNEL_VALUE(kern,l,i,baseindex+k);
-   //and for total kernel
-   for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
-    KERNEL_TOTAL_VALUE(&smallkern,i,j) += KERNEL_TOTAL_VALUE(kern,i,baseindex+k);
-  }
- 
- //Make cumulative kernel (with radius)
- //this is what is used for the dose calculation 
- for (p=0;p<smallkern.ntheta;p++)
-  for (r=0;r<smallkern.nradii;r++)
-  { 
-   for (i=0;i<N_KERNEL_CATEGORIES;i++)
-    if (r > 0)
-     KERNEL_VALUE(&smallkern,i,r,p)
-     = KERNEL_VALUE(&smallkern,i,r-1,p) + KERNEL_VALUE(&smallkern,i,r,p);
-   if (r > 0)
-    KERNEL_TOTAL_VALUE(&smallkern,r,p)
-    = KERNEL_TOTAL_VALUE(&smallkern,r-1,p) + KERNEL_TOTAL_VALUE(&smallkern,r,p);
-  }
-
-  // fill the coordinate vectors
- for (i=0;i<M;i++) x[i] = density->start.x + (float)i*dx;
- for (j=0;j<N;j++) y[j] = density->start.y + (float)j*dy;
- for (k=0;k<Q;k++) z[k] = density->start.z + (float)k*dz;
-
- // fill in the polar coordinates vectors
- for (q=0;q<NPHI;q++) 
- {
-	 phi[q] = ((float)q + (float)0.5)*(float)2.0*(float)PI/(float)NPHI;
-	 sinphi[q] = (float)sin(phi[q]);
-	 cosphi[q] = (float)cos(phi[q]);
- }
-
- // Theta is subtracted from PI is because direction of travel along kernel ray is actually opposite of 
- // direction along which energy is radiating, so need to use a source voxel direction that 
- // is reflected about horizontal.  This can be thought of as the kernel inversion line.
-
- for (p=0;p<smallkern.ntheta;p++)
-  if (p == 0)
-  {
-   theta[p] = (float)0.5*smallkern.angular_boundary[0]*(float)PI/(float)180.0;
-   sintheta[p] = (float)sin((float)PI - theta[p]);
-   costheta[p] = (float)cos((float)PI - theta[p]);
-  }
-  else
-  {
-   theta[p] = (float)0.5*(smallkern.angular_boundary[p-1] + smallkern.angular_boundary[p])*(float)PI/(float)180.0;
-   sintheta[p] = (float)sin((float)PI - theta[p]);
-   costheta[p] = (float)cos((float)PI - theta[p]);
-  }
- 
- // store the sines and cosines in a lookup table
-
- // the step size for the convolution integration is the smallest voxel side length
- if (dx <= dy && dx <= dz)
-	 delr = (float)2.0*dx;
- else if (dy <= dx && dy <= dz)
-	 delr = (float)2.0*dy;
- else
-	 delr = (float)2.0*dz;
-
- //calculate dose at each point
- //done from deposition (catcher's) point of view
- for (k=0;k<Q; k++)
-  for (j=0;j<N; j++)
-   for (i=0;i<M; i++)
-	if (GRID_VALUE(dose_mask,i,j,k) > 0)  // only calculate dose inside dose mask
-	{
-	// do the integral for the point in the ROI
-	for (p=0;p<smallkern.ntheta;p++) //polar
-	 for (q=0;q<NPHI;q++) //azimuthal
-	 {
-	  //initialise position of current voxel
-	  current_x = x[i];
-	  current_y = y[j];
-	  current_z = z[k];
-
-	  //initialise effective radius along kernel direction
-	  r_eff = 0.0;
-	  //initialise cumulative kernel value for this direction
-	  last_cumval = 0.0;
-
-      //Using reciprocity technique where dose at point A due to point B
-	  //is dose at point B due to point A 
-
-      //x ,y, z increments along ray
-	  del_x = delr*(ip[0]*cosphi[q]*sintheta[p] + jp[0]*sinphi[q]*sintheta[p]
-			      + kp[0]*costheta[p]);
-	  del_y = delr*(ip[1]*cosphi[q]*sintheta[p] + jp[1]*sinphi[q]*sintheta[p]
-			      + kp[1]*costheta[p]);
-	  del_z = delr*(ip[2]*cosphi[q]*sintheta[p] + jp[2]*sinphi[q]*sintheta[p]
-			      + kp[2]*costheta[p]);
-
-	  //initialise physical radius
-	  r = 0;
-	  do
-	  {
-	    //interaction point is at mid-point of curent increment
-	    inter_x = current_x + (float)0.5*del_x;
-	    inter_y = current_y + (float)0.5*del_y;
-	    inter_z = current_z + (float)0.5*del_z;
-
-	    //voxel containing interaction point
-	    inter_i = (int) ((inter_x - density->start.x)/dx);
-	    inter_j = (int) ((inter_y - density->start.y)/dy);
-	    inter_k = (int) ((inter_z - density->start.z)/dz);
-	   
-	   // stop the integral if interaction point is outside the dose calculation limits
-	   if (    (inter_i < 0) || (inter_i + 1 >= M)
-	        || (inter_j < 0) || (inter_j + 1 >= N)
-	   	    || (inter_k < 0) || (inter_k + 1 >= Q)
-			|| (GRID_VALUE(dose_mask,inter_i,inter_j,inter_k) <= 0.0))
-		  break;
-
-	   	// Position of the end of the increment.  Interaction point is at the
-	    // midpoint.
-        current_x += del_x;
-	    current_y += del_y;
-	    current_z += del_z;
-        
-        //effective distance increment
-        delr_eff = delr*GRID_VALUE(density,inter_i,inter_j,inter_k);
-		//effective radius of interaction point
-		inter_r_eff = r_eff + (float)0.5*delr_eff;
-	    r_eff += delr_eff;
-
-		// trilinear interpolation method of the terma contribution, f
-
-		// relative differences between the interaction point and the lower voxel bound
-		t = (inter_x - x[inter_i])/dx;
-		u = (inter_y - y[inter_j])/dy;
-		v = (inter_z - z[inter_k])/dz; 
-
-		f = GRID_VALUE(terma,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
-		  + GRID_VALUE(terma,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
-		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
-		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k+1)*t*u*v
-		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
-		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
-		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
-		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); 
-
-		/* 
-		// interpolate density at the interaction point
-		rho = GRID_VALUE(density,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
-		    + GRID_VALUE(density,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
-		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
-		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k+1)*t*u*v
-		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
-		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
-		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
-		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); */
-
-		// perform kernel lookup for r_eff, r_index is the kernel index of the first 
-		// bin boundary below the effective radius of the voxel
-		r_index = binSearch(smallkern.radial_boundary,inter_r_eff,smallkern.nradii);
-
-		// interpolate to obtain the effective cumulative kernel value
-		if (r_index == -1)  // radius is between zero and the first bin boundary
-		{
-			// fractional difference between inter_r_eff and the first bin boundary
-			t = inter_r_eff/smallkern.radial_boundary[0];
-			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,0,p);
-		}
-		else if (r_index >= smallkern.nradii-1)  // overshot the kernel bin boundaries
-		{
-			cumval = KERNEL_TOTAL_VALUE(&smallkern,smallkern.nradii-1,p);
-		}
-		else  // inter_r_eff is between the first upper bin boundary and the last
-		{
-			t = (inter_r_eff - smallkern.radial_boundary[r_index])
-				/(smallkern.radial_boundary[r_index + 1] - smallkern.radial_boundary[r_index]);
-			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,r_index,p)
-				       + t*KERNEL_TOTAL_VALUE(&smallkern,r_index+1,p);
-		}
-
-        kval = cumval - last_cumval;
-
-      	last_cumval = cumval;
-
-		// Kernel value to use is current increment in cumulative value
-        // Note that this is the fractional dose deposited at i,j,k due to
-        // terma in an effective increment (increment*density) along the kernel ray at the 
-		// interaction point. The value comes from the fractional dose deposited in an 
-		// effective increment along the ray	at i,j,k due to terma at the current 
-		// interaction point.
-
-	    //Increment dose value.
-	    //Note that to include the effect of density at i,j,k on ENERGY deposited at i,j,k, 
-	    //there should be a density term, but this cancels on conversion of energy to dose as indicated below
-	    // if (GRID_VALUE(terma,inter_i,inter_j,inter_k) > 0.001)
-	    GRID_VALUE(dose,i,j,k) += f*kval;
-
-	   r++;
-	  }
-	  while (r<10000);
-	 }	//p,q
- 
-      GRID_VALUE(dose,i,j,k)/= NPHI;
-    }
-
- //Inverse square correction to dose
- //This works better than applying the inverse square correction to terma
- //See Papanikolaou and Mackie 1993
- for (k=0;k<Q;k++)
-  for (j=0;j<N;j++)
-	for (i=0;i<M;i++)
-   if (GRID_VALUE(dose,i,j,k) > 0.0)
-   {
-	   // squared difference between the source and the voxel
-	   length = (float)pow(x[i] - bm->y_vec[0],2.0f) + (float)pow(y[j] - bm->y_vec[1],2.0f) 
-		   + (float)pow(z[k] - bm->y_vec[2],2.0f);
-	   
-	   if (length > 0.0)
-	      GRID_VALUE(dose,i,j,k) *= SAD*SAD/length;
-   } 
-
-   // free vectors
-   free_fvector(ip,0,2);
-   free_fvector(jp,0,2);
-   free_fvector(kp,0,2);
-   free_fvector(x,0,M-1);
-   free_fvector(y,0,N-1);
-   free_fvector(z,0,Q-1);
-   
-   free(smallkern.angular_boundary);
-   free(smallkern.radial_boundary);
-   // free(poly_kernel.total_matrix);
-   for (j=0;j<N_KERNEL_CATEGORIES;j++)
-	   free(smallkern.matrix[j]);
-
-   return(SUCCESS);
-}
+/* calc_dose.cpp */
+
+/* The dose at all voxels in the grid dose_mask is calculated using a convolution
+method that uses a polyenergetic kernel. Inhomogeneities are accounted for by kernel
+scaling, and an inverse square correction is applied after the convolution of the terma
+grid with the kernel, rather than being applied directly to the terma grid before
+the convolution. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <math.h>
+#include <string.h>
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int calc_dose(FLOAT_GRID *density, FLOAT_GRID *terma,FLOAT_GRID *dose, KERNEL *kern, 
+			  BEAM *bm, FLOAT_GRID *dose_mask)
+{
+ int i, j, k, l;
+ int p, q, r;
+ int M, N, Q;  // dimensions of CT array
+ int inter_i, inter_j, inter_k;
+ int r_index;
+ int baseindex;
+ float SAD;
+ float del_x, del_y, del_z;
+ float current_x, current_y, current_z;
+ float inter_x, inter_y, inter_z;
+ float r_eff, delr_eff, inter_r_eff;
+ float kval;
+ float cumval, last_cumval;
+ float length;
+ float *ip, *jp, *kp;
+ float dx, dy, dz;
+ float delr;  // convolution step size
+ float t, u, v, f;
+ float *x, *y, *z;  // vectors of CT coordinates
+ float *phi, *theta, *sinphi, *cosphi, *sintheta, *costheta;
+ float one;
+ float rho;
+
+ one = (float)1.0; 
+
+ // copy CT dimensions and voxel sizes for shorter references later
+ M = density->x_count;
+ N = density->y_count;
+ Q = density->z_count;
+
+ dx = density->inc.x;
+ dy = density->inc.y;
+ dz = density->inc.z;
+
+ // copy vectors describing the beam's eye view coordinate system as well
+ ip = fvector(0,2);   // ip and jp span the beam's eye view
+ jp = fvector(0,2);
+ kp = fvector(0,2);   // beam direction
+ 
+ // create the unit vector describing the beam direction
+ for (j=0;j<3;j++) ip[j] = bm->ip[j];
+ for (j=0;j<3;j++) jp[j] = bm->jp[j];
+ for (j=0;j<3;j++) kp[j] = bm->kp[j];
+
+ // vectors describing the location of each voxel
+ x = fvector(0,M-1);
+ y = fvector(0,N-1);
+ z = fvector(0,Q-1);
+
+ // lookup table for vectors in polar coordinates
+ phi = fvector(0,NPHI-1);
+ theta = fvector(0,NTHETA-1);
+ sinphi = fvector(0,NPHI-1);
+ cosphi = fvector(0,NPHI-1);
+ sintheta = fvector(0,NTHETA-1);
+ costheta = fvector(0,NTHETA-1);
+
+ //kernel with fewer elements for faster calculation
+ //see defs.h
+ KERNEL smallkern;
+ smallkern.radial_boundary = (float *)malloc(kern->nradii*sizeof(float));
+ smallkern.angular_boundary = (float *)malloc(kern->ntheta*sizeof(float));
+ //small kernel dimensions
+ smallkern.nradii = N_KERNEL_RADII;	 //same as original kernel
+ smallkern.ntheta = NTHETA;	//must divide evenly into N_KERNEL_ANGLES
+
+ SAD = bm->SAD;
+ 
+ for (i=0;i<N_KERNEL_CATEGORIES;i++)
+  if ( (smallkern.matrix[i] =
+   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
+	return(FAILURE);
+   }
+ 
+ if ( (smallkern.total_matrix =
+   (float *) calloc(smallkern.ntheta*smallkern.nradii,sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for total matrix\n");
+	return(FAILURE);
+   }
+  
+ //set up boundaries
+ for (i=0;i<smallkern.ntheta;i++)
+  smallkern.angular_boundary[i]	= ( (float) i + 1) * (float)180.0/(float) smallkern.ntheta;
+ for (i=0;i<smallkern.nradii;i++)
+  smallkern.radial_boundary[i] = kern->radial_boundary[i];
+  
+ //initialise 
+  for (i=0;i<smallkern.nradii;i++)
+   for (j=0;j<smallkern.ntheta;j++)
+   {
+    KERNEL_TOTAL_VALUE(&smallkern,i,j) = (float)0.0;
+    for (l=0;l<N_KERNEL_CATEGORIES;l++)
+      KERNEL_VALUE(&smallkern,l,i,j) = (float)0.0;
+   }
+
+ //create kernel values
+ for (i=0;i<smallkern.nradii;i++)
+  for (j=0;j<smallkern.ntheta;j++)
+  {   
+   //first angular index in original kernel for this element 
+   baseindex = j*N_KERNEL_ANGLES/NTHETA;
+   //for each category, sum values from original kernel 
+   for (l=0;l<N_KERNEL_CATEGORIES;l++)
+    for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
+     KERNEL_VALUE(&smallkern,l,i,j) += KERNEL_VALUE(kern,l,i,baseindex+k);
+   //and for total kernel
+   for (k=0;k<N_KERNEL_ANGLES/NTHETA;k++)
+    KERNEL_TOTAL_VALUE(&smallkern,i,j) += KERNEL_TOTAL_VALUE(kern,i,baseindex+k);
+  }
+ 
+ //Make cumulative kernel (with radius)
+ //this is what is used for the dose calculation 
+ for (p=0;p<smallkern.ntheta;p++)
+  for (r=0;r<smallkern.nradii;r++)
+  { 
+   for (i=0;i<N_KERNEL_CATEGORIES;i++)
+    if (r > 0)
+     KERNEL_VALUE(&smallkern,i,r,p)
+     = KERNEL_VALUE(&smallkern,i,r-1,p) + KERNEL_VALUE(&smallkern,i,r,p);
+   if (r > 0)
+    KERNEL_TOTAL_VALUE(&smallkern,r,p)
+    = KERNEL_TOTAL_VALUE(&smallkern,r-1,p) + KERNEL_TOTAL_VALUE(&smallkern,r,p);
+  }
+
+  // fill the coordinate vectors
+ for (i=0;i<M;i++) x[i] = density->start.x + (float)i*dx;
+ for (j=0;j<N;j++) y[j] = density->start.y + (float)j*dy;
+ for (k=0;k<Q;k++) z[k] = density->start.z + (float)k*dz;
+
+ // fill in the polar coordinates vectors
+ for (q=0;q<NPHI;q++) 
+ {
+	 phi[q] = ((float)q + (float)0.5)*(float)2.0*(float)PI/(float)NPHI;
+	 sinphi[q] = (float)sin(phi[q]);
+	 cosphi[q] = (float)cos(phi[q]);
+ }
+
+ // Theta is subtracted from PI is because direction of travel along kernel ray is actually opposite of 
+ // direction along which energy is radiating, so need to use a source voxel direction that 
+ // is reflected about horizontal.  This can be thought of as the kernel inversion line.
+
+ for (p=0;p<smallkern.ntheta;p++)
+  if (p == 0)
+  {
+   theta[p] = (float)0.5*smallkern.angular_boundary[0]*(float)PI/(float)180.0;
+   sintheta[p] = (float)sin((float)PI - theta[p]);
+   costheta[p] = (float)cos((float)PI - theta[p]);
+  }
+  else
+  {
+   theta[p] = (float)0.5*(smallkern.angular_boundary[p-1] + smallkern.angular_boundary[p])*(float)PI/(float)180.0;
+   sintheta[p] = (float)sin((float)PI - theta[p]);
+   costheta[p] = (float)cos((float)PI - theta[p]);
+  }
+ 
+ // store the sines and cosines in a lookup table
+
+ // the step size for the convolution integration is the smallest voxel side length
+ if (dx <= dy && dx <= dz)
+	 delr = (float)2.0*dx;
+ else if (dy <= dx && dy <= dz)
+	 delr = (float)2.0*dy;
+ else
+	 delr = (float)2.0*dz;
+
+ //calculate dose at each point
+ //done from deposition (catcher's) point of view
+ for (k=0;k<Q; k++)
+  for (j=0;j<N; j++)
+   for (i=0;i<M; i++)
+	if (GRID_VALUE(dose_mask,i,j,k) > 0)  // only calculate dose inside dose mask
+	{
+	// do the integral for the point in the ROI
+	for (p=0;p<smallkern.ntheta;p++) //polar
+	 for (q=0;q<NPHI;q++) //azimuthal
+	 {
+	  //initialise position of current voxel
+	  current_x = x[i];
+	  current_y = y[j];
+	  current_z = z[k];
+
+	  //initialise effective radius along kernel direction
+	  r_eff = 0.0;
+	  //initialise cumulative kernel value for this direction
+	  last_cumval = 0.0;
+
+      //Using reciprocity technique where dose at point A due to point B
+	  //is dose at point B due to point A 
+
+      //x ,y, z increments along ray
+	  del_x = delr*(ip[0]*cosphi[q]*sintheta[p] + jp[0]*sinphi[q]*sintheta[p]
+			      + kp[0]*costheta[p]);
+	  del_y = delr*(ip[1]*cosphi[q]*sintheta[p] + jp[1]*sinphi[q]*sintheta[p]
+			      + kp[1]*costheta[p]);
+	  del_z = delr*(ip[2]*cosphi[q]*sintheta[p] + jp[2]*sinphi[q]*sintheta[p]
+			      + kp[2]*costheta[p]);
+
+	  //initialise physical radius
+	  r = 0;
+	  do
+	  {
+	    //interaction point is at mid-point of curent increment
+	    inter_x = current_x + (float)0.5*del_x;
+	    inter_y = current_y + (float)0.5*del_y;
+	    inter_z = current_z + (float)0.5*del_z;
+
+	    //voxel containing interaction point
+	    inter_i = (int) ((inter_x - density->start.x)/dx);
+	    inter_j = (int) ((inter_y - density->start.y)/dy);
+	    inter_k = (int) ((inter_z - density->start.z)/dz);
+	   
+	   // stop the integral if interaction point is outside the dose calculation limits
+	   if (    (inter_i < 0) || (inter_i + 1 >= M)
+	        || (inter_j < 0) || (inter_j + 1 >= N)
+	   	    || (inter_k < 0) || (inter_k + 1 >= Q)
+			|| (GRID_VALUE(dose_mask,inter_i,inter_j,inter_k) <= 0.0))
+		  break;
+
+	   	// Position of the end of the increment.  Interaction point is at the
+	    // midpoint.
+        current_x += del_x;
+	    current_y += del_y;
+	    current_z += del_z;
+        
+        //effective distance increment
+        delr_eff = delr*GRID_VALUE(density,inter_i,inter_j,inter_k);
+		//effective radius of interaction point
+		inter_r_eff = r_eff + (float)0.5*delr_eff;
+	    r_eff += delr_eff;
+
+		// trilinear interpolation method of the terma contribution, f
+
+		// relative differences between the interaction point and the lower voxel bound
+		t = (inter_x - x[inter_i])/dx;
+		u = (inter_y - y[inter_j])/dy;
+		v = (inter_z - z[inter_k])/dz; 
+
+		f = GRID_VALUE(terma,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
+		  + GRID_VALUE(terma,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
+		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
+		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k+1)*t*u*v
+		  + GRID_VALUE(terma,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
+		  + GRID_VALUE(terma,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
+		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
+		  + GRID_VALUE(terma,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); 
+
+		/* 
+		// interpolate density at the interaction point
+		rho = GRID_VALUE(density,inter_i,inter_j,inter_k)*(one-t)*(one-u)*(one-v)
+		    + GRID_VALUE(density,inter_i,inter_j,inter_k+1)*(one-t)*(one-u)*v
+		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k+1)*(one-t)*u*v
+		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k+1)*t*u*v
+		    + GRID_VALUE(density,inter_i,inter_j+1,inter_k)*(one-t)*u*(one-v)
+		    + GRID_VALUE(density,inter_i+1,inter_j+1,inter_k)*t*u*(one-v)
+		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k+1)*t*(one-u)*v
+		    + GRID_VALUE(density,inter_i+1,inter_j,inter_k)*t*(one-u)*(one-v); */
+
+		// perform kernel lookup for r_eff, r_index is the kernel index of the first 
+		// bin boundary below the effective radius of the voxel
+		r_index = binSearch(smallkern.radial_boundary,inter_r_eff,smallkern.nradii);
+
+		// interpolate to obtain the effective cumulative kernel value
+		if (r_index == -1)  // radius is between zero and the first bin boundary
+		{
+			// fractional difference between inter_r_eff and the first bin boundary
+			t = inter_r_eff/smallkern.radial_boundary[0];
+			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,0,p);
+		}
+		else if (r_index >= smallkern.nradii-1)  // overshot the kernel bin boundaries
+		{
+			cumval = KERNEL_TOTAL_VALUE(&smallkern,smallkern.nradii-1,p);
+		}
+		else  // inter_r_eff is between the first upper bin boundary and the last
+		{
+			t = (inter_r_eff - smallkern.radial_boundary[r_index])
+				/(smallkern.radial_boundary[r_index + 1] - smallkern.radial_boundary[r_index]);
+			cumval = (1-t)*KERNEL_TOTAL_VALUE(&smallkern,r_index,p)
+				       + t*KERNEL_TOTAL_VALUE(&smallkern,r_index+1,p);
+		}
+
+        kval = cumval - last_cumval;
+
+      	last_cumval = cumval;
+
+		// Kernel value to use is current increment in cumulative value
+        // Note that this is the fractional dose deposited at i,j,k due to
+        // terma in an effective increment (increment*density) along the kernel ray at the 
+		// interaction point. The value comes from the fractional dose deposited in an 
+		// effective increment along the ray	at i,j,k due to terma at the current 
+		// interaction point.
+
+	    //Increment dose value.
+	    //Note that to include the effect of density at i,j,k on ENERGY deposited at i,j,k, 
+	    //there should be a density term, but this cancels on conversion of energy to dose as indicated below
+	    // if (GRID_VALUE(terma,inter_i,inter_j,inter_k) > 0.001)
+	    GRID_VALUE(dose,i,j,k) += f*kval;
+
+	   r++;
+	  }
+	  while (r<10000);
+	 }	//p,q
+ 
+      GRID_VALUE(dose,i,j,k)/= NPHI;
+    }
+
+ //Inverse square correction to dose
+ //This works better than applying the inverse square correction to terma
+ //See Papanikolaou and Mackie 1993
+ for (k=0;k<Q;k++)
+  for (j=0;j<N;j++)
+	for (i=0;i<M;i++)
+   if (GRID_VALUE(dose,i,j,k) > 0.0)
+   {
+	   // squared difference between the source and the voxel
+	   length = (float)pow(x[i] - bm->y_vec[0],2.0f) + (float)pow(y[j] - bm->y_vec[1],2.0f) 
+		   + (float)pow(z[k] - bm->y_vec[2],2.0f);
+	   
+	   if (length > 0.0)
+	      GRID_VALUE(dose,i,j,k) *= SAD*SAD/length;
+   } 
+
+   // free vectors
+   free_fvector(ip,0,2);
+   free_fvector(jp,0,2);
+   free_fvector(kp,0,2);
+   free_fvector(x,0,M-1);
+   free_fvector(y,0,N-1);
+   free_fvector(z,0,Q-1);
+   
+   free(smallkern.angular_boundary);
+   free(smallkern.radial_boundary);
+   // free(poly_kernel.total_matrix);
+   for (j=0;j<N_KERNEL_CATEGORIES;j++)
+	   free(smallkern.matrix[j]);
+
+   return(SUCCESS);
+}

+ 396 - 396
src-chtc/convolutionCondor.cpp

@@ -1,396 +1,396 @@
-/* Cconvolution.cpp */
-
-#include "defs.h"
-
-//function prototypes
-
-int load_kernels(MONO_KERNELS *, char []);
-int load_geometry(FLOAT_GRID *, char []);
-int pop_beam(BEAM *, FILE *);
-int calc_deff(FLOAT_GRID *,FLOAT_GRID *, FLOAT_GRID *, BEAM *);
-int terma_kerma(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,MONO_KERNELS *,FLOAT_GRID *);
-int make_poly_kernel(MONO_KERNELS *, KERNEL *);
-int calc_dose(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,KERNEL *,BEAM *, FLOAT_GRID *);
-int terma_dose_masks(FLOAT_GRID *, FLOAT_GRID *, BEAM *);
-int convolution(MONO_KERNELS *, BEAM *, FLOAT_GRID *, FILE *);
-
-char errstr[200];  // error string that all routines have access to
-
-int main(int argc, char *argv[])
-//  Expects four input arguments: 
-// 1)  kernel_filenames -- contains a list of the kernel files
-// 2)  geometry_filenames  -- contains a list of the geometry files
-// 3)  beamspec batch file -- locations of beamspec files in batch
-// 4)  beamlet batch file -- locations of resulting beamlets in batch
-{
-	int i,j,b,B;
-
-	char tmpstr[200];
-
-	FLOAT_GRID density;
-
-	MONO_KERNELS mono_kernels;
-
-	BEAM beam;
-
-	FILE *beamspec_batch_file;
-	FILE *beamlet_batch_file;
-
-	/*	// print the arguments
-	printf("Input arguments:\n");
-	for (j=1;j<argc;j++)
-	printf("%s\n",argv[j]); */
-
-	if (argc != 5)
-	{
-		printf("Expecting four input command line arguments, received %d.\n",argc);
-		return(FAILURE);
-	}
-
-	if (load_kernels(&mono_kernels,argv[1]) == FAILURE)
-	{
-		sprintf(tmpstr,"Failed at loading the kernels.\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-        printf("Successfully loaded kernels\n");
-
-	if (load_geometry(&density,argv[2]) == FAILURE)
-	{
-		sprintf(tmpstr,"Failed at loading the geometry.\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-        printf("Successfully loaded geometry files.\n");
-
-	/* 
-	// diagnostic lines
-	printf("SAD = %lf \n",beam.SAD);
-	printf("xp = %lf \n",beam.xp);
-	printf("yp = %lf \n",beam.yp);
-	printf("del_xp = %lf \n",beam.del_xp);
-	printf("del_yp = %lf \n",beam.del_yp);
-	printf("y_vec = (%lf,%lf,%lf) \n",beam.y_vec[0],beam.y_vec[1],beam.y_vec[2]);
-	printf("ip = (%lf,%lf,%lf) \n",beam.ip[0],beam.ip[1],beam.ip[2]);
-	printf("jp = (%lf,%lf,%lf) \n",beam.jp[0],beam.jp[1],beam.jp[2]);
-	printf("kp = (%lf,%lf,%lf) \n",beam.kp[0],beam.kp[1],beam.kp[2]);
-
-	printf("Xcount = %d, Ycount = %d, Zcount = %d \n",density.x_count,density.y_count,density.z_count);
-	printf("start = (%lf,%lf,%lf) \n",density.start.x,density.start.y,density.start.z);
-	printf("inc = (%lf,%lf,%lf) \n",density.inc.x,density.inc.y,density.inc.z); */
-
-
-	// open the beam specification batch file
-	if ((beamspec_batch_file = fopen(argv[3],"r")) == NULL)
-	{
-		printf("Failed to open beamspec batch file %s\n",argv[3]);
-		return(FAILURE);
-	}
-        printf("Successfully loaded beamspec files.\n");
-
-	// open the dose batch file
-	if ((beamlet_batch_file = fopen(argv[4],"wb")) == NULL)
-	{
-		printf("Failed to open beamlet batch file %s\n",argv[4]);
-		return(FAILURE);
-	}
-
-	// get the number of beams from the beamspec batch file
-	if (fgets(tmpstr,100,beamspec_batch_file) == NULL)  // pop off the first line
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	if (fscanf(beamspec_batch_file,"%d\n",&B) != 1)
-	{
-		sprintf(errstr,"Could not read-in number of beams from beamspec file.");
-		printf("%s\n",errstr);
-		return(FAILURE);
-	}
-
-	// write the number of beamlets in this batch as the first entry
-	fwrite(&B,sizeof(int),1,beamlet_batch_file); 
-
-	// Do convolution calculations for all consistent beamspec and dose
-	// filenames.  If a calculation for a beamlet fails, print an error 
-	// and move on to the next beamspec file.
-	for (b=0;b<B;b++)
-	{
-		// pop off a beam
-		if(pop_beam(&beam,beamspec_batch_file) == FAILURE)
-		{
-			sprintf(tmpstr,"Failed to load beamspec number %d:\n",b);
-			strcat(tmpstr,errstr);
-			strcpy(errstr,tmpstr);
-			printf("%s\n",errstr);
-		}
-		else if (convolution(&mono_kernels,&beam,&density,beamlet_batch_file) == FAILURE)
-		// An error occurred, so print the error string to standard out
-		// but do not terminate the remaining beam batches.
-		{
-			j = 0;
-			fwrite(&beam.num,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.x_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.y_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&density.z_count,sizeof(int),1,beamlet_batch_file);
-			fwrite(&j,sizeof(int),1,beamlet_batch_file);
-			printf("Error in the calculation for beamlet number %d,\n so all zeros were saved for the resulting beamlet file.\n",b);
-			printf("%s\n",errstr);
-		}
-		else
-			printf("Successfully calculated beamlet %d of %s.\n",b,argv[3]); 
-	}
-
-	// close the beamlet file
-	fclose(beamlet_batch_file);
-
-	// free the density grid
-	free(density.matrix);
-
-	// only need to free angular and radial boundaries for the first
-	// kernel, since other kernel boundaries just point to the same place
-	free(mono_kernels.kernel[0].angular_boundary);
-	free(mono_kernels.kernel[0].radial_boundary);
-
-	// free the kernels
-	free(mono_kernels.energy);
-	free(mono_kernels.fluence);
-	free(mono_kernels.mu);
-	free(mono_kernels.mu_en);
- 	for (i=0;i<mono_kernels.nkernels;i++)
-		for (j=0;j<N_KERNEL_CATEGORIES;j++)
-			free(mono_kernels.kernel[i].matrix[j]); 
-
-	return(SUCCESS);
-}
-
-int convolution(MONO_KERNELS *mono_kernels, BEAM *beam, FLOAT_GRID *density, FILE *beamlet_batch_file)
-// routine that actually performs the convolution for a given kernel, beam, and geometry
-{
-	int i,j,M,N,Q,Nind,Ntotal;  // dimensions of the CT density grid
-	int *dose_ind;
-	float *dose_data, doseMax;
-	char tmpstr[200];  // temporary string
-
-	FLOAT_GRID terma_mask;
-	FLOAT_GRID dose_mask;
-	FLOAT_GRID deff;
-	FLOAT_GRID terma;
-	FLOAT_GRID kermac;
-	FLOAT_GRID dose;
-
-	KERNEL poly_kernel;
-
-	// copy the density grid dimensions to the calculation grids
-	copy_grid_geometry(density,&terma_mask);
-	copy_grid_geometry(density,&dose_mask);
-	copy_grid_geometry(density,&deff);
-	copy_grid_geometry(density,&terma);
-	copy_grid_geometry(density,&kermac);
-	copy_grid_geometry(density,&dose);
-
-	// dimensions of all the grids
-	M = density->x_count;
-	N = density->y_count;
-	Q = density->z_count;
-
-	Ntotal = M*N*Q;
-
-	// Allocate memory for all of the grids and fill them all with zeros
-	if ((terma_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for terma_mask.");
-		return(FAILURE);
-	}
-
-	if ((dose_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for dose_mask.");
-		return(FAILURE);
-	}
-
-	if ((deff.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for deff.");
-		return(FAILURE);
-	}
-
-	if ((terma.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for terma.");
-		return(FAILURE);
-	}
-
-	if ((kermac.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for kermac.");
-		return(FAILURE);
-	}
-
-	if ((dose.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-	{
-		sprintf(errstr,"Could not allocate memory for dose.");
-		return(FAILURE);
-	}
-	
-	for (i=0;i<Ntotal;i++)
-	{
-		terma_mask.matrix[i] = 0.0;
-		dose_mask.matrix[i] = 0.0;
-		deff.matrix[i] = 0.0;
-		terma.matrix[i] = 0.0;
-		kermac.matrix[i] = 0.0;
-		dose.matrix[i] = 0.0;
-	} 
-	
-	/* start calculations */
-
-	// If a failure occurs in any calculation, append the error
-	// onto the error string and then return a FAILURE.
-
-	// create terma and dose masks
-	if (SUCCESS != terma_dose_masks(&terma_mask,&dose_mask,beam))
-	{
-		sprintf(tmpstr,"Failed in terma_dose_masks!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-
-	//create polyenergetic kernel from mono kernels and fluence,mu data
-	if (SUCCESS != make_poly_kernel(mono_kernels,&poly_kernel) )
-	{
-		sprintf(tmpstr,"Failed making polyenergetic kernel!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-	
-	//create effective depth array from density array
-	if (SUCCESS != calc_deff(density,&deff,&terma_mask,beam))
-	{
-		sprintf(tmpstr,"Failed in calc_deff!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-        // printf("Successfully calculated deff for beam %d.\n", beam->num);
-
-	//create kerma and terma arrays
-	//note kerma is collision kerma and is used for a kernel hardening correction
-	if (SUCCESS != terma_kerma(&deff,&terma,&kermac,mono_kernels,&terma_mask))
-	{
-		sprintf(tmpstr,"Failed in terma_kerma calculation!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-        // printf("Successfully calculated terma for beam %d.\n", beam->num);
-
-	//use all this stuff to calculate dose
-	if ( (SUCCESS != calc_dose(density,&terma,&dose,&poly_kernel,beam,&dose_mask)) ) 
-	{
-		sprintf(tmpstr,"Failed calculating dose!\n");
-		strcat(tmpstr,errstr);
-		strcpy(errstr,tmpstr);
-		return(FAILURE);
-	}
-        // printf("Successfully calculated dose for beam %d.\n", beam->num);
-
-	/* //diagnostic lines:
-	FILE *fid;
-	fid = fopen("dose.bin","wb");
-	fwrite(dose.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("terma.bin","wb");
-	fwrite(terma.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("kermac.bin","wb");
-	fwrite(kermac.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("deff.bin","wb");
-	fwrite(deff.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("terma_mask.bin","wb");
-	fwrite(terma_mask.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("dose_mask.bin","wb");
-	fwrite(dose_mask.matrix,sizeof(float),Ntotal,fid);
-	fclose(fid);
-
-	fid = fopen("density.bin","wb");
-	fwrite(density->matrix,sizeof(float),Ntotal,fid);
-	fclose(fid); //*/
-
-    // find maximum dose
-	doseMax = 0.0;
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] > doseMax)
-			doseMax = dose.matrix[i];
-
-	// count the number of non-zero dose values
-	Nind = 0;
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
-			&& dose.matrix[i] > 0.0)
-			Nind++;
-		else
-			dose.matrix[i] = 0.0;  // turn off doses below threshold
-
-	// allocate memory for sparse dose data
-	dose_ind = (int *)malloc(sizeof(int)*Nind);
-	dose_data = (float *)malloc(sizeof(float)*Nind);
-
-	// store the sparse data	
-	j = 0;   // index just for the sparse data
-	for (i=0;i<Ntotal;i++)
-		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
-			&& dose.matrix[i] > 0.0)
-		{
-			dose_ind[j] = i;
-			dose_data[j] = dose.matrix[i];
-			j++; 
-		}
-
-	// save dose to a file
-
-	// save the total file size first, then the number of non-zero elements
-	fwrite(&beam->num,sizeof(int),1,beamlet_batch_file);
-	fwrite(&M,sizeof(int),1,beamlet_batch_file);
-	fwrite(&N,sizeof(int),1,beamlet_batch_file);
-	fwrite(&Q,sizeof(int),1,beamlet_batch_file);
-    fwrite(&Nind,sizeof(int),1,beamlet_batch_file);
-	fwrite(dose_ind,sizeof(int),Nind,beamlet_batch_file);
-	fwrite(dose_data,sizeof(float),Nind,beamlet_batch_file);
-
-	free(dose_ind);
-	free(dose_data);
-
-	// free the calculation grids
-	free(terma_mask.matrix);
-	free(dose_mask.matrix);
-	free(deff.matrix);
-	free(terma.matrix);
-	free(kermac.matrix);
-	free(dose.matrix);
-
-	free(poly_kernel.angular_boundary);
-	free(poly_kernel.radial_boundary);
-	// free(poly_kernel.total_matrix);
-	for (j=0;j<N_KERNEL_CATEGORIES;j++)
-		free(poly_kernel.matrix[j]);
-
-	return(SUCCESS);
-}
-
+/* Cconvolution.cpp */
+
+#include "defs.h"
+
+//function prototypes
+
+int load_kernels(MONO_KERNELS *, char []);
+int load_geometry(FLOAT_GRID *, char []);
+int pop_beam(BEAM *, FILE *);
+int calc_deff(FLOAT_GRID *,FLOAT_GRID *, FLOAT_GRID *, BEAM *);
+int terma_kerma(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,MONO_KERNELS *,FLOAT_GRID *);
+int make_poly_kernel(MONO_KERNELS *, KERNEL *);
+int calc_dose(FLOAT_GRID *,FLOAT_GRID *,FLOAT_GRID *,KERNEL *,BEAM *, FLOAT_GRID *);
+int terma_dose_masks(FLOAT_GRID *, FLOAT_GRID *, BEAM *);
+int convolution(MONO_KERNELS *, BEAM *, FLOAT_GRID *, FILE *);
+
+char errstr[200];  // error string that all routines have access to
+
+int main(int argc, char *argv[])
+//  Expects four input arguments: 
+// 1)  kernel_filenames -- contains a list of the kernel files
+// 2)  geometry_filenames  -- contains a list of the geometry files
+// 3)  beamspec batch file -- locations of beamspec files in batch
+// 4)  beamlet batch file -- locations of resulting beamlets in batch
+{
+	int i,j,b,B;
+
+	char tmpstr[200];
+
+	FLOAT_GRID density;
+
+	MONO_KERNELS mono_kernels;
+
+	BEAM beam;
+
+	FILE *beamspec_batch_file;
+	FILE *beamlet_batch_file;
+
+	/*	// print the arguments
+	printf("Input arguments:\n");
+	for (j=1;j<argc;j++)
+	printf("%s\n",argv[j]); */
+
+	if (argc != 5)
+	{
+		printf("Expecting four input command line arguments, received %d.\n",argc);
+		return(FAILURE);
+	}
+
+	if (load_kernels(&mono_kernels,argv[1]) == FAILURE)
+	{
+		sprintf(tmpstr,"Failed at loading the kernels.\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+        printf("Successfully loaded kernels\n");
+
+	if (load_geometry(&density,argv[2]) == FAILURE)
+	{
+		sprintf(tmpstr,"Failed at loading the geometry.\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+        printf("Successfully loaded geometry files.\n");
+
+	/* 
+	// diagnostic lines
+	printf("SAD = %lf \n",beam.SAD);
+	printf("xp = %lf \n",beam.xp);
+	printf("yp = %lf \n",beam.yp);
+	printf("del_xp = %lf \n",beam.del_xp);
+	printf("del_yp = %lf \n",beam.del_yp);
+	printf("y_vec = (%lf,%lf,%lf) \n",beam.y_vec[0],beam.y_vec[1],beam.y_vec[2]);
+	printf("ip = (%lf,%lf,%lf) \n",beam.ip[0],beam.ip[1],beam.ip[2]);
+	printf("jp = (%lf,%lf,%lf) \n",beam.jp[0],beam.jp[1],beam.jp[2]);
+	printf("kp = (%lf,%lf,%lf) \n",beam.kp[0],beam.kp[1],beam.kp[2]);
+
+	printf("Xcount = %d, Ycount = %d, Zcount = %d \n",density.x_count,density.y_count,density.z_count);
+	printf("start = (%lf,%lf,%lf) \n",density.start.x,density.start.y,density.start.z);
+	printf("inc = (%lf,%lf,%lf) \n",density.inc.x,density.inc.y,density.inc.z); */
+
+
+	// open the beam specification batch file
+	if ((beamspec_batch_file = fopen(argv[3],"r")) == NULL)
+	{
+		printf("Failed to open beamspec batch file %s\n",argv[3]);
+		return(FAILURE);
+	}
+        printf("Successfully loaded beamspec files.\n");
+
+	// open the dose batch file
+	if ((beamlet_batch_file = fopen(argv[4],"wb")) == NULL)
+	{
+		printf("Failed to open beamlet batch file %s\n",argv[4]);
+		return(FAILURE);
+	}
+
+	// get the number of beams from the beamspec batch file
+	if (fgets(tmpstr,100,beamspec_batch_file) == NULL)  // pop off the first line
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	if (fscanf(beamspec_batch_file,"%d\n",&B) != 1)
+	{
+		sprintf(errstr,"Could not read-in number of beams from beamspec file.");
+		printf("%s\n",errstr);
+		return(FAILURE);
+	}
+
+	// write the number of beamlets in this batch as the first entry
+	fwrite(&B,sizeof(int),1,beamlet_batch_file); 
+
+	// Do convolution calculations for all consistent beamspec and dose
+	// filenames.  If a calculation for a beamlet fails, print an error 
+	// and move on to the next beamspec file.
+	for (b=0;b<B;b++)
+	{
+		// pop off a beam
+		if(pop_beam(&beam,beamspec_batch_file) == FAILURE)
+		{
+			sprintf(tmpstr,"Failed to load beamspec number %d:\n",b);
+			strcat(tmpstr,errstr);
+			strcpy(errstr,tmpstr);
+			printf("%s\n",errstr);
+		}
+		else if (convolution(&mono_kernels,&beam,&density,beamlet_batch_file) == FAILURE)
+		// An error occurred, so print the error string to standard out
+		// but do not terminate the remaining beam batches.
+		{
+			j = 0;
+			fwrite(&beam.num,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.x_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.y_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&density.z_count,sizeof(int),1,beamlet_batch_file);
+			fwrite(&j,sizeof(int),1,beamlet_batch_file);
+			printf("Error in the calculation for beamlet number %d,\n so all zeros were saved for the resulting beamlet file.\n",b);
+			printf("%s\n",errstr);
+		}
+		else
+			printf("Successfully calculated beamlet %d of %s.\n",b,argv[3]); 
+	}
+
+	// close the beamlet file
+	fclose(beamlet_batch_file);
+
+	// free the density grid
+	free(density.matrix);
+
+	// only need to free angular and radial boundaries for the first
+	// kernel, since other kernel boundaries just point to the same place
+	free(mono_kernels.kernel[0].angular_boundary);
+	free(mono_kernels.kernel[0].radial_boundary);
+
+	// free the kernels
+	free(mono_kernels.energy);
+	free(mono_kernels.fluence);
+	free(mono_kernels.mu);
+	free(mono_kernels.mu_en);
+ 	for (i=0;i<mono_kernels.nkernels;i++)
+		for (j=0;j<N_KERNEL_CATEGORIES;j++)
+			free(mono_kernels.kernel[i].matrix[j]); 
+
+	return(SUCCESS);
+}
+
+int convolution(MONO_KERNELS *mono_kernels, BEAM *beam, FLOAT_GRID *density, FILE *beamlet_batch_file)
+// routine that actually performs the convolution for a given kernel, beam, and geometry
+{
+	int i,j,M,N,Q,Nind,Ntotal;  // dimensions of the CT density grid
+	int *dose_ind;
+	float *dose_data, doseMax;
+	char tmpstr[200];  // temporary string
+
+	FLOAT_GRID terma_mask;
+	FLOAT_GRID dose_mask;
+	FLOAT_GRID deff;
+	FLOAT_GRID terma;
+	FLOAT_GRID kermac;
+	FLOAT_GRID dose;
+
+	KERNEL poly_kernel;
+
+	// copy the density grid dimensions to the calculation grids
+	copy_grid_geometry(density,&terma_mask);
+	copy_grid_geometry(density,&dose_mask);
+	copy_grid_geometry(density,&deff);
+	copy_grid_geometry(density,&terma);
+	copy_grid_geometry(density,&kermac);
+	copy_grid_geometry(density,&dose);
+
+	// dimensions of all the grids
+	M = density->x_count;
+	N = density->y_count;
+	Q = density->z_count;
+
+	Ntotal = M*N*Q;
+
+	// Allocate memory for all of the grids and fill them all with zeros
+	if ((terma_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for terma_mask.");
+		return(FAILURE);
+	}
+
+	if ((dose_mask.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for dose_mask.");
+		return(FAILURE);
+	}
+
+	if ((deff.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for deff.");
+		return(FAILURE);
+	}
+
+	if ((terma.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for terma.");
+		return(FAILURE);
+	}
+
+	if ((kermac.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for kermac.");
+		return(FAILURE);
+	}
+
+	if ((dose.matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+	{
+		sprintf(errstr,"Could not allocate memory for dose.");
+		return(FAILURE);
+	}
+	
+	for (i=0;i<Ntotal;i++)
+	{
+		terma_mask.matrix[i] = 0.0;
+		dose_mask.matrix[i] = 0.0;
+		deff.matrix[i] = 0.0;
+		terma.matrix[i] = 0.0;
+		kermac.matrix[i] = 0.0;
+		dose.matrix[i] = 0.0;
+	} 
+	
+	/* start calculations */
+
+	// If a failure occurs in any calculation, append the error
+	// onto the error string and then return a FAILURE.
+
+	// create terma and dose masks
+	if (SUCCESS != terma_dose_masks(&terma_mask,&dose_mask,beam))
+	{
+		sprintf(tmpstr,"Failed in terma_dose_masks!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+
+	//create polyenergetic kernel from mono kernels and fluence,mu data
+	if (SUCCESS != make_poly_kernel(mono_kernels,&poly_kernel) )
+	{
+		sprintf(tmpstr,"Failed making polyenergetic kernel!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+	
+	//create effective depth array from density array
+	if (SUCCESS != calc_deff(density,&deff,&terma_mask,beam))
+	{
+		sprintf(tmpstr,"Failed in calc_deff!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+        // printf("Successfully calculated deff for beam %d.\n", beam->num);
+
+	//create kerma and terma arrays
+	//note kerma is collision kerma and is used for a kernel hardening correction
+	if (SUCCESS != terma_kerma(&deff,&terma,&kermac,mono_kernels,&terma_mask))
+	{
+		sprintf(tmpstr,"Failed in terma_kerma calculation!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+        // printf("Successfully calculated terma for beam %d.\n", beam->num);
+
+	//use all this stuff to calculate dose
+	if ( (SUCCESS != calc_dose(density,&terma,&dose,&poly_kernel,beam,&dose_mask)) ) 
+	{
+		sprintf(tmpstr,"Failed calculating dose!\n");
+		strcat(tmpstr,errstr);
+		strcpy(errstr,tmpstr);
+		return(FAILURE);
+	}
+        // printf("Successfully calculated dose for beam %d.\n", beam->num);
+
+	/* //diagnostic lines:
+	FILE *fid;
+	fid = fopen("dose.bin","wb");
+	fwrite(dose.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("terma.bin","wb");
+	fwrite(terma.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("kermac.bin","wb");
+	fwrite(kermac.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("deff.bin","wb");
+	fwrite(deff.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("terma_mask.bin","wb");
+	fwrite(terma_mask.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("dose_mask.bin","wb");
+	fwrite(dose_mask.matrix,sizeof(float),Ntotal,fid);
+	fclose(fid);
+
+	fid = fopen("density.bin","wb");
+	fwrite(density->matrix,sizeof(float),Ntotal,fid);
+	fclose(fid); //*/
+
+    // find maximum dose
+	doseMax = 0.0;
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] > doseMax)
+			doseMax = dose.matrix[i];
+
+	// count the number of non-zero dose values
+	Nind = 0;
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
+			&& dose.matrix[i] > 0.0)
+			Nind++;
+		else
+			dose.matrix[i] = 0.0;  // turn off doses below threshold
+
+	// allocate memory for sparse dose data
+	dose_ind = (int *)malloc(sizeof(int)*Nind);
+	dose_data = (float *)malloc(sizeof(float)*Nind);
+
+	// store the sparse data	
+	j = 0;   // index just for the sparse data
+	for (i=0;i<Ntotal;i++)
+		if (dose.matrix[i] >= doseMax*doseCutoffThreshold
+			&& dose.matrix[i] > 0.0)
+		{
+			dose_ind[j] = i;
+			dose_data[j] = dose.matrix[i];
+			j++; 
+		}
+
+	// save dose to a file
+
+	// save the total file size first, then the number of non-zero elements
+	fwrite(&beam->num,sizeof(int),1,beamlet_batch_file);
+	fwrite(&M,sizeof(int),1,beamlet_batch_file);
+	fwrite(&N,sizeof(int),1,beamlet_batch_file);
+	fwrite(&Q,sizeof(int),1,beamlet_batch_file);
+    fwrite(&Nind,sizeof(int),1,beamlet_batch_file);
+	fwrite(dose_ind,sizeof(int),Nind,beamlet_batch_file);
+	fwrite(dose_data,sizeof(float),Nind,beamlet_batch_file);
+
+	free(dose_ind);
+	free(dose_data);
+
+	// free the calculation grids
+	free(terma_mask.matrix);
+	free(dose_mask.matrix);
+	free(deff.matrix);
+	free(terma.matrix);
+	free(kermac.matrix);
+	free(dose.matrix);
+
+	free(poly_kernel.angular_boundary);
+	free(poly_kernel.radial_boundary);
+	// free(poly_kernel.total_matrix);
+	for (j=0;j<N_KERNEL_CATEGORIES;j++)
+		free(poly_kernel.matrix[j]);
+
+	return(SUCCESS);
+}
+

+ 138 - 138
src-chtc/defs.h

@@ -1,138 +1,138 @@
-/* defs.h */
-
-// libraries that will be needed throughout
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <malloc.h>
-
-#define MAX_KERNELS 50	//max number of monoenergetic kernels to use for creating polyenergetic kernel
-#define N_KERNEL_RADII 24  //number of radial increments in mono kernels 
-#define N_KERNEL_ANGLES 48 //number of angular increments in mono kernels
-#define N_KERNEL_CATEGORIES 5  //number of kernel categories (primary, first scatter...)
-
-// upsample factors to determine insideness for voxels on aperture edge:
-#define Mus  5
-#define Nus  5
-#define Qus  5
-
-#define SUCCESS 1
-#define FAILURE 0
-
-#define doseCutoffThreshold 0.005 // doses less than this fraction of the maximum are cut off
-
-#define RSAFE 2.0   // safety margin for dose_mask calculation in cm
-
-#define PI 3.14152654
-
-#define Y_DOSE_EXTENT 8.0  //optionally only calculate this many cm in y-direction (commented out in calc_dose)
-
-#define NPHI 12  //number of azimuthal angles for convolution 
-// #define DELR 0.4 //radial increments for convolution (adaptive to the problem now, in calc_dose)
-#define NTHETA 6  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)
-
-/* #define NPHI 12	//number of azimuthal angles for convolution 
-#define DELR 0.1 //radial increments for convolution
-#define NTHETA 12  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)  */
-
-#define MAXX(x,y) ((x) > (y) ? (x) : (y))
-
-//each kernel file contains 7 entries per voxel, the first five are these categores
-typedef enum
-{
- primary_,
- first_scatter_,
- second_scatter_,
- multiple_scatter_,
- brem_annih_
-} KERNEL_CATEGORIES;
-
-typedef struct
-{
-    float x;
-    float y;
-    float z;
-} POINT;
-
-//standard float precision grid structure, with dynamically allocated matrix 
-//used for density, deff, terma, kerma, dose
-typedef struct
-{
-    POINT start;
-    POINT inc;
-    int x_count;
-    int y_count;
-    int z_count;
-    float *matrix;
-} FLOAT_GRID;
-
-//macro to access grid values
-#define GRID_VALUE(GRID_ptr, i, j, k)\
-    ((GRID_ptr)->matrix[(i) +\
-                        (GRID_ptr)->x_count *\
-                         ((j) + ((k) * (GRID_ptr)->y_count))])
-
-// macro for 3D dot products
-#define DOT3D(vec1,vec2) ((vec1[0])*(vec2[0])+(vec1[1])*(vec2[1])+(vec1[2])*(vec2[2]))
-
-//kernel structure for each monoenergetic kernel and the polyenergetic kernel
-typedef struct
-{
- int nradii;
- int ntheta;
- float *radial_boundary;
- float *angular_boundary;
- float *matrix[N_KERNEL_CATEGORIES];  //kernel values for each category
- float *total_matrix;				   //sum of all categories (used for current convolution)
-} KERNEL;
-
-//macros for accessing kernel values
-#define KERNEL_VALUE(kern_ptr,category,i,j) \
-        (kern_ptr)->matrix[category][(i) + (j)*(kern_ptr)->nradii]
-#define KERNEL_TOTAL_VALUE(kern_ptr,i,j) \
-        (kern_ptr)->total_matrix[(i) + (j)*(kern_ptr)->nradii]
-
-//infor and array of KERNEL structures for monoenergetic kernels 
-typedef struct
-{
- int nkernels;
- float *energy;
- float *fluence;
- float *mu;
- float *mu_en;
- KERNEL kernel[MAX_KERNELS];
-} MONO_KERNELS;
-
-//beam description (center and size)
-typedef struct
-{
- float ip[3];  // first aperture center vector
- float jp[3];  // second aperture center vector
- float kp[3];  // source direction vector
- float y_vec[3];   // source location vector
-
- // aperture parameters
- float xp;
- float yp;
- float del_xp;   // aperture width in ip direction
- float del_yp;   // aperture width in jp direction
-
- // source-axis distance (leave here for now because to ubiquitous)
- float SAD;
-
- // beam number to avoid ambiguity
- int num;
-} BEAM;
-
-/* Prototypes of utility functions */
-float *fvector(int nl, int nh);
-float **fmatrix(int nrl, int nrh, int ncl, int nch);
-
-void free_fvector(float *v, int nl, int nh);
-void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch);
-
-int copy_grid_geometry(FLOAT_GRID *, FLOAT_GRID *);
-int binSearch(float *, float, int);
-
-void nrerror(char error_text[]);
+/* defs.h */
+
+// libraries that will be needed throughout
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <malloc.h>
+
+#define MAX_KERNELS 50	//max number of monoenergetic kernels to use for creating polyenergetic kernel
+#define N_KERNEL_RADII 24  //number of radial increments in mono kernels 
+#define N_KERNEL_ANGLES 48 //number of angular increments in mono kernels
+#define N_KERNEL_CATEGORIES 5  //number of kernel categories (primary, first scatter...)
+
+// upsample factors to determine insideness for voxels on aperture edge:
+#define Mus  5
+#define Nus  5
+#define Qus  5
+
+#define SUCCESS 1
+#define FAILURE 0
+
+#define doseCutoffThreshold 0.005 // doses less than this fraction of the maximum are cut off
+
+#define RSAFE 2.0   // safety margin for dose_mask calculation in cm
+
+#define PI 3.14152654
+
+#define Y_DOSE_EXTENT 8.0  //optionally only calculate this many cm in y-direction (commented out in calc_dose)
+
+#define NPHI 12  //number of azimuthal angles for convolution 
+// #define DELR 0.4 //radial increments for convolution (adaptive to the problem now, in calc_dose)
+#define NTHETA 6  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)
+
+/* #define NPHI 12	//number of azimuthal angles for convolution 
+#define DELR 0.1 //radial increments for convolution
+#define NTHETA 12  //number of polar angles for convolution (must divide evenly into N_KERNEL_ANGLES)  */
+
+#define MAXX(x,y) ((x) > (y) ? (x) : (y))
+
+//each kernel file contains 7 entries per voxel, the first five are these categores
+typedef enum
+{
+ primary_,
+ first_scatter_,
+ second_scatter_,
+ multiple_scatter_,
+ brem_annih_
+} KERNEL_CATEGORIES;
+
+typedef struct
+{
+    float x;
+    float y;
+    float z;
+} POINT;
+
+//standard float precision grid structure, with dynamically allocated matrix 
+//used for density, deff, terma, kerma, dose
+typedef struct
+{
+    POINT start;
+    POINT inc;
+    int x_count;
+    int y_count;
+    int z_count;
+    float *matrix;
+} FLOAT_GRID;
+
+//macro to access grid values
+#define GRID_VALUE(GRID_ptr, i, j, k)\
+    ((GRID_ptr)->matrix[(i) +\
+                        (GRID_ptr)->x_count *\
+                         ((j) + ((k) * (GRID_ptr)->y_count))])
+
+// macro for 3D dot products
+#define DOT3D(vec1,vec2) ((vec1[0])*(vec2[0])+(vec1[1])*(vec2[1])+(vec1[2])*(vec2[2]))
+
+//kernel structure for each monoenergetic kernel and the polyenergetic kernel
+typedef struct
+{
+ int nradii;
+ int ntheta;
+ float *radial_boundary;
+ float *angular_boundary;
+ float *matrix[N_KERNEL_CATEGORIES];  //kernel values for each category
+ float *total_matrix;				   //sum of all categories (used for current convolution)
+} KERNEL;
+
+//macros for accessing kernel values
+#define KERNEL_VALUE(kern_ptr,category,i,j) \
+        (kern_ptr)->matrix[category][(i) + (j)*(kern_ptr)->nradii]
+#define KERNEL_TOTAL_VALUE(kern_ptr,i,j) \
+        (kern_ptr)->total_matrix[(i) + (j)*(kern_ptr)->nradii]
+
+//infor and array of KERNEL structures for monoenergetic kernels 
+typedef struct
+{
+ int nkernels;
+ float *energy;
+ float *fluence;
+ float *mu;
+ float *mu_en;
+ KERNEL kernel[MAX_KERNELS];
+} MONO_KERNELS;
+
+//beam description (center and size)
+typedef struct
+{
+ float ip[3];  // first aperture center vector
+ float jp[3];  // second aperture center vector
+ float kp[3];  // source direction vector
+ float y_vec[3];   // source location vector
+
+ // aperture parameters
+ float xp;
+ float yp;
+ float del_xp;   // aperture width in ip direction
+ float del_yp;   // aperture width in jp direction
+
+ // source-axis distance (leave here for now because to ubiquitous)
+ float SAD;
+
+ // beam number to avoid ambiguity
+ int num;
+} BEAM;
+
+/* Prototypes of utility functions */
+float *fvector(int nl, int nh);
+float **fmatrix(int nrl, int nrh, int ncl, int nch);
+
+void free_fvector(float *v, int nl, int nh);
+void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch);
+
+int copy_grid_geometry(FLOAT_GRID *, FLOAT_GRID *);
+int binSearch(float *, float, int);
+
+void nrerror(char error_text[]);

+ 122 - 122
src-chtc/make_poly.cpp

@@ -1,122 +1,122 @@
-/* make_poly.cpp */
-
-/* Creates a poly-energetic kernel given the energy-binned beam fluence and 
-kernels for all of the beam energies. */
-
-#include "defs.h"
-
-//fillers for these entries in kernel structure
-#define UNCERT 1.0
-#define MEAN_RADIUS 0.0
-#define MEAN_ANGLE 0.0
-
-extern char errstr[200];  // error string that all routines have access to
-
-int make_poly_kernel(MONO_KERNELS *mono, KERNEL *poly)
-{
- 
-// There is a problem with the first block of commented statements, likely a memory leak
-
- KERNEL_CATEGORIES category;
- int i, j, e;
- float sum;
-
- poly->nradii = N_KERNEL_RADII;
- poly->ntheta = N_KERNEL_ANGLES;
- 
- poly->radial_boundary = (float *)malloc(poly->nradii*sizeof(float));
- poly->angular_boundary = (float *)malloc(poly->ntheta*sizeof(float));
-
- //copy radial boundaries from first mono kernel
- for (i=0;i<poly->nradii;i++)
-  poly->radial_boundary[i] = mono->kernel[0].radial_boundary[i];
-
- //copy angular boundaries from first mono kernel
- for (i=0;i<poly->ntheta;i++)
-  poly->angular_boundary[i] = mono->kernel[0].angular_boundary[i];
-
- for (i=0;i<N_KERNEL_CATEGORIES;i++)
-  if ( (poly->matrix[i] =
-   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
-	return(FAILURE);
-   }
- if ( (poly->total_matrix =
-   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
-   {
-	sprintf(errstr,"Cannot allocate space for total matrix\n");
-	return(FAILURE);
-   } 
-
- for (j=0;j<poly->ntheta;j++)
-  for (i=0;i<poly->nradii;i++)
-  {
-   KERNEL_TOTAL_VALUE(poly,i,j) = 0.0;
-
-   //weight of each mono kernel value in sum is fluence*energy*mu
-   category = primary_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = first_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = second_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = multiple_scatter_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-   category = brem_annih_;
-   KERNEL_VALUE(poly,category,i,j) = 0.0;
-   sum = 0.0;
-   for (e=0;e<mono->nkernels;e++)
-   {
-    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
-    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
-   }
-   KERNEL_VALUE(poly,category,i,j) /= sum;
-   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
-
-  }
-
- return(SUCCESS);
-
-}
+/* make_poly.cpp */
+
+/* Creates a poly-energetic kernel given the energy-binned beam fluence and 
+kernels for all of the beam energies. */
+
+#include "defs.h"
+
+//fillers for these entries in kernel structure
+#define UNCERT 1.0
+#define MEAN_RADIUS 0.0
+#define MEAN_ANGLE 0.0
+
+extern char errstr[200];  // error string that all routines have access to
+
+int make_poly_kernel(MONO_KERNELS *mono, KERNEL *poly)
+{
+ 
+// There is a problem with the first block of commented statements, likely a memory leak
+
+ KERNEL_CATEGORIES category;
+ int i, j, e;
+ float sum;
+
+ poly->nradii = N_KERNEL_RADII;
+ poly->ntheta = N_KERNEL_ANGLES;
+ 
+ poly->radial_boundary = (float *)malloc(poly->nradii*sizeof(float));
+ poly->angular_boundary = (float *)malloc(poly->ntheta*sizeof(float));
+
+ //copy radial boundaries from first mono kernel
+ for (i=0;i<poly->nradii;i++)
+  poly->radial_boundary[i] = mono->kernel[0].radial_boundary[i];
+
+ //copy angular boundaries from first mono kernel
+ for (i=0;i<poly->ntheta;i++)
+  poly->angular_boundary[i] = mono->kernel[0].angular_boundary[i];
+
+ for (i=0;i<N_KERNEL_CATEGORIES;i++)
+  if ( (poly->matrix[i] =
+   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for matrix %d\n",i);
+	return(FAILURE);
+   }
+ if ( (poly->total_matrix =
+   (float *) malloc(poly->ntheta*poly->nradii*sizeof(float))) == NULL)
+   {
+	sprintf(errstr,"Cannot allocate space for total matrix\n");
+	return(FAILURE);
+   } 
+
+ for (j=0;j<poly->ntheta;j++)
+  for (i=0;i<poly->nradii;i++)
+  {
+   KERNEL_TOTAL_VALUE(poly,i,j) = 0.0;
+
+   //weight of each mono kernel value in sum is fluence*energy*mu
+   category = primary_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = first_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = second_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = multiple_scatter_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+   category = brem_annih_;
+   KERNEL_VALUE(poly,category,i,j) = 0.0;
+   sum = 0.0;
+   for (e=0;e<mono->nkernels;e++)
+   {
+    KERNEL_VALUE(poly,category,i,j) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+	                                  * KERNEL_VALUE(&(mono->kernel[e]),category,i,j); 
+    sum += mono->fluence[e]*mono->energy[e]*mono->mu[e]; 
+   }
+   KERNEL_VALUE(poly,category,i,j) /= sum;
+   KERNEL_TOTAL_VALUE(poly,i,j) += KERNEL_VALUE(poly,category,i,j);
+
+  }
+
+ return(SUCCESS);
+
+}

+ 12 - 12
src-chtc/makefile

@@ -1,12 +1,12 @@
-CC = g++
-CFLAGS = -O2
-OBJECTS = convolutionCondor.o calc_deff.o parse_funcCondor.o make_poly.o raytrace.o terma_dose_masks.o terma_kerma.o calc_dose.o util.o
-
-Cconvolution : $(OBJECTS)
-	condor_compile $(CC) $(CFLAGS) $(OBJECTS) -o convolutionCondor
-
-%.o : %.cpp
-	$(CC) $(CFLAGS) -c $<
-
-clean : 
-	rm -f $(OBJECTS) convolutionCondor
+CC = g++
+CFLAGS = -O2
+OBJECTS = convolutionCondor.o calc_deff.o parse_funcCondor.o make_poly.o raytrace.o terma_dose_masks.o terma_kerma.o calc_dose.o util.o
+
+Cconvolution : $(OBJECTS)
+	condor_compile $(CC) $(CFLAGS) $(OBJECTS) -o convolutionCondor
+
+%.o : %.cpp
+	$(CC) $(CFLAGS) -c $<
+
+clean : 
+	rm -f $(OBJECTS) convolutionCondor

+ 825 - 825
src-chtc/parse_funcCondor.cpp

@@ -1,825 +1,825 @@
-/* parse_func.cpp */
-
-/* Checks the validity of the arguments input to the convolution routine and 
-transfers the Matlab-style arguments to the C structures defined in defs.h. */
-
-/* This parse function operates on file inputs rather than on Matlab inputs. */
-
-#include "defs.h"
-
-// Markers that are searched for inside the kernel_filenames file, which is 
-// passed to the load_kernels routine. The line after each of these markers
-// in the kernel_filenames file is a filename corresponding to the marker.
-#define kernel_header_line "kernel_header"
-#define kernel_radii_line "kernel_radii"
-#define kernel_angles_line "kernel_angles"
-#define kernel_energies_line "kernel_energies"
-#define kernel_primary_line "kernel_primary"
-#define kernel_first_scatter_line "kernel_first_scatter"
-#define kernel_second_scatter_line "kernel_second_scatter"
-#define kernel_multiple_scatter_line "kernel_multiple_scatter"
-#define kernel_brem_annih_line "kernel_brem_annih"
-#define kernel_total_line "kernel_total"
-#define kernel_fluence_line "kernel_fluence"
-#define kernel_mu_line "kernel_mu"
-#define kernel_mu_en_line "kernel_mu_en"
-
-// Markers that are searched for inside the geometry_filenames, which is 
-// passed to the load_geometry routine. These have the same meaning as
-// the kernel_filenames markers.
-#define geometry_header "./geometry_files/geometry_header.txt"
-#define geometry_density "./geometry_files/density.bin"
-#define beam_data "./geometry_files/beam_data.txt"
-
-#define geometry_header_line "geometry_header"
-#define geometry_density_line "geometry_density"
-#define beam_data_line "beam_data"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int load_kernels(MONO_KERNELS *mono_kernels, char kernel_filenames[])
-/* Ensures that the kernel files have the following format:
-
-               radii: [1xNradii float]
-              angles: [1xNangles float]
-            energies: [1xNenergies float]
-             primary: [Nradii x Nangles x Nenergies float]
-       first_scatter: [Nradii x Nangles x Nenergies float]
-      second_scatter: [Nradii x Nangles x Nenergies float]
-    multiple_scatter: [Nradii x Nangles x Nenergies float]
-          brem_annih: [Nradii x Nangles x Nenergies float]
-               total: [Nradii x Nangles x Nenergies float]
-          mean_radii: [Nradii x Nangles x Nenergies float] (not used)
-         mean_angles: [Nradii x Nangles x Nenergies float] (not used)
-           helpfield: [any x any char] 
-             fluence: [1xNenergies float]
-                  mu: [1xNenergies float]
-               mu_en: [1xNenergies float]
-
-mistakes or inconsistencies will result in errors.
-
-  Results are then stored in mono_kernels.
-
-The names of the files containing all of these parameters are given
-by the kernel_filenames file.
-
-*/
-{
-	int j,k;
-	int Nenergies, Nangles, Nradii;
-	char str[200];
-	// some strings to hold filenames
-	char header_filename[200], radii_filename[200], angles_filename[200];
-	char energies_filename[200], primary_filename[200], first_scatter_filename[200];
-	char second_scatter_filename[200], multiple_scatter_filename[200];
-	char brem_annih_filename[200], total_filename[200], fluence_filename[200];
-	char mu_filename[200], mu_en_filename[200];
-
-	// flags for file readin
-	int header_flag = 0;
-	int radii_flag = 0;
-	int angles_flag = 0;
-	int energies_flag = 0;
-	int primary_flag = 0;
-	int first_flag = 0;
-	int second_flag = 0;
-	int multiple_flag = 0;
-	int brem_annih_flag = 0;
-	int total_flag = 0;
-	int fluence_flag = 0;
-	int mu_flag = 0;
-	int mu_en_flag = 0;
-
-	FILE *fid;  // generic filename
-	FILE *primary, *first, *second, *multiple, *brem_annih, *total;  // kernel files
-
-	// read in the data filenames
-	if ( (fid = fopen(kernel_filenames,"r")) == NULL)  // open the kernel filenames
-	{
-		sprintf(errstr,"Could not open the kernel filenames file");
-		return(FAILURE);
-	}
-
-	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
-	{
-	  if (!strcmp(str,kernel_header_line))
-	    if (fscanf(fid,"%s\n",header_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_header filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      header_flag = 1;
-	  else if (!strcmp(str,kernel_radii_line))
-	    if (fscanf(fid,"%s\n",radii_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_radii filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      radii_flag = 1;
-	  else if (!strcmp(str,kernel_angles_line))
-	    if (fscanf(fid,"%s\n",angles_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_angles filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-            else
-	      angles_flag = 1;
-	  else if (!strcmp(str,kernel_energies_line))
-        if (fscanf(fid,"%s\n",energies_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_energies filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      energies_flag = 1;
-          else if (!strcmp(str,kernel_fluence_line))
-	    if (fscanf(fid,"%s\n",fluence_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_fluence filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      fluence_flag = 1;
-	  else if (!strcmp(str,kernel_primary_line))
-        if (fscanf(fid,"%s\n",primary_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_primary filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      primary_flag = 1;
-	  else if (!strcmp(str,kernel_first_scatter_line))
-        if (fscanf(fid,"%s\n",first_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_first_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      first_flag = 1;
-	  else if (!strcmp(str,kernel_second_scatter_line))
-	    if (fscanf(fid,"%s\n",second_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_second_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      second_flag = 1;
-	  else if (!strcmp(str,kernel_multiple_scatter_line))
-        if (fscanf(fid,"%s\n",multiple_scatter_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_multiple_scatter filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      multiple_flag = 1;
-	  else if (!strcmp(str,kernel_brem_annih_line))
-	    if (fscanf(fid,"%s\n",brem_annih_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_brem_annih filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else 
-	      brem_annih_flag = 1;
-	  else if (!strcmp(str,kernel_total_line))
-	    if (fscanf(fid,"%s\n",total_filename) != 1)
-	    {
-			sprintf(errstr,"Failed to read-in the kernel_total filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      total_flag = 1;
-	  else if (!strcmp(str,kernel_mu_line))
-	    if (fscanf(fid,"%s\n",mu_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_mu filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      mu_flag = 1;
-	  else if (!strcmp(str,kernel_mu_en_line))
-	    if (fscanf(fid,"%s\n",mu_en_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the kernel_mu_en filename from the kernel filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      mu_en_flag = 1;
-	  else
-	  {   
-		    sprintf(errstr,"Unrecognized string in the kernel filenames file: %s\n",str);
-			return(FAILURE);   
-	  }
-	}
-
-	// confirm that all of the required filenames have been found
-	if (header_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel header filename.");
-	  return(FAILURE);
-	}
-	else if (radii_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel radii filename.");
-	  return(FAILURE);
-	}
-	else if (angles_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel angles filename.");
-	  return(FAILURE);
-	}
-	else if (energies_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel energies filename.");
-	  return(FAILURE);
-	}
-	else if (primary_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a primary kernel filename.");
-	  return(FAILURE);
-	}
-	else if (first_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a first scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (second_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a second scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (multiple_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a multiple scatter kernel filename.");
-	  return(FAILURE);
-	}
-	else if (brem_annih_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a brem_annih kernel filename.");
-	  return(FAILURE);
-	}
-	else if (total_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a total kernel filename.");
-	  return(FAILURE);
-	}
-	else if (fluence_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel fluence filename.");
-	  return(FAILURE);
-	}
-	else if (mu_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel mu filename.");
-	  return(FAILURE);
-	}
-	else if (mu_en_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a kernel mu_en filename.");
-	  return(FAILURE);
-	}
-
-	// read in the expected matrix sizes
-	if ( (fid=fopen(header_filename,"r")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel header file in kernel data folder.");
-		return(FAILURE);
-	}
-	else
-	{   
-		fgets(str,100,fid); // pop-off the first line of the header
-		if (fscanf(fid,"%d %d %d\n",&Nradii,&Nangles,&Nenergies) != 3)
-		{
-			sprintf(errstr,"Incorrect amount of data in kernel header file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	mono_kernels->nkernels = Nenergies;
-
-	// read in the energies, fluences, mu, and mu_en values
-	if ( (fid = fopen(energies_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel energies file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->energy = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel energies.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->energy,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of energies in kernel_energies file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	if ( (fid = fopen(fluence_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel fluences file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->fluence = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel fluences.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->fluence,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of fluences in kernel_fluences file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-	
-	if ( (fid = fopen(mu_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel mu file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->mu = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel mu.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->mu,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of mu values in kernel_mu file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	if ( (fid = fopen(mu_en_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel mu_en file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if ((mono_kernels->mu_en = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
-		{
-			sprintf(errstr,"Failed in memory allocation for kernel mu_en.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->mu_en,sizeof(float),Nenergies,fid) != Nenergies)
-		{
-			sprintf(errstr,"Incorrect number of mu_en values in kernel_mu_en file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	// Only assign memory for bin boundaries for the first kernel. Just point the other
-	// boundary pointers at the values in the first kernel.
-
-	if ( (fid = fopen(radii_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel radii file.");
-		return(FAILURE);
-	}
-	else
-	{
-		mono_kernels->kernel[0].nradii = Nradii;
-		if( (mono_kernels->kernel[0].radial_boundary = (float *)malloc(sizeof(float)*Nradii)) == NULL)
-		{
-			sprintf(errstr,"Failed to allocate memory for radial boundaries.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->kernel[0].radial_boundary,sizeof(float),Nradii,fid) != Nradii)
-		{
-			sprintf(errstr,"Incorrect number of radii values in kernel_radii file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-	
-	if ( (fid = fopen(angles_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing kernel angles file.");
-		return(FAILURE);
-	}
-	else
-	{
-		mono_kernels->kernel[0].ntheta = Nangles;
-		if( (mono_kernels->kernel[0].angular_boundary = (float *)malloc(sizeof(float)*Nangles)) == NULL)
-		{
-			sprintf(errstr,"Failed to allocate memory for angular boundaries.");
-			return(FAILURE);
-		}
-		if( (int)fread(mono_kernels->kernel[0].angular_boundary,sizeof(float),Nangles,fid) != Nangles)
-		{
-			sprintf(errstr,"Incorrect number of angular values in kernel_angles file.");
-			return(FAILURE);
-		}
-		fclose(fid);
-	}
-
-	// allocate space for kernel matrices and copy bin boundaries for other kernel categories
-	for (j=0;j<Nenergies;j++)  // loop through energies
-	{
-		if (j != 0)
-		{
-			mono_kernels->kernel[j].nradii = Nradii;
-			mono_kernels->kernel[j].ntheta = Nangles;
-	
-			mono_kernels->kernel[j].radial_boundary = mono_kernels->kernel[0].radial_boundary;
-			mono_kernels->kernel[j].angular_boundary = mono_kernels->kernel[0].angular_boundary;
-		}
-
-		// allocate space for kernels
-		for (k=0;k<N_KERNEL_CATEGORIES;k++)
-			if ((mono_kernels->kernel[j].matrix[k] 
-				= (float *)malloc(sizeof(float)*Nradii*Nangles*N_KERNEL_CATEGORIES)) == NULL)
-			{
-				sprintf(errstr,"Failed to allocate memory for kernel matrix.");
-				return(FAILURE);
-			}
-	}
-	
-	// load-in the kernels one at a time and fill-up the monoenergetic kernels
-	
-	// open the kernel files
-	if ( (primary = fopen(primary_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing primary kernel.");
-		return(FAILURE);
-	}
-
-	if ( (first = fopen(first_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing first scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (second = fopen(second_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing second scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (multiple = fopen(multiple_scatter_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing multiple scatter kernel.");
-		return(FAILURE);
-	}
-
-	if ( (brem_annih = fopen(brem_annih_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing brem_annih kernel.");
-		return(FAILURE);
-	}
-
-	if ( (total = fopen(total_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Missing total kernel.");
-		return(FAILURE);
-	}
-
-	// loop through all energies, reading the kernel files in to the kernel structures
-	for (j=0;j<Nenergies;j++)
-	{
-		if ( (int)fread(mono_kernels->kernel[j].matrix[0],sizeof(float),Nradii*Nangles,primary) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[1],sizeof(float),Nradii*Nangles,first) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[2],sizeof(float),Nradii*Nangles,second) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[3],sizeof(float),Nradii*Nangles,multiple) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-
-		if ( (int)fread(mono_kernels->kernel[j].matrix[4],sizeof(float),Nradii*Nangles,brem_annih) 
-			!= Nradii*Nangles)
-		{
-			sprintf(errstr,"Could not read the correct number of kernel values.");
-			return(FAILURE);
-		}
-	}
-
-	// close the kernel files
-	fclose(primary);
-	fclose(first);
-	fclose(second);
-	fclose(multiple);
-	fclose(brem_annih);
-
-	return(SUCCESS);
-}
-
-int load_geometry(FLOAT_GRID *density, char geometry_filenames[])
-/* Ensure that the GEOMETRY structure has the following format:
-  Geometry = 
-
-         start: [3 element float]
-    voxel_size: [3 element float]
-          data: [M x N x Q float]
-          beam: [1x1 struct] 
-		  
- Geometry.beam = 
-
-    ip: [3 element float]
-    jp: [3 element float]
-    kp: [3 element float]
-     y_vec: [3 element float]
-        xp: [float scalar]
-        yp: [float scalar]
-    del_xp: [float scalar]
-    del_yp: [float scalar]
-	   SAD: [float scalar]
-	
-
-	and load the data into memory.  
-
-The names of the files containing the above data are listed in two files:
-geometry_filenames and beam_filenames.  The beam data are stored in a 
-separate file since many dose calculations are done by changing the 
-beam data and leaving the geometry data constant.  This way one can use
-a separate beam file for each beam but the same geometry file.
-*/
-{
-	int Ntotal;
-	char str[200];   // dummy string
-	char header_filename[200], density_filename[200];
-	// flags for filename readin
-	int header_flag = 0;
-	int density_flag = 0;
-	FILE *fid;          // dummy filename
-
-	// read in the geometry filenames
-	if ( (fid = fopen(geometry_filenames,"r")) == NULL)  // open the geometry filenames
-	{
-	  sprintf(errstr,"Could not open the geometry filenames file\n");
-	  return(FAILURE);
-	}
-
-	// read in the non-beam geometric data
-	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
-	{
-	  if (!strcmp(str,geometry_header_line))
-	    if (fscanf(fid,"%s\n",header_filename) != 1)
-		{
-			sprintf(errstr,"Failed to read-in the geometry_header filename from the geometry filenames file.");
-		}
-	    else
-	      header_flag = 1;
-	  else if (!strcmp(str,geometry_density_line))
-	    if (fscanf(fid,"%s\n",density_filename) != 1)
-		{
-	        sprintf(errstr,"Failed to read-in the geometry_density filename from the geometry filenames file.");
-			return(FAILURE);
-		}
-	    else
-	      density_flag = 1;
-	  else
-	  {   
-			sprintf("Unrecognized string in the geometry filenames file: %s\n",str);
-			return(FAILURE);   
-	  }
-	}
-	
-    // confirm that all of the required filenames have been found
-	if (header_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a geometry header filename.\n");
-	  return(FAILURE);
-	}
-	else if (density_flag == 0)
-	{
-	  sprintf(errstr,"Unable to find a geometry density filename.\n");
-	  return(FAILURE);
-	}
-
-	// read in geometric and beam data
-	if( (fid = fopen(header_filename,"r")) == NULL)
-	{
-		sprintf(errstr,"Could not open geometry header file.");
-		return(FAILURE);
-	}
-	else
-	{
-		// pop-off the first line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%d %d %d\n",&density->x_count,&density->y_count,&density->z_count) != 3)
-		{
-			sprintf(errstr,"Could not read-in data grid size.");
-			return(FAILURE);
-		}
-		
-		// pop-off the next line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header  file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%f %f %f\n",&density->start.x,&density->start.y,&density->start.z) != 3)
-		{
-			sprintf(errstr,"Could not read-in density grid start position.");
-			return(FAILURE);
-		}
-
-		// pop-off the next line of the header file
-		if (fgets(str,100,fid) == NULL) 
-		{
-			sprintf(errstr,"Could not read from geometry header file.");
-			return(FAILURE);
-		}
-
-		// read-in the CT data grid size
-		if (fscanf(fid,"%f %f %f\n",&density->inc.x,&density->inc.y,&density->inc.z) != 3)
-		{
-			sprintf(errstr,"Could not read-in voxel size vector.");
-			return(FAILURE);
-		}
-
-		Ntotal = density->x_count*density->y_count*density->z_count;
-	}
-
-	// read-in the CT density data
-	if( (fid = fopen(density_filename,"rb")) == NULL)
-	{
-		sprintf(errstr,"Could not open CT density file.");
-		return(FAILURE);
-	}
-	else
-	{
-		if( (density->matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
-		{
-			sprintf(errstr,"Unable to allocate space for CT density grid.");
-			return(FAILURE);
-		}
-		else if ((int)fread(density->matrix,sizeof(float),Ntotal,fid) != Ntotal)
-		{
-			sprintf(errstr,"Unable to read-in CT density data.");
-			return(FAILURE);
-		}
-	}
-	return(SUCCESS);
-}
-
-int pop_beam(BEAM *bm, FILE *beamspec_batch_file)
-/*  Pops a beam off of the beamspec_batch_file file and loads it into a BEAM structure.
-
-  Ensure that the beam data file has the following format:
- Geometry.beam = 
-
-        ip: [3 element float]
-        jp: [3 element float]
-        kp: [3 element float]
-     y_vec: [3 element float]
-        xp: [float scalar]
-        yp: [float scalar]
-    del_xp: [float scalar]
-    del_yp: [float scalar]
-	   SAD: [float scalar]
-	   num: [int scalar]
-	
-	and load the data into memory.  
-*/
-{
-	char str[200];      // dummy string
-
-	// read-in the beam data
-	// pop-off the first line of the beam data file
-
-	// read-in the CT data grid size
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		return(FAILURE);
-	}
-
-	if (fscanf(beamspec_batch_file,"%d\n",&bm->num) != 1)
-	{
-		sprintf(errstr,"Could not read-in beam data.");
-		return(FAILURE);
-	}
-
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the CT data grid size
-	if (fscanf(beamspec_batch_file,"%f %f %f %f %f\n",&bm->SAD,&bm->xp,&bm->yp,&bm->del_xp,&bm->del_yp) != 5)
-	{
-		sprintf(errstr,"Could not read-in beam data.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the source position vector
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->y_vec[0],&bm->y_vec[1],&bm->y_vec[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in source location vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the beam's eye view vectors, ip first
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->ip[0],&bm->ip[1],&bm->ip[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in ip vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the second beam's eye view vector, jp
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->jp[0],&bm->jp[1],&bm->jp[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in jp vector.");
-		return(FAILURE);
-	}
-
-	// pop-off the next line of the beam data file
-	if (fgets(str,100,beamspec_batch_file) == NULL) 
-	{
-		sprintf(errstr,"Could not read from from beam data file.");
-		return(FAILURE);
-	}
-
-	// read-in the third beam's eye view vector, kp
-	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->kp[0],&bm->kp[1],&bm->kp[2]) != 3)
-	{
-		sprintf(errstr,"Could not read-in kp vector.");
-		return(FAILURE);
-	}
-	
-	// ensure that ip,jp,kp are orthonormal and form a right-handed coordinate system
-	if (   (fabs(bm->ip[0]*bm->ip[0] + bm->ip[1]*bm->ip[1] + bm->ip[2]*bm->ip[2] - 1.0) > 1e-6)
-		|| (fabs(bm->jp[0]*bm->jp[0] + bm->jp[1]*bm->jp[1] + bm->jp[2]*bm->jp[2] - 1.0) > 1e-6)
-		|| (fabs(bm->kp[0]*bm->kp[0] + bm->kp[1]*bm->kp[1] + bm->kp[2]*bm->kp[2] - 1.0) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->jp[0] + bm->ip[1]*bm->jp[1] + bm->ip[2]*bm->jp[2]) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->kp[0] + bm->ip[1]*bm->kp[1] + bm->ip[2]*bm->kp[2]) > 1e-6)
-		|| (fabs(bm->jp[0]*bm->kp[0] + bm->jp[1]*bm->kp[1] + bm->jp[2]*bm->kp[2]) > 1e-6))
-	{
-		sprintf(errstr,"Beam's eye view unit vectors ip, jp, and kp must be orthonormal.");
-		return(FAILURE);
-	}
-
-	// check that cross(ip,jp) = kp
-	if (   (fabs(bm->ip[1]*bm->jp[2] - bm->ip[2]*bm->jp[1] - bm->kp[0]) > 1e-6)
-		|| (fabs(bm->ip[2]*bm->jp[0] - bm->ip[0]*bm->jp[2] - bm->kp[1]) > 1e-6)
-		|| (fabs(bm->ip[0]*bm->jp[1] - bm->ip[1]*bm->jp[0] - bm->kp[2]) > 1e-6))
-	{
-		sprintf(errstr,"Must have cross(ip,jp) = kp for beam's eye view");
-		return(FAILURE);
-	}
-
-	return(SUCCESS);
-}
+/* parse_func.cpp */
+
+/* Checks the validity of the arguments input to the convolution routine and 
+transfers the Matlab-style arguments to the C structures defined in defs.h. */
+
+/* This parse function operates on file inputs rather than on Matlab inputs. */
+
+#include "defs.h"
+
+// Markers that are searched for inside the kernel_filenames file, which is 
+// passed to the load_kernels routine. The line after each of these markers
+// in the kernel_filenames file is a filename corresponding to the marker.
+#define kernel_header_line "kernel_header"
+#define kernel_radii_line "kernel_radii"
+#define kernel_angles_line "kernel_angles"
+#define kernel_energies_line "kernel_energies"
+#define kernel_primary_line "kernel_primary"
+#define kernel_first_scatter_line "kernel_first_scatter"
+#define kernel_second_scatter_line "kernel_second_scatter"
+#define kernel_multiple_scatter_line "kernel_multiple_scatter"
+#define kernel_brem_annih_line "kernel_brem_annih"
+#define kernel_total_line "kernel_total"
+#define kernel_fluence_line "kernel_fluence"
+#define kernel_mu_line "kernel_mu"
+#define kernel_mu_en_line "kernel_mu_en"
+
+// Markers that are searched for inside the geometry_filenames, which is 
+// passed to the load_geometry routine. These have the same meaning as
+// the kernel_filenames markers.
+#define geometry_header "./geometry_files/geometry_header.txt"
+#define geometry_density "./geometry_files/density.bin"
+#define beam_data "./geometry_files/beam_data.txt"
+
+#define geometry_header_line "geometry_header"
+#define geometry_density_line "geometry_density"
+#define beam_data_line "beam_data"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int load_kernels(MONO_KERNELS *mono_kernels, char kernel_filenames[])
+/* Ensures that the kernel files have the following format:
+
+               radii: [1xNradii float]
+              angles: [1xNangles float]
+            energies: [1xNenergies float]
+             primary: [Nradii x Nangles x Nenergies float]
+       first_scatter: [Nradii x Nangles x Nenergies float]
+      second_scatter: [Nradii x Nangles x Nenergies float]
+    multiple_scatter: [Nradii x Nangles x Nenergies float]
+          brem_annih: [Nradii x Nangles x Nenergies float]
+               total: [Nradii x Nangles x Nenergies float]
+          mean_radii: [Nradii x Nangles x Nenergies float] (not used)
+         mean_angles: [Nradii x Nangles x Nenergies float] (not used)
+           helpfield: [any x any char] 
+             fluence: [1xNenergies float]
+                  mu: [1xNenergies float]
+               mu_en: [1xNenergies float]
+
+mistakes or inconsistencies will result in errors.
+
+  Results are then stored in mono_kernels.
+
+The names of the files containing all of these parameters are given
+by the kernel_filenames file.
+
+*/
+{
+	int j,k;
+	int Nenergies, Nangles, Nradii;
+	char str[200];
+	// some strings to hold filenames
+	char header_filename[200], radii_filename[200], angles_filename[200];
+	char energies_filename[200], primary_filename[200], first_scatter_filename[200];
+	char second_scatter_filename[200], multiple_scatter_filename[200];
+	char brem_annih_filename[200], total_filename[200], fluence_filename[200];
+	char mu_filename[200], mu_en_filename[200];
+
+	// flags for file readin
+	int header_flag = 0;
+	int radii_flag = 0;
+	int angles_flag = 0;
+	int energies_flag = 0;
+	int primary_flag = 0;
+	int first_flag = 0;
+	int second_flag = 0;
+	int multiple_flag = 0;
+	int brem_annih_flag = 0;
+	int total_flag = 0;
+	int fluence_flag = 0;
+	int mu_flag = 0;
+	int mu_en_flag = 0;
+
+	FILE *fid;  // generic filename
+	FILE *primary, *first, *second, *multiple, *brem_annih, *total;  // kernel files
+
+	// read in the data filenames
+	if ( (fid = fopen(kernel_filenames,"r")) == NULL)  // open the kernel filenames
+	{
+		sprintf(errstr,"Could not open the kernel filenames file");
+		return(FAILURE);
+	}
+
+	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
+	{
+	  if (!strcmp(str,kernel_header_line))
+	    if (fscanf(fid,"%s\n",header_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_header filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      header_flag = 1;
+	  else if (!strcmp(str,kernel_radii_line))
+	    if (fscanf(fid,"%s\n",radii_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_radii filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      radii_flag = 1;
+	  else if (!strcmp(str,kernel_angles_line))
+	    if (fscanf(fid,"%s\n",angles_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_angles filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+            else
+	      angles_flag = 1;
+	  else if (!strcmp(str,kernel_energies_line))
+        if (fscanf(fid,"%s\n",energies_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_energies filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      energies_flag = 1;
+          else if (!strcmp(str,kernel_fluence_line))
+	    if (fscanf(fid,"%s\n",fluence_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_fluence filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      fluence_flag = 1;
+	  else if (!strcmp(str,kernel_primary_line))
+        if (fscanf(fid,"%s\n",primary_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_primary filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      primary_flag = 1;
+	  else if (!strcmp(str,kernel_first_scatter_line))
+        if (fscanf(fid,"%s\n",first_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_first_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      first_flag = 1;
+	  else if (!strcmp(str,kernel_second_scatter_line))
+	    if (fscanf(fid,"%s\n",second_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_second_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      second_flag = 1;
+	  else if (!strcmp(str,kernel_multiple_scatter_line))
+        if (fscanf(fid,"%s\n",multiple_scatter_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_multiple_scatter filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      multiple_flag = 1;
+	  else if (!strcmp(str,kernel_brem_annih_line))
+	    if (fscanf(fid,"%s\n",brem_annih_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_brem_annih filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else 
+	      brem_annih_flag = 1;
+	  else if (!strcmp(str,kernel_total_line))
+	    if (fscanf(fid,"%s\n",total_filename) != 1)
+	    {
+			sprintf(errstr,"Failed to read-in the kernel_total filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      total_flag = 1;
+	  else if (!strcmp(str,kernel_mu_line))
+	    if (fscanf(fid,"%s\n",mu_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_mu filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      mu_flag = 1;
+	  else if (!strcmp(str,kernel_mu_en_line))
+	    if (fscanf(fid,"%s\n",mu_en_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the kernel_mu_en filename from the kernel filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      mu_en_flag = 1;
+	  else
+	  {   
+		    sprintf(errstr,"Unrecognized string in the kernel filenames file: %s\n",str);
+			return(FAILURE);   
+	  }
+	}
+
+	// confirm that all of the required filenames have been found
+	if (header_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel header filename.");
+	  return(FAILURE);
+	}
+	else if (radii_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel radii filename.");
+	  return(FAILURE);
+	}
+	else if (angles_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel angles filename.");
+	  return(FAILURE);
+	}
+	else if (energies_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel energies filename.");
+	  return(FAILURE);
+	}
+	else if (primary_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a primary kernel filename.");
+	  return(FAILURE);
+	}
+	else if (first_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a first scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (second_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a second scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (multiple_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a multiple scatter kernel filename.");
+	  return(FAILURE);
+	}
+	else if (brem_annih_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a brem_annih kernel filename.");
+	  return(FAILURE);
+	}
+	else if (total_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a total kernel filename.");
+	  return(FAILURE);
+	}
+	else if (fluence_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel fluence filename.");
+	  return(FAILURE);
+	}
+	else if (mu_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel mu filename.");
+	  return(FAILURE);
+	}
+	else if (mu_en_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a kernel mu_en filename.");
+	  return(FAILURE);
+	}
+
+	// read in the expected matrix sizes
+	if ( (fid=fopen(header_filename,"r")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel header file in kernel data folder.");
+		return(FAILURE);
+	}
+	else
+	{   
+		fgets(str,100,fid); // pop-off the first line of the header
+		if (fscanf(fid,"%d %d %d\n",&Nradii,&Nangles,&Nenergies) != 3)
+		{
+			sprintf(errstr,"Incorrect amount of data in kernel header file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	mono_kernels->nkernels = Nenergies;
+
+	// read in the energies, fluences, mu, and mu_en values
+	if ( (fid = fopen(energies_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel energies file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->energy = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel energies.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->energy,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of energies in kernel_energies file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	if ( (fid = fopen(fluence_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel fluences file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->fluence = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel fluences.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->fluence,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of fluences in kernel_fluences file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+	
+	if ( (fid = fopen(mu_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel mu file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->mu = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel mu.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->mu,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of mu values in kernel_mu file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	if ( (fid = fopen(mu_en_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel mu_en file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if ((mono_kernels->mu_en = (float *)malloc(sizeof(float)*Nenergies)) == NULL)
+		{
+			sprintf(errstr,"Failed in memory allocation for kernel mu_en.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->mu_en,sizeof(float),Nenergies,fid) != Nenergies)
+		{
+			sprintf(errstr,"Incorrect number of mu_en values in kernel_mu_en file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	// Only assign memory for bin boundaries for the first kernel. Just point the other
+	// boundary pointers at the values in the first kernel.
+
+	if ( (fid = fopen(radii_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel radii file.");
+		return(FAILURE);
+	}
+	else
+	{
+		mono_kernels->kernel[0].nradii = Nradii;
+		if( (mono_kernels->kernel[0].radial_boundary = (float *)malloc(sizeof(float)*Nradii)) == NULL)
+		{
+			sprintf(errstr,"Failed to allocate memory for radial boundaries.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->kernel[0].radial_boundary,sizeof(float),Nradii,fid) != Nradii)
+		{
+			sprintf(errstr,"Incorrect number of radii values in kernel_radii file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+	
+	if ( (fid = fopen(angles_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing kernel angles file.");
+		return(FAILURE);
+	}
+	else
+	{
+		mono_kernels->kernel[0].ntheta = Nangles;
+		if( (mono_kernels->kernel[0].angular_boundary = (float *)malloc(sizeof(float)*Nangles)) == NULL)
+		{
+			sprintf(errstr,"Failed to allocate memory for angular boundaries.");
+			return(FAILURE);
+		}
+		if( (int)fread(mono_kernels->kernel[0].angular_boundary,sizeof(float),Nangles,fid) != Nangles)
+		{
+			sprintf(errstr,"Incorrect number of angular values in kernel_angles file.");
+			return(FAILURE);
+		}
+		fclose(fid);
+	}
+
+	// allocate space for kernel matrices and copy bin boundaries for other kernel categories
+	for (j=0;j<Nenergies;j++)  // loop through energies
+	{
+		if (j != 0)
+		{
+			mono_kernels->kernel[j].nradii = Nradii;
+			mono_kernels->kernel[j].ntheta = Nangles;
+	
+			mono_kernels->kernel[j].radial_boundary = mono_kernels->kernel[0].radial_boundary;
+			mono_kernels->kernel[j].angular_boundary = mono_kernels->kernel[0].angular_boundary;
+		}
+
+		// allocate space for kernels
+		for (k=0;k<N_KERNEL_CATEGORIES;k++)
+			if ((mono_kernels->kernel[j].matrix[k] 
+				= (float *)malloc(sizeof(float)*Nradii*Nangles*N_KERNEL_CATEGORIES)) == NULL)
+			{
+				sprintf(errstr,"Failed to allocate memory for kernel matrix.");
+				return(FAILURE);
+			}
+	}
+	
+	// load-in the kernels one at a time and fill-up the monoenergetic kernels
+	
+	// open the kernel files
+	if ( (primary = fopen(primary_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing primary kernel.");
+		return(FAILURE);
+	}
+
+	if ( (first = fopen(first_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing first scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (second = fopen(second_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing second scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (multiple = fopen(multiple_scatter_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing multiple scatter kernel.");
+		return(FAILURE);
+	}
+
+	if ( (brem_annih = fopen(brem_annih_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing brem_annih kernel.");
+		return(FAILURE);
+	}
+
+	if ( (total = fopen(total_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Missing total kernel.");
+		return(FAILURE);
+	}
+
+	// loop through all energies, reading the kernel files in to the kernel structures
+	for (j=0;j<Nenergies;j++)
+	{
+		if ( (int)fread(mono_kernels->kernel[j].matrix[0],sizeof(float),Nradii*Nangles,primary) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[1],sizeof(float),Nradii*Nangles,first) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[2],sizeof(float),Nradii*Nangles,second) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[3],sizeof(float),Nradii*Nangles,multiple) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+
+		if ( (int)fread(mono_kernels->kernel[j].matrix[4],sizeof(float),Nradii*Nangles,brem_annih) 
+			!= Nradii*Nangles)
+		{
+			sprintf(errstr,"Could not read the correct number of kernel values.");
+			return(FAILURE);
+		}
+	}
+
+	// close the kernel files
+	fclose(primary);
+	fclose(first);
+	fclose(second);
+	fclose(multiple);
+	fclose(brem_annih);
+
+	return(SUCCESS);
+}
+
+int load_geometry(FLOAT_GRID *density, char geometry_filenames[])
+/* Ensure that the GEOMETRY structure has the following format:
+  Geometry = 
+
+         start: [3 element float]
+    voxel_size: [3 element float]
+          data: [M x N x Q float]
+          beam: [1x1 struct] 
+		  
+ Geometry.beam = 
+
+    ip: [3 element float]
+    jp: [3 element float]
+    kp: [3 element float]
+     y_vec: [3 element float]
+        xp: [float scalar]
+        yp: [float scalar]
+    del_xp: [float scalar]
+    del_yp: [float scalar]
+	   SAD: [float scalar]
+	
+
+	and load the data into memory.  
+
+The names of the files containing the above data are listed in two files:
+geometry_filenames and beam_filenames.  The beam data are stored in a 
+separate file since many dose calculations are done by changing the 
+beam data and leaving the geometry data constant.  This way one can use
+a separate beam file for each beam but the same geometry file.
+*/
+{
+	int Ntotal;
+	char str[200];   // dummy string
+	char header_filename[200], density_filename[200];
+	// flags for filename readin
+	int header_flag = 0;
+	int density_flag = 0;
+	FILE *fid;          // dummy filename
+
+	// read in the geometry filenames
+	if ( (fid = fopen(geometry_filenames,"r")) == NULL)  // open the geometry filenames
+	{
+	  sprintf(errstr,"Could not open the geometry filenames file\n");
+	  return(FAILURE);
+	}
+
+	// read in the non-beam geometric data
+	while (fscanf(fid,"%s\n",str) != EOF)  // read until the end of the file
+	{
+	  if (!strcmp(str,geometry_header_line))
+	    if (fscanf(fid,"%s\n",header_filename) != 1)
+		{
+			sprintf(errstr,"Failed to read-in the geometry_header filename from the geometry filenames file.");
+		}
+	    else
+	      header_flag = 1;
+	  else if (!strcmp(str,geometry_density_line))
+	    if (fscanf(fid,"%s\n",density_filename) != 1)
+		{
+	        sprintf(errstr,"Failed to read-in the geometry_density filename from the geometry filenames file.");
+			return(FAILURE);
+		}
+	    else
+	      density_flag = 1;
+	  else
+	  {   
+			sprintf("Unrecognized string in the geometry filenames file: %s\n",str);
+			return(FAILURE);   
+	  }
+	}
+	
+    // confirm that all of the required filenames have been found
+	if (header_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a geometry header filename.\n");
+	  return(FAILURE);
+	}
+	else if (density_flag == 0)
+	{
+	  sprintf(errstr,"Unable to find a geometry density filename.\n");
+	  return(FAILURE);
+	}
+
+	// read in geometric and beam data
+	if( (fid = fopen(header_filename,"r")) == NULL)
+	{
+		sprintf(errstr,"Could not open geometry header file.");
+		return(FAILURE);
+	}
+	else
+	{
+		// pop-off the first line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%d %d %d\n",&density->x_count,&density->y_count,&density->z_count) != 3)
+		{
+			sprintf(errstr,"Could not read-in data grid size.");
+			return(FAILURE);
+		}
+		
+		// pop-off the next line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header  file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%f %f %f\n",&density->start.x,&density->start.y,&density->start.z) != 3)
+		{
+			sprintf(errstr,"Could not read-in density grid start position.");
+			return(FAILURE);
+		}
+
+		// pop-off the next line of the header file
+		if (fgets(str,100,fid) == NULL) 
+		{
+			sprintf(errstr,"Could not read from geometry header file.");
+			return(FAILURE);
+		}
+
+		// read-in the CT data grid size
+		if (fscanf(fid,"%f %f %f\n",&density->inc.x,&density->inc.y,&density->inc.z) != 3)
+		{
+			sprintf(errstr,"Could not read-in voxel size vector.");
+			return(FAILURE);
+		}
+
+		Ntotal = density->x_count*density->y_count*density->z_count;
+	}
+
+	// read-in the CT density data
+	if( (fid = fopen(density_filename,"rb")) == NULL)
+	{
+		sprintf(errstr,"Could not open CT density file.");
+		return(FAILURE);
+	}
+	else
+	{
+		if( (density->matrix = (float *)malloc(sizeof(float)*Ntotal)) == NULL)
+		{
+			sprintf(errstr,"Unable to allocate space for CT density grid.");
+			return(FAILURE);
+		}
+		else if ((int)fread(density->matrix,sizeof(float),Ntotal,fid) != Ntotal)
+		{
+			sprintf(errstr,"Unable to read-in CT density data.");
+			return(FAILURE);
+		}
+	}
+	return(SUCCESS);
+}
+
+int pop_beam(BEAM *bm, FILE *beamspec_batch_file)
+/*  Pops a beam off of the beamspec_batch_file file and loads it into a BEAM structure.
+
+  Ensure that the beam data file has the following format:
+ Geometry.beam = 
+
+        ip: [3 element float]
+        jp: [3 element float]
+        kp: [3 element float]
+     y_vec: [3 element float]
+        xp: [float scalar]
+        yp: [float scalar]
+    del_xp: [float scalar]
+    del_yp: [float scalar]
+	   SAD: [float scalar]
+	   num: [int scalar]
+	
+	and load the data into memory.  
+*/
+{
+	char str[200];      // dummy string
+
+	// read-in the beam data
+	// pop-off the first line of the beam data file
+
+	// read-in the CT data grid size
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		return(FAILURE);
+	}
+
+	if (fscanf(beamspec_batch_file,"%d\n",&bm->num) != 1)
+	{
+		sprintf(errstr,"Could not read-in beam data.");
+		return(FAILURE);
+	}
+
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the CT data grid size
+	if (fscanf(beamspec_batch_file,"%f %f %f %f %f\n",&bm->SAD,&bm->xp,&bm->yp,&bm->del_xp,&bm->del_yp) != 5)
+	{
+		sprintf(errstr,"Could not read-in beam data.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the source position vector
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->y_vec[0],&bm->y_vec[1],&bm->y_vec[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in source location vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the beam's eye view vectors, ip first
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->ip[0],&bm->ip[1],&bm->ip[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in ip vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the second beam's eye view vector, jp
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->jp[0],&bm->jp[1],&bm->jp[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in jp vector.");
+		return(FAILURE);
+	}
+
+	// pop-off the next line of the beam data file
+	if (fgets(str,100,beamspec_batch_file) == NULL) 
+	{
+		sprintf(errstr,"Could not read from from beam data file.");
+		return(FAILURE);
+	}
+
+	// read-in the third beam's eye view vector, kp
+	if (fscanf(beamspec_batch_file,"%f %f %f\n",&bm->kp[0],&bm->kp[1],&bm->kp[2]) != 3)
+	{
+		sprintf(errstr,"Could not read-in kp vector.");
+		return(FAILURE);
+	}
+	
+	// ensure that ip,jp,kp are orthonormal and form a right-handed coordinate system
+	if (   (fabs(bm->ip[0]*bm->ip[0] + bm->ip[1]*bm->ip[1] + bm->ip[2]*bm->ip[2] - 1.0) > 1e-6)
+		|| (fabs(bm->jp[0]*bm->jp[0] + bm->jp[1]*bm->jp[1] + bm->jp[2]*bm->jp[2] - 1.0) > 1e-6)
+		|| (fabs(bm->kp[0]*bm->kp[0] + bm->kp[1]*bm->kp[1] + bm->kp[2]*bm->kp[2] - 1.0) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->jp[0] + bm->ip[1]*bm->jp[1] + bm->ip[2]*bm->jp[2]) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->kp[0] + bm->ip[1]*bm->kp[1] + bm->ip[2]*bm->kp[2]) > 1e-6)
+		|| (fabs(bm->jp[0]*bm->kp[0] + bm->jp[1]*bm->kp[1] + bm->jp[2]*bm->kp[2]) > 1e-6))
+	{
+		sprintf(errstr,"Beam's eye view unit vectors ip, jp, and kp must be orthonormal.");
+		return(FAILURE);
+	}
+
+	// check that cross(ip,jp) = kp
+	if (   (fabs(bm->ip[1]*bm->jp[2] - bm->ip[2]*bm->jp[1] - bm->kp[0]) > 1e-6)
+		|| (fabs(bm->ip[2]*bm->jp[0] - bm->ip[0]*bm->jp[2] - bm->kp[1]) > 1e-6)
+		|| (fabs(bm->ip[0]*bm->jp[1] - bm->ip[1]*bm->jp[0] - bm->kp[2]) > 1e-6))
+	{
+		sprintf(errstr,"Must have cross(ip,jp) = kp for beam's eye view");
+		return(FAILURE);
+	}
+
+	return(SUCCESS);
+}

+ 345 - 345
src-chtc/raytrace.cpp

@@ -1,345 +1,345 @@
-/* C_RAYTRACE.C ***************************************************************/
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int raytrace(FLOAT_GRID *electron_density_grid,FLOAT_GRID *radiological_depth_grid,
-             POINT point1,POINT point2)
-/*
---------------------------------------------------------------------------------
-   NAME
- 	c_raytrace
- 
-   SYNOPSIS
-        point1 and point2 are the end points of the ray. 
-
-   DESCRIPTION
-        This function traces the ray from point x to point y (in real 
-        coords), assigning depth to any voxels which that ray crosses. The 
-        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
-        1985). This routine will not be understood without thorough reading 
-        of that paper! Point1 and point2 are the start and end points of the 
-        ray, respectively. External structures of type GRID are assumed to 
-        exist, where electron_density_grid are the electron densities, and 
-        radiological_depth_grid is the output grid for these calculations.
-        Voxels in radiological_depth_grid are initially set -ve prior to 
-        calling this function.
- 
-   AUTHOR
-        Written by David C. Murray
-                   University of Waikato
-                   Private Bag 3105
-                   Hamilton
-                   New Zealand
-        and Copyright (1991) to
-                   David C. Murray and Peter W. Hoban,
-                   Cancer Society of New Zealand Inc., and 
-                   University of Waikato.
---------------------------------------------------------------------------------
-*/
-
-{
-/* Variable descriptions:
-   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
-     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
-   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
-   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
-   dx,dy,dz are the widths in cm of the voxels
-*/
-float         x1,y1,z1,
-              x2,y2,z2,
-              xp1,yp1,zp1,
-              dx,dy,dz;
-int           Nx,Ny,Nz;
-
-/*General ray-trace algorithm variables*/
-float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
-float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
-					/*limits of alpha x,y,z parameters*/
-float alpha_min, alpha_max;		/*limits of alpha parameter*/
-int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
-float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
-float *alpha;				/*holds merged set of alpha values*/
-int i_index,j_index,k_index;		/*loop indices for merging alphas*/
-int a;					/*loop counter*/
-int max_index;				/*max index of merged alpha array*/
-float d12;				/*distance between ray end points*/
-float alpha_mid;			/*mid-point of intersection length*/
-float length;				/*intersection length*/
-int i,j,k;				/*indices of voxel with int. length*/
-float rpl = 0.0;			/*radiological path length in cm*/
-float voxel_density;			/*temporary voxel density*/
-float lmax;  // best possible penetration pathlength for a voxel
-float pnorm;  // absolute difference between p1 and p2
-
-/* Assign variables */
-/******************************************************************************/
-x1 = point1.x;
-y1 = point1.y;
-z1 = point1.z;
-x2 = point2.x;
-y2 = point2.y;
-z2 = point2.z;
-Nx = electron_density_grid->x_count + 1;
-Ny = electron_density_grid->y_count + 1;
-Nz = electron_density_grid->z_count + 1;
-dx = electron_density_grid->inc.x;
-dy = electron_density_grid->inc.y;
-dz = electron_density_grid->inc.z;
-
-// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
-xp1 = electron_density_grid->start.x - 0.5*dx;
-yp1 = electron_density_grid->start.y - 0.5*dy;
-zp1 = electron_density_grid->start.z - 0.5*dz;
-
-pnorm = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
-
-// this is the largest pathlength possible for a ray through a voxel:
-lmax = sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
-
-/* Calculate xpN,ypN,zpN */
-/******************************************************************************/
-xpN = xp1 + (Nx-1)*dx;
-ypN = yp1 + (Ny-1)*dy;
-zpN = zp1 + (Nz-1)*dz;
-
-/*Calculate alpha_min and alpha_max*/
-/******************************************************************************/
-/*Avoid division by zero*/
-if (x1==x2)
-  x2 += 0.00001;
-if (y1==y2)
-  y2 += 0.00001;
-if (z1==z2)
-  z2 += 0.00001;
-if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
-{
-	sprintf(errstr,"Error - ray trace region too small.");
-	return(FAILURE);
-}
-
-alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
-                                                      : ((xpN-x1)/(x2-x1));
-alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
-                                                      : ((ypN-y1)/(y2-y1));
-alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
-                                                      : ((zpN-z1)/(z2-z1));
-alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
-if (alpha_z_min>alpha_min) 
-  alpha_min = alpha_z_min;
-if (alpha_min<0)
-  alpha_min = 0;
-alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
-if (alpha_z_max<alpha_max) 
-  alpha_max = alpha_z_max;
-if (alpha_max>1)
-  alpha_max = 1;
-
-// Monitor lines...
-/*
-printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
-                alpha_x_min,alpha_y_min,alpha_z_min);
-printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
-                alpha_x_max,alpha_y_max,alpha_z_max);
-printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
-printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx); */
-
-/*Determine the ranges of i,j,k indices*/
-/******************************************************************************/
-/*The following assignments require conversion from float to integer types*/
-/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
-/*functions convert to the correct value. Note that the range of these*/
-/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
-		
-i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
-                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
-i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
-                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
-j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
-                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
-j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
-                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
-k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
-                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
-k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
-                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
-
-/*Monitor lines...
-fprintf(stdout,"    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
-fprintf(stdout,"    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max);
-*/
-/*Generate sets of alpha values,reversing order if necessary*/
-/******************************************************************************/
-/*allocate array space on stack*/
-if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
-	return(FAILURE);
-}
-
-if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
-	return(FAILURE);
-}
-
-/* 
-printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
-printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
-printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
- 
-if (i_min <= i_max)
-  if (x2>x1)
-    {
-    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=1;a<=i_max-i_min;a++)
-      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
-    }
-  else
-    {
-    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
-    for (a=i_max-i_min-1;a>=0;a--)
-      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
-    }
-alpha_x[i_max-i_min+1] = 10000.0;
-if (j_min <= j_max)
-  if (y2>y1)
-    {
-    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=1;a<=j_max-j_min;a++)
-      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
-    }
-  else
-    {
-    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
-    for (a=j_max-j_min-1;a>=0;a--)
-      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
-    }
-alpha_y[j_max-j_min+1] = 10001.0;
-if (k_min <= k_max)
-  if (z2>z1)
-    {
-    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=1;a<=k_max-k_min;a++)
-      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
-    }
-  else
-    {
-    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
-    for (a=k_max-k_min-1;a>=0;a--)
-      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
-  }
-alpha_z[k_max-k_min+1] = 10002.0; 
-
-
-/*Monitor lines...
-if (i_max<i_min)
-  fprintf(stdout,"    No alpha_x values\n");
-else
-  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
-                 alpha_x[0],alpha_x[i_max-i_min]);
-if (j_max<j_min)
-  fprintf(stdout,"    No alpha_y values\n");
-else
-  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
-                 alpha_y[0],alpha_y[j_max-j_min]);
-if (k_max<k_min)
-  fprintf(stdout,"    No alpha_z values\n");
-else
-  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
-                 alpha_z[0],alpha_z[k_max-k_min]);
-*/
-/*Generate merged set of alpha values*/
-
-
-/******************************************************************************/
-if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
-{
-	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
-	return(FAILURE);
-}
-
-max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
-alpha[0] = alpha_min;
-i_index = 0;
-j_index = 0;
-k_index = 0;
-for (a=1;a<=max_index-1;a++)
-  if (alpha_x[i_index]<alpha_y[j_index])
-    if (alpha_x[i_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_x[i_index];
-      i_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-  else
-    if (alpha_y[j_index]<alpha_z[k_index])
-      {
-      alpha[a] = alpha_y[j_index];
-      j_index += 1;
-      }
-    else
-      {
-      alpha[a] = alpha_z[k_index];
-      k_index += 1;
-      }
-alpha[max_index] = alpha_max;
-free(alpha_x);				//deallocate temp array storage
-free(alpha_y);
-free(alpha_z);
-/*Monitor lines...
-fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
-for (a=0;a<=max_index;a++)
-  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
-*/
-/*Calculate voxel lengths and indices, and assign radiological depth*/
-/******************************************************************************/
-d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
-					//d12 is distance between ray end pts
-// printf("made it this far in raytrace.\n");
-for (a=1;a<=max_index;a++)
-  {
-  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
-  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
-    {
-    alpha_mid = (alpha[a]+alpha[a-1])/2.0;
-					//alpha_mid is middle of int. length
-    i = (int) floor((x1 + alpha_mid*(x2-x1) - xp1)/dx);
-    j = (int) floor((y1 + alpha_mid*(y2-y1) - yp1)/dy);
-    k = (int) floor((z1 + alpha_mid*(z2-z1) - zp1)/dz);
-					//i,j,k are indices of voxel
-
-    // Remember that this function traces only a single ray.
-    // rpl has been set to zero during initialisation.
-
-    voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
-    rpl += length * voxel_density/2.0;  // add first half of int. length
-    // store pathlength only if the voxel is intersected almost directly
-	// by the ray
-    if (length>=0.75/2*lmax && GRID_VALUE(radiological_depth_grid,i,j,k)<0.0)
-      GRID_VALUE(radiological_depth_grid, i, j, k) = rpl;
-    
-    rpl += length * voxel_density/2.0;  //add second half of int. length  
-    }    
-  } 
-free(alpha); 			//deallocate remaining array storage 
-
-return(SUCCESS);
-
-} 					/*End of s_raytrace routine*/
+/* C_RAYTRACE.C ***************************************************************/
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int raytrace(FLOAT_GRID *electron_density_grid,FLOAT_GRID *radiological_depth_grid,
+             POINT point1,POINT point2)
+/*
+--------------------------------------------------------------------------------
+   NAME
+ 	c_raytrace
+ 
+   SYNOPSIS
+        point1 and point2 are the end points of the ray. 
+
+   DESCRIPTION
+        This function traces the ray from point x to point y (in real 
+        coords), assigning depth to any voxels which that ray crosses. The 
+        technique used is that described by Siddon R.L. (Med Phys 12 (2), 
+        1985). This routine will not be understood without thorough reading 
+        of that paper! Point1 and point2 are the start and end points of the 
+        ray, respectively. External structures of type GRID are assumed to 
+        exist, where electron_density_grid are the electron densities, and 
+        radiological_depth_grid is the output grid for these calculations.
+        Voxels in radiological_depth_grid are initially set -ve prior to 
+        calling this function.
+ 
+   AUTHOR
+        Written by David C. Murray
+                   University of Waikato
+                   Private Bag 3105
+                   Hamilton
+                   New Zealand
+        and Copyright (1991) to
+                   David C. Murray and Peter W. Hoban,
+                   Cancer Society of New Zealand Inc., and 
+                   University of Waikato.
+--------------------------------------------------------------------------------
+*/
+
+{
+/* Variable descriptions:
+   x1,x2,y1,y2,z1,z2 are the coordinates of the ray end points 
+     (i.e. (x1,y1,z1)=source, (x2,y2,z2)=point beyond phantom) 
+   xp1,yp1,zp1 are the real coords of voxel region origin (in cm) 
+   Nx,Ny,Nz are (no. of voxels + 1) in each direction 
+   dx,dy,dz are the widths in cm of the voxels
+*/
+float         x1,y1,z1,
+              x2,y2,z2,
+              xp1,yp1,zp1,
+              dx,dy,dz;
+int           Nx,Ny,Nz;
+
+/*General ray-trace algorithm variables*/
+float xpN, ypN, zpN;			/*real coords in cm of region limits*/ 
+float alpha_x_min,alpha_y_min,alpha_z_min,alpha_x_max,alpha_y_max,alpha_z_max;
+					/*limits of alpha x,y,z parameters*/
+float alpha_min, alpha_max;		/*limits of alpha parameter*/
+int i_min,i_max,j_min,j_max,k_min,k_max;/*limits of indices for x,y,z dirns*/
+float *alpha_x,*alpha_y,*alpha_z;	/*hold sets of x,y,z alpha values*/
+float *alpha;				/*holds merged set of alpha values*/
+int i_index,j_index,k_index;		/*loop indices for merging alphas*/
+int a;					/*loop counter*/
+int max_index;				/*max index of merged alpha array*/
+float d12;				/*distance between ray end points*/
+float alpha_mid;			/*mid-point of intersection length*/
+float length;				/*intersection length*/
+int i,j,k;				/*indices of voxel with int. length*/
+float rpl = 0.0;			/*radiological path length in cm*/
+float voxel_density;			/*temporary voxel density*/
+float lmax;  // best possible penetration pathlength for a voxel
+float pnorm;  // absolute difference between p1 and p2
+
+/* Assign variables */
+/******************************************************************************/
+x1 = point1.x;
+y1 = point1.y;
+z1 = point1.z;
+x2 = point2.x;
+y2 = point2.y;
+z2 = point2.z;
+Nx = electron_density_grid->x_count + 1;
+Ny = electron_density_grid->y_count + 1;
+Nz = electron_density_grid->z_count + 1;
+dx = electron_density_grid->inc.x;
+dy = electron_density_grid->inc.y;
+dz = electron_density_grid->inc.z;
+
+// (xp1,yp1,zp1) are the locations of the first grid planes for each dimension
+xp1 = electron_density_grid->start.x - 0.5*dx;
+yp1 = electron_density_grid->start.y - 0.5*dy;
+zp1 = electron_density_grid->start.z - 0.5*dz;
+
+pnorm = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
+
+// this is the largest pathlength possible for a ray through a voxel:
+lmax = sqrt(pow((x2-x1)*dx,2.0f)+pow((y2-y1)*dy,2.0f)+pow((z2-z1)*dz,2.0f))/pnorm;
+
+/* Calculate xpN,ypN,zpN */
+/******************************************************************************/
+xpN = xp1 + (Nx-1)*dx;
+ypN = yp1 + (Ny-1)*dy;
+zpN = zp1 + (Nz-1)*dz;
+
+/*Calculate alpha_min and alpha_max*/
+/******************************************************************************/
+/*Avoid division by zero*/
+if (x1==x2)
+  x2 += 0.00001;
+if (y1==y2)
+  y2 += 0.00001;
+if (z1==z2)
+  z2 += 0.00001;
+if ((fabs(x1-x2)<dx) && (fabs(y1-y2)<dy) && (fabs(z1-z2)<dz))
+{
+	sprintf(errstr,"Error - ray trace region too small.");
+	return(FAILURE);
+}
+
+alpha_x_min = (((xp1-x1)/(x2-x1))<((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_min = (((yp1-y1)/(y2-y1))<((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_min = (((zp1-z1)/(z2-z1))<((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_x_max = (((xp1-x1)/(x2-x1))>((xpN-x1)/(x2-x1))) ? ((xp1-x1)/(x2-x1)) 
+                                                      : ((xpN-x1)/(x2-x1));
+alpha_y_max = (((yp1-y1)/(y2-y1))>((ypN-y1)/(y2-y1))) ? ((yp1-y1)/(y2-y1)) 
+                                                      : ((ypN-y1)/(y2-y1));
+alpha_z_max = (((zp1-z1)/(z2-z1))>((zpN-z1)/(z2-z1))) ? ((zp1-z1)/(z2-z1)) 
+                                                      : ((zpN-z1)/(z2-z1));
+alpha_min = (alpha_x_min>alpha_y_min) ? alpha_x_min : alpha_y_min;
+if (alpha_z_min>alpha_min) 
+  alpha_min = alpha_z_min;
+if (alpha_min<0)
+  alpha_min = 0;
+alpha_max = (alpha_x_max<alpha_y_max) ? alpha_x_max : alpha_y_max;
+if (alpha_z_max<alpha_max) 
+  alpha_max = alpha_z_max;
+if (alpha_max>1)
+  alpha_max = 1;
+
+// Monitor lines...
+/*
+printf("    alpha_x,y,z_min: %7.4f %7.4f %7.4f\n",
+                alpha_x_min,alpha_y_min,alpha_z_min);
+printf("    alpha_x,y,z_max: %7.4f %7.4f %7.4f\n",
+                alpha_x_max,alpha_y_max,alpha_z_max);
+printf("    alpha_min,alpha_max: %7.4f %7.4f\n",alpha_min,alpha_max);
+printf("Nx, xpN, x2,x1, dx = %d %5.2f %5.2f %5.2f %5.2f\n",Nx,xpN,x2,x1,dx); */
+
+/*Determine the ranges of i,j,k indices*/
+/******************************************************************************/
+/*The following assignments require conversion from float to integer types*/
+/*The value 0.001 is added/subtracted to ensure that the ceiling and floor*/
+/*functions convert to the correct value. Note that the range of these*/
+/*variables is from 1 to Nx,Ny,Nz, NOT 0 to Nx-1,Ny-1,Nz-1*/
+		
+i_min = (x2>x1) ? (int) ceil((float) Nx - (xpN-alpha_min*(x2-x1)-x1)/dx-0.001)
+                : (int) ceil((float) Nx - (xpN-alpha_max*(x2-x1)-x1)/dx-0.001);
+i_max = (x2>x1) ? (int) floor(1.0000 + (x1+alpha_max*(x2-x1)-xp1)/dx+0.001)
+                : (int) floor(1.0000 + (x1+alpha_min*(x2-x1)-xp1)/dx+0.001);
+j_min = (y2>y1) ? (int) ceil((float) Ny - (ypN-alpha_min*(y2-y1)-y1)/dy-0.001)
+                : (int) ceil((float) Ny - (ypN-alpha_max*(y2-y1)-y1)/dy-0.001);
+j_max = (y2>y1) ? (int) floor(1.0000 + (y1+alpha_max*(y2-y1)-yp1)/dy+0.001)
+                : (int) floor(1.0000 + (y1+alpha_min*(y2-y1)-yp1)/dy+0.001);
+k_min = (z2>z1) ? (int) ceil((float) Nz - (zpN-alpha_min*(z2-z1)-z1)/dz-0.001)
+                : (int) ceil((float) Nz - (zpN-alpha_max*(z2-z1)-z1)/dz-0.001);
+k_max = (z2>z1) ? (int) floor(1.0000 + (z1+alpha_max*(z2-z1)-zp1)/dz+0.001)
+                : (int) floor(1.0000 + (z1+alpha_min*(z2-z1)-zp1)/dz+0.001); 
+
+/*Monitor lines...
+fprintf(stdout,"    i,j,k_min: %3d %3d %3d\n",i_min,j_min,k_min);
+fprintf(stdout,"    i,j,k_max: %3d %3d %3d\n",i_max,j_max,k_max);
+*/
+/*Generate sets of alpha values,reversing order if necessary*/
+/******************************************************************************/
+/*allocate array space on stack*/
+if ((alpha_x = (float*) calloc(Nx+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_x allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_y = (float*) calloc(Ny+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_y allocation.");
+	return(FAILURE);
+}
+
+if ((alpha_z = (float*) calloc(Nz+1,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha_z allocation.");
+	return(FAILURE);
+}
+
+/* 
+printf("Nx = %d, i_min = %d, i_max = %d\n",Nx,i_min,i_max);
+printf("Ny = %d, j_min = %d, j_max = %d\n",Ny,j_min,j_max);
+printf("Nz = %d, k_min = %d, k_max = %d\n",Nz,k_min,k_max); */
+ 
+if (i_min <= i_max)
+  if (x2>x1)
+    {
+    alpha_x[0] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=1;a<=i_max-i_min;a++)
+      alpha_x[a] = alpha_x[a-1]+dx/(x2-x1);
+    }
+  else
+    {
+    alpha_x[i_max-i_min] = ((xp1+(i_min-1)*dx)-x1)/(x2-x1);
+    for (a=i_max-i_min-1;a>=0;a--)
+      alpha_x[a] = alpha_x[a+1]+(dx/(x2-x1));
+    }
+alpha_x[i_max-i_min+1] = 10000.0;
+if (j_min <= j_max)
+  if (y2>y1)
+    {
+    alpha_y[0] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=1;a<=j_max-j_min;a++)
+      alpha_y[a] = alpha_y[a-1]+dy/(y2-y1);
+    }
+  else
+    {
+    alpha_y[j_max-j_min] = ((yp1+(j_min-1)*dy)-y1)/(y2-y1);
+    for (a=j_max-j_min-1;a>=0;a--)
+      alpha_y[a] = alpha_y[a+1]+(dy/(y2-y1));
+    }
+alpha_y[j_max-j_min+1] = 10001.0;
+if (k_min <= k_max)
+  if (z2>z1)
+    {
+    alpha_z[0] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=1;a<=k_max-k_min;a++)
+      alpha_z[a] = alpha_z[a-1]+(dz/(z2-z1));
+    }
+  else
+    {
+    alpha_z[k_max-k_min] = ((zp1+(k_min-1)*dz)-z1)/(z2-z1);
+    for (a=k_max-k_min-1;a>=0;a--)
+      alpha_z[a] = alpha_z[a+1]+(dz/(z2-z1));
+  }
+alpha_z[k_max-k_min+1] = 10002.0; 
+
+
+/*Monitor lines...
+if (i_max<i_min)
+  fprintf(stdout,"    No alpha_x values\n");
+else
+  fprintf(stdout,"    First & last alpha_x values: %7.4f %7.4f\n",
+                 alpha_x[0],alpha_x[i_max-i_min]);
+if (j_max<j_min)
+  fprintf(stdout,"    No alpha_y values\n");
+else
+  fprintf(stdout,"    First & last alpha_y values: %7.4f %7.4f\n",
+                 alpha_y[0],alpha_y[j_max-j_min]);
+if (k_max<k_min)
+  fprintf(stdout,"    No alpha_z values\n");
+else
+  fprintf(stdout,"    First & last alpha_z values: %7.4f %7.4f\n",
+                 alpha_z[0],alpha_z[k_max-k_min]);
+*/
+/*Generate merged set of alpha values*/
+
+
+/******************************************************************************/
+if ((alpha = (float*) calloc(Nx+Ny+Nz+3,sizeof(float))) == NULL)
+{
+	sprintf(errstr,"Error - insufficient heap for alpha allocation.");
+	return(FAILURE);
+}
+
+max_index = (i_max-i_min+1)+(j_max-j_min+1)+(k_max-k_min+1)+1;
+alpha[0] = alpha_min;
+i_index = 0;
+j_index = 0;
+k_index = 0;
+for (a=1;a<=max_index-1;a++)
+  if (alpha_x[i_index]<alpha_y[j_index])
+    if (alpha_x[i_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_x[i_index];
+      i_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+  else
+    if (alpha_y[j_index]<alpha_z[k_index])
+      {
+      alpha[a] = alpha_y[j_index];
+      j_index += 1;
+      }
+    else
+      {
+      alpha[a] = alpha_z[k_index];
+      k_index += 1;
+      }
+alpha[max_index] = alpha_max;
+free(alpha_x);				//deallocate temp array storage
+free(alpha_y);
+free(alpha_z);
+/*Monitor lines...
+fprintf(stdout,"    Number of elements in merged set = %4d\n",max_index+1);
+for (a=0;a<=max_index;a++)
+  fprintf(stdout,"      Element %3d = %7.5f\n",a,alpha[a]);
+*/
+/*Calculate voxel lengths and indices, and assign radiological depth*/
+/******************************************************************************/
+d12 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
+					//d12 is distance between ray end pts
+// printf("made it this far in raytrace.\n");
+for (a=1;a<=max_index;a++)
+  {
+  length = d12*(alpha[a]-alpha[a-1]);	//length is voxel intersection length
+  if (fabs(length)>0.01)		//do not process unless > 0.01 cm
+    {
+    alpha_mid = (alpha[a]+alpha[a-1])/2.0;
+					//alpha_mid is middle of int. length
+    i = (int) floor((x1 + alpha_mid*(x2-x1) - xp1)/dx);
+    j = (int) floor((y1 + alpha_mid*(y2-y1) - yp1)/dy);
+    k = (int) floor((z1 + alpha_mid*(z2-z1) - zp1)/dz);
+					//i,j,k are indices of voxel
+
+    // Remember that this function traces only a single ray.
+    // rpl has been set to zero during initialisation.
+
+    voxel_density = GRID_VALUE(electron_density_grid,i,j,k);
+    rpl += length * voxel_density/2.0;  // add first half of int. length
+    // store pathlength only if the voxel is intersected almost directly
+	// by the ray
+    if (length>=0.75/2*lmax && GRID_VALUE(radiological_depth_grid,i,j,k)<0.0)
+      GRID_VALUE(radiological_depth_grid, i, j, k) = rpl;
+    
+    rpl += length * voxel_density/2.0;  //add second half of int. length  
+    }    
+  } 
+free(alpha); 			//deallocate remaining array storage 
+
+return(SUCCESS);
+
+} 					/*End of s_raytrace routine*/

+ 301 - 301
src-chtc/terma_dose_masks.cpp

@@ -1,301 +1,301 @@
-/* terma_dose_masks.cpp */
-
-/* All voxels that lie within a cylinder of radius RAPERTURE + RSAFE, centered
-on the central beam axis, are marked in the dose_mask grid.  These voxels will
-be used in the dose calculation.  The voxels that are marked in the terma_mask
-grid are a subset of those that are marked in the dose_mask grid. The terma_mask
-grid contains values that specify the fraction of each voxel that lies inside
-of the beam aperture in the beam's eye view plane, which exists at a distance
-SAD from the x-ray source location. */
-
-/* Determination of voxel "insideness" for the terma_mask:
-If it is discovered that a voxel is intersected by an aperture boundary in the
-beam's eye view plane, then that voxel is broken-up into Mus x Nus x Qus sub-
-voxels (upsampled).  The fraction of the sub-voxels that lie inside the beam
-aperture in the beam's eye view then becomes the insideness for that voxel. */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int terma_dose_masks(FLOAT_GRID *terma_mask, FLOAT_GRID *dose_mask, BEAM *bm)
-// The user must allocate space for terma_mask and dose_mask before calling 
-// this function.
-// The validity of all of the arguments to this function are assumed to be 
-// checked with the parse_func, which acts as a gatekeeper for the convolution
-// program.
-{
-	// scalars
-	int i,j,k,m;     // indices
-	int ius,jus,kus;  // upsample voxel indices
-	int M,N,Q;     // grid dimensions
-	float dx,dy,dz;  // voxel dimensions
-	float xp,yp,SAD; // aperture center in ip,jp,kp coordinate system
-	float xsub,ysub,zsub;  // coordinates of sub-voxels
-	float del_xp,del_yp; // width of beamlet field in plane at SAD
-	float Rmax,Rcurr,Rcyl,Rvox,Rcyl_sqr,Rproj;
-	float eta,gamma,delta;  // dummy variables
-
-	// vectors
-	float *x,*y,*z;  // x,y,z coordinate vectors
-	float *dxus,*dyus,*dzus;  // upsample vectors
-	float *y_vec,*ip,*jp,*kp,*d_hat;  // beam vectors
-
-	// matrices
-	float **c;  // matrix of the 8 corners of voxel grid
-	
-	// Ensure that upsample factors are all greater than zero
-	if (Mus < 1 || Nus < 1 || Qus < 1)
-	{
-		sprintf(errstr,"Upsample factors must all be greater than zero.");
-		return(FAILURE);
-	}
-
-	// record the sizes of terma_mask and dose_mask
-	M = terma_mask->x_count;
-	N = terma_mask->y_count;
-	Q = terma_mask->z_count;
-
-	if (M != dose_mask->x_count || N != dose_mask->y_count 
-		|| Q != dose_mask->z_count)
-	{
-		sprintf(errstr,"dose_mask and terma_mask dimensions are incompatible.");
-		return(FAILURE);
-	}
-
-	dx = terma_mask->inc.x;
-	dy = terma_mask->inc.y;
-	dz = terma_mask->inc.z;
-	
-	// initialize vectors
-	x = fvector(0,M-1);
-	y = fvector(0,N-1);
-	z = fvector(0,Q-1);
-
-	dxus = fvector(0,Mus-1);
-	dyus = fvector(0,Nus-1);
-	dzus = fvector(0,Qus-1);
-
-	y_vec = fvector(0,2);
-	ip = fvector(0,2);
-	jp = fvector(0,2);
-	kp = fvector(0,2);
-	d_hat = fvector(0,2);
-
-	// initialize matrices
-	c = fmatrix(0,7,0,2);
-
-	// fill-in the voxel coordinate vectors
-	for (i=0;i<M;i++) x[i] = terma_mask->start.x + (float)i*dx;
-	for (j=0;j<N;j++) y[j] = terma_mask->start.y + (float)j*dy;
-	for (k=0;k<Q;k++) z[k] = terma_mask->start.z + (float)k*dz;
-
-	// fill-in the upsample vectors
-	// For a voxel at (i,j,k), the xyz coordinates of a sub-voxel (ius,jus,kus)
-	// are (x[i] + dxus[ius], y[j] + dyus[jus], z[k] + dzus[k])
-	dxus[0] = -0.5*dx*(1-1/Mus);
-	for (ius=1;ius<Mus;ius++)  dxus[ius] = dxus[ius-1] + dx/Mus;
-
-	dyus[0] = -0.5*dy*(1-1/Nus);
-	for (jus=1;jus<Nus;jus++) dyus[jus] = dyus[jus-1] + dy/Nus;
-
-	dzus[0] = -0.5*dz*(1-1/Qus);
-	for (kus=1;kus<Qus;kus++) dzus[kus] = dzus[kus-1] + dz/Qus;
-
-	// rewrite beam vectors for quick reference later
-	y_vec[0] = bm->y_vec[0];
-	y_vec[1] = bm->y_vec[1];
-	y_vec[2] = bm->y_vec[2];
-
-	// coordinate system in beam's eye view
-	for (j=0;j<3;j++) ip[j] = bm->ip[j];
-	for (j=0;j<3;j++) jp[j] = bm->jp[j];
-	for (j=0;j<3;j++) kp[j] = bm->kp[j];
-
-	// aperture center in beam's eye view
-	xp = bm->xp;
-	yp = bm->yp;
-
-	// aperture size in beam's eye view
-	del_xp = bm->del_xp;
-	del_yp = bm->del_yp;
-
-	// source-axis distance of the beam
-	SAD = bm->SAD;
-
-	// calculate the max distance between the source vector and each grid corner
-	Rmax = 0.0;
-	
-	// the the matrix c with the coordinates of the eight corners of the grid.
-	for (i=0;i<=1;i++)
-	  for (j=0;j<=1;j++)
-	    for (k=0;k<=1;k++)
-		{ 
-		  //                     0 => lower corners         1 => upper corners
-		  c[i+j*2+k*4][0] = (1-(float)i)*(x[0]-dx/2.0) + (float)i*(x[M-1]+dx/2.0);
-		  c[i+j*2+k*4][1] = (1-(float)j)*(y[0]-dy/2.0) + (float)j*(y[N-1]+dy/2.0);
-		  c[i+j*2+k*4][2] = (1-(float)k)*(z[0]-dz/2.0) + (float)k*(z[Q-1]+dz/2.0);
-		}
-
-	// find which corner is the farthest from the source
-	for (m=0;m<=7;m++)
-	{
-		Rcurr = sqrt(pow(y_vec[0] - c[m][0],2.0f)
-			       + pow(y_vec[1] - c[m][1],2.0f)
-				   + pow(y_vec[2] - c[m][2],2.0f));
-		if (Rcurr > Rmax)
-			Rmax = Rcurr;
-	}
-
-	// Fill the dose_mask
-
-	// Radius of cylinder about y_vec + kp that will contain all voxels
-	// to be used in the dose calculation.
-	Rcyl = sqrt(del_xp*del_xp + del_yp*del_yp)*Rmax/SAD;  // project Rmax to aperture plane
-	Rcyl_sqr = Rcyl*Rcyl + RSAFE*RSAFE;  // add an empirical safety margin to the radius squared
-
-	// calculate the true source direction
-	// d_hat points at the center of the aperture from the source location
-	d_hat[0] = xp*ip[0] + yp*jp[0] + SAD*kp[0];
-	d_hat[1] = xp*ip[1] + yp*jp[1] + SAD*kp[1];
-	d_hat[2] = xp*ip[2] + yp*jp[2] + SAD*kp[2];
-
-	// normalize d_hat so it's a true "hat" vector
-	delta = sqrt(d_hat[0]*d_hat[0] + d_hat[1]*d_hat[1] + d_hat[2]*d_hat[2]);
-	d_hat[0] = d_hat[0]/delta;
-	d_hat[1] = d_hat[1]/delta;
-	d_hat[2] = d_hat[2]/delta;
-
-	for (k=0;k<Q;k++)
-	 for (j=0;j<N;j++)
-	  for (i=0;i<M;i++)
-	  {
-		  // squared distance between the voxel and the source:
-		  eta = (x[i] - y_vec[0])*(x[i] - y_vec[0])
-			  + (y[j] - y_vec[1])*(y[j] - y_vec[1])
-			  + (z[k] - y_vec[2])*(z[k] - y_vec[2]);
-
-		  // squared distance between the voxel and the source along source direction, 
-	      // y_vec + kp:
-		  gamma = pow((x[i] - y_vec[0])*d_hat[0]
-				    + (y[j] - y_vec[1])*d_hat[1]
-				    + (z[k] - y_vec[2])*d_hat[2],2.0f);
-
-		  // printf("%lf %lf\n",eta, gamma);
-
-		  // squared difference between the voxel and the axis of the cylinder
-		  delta = eta - gamma;
-
-		  // If the voxel is inside the cylinder about y_vec + ip of radius Rcyl plus
-		  // a safety margin then mark it in dose_mask.
-		  if (delta <= Rcyl_sqr)
-			  GRID_VALUE(dose_mask,i,j,k) = 1.0;
-		  else
-			  GRID_VALUE(dose_mask,i,j,k) = 0.0;
-	  }
-
-	// Fill the terma_mask, including the insideness of each voxel
-
-	// Each voxel is enclosed with in a sphere of the following radius:
-	Rvox = 0.5*sqrt(dx*dx + dy*dy + dz*dz);
-
-	for (i=0;i<M;i++)
-	 for (j=0;j<N;j++)
-	  for (k=0;k<Q;k++)
-	   // deal only with voxels that are marked in the dose_mask
-	   if (GRID_VALUE(dose_mask,i,j,k) > 0.0)
-	   {
-		 // distance between source and voxel in the kp direction
-	     delta = kp[0]*(x[i] - y_vec[0])
-               + kp[1]*(y[j] - y_vec[1])
-               + kp[2]*(z[k] - y_vec[2]);
-
-		 // voxel's projected offset on the aperture plane in the ip direction:
-		 eta = (SAD/delta)*(  ip[0]*(x[i] - y_vec[0])
-				            + ip[1]*(y[j] - y_vec[1])
-						    + ip[2]*(z[k] - y_vec[2])) - xp;
-		 // voxel's projected offset on the aperture plane in the jp direction:
-		 gamma = (SAD/delta)*(  jp[0]*(x[i] - y_vec[0])
-				              + jp[1]*(y[j] - y_vec[1])
-						      + jp[2]*(z[k] - y_vec[2])) - yp;
-
-		 // take absolute value of offsets
-		 eta = fabs(eta);
-		 gamma = fabs(gamma);
-
-		 Rproj = Rvox*SAD/delta;  // voxel radius projected to plane at SAD
-
-		 // Determine where the voxel lies with respect to the aperture:
-		 if (eta <= 0.5*del_xp+Rproj && gamma <= 0.5*del_yp+Rproj)
-		 // voxel is inside aperture plus a half-voxel margin:
-			if (eta >= 0.5*del_xp-Rproj || gamma >= 0.5*del_yp-Rproj)
-		    // voxel is between the aperture plus/minus a half-voxel margin:
-			// (true at this point if the voxel size is larger than the aperture size)
-			{
-			    // Determine insideness of the voxel by breaking it up
-				// into subvoxels and projecting the parts to the aperture plane.
-				m = 0;  // number of subvoxels inside aperture
-	            // project each subvoxel onto the aperture at SAD
-		        for (ius=0;ius<Mus;ius++)
-			     for (jus=0;jus<Nus;jus++)
-			      for (kus=0;kus<Qus;kus++)
-				  {
-			        // find the center of the subvoxel
-			        xsub = x[i] + dxus[ius];
-			        ysub = y[j] + dyus[jus];
-			        zsub = z[k] + dzus[kus];
-
-			        // project the subvoxel onto the aperture
-			        // distance between source and subvoxel in the kp direction
-			        delta = kp[0]*(xsub - y_vec[0])
-				          + kp[1]*(ysub - y_vec[1])
-					      + kp[2]*(zsub - y_vec[2]);
-
-			        // projected offset on aperture plane in the ip direction:
-			        eta = (SAD/delta)*(  ip[0]*(xsub - y_vec[0])
-				                       + ip[1]*(ysub - y_vec[1])
-								       + ip[2]*(zsub - y_vec[2])) - xp;
-			        // projected offset on aperture plane in the jp direction:
-			        gamma = (SAD/delta)*(  jp[0]*(xsub - y_vec[0])
-				                         + jp[1]*(ysub - y_vec[1])
-								         + jp[2]*(zsub - y_vec[2])) - yp;
-
-		            eta = fabs(eta);
-			        gamma = fabs(gamma);
-
-			        // check if the subvoxel is inside the aperture at SAD
-			        if (eta <= 0.5*del_xp && gamma <= 0.5*del_yp)
-				       m++;
-				  }
-
-		        // the fraction of subvoxels inside the aperture becomes the insidness
-	            GRID_VALUE(terma_mask,i,j,k) = (float)m/(float)(Mus*Nus*Qus);
-			}
-			else
-			// voxel is inside the aperture minus a half-voxel margin
-				GRID_VALUE(terma_mask,i,j,k) = 1.0;
-		 else
-		 // voxel outside the aperture plus the half-voxel margin
-		    GRID_VALUE(terma_mask,i,j,k) = 0.0;
-	   }
-
-	// free vectors
-	free_fvector(x,0,M-1);
-	free_fvector(y,0,N-1);
-	free_fvector(z,0,Q-1);
-
-	free_fvector(dxus,0,Mus-1);
-	free_fvector(dyus,0,Nus-1);
-	free_fvector(dzus,0,Qus-1);
-
-	free_fvector(y_vec,0,2);
-	free_fvector(ip,0,2);
-	free_fvector(jp,0,2);
-	free_fvector(kp,0,2);
-	free_fvector(d_hat,0,2);
-
-	// free matrices
-	free_fmatrix(c,0,7,0,2);
-
-	return(SUCCESS);
-}
+/* terma_dose_masks.cpp */
+
+/* All voxels that lie within a cylinder of radius RAPERTURE + RSAFE, centered
+on the central beam axis, are marked in the dose_mask grid.  These voxels will
+be used in the dose calculation.  The voxels that are marked in the terma_mask
+grid are a subset of those that are marked in the dose_mask grid. The terma_mask
+grid contains values that specify the fraction of each voxel that lies inside
+of the beam aperture in the beam's eye view plane, which exists at a distance
+SAD from the x-ray source location. */
+
+/* Determination of voxel "insideness" for the terma_mask:
+If it is discovered that a voxel is intersected by an aperture boundary in the
+beam's eye view plane, then that voxel is broken-up into Mus x Nus x Qus sub-
+voxels (upsampled).  The fraction of the sub-voxels that lie inside the beam
+aperture in the beam's eye view then becomes the insideness for that voxel. */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int terma_dose_masks(FLOAT_GRID *terma_mask, FLOAT_GRID *dose_mask, BEAM *bm)
+// The user must allocate space for terma_mask and dose_mask before calling 
+// this function.
+// The validity of all of the arguments to this function are assumed to be 
+// checked with the parse_func, which acts as a gatekeeper for the convolution
+// program.
+{
+	// scalars
+	int i,j,k,m;     // indices
+	int ius,jus,kus;  // upsample voxel indices
+	int M,N,Q;     // grid dimensions
+	float dx,dy,dz;  // voxel dimensions
+	float xp,yp,SAD; // aperture center in ip,jp,kp coordinate system
+	float xsub,ysub,zsub;  // coordinates of sub-voxels
+	float del_xp,del_yp; // width of beamlet field in plane at SAD
+	float Rmax,Rcurr,Rcyl,Rvox,Rcyl_sqr,Rproj;
+	float eta,gamma,delta;  // dummy variables
+
+	// vectors
+	float *x,*y,*z;  // x,y,z coordinate vectors
+	float *dxus,*dyus,*dzus;  // upsample vectors
+	float *y_vec,*ip,*jp,*kp,*d_hat;  // beam vectors
+
+	// matrices
+	float **c;  // matrix of the 8 corners of voxel grid
+	
+	// Ensure that upsample factors are all greater than zero
+	if (Mus < 1 || Nus < 1 || Qus < 1)
+	{
+		sprintf(errstr,"Upsample factors must all be greater than zero.");
+		return(FAILURE);
+	}
+
+	// record the sizes of terma_mask and dose_mask
+	M = terma_mask->x_count;
+	N = terma_mask->y_count;
+	Q = terma_mask->z_count;
+
+	if (M != dose_mask->x_count || N != dose_mask->y_count 
+		|| Q != dose_mask->z_count)
+	{
+		sprintf(errstr,"dose_mask and terma_mask dimensions are incompatible.");
+		return(FAILURE);
+	}
+
+	dx = terma_mask->inc.x;
+	dy = terma_mask->inc.y;
+	dz = terma_mask->inc.z;
+	
+	// initialize vectors
+	x = fvector(0,M-1);
+	y = fvector(0,N-1);
+	z = fvector(0,Q-1);
+
+	dxus = fvector(0,Mus-1);
+	dyus = fvector(0,Nus-1);
+	dzus = fvector(0,Qus-1);
+
+	y_vec = fvector(0,2);
+	ip = fvector(0,2);
+	jp = fvector(0,2);
+	kp = fvector(0,2);
+	d_hat = fvector(0,2);
+
+	// initialize matrices
+	c = fmatrix(0,7,0,2);
+
+	// fill-in the voxel coordinate vectors
+	for (i=0;i<M;i++) x[i] = terma_mask->start.x + (float)i*dx;
+	for (j=0;j<N;j++) y[j] = terma_mask->start.y + (float)j*dy;
+	for (k=0;k<Q;k++) z[k] = terma_mask->start.z + (float)k*dz;
+
+	// fill-in the upsample vectors
+	// For a voxel at (i,j,k), the xyz coordinates of a sub-voxel (ius,jus,kus)
+	// are (x[i] + dxus[ius], y[j] + dyus[jus], z[k] + dzus[k])
+	dxus[0] = -0.5*dx*(1-1/Mus);
+	for (ius=1;ius<Mus;ius++)  dxus[ius] = dxus[ius-1] + dx/Mus;
+
+	dyus[0] = -0.5*dy*(1-1/Nus);
+	for (jus=1;jus<Nus;jus++) dyus[jus] = dyus[jus-1] + dy/Nus;
+
+	dzus[0] = -0.5*dz*(1-1/Qus);
+	for (kus=1;kus<Qus;kus++) dzus[kus] = dzus[kus-1] + dz/Qus;
+
+	// rewrite beam vectors for quick reference later
+	y_vec[0] = bm->y_vec[0];
+	y_vec[1] = bm->y_vec[1];
+	y_vec[2] = bm->y_vec[2];
+
+	// coordinate system in beam's eye view
+	for (j=0;j<3;j++) ip[j] = bm->ip[j];
+	for (j=0;j<3;j++) jp[j] = bm->jp[j];
+	for (j=0;j<3;j++) kp[j] = bm->kp[j];
+
+	// aperture center in beam's eye view
+	xp = bm->xp;
+	yp = bm->yp;
+
+	// aperture size in beam's eye view
+	del_xp = bm->del_xp;
+	del_yp = bm->del_yp;
+
+	// source-axis distance of the beam
+	SAD = bm->SAD;
+
+	// calculate the max distance between the source vector and each grid corner
+	Rmax = 0.0;
+	
+	// the the matrix c with the coordinates of the eight corners of the grid.
+	for (i=0;i<=1;i++)
+	  for (j=0;j<=1;j++)
+	    for (k=0;k<=1;k++)
+		{ 
+		  //                     0 => lower corners         1 => upper corners
+		  c[i+j*2+k*4][0] = (1-(float)i)*(x[0]-dx/2.0) + (float)i*(x[M-1]+dx/2.0);
+		  c[i+j*2+k*4][1] = (1-(float)j)*(y[0]-dy/2.0) + (float)j*(y[N-1]+dy/2.0);
+		  c[i+j*2+k*4][2] = (1-(float)k)*(z[0]-dz/2.0) + (float)k*(z[Q-1]+dz/2.0);
+		}
+
+	// find which corner is the farthest from the source
+	for (m=0;m<=7;m++)
+	{
+		Rcurr = sqrt(pow(y_vec[0] - c[m][0],2.0f)
+			       + pow(y_vec[1] - c[m][1],2.0f)
+				   + pow(y_vec[2] - c[m][2],2.0f));
+		if (Rcurr > Rmax)
+			Rmax = Rcurr;
+	}
+
+	// Fill the dose_mask
+
+	// Radius of cylinder about y_vec + kp that will contain all voxels
+	// to be used in the dose calculation.
+	Rcyl = sqrt(del_xp*del_xp + del_yp*del_yp)*Rmax/SAD;  // project Rmax to aperture plane
+	Rcyl_sqr = Rcyl*Rcyl + RSAFE*RSAFE;  // add an empirical safety margin to the radius squared
+
+	// calculate the true source direction
+	// d_hat points at the center of the aperture from the source location
+	d_hat[0] = xp*ip[0] + yp*jp[0] + SAD*kp[0];
+	d_hat[1] = xp*ip[1] + yp*jp[1] + SAD*kp[1];
+	d_hat[2] = xp*ip[2] + yp*jp[2] + SAD*kp[2];
+
+	// normalize d_hat so it's a true "hat" vector
+	delta = sqrt(d_hat[0]*d_hat[0] + d_hat[1]*d_hat[1] + d_hat[2]*d_hat[2]);
+	d_hat[0] = d_hat[0]/delta;
+	d_hat[1] = d_hat[1]/delta;
+	d_hat[2] = d_hat[2]/delta;
+
+	for (k=0;k<Q;k++)
+	 for (j=0;j<N;j++)
+	  for (i=0;i<M;i++)
+	  {
+		  // squared distance between the voxel and the source:
+		  eta = (x[i] - y_vec[0])*(x[i] - y_vec[0])
+			  + (y[j] - y_vec[1])*(y[j] - y_vec[1])
+			  + (z[k] - y_vec[2])*(z[k] - y_vec[2]);
+
+		  // squared distance between the voxel and the source along source direction, 
+	      // y_vec + kp:
+		  gamma = pow((x[i] - y_vec[0])*d_hat[0]
+				    + (y[j] - y_vec[1])*d_hat[1]
+				    + (z[k] - y_vec[2])*d_hat[2],2.0f);
+
+		  // printf("%lf %lf\n",eta, gamma);
+
+		  // squared difference between the voxel and the axis of the cylinder
+		  delta = eta - gamma;
+
+		  // If the voxel is inside the cylinder about y_vec + ip of radius Rcyl plus
+		  // a safety margin then mark it in dose_mask.
+		  if (delta <= Rcyl_sqr)
+			  GRID_VALUE(dose_mask,i,j,k) = 1.0;
+		  else
+			  GRID_VALUE(dose_mask,i,j,k) = 0.0;
+	  }
+
+	// Fill the terma_mask, including the insideness of each voxel
+
+	// Each voxel is enclosed with in a sphere of the following radius:
+	Rvox = 0.5*sqrt(dx*dx + dy*dy + dz*dz);
+
+	for (i=0;i<M;i++)
+	 for (j=0;j<N;j++)
+	  for (k=0;k<Q;k++)
+	   // deal only with voxels that are marked in the dose_mask
+	   if (GRID_VALUE(dose_mask,i,j,k) > 0.0)
+	   {
+		 // distance between source and voxel in the kp direction
+	     delta = kp[0]*(x[i] - y_vec[0])
+               + kp[1]*(y[j] - y_vec[1])
+               + kp[2]*(z[k] - y_vec[2]);
+
+		 // voxel's projected offset on the aperture plane in the ip direction:
+		 eta = (SAD/delta)*(  ip[0]*(x[i] - y_vec[0])
+				            + ip[1]*(y[j] - y_vec[1])
+						    + ip[2]*(z[k] - y_vec[2])) - xp;
+		 // voxel's projected offset on the aperture plane in the jp direction:
+		 gamma = (SAD/delta)*(  jp[0]*(x[i] - y_vec[0])
+				              + jp[1]*(y[j] - y_vec[1])
+						      + jp[2]*(z[k] - y_vec[2])) - yp;
+
+		 // take absolute value of offsets
+		 eta = fabs(eta);
+		 gamma = fabs(gamma);
+
+		 Rproj = Rvox*SAD/delta;  // voxel radius projected to plane at SAD
+
+		 // Determine where the voxel lies with respect to the aperture:
+		 if (eta <= 0.5*del_xp+Rproj && gamma <= 0.5*del_yp+Rproj)
+		 // voxel is inside aperture plus a half-voxel margin:
+			if (eta >= 0.5*del_xp-Rproj || gamma >= 0.5*del_yp-Rproj)
+		    // voxel is between the aperture plus/minus a half-voxel margin:
+			// (true at this point if the voxel size is larger than the aperture size)
+			{
+			    // Determine insideness of the voxel by breaking it up
+				// into subvoxels and projecting the parts to the aperture plane.
+				m = 0;  // number of subvoxels inside aperture
+	            // project each subvoxel onto the aperture at SAD
+		        for (ius=0;ius<Mus;ius++)
+			     for (jus=0;jus<Nus;jus++)
+			      for (kus=0;kus<Qus;kus++)
+				  {
+			        // find the center of the subvoxel
+			        xsub = x[i] + dxus[ius];
+			        ysub = y[j] + dyus[jus];
+			        zsub = z[k] + dzus[kus];
+
+			        // project the subvoxel onto the aperture
+			        // distance between source and subvoxel in the kp direction
+			        delta = kp[0]*(xsub - y_vec[0])
+				          + kp[1]*(ysub - y_vec[1])
+					      + kp[2]*(zsub - y_vec[2]);
+
+			        // projected offset on aperture plane in the ip direction:
+			        eta = (SAD/delta)*(  ip[0]*(xsub - y_vec[0])
+				                       + ip[1]*(ysub - y_vec[1])
+								       + ip[2]*(zsub - y_vec[2])) - xp;
+			        // projected offset on aperture plane in the jp direction:
+			        gamma = (SAD/delta)*(  jp[0]*(xsub - y_vec[0])
+				                         + jp[1]*(ysub - y_vec[1])
+								         + jp[2]*(zsub - y_vec[2])) - yp;
+
+		            eta = fabs(eta);
+			        gamma = fabs(gamma);
+
+			        // check if the subvoxel is inside the aperture at SAD
+			        if (eta <= 0.5*del_xp && gamma <= 0.5*del_yp)
+				       m++;
+				  }
+
+		        // the fraction of subvoxels inside the aperture becomes the insidness
+	            GRID_VALUE(terma_mask,i,j,k) = (float)m/(float)(Mus*Nus*Qus);
+			}
+			else
+			// voxel is inside the aperture minus a half-voxel margin
+				GRID_VALUE(terma_mask,i,j,k) = 1.0;
+		 else
+		 // voxel outside the aperture plus the half-voxel margin
+		    GRID_VALUE(terma_mask,i,j,k) = 0.0;
+	   }
+
+	// free vectors
+	free_fvector(x,0,M-1);
+	free_fvector(y,0,N-1);
+	free_fvector(z,0,Q-1);
+
+	free_fvector(dxus,0,Mus-1);
+	free_fvector(dyus,0,Nus-1);
+	free_fvector(dzus,0,Qus-1);
+
+	free_fvector(y_vec,0,2);
+	free_fvector(ip,0,2);
+	free_fvector(jp,0,2);
+	free_fvector(kp,0,2);
+	free_fvector(d_hat,0,2);
+
+	// free matrices
+	free_fmatrix(c,0,7,0,2);
+
+	return(SUCCESS);
+}

+ 60 - 60
src-chtc/terma_kerma.cpp

@@ -1,60 +1,60 @@
-/* terma_kerma.cpp */
-
-/* Calculates the terma and the kerma of every voxel in the terma_mask.  */
-
-#include "defs.h"
-
-extern char errstr[200];  // error string that all routines have access to
-
-int terma_kerma(FLOAT_GRID *deff, FLOAT_GRID *terma, FLOAT_GRID *kermac,
-				MONO_KERNELS *mono, FLOAT_GRID *terma_mask)
-{													 
- // insideness is accounted for with terma_mask
- int i, j, k, e;
- float kermac0, terma0;
-
- //calculate T and Kc at zero depth for use in hardening correction
- //see Hoban et al 1994 (PMB)
- kermac0 = terma0 = 0.0;
- for (e=0;e<mono->nkernels;e++)
- {
-   kermac0 = mono->fluence[e]*mono->energy[e]*mono->mu_en[e];
-   terma0 = mono->fluence[e]*mono->energy[e]*mono->mu[e];
- }
-
- for (j=0;j<deff->y_count;j++)
-  for (k=0;k<deff->z_count;k++)
-   for (i=0;i<deff->x_count;i++)
-    if (GRID_VALUE(terma_mask,i,j,k) > 0)
-    {
-	  // The amount of each voxel that is inside the field (insideness) was
-	  // was accounted in the calculation of the terma_mask
-
-	  //sum terma and collision kerma over each energy in spectrum 
-	  // (stored in mono kernel structure)
-	  for (e=0;e<mono->nkernels;e++)
-	  {
-       GRID_VALUE(terma,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
-                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
-       GRID_VALUE(kermac,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu_en[e]
-                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
-	  }
-	  
-	  //adjust terma and collision kerma according to insideness
-	  GRID_VALUE(terma,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
-	  GRID_VALUE(kermac,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
-
-	  // beam hardening correction
-	  if (terma0 <= 0.0 || kermac0 <= 0.0)
-		nrerror("Input spectrum must not sum to zero."); 
-	  else
-		GRID_VALUE(terma,i,j,k) *= (GRID_VALUE(kermac,i,j,k)/GRID_VALUE(terma,i,j,k))
-								/(kermac0/terma0);
-	}
-	else
-	{
-		GRID_VALUE(terma,i,j,k) = 0.0;
-		GRID_VALUE(kermac,i,j,k) = 0.0;
-	}
-    return(SUCCESS);
-}
+/* terma_kerma.cpp */
+
+/* Calculates the terma and the kerma of every voxel in the terma_mask.  */
+
+#include "defs.h"
+
+extern char errstr[200];  // error string that all routines have access to
+
+int terma_kerma(FLOAT_GRID *deff, FLOAT_GRID *terma, FLOAT_GRID *kermac,
+				MONO_KERNELS *mono, FLOAT_GRID *terma_mask)
+{													 
+ // insideness is accounted for with terma_mask
+ int i, j, k, e;
+ float kermac0, terma0;
+
+ //calculate T and Kc at zero depth for use in hardening correction
+ //see Hoban et al 1994 (PMB)
+ kermac0 = terma0 = 0.0;
+ for (e=0;e<mono->nkernels;e++)
+ {
+   kermac0 = mono->fluence[e]*mono->energy[e]*mono->mu_en[e];
+   terma0 = mono->fluence[e]*mono->energy[e]*mono->mu[e];
+ }
+
+ for (j=0;j<deff->y_count;j++)
+  for (k=0;k<deff->z_count;k++)
+   for (i=0;i<deff->x_count;i++)
+    if (GRID_VALUE(terma_mask,i,j,k) > 0)
+    {
+	  // The amount of each voxel that is inside the field (insideness) was
+	  // was accounted in the calculation of the terma_mask
+
+	  //sum terma and collision kerma over each energy in spectrum 
+	  // (stored in mono kernel structure)
+	  for (e=0;e<mono->nkernels;e++)
+	  {
+       GRID_VALUE(terma,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu[e]
+                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
+       GRID_VALUE(kermac,i,j,k) += mono->fluence[e]*mono->energy[e]*mono->mu_en[e]
+                              * exp(-mono->mu[e]*GRID_VALUE(deff,i,j,k));
+	  }
+	  
+	  //adjust terma and collision kerma according to insideness
+	  GRID_VALUE(terma,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
+	  GRID_VALUE(kermac,i,j,k) *= GRID_VALUE(terma_mask,i,j,k);
+
+	  // beam hardening correction
+	  if (terma0 <= 0.0 || kermac0 <= 0.0)
+		nrerror("Input spectrum must not sum to zero."); 
+	  else
+		GRID_VALUE(terma,i,j,k) *= (GRID_VALUE(kermac,i,j,k)/GRID_VALUE(terma,i,j,k))
+								/(kermac0/terma0);
+	}
+	else
+	{
+		GRID_VALUE(terma,i,j,k) = 0.0;
+		GRID_VALUE(kermac,i,j,k) = 0.0;
+	}
+    return(SUCCESS);
+}

+ 117 - 117
src-chtc/util.cpp

@@ -1,117 +1,117 @@
-/* util.c */
-/* Functions that are used for utility throughout the routines used for the C/S 
-calculation.  Most of these functions are from Numerical Recipes in C by Press. */
-
-#include "defs.h"
-
-#define NR_END 1
-#define FREE_ARG char*
-
-extern char errstr[200];  // error string that all routines have access to
-
-void nrerror(char error_text[])
-/* Numerical Recipes standard error handler */
-{
- fprintf(stderr,"Numerical Recipes run-time error...\n");
- fprintf(stderr,"%s\n",error_text);
- fprintf(stderr,"...now exiting to system...\n");
- exit(1);
-}
-
-float *fvector(int nl, int nh)
-/* allocate a float vector with subscript range v[nl..nh] */
-{
- float *v;
- v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
- if (!v) nrerror("allocation failure in fvector()");
- return v-nl+NR_END;
-}
-
-
-void free_fvector(float *v, int nl, int nh)
-/* free a float vector allocated with fvector() */
-{
- free((FREE_ARG) (v+nl-NR_END));
-}
-
-
-float **fmatrix(int nrl, int nrh, int ncl, int nch)
-/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
-{
- int i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
- float **m;
- /* allocate pointers to rows */
- m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
- if (!m) nrerror("allocation failure 1 in matrix()");
- m += NR_END;
- m -= nrl;
- /* allocate rows and set pointers to them */
- m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
- if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
- m[nrl] += NR_END;
- m[nrl] -= ncl;
- for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
- /* return pointer to array of pointers to rows */
- return m;
-}
-
-void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch)
-/* free a float matrix allocated by fmatrix() */
-{
- free((FREE_ARG) (m[nrl]+ncl-NR_END));
- free((FREE_ARG) (m+nrl-NR_END));
-}
-
-int copy_grid_geometry(FLOAT_GRID *grid_old, FLOAT_GRID *grid_new)
-// Copies geometric grid information from grid_old to grid_new
-{
-	grid_new->start.x = grid_old->start.x;
-	grid_new->start.y = grid_old->start.y;
-	grid_new->start.z = grid_old->start.z;
-
-	grid_new->inc.x = grid_old->inc.x;
-	grid_new->inc.y = grid_old->inc.y;
-	grid_new->inc.z = grid_old->inc.z;
-
-	grid_new->x_count = grid_old->x_count;
-	grid_new->y_count = grid_old->y_count;
-	grid_new->z_count = grid_old->z_count;
-
-	return(SUCCESS);
-}
-
-int binSearch(float *a, float searchnum, int M)
-/* Accepts a float array of data of length M ordered lowest to highest and a number called searchnum. 
-Returns the index of the first element of the array, a, that is less than the searchnum. 
-If the searchnum is less than a[0], then -1 is returned, and if the searchnum is greater 
-than or equal to M, then M is returned. */
-{
-    int found, mid, top, bottom;
-
-    bottom = 0;
-    top = M-1;
-
-    found = 0;  // flag that is set to 1 once the proper index is found
- 
-    // Ensure that the search parameter lies inside boundaries
-	if(searchnum >= a[top])
-		return(M); 
-	if(searchnum <= a[bottom])
-		return(-1);
-
-	while(!found)
-	{
-		mid = (top + bottom) / 2;
-		if(searchnum == a[mid])
-			found = 1;
-		else
-			if(searchnum < a[mid])
-				top = mid - 1;
-			else
-				if(searchnum > a[mid + 1])
-					bottom = mid + 1;
-				else
-					found = 1; 
-	}
-	return(mid);
-}
+/* util.c */
+/* Functions that are used for utility throughout the routines used for the C/S 
+calculation.  Most of these functions are from Numerical Recipes in C by Press. */
+
+#include "defs.h"
+
+#define NR_END 1
+#define FREE_ARG char*
+
+extern char errstr[200];  // error string that all routines have access to
+
+void nrerror(char error_text[])
+/* Numerical Recipes standard error handler */
+{
+ fprintf(stderr,"Numerical Recipes run-time error...\n");
+ fprintf(stderr,"%s\n",error_text);
+ fprintf(stderr,"...now exiting to system...\n");
+ exit(1);
+}
+
+float *fvector(int nl, int nh)
+/* allocate a float vector with subscript range v[nl..nh] */
+{
+ float *v;
+ v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
+ if (!v) nrerror("allocation failure in fvector()");
+ return v-nl+NR_END;
+}
+
+
+void free_fvector(float *v, int nl, int nh)
+/* free a float vector allocated with fvector() */
+{
+ free((FREE_ARG) (v+nl-NR_END));
+}
+
+
+float **fmatrix(int nrl, int nrh, int ncl, int nch)
+/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
+{
+ int i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
+ float **m;
+ /* allocate pointers to rows */
+ m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
+ if (!m) nrerror("allocation failure 1 in matrix()");
+ m += NR_END;
+ m -= nrl;
+ /* allocate rows and set pointers to them */
+ m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
+ if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
+ m[nrl] += NR_END;
+ m[nrl] -= ncl;
+ for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
+ /* return pointer to array of pointers to rows */
+ return m;
+}
+
+void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch)
+/* free a float matrix allocated by fmatrix() */
+{
+ free((FREE_ARG) (m[nrl]+ncl-NR_END));
+ free((FREE_ARG) (m+nrl-NR_END));
+}
+
+int copy_grid_geometry(FLOAT_GRID *grid_old, FLOAT_GRID *grid_new)
+// Copies geometric grid information from grid_old to grid_new
+{
+	grid_new->start.x = grid_old->start.x;
+	grid_new->start.y = grid_old->start.y;
+	grid_new->start.z = grid_old->start.z;
+
+	grid_new->inc.x = grid_old->inc.x;
+	grid_new->inc.y = grid_old->inc.y;
+	grid_new->inc.z = grid_old->inc.z;
+
+	grid_new->x_count = grid_old->x_count;
+	grid_new->y_count = grid_old->y_count;
+	grid_new->z_count = grid_old->z_count;
+
+	return(SUCCESS);
+}
+
+int binSearch(float *a, float searchnum, int M)
+/* Accepts a float array of data of length M ordered lowest to highest and a number called searchnum. 
+Returns the index of the first element of the array, a, that is less than the searchnum. 
+If the searchnum is less than a[0], then -1 is returned, and if the searchnum is greater 
+than or equal to M, then M is returned. */
+{
+    int found, mid, top, bottom;
+
+    bottom = 0;
+    top = M-1;
+
+    found = 0;  // flag that is set to 1 once the proper index is found
+ 
+    // Ensure that the search parameter lies inside boundaries
+	if(searchnum >= a[top])
+		return(M); 
+	if(searchnum <= a[bottom])
+		return(-1);
+
+	while(!found)
+	{
+		mid = (top + bottom) / 2;
+		if(searchnum == a[mid])
+			found = 1;
+		else
+			if(searchnum < a[mid])
+				top = mid - 1;
+			else
+				if(searchnum > a[mid + 1])
+					bottom = mid + 1;
+				else
+					found = 1; 
+	}
+	return(mid);
+}

+ 14 - 14
view_beamlet.m

@@ -1,15 +1,15 @@
-
-
-% data = read_ryan_beamlets('F:\021_WiscPlan_data\Hippocampus_HD_2\batch_dose.bin')
-
-
-idx = 3000;
-
-tabula = zeros([data{idx}.x_count, data{idx}.y_count, data{idx}.z_count]);
-
-tabula(data{idx}.non_zero_indices)   = tabula(data{idx}.non_zero_indices)+data{idx}.non_zero_values;
-tabula(data{idx+1}.non_zero_indices) = tabula(data{idx+1}.non_zero_indices)+data{idx+1}.non_zero_values;
-
-tabula(data{idx+2}.non_zero_indices) = tabula(data{idx+2}.non_zero_indices)+data{idx+2}.non_zero_values;
-
+
+
+% data = read_ryan_beamlets('F:\021_WiscPlan_data\Hippocampus_HD_2\batch_dose.bin')
+
+
+idx = 3000;
+
+tabula = zeros([data{idx}.x_count, data{idx}.y_count, data{idx}.z_count]);
+
+tabula(data{idx}.non_zero_indices)   = tabula(data{idx}.non_zero_indices)+data{idx}.non_zero_values;
+tabula(data{idx+1}.non_zero_indices) = tabula(data{idx+1}.non_zero_indices)+data{idx+1}.non_zero_values;
+
+tabula(data{idx+2}.non_zero_indices) = tabula(data{idx+2}.non_zero_indices)+data{idx+2}.non_zero_values;
+
 orthoslice(tabula);

+ 272 - 272
vol_prep.m

@@ -1,272 +1,272 @@
-
-
-function vol_prep
-% This series of functions take in segmented PET/CT image paths and outputs
-% Dose Painting (DP) maps, as well as some intermediate results. 
-% this function calls three other functions:
-% - vol_prep_bin
-% - vol_prep_fuzzy
-% - vol_prep_DPmap
-% that are needed for expanding the initial segmentations done in the
-% segmentation GUI
-
-close all
-
-%% ---=== INPUT PARAMS ===---
-
-patname = 'FET_FGL005';
-% patname = 'FET_FGL015';
-% patname = 'FET_FGL022';
-timepoint = 'B1';
-
-paths.in = ['\\Mpufs5\data_wnx1\_Data\Glioma_aus\' patname '\' timepoint '\Processed'];
-paths.CT_in = [patname '_' timepoint '_CT2FET'];
-paths.target_bin_in  = [ patname '_' timepoint '_seg_thr2.0'];
-paths.target_fzy_in  = [ patname '_' timepoint '_seg_combined'];
-paths.body_bin_in    = [ patname '_' timepoint '_head'];
-
-% paths.target_bin_in  = [patname '_' timepoint '_thr2'];
-% paths.target_fzy_in  = [patname '_' timepoint '_thr2'];
-% paths.body_bin_in    = [patname '_' timepoint '_head'];
-
-
-margins.CTV = 1.0; % GTV->CTV margin, in cm
-margins.PTV = 0.5; % CTV->PTV margin, in cm
-margins.body = 7.0; % how far from tumor do we still include body, in cm
-
-dose.min = 60;
-dose.max = 63;
-
-
-%% ---=== FUNCTION CALLS ===---
-fprintf('Starting binary volume expansion...')
-vol_prep_bin(paths, margins)
-fprintf(' done!\n')
-
-fprintf('Starting fuzzy volume expansion...')
-vol_prep_fuzzy(paths, margins)
-fprintf(' done!\n')
-
-fprintf('Creating dose plans ...')
-vol_prep_DPmap(paths, dose)
-fprintf(' done!\n')
-end
-
-
-function vol_prep_bin(paths, margins)
-% this function takes in the segmentations and creates PTV/GTV/CTV binary volumes,
-% as well as appropriately cropped healthy tissue (body) segmentation.
-
-[CT_in, CT_meta] = nrrdread([paths.in '\' paths.CT_in '.nrrd']);
-[GTV_in, GTV_meta] = nrrdread([paths.in '\' paths.target_bin_in '.nrrd']);
-[body_in, body_meta] = nrrdread([paths.in '\' paths.body_bin_in '.nrrd']);
-
-colorwash(CT_in, GTV_in,  [-500, 500], [0, 1.2]);
-
-%% identify target voxels - these are used when identifiying valid beamlets
-% voxels that need to be considered (above the threshold)
-p_threshold = 0;
-GTV_binary = zeros(size(GTV_in));
-GTV_binary(GTV_in>p_threshold) = 1;
-
-% Account for infiltration (GTV -> CTV)
-CTV = zeros(size(GTV_binary));
-bwD = bwdistsc(GTV_binary, GTV_meta.spacedirections);
-CTV(bwD<margins.CTV) = 1;
-
-% expand to PTV (CTV -> PTV)
-PTV = zeros(size(GTV_binary));
-bwD = bwdistsc(GTV_binary, GTV_meta.spacedirections);
-PTV(bwD<margins.PTV) = 1;
-
-%% identify body volume of interest
-body = body_in;
-bwD = bwdistsc(GTV_binary, GTV_meta.spacedirections);
-body(PTV>0) = 0;
-body(bwD>margins.body) = 0; % how far from the tumor are we still interested in the body
-
-%% save outputs
-filename = [paths.in '\RODP_files\' paths.target_bin_in '_binCTV.nrrd'];
-matrix = single(CTV);
-pixelspacing = GTV_meta.spacedirections;
-origin = GTV_meta.spaceorigin;
-nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
-
-filename = [paths.in '\RODP_files\' paths.target_bin_in '_binPTV.nrrd'];
-matrix = single(PTV);
-pixelspacing = GTV_meta.spacedirections;
-origin = GTV_meta.spaceorigin;
-nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
-
-filename = [paths.in '\RODP_files\' paths.body_bin_in '_crop_bin.nrrd'];
-matrix = single(body);
-pixelspacing = body_meta.spacedirections;
-origin = body_meta.spaceorigin;
-nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
-
-colorwash(CT_in, PTV,  [-500, 500], [0, 1.2]);
-colorwash(CT_in, body, [-500, 500], [0, 1.2]);
-end
-
-function vol_prep_fuzzy(paths, margins)
-% this function takes in the segmentations and creates fuzzy (probabilistic)
-% PTV/GTV/CTV volumes
-
-infilt_range = margins.CTV; % range of infiltration, in cm. Should be value of sigma (or 1/3 decay range). Assuming normal infil.
-
-[CT_in, CT_meta] = nrrdread([paths.in '\' paths.CT_in '.nrrd']);
-[GTV_in, GTV_meta] = nrrdread([paths.in '\' paths.target_fzy_in '.nrrd']);
-% [body_in, body_meta] = nrrdread([paths.in '\' paths.body_bin_in '.nrrd']);
-colorwash(CT_in, GTV_in,  [-500, 500], [0, 1.2]);
-
-%% Account for infiltration (GTV -> CTV)
-
-% -- get distance from central dot --
-ir_a = 1.5; % infiltration range factor
-
-CTV = zeros(size(GTV_in));
-bwD = bwdistsc(GTV_in>0.05, GTV_meta.spacedirections);
-CTV(bwD< (ir_a * infilt_range) ) = 1;
-
-% for each voxel in the area of interest, figure out the highest
-% probability based on range from tumor * p that tumor is there
-GTV_idx_lst = find(GTV_in   >0.05);
-CTV_idx_lst = find(CTV      >0.0);
-prob_CTV = zeros(size(GTV_in));
-
-f = waitbar(0,'calculating expansion');
-
-% define area of interest
-Ksize = 1+2*ceil((ir_a * infilt_range)/min(GTV_meta.spacedirections)); % get kernel for convolution.
-kernel_base = zeros(Ksize,Ksize,Ksize); 
-kernel_base(ceil(Ksize/2),ceil(Ksize/2),ceil(Ksize/2))=1;
-bwD = bwdistsc(kernel_base, GTV_meta.spacedirections);
-kernel = zeros(size(kernel_base));
-kernel(bwD< (ir_a * infilt_range)) = 1;
-
-CTV_idx_lst_num = numel(CTV_idx_lst);
-prob_CTV_solutions = zeros(1,CTV_idx_lst_num);
-
-tic 
-for i = 1:CTV_idx_lst_num
-    i_idx = CTV_idx_lst(i);
-    [y1, x1, z1] = ind2sub(size(GTV_in), i_idx);
-    
-    waitbar(i/numel(CTV_idx_lst),f);
-    
-    % get the crop of nearby voxels in tumor
-%     tabula = zeros(size(GTV_in));
-%     tabula(i_idx) = 1;
-%     tabula2 = convn(tabula, kernel, 'same');
-%     idx_nearby = find(tabula2>0);
-    
-    idx_nearby = f_neighbors(i_idx, size(GTV_in), ir_a, infilt_range, GTV_meta.spacedirections);
-    
-    % overlap
-    idx_GTV_nearby = intersect (idx_nearby, GTV_idx_lst);
-    
-    if numel(idx_GTV_nearby) <1
-        prob_CTV_solutions(i) = 0;
-        error('this is fucky. no voxels within range')
-    end
-    
-    p_list=zeros(1, numel(idx_GTV_nearby));
-    p_list_max = 0;
-    
-    for j = 1:numel(idx_GTV_nearby)
-        j_idx = idx_GTV_nearby(j);
-        if GTV_in(j_idx) < p_list_max
-            continue
-        end
-        
-        [y2, x2, z2] = ind2sub(size(GTV_in), j_idx);
-        d = sqrt((((y2-y1)*GTV_meta.spacedirections(1))^2 + ...
-            ((x2-x1)*GTV_meta.spacedirections(2))^2 + ((z2-z1)*GTV_meta.spacedirections(3))^2));
-        % get probability of invisible infiltration at given voxel, based
-        % on single voxel from tumor
-        p_list(j) = GTV_in(j_idx) * exp(-(d*d)/(infilt_range*infilt_range));
-        
-        p_list_max = max(p_list_max, p_list(j));
-        
-        if p_list(j) == 1
-            prob_CTV_solutions(i) = 1;
-            break
-        end
-    end
-    prob_CTV_solutions(i) = max(p_list);
-end
-toc
-prob_CTV(CTV_idx_lst) = prob_CTV_solutions;
-close(f)
-
-colorwash(CT_in, prob_CTV,  [-500, 500], [0, 1.2]);
-
-
-%% save outputs
-filename = [paths.in '\RODP_files\' paths.target_bin_in '_fuzzyCTV.nrrd'];
-matrix = single(prob_CTV);
-pixelspacing = GTV_meta.spacedirections;
-origin = GTV_meta.spaceorigin;
-nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
-
-end
-function neigh_mat_idx = f_neighbors(idx, mat_size, ir_a, infilt_range, voxsize);
-% this function returns indeces of the box nearby around 
-    [y, x, z] = ind2sub(mat_size, idx);
-    
-    y1 = max(1, floor(y - ir_a*infilt_range/(voxsize(1))));
-    y2 = min(mat_size(1), ceil(y + ir_a*infilt_range/(voxsize(1))));
-    
-    x1 = max(1, floor(x - ir_a*infilt_range/(voxsize(2))));
-    x2 = min(mat_size(1), ceil(x + ir_a*infilt_range/(voxsize(2))));
-    
-    z1 = max(1, floor(z - ir_a*infilt_range/(voxsize(3))));
-    z2 = min(mat_size(1), ceil(z + ir_a*infilt_range/(voxsize(3))));
-    
-    tabula = zeros(mat_size);
-    tabula(y1:y2, x1:x2, z1:z2)=1;
-    
-    neigh_mat_idx = find( tabula>0);
-
-end
-
-function vol_prep_DPmap(paths, dose)
-% this function takes in the segmentations and creates fuzzy (probabilistic)
-% PTV/GTV/CTV volumes
-
-[CT_in, CT_meta] = nrrdread([paths.in '\' paths.CT_in '.nrrd']);
-[CTV_fuzzy, CTV_meta] = nrrdread([paths.in '\RODP_files\' paths.target_bin_in '_fuzzyCTV.nrrd']);
-
-dose_min = f_dose_min(CTV_fuzzy, dose.min);
-dose_max = f_dose_max(CTV_fuzzy, dose.max);
-
-orthoslice(dose_min, [0, dose.max+10]) % plot min dose boundary
-orthoslice(dose_max, [0, dose.max+10]) % plot max dose boundary
-
-%% save outputs
-filename = [paths.in '\RODP_files\' paths.target_bin_in '_DP_minDose.nrrd'];
-% filename = [pathIn 'RODP_files\FET_FGL005_B1_DP_minDose.nrrd'];
-matrix = single(dose_min);
-pixelspacing = CTV_meta.spacedirections;
-origin = CTV_meta.spaceorigin;
-nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
-
-filename = [paths.in '\RODP_files\' paths.target_bin_in '_DP_maxDose.nrrd'];
-% filename = [pathIn 'RODP_files\FET_FGL005_B1_DP_maxDose.nrrd'];
-matrix = single(dose_max);
-pixelspacing = CTV_meta.spacedirections;
-origin = CTV_meta.spaceorigin;
-nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
-
-end
-function dose_min = f_dose_min(CTV_fuzzy, D_min)
-% get low boundary for ideal dose plan
-dose_min = D_min* min(1, 2* max(0, (CTV_fuzzy - 0.25)));
-dose_min(CTV_fuzzy>0.98) = 1.2*D_min;
-% orthoslice(dose_min)
-end
-function dose_max = f_dose_max(CTV_fuzzy, D_max)
-% get hihg boundary for ideal dose plan
-dose_max = D_max* min(1, 2* max(0, (CTV_fuzzy - 0.0)));
-dose_max(CTV_fuzzy>0.98) = 1.2*D_max;
-end
+
+
+function vol_prep
+% This series of functions take in segmented PET/CT image paths and outputs
+% Dose Painting (DP) maps, as well as some intermediate results. 
+% this function calls three other functions:
+% - vol_prep_bin
+% - vol_prep_fuzzy
+% - vol_prep_DPmap
+% that are needed for expanding the initial segmentations done in the
+% segmentation GUI
+
+close all
+
+%% ---=== INPUT PARAMS ===---
+
+patname = 'FET_FGL005';
+% patname = 'FET_FGL015';
+% patname = 'FET_FGL022';
+timepoint = 'B1';
+
+paths.in = ['\\Mpufs5\data_wnx1\_Data\Glioma_aus\' patname '\' timepoint '\Processed'];
+paths.CT_in = [patname '_' timepoint '_CT2FET'];
+paths.target_bin_in  = [ patname '_' timepoint '_seg_thr2.0'];
+paths.target_fzy_in  = [ patname '_' timepoint '_seg_combined'];
+paths.body_bin_in    = [ patname '_' timepoint '_head'];
+
+% paths.target_bin_in  = [patname '_' timepoint '_thr2'];
+% paths.target_fzy_in  = [patname '_' timepoint '_thr2'];
+% paths.body_bin_in    = [patname '_' timepoint '_head'];
+
+
+margins.CTV = 1.0; % GTV->CTV margin, in cm
+margins.PTV = 0.5; % CTV->PTV margin, in cm
+margins.body = 7.0; % how far from tumor do we still include body, in cm
+
+dose.min = 60;
+dose.max = 63;
+
+
+%% ---=== FUNCTION CALLS ===---
+fprintf('Starting binary volume expansion...')
+vol_prep_bin(paths, margins)
+fprintf(' done!\n')
+
+fprintf('Starting fuzzy volume expansion...')
+vol_prep_fuzzy(paths, margins)
+fprintf(' done!\n')
+
+fprintf('Creating dose plans ...')
+vol_prep_DPmap(paths, dose)
+fprintf(' done!\n')
+end
+
+
+function vol_prep_bin(paths, margins)
+% this function takes in the segmentations and creates PTV/GTV/CTV binary volumes,
+% as well as appropriately cropped healthy tissue (body) segmentation.
+
+[CT_in, CT_meta] = nrrdread([paths.in '\' paths.CT_in '.nrrd']);
+[GTV_in, GTV_meta] = nrrdread([paths.in '\' paths.target_bin_in '.nrrd']);
+[body_in, body_meta] = nrrdread([paths.in '\' paths.body_bin_in '.nrrd']);
+
+colorwash(CT_in, GTV_in,  [-500, 500], [0, 1.2]);
+
+%% identify target voxels - these are used when identifiying valid beamlets
+% voxels that need to be considered (above the threshold)
+p_threshold = 0;
+GTV_binary = zeros(size(GTV_in));
+GTV_binary(GTV_in>p_threshold) = 1;
+
+% Account for infiltration (GTV -> CTV)
+CTV = zeros(size(GTV_binary));
+bwD = bwdistsc(GTV_binary, GTV_meta.spacedirections);
+CTV(bwD<margins.CTV) = 1;
+
+% expand to PTV (CTV -> PTV)
+PTV = zeros(size(GTV_binary));
+bwD = bwdistsc(GTV_binary, GTV_meta.spacedirections);
+PTV(bwD<margins.PTV) = 1;
+
+%% identify body volume of interest
+body = body_in;
+bwD = bwdistsc(GTV_binary, GTV_meta.spacedirections);
+body(PTV>0) = 0;
+body(bwD>margins.body) = 0; % how far from the tumor are we still interested in the body
+
+%% save outputs
+filename = [paths.in '\RODP_files\' paths.target_bin_in '_binCTV.nrrd'];
+matrix = single(CTV);
+pixelspacing = GTV_meta.spacedirections;
+origin = GTV_meta.spaceorigin;
+nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
+
+filename = [paths.in '\RODP_files\' paths.target_bin_in '_binPTV.nrrd'];
+matrix = single(PTV);
+pixelspacing = GTV_meta.spacedirections;
+origin = GTV_meta.spaceorigin;
+nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
+
+filename = [paths.in '\RODP_files\' paths.body_bin_in '_crop_bin.nrrd'];
+matrix = single(body);
+pixelspacing = body_meta.spacedirections;
+origin = body_meta.spaceorigin;
+nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
+
+colorwash(CT_in, PTV,  [-500, 500], [0, 1.2]);
+colorwash(CT_in, body, [-500, 500], [0, 1.2]);
+end
+
+function vol_prep_fuzzy(paths, margins)
+% this function takes in the segmentations and creates fuzzy (probabilistic)
+% PTV/GTV/CTV volumes
+
+infilt_range = margins.CTV; % range of infiltration, in cm. Should be value of sigma (or 1/3 decay range). Assuming normal infil.
+
+[CT_in, CT_meta] = nrrdread([paths.in '\' paths.CT_in '.nrrd']);
+[GTV_in, GTV_meta] = nrrdread([paths.in '\' paths.target_fzy_in '.nrrd']);
+% [body_in, body_meta] = nrrdread([paths.in '\' paths.body_bin_in '.nrrd']);
+colorwash(CT_in, GTV_in,  [-500, 500], [0, 1.2]);
+
+%% Account for infiltration (GTV -> CTV)
+
+% -- get distance from central dot --
+ir_a = 1.5; % infiltration range factor
+
+CTV = zeros(size(GTV_in));
+bwD = bwdistsc(GTV_in>0.05, GTV_meta.spacedirections);
+CTV(bwD< (ir_a * infilt_range) ) = 1;
+
+% for each voxel in the area of interest, figure out the highest
+% probability based on range from tumor * p that tumor is there
+GTV_idx_lst = find(GTV_in   >0.05);
+CTV_idx_lst = find(CTV      >0.0);
+prob_CTV = zeros(size(GTV_in));
+
+f = waitbar(0,'calculating expansion');
+
+% define area of interest
+Ksize = 1+2*ceil((ir_a * infilt_range)/min(GTV_meta.spacedirections)); % get kernel for convolution.
+kernel_base = zeros(Ksize,Ksize,Ksize); 
+kernel_base(ceil(Ksize/2),ceil(Ksize/2),ceil(Ksize/2))=1;
+bwD = bwdistsc(kernel_base, GTV_meta.spacedirections);
+kernel = zeros(size(kernel_base));
+kernel(bwD< (ir_a * infilt_range)) = 1;
+
+CTV_idx_lst_num = numel(CTV_idx_lst);
+prob_CTV_solutions = zeros(1,CTV_idx_lst_num);
+
+tic 
+for i = 1:CTV_idx_lst_num
+    i_idx = CTV_idx_lst(i);
+    [y1, x1, z1] = ind2sub(size(GTV_in), i_idx);
+    
+    waitbar(i/numel(CTV_idx_lst),f);
+    
+    % get the crop of nearby voxels in tumor
+%     tabula = zeros(size(GTV_in));
+%     tabula(i_idx) = 1;
+%     tabula2 = convn(tabula, kernel, 'same');
+%     idx_nearby = find(tabula2>0);
+    
+    idx_nearby = f_neighbors(i_idx, size(GTV_in), ir_a, infilt_range, GTV_meta.spacedirections);
+    
+    % overlap
+    idx_GTV_nearby = intersect (idx_nearby, GTV_idx_lst);
+    
+    if numel(idx_GTV_nearby) <1
+        prob_CTV_solutions(i) = 0;
+        error('this is fucky. no voxels within range')
+    end
+    
+    p_list=zeros(1, numel(idx_GTV_nearby));
+    p_list_max = 0;
+    
+    for j = 1:numel(idx_GTV_nearby)
+        j_idx = idx_GTV_nearby(j);
+        if GTV_in(j_idx) < p_list_max
+            continue
+        end
+        
+        [y2, x2, z2] = ind2sub(size(GTV_in), j_idx);
+        d = sqrt((((y2-y1)*GTV_meta.spacedirections(1))^2 + ...
+            ((x2-x1)*GTV_meta.spacedirections(2))^2 + ((z2-z1)*GTV_meta.spacedirections(3))^2));
+        % get probability of invisible infiltration at given voxel, based
+        % on single voxel from tumor
+        p_list(j) = GTV_in(j_idx) * exp(-(d*d)/(infilt_range*infilt_range));
+        
+        p_list_max = max(p_list_max, p_list(j));
+        
+        if p_list(j) == 1
+            prob_CTV_solutions(i) = 1;
+            break
+        end
+    end
+    prob_CTV_solutions(i) = max(p_list);
+end
+toc
+prob_CTV(CTV_idx_lst) = prob_CTV_solutions;
+close(f)
+
+colorwash(CT_in, prob_CTV,  [-500, 500], [0, 1.2]);
+
+
+%% save outputs
+filename = [paths.in '\RODP_files\' paths.target_bin_in '_fuzzyCTV.nrrd'];
+matrix = single(prob_CTV);
+pixelspacing = GTV_meta.spacedirections;
+origin = GTV_meta.spaceorigin;
+nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
+
+end
+function neigh_mat_idx = f_neighbors(idx, mat_size, ir_a, infilt_range, voxsize);
+% this function returns indeces of the box nearby around 
+    [y, x, z] = ind2sub(mat_size, idx);
+    
+    y1 = max(1, floor(y - ir_a*infilt_range/(voxsize(1))));
+    y2 = min(mat_size(1), ceil(y + ir_a*infilt_range/(voxsize(1))));
+    
+    x1 = max(1, floor(x - ir_a*infilt_range/(voxsize(2))));
+    x2 = min(mat_size(1), ceil(x + ir_a*infilt_range/(voxsize(2))));
+    
+    z1 = max(1, floor(z - ir_a*infilt_range/(voxsize(3))));
+    z2 = min(mat_size(1), ceil(z + ir_a*infilt_range/(voxsize(3))));
+    
+    tabula = zeros(mat_size);
+    tabula(y1:y2, x1:x2, z1:z2)=1;
+    
+    neigh_mat_idx = find( tabula>0);
+
+end
+
+function vol_prep_DPmap(paths, dose)
+% this function takes in the segmentations and creates fuzzy (probabilistic)
+% PTV/GTV/CTV volumes
+
+[CT_in, CT_meta] = nrrdread([paths.in '\' paths.CT_in '.nrrd']);
+[CTV_fuzzy, CTV_meta] = nrrdread([paths.in '\RODP_files\' paths.target_bin_in '_fuzzyCTV.nrrd']);
+
+dose_min = f_dose_min(CTV_fuzzy, dose.min);
+dose_max = f_dose_max(CTV_fuzzy, dose.max);
+
+orthoslice(dose_min, [0, dose.max+10]) % plot min dose boundary
+orthoslice(dose_max, [0, dose.max+10]) % plot max dose boundary
+
+%% save outputs
+filename = [paths.in '\RODP_files\' paths.target_bin_in '_DP_minDose.nrrd'];
+% filename = [pathIn 'RODP_files\FET_FGL005_B1_DP_minDose.nrrd'];
+matrix = single(dose_min);
+pixelspacing = CTV_meta.spacedirections;
+origin = CTV_meta.spaceorigin;
+nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
+
+filename = [paths.in '\RODP_files\' paths.target_bin_in '_DP_maxDose.nrrd'];
+% filename = [pathIn 'RODP_files\FET_FGL005_B1_DP_maxDose.nrrd'];
+matrix = single(dose_max);
+pixelspacing = CTV_meta.spacedirections;
+origin = CTV_meta.spaceorigin;
+nrrdWriter(filename, matrix, pixelspacing, origin, 'raw');
+
+end
+function dose_min = f_dose_min(CTV_fuzzy, D_min)
+% get low boundary for ideal dose plan
+dose_min = D_min* min(1, 2* max(0, (CTV_fuzzy - 0.25)));
+dose_min(CTV_fuzzy>0.98) = 1.2*D_min;
+% orthoslice(dose_min)
+end
+function dose_max = f_dose_max(CTV_fuzzy, D_max)
+% get hihg boundary for ideal dose plan
+dose_max = D_max* min(1, 2* max(0, (CTV_fuzzy - 0.0)));
+dose_max(CTV_fuzzy>0.98) = 1.2*D_max;
+end