/// <summary> /// Create verifications plans for a given treatment plan. /// </summary> public static void CreateVerificationPlan(Course course, IEnumerable <Beam> beams, ExternalPlanSetup verifiedPlan, StructureSet verificationStructures, string planId, bool calculateDose) { var verificationPlan = course.AddExternalPlanSetupAsVerificationPlan(verificationStructures, verifiedPlan); Helpers.RemoveOldPlan(course, planId); verificationPlan.Id = planId; // Put isocenter to the center of the body. var isocenter = verificationStructures.Structures.Single(st => st.Id.ToLower().StartsWith("body")).CenterPoint; // Copy the given beams to the verification plan and the meterset values. var getCollimatorAndGantryAngleFromBeam = beams.Count() > 1; var presetValues = (from beam in beams let newBeamId = CopyBeam(beam, verificationPlan, isocenter, getCollimatorAndGantryAngleFromBeam) select new KeyValuePair <string, MetersetValue>(newBeamId, beam.Meterset)).ToList(); // Set presciption const int numberOfFractions = 1; verificationPlan.UniqueFractionation.SetPrescription(numberOfFractions, verifiedPlan.UniqueFractionation.PrescribedDosePerFraction, prescribedPercentage: 1.0); if (calculateDose) { verificationPlan.SetCalculationModel(CalculationType.PhotonVolumeDose, DoseCalculationAlgorithm); Trace.WriteLine("\nCalculating dose for verification plan...\n"); var res = verificationPlan.CalculateDoseWithPresetValues(presetValues); if (!res.Success) { var message = string.Format("Dose calculation failed for verification plan. Output:\n{0}", res); Trace.WriteLine(message); throw new Exception(message); } } }
private static void Execute(Common.Model.API.Application app, string patientId, string planId) { var patient = app.OpenPatientById(patientId); patient.BeginModifications(); if (!Helpers.CheckStructures(patient)) { return; } // The demo patient has structures in a set structure called "Prostate". var structures = patient.StructureSets.Single(st => st.Id == "Prostate"); var course = Helpers.GetCourse(patient, CourseId); // If old courses exists, remove them. Remove also the structures generated by the script (in the previous run). Helpers.RemoveOldPlan(course, planId); Helpers.RemoveStructures(structures, new List <string> { "PTV", PlanGeneration.ExpandedCTVId, PlanGeneration.PTVSubOARSId }); // Launch the prescription dialog. var prescriptionDialog = new PrescriptionDialog(patientId, DefaultDosePerFraction, DefaultNumberOfFractions, DefaultMarginForPTVInMM, structures.Structures) { Width = 300, Height = 350 }; double?dosePerFraction = null; int? numberOfFractions = null; double?marginForPTV = null; string ctvId = string.Empty; prescriptionDialog.Closed += (s, e) => { dosePerFraction = prescriptionDialog.DosePerFraction; numberOfFractions = prescriptionDialog.NumberOfFractions; marginForPTV = prescriptionDialog.PTVMargin; ctvId = prescriptionDialog.SelectedStructure; }; prescriptionDialog.ShowDialog(); // If the user inputs are valid, proceed to plan creation. if (dosePerFraction.HasValue && numberOfFractions.HasValue && marginForPTV.HasValue && ctvId != string.Empty) { // Create new plan. var plan = course.AddExternalPlanSetup(structures); plan.Id = planId; // Re-direct output from trace to console. Trace.Listeners.Add(new ConsoleTraceListener()); // Beam geometry generation. PlanGeneration.GenerateBeamGeometry(plan, dosePerFraction != null ? dosePerFraction.Value : 0, numberOfFractions != null ? numberOfFractions.Value : 0, marginForPTV != null ? marginForPTV.Value : 0, ctvId); // DVH estimation. var structureMatches = PlanGeneration.GetStructureMatches(plan); structureMatches.Remove(PlanGeneration.ExpandedCTVId); structureMatches.Add(PlanGeneration.PTVSubOARSId, new ModelStructure("PTV", ModelStructureType.Target)); PlanGeneration.CalculateDVHEstimates(plan, structureMatches); // Add normal tissue objectives. PlanGeneration.AddNTO(plan); // Save beam geometry and DVH estimation results. var message = "Beam geometry generation and DVH estimation completed."; SaveAndShowMessage(app, message); // Optimization. PlanGeneration.Optimize(plan); // Save optimization results. message = "Optimization completed."; SaveAndShowMessage(app, message); // Caluclate dose. PlanGeneration.CalculateDose(plan); Trace.WriteLine("\nPlan successfully generated.\n"); // Normalize plan. PlanGeneration.Normalize(plan, structureMatches); app.SaveModifications(); // Report DVHs. var outputPath = @"C:\Temp\dvh.svg"; const string browser = @"C:\Program Files (x86)\Mozilla Firefox\firefox.exe"; var structuresForReporting = plan.StructureSet.Structures.Where(st => structureMatches.ContainsKey(st.Id)); const int dvhWidth = 512; const int dvhHeight = 256; SVGFromDVH.SaveSVGFromStructures(outputPath, plan, structuresForReporting, dvhWidth, dvhHeight); outputPath = @"C:\Temp"; var reportLocation = PlanQualityReporter.CreateReport(plan, structureMatches, outputPath); Trace.WriteLine("\nReport successfully generated.\n"); // Display the generated report in web browser. Process.Start(browser, reportLocation); Thread.Sleep(1000); // Ask user if we want to proceed to plan verification. const string title = "Quality assurance"; message = "Proceed to creation of verification plan?"; var res = MessageBox.Show(new Window { Topmost = true }, message, title, MessageBoxButton.YesNo, MessageBoxImage.Question); if (res == MessageBoxResult.Yes) { // Create verification plan. Trace.Write("\nRetrieving CT image of the QA device...\n"); var qaStructures = patient.StructureSets.Where(set => set.Id == VerificationPatientImageId).ToList(); // If we have already loaded the structures for verification, do not load them again. Currently, ESAPI doesn't offer methods to remove them... (has to be done by hand in Eclipse). var verificationStructures = qaStructures.Any() ? qaStructures.First() : plan.Course.Patient.CopyImageFromOtherPatient(VerificationPatientId, VerificationPatientStudyId, VerificationPatientImageId); CreateVerificationPlan(app, plan, verificationStructures); app.SaveModifications(); Trace.WriteLine("\nVerification plans succesfully created.\n"); } Trace.WriteLine("\nScript successfully executed.\n"); } else { const string message = "Please provide a valid prescription."; const string title = "Invalid prescription"; MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Error); } }
/// <summary> /// Run MCO /// </summary> /// <param name="app"></param> /// <param name="patient"></param> /// <param name="courseId"></param> /// <param name="planSetupId"></param> public static void RunMCO(Patient patient, string courseId, string planSetupId) { string message; string m_mcoImrtPlanSetupId = planSetupId; message = string.Format("Patient {0} opened for MCO", patient.Id); Trace.WriteLine(message); var planSetupOrig = Helpers.FindPlanSetup(patient, courseId, m_mcoImrtPlanSetupId); var planSetup = planSetupOrig.Course.CopyPlanSetup(planSetupOrig) as ExternalPlanSetup; Helpers.RemoveOldPlan(planSetupOrig.Course, "MyMCOPlanV1"); planSetup.Id = "MyMCOPlanV1"; message = string.Format("planSetupOrig {0} found", planSetupOrig.Id); Trace.WriteLine(message); message = string.Format("Copy planSetupOrig {0} found", planSetup.Id); Trace.WriteLine(message); message = string.Format("Calculation model for Photons {0} found", planSetup.GetCalculationModel(CalculationType.PhotonIMRTOptimization)); Trace.WriteLine(message); //Create Plan Collection message = string.Format("Is trade-off ready? {0}", planSetup.TradeoffExplorationContext.HasPlanCollection.ToString()); Trace.WriteLine(message); message = string.Format("Has Tradeoff objectives set? {0}", planSetup.TradeoffExplorationContext.TradeoffObjectives.Any().ToString()); Trace.WriteLine(message); var tradeoffCandidates = planSetup.TradeoffExplorationContext.TradeoffStructureCandidates; Structure structure = tradeoffCandidates.First(); message = string.Format("Add one structure ({0}) as Tradeoff objectives set? {1}", structure.Id, planSetup.TradeoffExplorationContext.AddTradeoffObjective(structure)); Trace.WriteLine(message); message = string.Format("Can a plan collection be created? {0}", planSetup.TradeoffExplorationContext.CanCreatePlanCollection); Trace.WriteLine(message); message = string.Format("Create the plan collection, result={0}", planSetup.TradeoffExplorationContext.CreatePlanCollection(false, TradeoffPlanGenerationIntermediateDoseMode.NotUsed)); Trace.WriteLine(message); message = string.Format("Is trade-off exploration ready? {0}", planSetup.TradeoffExplorationContext.HasPlanCollection.ToString()); Trace.WriteLine(message); foreach (var tradeoffObjective in planSetup.TradeoffExplorationContext.TradeoffObjectives) { message = string.Format("Objective cost ({0}) = {1}", tradeoffObjective.Structure, planSetup.TradeoffExplorationContext.GetObjectiveCost(tradeoffObjective)); Trace.WriteLine(message); } message = string.Format("CurrentDose = {0}", planSetup.TradeoffExplorationContext.CurrentDose.DoseMax3D); Trace.WriteLine(message); foreach (var structureItem in planSetup.TradeoffExplorationContext.TargetStructures) { var structureDvh = planSetup.TradeoffExplorationContext.GetStructureDvh(structureItem); message = string.Format("GetStructureDvh({0}).MaxDose = {1}, MeanDose = {2}", structureItem.Id, structureDvh.MaxDose, structureDvh.MeanDose); Trace.WriteLine(message); } // Navigate with the trade-off objectives var tradeoffObjectiveToNavigate = planSetup.TradeoffExplorationContext.TradeoffObjectives.First(); double costForTradeoffObjectiveToNavigate = 0.0; var cost = planSetup.TradeoffExplorationContext.GetObjectiveCost(tradeoffObjectiveToNavigate); var lowerLimit = planSetup.TradeoffExplorationContext.GetObjectiveLowerLimit(tradeoffObjectiveToNavigate); var upperLimit = planSetup.TradeoffExplorationContext.GetObjectiveUpperLimit(tradeoffObjectiveToNavigate); // move restrictor halfway between current cost and upper limit var newRestrictorPos = cost + (upperLimit - cost) * 0.5; message = string.Format("TradeoffObjective = {0}, Lower limit = {1}, upper limit = {2}, cost = {3}.", tradeoffObjectiveToNavigate.Structure, lowerLimit, upperLimit, cost); Trace.WriteLine(message); message = string.Format("Set upper restrictor of halfway between cost and upper limit {0} to {1}", tradeoffObjectiveToNavigate.Structure, newRestrictorPos); Trace.WriteLine(message); planSetup.TradeoffExplorationContext.SetObjectiveUpperRestrictor(tradeoffObjectiveToNavigate, newRestrictorPos); message = string.Format("Set tradeoffObjective {0} to {1}", tradeoffObjectiveToNavigate.Structure, costForTradeoffObjectiveToNavigate); Trace.WriteLine(message); planSetup.TradeoffExplorationContext.SetObjectiveCost(tradeoffObjectiveToNavigate, costForTradeoffObjectiveToNavigate); message = string.Format("--------View again the results---------"); Trace.WriteLine(message); foreach (var tradeoffObjective in planSetup.TradeoffExplorationContext.TradeoffObjectives) { message = string.Format("Objective cost ({0}) = {1}", tradeoffObjective.Structure, planSetup.TradeoffExplorationContext.GetObjectiveCost(tradeoffObjective)); Trace.WriteLine(message); } message = string.Format("CurrentDose = {0}", planSetup.TradeoffExplorationContext.CurrentDose.DoseMax3D); Trace.WriteLine(message); foreach (var structureItem in planSetup.TradeoffExplorationContext.TargetStructures) { var structureDvh = planSetup.TradeoffExplorationContext.GetStructureDvh(structureItem); message = string.Format("GetStructureDvh({0}).MaxDose = {1}, MeanDose = {2}", structureItem.Id, structureDvh.MaxDose, structureDvh.MeanDose); Trace.WriteLine(message); } cost = planSetup.TradeoffExplorationContext.GetObjectiveCost(tradeoffObjectiveToNavigate); lowerLimit = planSetup.TradeoffExplorationContext.GetObjectiveLowerLimit(tradeoffObjectiveToNavigate); upperLimit = planSetup.TradeoffExplorationContext.GetObjectiveUpperLimit(tradeoffObjectiveToNavigate); message = string.Format("TradeoffObjective = {0}, Lower limit = {1}, upper limit = {2}, cost = {3}.", tradeoffObjectiveToNavigate.Structure, lowerLimit, upperLimit, cost); Trace.WriteLine(message); //apply MCO message = string.Format("Saving plan collection and in case of IMRT applying to the plan setup."); Trace.WriteLine(message); planSetup.TradeoffExplorationContext.ApplyTradeoffExplorationResult(); message = string.Format("Is Applying plan to plan setup in case IMRT successful? {0}", planSetup.TradeoffExplorationContext.CreateDeliverableVmatPlan(false)); Trace.WriteLine(message); }