123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- /* lsq_util.c */
- // Least squares utilities.
- #include "lsq.h"
- extern char errstr[200]; // error string
- int calculate_dose_diff(GRID_ARRAY *beamlets, float weight_diff, int weight_bixel_num, GRID *dose)
- {
- // only change the summed dose by the dose change of a single beamlet
- static int i;
- // dose calculation with sparse beamlet matrices
- for (i=0; i<beamlets->array[weight_bixel_num].size; i++)
- dose->matrix[beamlets->array[weight_bixel_num].indices[i]]
- += weight_diff*beamlets->array[weight_bixel_num].data[i];
- return(SUCCESS);
- }
- // put a full dose calculation file here
- int calculate_dose(GRID_ARRAY *beamlets, GRID *dose)
- // do a full dose calculation
- {
- static int i,j;
- // clear the dose grid
- for (i=0;i<beamlets->Nvox;i++)
- dose->matrix[i] = 0.0;
- // dose calculation with sparse beamlet matrices
- for (j=0;j<beamlets->num_beamlets;j++) // loop through beams
- for (i=0;i<beamlets->array[j].size;i++) // loop through non-zero dose voxels
- dose->matrix[beamlets->array[j].indices[i]]
- += beamlets->beam_weight[j]*beamlets->array[j].data[i];
- return(SUCCESS);
- }
- int calc_dvh(GRID *dose, int Nind, int *ind, DVH *dvh)
- // Calculates a dose volume histogram using the dose grid based on the parameters in DVH.
- // Memory for the dvh array must be pre-allocated before calling this function.
- // The resulting DVH is given in units of percent volume [0..100].
- {
- int i,n,m;
- // fill the dvh with zeros
- for (m=0;m<dvh->Nbins;m++)
- dvh->dvh[m] = 0.0;
-
- // quit if del_d is less than or equal to zero
- if (dvh->del_d <= 0.0)
- {
- sprintf(errstr,"del_d was less than or equal to zero");
- printf("del_d error\n");
- return(FAILURE);
- }
- // calculate the DVH
- for (n=0;n<Nind;n++)
- {
- // dose index in the dose grid
- i = ind[n];
- // find the dose index in the dvh
- m = (int)(dose->matrix[i]/dvh->del_d);
- if (m >= 0 && m < dvh->Nbins)
- dvh->dvh[m] += (float)1.0;
- }
-
- // integrate the dvh from d to infinity for all d, then normalize to 100% at d=0
- for (m=dvh->Nbins-2;m>=0;m--)
- dvh->dvh[m] += dvh->dvh[m+1];
- // normalization step
- if (Nind != 0) // avoid divide-by-zero errors
- for (m=0;m<dvh->Nbins;m++)
- dvh->dvh[m] *= (float)100.0/(float)Nind;
- else // no voxels, but 100% still gets 0 Gy or more
- dvh->dvh[0] = 100;
- return(SUCCESS);
- }
- int output_dose_weights(GRID_ARRAY *beamlets, GRID *dose,
- char *dosefilename, char *weightfilename)
- // Writes the current dose distribution and beamlet weights to dosefilename
- // and weightfilename, respectively.
- {
- FILE *dosefile, *weightfile;
- dosefile = fopen(dosefilename,"wb");
- weightfile = fopen(weightfilename,"wb");
- // print dose and weight files
- if ((int)fwrite(dose->matrix,sizeof(float),beamlets->Nvox,dosefile) != beamlets->Nvox)
- {
- sprintf(errstr,"Unable to write dose data to file \n%s.",dosefilename);
- return(FAILURE);
- }
- if ((int)fwrite(beamlets->beam_weight,sizeof(float),beamlets->num_beamlets,weightfile) != beamlets->num_beamlets)
- {
- sprintf(errstr,"Unable to write beamlet weight data to file \n%s.",weightfilename);
- return(FAILURE);
- }
- fclose(dosefile);
- fclose(weightfile);
- return(SUCCESS);
- }
- float calc_obj_func(GRID_ARRAY *beamlets, GRID *dose, PRESC *presc)
- // Calculate the objective function value.
- {
- int i, j, k;
- float E, Eplus, Eminus, Edvh_plus, Edvh_minus;
- float diff, del_d_plus, del_d_minus;
- E = 0.0;
- for (k=0;k<presc->Ntissue;k++) // loop through all tissue types
- if (presc->array[k].Nind != 0 && presc->array[k].alpha > 0.0)
- // continue only if the ROI contains voxels and has an importance above zero
- {
- // initialize objective function terms for tissue k to zero
- Eplus = 0.0;
- Eminus = 0.0;
- Edvh_plus = 0.0;
- Edvh_minus = 0.0;
- // calculate the over- and underdose penalty terms
- for (j=0;j<presc->array[k].Nind;j++)
- {
- i = presc->array[k].ind[j]; // current voxel index
- // overdose penalty term
- diff = dose->matrix[i] - presc->array[k].dPlus[j];
- if (diff > 0.0)
- Eplus += diff*diff;
- // underdose penalty term
- diff = dose->matrix[i] - presc->array[k].dMinus[j];
- if (diff < 0.0)
- Eminus += diff*diff;
- }
- // calculate the dvh penalties if they apply
- if ((presc->array[k].betaVPlus > 0.0) || (presc->array[k].betaVMinus > 0.0))
- {
- if (presc->array[k].betaVPlus > 0.0)
- // penalize overdosed dose volume considerations
- {
- del_d_plus = presc->array[k].dvh.del_d_plus;
- // dvh_plus constraints
- for (j=0;j<presc->array[k].Nind;j++)
- {
- i = presc->array[k].ind[j]; // current voxel of interest
- diff = dose->matrix[i] - presc->array[k].dVPlus;
- if (diff >= 0 && diff <= del_d_plus) // see if this voxel should be penalized
- Edvh_plus += diff*diff;
- }
- }
- if (presc->array[k].betaVMinus > 0.0)
- // penalize underdosed dose volume considerations
- {
- del_d_minus = presc->array[k].dvh.del_d_minus;
-
- // dvh_minus constraints
- for (j=0;j<presc->array[k].Nind;j++)
- {
- i = presc->array[k].ind[j]; // current voxel of interest
- diff = dose->matrix[i] - presc->array[k].dVMinus;
- if (diff >= del_d_minus && diff <= 0) // see if this voxel should be penalized
- Edvh_minus += diff*diff;
- }
- }
- }
- // update the objective function
- E += presc->array[k].alpha/(float)presc->array[k].Nind
- *(presc->array[k].betaPlus*Eplus
- + presc->array[k].betaMinus*Eminus
- + presc->array[k].betaVPlus*Edvh_plus
- + presc->array[k].betaVMinus*Edvh_minus);
- }
- return(E);
- }
- int compare(void *arg1, void *arg2)
- // Compare two floats to each other.
- {
- if (*(float *)arg1 < *(float *)arg2)
- return -1;
- else if (*(float *)arg1 == *(float *)arg2)
- return 0;
- else
- return 1;
- }
- int calcAllDvhs(GRID *dose, PRESC *presc)
- // Calculates the dvh for each tissue type in the prescription
- {
- int i, j, k;
- float d_max;
- char tmpstr[200];
- for (k=0;k<presc->Ntissue;k++)
- {
- // find the current maximum dose in the ROI
- d_max = 0.0;
- for (j=0;j<presc->array[k].Nind;j++)
- {
- i = presc->array[k].ind[j]; // current voxel index
- if (dose->matrix[i] > d_max)
- d_max = dose->matrix[i];
- }
- // set up dose bins for the current dvh
- presc->array[k].dvh.Nbins = Ndvh_bins;
- presc->array[k].dvh.dmax = d_max*(float)1.1; // go over the max dose by a small amount
- if (d_max != 0.0) // zero dose delivered to this tissue
- presc->array[k].dvh.del_d = presc->array[k].dvh.dmax/(float)presc->array[k].dvh.Nbins;
- else
- presc->array[k].dvh.del_d = (float)100.0/(float)presc->array[k].dvh.Nbins;
- // calculate the dvh for this tissue
- if (calc_dvh(dose, presc->array[k].Nind, presc->array[k].ind, &presc->array[k].dvh) == FAILURE)
- {
- strcpy(tmpstr,errstr); // copy the error string passed from the dvh calculator
- sprintf(errstr,"Failed in DVH calculation for tissue %d:\n%s\n",k,tmpstr);
- return(FAILURE);
- }
- // if applicable in the optimization, find del_d_plus and del_d_minus
- if (presc->array[k].betaVPlus > 0.0)
- {
- // find where vPlus occurs in the DVH
- for (j=0;j<presc->array[k].dvh.Nbins;j++)
- if (presc->array[k].dvh.dvh[j] < presc->array[k].vPlus)
- break;
- // j is the dvh index that marks the crossing from above to below vPlus
- // use j to see if any dvh penalties will be applied here
- if ((float)j*presc->array[k].dvh.del_d >= presc->array[k].dVPlus)
- presc->array[k].dvh.del_d_plus
- = (float)j*presc->array[k].dvh.del_d - presc->array[k].dVPlus;
- else
- presc->array[k].dvh.del_d_plus = 0.0;
- }
- if (presc->array[k].betaVMinus > 0.0)
- {
- // find where vMinus occurs in the DVH
- for (j=0;j<presc->array[k].dvh.Nbins;j++)
- if (presc->array[k].dvh.dvh[j] < presc->array[k].vMinus)
- break;
- // j is the dvh index that marks the crossing from above to below vMinus
- // use j to see if any dvh penalties will be applied here
- if ((float)j*presc->array[k].dvh.del_d <= presc->array[k].dVMinus)
- presc->array[k].dvh.del_d_minus
- = (float)j*presc->array[k].dvh.del_d - presc->array[k].dVMinus;
- else
- presc->array[k].dvh.del_d_minus = 0.0;
- }
- }
- return(SUCCESS);
- }
- int find_used_voxels(PRESC *presc, int *usedVoxels)
- // Finds all voxels that are affected by the prescription. Voxels that are
- // affected are marked as 1, those that aren't are marked as 0.
- {
- int i,j,k;
- // voxels are unused until proven otherwise
- for (i=0;i<presc->x_count*presc->y_count*presc->z_count;i++)
- usedVoxels[i] = 0;
- // loop through all tissues, finding voxels that are used
- for (k=0;k<presc->Ntissue;k++)
- if ( (presc->array[k].alpha > 0.0)
- && ( presc->array[k].betaMinus > 0.0 || presc->array[k].betaPlus
- || presc->array[k].betaVMinus || presc->array[k].betaVPlus ))
- for (j=0;j<presc->array[k].Nind;j++)
- usedVoxels[presc->array[k].ind[j]] = 1;
- return(SUCCESS);
- }
- int fillPrescriptionGrid(PRESC *presc, PRESCGRID *prescGrid)
- {
- int i,j,k;
- int *currTiss;
- prescGrid->x_count = presc->x_count;
- prescGrid->y_count = presc->y_count;
- prescGrid->z_count = presc->z_count;
- prescGrid->Nvox = presc->x_count*presc->y_count*presc->z_count;
-
- prescGrid->array = (PRESCNODE **)malloc(sizeof(PRESCNODE *)*prescGrid->Nvox);
- prescGrid->numNodes = (int *)malloc(sizeof(int)*prescGrid->Nvox);
- for (i=0;i<prescGrid->Nvox;i++) prescGrid->numNodes[i] = 0;
- // Count the number of tissues that fall inside each voxel
- for (k=0;k<presc->Ntissue;k++)
- if ( (presc->array[k].alpha > 0.0)
- && ( presc->array[k].betaMinus > 0.0 || presc->array[k].betaPlus
- || presc->array[k].betaVMinus || presc->array[k].betaVPlus ))
- for (j=0;j<presc->array[k].Nind;j++)
- prescGrid->numNodes[presc->array[k].ind[j]]++;
- // allocate memory for the prescription grid nodes
- for (i=0;i<prescGrid->Nvox;i++)
- if (prescGrid->numNodes[i] > 0)
- prescGrid->array[i] = (PRESCNODE *)malloc(sizeof(PRESCNODE)*prescGrid->numNodes[i]);
- // tally of the current number of tissues that have been placed in a voxel
- currTiss = (int *)malloc(sizeof(int)*prescGrid->Nvox);
- for (i=0;i<prescGrid->Nvox;i++) currTiss[i] = 0;
- // fill the prescription grid nodes
- for (k=0;k<presc->Ntissue;k++)
- if ( (presc->array[k].alpha > 0.0)
- && ( presc->array[k].betaMinus > 0.0 || presc->array[k].betaPlus
- || presc->array[k].betaVMinus || presc->array[k].betaVPlus ))
- for (j=0;j<presc->array[k].Nind;j++)
- {
- i = presc->array[k].ind[j]; // current voxel
- prescGrid->array[i][currTiss[i]].tissueInd = k;
- prescGrid->array[i][currTiss[i]].dMinus = presc->array[k].dMinus[j];
- prescGrid->array[i][currTiss[i]].dPlus = presc->array[k].dPlus[j];
- currTiss[i]++;
- }
- return(SUCCESS);
- }
- int loadBeamletsCalcDose(OPT_PARAM *op, GRID *dose, GRID_ARRAY *beamlets)
- // Loads all beamlets and calculates total dose using the current set of beamlet
- // weights. This function is necessary when the beamlets used for the optimization
- // have been scaled down to only include voxels that are used in the optimization.
- {
- int i,j,k,m,beamletNum,Nbeamlets,dims[3],Nind,num;
- char bixbatchfile[1000];
- int *ind;
- float *data;
- FILE *fid;
- beamletNum = 0;
-
- // reset the dose distribution to all zeros
- for (i=0;i<beamlets->Nvox;i++) dose->matrix[i] = 0.0;
- // load one beamlet at at a time, calculating total dose along the way
- for (k=0;k<beamlets->num_beamlet_batches;k++)
- {
- // open the beamlet batch file
- sprintf(bixbatchfile,"%s/%s%d.%s",op->bix_dir,op->bix_batch_base_filename,k,op->bix_batch_extension);
- if ((fid = fopen(bixbatchfile,"rb")) == NULL)
- {
- sprintf(errstr,"Unable to open file for beamlet batch %d.\n,filename: %s",k,bixbatchfile);
- return(FAILURE);
- }
- // read-in the number of beamlets that are in this file
- if((int)fread(&Nbeamlets,sizeof(int),1,fid) != 1)
- {
- sprintf(errstr,"Unable to read number of beamlets in file:\n%s",bixbatchfile);
- return(FAILURE);
- }
- // read-in all of the beamlets in the current batch
- for (j=0;j<Nbeamlets;j++)
- {
- if((int)fread(&num,sizeof(int),1,fid) != 1)
- {
- sprintf(errstr,"Unable to read beamlet number for beamlet %d in file:\n%s",j,bixbatchfile);
- return(FAILURE);
- }
- // read the beamlet dimensions
- if((int)fread(dims,sizeof(int),3,fid) != 3)
- {
- sprintf(errstr,"Unable to read beamlet dimensions for beamlet %d in file:\n%s",j,bixbatchfile);
- return(FAILURE);
- }
- // ensure that the beamlet has the same grid size as the prescription
- if((dims[0] != beamlets->x_count) || (dims[1] != beamlets->y_count) || (dims[2] != beamlets->z_count))
- {
- sprintf(errstr,"Mismatch in grid dimensions for beamlet %d in file:\n%s",j,bixbatchfile);
- return(FAILURE);
- }
-
- // read the number of non-zero values in the current beamlet
- if((int)fread(&Nind,sizeof(int),1,fid) != 1)
- {
- sprintf(errstr,"Unable to read number of non-zero values for beamlet %d in file:\n%s",j,bixbatchfile);
- return(FAILURE);
- }
- // allocate memory and read-in indices for the current beamlet
- if((ind = (int *)malloc(sizeof(int)*Nind)) == NULL)
- {
- sprintf(errstr,"Unable to allocate memory for indices of beamlet %d\n",num);
- return(FAILURE);
- }
- if((int)fread(ind,sizeof(int),Nind,fid) != Nind)
- {
- sprintf(errstr,"Unable to read-in indices for beamlet %d\n",num);
- return(FAILURE);
- }
- // allocate memory and read-in indices for the current beamlet
- if((data = (float *)malloc(sizeof(float)*Nind)) == NULL)
- {
- sprintf(errstr,"Unable to allocate memory for data of beamlet %d\n",num);
- return(FAILURE);
- }
- if((int)fread(data,sizeof(float),Nind,fid) != Nind)
- {
- sprintf(errstr,"Unable to read-in dose data for beamlet %d\n",num);
- return(FAILURE);
- }
- // add the current beamlet to the dose distribution
- for (m=0;m<Nind;m++)
- dose->matrix[ind[m]] += data[m]*beamlets->beam_weight[beamletNum];
- // free indices and data for the full beamlet
- free(ind);
- free(data);
- beamletNum++; // increment the beamlet number
- }
-
- printf("Successfully loaded beamlet batch %d of %d.\n",k+1,beamlets->num_beamlet_batches);
- fclose(fid);
- }
- return(SUCCESS);
- }
- int truncateBeamWeights(float *beamWeights, int Nbeamlets, float modFactor)
- // Applies modulation factor to all of the beamlet weights, including
- // the ones that are not flagged.
- {
- int j, Nnonzero;
- float meanInt, maxInt;
-
- Nnonzero = 0;
- maxInt = 0.0;
- meanInt = 0.0;
- for (j=0;j<Nbeamlets;j++)
- if (beamWeights[j] > 0.0)
- {
- Nnonzero++;
- meanInt += beamWeights[j];
- }
-
- meanInt /= (float)Nnonzero; // calculate the mean of the intensity weights
-
- maxInt = modFactor*meanInt; // maximum allowable intensity
- // set any weights that are greater than the maximum to the maximum intensity
- for (j=0;j<Nbeamlets;j++)
- if (beamWeights[j] > maxInt)
- beamWeights[j] = maxInt;
- return(SUCCESS);
- }
|