lsq_util.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /* lsq_util.c */
  2. // Least squares utilities.
  3. #include "lsq.h"
  4. extern char errstr[200]; // error string
  5. int calculate_dose_diff(GRID_ARRAY *beamlets, float weight_diff, int weight_bixel_num, GRID *dose)
  6. {
  7. // only change the summed dose by the dose change of a single beamlet
  8. static int i;
  9. // dose calculation with sparse beamlet matrices
  10. for (i=0; i<beamlets->array[weight_bixel_num].size; i++)
  11. dose->matrix[beamlets->array[weight_bixel_num].indices[i]]
  12. += weight_diff*beamlets->array[weight_bixel_num].data[i];
  13. return(SUCCESS);
  14. }
  15. // put a full dose calculation file here
  16. int calculate_dose(GRID_ARRAY *beamlets, GRID *dose)
  17. // do a full dose calculation
  18. {
  19. static int i,j;
  20. // clear the dose grid
  21. for (i=0;i<beamlets->Nvox;i++)
  22. dose->matrix[i] = 0.0;
  23. // dose calculation with sparse beamlet matrices
  24. for (j=0;j<beamlets->num_beamlets;j++) // loop through beams
  25. for (i=0;i<beamlets->array[j].size;i++) // loop through non-zero dose voxels
  26. dose->matrix[beamlets->array[j].indices[i]]
  27. += beamlets->beam_weight[j]*beamlets->array[j].data[i];
  28. return(SUCCESS);
  29. }
  30. int calc_dvh(GRID *dose, int Nind, int *ind, DVH *dvh)
  31. // Calculates a dose volume histogram using the dose grid based on the parameters in DVH.
  32. // Memory for the dvh array must be pre-allocated before calling this function.
  33. // The resulting DVH is given in units of percent volume [0..100].
  34. {
  35. int i,n,m;
  36. // fill the dvh with zeros
  37. for (m=0;m<dvh->Nbins;m++)
  38. dvh->dvh[m] = 0.0;
  39. // quit if del_d is less than or equal to zero
  40. if (dvh->del_d <= 0.0)
  41. {
  42. sprintf(errstr,"del_d was less than or equal to zero");
  43. printf("del_d error\n");
  44. return(FAILURE);
  45. }
  46. // calculate the DVH
  47. for (n=0;n<Nind;n++)
  48. {
  49. // dose index in the dose grid
  50. i = ind[n];
  51. // find the dose index in the dvh
  52. m = (int)(dose->matrix[i]/dvh->del_d);
  53. if (m >= 0 && m < dvh->Nbins)
  54. dvh->dvh[m] += (float)1.0;
  55. }
  56. // integrate the dvh from d to infinity for all d, then normalize to 100% at d=0
  57. for (m=dvh->Nbins-2;m>=0;m--)
  58. dvh->dvh[m] += dvh->dvh[m+1];
  59. // normalization step
  60. if (Nind != 0) // avoid divide-by-zero errors
  61. for (m=0;m<dvh->Nbins;m++)
  62. dvh->dvh[m] *= (float)100.0/(float)Nind;
  63. else // no voxels, but 100% still gets 0 Gy or more
  64. dvh->dvh[0] = 100;
  65. return(SUCCESS);
  66. }
  67. int output_dose_weights(GRID_ARRAY *beamlets, GRID *dose,
  68. char *dosefilename, char *weightfilename)
  69. // Writes the current dose distribution and beamlet weights to dosefilename
  70. // and weightfilename, respectively.
  71. {
  72. FILE *dosefile, *weightfile;
  73. dosefile = fopen(dosefilename,"wb");
  74. weightfile = fopen(weightfilename,"wb");
  75. // print dose and weight files
  76. if ((int)fwrite(dose->matrix,sizeof(float),beamlets->Nvox,dosefile) != beamlets->Nvox)
  77. {
  78. sprintf(errstr,"Unable to write dose data to file \n%s.",dosefilename);
  79. return(FAILURE);
  80. }
  81. if ((int)fwrite(beamlets->beam_weight,sizeof(float),beamlets->num_beamlets,weightfile) != beamlets->num_beamlets)
  82. {
  83. sprintf(errstr,"Unable to write beamlet weight data to file \n%s.",weightfilename);
  84. return(FAILURE);
  85. }
  86. fclose(dosefile);
  87. fclose(weightfile);
  88. return(SUCCESS);
  89. }
  90. float calc_obj_func(GRID_ARRAY *beamlets, GRID *dose, PRESC *presc)
  91. // Calculate the objective function value.
  92. {
  93. int i, j, k;
  94. float E, Eplus, Eminus, Edvh_plus, Edvh_minus;
  95. float diff, del_d_plus, del_d_minus;
  96. E = 0.0;
  97. for (k=0;k<presc->Ntissue;k++) // loop through all tissue types
  98. if (presc->array[k].Nind != 0 && presc->array[k].alpha > 0.0)
  99. // continue only if the ROI contains voxels and has an importance above zero
  100. {
  101. // initialize objective function terms for tissue k to zero
  102. Eplus = 0.0;
  103. Eminus = 0.0;
  104. Edvh_plus = 0.0;
  105. Edvh_minus = 0.0;
  106. // calculate the over- and underdose penalty terms
  107. for (j=0;j<presc->array[k].Nind;j++)
  108. {
  109. i = presc->array[k].ind[j]; // current voxel index
  110. // overdose penalty term
  111. diff = dose->matrix[i] - presc->array[k].dPlus[j];
  112. if (diff > 0.0)
  113. Eplus += diff*diff;
  114. // underdose penalty term
  115. diff = dose->matrix[i] - presc->array[k].dMinus[j];
  116. if (diff < 0.0)
  117. Eminus += diff*diff;
  118. }
  119. // calculate the dvh penalties if they apply
  120. if ((presc->array[k].betaVPlus > 0.0) || (presc->array[k].betaVMinus > 0.0))
  121. {
  122. if (presc->array[k].betaVPlus > 0.0)
  123. // penalize overdosed dose volume considerations
  124. {
  125. del_d_plus = presc->array[k].dvh.del_d_plus;
  126. // dvh_plus constraints
  127. for (j=0;j<presc->array[k].Nind;j++)
  128. {
  129. i = presc->array[k].ind[j]; // current voxel of interest
  130. diff = dose->matrix[i] - presc->array[k].dVPlus;
  131. if (diff >= 0 && diff <= del_d_plus) // see if this voxel should be penalized
  132. Edvh_plus += diff*diff;
  133. }
  134. }
  135. if (presc->array[k].betaVMinus > 0.0)
  136. // penalize underdosed dose volume considerations
  137. {
  138. del_d_minus = presc->array[k].dvh.del_d_minus;
  139. // dvh_minus constraints
  140. for (j=0;j<presc->array[k].Nind;j++)
  141. {
  142. i = presc->array[k].ind[j]; // current voxel of interest
  143. diff = dose->matrix[i] - presc->array[k].dVMinus;
  144. if (diff >= del_d_minus && diff <= 0) // see if this voxel should be penalized
  145. Edvh_minus += diff*diff;
  146. }
  147. }
  148. }
  149. // update the objective function
  150. E += presc->array[k].alpha/(float)presc->array[k].Nind
  151. *(presc->array[k].betaPlus*Eplus
  152. + presc->array[k].betaMinus*Eminus
  153. + presc->array[k].betaVPlus*Edvh_plus
  154. + presc->array[k].betaVMinus*Edvh_minus);
  155. }
  156. return(E);
  157. }
  158. int compare(void *arg1, void *arg2)
  159. // Compare two floats to each other.
  160. {
  161. if (*(float *)arg1 < *(float *)arg2)
  162. return -1;
  163. else if (*(float *)arg1 == *(float *)arg2)
  164. return 0;
  165. else
  166. return 1;
  167. }
  168. int calcAllDvhs(GRID *dose, PRESC *presc)
  169. // Calculates the dvh for each tissue type in the prescription
  170. {
  171. int i, j, k;
  172. float d_max;
  173. char tmpstr[200];
  174. for (k=0;k<presc->Ntissue;k++)
  175. {
  176. // find the current maximum dose in the ROI
  177. d_max = 0.0;
  178. for (j=0;j<presc->array[k].Nind;j++)
  179. {
  180. i = presc->array[k].ind[j]; // current voxel index
  181. if (dose->matrix[i] > d_max)
  182. d_max = dose->matrix[i];
  183. }
  184. // set up dose bins for the current dvh
  185. presc->array[k].dvh.Nbins = Ndvh_bins;
  186. presc->array[k].dvh.dmax = d_max*(float)1.1; // go over the max dose by a small amount
  187. if (d_max != 0.0) // zero dose delivered to this tissue
  188. presc->array[k].dvh.del_d = presc->array[k].dvh.dmax/(float)presc->array[k].dvh.Nbins;
  189. else
  190. presc->array[k].dvh.del_d = (float)100.0/(float)presc->array[k].dvh.Nbins;
  191. // calculate the dvh for this tissue
  192. if (calc_dvh(dose, presc->array[k].Nind, presc->array[k].ind, &presc->array[k].dvh) == FAILURE)
  193. {
  194. strcpy(tmpstr,errstr); // copy the error string passed from the dvh calculator
  195. sprintf(errstr,"Failed in DVH calculation for tissue %d:\n%s\n",k,tmpstr);
  196. return(FAILURE);
  197. }
  198. // if applicable in the optimization, find del_d_plus and del_d_minus
  199. if (presc->array[k].betaVPlus > 0.0)
  200. {
  201. // find where vPlus occurs in the DVH
  202. for (j=0;j<presc->array[k].dvh.Nbins;j++)
  203. if (presc->array[k].dvh.dvh[j] < presc->array[k].vPlus)
  204. break;
  205. // j is the dvh index that marks the crossing from above to below vPlus
  206. // use j to see if any dvh penalties will be applied here
  207. if ((float)j*presc->array[k].dvh.del_d >= presc->array[k].dVPlus)
  208. presc->array[k].dvh.del_d_plus
  209. = (float)j*presc->array[k].dvh.del_d - presc->array[k].dVPlus;
  210. else
  211. presc->array[k].dvh.del_d_plus = 0.0;
  212. }
  213. if (presc->array[k].betaVMinus > 0.0)
  214. {
  215. // find where vMinus occurs in the DVH
  216. for (j=0;j<presc->array[k].dvh.Nbins;j++)
  217. if (presc->array[k].dvh.dvh[j] < presc->array[k].vMinus)
  218. break;
  219. // j is the dvh index that marks the crossing from above to below vMinus
  220. // use j to see if any dvh penalties will be applied here
  221. if ((float)j*presc->array[k].dvh.del_d <= presc->array[k].dVMinus)
  222. presc->array[k].dvh.del_d_minus
  223. = (float)j*presc->array[k].dvh.del_d - presc->array[k].dVMinus;
  224. else
  225. presc->array[k].dvh.del_d_minus = 0.0;
  226. }
  227. }
  228. return(SUCCESS);
  229. }
  230. int find_used_voxels(PRESC *presc, int *usedVoxels)
  231. // Finds all voxels that are affected by the prescription. Voxels that are
  232. // affected are marked as 1, those that aren't are marked as 0.
  233. {
  234. int i,j,k;
  235. // voxels are unused until proven otherwise
  236. for (i=0;i<presc->x_count*presc->y_count*presc->z_count;i++)
  237. usedVoxels[i] = 0;
  238. // loop through all tissues, finding voxels that are used
  239. for (k=0;k<presc->Ntissue;k++)
  240. if ( (presc->array[k].alpha > 0.0)
  241. && ( presc->array[k].betaMinus > 0.0 || presc->array[k].betaPlus
  242. || presc->array[k].betaVMinus || presc->array[k].betaVPlus ))
  243. for (j=0;j<presc->array[k].Nind;j++)
  244. usedVoxels[presc->array[k].ind[j]] = 1;
  245. return(SUCCESS);
  246. }
  247. int fillPrescriptionGrid(PRESC *presc, PRESCGRID *prescGrid)
  248. {
  249. int i,j,k;
  250. int *currTiss;
  251. prescGrid->x_count = presc->x_count;
  252. prescGrid->y_count = presc->y_count;
  253. prescGrid->z_count = presc->z_count;
  254. prescGrid->Nvox = presc->x_count*presc->y_count*presc->z_count;
  255. prescGrid->array = (PRESCNODE **)malloc(sizeof(PRESCNODE *)*prescGrid->Nvox);
  256. prescGrid->numNodes = (int *)malloc(sizeof(int)*prescGrid->Nvox);
  257. for (i=0;i<prescGrid->Nvox;i++) prescGrid->numNodes[i] = 0;
  258. // Count the number of tissues that fall inside each voxel
  259. for (k=0;k<presc->Ntissue;k++)
  260. if ( (presc->array[k].alpha > 0.0)
  261. && ( presc->array[k].betaMinus > 0.0 || presc->array[k].betaPlus
  262. || presc->array[k].betaVMinus || presc->array[k].betaVPlus ))
  263. for (j=0;j<presc->array[k].Nind;j++)
  264. prescGrid->numNodes[presc->array[k].ind[j]]++;
  265. // allocate memory for the prescription grid nodes
  266. for (i=0;i<prescGrid->Nvox;i++)
  267. if (prescGrid->numNodes[i] > 0)
  268. prescGrid->array[i] = (PRESCNODE *)malloc(sizeof(PRESCNODE)*prescGrid->numNodes[i]);
  269. // tally of the current number of tissues that have been placed in a voxel
  270. currTiss = (int *)malloc(sizeof(int)*prescGrid->Nvox);
  271. for (i=0;i<prescGrid->Nvox;i++) currTiss[i] = 0;
  272. // fill the prescription grid nodes
  273. for (k=0;k<presc->Ntissue;k++)
  274. if ( (presc->array[k].alpha > 0.0)
  275. && ( presc->array[k].betaMinus > 0.0 || presc->array[k].betaPlus
  276. || presc->array[k].betaVMinus || presc->array[k].betaVPlus ))
  277. for (j=0;j<presc->array[k].Nind;j++)
  278. {
  279. i = presc->array[k].ind[j]; // current voxel
  280. prescGrid->array[i][currTiss[i]].tissueInd = k;
  281. prescGrid->array[i][currTiss[i]].dMinus = presc->array[k].dMinus[j];
  282. prescGrid->array[i][currTiss[i]].dPlus = presc->array[k].dPlus[j];
  283. currTiss[i]++;
  284. }
  285. return(SUCCESS);
  286. }
  287. int loadBeamletsCalcDose(OPT_PARAM *op, GRID *dose, GRID_ARRAY *beamlets)
  288. // Loads all beamlets and calculates total dose using the current set of beamlet
  289. // weights. This function is necessary when the beamlets used for the optimization
  290. // have been scaled down to only include voxels that are used in the optimization.
  291. {
  292. int i,j,k,m,beamletNum,Nbeamlets,dims[3],Nind,num;
  293. char bixbatchfile[1000];
  294. int *ind;
  295. float *data;
  296. FILE *fid;
  297. beamletNum = 0;
  298. // reset the dose distribution to all zeros
  299. for (i=0;i<beamlets->Nvox;i++) dose->matrix[i] = 0.0;
  300. // load one beamlet at at a time, calculating total dose along the way
  301. for (k=0;k<beamlets->num_beamlet_batches;k++)
  302. {
  303. // open the beamlet batch file
  304. sprintf(bixbatchfile,"%s/%s%d.%s",op->bix_dir,op->bix_batch_base_filename,k,op->bix_batch_extension);
  305. if ((fid = fopen(bixbatchfile,"rb")) == NULL)
  306. {
  307. sprintf(errstr,"Unable to open file for beamlet batch %d.\n,filename: %s",k,bixbatchfile);
  308. return(FAILURE);
  309. }
  310. // read-in the number of beamlets that are in this file
  311. if((int)fread(&Nbeamlets,sizeof(int),1,fid) != 1)
  312. {
  313. sprintf(errstr,"Unable to read number of beamlets in file:\n%s",bixbatchfile);
  314. return(FAILURE);
  315. }
  316. // read-in all of the beamlets in the current batch
  317. for (j=0;j<Nbeamlets;j++)
  318. {
  319. if((int)fread(&num,sizeof(int),1,fid) != 1)
  320. {
  321. sprintf(errstr,"Unable to read beamlet number for beamlet %d in file:\n%s",j,bixbatchfile);
  322. return(FAILURE);
  323. }
  324. // read the beamlet dimensions
  325. if((int)fread(dims,sizeof(int),3,fid) != 3)
  326. {
  327. sprintf(errstr,"Unable to read beamlet dimensions for beamlet %d in file:\n%s",j,bixbatchfile);
  328. return(FAILURE);
  329. }
  330. // ensure that the beamlet has the same grid size as the prescription
  331. if((dims[0] != beamlets->x_count) || (dims[1] != beamlets->y_count) || (dims[2] != beamlets->z_count))
  332. {
  333. sprintf(errstr,"Mismatch in grid dimensions for beamlet %d in file:\n%s",j,bixbatchfile);
  334. return(FAILURE);
  335. }
  336. // read the number of non-zero values in the current beamlet
  337. if((int)fread(&Nind,sizeof(int),1,fid) != 1)
  338. {
  339. sprintf(errstr,"Unable to read number of non-zero values for beamlet %d in file:\n%s",j,bixbatchfile);
  340. return(FAILURE);
  341. }
  342. // allocate memory and read-in indices for the current beamlet
  343. if((ind = (int *)malloc(sizeof(int)*Nind)) == NULL)
  344. {
  345. sprintf(errstr,"Unable to allocate memory for indices of beamlet %d\n",num);
  346. return(FAILURE);
  347. }
  348. if((int)fread(ind,sizeof(int),Nind,fid) != Nind)
  349. {
  350. sprintf(errstr,"Unable to read-in indices for beamlet %d\n",num);
  351. return(FAILURE);
  352. }
  353. // allocate memory and read-in indices for the current beamlet
  354. if((data = (float *)malloc(sizeof(float)*Nind)) == NULL)
  355. {
  356. sprintf(errstr,"Unable to allocate memory for data of beamlet %d\n",num);
  357. return(FAILURE);
  358. }
  359. if((int)fread(data,sizeof(float),Nind,fid) != Nind)
  360. {
  361. sprintf(errstr,"Unable to read-in dose data for beamlet %d\n",num);
  362. return(FAILURE);
  363. }
  364. // add the current beamlet to the dose distribution
  365. for (m=0;m<Nind;m++)
  366. dose->matrix[ind[m]] += data[m]*beamlets->beam_weight[beamletNum];
  367. // free indices and data for the full beamlet
  368. free(ind);
  369. free(data);
  370. beamletNum++; // increment the beamlet number
  371. }
  372. printf("Successfully loaded beamlet batch %d of %d.\n",k+1,beamlets->num_beamlet_batches);
  373. fclose(fid);
  374. }
  375. return(SUCCESS);
  376. }
  377. int truncateBeamWeights(float *beamWeights, int Nbeamlets, float modFactor)
  378. // Applies modulation factor to all of the beamlet weights, including
  379. // the ones that are not flagged.
  380. {
  381. int j, Nnonzero;
  382. float meanInt, maxInt;
  383. Nnonzero = 0;
  384. maxInt = 0.0;
  385. meanInt = 0.0;
  386. for (j=0;j<Nbeamlets;j++)
  387. if (beamWeights[j] > 0.0)
  388. {
  389. Nnonzero++;
  390. meanInt += beamWeights[j];
  391. }
  392. meanInt /= (float)Nnonzero; // calculate the mean of the intensity weights
  393. maxInt = modFactor*meanInt; // maximum allowable intensity
  394. // set any weights that are greater than the maximum to the maximum intensity
  395. for (j=0;j<Nbeamlets;j++)
  396. if (beamWeights[j] > maxInt)
  397. beamWeights[j] = maxInt;
  398. return(SUCCESS);
  399. }