// Compute dose
        public void ComputeDose()
        {
            // Set normalization value
            verifPln.PlanNormalizationValue = currPln.PlanNormalizationValue;
            // Set the plan calculation model
            verifPln.SetCalculationModel(CalculationType.PhotonVolumeDose, currPln.PhotonCalculationModel);
            Dictionary <String, String> currPlnCalcModels = currPln.GetCalculationOptions(currPln.PhotonCalculationModel);

            foreach (KeyValuePair <String, String> calcModel in currPlnCalcModels)
            {
                verifPln.SetCalculationOption(currPln.PhotonCalculationModel, calcModel.Key, calcModel.Value);
            }
            // Compute dose
            // For plan containing non-IMRT beams
            if (verifPln.Beams.Any(b => b.MLCPlanType == MLCPlanType.ArcDynamic || b.MLCPlanType == MLCPlanType.Static))
            {
                verifPln.CalculateDose();  // Compute dose for non-IMRT type beams
                // Correct for MU by changing beam weighting
                foreach (Beam verifBm in verifPln.Beams)
                {
                    BeamParameters verifBmParam = verifBm.GetEditableParameters();
                    verifBmParam.WeightFactor = muValues.First(mv => mv.Key == verifBm.Id).Value.Value / verifBm.Meterset.Value;
                    verifBm.ApplyParameters(verifBmParam);
                }
            }
            // For all other IMRT plans
            else
            {
                verifPln.CalculateDoseWithPresetValues(muValues);  // Compute dose for IMRT type beams
            }
        }
Exemple #2
0
        static void CopyJawAndLeafPositions(Beam from, BeamParameters to)
        {
            IEnumerable <ControlPointParameters> cps = to.ControlPoints;
            int ix = 0;

            foreach (var cp in from.ControlPoints)
            {
                cps.ElementAt(ix).JawPositions  = cp.JawPositions;
                cps.ElementAt(ix).LeafPositions = cp.LeafPositions;
                ix++;
            }
        }
        // Copy the MLC and jaw positions from the beam in approved plan to the beam in verificiation plan
        private BeamParameters copyControlPoints(Beam currBm, Beam verifBm)
        {
            BeamParameters verifBmParam = verifBm.GetEditableParameters();

            for (int i_CP = 0; i_CP < verifBm.ControlPoints.Count(); i_CP++)
            {
                verifBmParam.ControlPoints.ElementAt(i_CP).LeafPositions = currBm.ControlPoints.ElementAt(i_CP).LeafPositions;
                verifBmParam.ControlPoints.ElementAt(i_CP).JawPositions  = currBm.ControlPoints.ElementAt(i_CP).JawPositions;
            }
            verifBmParam.WeightFactor = currBm.WeightFactor;
            return(verifBmParam);
        }
        // Compute isocenter shift on verification plan
        public VVector ComputeIsoShift(QASettings qaSet)
        {
            verifPlnIso = qaSet.pIso;                        // Set iso center from settings
            List <Double> infFldEdges = new List <Double>(); // create list to store inferior field edge for each beam

            foreach (Beam bm in currPln.Beams)
            {
                if (bm.MetersetPerGy > 0)
                {
                    BeamParameters bmParam = bm.GetEditableParameters();
                    Double         collAng = bmParam.ControlPoints.First().CollimatorAngle;
                    VRect <Double> collPos = bmParam.ControlPoints.First().JawPositions;
                    // Compute the approximate inferior field edge position shaped by the collimator and MLC
                    Double cosAng = Math.Cos(Math.PI * collAng / 180.0);
                    Double sinAng = Math.Sin(Math.PI * collAng / 180.0);
                    Double DelX   = 400.0; //field edge can be defined by one X and one Y jaw
                    Double DelY   = 400.0;
                    if (cosAng > 0.01)
                    {
                        DelY = -collPos.Y1 / cosAng;
                    }
                    if (cosAng < -0.01)
                    {
                        DelY = -collPos.Y2 / cosAng;
                    }                                                    //past 90 deg, Y2 defines inferior edge
                    if (sinAng > 0.01)
                    {
                        DelX = -collPos.X1 / sinAng;
                    }                                                    //ccw rotation (respect to BEV), X1 defines inferior edge
                    if (sinAng < -0.01)
                    {
                        DelX = -collPos.X2 / sinAng;
                    }                                      //cw rotation (respect to BEV), X2 defines inferior edge
                    infFldEdges.Add(Math.Min(DelX, DelY)); //use the minimum between DelX and DelY as the approximate inferior field edge
                }
            }
            if (infFldEdges.Count == 0)
            {
                return(new VVector(Double.NaN, Double.NaN, Double.NaN));
            }                                                                                       // no field edge found, either beam parameters invalid or no MU
            Double MedInfFldEdge = GetMedian(infFldEdges);

            if (MedInfFldEdge > qaSet.pLen)                                                              // if the field edge is longer than the length of qa phantom
            {
                verifPlnIso.z = verifPlnIso.z + Math.Ceiling(MedInfFldEdge / 10 - qaSet.pLen / 10) * 10; // shift the iso superiorly (cm as minimum shift unit)
            }
            return(verifPlnIso);
        }
 // Add beam to the plan
 public Beam AddBeamToVerifPlan(Beam currBm)
 {
     if (verifPln == null)
     {
         return(null);
     }
     else
     {
         bmTech = getMLCBmTechnique(currBm);  // find beam technique
         // Create machine parameters
         String energy  = currBm.EnergyModeDisplayName;
         String fluence = null;
         Match  EMode   = Regex.Match(currBm.EnergyModeDisplayName, @"^([0-9]+[A-Z]+)-?([A-Z]+)?", RegexOptions.IgnoreCase); //format is... e.g. 6X(-FFF)
         if (EMode.Success)
         {
             if (EMode.Groups[2].Length > 0)  // fluence mode
             {
                 energy  = EMode.Groups[1].Value;
                 fluence = EMode.Groups[2].Value;
             } // else normal modes uses default in decleration
         }
         ExternalBeamMachineParameters machParam = new ExternalBeamMachineParameters(currBm.TreatmentUnit.Id.ToString(),
                                                                                     energy, currBm.DoseRate, currBm.Technique.Id.ToString(), fluence);
         // Define collimator, gantry and couch angles //
         Double gantryAng = currBm.ControlPoints.First().GantryAngle;
         Double collAng   = currBm.ControlPoints.First().CollimatorAngle;
         Double couchAng  = 0.0;
         // MU values for each control point //
         IEnumerable <double> muSet = currBm.ControlPoints.Select(cp => cp.MetersetWeight).ToList();
         // Add beam MU to the list of MU values //
         muValues.Add(new KeyValuePair <string, MetersetValue>(currBm.Id, currBm.Meterset));
         // Start adding beam based on beam technique //
         if (bmTech == "StaticMLC")
         {
             Beam verifBm = verifPln.AddMLCBeam(machParam, new float[2, 60], new VRect <double>(-10.0, -10.0, 10.0, 10.0),
                                                collAng, gantryAng, couchAng, verifPlnIso);
             verifBm.Id = currBm.Id;
             BeamParameters ctrPtParam = copyControlPoints(currBm, verifBm);
             verifBm.ApplyParameters(ctrPtParam);
             return(verifBm);
         }
         else if (bmTech == "StaticSegWin")
         {
             Beam verifBm = verifPln.AddMultipleStaticSegmentBeam(machParam, muSet,
                                                                  collAng, gantryAng, couchAng, verifPlnIso);
             verifBm.Id = currBm.Id;
             BeamParameters ctrPtParam = copyControlPoints(currBm, verifBm);
             verifBm.ApplyParameters(ctrPtParam);
             return(verifBm);
         }
         else if (bmTech == "StaticSlidingWin")
         {
             Beam verifBm = verifPln.AddSlidingWindowBeam(machParam, muSet,
                                                          collAng, gantryAng, couchAng, verifPlnIso);
             verifBm.Id = currBm.Id;
             BeamParameters ctrPtParam = copyControlPoints(currBm, verifBm);
             verifBm.ApplyParameters(ctrPtParam);
             return(verifBm);
         }
         else if (bmTech == "ConformalArc")
         {
             Beam verifBm = verifPln.AddConformalArcBeam(machParam, collAng, currBm.ControlPoints.Count(),
                                                         currBm.ControlPoints.First().GantryAngle, currBm.ControlPoints.Last().GantryAngle,
                                                         currBm.GantryDirection, couchAng, verifPlnIso);
             verifBm.Id = currBm.Id;
             BeamParameters ctrPtParam = copyControlPoints(currBm, verifBm);
             verifBm.ApplyParameters(ctrPtParam);
             return(verifBm);
         }
         else if (bmTech == "VMAT")
         {
             Beam verifBm = verifPln.AddVMATBeam(machParam, muSet, collAng,
                                                 currBm.ControlPoints.First().GantryAngle, currBm.ControlPoints.Last().GantryAngle,
                                                 currBm.GantryDirection, couchAng, verifPlnIso);
             verifBm.Id = currBm.Id;
             BeamParameters ctrPtParam = copyControlPoints(currBm, verifBm);
             verifBm.ApplyParameters(ctrPtParam);
             return(verifBm);
         }
         else // null
         {
             return(null);
         }
     }
 }
        private void newPlan_btn_Click(object sender, RoutedEventArgs e)
        {
            Course c2 = null;

            if (p.Courses.Where(x => x.Id == course_txt.Text).Count() == 0)
            {
                c2    = p.AddCourse();
                c2.Id = course_txt.Text;
            }
            else
            {
                c2 = p.Courses.First(x => x.Id == course_txt.Text);
            }
            ExternalPlanSetup ps2 = c2.AddExternalPlanSetup(ps.StructureSet);

            //doses should all be the same.t
            //ps2.DosePerFraction = ps.DosePerFraction; //read only
            //ps2.TotalDose = ps.TotalDose;//read only
            ps2.SetPrescription(
                (int)ps.NumberOfFractions,
                ps.DosePerFraction,
                ps.TreatmentPercentage);
            //I've chnaged this down below. Currently, the calculation will take place with preset monitor units
            //making it the same as the plan its copied from but then I scale the normaliztation factor by 1.3% because the discover is not in the beam.
            ps2.PlanNormalizationValue = val * ps.PlanNormalizationValue;

            //val = (double)Convert.ToDouble(Input.Text);
            bool valid = double.TryParse(Input.Text.ToString(), out val);

            ps2.PlanNormalizationValue = val + no_norm;
            //ps2.TreatmentPercentage = ps.TreatmentPercentage;//read only

            //ps2.AddMLCBeam()
            ps2.Id = plan_txt.Text;
            List <KeyValuePair <string, MetersetValue> > mu_list = new List <KeyValuePair <string, MetersetValue> >();

            /*foreach (FieldInfo fi in fields)########################*/
            for (int t = 0; t < fields.Count(); t++)
            {
                FieldInfo fi = fields[t];
                Beam      b2;
                if (fi.gantry_direction == 0)
                {
                    b2 = ps2.AddSlidingWindowBeam(fi.Ebmp, fi.cpInfos.Select(x => x.meterSet),
                                                  fi.collAngle, fi.gantry, fi.couch, fi.isocenter);
                }
                else
                {
                    b2 = ps2.AddVMATBeam(fi.Ebmp, fi.cpInfos.Select(x => x.meterSet), fi.collAngle,
                                         fi.gantry, fi.gantry_stop, fi.gantry_direction, fi.couch, fi.isocenter);
                }
                int cploc = 0;
                //if (fi.applicator != null) { b2.Applicator = fi.applicator; }
                BeamParameters beamp = fi.bp;
                //b2.ApplyParameters(new BeamParameters(ControlPoint cp))
                //int cploc = 0;
                //foreach (cpInfo cpi in fi.cpInfos)
                //double MU_old = 0;
                foreach (ControlPointParameters cpp in beamp.ControlPoints)
                //for(int xx=0; xx< beamp.ControlPoints.Count(); xx++)
                {  /* ControlPointParameters cpp= beamp.ControlPoints[xx];*/
                    float[,] leafPos = new float[2, 60];
                    int    leafloc = 0;
                    double x1      = cpp.JawPositions.X1;
                    double x2      = cpp.JawPositions.X2;
                    cpInfo cpi     = fi.cpInfos[cploc];

                    //foreach (cpDetail cpd in cpi.cpDetails)#####################
                    for (int dd = 0; dd < cpi.cpDetails.Count(); dd++)
                    {
                        cpDetail cpd = cpi.cpDetails[dd];
                        //sometimes the errors show that the difference will overlap the leaves.
                        //here we check for the overla[p and if there is n overlap, leaf B just gets set to 0.1 less than the leaf A position.
                        //thus ignoring the deviation fort that leaf pair.
                        if (cpd.leafB + Convert.ToSingle(cpd.deviationB) > cpd.leafA + Convert.ToSingle(cpd.deviationA))
                        {
                            leafPos[1, leafloc] = cpd.leafA + (float)cpd.deviationA;
                            leafPos[0, leafloc] = leafPos[1, leafloc] - (float)0.1;
                        }
                        else
                        {
                            /*if (cpd.leafA + (float)cpd.deviationA < x1)
                             * {
                             *
                             *  leafPos[1, leafloc] = (float)x1 + (float)0.5;
                             *  leafPos[0, leafloc] = (float)x1;
                             * }
                             * else if (cpd.leafA + (float)cpd.deviationA > x2)
                             * {
                             *  leafPos[1, leafloc] = (float)x2;
                             *  if(cpd.leafB + (float)cpd.deviationB > x2)
                             *  {
                             *      leafPos[0, leafloc] = (float)x2 - (float)0.5;
                             *  }
                             *  else
                             *  {
                             *      leafPos[0, leafloc] = cpd.leafB + (float)cpd.deviationB;
                             *  }
                             * }
                             * else
                             * {
                             *  leafPos[1, leafloc] = cpd.leafA + Convert.ToSingle(cpd.deviationA);
                             *  leafPos[0, leafloc] = cpd.leafB + (float)cpd.deviationB;
                             * }*/
                            leafPos[1, leafloc] = cpd.leafA + (float)cpd.deviationA;
                            leafPos[0, leafloc] = cpd.leafB + (float)cpd.deviationB;

                            //leafPos[0, leafloc] = cpd.leafA + Convert.ToSingle(cpd.deviationA);
                            //leafPos[1, leafloc] = cpd.leafB + Convert.ToSingle(cpd.deviationB);
                        }

                        leafloc++;
                    }
                    ////start with the first leaf position, and then interoplate all the rest.
                    //float leaf_oldA = 0;
                    //float leaf_oldB = 0;
                    //for (int i = 0; i < cpi.cpDetails.Count(); i++)
                    //{

                    //    if (i == 0)
                    //    {
                    //        leafPos[0, i] = cpi.cpDetails[i].leafA;
                    //        leafPos[1, i] = cpi.cpDetails[i + 1].leafB;
                    //        leaf_oldA = leafPos[0, i];
                    //        leaf_oldB = leafPos[1, i];
                    //        //mU_old = cpi.meterSet[i];
                    //    }
                    //    else
                    //    {
                    //        //let the interpolation begin.
                    //        //first the MU
                    //    }
                    //}
                    //beamp.SetAllLeafPositions(leafPos);
                    //ControlPointParameters cpp =  beamp.ControlPoints[cploc]
                    cpp.LeafPositions = leafPos;
                    //double check to see if this has to be applied every time. VMAT code is taking a long time.


                    //**********************************
                    b2.ApplyParameters(beamp);
                    //**********************************



                    cploc++;
                }
                //calculate the dose for each of the fields.
                mu_list.Add(new KeyValuePair <string, MetersetValue>(b2.Id, fi.MU));
            }
            ps2.CalculateDoseWithPresetValues(mu_list);
            //ps2.PlanNormalizationMethod = ps.PlanNormalizationMethod;\
            //need to renormalize by 1.3% in order to take into account the Discover that we cannot add to the newly calculated plan.
            //ps2.PlanNormalizationValue = val * ps2.PlanNormalizationValue;
            //val = (double)Convert.ToDouble(Input.Text);
            if (double.TryParse(Input.Text.ToString(), out val))
            {
                ps2.PlanNormalizationValue = val + no_norm;
            }
            MessageBox.Show($"{plan_txt.Text} created successfully.");
        }