static void Execute(Application app) { Patient pat = app.OpenPatientById("exercise5-0"); try { pat.BeginModifications(); const string courseId = "AutoPlanned"; Course course = pat.Courses.Where(o => o.Id == courseId).SingleOrDefault(); if (course == null) { if (course == null) { course = pat.AddCourse(); course.Id = courseId; } } StructureSet ss = pat.StructureSets.First(x => x.Id == "CT_1"); if (course.CanAddPlanSetup(ss)) { // find the PTV Structure ptv = ss.Structures.First(x => x.Id == "PTV"); // Put isocenter to the center of the ptv. var isocenter = ptv.CenterPoint; //add plan and beams ExternalPlanSetup plan = course.AddExternalPlanSetup(ss); plan.SetPrescription(5, new DoseValue(2, DoseValue.DoseUnit.Gy), 1.0); Beam g0 = plan.AddMLCBeam(MachineParameters, null, new VRect <double>(-10, -10, 10, 10), 0, 0, 0, isocenter); Beam g180 = plan.AddMLCBeam(MachineParameters, null, new VRect <double>(-10, -10, 10, 10), 0, 180.0, 0, isocenter); // fit beam jaws and MLC bool useAsymmetricXJaw = true, useAsymmetricYJaws = true, optimizeCollimatorRotation = true; g0.FitCollimatorToStructure(new FitToStructureMargins(0), ptv, useAsymmetricXJaw, useAsymmetricYJaws, optimizeCollimatorRotation); FitToStructureMargins margins = new FitToStructureMargins(1); JawFitting jawFit = JawFitting.FitToRecommended; OpenLeavesMeetingPoint olmp = OpenLeavesMeetingPoint.OpenLeavesMeetingPoint_Middle; ClosedLeavesMeetingPoint clmp = ClosedLeavesMeetingPoint.ClosedLeavesMeetingPoint_BankOne; g0.FitMLCToStructure(margins, ptv, optimizeCollimatorRotation, jawFit, olmp, clmp); g180.FitMLCToStructure(margins, ptv, optimizeCollimatorRotation, jawFit, olmp, clmp); // format the field ids g0.Id = string.Format("g{0}c{1}", g0.GantryAngleToUser(g0.ControlPoints[0].GantryAngle), g0.CollimatorAngleToUser(g0.ControlPoints[0].CollimatorAngle) ); g180.Id = string.Format("g{0}c{1}", g180.GantryAngleToUser(g180.ControlPoints[0].GantryAngle), g180.CollimatorAngleToUser(g180.ControlPoints[0].CollimatorAngle) ); app.SaveModifications(); } } finally { app.ClosePatient(); } }
/// <summary> /// Create a copy of an existing beam (beams are unique to plans). /// </summary> public static void CopyStaticMlcBeam(Beam originalBeam, ExternalPlanSetup plan) { var MachineParameters = new ExternalBeamMachineParameters(originalBeam.TreatmentUnit.Id, originalBeam.EnergyModeDisplayName, originalBeam.DoseRate, originalBeam.Technique.Id, string.Empty); // Create a new beam. var collimatorAngle = originalBeam.ControlPoints.First().CollimatorAngle; var gantryAngle = originalBeam.ControlPoints.First().GantryAngle; var PatientSupportAngle = originalBeam.ControlPoints.First().PatientSupportAngle; var jawPositions = originalBeam.ControlPoints.First().JawPositions; var leafPositions = originalBeam.ControlPoints.First().LeafPositions; var isocenter = originalBeam.IsocenterPosition; var beam = plan.AddMLCBeam(MachineParameters, leafPositions, jawPositions, collimatorAngle, gantryAngle, PatientSupportAngle, isocenter); if (plan.Beams.Where(b => b.Id == originalBeam.Id).Count() > 0) { throw new InvalidOperationException($"{originalBeam.Id} already exists"); } beam.Id = originalBeam.Id; // Copy control points from the original beam. var editableParams = beam.GetEditableParameters(); editableParams.WeightFactor = originalBeam.WeightFactor; beam.ApplyParameters(editableParams); }
public void Execute(ScriptContext context /*, System.Windows.Window window, ScriptEnvironment environment*/) { // TODO : Add here the code that is called when the script is launched from Eclipse. Patient p = context.Patient; p.BeginModifications();//this line for scripting automation. //find the ctv in the structures. Structure ctv = context.StructureSet.Structures.First(o => o.DicomType == "CTV"); //create on the structureset a PTV from the ctv. Structure ptv = context.StructureSet.AddStructure("PTV", "PTVAuto"); ptv.SegmentVolume = ctv.Margin(8); //create a new plan. Course c_auto = p.AddCourse(); c_auto.Id = "Course_Auto"; ExternalPlanSetup plan = c_auto.AddExternalPlanSetup(context.StructureSet); plan.Id = "Plan_Auto"; //create the fields. //define the externalBeam Parameters ExternalBeamMachineParameters ebmp = new ExternalBeamMachineParameters( "TrueBeam", "6X", 600, "STATIC", null); //set gantry angles double[] g_angles = new double[] { 270, 0, 90, 180 }; foreach (double ga in g_angles) { //add a new beam with intial parametres Beam b = plan.AddMLCBeam( ebmp, new float[2, 60], new VRect <double>(-10, -10, 10, 10), 0, ga, 0, ptv.CenterPoint); //fit the MLC to the structure outline of the PTV. b.FitMLCToStructure(new FitToStructureMargins(10), ptv, false, JawFitting.FitToRecommended, OpenLeavesMeetingPoint.OpenLeavesMeetingPoint_Middle, ClosedLeavesMeetingPoint.ClosedLeavesMeetingPoint_Center); } //Calculate Dose plan.CalculateDose(); //Set Normalization plan.PlanNormalizationValue = plan.Beams.Count() * 100; //Set Prescription. plan.SetPrescription(30, new DoseValue(180, DoseValue.DoseUnit.cGy), 1); }
private void createMlcField(float[,] flncMtx, float rotAng) { int height = flncMtx.GetLength(0); int width = flncMtx.GetLength(1); double xOrg = -0.5 * ((double)width * flncRes - flncRes); double yOrg = 0.5 * ((double)height * flncRes - flncRes); // Create fluence Fluence mlcFlnc = new Fluence(flncMtx, xOrg, yOrg); // Add beam Beam currBm = currPln.AddMLCBeam(currMachParam, new float[2, 60], new VRect <double>(-50.0, -50.0, 50.0, 50.0), rotAng, 0.0, 0.0, currIsoCtr); currBm.SetOptimalFluence(mlcFlnc); currPln.CalculateLeafMotions(vlmcOpt); }
// 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); } } }
public bool CopyAndCreate(Application app, string ptId_Tgt, string crsId_Tgt, string plnId_Tgt, string structId_Tgt, PlanParameters plnParam_Ref) { //Open patient// PatientSummary ptSumm = app.PatientSummaries.FirstOrDefault(ps => ps.Id == ptId_Tgt); if (ptSumm == null) { Console.WriteLine("--Cannot find patient" + ptId_Tgt + "."); return(false); } Patient pt = app.OpenPatient(ptSumm); try { pt.BeginModifications(); //Open or create course// Course crs = pt.Courses.FirstOrDefault(c => c.Id == crsId_Tgt); if (crs == null) { Console.WriteLine("-Create course " + crsId_Tgt + "."); crs = pt.AddCourse(); crs.Id = crsId_Tgt; } //Create plan// ExternalPlanSetup pln = crs.ExternalPlanSetups.FirstOrDefault(p => p.Id == plnId_Tgt); if (pln == null) { StructureSet structSet = pt.StructureSets.FirstOrDefault(ss => ss.Id == structId_Tgt); if (structSet == null) { Console.WriteLine("--Cannot find structure set " + structId_Tgt + ". Plan is not created\n"); app.ClosePatient(); return(false); } pln = crs.AddExternalPlanSetup(structSet); pln.Id = plnId_Tgt; } //Return if there is already a plan with the same name// else { Console.WriteLine("--A plan with name " + plnId_Tgt + " already exists. Plan is not created\n"); app.ClosePatient(); return(false); } Console.WriteLine("-Start creating plan " + plnId_Tgt + "."); //Set plan prescription properties// pln.SetPrescription(plnParam_Ref.N_Fx, plnParam_Ref.DoseperFx, plnParam_Ref.TrtPct); ///////////Create beam by copying from the beams in reference plan parameters//////////// //Create empty list of MU values for each beam// List <KeyValuePair <string, MetersetValue> > muValues = new List <KeyValuePair <string, MetersetValue> >(); foreach (PlanParameters.BmParam bmParam in plnParam_Ref.BmParamLs) { //Add beam, type based on reference MLC beam technique// IEnumerable <double> muSet = bmParam.CtrPtParam.ControlPoints.Select(cp => cp.MetersetWeight).ToList(); switch (bmParam.MLCBmTechnique) { case "StaticMLC": Beam bm = pln.AddMLCBeam(bmParam.MachParam, new float[2, 60], new VRect <double>(-10.0, -10.0, 10.0, 10.0), 0.0, 0.0, 0.0, bmParam.CtrPtParam.Isocenter); bm.Id = bmParam.bmId; bm.ApplyParameters(bmParam.CtrPtParam); break; case "StaticSegWin": bm = pln.AddMultipleStaticSegmentBeam(bmParam.MachParam, muSet, 0.0, 0.0, 0.0, bmParam.CtrPtParam.Isocenter); bm.Id = bmParam.bmId; muValues.Add(new KeyValuePair <string, MetersetValue>(bmParam.bmId, bmParam.mu)); bm.ApplyParameters(bmParam.CtrPtParam); break; case "StaticSlidingWin": bm = pln.AddSlidingWindowBeam(bmParam.MachParam, muSet, 0.0, 0.0, 0.0, bmParam.CtrPtParam.Isocenter); bm.Id = bmParam.bmId; muValues.Add(new KeyValuePair <string, MetersetValue>(bmParam.bmId, bmParam.mu)); bm.ApplyParameters(bmParam.CtrPtParam); break; case "ConformalArc": bm = pln.AddConformalArcBeam(bmParam.MachParam, 0.0, bmParam.CtrPtParam.ControlPoints.Count(), bmParam.CtrPtParam.ControlPoints.First().GantryAngle, bmParam.CtrPtParam.ControlPoints.Last().GantryAngle, bmParam.CtrPtParam.GantryDirection, 0.0, bmParam.CtrPtParam.Isocenter); bm.Id = bmParam.bmId; bm.ApplyParameters(bmParam.CtrPtParam); break; case "VMAT": bm = pln.AddVMATBeam(bmParam.MachParam, muSet, 0.0, bmParam.CtrPtParam.ControlPoints.First().GantryAngle, bmParam.CtrPtParam.ControlPoints.Last().GantryAngle, bmParam.CtrPtParam.GantryDirection, 0.0, bmParam.CtrPtParam.Isocenter); bm.Id = bmParam.bmId; bm.ApplyParameters(bmParam.CtrPtParam); break; default: Console.WriteLine("--At least one of the beams is unidentified, plan is not created.\n"); app.ClosePatient(); return(false); } } //Set the plan normalization value// pln.PlanNormalizationValue = plnParam_Ref.PlnNormFactr; //Set the plan calculation model// pln.SetCalculationModel(CalculationType.PhotonVolumeDose, plnParam_Ref.CalcModel); //If one of the beams is static IMRT, compute dose to enforce MUs to beams// if (plnParam_Ref.BmParamLs.Any(bm => bm.MLCBmTechnique == "StaticSegWin" || bm.MLCBmTechnique == "StaticSlidingWin")) { Console.WriteLine("--Start computing static beam IMRT plan."); pln.CalculateDoseWithPresetValues(muValues); } Console.WriteLine("-Finish plan creation.\n"); app.SaveModifications(); app.ClosePatient(); return(true); } catch (Exception ex) { Console.WriteLine(ex.ToString()); app.ClosePatient(); return(false); } }
private void set_beams(List <VVector> isoLocations) { //DRR parameters (dummy parameters to generate DRRs for each field) DRRCalculationParameters DRR = new DRRCalculationParameters(); DRR.DRRSize = 500.0; DRR.FieldOutlines = true; DRR.StructureOutlines = true; DRR.SetLayerParameters(1, 1.0, 100.0, 1000.0); //place the beams for the VMAT plan //unfortunately, all of Nataliya's requirements for beam placement meant that this process couldn't simply draw from beam placement templates. Some of the beam placements for specific isocenters //and under certain conditions needed to be hard-coded into the script. I'm not really a fan of this, but it was the only way to satisify Nataliya's requirements. int count = 0; string beamName; VRect <double> jp; for (int i = 0; i < numVMATIsos; i++) { for (int j = 0; j < numBeams[i]; j++) { //second isocenter and third beam requires the x-jaw positions to be mirrored about the y-axis (these jaw positions are in the fourth element of the jawPos list) //this is generally the isocenter located in the pelvis and we want the beam aimed at the kidneys-area if (i == 1 && j == 2) { jp = jawPos.ElementAt(j + 1); } else if (i == 1 && j == 3) { jp = jawPos.ElementAt(j - 1); } else { jp = jawPos.ElementAt(j); } Beam b; beamName = ""; beamName += String.Format("{0} ", count + 1); //zero collimator rotations of two main fields for beams in isocenter immediately superior to matchline. Adjust the third beam such that collimator rotation is 90 degrees. Do not adjust 4th beam double coll = collRot[j]; if ((numIsos > numVMATIsos) && (i == (numVMATIsos - 1))) { if (j < 2) { coll = 0.0; } else if (j == 2) { coll = 90.0; } } //all even beams (e.g., 2, 4, etc.) will be CCW and all odd beams will be CW if (count % 2 == 0) { b = plan.AddArcBeam(ebmpArc, jp, coll, CCW[0], CCW[1], GantryDirection.CounterClockwise, 0, isoLocations.ElementAt(i)); if (j >= 2) { beamName += String.Format("CCW {0}{1}", isoNames.ElementAt(i), 90); } else { beamName += String.Format("CCW {0}{1}", isoNames.ElementAt(i), ""); } } else { b = plan.AddArcBeam(ebmpArc, jp, coll, CW[0], CW[1], GantryDirection.Clockwise, 0, isoLocations.ElementAt(i)); if (j >= 2) { beamName += String.Format("CW {0}{1}", isoNames.ElementAt(i), 90); } else { beamName += String.Format("CW {0}{1}", isoNames.ElementAt(i), ""); } } b.Id = beamName; b.CreateOrReplaceDRR(DRR); count++; } } //add additional plan for ap/pa legs fields (all ap/pa isocenter fields will be contained within this plan) if (numIsos > numVMATIsos) { //6-10-2020 EAS, checked if exisiting _Legs plan is present in createPlan method legs_planUpper = tbi.AddExternalPlanSetup(selectedSS); if (singleAPPAplan) { legs_planUpper.Id = String.Format("_Legs"); } else { legs_planUpper.Id = String.Format("{0} Upper Legs", numVMATIsos + 1); } //100% dose prescribed in plan legs_planUpper.SetPrescription(prescription.Item1, prescription.Item2, 1.0); legs_planUpper.SetCalculationModel(CalculationType.PhotonVolumeDose, calculationModel); Structure target; if (useFlash) { target = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "ts_flash_target"); } else { target = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "ptv_body"); } //adjust x2 jaw (furthest from matchline) so that it covers edge of target volume double x2 = isoLocations.ElementAt(numVMATIsos).z - (target.MeshGeometry.Positions.Min(p => p.Z) - 20.0); if (x2 > 200.0) { x2 = 200.0; } else if (x2 < 10.0) { x2 = 10.0; } //AP field //set MLC positions. First row is bank number 0 (X1 leaves) and second row is bank number 1 (X2). float[,] MLCpos = new float[2, 60]; for (int i = 0; i < 60; i++) { MLCpos[0, i] = (float)-200.0; MLCpos[1, i] = (float)(x2); } Beam b = legs_planUpper.AddMLCBeam(ebmpStatic, MLCpos, new VRect <double>(-200.0, -200.0, x2, 200.0), 90.0, 0.0, 0.0, isoLocations.ElementAt(numVMATIsos)); b.Id = String.Format("{0} AP Upper Legs", ++count); b.CreateOrReplaceDRR(DRR); //PA field b = legs_planUpper.AddMLCBeam(ebmpStatic, MLCpos, new VRect <double>(-200.0, -200.0, x2, 200.0), 90.0, 180.0, 0.0, isoLocations.ElementAt(numVMATIsos)); b.Id = String.Format("{0} PA Upper Legs", ++count); b.CreateOrReplaceDRR(DRR); if ((numIsos - numVMATIsos) == 2) { VVector infIso = new VVector(); //the element at numVMATIsos in isoLocations vector is the first AP/PA isocenter infIso.x = isoLocations.ElementAt(numVMATIsos).x; infIso.y = isoLocations.ElementAt(numVMATIsos).y; double x1 = -200.0; //if the distance between the matchline and the inferior edge of the target is < 600 mm, set the beams in the second isocenter (inferior-most) to be half-beam blocks if (selectedSS.Structures.First(x => x.Id.ToLower() == "matchline").CenterPoint.z - target.MeshGeometry.Positions.Min(p => p.Z) < 600.0) { infIso.z = isoLocations.ElementAt(numVMATIsos).z - 200.0; x1 = 0.0; } else { infIso.z = isoLocations.ElementAt(numVMATIsos).z - 390.0; } //fit x1 jaw to extend of patient x2 = infIso.z - (target.MeshGeometry.Positions.Min(p => p.Z) - 20.0); if (x2 > 200.0) { x2 = 200.0; } else if (x2 < 10.0) { x2 = 10.0; } //set MLC positions MLCpos = new float[2, 60]; for (int i = 0; i < 60; i++) { MLCpos[0, i] = (float)(x1); MLCpos[1, i] = (float)(x2); } //AP field if (singleAPPAplan) { b = legs_planUpper.AddMLCBeam(ebmpStatic, MLCpos, new VRect <double>(x1, -200.0, x2, 200.0), 90.0, 0.0, 0.0, infIso); b.Id = String.Format("{0} AP Lower Legs", ++count); b.CreateOrReplaceDRR(DRR); //PA field b = legs_planUpper.AddMLCBeam(ebmpStatic, MLCpos, new VRect <double>(x1, -200.0, x2, 200.0), 90.0, 180.0, 0.0, infIso); b.Id = String.Format("{0} PA Lower Legs", ++count); b.CreateOrReplaceDRR(DRR); } else { //create a new legs plan if the user wants to separate the two APPA isocenters into separate plans ExternalPlanSetup legs_planLower = tbi.AddExternalPlanSetup(selectedSS); legs_planLower.Id = String.Format("{0} Lower Legs", numIsos); legs_planLower.SetPrescription(prescription.Item1, prescription.Item2, 1.0); legs_planLower.SetCalculationModel(CalculationType.PhotonVolumeDose, calculationModel); b = legs_planLower.AddMLCBeam(ebmpStatic, MLCpos, new VRect <double>(x1, -200.0, x2, 200.0), 90.0, 0.0, 0.0, infIso); b.Id = String.Format("{0} AP Lower Legs", ++count); b.CreateOrReplaceDRR(DRR); //PA field b = legs_planLower.AddMLCBeam(ebmpStatic, MLCpos, new VRect <double>(x1, -200.0, x2, 200.0), 90.0, 180.0, 0.0, infIso); b.Id = String.Format("{0} PA Lower Legs", ++count); b.CreateOrReplaceDRR(DRR); } } //MessageBox.Show("calculating dose"); //legs_planUpper.CalculateDose(); //const int nChars = 256; //StringBuilder Buff = new StringBuilder(nChars); //IntPtr handle = GetForegroundWindow(); //if (GetWindowText(handle, Buff, nChars) > 0) //{ // MessageBox.Show(Buff.ToString()); //} } MessageBox.Show("Beams placed successfully!\nPlease proceed to the optimization setup tab!"); }