lsq_main.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /* lsq is a linear least squares optimization algorithm for finding
  2. optimal energy fluence weighting factors for radiation therapy. Tomotherapy
  3. has a patent on the algorithm. The algorithm is explained in detail by
  4. Dave Shepard in the publication: PMB 45 (2000) 69-90. */
  5. #include "lsq.h"
  6. char errstr[200]; // globally available string for passing errors
  7. int firstIterFlag; // flag that is activated only on the first iteration
  8. #define OPT_INPUT_FILE "optInput.txt"
  9. int main(int argc, char *argv[])
  10. // Expects one or zero command line input arguments. If a lsq header file is not
  11. // included as an input argument, then OPT_INPUT_FILE is used.
  12. {
  13. float weight_diff, start_time, end_time, update_factor;
  14. float clockStart, clockStop;
  15. int *usedVoxels;
  16. int i, j, iter_num;
  17. // filename strings
  18. char opt_input_file[200];
  19. float *E; // objective function values
  20. char doseFileStr[200];
  21. char weightFileStr[200];
  22. // structures for the optimization
  23. PRESC presc;
  24. PRESCGRID prescGrid;
  25. OPT_PARAM op;
  26. GRID dose;
  27. GRID doseTot;
  28. GRID_ARRAY beamlets;
  29. // dummy file
  30. FILE *fid;
  31. // check to see if an input argument was supplied
  32. if (argc > 2) // calling the executable counts as one argument
  33. {
  34. printf("Expecting one or zero input command line arguments, received %d.\n",argc);
  35. return(FAILURE);
  36. }
  37. if (argc == 1) // only the executable was called, no other arguments
  38. strcpy(opt_input_file,OPT_INPUT_FILE);
  39. else // one arguments was supplied
  40. strcpy(opt_input_file,argv[1]);
  41. // read in optimization parameters
  42. if (read_in_opt_parameters(&op, opt_input_file) == FAILURE)
  43. {
  44. printf("Failed to read in optimization properties:\n%s\n",errstr);
  45. return(FAILURE);
  46. }
  47. else
  48. printf("Successfully read-in optimization parameters.\n");
  49. // print optimization parameters for verification of readin
  50. printf("Niterations = %d\n",op.Niterations);
  51. printf("prescription_filename = %s\n",op.prescription_filename);
  52. printf("initial_beam_weights_filename = %s\n",op.initial_beam_weights_filename);
  53. printf("beamlet_header_file = %s\n",op.beamlet_header_file);
  54. printf("dose_batch_base_name = %s\n",op.dose_batch_base_name);
  55. printf("dose_batch_extension = %s\n",op.dose_batch_extension);
  56. printf("weight_batch_base_name = %s\n",op.weight_batch_base_name);
  57. printf("weight_batch_extension = %s\n",op.weight_batch_extension);
  58. printf("modFactor = %d\n",op.modFactor);
  59. // read in the prescription
  60. if (read_in_prescription(&presc, op.prescription_filename) == FAILURE)
  61. {
  62. printf("Failed to read in prescription:\n%s\n",errstr);
  63. return(FAILURE);
  64. }
  65. else
  66. printf("Successfully read-in prescription.\n");
  67. fillPrescriptionGrid(&presc, &prescGrid);
  68. if ( (usedVoxels = (int *)malloc(sizeof(int)*presc.Nvox)) == NULL)
  69. {
  70. printf("Memory allocation for usedVoxels array failed.\n");
  71. return(FAILURE);
  72. }
  73. fid = fopen("prescGridTest.bin","wb");
  74. fwrite(prescGrid.numNodes,sizeof(int),prescGrid.Nvox,fid);
  75. fclose(fid);
  76. if (SMARTBEAMLETS == 1)
  77. find_used_voxels(&presc,usedVoxels);
  78. else
  79. for (i=0;i<presc.Nvox;i++) usedVoxels[i] = 1;
  80. // count number of used voxels
  81. i = 0;
  82. for (j=0;j<presc.Nvox;j++)
  83. if (usedVoxels[j] == 1)
  84. i++;
  85. printf("total number of used voxels = %d\n",i);
  86. // allocate memory for dose matrix
  87. if ((dose.matrix = (float *)malloc(sizeof(float)*presc.Nvox)) == NULL)
  88. {
  89. printf("Memory allocation for dose matrix failed.\n");
  90. return(FAILURE);
  91. }
  92. dose.x_count = presc.x_count;
  93. dose.y_count = presc.y_count;
  94. dose.z_count = presc.z_count;
  95. dose.Nvox = presc.Nvox;
  96. // allocate memory for the total dose matrix
  97. if ((doseTot.matrix = (float *)malloc(sizeof(float)*presc.Nvox)) == NULL)
  98. {
  99. printf("Memory allocation for dose matrix failed.\n");
  100. return(FAILURE);
  101. }
  102. doseTot.x_count = presc.x_count;
  103. doseTot.y_count = presc.y_count;
  104. doseTot.z_count = presc.z_count;
  105. doseTot.Nvox = presc.Nvox;
  106. // load the beamlets into memory, calculate full initial guess
  107. if (read_in_beamlets(&beamlets,op.beamlet_header_file,op.initial_beam_weights_filename,usedVoxels,&op,&doseTot) == FAILURE)
  108. {
  109. printf("Read in beamlets failed: %s\n",errstr);
  110. return(FAILURE);
  111. }
  112. // ensure that dimensions of beamlets and prescription masks are consistent
  113. if (beamlets.x_count != presc.x_count
  114. || beamlets.y_count != presc.y_count
  115. || beamlets.z_count != presc.z_count)
  116. {
  117. printf("Prescription dimensions (%d,%d,%d) do not match beamlet dimensions (%d,%d,%d)\n",
  118. presc.x_count,presc.y_count,presc.z_count,
  119. beamlets.x_count,beamlets.y_count,beamlets.z_count);
  120. return(FAILURE);
  121. }
  122. // calculate initial dose for the purposes of the optimization
  123. clockStart = clock()/(float)CLOCKS_PER_SEC;
  124. calculate_dose(&beamlets, &dose);
  125. clockStop = clock()/(float)CLOCKS_PER_SEC;
  126. printf("initial dose successfully calculated\n");
  127. printf("Initial dosecalc time = %f\n",clockStop - clockStart);
  128. calcAllDvhs(&dose, &presc); // recalculate dvhs
  129. printf("initial dvhs successfully calculated\n");
  130. // start the clock
  131. start_time = clock()/(float) CLOCKS_PER_SEC;
  132. printf ("Starting iterations\n" );
  133. E = (float *)malloc(sizeof(float)*op.Niterations+1);
  134. // write the initial guess to a file
  135. sprintf(doseFileStr,"%s%d.%s",op.dose_batch_base_name,0,op.dose_batch_extension);
  136. fid = fopen(doseFileStr,"wb");
  137. if (SMARTBEAMLETS == 1)
  138. fwrite(doseTot.matrix,sizeof(float),beamlets.Nvox,fid);
  139. else
  140. fwrite(dose.matrix,sizeof(float),beamlets.Nvox,fid);
  141. fclose(fid);
  142. // write initial weights guess to a file
  143. sprintf(weightFileStr,"%s%d.%s",op.weight_batch_base_name,0,op.weight_batch_extension);
  144. fid = fopen(weightFileStr,"wb");
  145. fwrite(beamlets.beam_weight,sizeof(float),beamlets.num_beamlets,fid);
  146. fclose(fid);
  147. // calculate the initial objective function value
  148. E[0] = calc_obj_func(&beamlets,&dose,&presc);
  149. printf("Initial objective function value = %f\n",E[0]);
  150. // calculate one optimization iteration
  151. for (iter_num = 0; iter_num < op.Niterations; iter_num++)
  152. {
  153. if (iter_num == 0)
  154. firstIterFlag = 0;
  155. else
  156. firstIterFlag = 0;
  157. for (j=0;j<beamlets.num_beamlets;j++)
  158. if (beamlets.beam_weight[j] != 0.0) // proceed only if the beam is not turned off
  159. {
  160. if (calc_update_factor(&beamlets, &dose, &presc, j, &update_factor, &prescGrid) == FAILURE)
  161. {
  162. printf("Failed in update factor calculation for iteration %d, beamlet number %d:\n%s\n",iter_num,j,errstr);
  163. return(FAILURE);
  164. }
  165. // difference between new and old weights
  166. weight_diff = (update_factor - (float)1.0)*beamlets.beam_weight[j];
  167. // new beamlet weight
  168. beamlets.beam_weight[j] *= update_factor;
  169. }
  170. // apply modulation factor
  171. truncateBeamWeights(beamlets.beam_weight,beamlets.num_beamlets,op.modFactor);
  172. calculate_dose(&beamlets, &dose); // recalculate the dose distribution
  173. calcAllDvhs(&dose, &presc); // recalculate dvhs
  174. // calculate the objective function
  175. E[iter_num+1] = calc_obj_func(&beamlets,&dose,&presc);
  176. printf("Objective function for iteration %d of %d was %f\n",iter_num+1,op.Niterations,E[iter_num+1]);
  177. if ((int)fmod((double)iter_num+1.0,op.Nperbatch) == 0 || iter_num + 1 == op.Niterations)
  178. {
  179. printf("Printing dose and weights.\n");
  180. if (SMARTBEAMLETS == 1)
  181. {
  182. printf("Loading full beamlets for dose calculation ...\n");
  183. // load the beamlets and calculate dose
  184. if (loadBeamletsCalcDose(&op, &doseTot, &beamlets) != SUCCESS)
  185. {
  186. printf("Failed to calculate total dose for output of results: %s\n",errstr);
  187. return(FAILURE);
  188. }
  189. }
  190. // create dose filename
  191. sprintf(doseFileStr,"%s%d.%s",op.dose_batch_base_name,iter_num+1,op.dose_batch_extension);
  192. fid = fopen(doseFileStr,"wb");
  193. if (SMARTBEAMLETS == 1)
  194. fwrite(doseTot.matrix,sizeof(float),beamlets.Nvox,fid);
  195. else
  196. fwrite(dose.matrix,sizeof(float),beamlets.Nvox,fid);
  197. fclose(fid);
  198. // create weights filename
  199. sprintf(weightFileStr,"%s%d.%s",op.weight_batch_base_name,iter_num+1,op.weight_batch_extension);
  200. fid = fopen(weightFileStr,"wb");
  201. fwrite(beamlets.beam_weight,sizeof(float),beamlets.num_beamlets,fid);
  202. fclose(fid);
  203. }
  204. }
  205. end_time = clock()/((float) CLOCKS_PER_SEC);
  206. // write the objective function vector to a file
  207. fid = fopen(op.obj_func_name,"wb");
  208. fwrite(E,sizeof(float),op.Niterations+1,fid);
  209. fclose(fid);
  210. free(usedVoxels);
  211. // free the memory allocated for the dose grid
  212. free(dose.matrix);
  213. free(doseTot.matrix);
  214. for (i=0; i<beamlets.num_beamlets;i++)
  215. {
  216. free(beamlets.array[i].indices);
  217. free(beamlets.array[i].data);
  218. }
  219. free(beamlets.beam_weight);
  220. free(beamlets.initial_beam_weight);
  221. // free prescription arrays
  222. for (i=0;i<presc.Ntissue;i++)
  223. {
  224. free(presc.array[i].ind);
  225. free(presc.array[i].dMinus);
  226. free(presc.array[i].dPlus);
  227. }
  228. free(presc.array);
  229. // free prescription grid
  230. for (i=0;i<prescGrid.Nvox;i++)
  231. if (prescGrid.numNodes[i] > 0)
  232. free(prescGrid.array[i]);
  233. free(prescGrid.array);
  234. free(prescGrid.numNodes);
  235. printf("Elapsed optimization time %f\n",end_time-start_time);
  236. // create a file that signals that the optimization is done
  237. fid = fopen("optDone.txt","w");
  238. fprintf(fid,"Optimization complete\n");
  239. fclose(fid);
  240. return(SUCCESS);
  241. }