Example #1
0
        private Tuple <string, string, AutoCheckStatus> GetOptimizationInfo(StructureSet structureSet, PlanSetup planSetup)
        {
            string           value   = string.Empty;
            string           details = string.Empty;
            AutoCheckStatus  status  = AutoCheckStatus.MANUAL;
            List <Structure> strList = structureSet.Structures.Where(s => s.Id.ToLower().StartsWith("z_ptv")).ToList();

            List <string> lowerPTVObjectiveStructures = new List <string>(); //J Add list for name of all structures that have an lower objective

            foreach (OptimizationObjective optimizationObjective in planSetup.OptimizationSetup.Objectives)
            {
                if (optimizationObjective.GetType() == typeof(OptimizationPointObjective))
                {
                    OptimizationPointObjective optimizationPointObjective = (OptimizationPointObjective)optimizationObjective;
                    if (((optimizationPointObjective.Operator.ToString().ToLower() == "lower") || (optimizationPointObjective.Operator.ToString().ToLower() == "upper")) && optimizationPointObjective.StructureId.StartsWith("Z_PTV"))
                    {
                        // Generates a list for with name of all structures that have a lower objective (ie finds the PTVs).
                        lowerPTVObjectiveStructures.Add(optimizationPointObjective.StructureId);
                    }
                    details += (details.Length == 0 ? "Optimization objectives:\r\n  " : "\r\n  ") + optimizationPointObjective.StructureId + ": " + optimizationPointObjective.Operator.ToString() + ", dose: " + optimizationPointObjective.Dose.Dose.ToString("0.000") + ", volume: " + optimizationPointObjective.Volume.ToString("0.0") + ", priority: " + optimizationPointObjective.Priority.ToString();
                }
            }
            if (!strList.Any() && !lowerPTVObjectiveStructures.Any())
            {
                value += "Inget optimeringsPTV hittat, verifera";
                status = AutoCheckStatus.MANUAL;
            }
            else if (strList.Any() && !lowerPTVObjectiveStructures.Any())
            {
                value += "OptimeringsPTV har ritats men ej används i optimering, vänligen verifera";
                status = AutoCheckStatus.WARNING;
            }
            else if (strList.Any() && lowerPTVObjectiveStructures.Any())
            {
                value += "OptimeringsPTV har ritats och använts optimering, vänligen verifiera";
                status = AutoCheckStatus.MANUAL;
            }

            // JSR
            foreach (OptimizationParameter optimizationParameter in planSetup.OptimizationSetup.Parameters)
            {
                if (optimizationParameter.GetType() == typeof(OptimizationPointCloudParameter))
                {
                    OptimizationPointCloudParameter optimizationPointCloudParameter = (OptimizationPointCloudParameter)optimizationParameter;
                    details += (details.Length == 0 ? string.Empty : "\r\n") + "Point cloud parameter: " + optimizationPointCloudParameter.Structure.Id + "=" + optimizationPointCloudParameter.Structure.DicomType.ToString();
                }
                else if (optimizationParameter.GetType() == typeof(OptimizationNormalTissueParameter))
                {
                    OptimizationNormalTissueParameter optimizationNormalTissueParameter = (OptimizationNormalTissueParameter)optimizationParameter;
                    details += (details.Length == 0 ? string.Empty : "\r\n") + "Normal tissue parameter: priority=" + optimizationNormalTissueParameter.Priority.ToString();
                }
                else if (optimizationParameter.GetType() == typeof(OptimizationExcludeStructureParameter))
                {
                    OptimizationExcludeStructureParameter optimizationExcludeStructureParameter = (OptimizationExcludeStructureParameter)optimizationParameter;
                    details += (details.Length == 0 ? string.Empty : "\r\n") + "Exclude structure parameter: " + optimizationExcludeStructureParameter.Structure.Id;
                }
            }
            return(new Tuple <string, string, AutoCheckStatus>(value, details, status));
        }
Example #2
0
        public void B()
        {
            checklistItems.Add(new ChecklistItem("B. Bolus"));

            string          b1_value  = string.Empty;
            AutoCheckStatus b1_status = AutoCheckStatus.UNKNOWN;

            if (planSetup.StructureSet != null)
            {
                bool tpsBolusExist = false;
                foreach (Structure structure in planSetup.StructureSet.Structures)
                {
                    if (string.Compare(structure.DicomType, "BOLUS") == 0)
                    {
                        tpsBolusExist = true;
                    }
                }
                if (!tpsBolusExist)
                {
                    b1_value  = "Ej ansatt";
                    b1_status = AutoCheckStatus.PASS;
                }
                else
                {
                    b1_value = "Bolus har ansatts i TPS";
                }
            }
            else
            {
                b1_value = "StructureSet saknas";
            }
            checklistItems.Add(new ChecklistItem("B1. I dosplaneringssystemet ansatt bolus är med i beräkningen", "Kontrollera att bolus som ansatts i dosplaneringssystemet är med i beräkningen (kopplat till resp. fält)", b1_value, b1_status));

            AutoCheckStatus b2_status = AutoCheckStatus.MANUAL;
            string          b2_value  = string.Empty;
            // Check against prescription
            DataTable bolus = AriaInterface.Query("select PlanSetupSer, PlanSetup.PrescriptionSer, Prescription.PrescriptionSer, BolusFrequency, BolusThickness from PlanSetup, Prescription where PlanSetup.PrescriptionSer = Prescription.PrescriptionSer and PlanSetup.PlanSetupSer = " + planSetupSer.ToString());

            if (bolus.Rows.Count > 0)
            {
                b2_value += (bolus.Rows[0][3] == DBNull.Value ? string.Empty : (string)bolus.Rows[0][3]);
                b2_value += (b2_value.Length == 0 ? string.Empty : ", ") + (bolus.Rows[0][4] == DBNull.Value ? string.Empty : (string)bolus.Rows[0][4]);
            }

            if (String.IsNullOrWhiteSpace(b2_value))
            {
                b2_value = "Information saknas";
            }

            checklistItems.Add(new ChecklistItem("B2. Ordinationen innehåller information om bolus", "Kontrollera att bolus finns angivet i ordinationen (aktuell tjocklek och bolustyp)\r\n  • Notera att uppgifter normalt saknas för de behandlingar där bolus används rutinmässigt (t.ex. 0.5 cm superflabb över ärr för abladerad mam)", b2_value, b2_status));
        }
Example #3
0
        OldChecks()
        {
            string u3_value = string.Empty;

            foreach (Beam beam in planSetup.Beams)
            {
                if (!beam.IsSetupField)
                {
                    if (u3_value != string.Empty)
                    {
                        u3_value += ", ";
                    }
                    u3_value += beam.Id + ": " + Math.Round(beam.Meterset.Value, 1).ToString() + " " + beam.Meterset.Unit.ToString();
                }
            }
            checklistItems.Add(new ChecklistItem("U3. Jämför MU mellan behandlingsprotokoll och Aria", "Kontrollera att MU stämmer överens mellan Aria/Eclipse och behandlingsprotokoll", u3_value, AutoCheckStatus.MANUAL));

            if (checklistType != ChecklistType.EclipseVMAT && checklistType != ChecklistType.MasterPlanIMRT)
            {
                checklistItems.Add(new ChecklistItem("U4. Diodvärden finns dokumenterade i protokollet", "Kontrollera att diodvärden finns dokumenterade i protokollet för konventionella planer.\r\nEclipse: Centralaxeln är lämplig som diodpunkt, i annat fall ska manuellt inskrivna diodvärden finnas i protokollet", string.Empty, AutoCheckStatus.MANUAL));
            }

            string          g1_value  = (image == null ? "-" : image.Comment);
            AutoCheckStatus g1_status = CheckResult(string.Compare(g1_value, "RT Thorax med gating  3.0  I30s") == 0);

            checklistItems.Add(new ChecklistItem("G1. CT-studie är korrekt m.a.p. gatingordination", "Kontrollera att det är ritat i korrekt CT-studie m.a.p. gatingordination (anges av läkare under kommentarer under behandlingsordination i behandlingskortet) och Image comment i protokollet", g1_value, g1_status));

            string          s11_value  = string.Empty;
            AutoCheckStatus s11_status = AutoCheckStatus.PASS;

            foreach (Beam beam in planSetup.Beams)
            {
                string    refImageId         = string.Empty;
                DataTable dataTableIDUPosVrt = AriaInterface.Query("select Image.ImageId from Radiation,Image where Image.ImageSer=Radiation.RefImageSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");
                if (dataTableIDUPosVrt.Rows.Count == 1)
                {
                    refImageId = (string)dataTableIDUPosVrt.Rows[0][0];
                }
                else
                {
                    s11_status = AutoCheckStatus.FAIL;
                }
                s11_value += (s11_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + (refImageId.Length == 0 ? "-" : refImageId);
            }
            checklistItems.Add(new ChecklistItem("S3. Referensbild/DRR kopplad till alla fält", "Kontrollera att alla fält har en DRR kopplad samt har referensbild kopplad (gul ram runt bildikonen)", s11_value, s11_status));
        }
Example #4
0
        public void X()
        {
            checklistItems.Add(new ChecklistItem("X. Slutförande"));

            //checklistItems.Add(new ChecklistItem("X1. Skriv in antal MU, diodvärden och följande eventuella diodkorrektioner i behandlingskortet", "Skriv in antal MU, diodvärden och följande eventuella diodkorrektioner i behandlingskortet (se ”In vivo-dosimetri”-dokumentet för detaljer):\r\n  • Kil (Mimatordioder på Elekta)\r\n  • Kort SSD (IBA-dioder)\r\n  • Långt SSD (Mimatordioder)", string.Empty, AutoCheckStatus.MANUAL));

            string          x2_value  = string.Empty;
            AutoCheckStatus x2_status = AutoCheckStatus.MANUAL;

            if (image != null && image.Series != null)
            {
                x2_value = image.Series.ImagingDeviceId;
                if (string.Compare(image.Series.ImagingDeviceId, "CT_A") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_B") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_C") == 0)
                {
                    if (planSetup.Beams.Count() > 0)
                    {
                        double             userY   = -image.UserOrigin.y * 0.1;
                        IEnumerable <Beam> txBeams = planSetup.Beams.Where(x => x.IsSetupField == false);
                        //Summarises all ssds for treatment beams, if this is > x*1000 the bool will be true.
                        bool fhaTechnique = txBeams.Select(x => Math.Round(x.SSD)).ToList().Sum() >= (double)txBeams.Count() * 1000;
                        IEnumerable <VVector> uniqueIsos = new List <VVector>();
                        if (fhaTechnique)
                        {
                            uniqueIsos = GetAllIsocenters(planSetup);
                        }
                        if (uniqueIsos.Count() > 1 && uniqueIsos.Count() <= 2) //This part will give 2 different couch positions based if there are 2 isocenters.
                        {
                            bool   warningToggle = false;
                            double firstIsoYPos  = double.NaN;
                            foreach (Beam beam in planSetup.Beams)
                            {
                                if (!beam.IsSetupField && !(firstIsoYPos == -(beam.IsocenterPosition.y - image.UserOrigin.y) * 0.1))
                                {
                                    double isoY = -(beam.IsocenterPosition.y - image.UserOrigin.y) * 0.1;

                                    if (planSetup.TreatmentOrientation.ToString().IndexOf("Prone") != -1) // Change sign if Orientation is Prone.
                                    {
                                        isoY  *= -1;
                                        userY *= -1;
                                    }
                                    double shiftY = 7.1;
                                    double sumY   = -isoY - userY + shiftY;
                                    x2_value += ", Beräknad britshöjd " + (Double.IsNaN(firstIsoYPos) ? "Iso 1: ": "Iso 2: ") + (-userY).ToString("0.0") + (-isoY >= 0 ? "+" : string.Empty) + (-isoY).ToString("0.0") + "+" + shiftY.ToString("0.0") + " = " + sumY.ToString("0.0") + " cm";
                                    if (sumY < -30 && !warningToggle)
                                    {
                                        x2_status = AutoCheckStatus.WARNING;
                                    }
                                    if (Double.IsNaN(firstIsoYPos))
                                    {
                                        firstIsoYPos = isoY;
                                    }
                                }
                            }
                        }
                        else if (uniqueIsos.Count() > 2) // if more that 2 isos it will promp the user to measure manually.
                        {
                            x2_value += ", Mer än tre iso mät positioner manuellt";
                        }
                        else
                        {
                            double isoY = -(planSetup.Beams.First().IsocenterPosition.y - image.UserOrigin.y) * 0.1;
                            if (planSetup.TreatmentOrientation.ToString().IndexOf("Prone") != -1) // Change sign if Orientation is Prone.
                            {
                                isoY  *= -1;
                                userY *= -1;
                            }
                            double shiftY = 7.1;
                            double sumY   = -isoY - userY + shiftY;
                            x2_value += ", Beräknad britshöjd: " + (-userY).ToString("0.0") + (-isoY >= 0 ? "+" : string.Empty) + (-isoY).ToString("0.0") + "+" + shiftY.ToString("0.0") + " = " + sumY.ToString("0.0") + " cm";
                            if (sumY < -30)
                            {
                                x2_status = AutoCheckStatus.WARNING;
                            }
                        }
                    }
                }
                else if (string.Compare(image.Series.ImagingDeviceId, "PET/CT 01") == 0)
                {
                    x2_value += ", Mät position manuellt";
                }
                else if (string.Compare(image.Series.ImagingDeviceId, "PET/CT 02") == 0)
                {
                    x2_value += ", Mät position manuellt";
                }
                else if (string.Compare(image.Series.ImagingDeviceId, "PET/CT 03") == 0)
                {
                    x2_value += ", Mät position manuellt";
                }
                else if (syntheticCT)
                {
                    x2_value += ", Mät position manuellt";
                }
            }
            checklistItems.Add(new ChecklistItem("X2. Förväntad britshöjd räknas ut och läggs in i Aria", "Räkna ut förväntad britshöjd och lägg in i Aria (på alla fält, inklusive setup-fält) i modulen Treatment Preparation i rutan för Couch Vrt:\r\n• Eclipse: -DICOM offset Z - isocenter Z + offset cm\r\n• Offset är 7,1 cm för CT_A, CT_B, CT_C\r\n• Observera att vid för prone byter DICOM-koordinaten tecken\r\n• Observera risk för kollision mellan gantry och bord vid Vrt < -30 cm\r\nVid SSD-teknik:\r\n  • Ska tjockleken på eventuell vacuumpåse bestämmas genom mätning i CT-bilderna och antecknas under Setup note\r\n  • Räkna ut förflyttning från fältet närmast 0° till övriga fält (Isocenterkoordinat för ursprungsfältet minus övriga fälts isocenterkoordinater) och anteckna detta på sida 2 i behandlingsprotokollet. Exempel: Relativ förflyttning från fält 1 till fält 2: ∆Vrt=25,0 cm.\r\n  • Skriv följande under Setup note: ”FHA-beh. Ring fysiker vid start.”", x2_value, x2_status));
            //checklistItems.Add(new ChecklistItem("X2. Förväntad britshöjd räknas ut och läggs in i Aria", "Räkna ut förväntad britshöjd och lägg in i Aria (på alla fält, inklusive setup-fält) i modulen Treatment Preparation i rutan för Couch Vrt:\r\n• Eclipse: -DICOM offset Z - isocenter Z + offset cm\r\nMasterPlan: -TPRP coordinate Z - isocenter Z + offset cm\r\n• Offset är 7,1 cm för CT_A, CT_B, CT_C och -17,5 för PET/CT 01 (kan dock variera beroende på britshöjd vid PET-undersökningen)\r\n• Observera risk för kollision mellan gantry och bord vid Vrt < -30 cm\r\nVid SSD-teknik:\r\n  • Ska tjockleken på eventuell vacuumpåse bestämmas genom mätning i CT-bilderna och antecknas under Setup note\r\n  • Räkna ut förflyttning från fältet närmast 0° till övriga fält (Isocenterkoordinat för ursprungsfältet minus övriga fälts isocenterkoordinater) och anteckna detta på sida 2 i behandlingsprotokollet. Exempel: Relativ förflyttning från fält 1 till fält 2: ∆Vrt=25,0 cm.\r\n  • Skriv följande under Setup note: ”FHA-beh. Ring fysiker vid start.”", x2_value, x2_status));
            // Add elinores corda computation here

            if (checklistType == ChecklistType.EclipseVMAT && GetVMATCoplanar(planSetup) == false)
            {
                // check that setup note for beam "Uppl*gg" contains the string
                AutoCheckStatus x3_status = AutoCheckStatus.FAIL;
                string          defSetup  = "NC-platta används vid behandling pga golvvinkel";//OBS! Icke-coplanar behandling (britsrotation). Använd NC-plattan som förlängning av britsen.";
                DataTable       setupNote = AriaInterface.Query("select SetupNote from Radiation where PlanSetupSer=" + planSetupSer.ToString() + " and UPPER(RadiationId) like 'UPPL%GG'");
                foreach (DataRow row in setupNote.Rows)
                {
                    if (row["SetupNote"].ToString().IndexOf(defSetup) >= 0)
                    {
                        x3_status = AutoCheckStatus.PASS;
                    }
                }
                if (x3_status == AutoCheckStatus.FAIL)
                {
                    Clipboard.SetText(defSetup + "\r\n");
                    checklistItems.Add(new ChecklistItem("X3. Notera icke coplanar VMAT under Setup note", "Planen i fråga är en icke coplanar VMAT behandling. Säkerställ att en notering om detta finns under planens Setup note. Den exakta formuleringen ska vara: \r\n" + defSetup, string.Empty, defSetup, x3_status));
                }
                else
                {
                    checklistItems.Add(new ChecklistItem("X3. Notera icke coplanar VMAT under Setup note", "Planen i fråga är en icke coplanar VMAT behandling. Säkerställ att en notering om detta finns under planens Setup note. Den exakta formuleringen ska vara: \r\n" + defSetup, string.Empty, x3_status));
                }
            }

            if (checklistType == ChecklistType.Eclipse || checklistType == ChecklistType.EclipseGating)
            {
                checklistItems.Add(new ChecklistItem("X4. Genomför oberoende MU-kontroll", "Genomför obeorende MU-kontroll via RVP", "", AutoCheckStatus.MANUAL));
            }

            if (checklistType == ChecklistType.EclipseVMAT || checklistType == ChecklistType.EclipseConformal)
            {
                AutoCheckStatus x5_status  = AutoCheckStatus.MANUAL;
                string          x5_value   = string.Empty;
                string          x5_details = string.Empty;
                //List<string> reqStrings = new List<string>() {"qc","d","4"};
                //lägg till kontroll att QC - plan finns och ger annars varning. WORK in progress
                DataTable qcPlans = AriaInterface.Query("select PlanSetup.PlanSetupId from (select ClinRTPlanSer = RTPlan.RTPlanSer from RTPlan where RTPlan.PlanSetupSer = '" + planSetupSer.ToString() + "') as ClinRTPlan, PlanSetup inner join RTPlan on PlanSetup.PlanSetupSer = RTPlan.PlanSetupSer inner join PlanRelationship on PlanRelationship.RTPlanSer = RTPlan.RTPlanSer where PlanRelationship.RelationshipType = 'VERIFIED_PLAN' and PlanRelationship.RelatedRTPlanSer = ClinRTPlanSer order by PlanSetup.PlanSetupId");

                if (qcPlans.Rows.Count > 0)
                {
                    foreach (DataRow row in qcPlans.Rows)
                    {
                        x5_value += (x5_value.Length == 0 ? "Verifikationsplaner finns: " : ", ") + (string)row["PlanSetupId"];
                    }
                    if (!(x5_value.IndexOf("QC") > 1 && (x5_value.IndexOf("d") > 1 || x5_value.IndexOf("D") > 1) && x5_value.IndexOf("4") > 1))
                    {
                        x5_value += " OBS: Inkorrekt namn på verifikationsplan, automatisk export ej möjlig";
                        x5_status = AutoCheckStatus.WARNING;
                    }
                }
                else // SÄtter varning om det inte finns nån QC-plan
                {
                    x5_status = AutoCheckStatus.FAIL;
                    x5_value  = "Det finns ingen QC-plan kopplad till den kliniska planen. Det skall föreligga QC-plan för Delta4.";
                }

                checklistItems.Add(new ChecklistItem("X5. QC-planer/QC course sätts till Completed.", "Sätt status på QC coursen till Completed. \nKontroll av befintiliga QC-planer görs. \nNamngivning enligt: QC PX_X Delta4.", x5_value, x5_status));
            }
            if (checklistType == ChecklistType.EclipseGating && image.Comment.IndexOf("DIBH") != -1 || checklistType == ChecklistType.EclipseGating && image.Comment.IndexOf("BH") != -1)
            {
                double[] deltaCouch = new double[3];
                IEnumerable <VVector> AllIsosPos = GetAllIsocenters(planSetup);
                if (AllIsosPos.Count() == 1)
                {
                    Beam beam = planSetup.Beams.Where(b => b.IsSetupField == false).FirstOrDefault();
                    deltaCouch[0] = -beam.IsocenterPosition.x / 10.0;
                    deltaCouch[1] = -beam.IsocenterPosition.z / 10.0;
                    DataTable CouchPos = AriaInterface.Query("select distinct Slice.CouchVrt from Slice inner join Series on Series.SeriesSer=Slice.SeriesSer where Series.SeriesUID='" + image.Series.UID + "'");
                    double    couchVrt = (double)CouchPos.Rows[0]["CouchVrt"];
                    deltaCouch[2] = beam.IsocenterPosition.y / 10.0 - couchVrt;
                    checklistItems.Add(new ChecklistItem("X6. Fyll i värden för Delta Couch.", "Fyll i beräknade Delta Couch-värden för planens alla fält.", String.Format("Vrt: {0:N2} cm, Lng: {1:N2} cm, Lat: {2:N2} cm", deltaCouch[2], deltaCouch[1], deltaCouch[0]), String.Format("Delta Couch shift (cm):\r\nVrt:\t{0:N2}\r\nLng:\t{1:N2}\r\nLat:\t{2:N2}", deltaCouch[2], deltaCouch[1], deltaCouch[0]), AutoCheckStatus.MANUAL));
                }
                else
                {
                    string    IsoInfo  = string.Empty;
                    DataTable CouchPos = AriaInterface.Query("select distinct Slice.CouchVrt from Slice inner join Series on Series.SeriesSer=Slice.SeriesSer where Series.SeriesUID='" + image.Series.UID + "'");
                    double    couchVrt = (double)CouchPos.Rows[0]["CouchVrt"];
                    int       count    = 0;
                    foreach (VVector iso in AllIsosPos)
                    {
                        count        += 1;
                        deltaCouch[0] = -iso.x / 10.0;
                        deltaCouch[1] = -iso.z / 10.0;
                        deltaCouch[2] = iso.y / 10 - couchVrt;
                        IsoInfo      += "Iso " + count.ToString() + String.Format(": Vrt: {0:N2} cm, Lng: {1:N2} cm, Lat: {2:N2} cm", deltaCouch[2], deltaCouch[1], deltaCouch[0]) + " \r\n\r\n";
                    }
                    checklistItems.Add(new ChecklistItem("X6. Fyll i värden för Delta Couch.", "Fyll i beräknade Delta Couch-värden för planens alla fält. \r\nDUBBLA ISOCENTER + DIBH! Fysiker importerar till Catalyst", "Planen ifråga har " + (count).ToString() + " isocenter och därmed skall multipla delta couch fyllas i se Detaljer ----->", "Delta Couch shift (cm):\r\n" + IsoInfo, AutoCheckStatus.WARNING));
                }

                //checklistItems.Add(new ChecklistItem("X7. Importera underlag till Catalyst.", "Importera plan och strukturset till Catalyst i enlighet med gällande metodbeskrivning.", String.Empty, AutoCheckStatus.MANUAL));
            }

            checklistItems.Add(new ChecklistItem("X7. Treatment Approved", "Gör planen Treatment Approved. Planen får endast göras Treatment Approved efter att ovanstående kontroller är utförda och Oberoende MU-kontroll eller QC-mätning är godkänd.", string.Empty, AutoCheckStatus.MANUAL));

            checklistItems.Add(new ChecklistItem("X8. Task sätts till Done", "Tryck Done när alla kontroller är klara\r\n  • Ändra Qty till det antal planer som har kontrollerats\r\n  • Om planen har kontrollmätts tycker man Done först när planen både är kontrollerad och kontrollmätt", string.Empty, AutoCheckStatus.MANUAL));

            //checklistItems.Add(new ChecklistItem("X5. Signera i rutan Fysiker kontroll", "Genomgången checklista med accepterat resultat bekräftas med signatur i behandlingskortet i rutan Fysiker kontroll.", string.Empty, AutoCheckStatus.MANUAL));
        }
Example #5
0
        public void V()
        {
            if (checklistType == ChecklistType.EclipseVMAT || checklistType == ChecklistType.MasterPlanIMRT)
            {
                checklistItems.Add(new ChecklistItem("V. VMAT/IMRT"));

                string          v1_value            = string.Empty;
                AutoCheckStatus v1_status           = AutoCheckStatus.FAIL;
                int             v1_numberOfWarnings = 0;
                int             v1_numberOfPass     = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double collimatorAngle = beam.ControlPoints[0].CollimatorAngle;
                        if (checklistType == ChecklistType.MasterPlanIMRT)
                        {
                            if (collimatorAngle == 2)
                            {
                                v1_numberOfPass++;
                            }
                            else if (collimatorAngle > 2 && collimatorAngle < 358)
                            {
                                v1_numberOfWarnings++;
                            }
                        }
                        else
                        {
                            if (collimatorAngle == 5 || collimatorAngle == 355)
                            {
                                v1_numberOfPass++;
                            }
                            else if (collimatorAngle > 5 && collimatorAngle < 355)
                            {
                                v1_numberOfWarnings++;
                            }
                        }
                        v1_value += (v1_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + collimatorAngle.ToString("0.0") + "°";
                    }
                }
                if (v1_numberOfPass == numberOfTreatmentBeams)
                {
                    v1_status = AutoCheckStatus.PASS;
                }
                else if (v1_numberOfPass + v1_numberOfWarnings == numberOfTreatmentBeams)
                {
                    v1_status = AutoCheckStatus.WARNING;
                }
                checklistItems.Add(new ChecklistItem("V1. Kollimatorvinkeln är lämplig", "Kontrollera att kollimatorvinkeln är lämplig\r\n  • VMAT: vanligtvis 5° grader resp. 355°, men passar detta ej PTV är andra vinklar ok (dock ej vinklar mellan 355° och 5°)", v1_value, v1_status));

                if (checklistType == ChecklistType.EclipseVMAT)
                {
                    string          v2_value        = string.Empty;
                    AutoCheckStatus v2_status       = AutoCheckStatus.WARNING;
                    int             v2_numberOfPass = 0;
                    foreach (Beam beam in planSetup.Beams)
                    {
                        if (!beam.IsSetupField)
                        {
                            double fieldWidth = 0.1 * (beam.ControlPoints[0].JawPositions.X2 - beam.ControlPoints[0].JawPositions.X1);
                            if (fieldWidth <= 15)
                            {
                                v2_numberOfPass++;
                            }
                            v2_value += (v2_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + fieldWidth.ToString("0.0") + " cm";
                        }
                    }
                    if (v2_numberOfPass == numberOfTreatmentBeams)
                    {
                        v2_status = AutoCheckStatus.PASS;
                    }
                    checklistItems.Add(new ChecklistItem("V2. Fältbredden är rimlig ", "Kontrollera att VMAT-fält har en rimlig fältbredd (riktvärde 15 cm, vid större target rekommenderas två arcs och delade fält).", v2_value, v2_status));

                    string v3_details = string.Empty;
                    if (planSetup.OptimizationSetup != null)
                    {
                        /*foreach (OptimizationObjective optimizationObjective in planSetup.OptimizationSetup.Objectives)
                         *  if(optimizationObjective.GetType()==typeof(OptimizationPointObjective))
                         *  {
                         *      OptimizationPointObjective optimizationPointObjective = (OptimizationPointObjective)optimizationObjective;
                         *      v3_details += (v3_details.Length == 0 ? "Optimization objectives:\r\n  " : "\r\n  ") + optimizationPointObjective.StructureId + ": " +  optimizationPointObjective.Operator.ToString() + ", dose: " + optimizationPointObjective.Dose.Dose.ToString("0.000") + ", volume: " + optimizationPointObjective.Volume.ToString("0.0") + ", priority: " + optimizationPointObjective.Priority.ToString();
                         *  }*/
                        foreach (OptimizationParameter optimizationParameter in planSetup.OptimizationSetup.Parameters)
                        {
                            if (optimizationParameter.GetType() == typeof(OptimizationPointCloudParameter))
                            {
                                OptimizationPointCloudParameter optimizationPointCloudParameter = (OptimizationPointCloudParameter)optimizationParameter;
                                v3_details += (v3_details.Length == 0 ? string.Empty : "\r\n") + "Point cloud parameter: " + optimizationPointCloudParameter.Structure.Id + "=" + optimizationPointCloudParameter.Structure.DicomType.ToString();
                            }
                            else if (optimizationParameter.GetType() == typeof(OptimizationNormalTissueParameter))
                            {
                                OptimizationNormalTissueParameter optimizationNormalTissueParameter = (OptimizationNormalTissueParameter)optimizationParameter;
                                v3_details += (v3_details.Length == 0 ? string.Empty : "\r\n") + "Normal tissue parameter: priority=" + optimizationNormalTissueParameter.Priority.ToString();
                            }
                            else if (optimizationParameter.GetType() == typeof(OptimizationExcludeStructureParameter))
                            {
                                OptimizationExcludeStructureParameter optimizationExcludeStructureParameter = (OptimizationExcludeStructureParameter)optimizationParameter;
                                v3_details += (v3_details.Length == 0 ? string.Empty : "\r\n") + "Exclude structure parameter: " + optimizationExcludeStructureParameter.Structure.Id;
                            }
                        }
                    }
                    checklistItems.Add(new ChecklistItem("V3. Optimeringsbolus är korrekt använt", "Kontrollera att optimeringsbolus har använts korrekt för ytliga target:	\r\n  Eclipse H&N (VMAT):\r\n    • Optimerings-PTV har använts vid optimeringen i de fall då PTV har beskurits med hänsyn till ytterkonturen\r\n    • Skillnaderna i maxdos för uncertainty-planerna (±0,4 cm i x, y, resp. z) är <5% relativt orginalplanen. Planerna skapas av dosplaneraren.\r\n    • HELP_BODY inkluderar både patientens ytterkontur (BODY) och optimeringsbolus\r\n  Eclipse Ani, Recti (VMAT):\r\n    • BODY ska inkludera eventuellt optimeringsbolus\r\n  Optimeringsbolus i Eclipse (VMAT):\r\n    • HU för optimeringsbolus är satt till 0 HU\r\n    • Optimeringsbolus är skapat genom 5 mm (H&N) eller 6 mm (Ani, Recti) expansion från det PTV-struktur optimeringen skett på. Boluset ska ej gå innanför patientens hudyta.", string.Empty, v3_details, AutoCheckStatus.MANUAL));

                    checklistItems.Add(new ChecklistItem("V4. Leveransmönstret är rimligt", "Kontrollera att leveransmönstret är rimligt (att det inte är en stor andel extremt små öppningar och att riskorgan skärmas, samt att alla segment går på ett target)", string.Empty, AutoCheckStatus.MANUAL));
                }
            }
        }
Example #6
0
        public void P()
        {
            checklistItems.Add(new ChecklistItem("P. Dosplan"));

            string          p1_value  = planSetup.ApprovalStatus.ToString();
            AutoCheckStatus p1_status = CheckResult(planSetup.ApprovalStatus == PlanSetupApprovalStatus.PlanningApproved);

            checklistItems.Add(new ChecklistItem("P1. Planen är planning approved", "Kontrollera att planen är Planning Approved i Aria.", p1_value, p1_status));

            string          p2_value  = string.Empty;
            AutoCheckStatus p2_status = AutoCheckStatus.FAIL;

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Multiple)
            {
                p2_status = AutoCheckStatus.WARNING;
            }
            int p2_numberOfPass = 0;

            foreach (Beam beam in planSetup.Beams)
            {
                bool fff = (beam.EnergyModeDisplayName.IndexOf("FFF") != -1);
                if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
                {
                    if (fff == false && beam.DoseRate == 600)
                    {
                        p2_numberOfPass++;
                    }
                    else if (fff == true && beam.EnergyModeDisplayName.IndexOf("6") == 0 && beam.DoseRate == 1400)
                    {
                        p2_numberOfPass++;
                    }
                    else if (fff == true && beam.EnergyModeDisplayName.IndexOf("10") == 0 && beam.DoseRate == 2400)
                    {
                        p2_numberOfPass++;
                    }
                }
                else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta)
                {
                    if (beam.EnergyModeDisplayName.IndexOf("4") == 0 && beam.DoseRate == 250)
                    {
                        p2_numberOfPass++;
                    }
                    else if (beam.EnergyModeDisplayName.IndexOf("6") == 0 && beam.DoseRate == 600)
                    {
                        p2_numberOfPass++;
                    }
                    else if (beam.EnergyModeDisplayName.IndexOf("10") == 0 && beam.DoseRate == 500)
                    {
                        p2_numberOfPass++;
                    }

                    /*{
                     *  if (beam.TreatmentUnit.Id.IndexOf("L05") == -1 && beam.DoseRate == 400)
                     *      p2_numberOfPass++;
                     *  else if (beam.TreatmentUnit.Id.IndexOf("L05") != -1 && beam.DoseRate == 500)
                     *      p2_numberOfPass++;
                     * }*/
                }
                p2_value += (p2_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + beam.DoseRate.ToString();
            }
            if (p2_numberOfPass == numberOfBeams)
            {
                p2_status = AutoCheckStatus.PASS;
            }
            p2_value = reorderBeamParam(p2_value, ",");
            checklistItems.Add(new ChecklistItem("P2. Dosraten är korrekt", "Kontrollera att dosraten (MU/min) är korrekt:\r\n  • Varian: 600 (ej FFF), 1400 (6 MV FFF), 2400 (10 MV FFF)\r\n  • Elekta: 250 (4 MV), 600 (6 MV), 500 (10 MV)", p2_value, p2_status));

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          p3_value        = string.Empty;
                AutoCheckStatus p3_status       = AutoCheckStatus.FAIL;
                int             p3_numberOfPass = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double    treatmentTime      = double.NaN;
                        DataTable treatmentTimeTable = AriaInterface.Query("select TreatmentTime from Radiation,ExternalFieldCommon where ExternalFieldCommon.RadiationSer=Radiation.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");

                        if (treatmentTimeTable.Rows.Count == 1 && treatmentTimeTable.Rows[0][0] != DBNull.Value)
                        {
                            treatmentTime = (double)treatmentTimeTable.Rows[0][0];

                            double openMU;
                            double wedgedMU;
                            GetMU(beam, out openMU, out wedgedMU);

                            if (beam.EnergyModeDisplayName.IndexOf("FFF") != -1)
                            {
                                if (openMU < 600 && treatmentTime == 0.5)
                                {
                                    p3_numberOfPass++;
                                }
                            }
                            else if (checklistType == ChecklistType.EclipseVMAT)
                            {
                                if (openMU <= 400 && treatmentTime == 2)
                                {
                                    p3_numberOfPass++;
                                }
                                else if (openMU > 400 && treatmentTime == 3)
                                {
                                    p3_numberOfPass++;
                                }
                            }
                            else if (checklistType == ChecklistType.EclipseGating)
                            {
                                if (treatmentTime == 5)
                                {
                                    p3_numberOfPass++;
                                }
                            }
                            else
                            {
                                if (openMU <= 500 && wedgedMU == 0 && treatmentTime == 1 || wedgedMU > 0 && wedgedMU <= 300 && treatmentTime == 1)
                                {
                                    p3_numberOfPass++;
                                }
                                else if (openMU > 500 && wedgedMU == 0 && treatmentTime == 2 || wedgedMU > 300 && treatmentTime == 2)
                                {
                                    p3_numberOfPass++;
                                }
                            }
                        }

                        p3_value += (p3_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + (double.IsNaN(treatmentTime) ? "-" : treatmentTime.ToString() + " min");
                    }
                }
                if (p3_numberOfPass == numberOfTreatmentBeams)
                {
                    p3_status = AutoCheckStatus.PASS;
                }
                p3_value = reorderBeamParam(p3_value, ",");

                checklistItems.Add(new ChecklistItem("P3. Beam on-tiderna är korrekta", "Kontrollera att fälten är tilldelade korrekta beam on-tider:\r\n  • 0.5 min för FFF fält med <600 MU\r\n  • 1 min för öppna fält med <=500 MU och kilfält med <=300 MU\r\n  • 2 min för öppna fält med >500 MU, kilfält med >300 MU, och RapidArc (<=400 MU/arc)\r\n  • 3 min för RA (>400 MU/arc)\r\n  • 5 min för gating", p3_value, p3_status));
            }

            string          p4_value          = string.Empty;
            AutoCheckStatus p4_status         = AutoCheckStatus.FAIL;
            DataTable       dataTableUseGated = AriaInterface.Query("select distinct ExternalFieldCommon.MotionCompTechnique from Radiation,ExternalFieldCommon where Radiation.RadiationSer=ExternalFieldCommon.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString());

            if (dataTableUseGated.Rows.Count == 1 && dataTableUseGated.Rows[0][0] != DBNull.Value && string.Compare((string)dataTableUseGated.Rows[0][0], "GATING") == 0)
            {
                if (checklistType == ChecklistType.EclipseGating)
                {
                    p4_status = AutoCheckStatus.PASS;
                }
                else
                {
                    p4_status = AutoCheckStatus.FAIL;
                }
                p4_value = "Ikryssad";
            }
            else
            {
                if (checklistType == ChecklistType.EclipseGating)
                {
                    p4_status = AutoCheckStatus.FAIL;
                }
                else
                {
                    p4_status = AutoCheckStatus.PASS;
                }
                p4_value = "Ej ikryssad";
            }
            checklistItems.Add(new ChecklistItem("P4. Use Gated är korrekt", "Kontrollera att rutan Use Gated under Plan properties är ikryssad för gatingplaner respektive inte ikryssad för icke-gatingplaner.", p4_value, p4_status));

            if (checklistType == ChecklistType.EclipseGating)
            {
                string          p5_value  = string.Empty;
                AutoCheckStatus p5_status = AutoCheckStatus.FAIL;
                if (image != null && image.Comment.ToLower().IndexOf("bh") == -1)
                {
                    int p5_numberOfPass = 0;
                    foreach (Beam beam in planSetup.Beams)
                    {
                        if (!beam.IsSetupField)
                        {
                            double openMU;
                            double wedgedMU;
                            GetMU(beam, out openMU, out wedgedMU);
                            if (wedgedMU == 0)
                            {
                                p5_numberOfPass++;
                            }
                        }
                    }
                    if (p5_numberOfPass == numberOfTreatmentBeams)
                    {
                        p5_status = AutoCheckStatus.PASS;
                    }
                    p5_value = "EIG";
                }
                else
                {
                    p5_status = AutoCheckStatus.PASS;
                    p5_value  = "Breath hold";
                }
                checklistItems.Add(new ChecklistItem("P5. Kilade fält ej förekommande för EIG", "Kontrollera att det inte finns några kilade fält i EIG gating-plan.", p5_value, p5_status));
            }

            string          p6_value                   = string.Empty;
            string          p6_value_detailed          = string.Empty;
            AutoCheckStatus p6_status                  = AutoCheckStatus.UNKNOWN;
            DataTable       dataTableTreatmentSessions = AriaInterface.Query("select Session.SessionNum,SessionRTPlan.Status from Session,SessionRTPlan,RTPlan where Session.SessionSer=SessionRTPlan.SessionSer and RTPlan.RTPlanSer=SessionRTPlan.RTPlanSer and RTPlan.PlanSetupSer=" + planSetupSer.ToString() + " order by SessionNum");

            foreach (DataRow dataRow in dataTableTreatmentSessions.Rows)
            {
                int    sessionNr = (int)dataRow[0];
                string status    = (dataRow[1] == DBNull.Value ? "-" : (string)dataRow[1]);
                p6_value_detailed += (p6_value_detailed.Length == 0 ? string.Empty : "\r\n") + "Session " + sessionNr.ToString() + ": " + status;
            }
            p6_value = "# aktiva sessioner: " + dataTableTreatmentSessions.Rows.Count.ToString();
            if (fractionation != null && fractionation.NumberOfFractions > 0 && fractionation.NumberOfFractions == dataTableTreatmentSessions.Rows.Count)
            {
                p6_status = AutoCheckStatus.PASS;
            }
            else
            {
                p6_status = AutoCheckStatus.FAIL;
            }
            checklistItems.Add(new ChecklistItem("P6. Behandlingssessionerna är aktiva", "Kontrollera att alla behandlingssessioner är aktiva", p6_value, p6_value_detailed, p6_status));

            if (checklistType == ChecklistType.Eclipse || checklistType == ChecklistType.EclipseGating || checklistType == ChecklistType.MasterPlan)
            {
                string          p7_value        = string.Empty;
                AutoCheckStatus p7_status       = AutoCheckStatus.FAIL;
                int             p7_numberOfPass = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double diode_value = double.NaN;
                        if (beam.Comment.Length > 0)
                        {
                            NumberFormatInfo numberFormatInfo = new NumberFormatInfo()
                            {
                                NumberDecimalSeparator = ".", NumberGroupSeparator = string.Empty, NegativeInfinitySymbol = "Inf", PositiveInfinitySymbol = "Inf", NaNSymbol = "NaN", NumberDecimalDigits = 0
                            };
                            string[] splitString = beam.Comment.ToLower().Split(new string[] { " ", "gy" }, StringSplitOptions.RemoveEmptyEntries);
                            if (splitString.Length == 0)
                            {
                                double.TryParse(beam.Comment.Replace(',', '.'), NumberStyles.Number | NumberStyles.AllowExponent, numberFormatInfo, out diode_value);
                            }
                            else
                            {
                                double.TryParse(splitString[0].Replace(',', '.'), NumberStyles.Number | NumberStyles.AllowExponent, numberFormatInfo, out diode_value);
                            }
                        }
                        double openMU;
                        double wedgedMU;
                        GetMU(beam, out openMU, out wedgedMU);
                        if (double.IsNaN(diode_value) == false)
                        {
                            p7_numberOfPass++;
                        }
                        else
                        {
                            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian && openMU + wedgedMU < 25)
                            {
                                p7_numberOfPass++;
                            }
                            else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta && openMU < 25 && openMU + wedgedMU < 50)
                            {
                                p7_numberOfPass++;
                            }
                        }
                        p7_value += (p7_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + (double.IsNaN(diode_value) ? "-" : diode_value.ToString() + " Gy");
                    }
                }
                if (p7_numberOfPass == numberOfTreatmentBeams)
                {
                    p7_status = AutoCheckStatus.PASS;
                }
                p7_value = reorderBeamParam(p7_value, ",");
                checklistItems.Add(new ChecklistItem("P7. Diodvärden finns införda under Comments för fälten", "Kontrollera att diodvärden finns införda för fält med >=25 MU alternativt >=50 MU (öppet+kil) för Elekta.", p7_value, p7_status));
            }

            checklistItems.Add(new ChecklistItem("P8. Dosfördelningen är rimlig", "Kontrollera att dosfördelningen är rimlig med avseende på targettäckning och omkringliggande riskorgan", "", AutoCheckStatus.MANUAL));

            string          p9_value_detailed = string.Empty;
            string          p9_value          = String.Empty;
            bool            isSplit           = false;
            AutoCheckStatus p9_status         = AutoCheckStatus.UNKNOWN;

            if (checklistType == ChecklistType.EclipseVMAT)
            {
                isSplit = GetIsSplitVMAT(planSetup);
            }
            foreach (Beam beam in planSetup.Beams)
            {
                if (!beam.IsSetupField)
                {
                    double openMU;
                    double wedgedMU;
                    GetMU(beam, out openMU, out wedgedMU);

                    p9_value_detailed += beam.Id + ":\r\n";
                    if (checklistType == ChecklistType.EclipseVMAT)
                    {
                        p9_value_detailed += "  Open: " + openMU.ToString("0.0") + " MU\r\n  " + beam.MetersetPerGy.ToString("0.0") + " MU/Gy\r\n";
                        if (beam.MetersetPerGy > 300 && !isSplit)
                        {
                            p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För många MU/Gy";
                        }
                        else if (beam.MetersetPerGy > 550 && isSplit)
                        {
                            p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För många MU/Gy";
                        }
                    }
                    else
                    {
                        p9_value_detailed += "  Open: " + openMU.ToString("0.0") + ", Wedged: " + wedgedMU.ToString("0.0") + "\r\n";
                    }
                    p9_value_detailed += "  Energi: " + beam.EnergyModeDisplayName + "\r\n\r\n";

                    if (openMU < 10 && openMU != 0 || wedgedMU < 30 && wedgedMU != 0)
                    {
                        p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För få MU";
                    }
                    if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta && openMU + wedgedMU > 999)
                    {
                        p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För många MU";
                    }
                }
            }
            if (p9_value.Length > 0)
            {
                if (checklistType == ChecklistType.EclipseVMAT)
                {
                    p9_status = AutoCheckStatus.WARNING;
                }
                else
                {
                    p9_status = AutoCheckStatus.FAIL;
                }
                p9_value = reorderBeamParam(p9_value, ",");
            }

            p9_value_detailed = reorderBeamParam(p9_value_detailed, "\r\n\r\n");
            checklistItems.Add(new ChecklistItem("P9. Fälten ser rimliga ut vad gäller form, energi, MU och korrektion av artefakter", "Kontrollera att fälten ser rimliga ut vad gäller form, energi, MU och korrektion av artefakter\r\n  • Riktlinje för RapidArc är max 300 MU/Gy om bländarna är utanför target under hela varvet (sett ur BEV). Vid delvis skärmat target är denna gräns max 550 MU/Gy.\r\n  • Öppna fält ska ha ≥10 MU och fält med fast kil (Elekta) ska ha ≥30 kilade MU.\r\n  •  För Elekta gäller dessutom att totala antalet MU per fält (öppet + kilat) ej får överstiga 999 MU.", p9_value, p9_value_detailed, p9_status));

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta)
            {
                AutoCheckStatus p10_status = AutoCheckStatus.UNKNOWN;
                string          p10_value  = ElektaMLCCheck(planSetup);
                p10_status = CheckResult(String.Compare(p10_value, "MLC positioner OK.", true) == 0);
                checklistItems.Add(new ChecklistItem("P10. MLC:n är indragen till X-bländare, och ett/två blad är öppna utanför Y-bländare", "Kontrollera att MLC:n är indragen till X-bländare eller innanför, och att ett helt bladpar är öppet utanför Y-bländare på resp. sida om Y1 resp. Y2 har decimal 0,7, 0,8 eller 0,9.", p10_value, p10_status));
            }

            string          p11_value     = "Metod: " + planSetup.PlanNormalizationMethod + ", target: " + planSetup.TargetVolumeID + ", prescribed percentage: " + (planSetup.PrescribedPercentage * 100.0).ToString("0.0") + ", värde: " + planSetup.PlanNormalizationValue.ToString("0.0");
            AutoCheckStatus p11_status    = AutoCheckStatus.MANUAL;
            double          normLimitVMAT = 3.0;

            if (checklistType == ChecklistType.EclipseVMAT && Math.Abs(planSetup.PlanNormalizationValue - 100) > normLimitVMAT)
            {
                p11_status = AutoCheckStatus.FAIL;
            }
            checklistItems.Add(new ChecklistItem("P11. Normering är korrekt", "Kontrollera att planen är normerad på korrekt vis \r\n  • Normalt till targetvolymens medeldos (om särskilt skäl föreligger kan en punktnormering användas). \r\n  • För stereotaktiska lungor i Eclipse normeras dosen till isocenter och ordineras till 75%-isodosen.\r\n  • För VMAT ska Plan Normalization Value skall normeringsvärdet vara i intervallet [0.970, 1.030].", p11_value, p11_status));

            string                p12_value               = string.Empty;
            string                p13_value               = string.Empty;
            string                p13_value_detailed      = string.Empty;
            AutoCheckStatus       p13_status              = AutoCheckStatus.WARNING;
            List <ReferencePoint> referencePoints         = new List <ReferencePoint>();
            List <double>         referencePointDose      = new List <double>();
            List <double>         referencePointTotalDose = new List <double>();
            List <int>            activeReferencePoints   = new List <int>();

            // Get dose to reference points in active course
            foreach (PlanSetup planSetupInCourse in course.PlanSetups)
            {
                if (planSetupInCourse.ApprovalStatus != PlanSetupApprovalStatus.UnApproved && planSetupInCourse.ApprovalStatus != PlanSetupApprovalStatus.Rejected)
                {
                    foreach (Beam beam in planSetupInCourse.Beams)
                    {
                        foreach (FieldReferencePoint fieldReferencePoint in beam.FieldReferencePoints)
                        {
                            int referencePointIndex = -1;
                            for (int refPointNr = 0; refPointNr < referencePoints.Count; refPointNr++)
                            {
                                if (string.Compare(fieldReferencePoint.ReferencePoint.Id, referencePoints[refPointNr].Id) == 0)
                                {
                                    referencePointIndex = refPointNr;
                                    break;
                                }
                            }
                            if (referencePointIndex == -1)
                            {
                                referencePointIndex = referencePoints.Count;
                                referencePoints.Add(fieldReferencePoint.ReferencePoint);
                                referencePointDose.Add(0.0);
                                referencePointTotalDose.Add(0.0);
                            }
                            referencePointTotalDose[referencePointIndex] += fieldReferencePoint.FieldDose.Dose * (planSetupInCourse.UniqueFractionation == null ? double.NaN : (double)planSetupInCourse.UniqueFractionation.NumberOfFractions);
                            if (planSetupInCourse == planSetup)
                            {
                                referencePointDose[referencePointIndex] += fieldReferencePoint.FieldDose.Dose;
                                if (activeReferencePoints.Contains(referencePointIndex) == false)
                                {
                                    activeReferencePoints.Add(referencePointIndex);
                                }
                            }
                        }
                    }
                }
            }
            int p13_numberOfPass = 0;

            for (int refPointNr = 0; refPointNr < referencePoints.Count; refPointNr++)
            {
                p13_value_detailed += (p13_value_detailed.Length == 0 ? string.Empty : "\r\n\r\n") + referencePoints[refPointNr].Id + ":\r\n";

                double totalDoseLimit   = double.NaN;
                double dailyDoseLimit   = double.NaN;
                double sessionDoseLimit = double.NaN;

                DataTable dataTableRefPointLimits = AriaInterface.Query("select distinct RefPoint.RefPointId,RefPoint.TotalDoseLimit,RefPoint.DailyDoseLimit,RefPoint.SessionDoseLimit from PlanSetup,Radiation,RadiationRefPoint,RefPoint where RadiationRefPoint.RefPointSer=RefPoint.RefPointSer and RadiationRefPoint.RadiationSer=Radiation.RadiationSer and PlanSetup.PlanSetupSer=Radiation.PlanSetupSer and PlanSetup.CourseSer=" + courseSer.ToString() + " and RefPoint.RefPointId='" + referencePoints[refPointNr].Id + "'");
                if (dataTableRefPointLimits.Rows.Count == 1)
                {
                    totalDoseLimit   = (dataTableRefPointLimits.Rows[0][1] == DBNull.Value ? totalDoseLimit = double.NaN : totalDoseLimit = (double)dataTableRefPointLimits.Rows[0][1]);
                    dailyDoseLimit   = (dataTableRefPointLimits.Rows[0][2] == DBNull.Value ? dailyDoseLimit = double.NaN : dailyDoseLimit = (double)dataTableRefPointLimits.Rows[0][2]);
                    sessionDoseLimit = (dataTableRefPointLimits.Rows[0][3] == DBNull.Value ? sessionDoseLimit = double.NaN : sessionDoseLimit = (double)dataTableRefPointLimits.Rows[0][3]);
                }
                p13_value_detailed += "  Dosbidrag från aktuell plan: " + (fractionation == null ? double.NaN : referencePointDose[refPointNr] * (double)fractionation.NumberOfFractions).ToString("0.000") + " Gy, " + referencePointDose[refPointNr].ToString("0.000") + " Gy/fr " + " (Total dose limit: " + totalDoseLimit.ToString("0.000") + " Gy, daily limit: " + dailyDoseLimit.ToString("0.000") + " Gy, session limit: " + sessionDoseLimit.ToString("0.000") + " Gy)\r\n";
                p13_value_detailed += "  Totalt dosbidrag från samtliga godkändaplaner: " + referencePointTotalDose[refPointNr].ToString("0.000") + " Gy " + " (Total limit: " + totalDoseLimit.ToString("0.000") + " Gy)";

                if (activeReferencePoints.Contains(refPointNr)) // Reference point is present in the active plan
                {
                    p12_value += (p12_value.Length == 0 ? string.Empty : ", ") + referencePoints[refPointNr].Id + ": " + referencePointDose[refPointNr].ToString("0.000") + " Gy";
                    p13_value += (p13_value.Length == 0 ? string.Empty : ", ") + referencePoints[refPointNr].Id + ": (T:" + totalDoseLimit.ToString("0.000") + "/D:" + dailyDoseLimit.ToString("0.000") + "/S:" + sessionDoseLimit.ToString("0.000") + " Gy)";

                    if (Math.Round(referencePointDose[refPointNr], 3) <= Math.Round(dailyDoseLimit, 3) &&
                        Math.Round(referencePointDose[refPointNr], 3) <= Math.Round(sessionDoseLimit, 3) &&
                        Math.Round(referencePointTotalDose[refPointNr], 3) == Math.Round(totalDoseLimit, 3))
                    {
                        p13_numberOfPass++;
                    }
                }
            }
            if (activeReferencePoints.Count > 0 && p13_numberOfPass == activeReferencePoints.Count)
            {
                p13_status = AutoCheckStatus.UNKNOWN;
            }
            checklistItems.Add(new ChecklistItem("P12. Referenspunkternas dosbidrag är korrekta", "Kontrollera att dosbidrag till referenspunkter (dos) är korrekta:\r\n  • Varje plan ska ha en punkt (primary reference point) som summerar upp till ordinerad dos för det största PTV som planen primärt behandlar.\r\n  • Om flera planer bidrar med dos till samma targetvolymer eller om en plan bidrar med dos till flera targetvolymer ska det finnas referenspunkter utan lokalisation i alla planer som summerar dosen till dessa volymer.\r\n  • Referenspunkterna ska inte ha dosbidrag från tidigare behandlingar.", p12_value, AutoCheckStatus.MANUAL));
            checklistItems.Add(new ChecklistItem("P13. Referenspunkternas gränser är korrekta", "Kontrollera att referenspunkternas gränser (dos) är korrekta", p13_value, p13_value_detailed, p13_status));

            if (checklistType == ChecklistType.Eclipse || checklistType == ChecklistType.EclipseGating)
            {
                checklistItems.Add(new ChecklistItem("P14. Skarven är flyttad korrekt för skarvplan", "Skarvplaner: Skarven är flyttad korrekt och fälten är i övrigt likadana\r\n  • Bröstbehandlingar med kollimator i 0° för både huvudfält i fossa- och tang.-fält flyttas endast om eventuellt PTV_66 ligger i skarven.", string.Empty, AutoCheckStatus.MANUAL));
            }


            AutoCheckStatus p15_status       = AutoCheckStatus.UNKNOWN;
            string          p15_value        = string.Empty;
            int             p15_numberOfPass = 0;
            List <string>   machineId        = new List <string>();

            foreach (Beam beam in planSetup.Beams)
            {
                machineId.Add(beam.TreatmentUnit.Id);
                if (String.Equals(beam.TreatmentUnit.ToString(), planSetup.Beams.First().TreatmentUnit.ToString()))
                {
                    p15_numberOfPass += 1;
                }
                p15_value += (p15_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + beam.TreatmentUnit.Id;
            }
            if (p15_numberOfPass == numberOfBeams)
            {
                p15_status = AutoCheckStatus.PASS;
            }
            else
            {
                p15_status = AutoCheckStatus.FAIL;
            }
            p15_value = reorderBeamParam(p15_value, ",");
            checklistItems.Add(new ChecklistItem("P15. Konsekvent maskinval", "Kontrollera att samtliga fält är planerade till en och samma behandlingsapparat.", p15_value, p15_status));

            AutoCheckStatus p16_status           = AutoCheckStatus.UNKNOWN;
            string          p16_value            = string.Empty;
            string          p16_value_detailed   = "Följande bokningar är aktiva:\r\n";
            string          treatMachineIdCommon = machineId.ToArray().GroupBy(v => v)
                                                   .OrderByDescending(g => g.Count())
                                                   .First()
                                                   .Key;

            p16_value = "Planerat: " + treatMachineIdCommon + (machineId.Distinct().Count() == 1 ? " (enhetligt)" : " (tvetydigt)");
            DateTime      date                  = DateTime.Now;
            List <string> bookedMachineId       = new List <string>();
            string        bookedMachineIdCommon = string.Empty;
            //DataTable bookings = AriaInterface.Query("select x.MachineId, x.ScheduledStartTime from (SELECT DISTINCT Patient.PatientSer, Patient.PatientId, ScheduledActivity.ActualEndDate,ScheduledActivity.ScheduledActivityCode, ScheduledActivity.ActivityInstanceSer,Machine.MachineId,ScheduledActivity.ScheduledStartTime, ScheduledActivity.ObjectStatus FROM ScheduledActivity,Attendee,Patient,Machine WHERE Patient.PatientId = " + patient.Id.ToString() + " AND ScheduledActivity.ObjectStatus='Active' AND ScheduledActivity.ScheduledActivityCode = 'Open' AND ScheduledActivity.PatientSer=Patient.PatientSer AND Attendee.ActivityInstanceSer=ScheduledActivity.ActivityInstanceSer AND Machine.ResourceSer=Attendee.ResourceSer and ScheduledActivity.ScheduledStartTime > '" + date.ToString("yyyy-MM-dd") + " 00:00:00') as x where PatientId = '" + patient.Id.ToString() + "' ORDER BY ScheduledStartTime");
            DataTable bookings = AriaInterface.Query("SELECT DISTINCT Patient.PatientSer, Patient.PatientId, ScheduledActivity.ActualEndDate,ScheduledActivity.ScheduledActivityCode, ScheduledActivity.ActivityInstanceSer,Machine.MachineId,ScheduledActivity.ScheduledStartTime, ScheduledActivity.ObjectStatus FROM ScheduledActivity,Attendee,Patient,Machine WHERE Patient.PatientId = '" + patient.Id.ToString() + "' AND ScheduledActivity.ObjectStatus='Active' AND ScheduledActivity.ScheduledActivityCode = 'Open' AND ScheduledActivity.PatientSer=Patient.PatientSer AND Attendee.ActivityInstanceSer=ScheduledActivity.ActivityInstanceSer AND Attendee.ObjectStatus='Active' AND Machine.MachineType = 'RadiationDevice' AND Machine.ResourceSer=Attendee.ResourceSer and ScheduledActivity.ScheduledStartTime > '" + date.ToString("yyyy-MM-dd") + " 00:00:00' ORDER BY ScheduledStartTime");

            if (bookings.Rows.Count > 0)
            {
                foreach (DataRow row in bookings.Rows)
                {
                    bookedMachineId.Add((string)row["MachineId"]);
                    p16_value_detailed += (string)row["ScheduledStartTime"].ToString() + ": " + (string)row["MachineId"] + "\r\n";
                }
                bookedMachineIdCommon = bookedMachineId.ToArray().GroupBy(v => v)
                                        .OrderByDescending(g => g.Count())
                                        .First()
                                        .Key;
                p16_value += ", Bokat: " + bookedMachineIdCommon + (bookedMachineId.Distinct().Count() == 1 ? " (enhetligt)" : " (tvetydigt)");
                if (String.Equals(treatMachineIdCommon, bookedMachineIdCommon, StringComparison.OrdinalIgnoreCase) && bookedMachineId.Distinct().Count() == 1 && machineId.Distinct().Count() == 1)
                {
                    p16_status = AutoCheckStatus.PASS;
                }
                else if (String.Equals(treatMachineIdCommon, bookedMachineIdCommon, StringComparison.OrdinalIgnoreCase))
                {
                    p16_status = AutoCheckStatus.MANUAL;
                }
                else
                {
                    p16_status = AutoCheckStatus.FAIL;
                }
            }
            else
            {
                p16_value += ", Bokat: -";
                p16_status = AutoCheckStatus.WARNING;
            }

            checklistItems.Add(new ChecklistItem("P16. Konsekvens mellan planerad och bokad behandlingsapparat.", "Kontrollera att patienten är bokad till den behandlingsapparat som planen är planerad för.", p16_value, p16_value_detailed, p16_status));
        }
Example #7
0
        public void S()
        {
            checklistItems.Add(new ChecklistItem("S. Setup"));
            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          s1_value            = string.Empty;
                AutoCheckStatus s1_status           = AutoCheckStatus.FAIL;
                int             s1_numberOfPass     = 0;
                int             s1_numberOfWarnings = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    double    iduPosVrt          = double.NaN;
                    DataTable dataTableIDUPosVrt = AriaInterface.Query("select IDUPosVrt from Radiation,ExternalFieldCommon where ExternalFieldCommon.RadiationSer=Radiation.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");
                    if (dataTableIDUPosVrt.Rows.Count == 1 && dataTableIDUPosVrt.Rows[0][0] != DBNull.Value && !Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                    {
                        iduPosVrt = (double)dataTableIDUPosVrt.Rows[0][0];
                        if (iduPosVrt == -50)
                        {
                            s1_numberOfPass++;
                        }
                        else
                        {
                            s1_numberOfWarnings++;
                        }
                    }
                    else if (Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text)) // Field with Id Upplägg may have any ImageVrt Position, even undefined.
                    {
                        s1_numberOfPass++;
                    }
                    s1_value += (s1_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + (double.IsNaN(iduPosVrt) ? "-" : ((double)iduPosVrt).ToString("0.0") + " cm");
                }
                if (s1_numberOfPass == numberOfBeams)
                {
                    s1_status = AutoCheckStatus.PASS;
                }
                else if (s1_numberOfPass + s1_numberOfWarnings == numberOfBeams)
                {
                    s1_status = AutoCheckStatus.WARNING;
                }
                s1_value = reorderBeamParam(s1_value, ",");
                checklistItems.Add(new ChecklistItem("S1. Bildplattans vertikala position är -50 cm om inte särskilda skäl föreligger", "Kontrollera att bildplattans vertikala position är -50 cm om inte särskilda skäl föreligger", s1_value, s1_status));
            }

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta)
            {
                string          s2_value        = string.Empty;
                string          s2_value_detail = String.Empty;
                AutoCheckStatus s2_status       = AutoCheckStatus.PASS;
                //List<double> s2_gantryAngles = new List<double>();
                Dictionary <string, double> s2_gantryAngles = new Dictionary <string, double>();
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        s2_gantryAngles.Add(beam.Id, beam.ControlPoints[0].GantryAngle);
                        s2_value += (s2_value.Length == 0 ? "Sida: " + treatmentSide.ToString() + ", " : ", ") + beam.Id + ": " + beam.ControlPoints[0].GantryAngle.ToString("0.0");
                    }
                }
                if (treatmentSide == TreatmentSide.PlusX)
                {
                    bool fieldsOnOppositeSide = false;
                    foreach (KeyValuePair <string, double> entry in s2_gantryAngles)
                    {
                        if (entry.Value > 185 && entry.Value <= 290)
                        {
                            fieldsOnOppositeSide = true;
                        }
                    }
                    if (fieldsOnOppositeSide == false)
                    {
                        foreach (KeyValuePair <string, double> entry in s2_gantryAngles)
                        {
                            if (entry.Value <= 270 && entry.Value > 180 && checklistType != ChecklistType.EclipseVMAT) //added to ignore vmat to avoid error for elekta vmat
                            {
                                s2_status        = AutoCheckStatus.WARNING;
                                s2_value_detail += (s2_value_detail.Length == 0 ? String.Empty : "\r\n") + entry.Key + ": " + entry.Value.ToString("0.0");
                            }
                        }
                    }
                }
                else
                {
                    bool fieldsOnOppositeSide = false;
                    foreach (KeyValuePair <string, double> entry in s2_gantryAngles)
                    {
                        if (entry.Value >= 70 && entry.Value < 175)
                        {
                            fieldsOnOppositeSide = true;
                        }
                    }
                    if (fieldsOnOppositeSide == false)
                    {
                        foreach (KeyValuePair <string, double> entry in s2_gantryAngles)
                        {
                            if (entry.Value >= 90 && entry.Value <= 180 && checklistType != ChecklistType.EclipseVMAT) //added to ignore vmat avoid error for elekta vmat
                            {
                                s2_status        = AutoCheckStatus.WARNING;
                                s2_value_detail += (s2_value_detail.Length == 0 ? String.Empty : "\r\n") + entry.Key + ": " + entry.Value.ToString("0.0");
                            }
                        }
                    }
                }
                s2_value = reorderBeamParam(s2_value, ",");
                if (s2_value_detail.Length > 0)
                {
                    s2_value_detail = reorderBeamParam(s2_value_detail, "\r\n");
                    s2_value_detail = "Gantryt kommer att rotera ofördelaktigt för att nå följande fält\r\n" + s2_value_detail;
                    checklistItems.Add(new ChecklistItem("S2. Fördelaktiga gantryvinklar har valts.", "Kontrollera att fördelaktiga gantryvinklar har valts med avsseende på rotationsriktning för fält nära 180°. Om det finns fält som går över långt på motstående sida (70° resp. 290°) ges inga rekommendationer. I annat fall gäller rekommendationen:\r\n  • Vänstersidiga behandlingar: Fält med 180<gantryvinkel<=270 undanbedes\r\n  • Högersidiga behandlingar: Fält med 90<=gantryvinkel<=180 undanbedes\r\n  • Notera att det omvända förhållandet mellan behandlingssida och fält gäller om patienten är orienterad Feet First (fötterna mot gantryt)", s2_value, s2_value_detail, s2_status));
                }
                else
                {
                    checklistItems.Add(new ChecklistItem("S2. Fördelaktiga gantryvinklar har valts.", "Kontrollera att fördelaktiga gantryvinklar har valts med avsseende på rotationsriktning för fält nära 180°. Om det finns fält som går över långt på motstående sida (70° resp. 290°) ges inga rekommendationer. I annat fall gäller rekommendationen:\r\n  • Vänstersidiga behandlingar: Fält med 180<gantryvinkel<=270 undanbedes\r\n  • Högersidiga behandlingar: Fält med 90<=gantryvinkel<=180 undanbedes\r\n  • Notera att det omvända förhållandet mellan behandlingssida och fält gäller om patienten är orienterad Feet First (fötterna mot gantryt)", s2_value, s2_status));
                }
            }

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          s2_value                = string.Empty;
                AutoCheckStatus s2_status               = AutoCheckStatus.FAIL;
                int             s2_numberOfPass         = 0;
                List <double>   s2_gantryAngles         = new List <double>();
                List <bool>     s2_gantryAnglesExtended = new List <bool>();
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        DataTable dataTableExtended = AriaInterface.Query("select GantryRtnExt from ExternalField,Radiation where GantryRtnExt='EN' and ExternalField.RadiationSer=Radiation.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");
                        bool      extended          = (dataTableExtended.Rows.Count == 1);
                        s2_gantryAnglesExtended.Add(extended);
                        s2_gantryAngles.Add(beam.ControlPoints[0].GantryAngle);
                        s2_value += (s2_value.Length == 0 ? "Sida: " + treatmentSide.ToString() + ", " : ", ") + beam.Id + ": " + beam.ControlPoints[0].GantryAngle.ToString("0.0") + (extended ? "E" : string.Empty);
                    }
                }
                if (checklistType == ChecklistType.EclipseVMAT)
                {
                    foreach (bool extended in s2_gantryAnglesExtended)
                    {
                        if (!extended)
                        {
                            s2_numberOfPass++;
                        }
                    }
                }
                else if (treatmentSide == TreatmentSide.PlusX)
                {
                    bool fieldsOnOppositeSide = false;
                    foreach (double angle in s2_gantryAngles)
                    {
                        if (angle > 185 && angle <= 290)
                        {
                            fieldsOnOppositeSide = true;
                        }
                    }
                    for (int beamNr = 0; beamNr < s2_gantryAngles.Count; beamNr++)
                    {
                        if (fieldsOnOppositeSide)
                        {
                            if (s2_gantryAnglesExtended[beamNr] == false)
                            {
                                s2_numberOfPass++;
                            }
                        }
                        else
                        {
                            if (s2_gantryAngles[beamNr] > 180 && s2_gantryAngles[beamNr] <= 185)
                            {
                                if (s2_gantryAnglesExtended[beamNr] == true)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                            else
                            {
                                if (s2_gantryAnglesExtended[beamNr] == false)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                        }
                    }
                }
                else
                {
                    bool fieldsOnOppositeSide = false;
                    foreach (double angle in s2_gantryAngles)
                    {
                        if (angle >= 70 && angle < 175)
                        {
                            fieldsOnOppositeSide = true;
                        }
                    }
                    for (int beamNr = 0; beamNr < s2_gantryAngles.Count; beamNr++)
                    {
                        if (fieldsOnOppositeSide)
                        {
                            if (s2_gantryAnglesExtended[beamNr] == false)
                            {
                                s2_numberOfPass++;
                            }
                        }
                        else
                        {
                            if (s2_gantryAngles[beamNr] >= 175 && s2_gantryAngles[beamNr] <= 180)
                            {
                                if (s2_gantryAnglesExtended[beamNr] == true)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                            else
                            {
                                if (s2_gantryAnglesExtended[beamNr] == false)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                        }
                    }
                }
                if (s2_numberOfPass == numberOfTreatmentBeams)
                {
                    s2_status = AutoCheckStatus.PASS;
                }
                s2_value = reorderBeamParam(s2_value, ",");
                checklistItems.Add(new ChecklistItem("S2. Extended har valts korrekt på behandlingsfält", "Kontrollera att Extended har valts korrekt på behandlingsfält. Om det finns fält som går över långt på motstående sida (70° resp. 290°) ska inga fält ha Extended. I annat fall gäller:\r\n  • Vänstersidiga behandlingar: Fält med 180<gantryvinkel<=185 ska ha Extended\r\n  • Högersidiga behandlingar: Fält med 175<=gantryvinkel<=180 ska ha Extended\r\n  • Övriga fält ska ej ha Extended\r\n  • Notera att det omvända förhållandet mellan behandlingssida och fält som ska ha Extended gäller om patienten är orienterad Feet First (fötterna mot gantryt)", s2_value, s2_status));
            }

            string          s3_value                 = string.Empty;
            AutoCheckStatus s3_status                = AutoCheckStatus.UNKNOWN;
            List <double>   s3_setupFieldAngles      = new List <double>();
            List <double>   s4_setupFieldCouchAngles = new List <double>();
            List <double>   s4_FieldCouchAngles      = new List <double>();
            List <string>   s3_beamIds               = new List <string>();

            foreach (Beam beam in planSetup.Beams)
            {
                if (beam.IsSetupField && !Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                {
                    s3_setupFieldAngles.Add(beam.ControlPoints[0].GantryAngle);
                    s4_setupFieldCouchAngles.Add(beam.ControlPoints[0].PatientSupportAngle);
                    s3_beamIds.Add(beam.Id.ToLower());
                    s3_value += (s3_value.Length == 0 ? "Sida: " + treatmentSide.ToString() + ", " : ", ") + beam.Id + ": " + beam.ControlPoints[0].GantryAngle.ToString("0.0");
                }
                else if (!beam.IsSetupField)
                {
                    s4_FieldCouchAngles.Add(beam.ControlPoints[0].PatientSupportAngle);
                }
            }
            int s3_cbctIndex = s3_beamIds.IndexOf("cbct");

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                if (s3_setupFieldAngles.Count == 0)
                {
                    s3_value = "Setupfält saknas i planen";
                }
                else if (s3_setupFieldAngles.Count == 1 && s3_cbctIndex == 0)
                {
                    s3_status = AutoCheckStatus.PASS;
                }
                else if (s3_setupFieldAngles.Count == 3)
                {
                    // Ta bort CBCT från fortsatta kontrollen
                    if (s3_cbctIndex != -1)
                    {
                        s3_beamIds.RemoveAt(s3_cbctIndex);
                        s3_setupFieldAngles.RemoveAt(s3_cbctIndex);
                    }
                }
                if (s3_setupFieldAngles.Count == 2)
                {
                    if (treatmentSide == TreatmentSide.PlusX) // Vänstersidig
                    {
                        if (s3_setupFieldAngles.IndexOf(0) != -1 && s3_setupFieldAngles.IndexOf(270) != -1)
                        {
                            s3_status = AutoCheckStatus.PASS;
                        }
                        else
                        {
                            s3_status = AutoCheckStatus.FAIL;
                        }
                    }
                    else // Högersidig
                    {
                        if (s3_setupFieldAngles.IndexOf(180) != -1 && s3_setupFieldAngles.IndexOf(270) != -1)
                        {
                            s3_status = AutoCheckStatus.PASS;
                        }
                        else
                        {
                            s3_status = AutoCheckStatus.FAIL;
                        }
                    }
                }
            }
            else
            {
                s3_status = AutoCheckStatus.MANUAL; // If not Varian, then do manual check of setup angles.
            }
            s3_value = reorderBeamParam(s3_value, ",");
            checklistItems.Add(new ChecklistItem("S3. Gantryvinklar för setupfälten är korrekta", "Kontrollera att setupfältens gantryvinklar är korrekta (patientgeometrin avgör vinklar)\r\n  • Standard: 270° respektive 0°\r\n•  • Högersidiga behandlingar: 180° respektive 270°", s3_value, s3_status));

            string          s4_value  = string.Empty;
            AutoCheckStatus s4_status = AutoCheckStatus.MANUAL;

            if (s4_setupFieldCouchAngles.Count == 0)
            {
                s4_value = "Setupfält saknas i planen";
            }
            else
            {
                for (int i = 0; i < s4_setupFieldCouchAngles.Count; i++)
                {
                    if (s4_setupFieldCouchAngles[i] != 0)
                    {
                        s4_value += (s4_value.Length == 0 ? "Setupfält har följande vinklar: " : ", ") + s3_beamIds[i] + ": " + s4_setupFieldCouchAngles[i].ToString("0.0");
                        s4_status = AutoCheckStatus.WARNING;
                    }
                }

                s4_value = reorderBeamParam(s4_value, ",");
                //Gives manual if sum of all setupfields are 0 but tx fields are different. Gives auto OK if ALL fields have tableangle 0;
                if (s4_setupFieldCouchAngles.Sum() == 0 && s4_FieldCouchAngles.Sum() != 0)
                {
                    s4_status = AutoCheckStatus.MANUAL;
                    s4_value  = "Alla setupfält har golvvinkel 0°, behandlingsfält har ej golvvinkel 0°";
                }
                if (s4_setupFieldCouchAngles.Sum() == 0 && s4_FieldCouchAngles.Sum() == 0)
                {
                    s4_status = AutoCheckStatus.PASS;
                    s4_value  = "Alla setupfält och behandlingsfält har golvvinkel 0°";
                }
            }

            checklistItems.Add(new ChecklistItem("S4. Golvvinklar för setupfälten är korrekta", "Kontrollera att setupfältens golvvinklar är korrekta. Om ej särskilda anledningar föreligger ska golvvinkel för samtliga setupfält vara 0°", s4_value, s4_status));

            string          s5_value;
            AutoCheckStatus s5_status         = AutoCheckStatus.FAIL;
            string          s5_value_detailed = string.Empty;
            int             s5_numberOfPass   = 0;
            bool            s5_isocenterCouldNotBeDetermined = false;
            VVector         s5_isocenterPosition             = new VVector(double.NaN, double.NaN, double.NaN);
            List <VVector>  allIsoPos = new List <VVector>();

            foreach (Beam beam in planSetup.Beams)
            {
                double allowedDiff = 0.0;  // the allowed difference between isocenters in mm
                if (double.IsNaN(s5_isocenterPosition.x) && double.IsNaN(s5_isocenterPosition.y) && double.IsNaN(s5_isocenterPosition.z))
                {
                    s5_isocenterPosition = beam.IsocenterPosition;
                    allIsoPos.Add(s5_isocenterPosition);
                    if (double.IsNaN(beam.IsocenterPosition.x) == false && double.IsNaN(beam.IsocenterPosition.y) == false && double.IsNaN(beam.IsocenterPosition.z) == false)
                    {
                        s5_numberOfPass++;
                    }
                    else
                    {
                        s5_isocenterCouldNotBeDetermined = true;
                    }
                }

                //else if (Math.Round(s5_isocenterPosition.x, 1) == Math.Round(beam.IsocenterPosition.x, 1) && Math.Round(s5_isocenterPosition.y, 1) == Math.Round(beam.IsocenterPosition.y, 1) && Math.Round(s5_isocenterPosition.z, 1) == Math.Round(beam.IsocenterPosition.z, 1))
                else if (Math.Abs(s5_isocenterPosition.x - beam.IsocenterPosition.x) <= allowedDiff && Math.Abs(s5_isocenterPosition.y - beam.IsocenterPosition.y) <= allowedDiff && Math.Abs(s5_isocenterPosition.z - beam.IsocenterPosition.z) <= allowedDiff)
                {
                    s5_numberOfPass++;
                    allIsoPos.Add(beam.IsocenterPosition);
                }
                else
                {
                    allIsoPos.Add(beam.IsocenterPosition);
                }
            }

            if (s5_numberOfPass == numberOfBeams)//numberOfTreatmentBeams)
            {
                s5_value  = "Samma isocenter";
                s5_status = AutoCheckStatus.PASS;
            }
            else if (s5_isocenterCouldNotBeDetermined)
            {
                s5_value  = "Isocenterposition kunde ej bestämmas";
                s5_status = AutoCheckStatus.WARNING;
            }
            else
            {
                s5_value = "Olika isocenter mellan fälten";
                // Generates value-string with information of the two isocenters.
                int     i          = 0;
                string  nameIso1   = "Iso 1: ";
                string  nameIso2   = "Iso 2: ";
                VVector storedIso1 = new VVector(double.NaN, double.NaN, double.NaN);
                VVector storedIso2 = new VVector(double.NaN, double.NaN, double.NaN);
                if (allIsoPos.Distinct().Count() == 2)
                {
                    foreach (VVector v in allIsoPos)
                    {
                        if (v.x == s5_isocenterPosition.x && v.y == s5_isocenterPosition.y && v.z == s5_isocenterPosition.z)
                        {
                            nameIso1 += planSetup.Beams.ElementAt(i).Id + ", ";

                            storedIso1 = planSetup.Beams.ElementAt(i).IsocenterPosition - image.UserOrigin;
                        }
                        else
                        {
                            nameIso2  += planSetup.Beams.ElementAt(i).Id + ", ";
                            storedIso2 = planSetup.Beams.ElementAt(i).IsocenterPosition - image.UserOrigin;
                        }
                        s5_value_detailed += "Fält " + planSetup.Beams.ElementAt(i).Id + ": \r\nX: " + 0.1 * (planSetup.Beams.ElementAt(i).IsocenterPosition.x - image.UserOrigin.x) + " , Y: " + 0.1 * (planSetup.Beams.ElementAt(i).IsocenterPosition.z - image.UserOrigin.z) + " , Z: " + -0.1 * (planSetup.Beams.ElementAt(i).IsocenterPosition.y - image.UserOrigin.y) + ". \r\n";
                        i++;
                    }
                    s5_value = "Olika isocenter mellan fälten: " + nameIso1 + " X:" + 0.1 * storedIso1.x + " Y:" + 0.1 * storedIso1.z + " Z:" + -0.1 * storedIso1.y + " \n " + nameIso2 + " X:" + 0.1 * storedIso2.x + " Y:" + 0.1 * storedIso2.z + " Z:" + -0.1 * storedIso2.y;
                }
                else
                {
                    int j = 0;
                    s5_value          = "Minst tre isocenter mellan fälten. Vänligen korrigera: ";
                    s5_value_detailed = "Olika isocenter mellan fälten. Vänligen korrigera: \r\n";
                    foreach (VVector v in allIsoPos)
                    {
                        s5_value_detailed += "Fält " + planSetup.Beams.ElementAt(j).Id + ": \r\nX: " + 0.1 * (planSetup.Beams.ElementAt(j).IsocenterPosition.x - image.UserOrigin.x) + " , Y: " + 0.1 * (planSetup.Beams.ElementAt(j).IsocenterPosition.z - image.UserOrigin.z) + " , Z: " + -0.1 * (planSetup.Beams.ElementAt(j).IsocenterPosition.y - image.UserOrigin.y) + ". \r\n";
                        j++;
                    }
                }
                s5_status = AutoCheckStatus.WARNING;
            }

            checklistItems.Add(new ChecklistItem("S5. Alla fält har samma isocenter vid isocentrisk teknik", "Kontrollera att samtliga fälts (inklusive setup-fält) Isocenter sammanfaller.", s5_value, s5_value_detailed, s5_status));

            string s6_value = string.Empty;

            foreach (Beam beam in planSetup.Beams)
            {
                if (Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text) == false)
                {
                    DataTable DRRSetting = AriaInterface.Query("select distinct SliceRT.AcqNote from Radiation, PlanSetup, SliceRT, Slice, Image where  PlanSetup.PlanSetupSer =" + planSetupSer.ToString() + " and Radiation.RadiationId ='" + beam.Id + "' and PlanSetup.PlanSetupSer = Radiation.PlanSetupSer and SliceRT.RadiationSer = Radiation.RadiationSer and SliceRT.SliceSer = Slice.SliceSer and SliceRT.AcqNote like 'MultiWindow%'");
                    if (DRRSetting.Rows.Count == 1 && DRRSetting.Rows[0][0] != DBNull.Value)
                    {
                        // split file path
                        s6_value += (s6_value.Length == 0 ? "" : ", ") + beam.Id + ": " + QueryContents.FindInFiles((string)DRRSetting.Rows[0][0]);//(string)DRRSetting.Rows[0][0];
                    }
                }
            }
            s6_value = reorderBeamParam(s6_value, ",");
            checklistItems.Add(new ChecklistItem("S6. Kvalitén på DRR", "Kontrollera att kvalitén på DRR för alla fält som ska ha en DRR är acceptabel.", s6_value, AutoCheckStatus.MANUAL));

            string          s7_value      = string.Empty;
            AutoCheckStatus s7_status     = AutoCheckStatus.MANUAL;
            List <string>   s7_tolerances = new List <string>();

            foreach (Beam beam in planSetup.Beams)
            {
                string    toleranceId      = string.Empty;
                DataTable toleranceIdTable = AriaInterface.Query("select Tolerance.ToleranceId from Radiation,ExternalFieldCommon,Tolerance where ExternalFieldCommon.RadiationSer=Radiation.RadiationSer and ExternalFieldCommon.ToleranceSer=Tolerance.ToleranceSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");
                if (toleranceIdTable.Rows.Count == 1 && toleranceIdTable.Rows[0][0] != DBNull.Value)
                {
                    s7_tolerances.Add((string)toleranceIdTable.Rows[0][0]);
                }
                else
                {
                    s7_tolerances.Add("Saknas");
                }
            }
            string[] uniqueTolerances = s7_tolerances.Distinct().ToArray();
            if (uniqueTolerances.Length == 1 && String.Equals(s7_tolerances[0], "Saknas", StringComparison.OrdinalIgnoreCase) == false)
            {
                s7_value = s7_tolerances[0];
            }
            else if (uniqueTolerances.Length == 1 && String.Equals(s7_tolerances[0], "Saknas", StringComparison.OrdinalIgnoreCase) == false)
            {
                s7_value  = s7_tolerances[0];
                s7_status = AutoCheckStatus.FAIL;
            }
            else
            {
                foreach (string tolerance in uniqueTolerances)
                {
                    s7_value += (s7_value.Length == 0 ? string.Empty : ", ") + tolerance;
                }
                s7_status = AutoCheckStatus.FAIL;
            }
            checklistItems.Add(new ChecklistItem("S7. Toleranstabell har valts korrekt", "Kontrollera att korrekt toleranstabell har använts, baserat på maskintyp (Elekta/Varian), strålkvalité (elektroner/fotoner), nätmask (H&N fix), annan fixation som sitter fast i britsen (fast fix) eller icke fast fixation (utan fix).", s7_value, s7_status));

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          s8_value               = string.Empty;
                string          s8_value_detailed      = string.Empty;
                AutoCheckStatus s8_status              = AutoCheckStatus.MANUAL;
                List <string>   s8_imageModalityBeam   = new List <string>();
                List <int>      s8_imageModalityBeamNr = new List <int>();
                List <string>   s8_beamId              = new List <string>();
                foreach (Beam beam in planSetup.Beams)
                {
                    if (beam.IsSetupField && !Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                    {
                        List <string> protocolIds = new List <string>();

                        s8_value_detailed += (s8_value_detailed.Length == 0 ? string.Empty : "\r\n\r\n") + beam.Id + ": ";
                        s8_value           = string.Empty;
                        DataTable dataTableImageSessions = AriaInterface.Query("select Session.SessionNum,SessionProcedure.SessionProcedureTemplateId from SessionProcedurePart,SessionProcedure,Session,Radiation where SessionProcedurePart.RadiationSer=Radiation.RadiationSer and SessionProcedure.SessionProcedureSer=SessionProcedurePart.SessionProcedureSer and Session.SessionSer=SessionProcedure.SessionSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "' order by SessionNum");
                        foreach (DataRow dataRow in dataTableImageSessions.Rows)
                        {
                            int    sessionNr           = (int)dataRow[0];
                            string procedureTemplateId = (dataRow[1] == DBNull.Value ? "-" : (string)dataRow[1]);
                            s8_value_detailed += "\r\n  Session " + sessionNr.ToString() + ": " + procedureTemplateId;
                            protocolIds.Add(procedureTemplateId);
                        }

                        s8_beamId.Add(beam.Id);
                        string[] uniqueprotocolIds = protocolIds.Distinct().ToArray();
                        if (uniqueprotocolIds.Length == 0)
                        {
                            s8_imageModalityBeam.Add("Ingen");
                            s8_status = AutoCheckStatus.FAIL;
                        }
                        else if (uniqueprotocolIds.Length == 1)
                        {
                            s8_imageModalityBeam.Add(uniqueprotocolIds[0]);
                        }
                        else
                        {
                            s8_imageModalityBeam.Add("Flera");
                            s8_status = AutoCheckStatus.FAIL;
                        }
                        if (fractionation != null && fractionation.NumberOfFractions != protocolIds.Count)
                        {
                            s8_status = AutoCheckStatus.FAIL;
                        }
                        s8_imageModalityBeamNr.Add(protocolIds.Count);
                    }
                }
                for (int beamNr = 0; beamNr < s8_imageModalityBeam.Count; beamNr++)
                {
                    s8_value += (s8_value.Length == 0 ? string.Empty : ", ") + s8_beamId[beamNr] + ": " + s8_imageModalityBeam[beamNr] + " (" + s8_imageModalityBeamNr[beamNr].ToString() + " fr)";
                }
                checklistItems.Add(new ChecklistItem("S8. Bildtagningsmodalitet är korrekt", "Kontrollera att bildtagning är korrekt\r\nVarian:\r\n  • Korrekt bildtagningsmodalitet är inlagd, samt att bildtagning är aktiverad för alla sessioner på setup-fälten\r\n  • Se bilaga 4 i dokumentet ”Verifikationsbilder”\r\nElekta:\r\n  • Inga setup-fält på tangentiella bröstbehandlingar\r\n  • Inga setup-fält på L09, L07 och L05 (XVI används i första hand för icke-laterala behandlingar)\r\n  • På L03 tas bilder med behandlingsfält om de finns i 0/180° och 90/270°, annars ska det finnas setup-fält", s8_value, s8_value_detailed, s8_status));
            }

            string          s9_value  = "Saknas";
            AutoCheckStatus s9_status = AutoCheckStatus.FAIL;

            foreach (Beam beam in planSetup.Beams)
            {
                if (beam.IsSetupField && Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                {
                    s9_status = AutoCheckStatus.PASS;
                    s9_value  = "Existerar";
                    break;
                }
            }
            checklistItems.Add(new ChecklistItem("S9. Uppläggsfält existerar i planen", "Kontrollera att det finns ett fält med Id Upplägg i behandlingsplanen", s9_value, s9_status));

            checklistItems.Add(new ChecklistItem("S10. Uppläggningen är genomförbar", "Kontrollera att uppläggningen är genomförbar för den givna geometrin \r\n  • Exempelvis att behandlingar av extremt kaudala target inte är orienterade 'Head First'", "", AutoCheckStatus.MANUAL));
        }
Example #8
0
 public ChecklistItem(string shortInfo, string detailedInfo, string shortResult, AutoCheckStatus autoCheckStatus)
     : this(shortInfo, detailedInfo, shortResult, null, autoCheckStatus)
 {
 }
Example #9
0
        public void S()
        {
            checklistItems.Add(new ChecklistItem("S. Setup"));
            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          s1_value            = string.Empty;
                AutoCheckStatus s1_status           = AutoCheckStatus.FAIL;
                int             s1_numberOfPass     = 0;
                int             s1_numberOfWarnings = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    double    iduPosVrt          = double.NaN;
                    DataTable dataTableIDUPosVrt = AriaInterface.Query("select IDUPosVrt from Radiation,ExternalFieldCommon where ExternalFieldCommon.RadiationSer=Radiation.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");
                    if (dataTableIDUPosVrt.Rows.Count == 1 && dataTableIDUPosVrt.Rows[0][0] != DBNull.Value && !Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                    {
                        iduPosVrt = (double)dataTableIDUPosVrt.Rows[0][0];
                        if (iduPosVrt == -50)
                        {
                            s1_numberOfPass++;
                        }
                        else
                        {
                            s1_numberOfWarnings++;
                        }
                    }
                    else if (Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text)) // Field with Id Upplägg may have any ImageVrt Position, even undefined.
                    {
                        s1_numberOfPass++;
                    }
                    s1_value += (s1_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + (double.IsNaN(iduPosVrt) ? "-" : ((double)iduPosVrt).ToString("0.0") + " cm");
                }
                if (s1_numberOfPass == numberOfBeams)
                {
                    s1_status = AutoCheckStatus.PASS;
                }
                else if (s1_numberOfPass + s1_numberOfWarnings == numberOfBeams)
                {
                    s1_status = AutoCheckStatus.WARNING;
                }
                s1_value = reorderBeamParam(s1_value, ",");
                checklistItems.Add(new ChecklistItem("S1. Bildplattans vertikala position är -50 cm om inte särskilda skäl föreligger", "Kontrollera att bildplattans vertikala position är -50 cm om inte särskilda skäl föreligger", s1_value, s1_status));
            }

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          s2_value                = string.Empty;
                AutoCheckStatus s2_status               = AutoCheckStatus.FAIL;
                int             s2_numberOfPass         = 0;
                List <double>   s2_gantryAngles         = new List <double>();
                List <bool>     s2_gantryAnglesExtended = new List <bool>();
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        DataTable dataTableExtended = AriaInterface.Query("select GantryRtnExt from ExternalField,Radiation where GantryRtnExt='EN' and ExternalField.RadiationSer=Radiation.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");
                        bool      extended          = (dataTableExtended.Rows.Count == 1);
                        s2_gantryAnglesExtended.Add(extended);
                        s2_gantryAngles.Add(beam.ControlPoints[0].GantryAngle);
                        s2_value += (s2_value.Length == 0 ? "Sida: " + treatmentSide.ToString() + ", " : ", ") + beam.Id + ": " + beam.ControlPoints[0].GantryAngle.ToString("0.0") + (extended ? "E" : string.Empty);
                    }
                }
                if (checklistType == ChecklistType.EclipseVMAT)
                {
                    foreach (bool extended in s2_gantryAnglesExtended)
                    {
                        if (!extended)
                        {
                            s2_numberOfPass++;
                        }
                    }
                }
                else if (treatmentSide == TreatmentSide.PlusX)
                {
                    bool fieldsOnOppositeSide = false;
                    foreach (double angle in s2_gantryAngles)
                    {
                        if (angle > 185 && angle <= 290)
                        {
                            fieldsOnOppositeSide = true;
                        }
                    }
                    for (int beamNr = 0; beamNr < s2_gantryAngles.Count; beamNr++)
                    {
                        if (fieldsOnOppositeSide)
                        {
                            if (s2_gantryAnglesExtended[beamNr] == false)
                            {
                                s2_numberOfPass++;
                            }
                        }
                        else
                        {
                            if (s2_gantryAngles[beamNr] > 180 && s2_gantryAngles[beamNr] <= 185)
                            {
                                if (s2_gantryAnglesExtended[beamNr] == true)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                            else
                            {
                                if (s2_gantryAnglesExtended[beamNr] == false)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                        }
                    }
                }
                else
                {
                    bool fieldsOnOppositeSide = false;
                    foreach (double angle in s2_gantryAngles)
                    {
                        if (angle >= 70 && angle < 175)
                        {
                            fieldsOnOppositeSide = true;
                        }
                    }
                    for (int beamNr = 0; beamNr < s2_gantryAngles.Count; beamNr++)
                    {
                        if (fieldsOnOppositeSide)
                        {
                            if (s2_gantryAnglesExtended[beamNr] == false)
                            {
                                s2_numberOfPass++;
                            }
                        }
                        else
                        {
                            if (s2_gantryAngles[beamNr] >= 175 && s2_gantryAngles[beamNr] <= 180)
                            {
                                if (s2_gantryAnglesExtended[beamNr] == true)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                            else
                            {
                                if (s2_gantryAnglesExtended[beamNr] == false)
                                {
                                    s2_numberOfPass++;
                                }
                            }
                        }
                    }
                }
                if (s2_numberOfPass == numberOfTreatmentBeams)
                {
                    s2_status = AutoCheckStatus.PASS;
                }
                s2_value = reorderBeamParam(s2_value, ",");
                checklistItems.Add(new ChecklistItem("S2. Extended har valts korrekt på behandlingsfält", "Kontrollera att Extended har valts korrekt på behandlingsfält. Om det finns fält som går över långt på motstående sida (70° resp. 290°) ska inga fält ha Extended. I annat fall gäller:\r\n  • Vänstersidiga behandlingar: Fält med 180<gantryvinkel<=185 ska ha Extended\r\n  • Högersidiga behandlingar: Fält med 175<=gantryvinkel<=180 ska ha Extended\r\n  • Övriga fält ska ej ha Extended", s2_value, s2_status));
            }

            string          s3_value            = string.Empty;
            AutoCheckStatus s3_status           = AutoCheckStatus.UNKNOWN;
            List <double>   s3_setupFieldAngles = new List <double>();
            List <string>   s3_beamIds          = new List <string>();

            foreach (Beam beam in planSetup.Beams)
            {
                if (beam.IsSetupField && !Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                {
                    s3_setupFieldAngles.Add(beam.ControlPoints[0].GantryAngle);
                    s3_beamIds.Add(beam.Id.ToLower());
                    s3_value += (s3_value.Length == 0 ? "Sida: " + treatmentSide.ToString() + ", " : ", ") + beam.Id + ": " + beam.ControlPoints[0].GantryAngle.ToString("0.0");
                }
            }
            int s3_cbctIndex = s3_beamIds.IndexOf("cbct");

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                if (s3_setupFieldAngles.Count == 0)
                {
                    s3_value = "Setupfält saknas i planen";
                }
                else if (s3_setupFieldAngles.Count == 1 && s3_cbctIndex == 0)
                {
                    s3_status = AutoCheckStatus.PASS;
                }
                else if (s3_setupFieldAngles.Count == 3)
                {
                    // Ta bort CBCT från fortsatta kontrollen
                    if (s3_cbctIndex != -1)
                    {
                        s3_beamIds.RemoveAt(s3_cbctIndex);
                        s3_setupFieldAngles.RemoveAt(s3_cbctIndex);
                    }
                }
                if (s3_setupFieldAngles.Count == 2)
                {
                    if (treatmentSide == TreatmentSide.PlusX) // Vänstersidig
                    {
                        if (s3_setupFieldAngles.IndexOf(0) != -1 && s3_setupFieldAngles.IndexOf(270) != -1)
                        {
                            s3_status = AutoCheckStatus.PASS;
                        }
                        else
                        {
                            s3_status = AutoCheckStatus.FAIL;
                        }
                    }
                    else // Högersidig
                    {
                        if (s3_setupFieldAngles.IndexOf(180) != -1 && s3_setupFieldAngles.IndexOf(270) != -1)
                        {
                            s3_status = AutoCheckStatus.PASS;
                        }
                        else
                        {
                            s3_status = AutoCheckStatus.FAIL;
                        }
                    }
                }
            }
            else
            {
                s3_status = AutoCheckStatus.MANUAL; // If not Varian, then do manual check of setup angles.
            }
            s3_value = reorderBeamParam(s3_value, ",");
            checklistItems.Add(new ChecklistItem("S3. Gantryvinklar för setupfälten är korrekta", "Kontrollera att setupfältens gantryvinklar är korrekta (patientgeometrin avgör vinklar)\r\n  • Standard: 270° respektive 0°\r\n•  • Högersidiga behandlingar: 180° respektive 270°", s3_value, s3_status));

            string          s4_value;
            AutoCheckStatus s4_status       = AutoCheckStatus.FAIL;
            int             s4_numberOfPass = 0;
            bool            s4_isocenterCouldNotBeDetermined = false;
            VVector         s4_isocenterPosition             = new VVector(double.NaN, double.NaN, double.NaN);

            foreach (Beam beam in planSetup.Beams)
            {
                if (double.IsNaN(s4_isocenterPosition.x) && double.IsNaN(s4_isocenterPosition.y) && double.IsNaN(s4_isocenterPosition.z))
                {
                    s4_isocenterPosition = beam.IsocenterPosition;
                    if (double.IsNaN(beam.IsocenterPosition.x) == false && double.IsNaN(beam.IsocenterPosition.y) == false && double.IsNaN(beam.IsocenterPosition.z) == false)
                    {
                        s4_numberOfPass++;
                    }
                    else
                    {
                        s4_isocenterCouldNotBeDetermined = true;
                    }
                }
                else if (Math.Round(s4_isocenterPosition.x, 1) == Math.Round(beam.IsocenterPosition.x, 1) && Math.Round(s4_isocenterPosition.y, 1) == Math.Round(beam.IsocenterPosition.y, 1) && Math.Round(s4_isocenterPosition.z, 1) == Math.Round(beam.IsocenterPosition.z, 1))
                {
                    s4_numberOfPass++;
                }
            }
            if (s4_numberOfPass == numberOfBeams)//numberOfTreatmentBeams)
            {
                s4_value  = "Samma isocenter";
                s4_status = AutoCheckStatus.PASS;
            }
            else if (s4_isocenterCouldNotBeDetermined)
            {
                s4_value  = "Isocenterposition kunde ej bestämmas";
                s4_status = AutoCheckStatus.WARNING;
            }
            else
            {
                s4_value  = "Olika isocenter mellan fälten";
                s4_status = AutoCheckStatus.WARNING;
            }
            checklistItems.Add(new ChecklistItem("S4. Alla fält har samma isocenter vid isocentrisk teknik", "Kontrollera att samtliga fälts (inklusive setup-fält) Isocenter sammanfaller.", s4_value, s4_status));

            string s5_value = string.Empty;

            foreach (Beam beam in planSetup.Beams)
            {
                if (Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text) == false)
                {
                    DataTable DRRSetting = AriaInterface.Query("select distinct SliceRT.AcqNote from Radiation, PlanSetup, SliceRT, Slice, Image where  PlanSetup.PlanSetupSer =" + planSetupSer.ToString() + " and Radiation.RadiationId ='" + beam.Id + "' and PlanSetup.PlanSetupSer = Radiation.PlanSetupSer and SliceRT.RadiationSer = Radiation.RadiationSer and SliceRT.SliceSer = Slice.SliceSer and SliceRT.AcqNote like 'MultiWindow%'");
                    if (DRRSetting.Rows.Count == 1 && DRRSetting.Rows[0][0] != DBNull.Value)
                    {
                        // split file path
                        s5_value += (s5_value.Length == 0 ? "" : ", ") + beam.Id + ": " + QueryContents.FindInFiles((string)DRRSetting.Rows[0][0]);//(string)DRRSetting.Rows[0][0];
                    }
                }
            }
            s5_value = reorderBeamParam(s5_value, ",");
            checklistItems.Add(new ChecklistItem("S5. Kvalitén på DRR", "Kontrollera att kvalitén på DRR för alla fält som ska ha en DRR är acceptabel.", s5_value, AutoCheckStatus.MANUAL));

            string          s6_value      = string.Empty;
            AutoCheckStatus s6_status     = AutoCheckStatus.MANUAL;
            List <string>   s6_tolerances = new List <string>();

            foreach (Beam beam in planSetup.Beams)
            {
                string    toleranceId      = string.Empty;
                DataTable toleranceIdTable = AriaInterface.Query("select Tolerance.ToleranceId from Radiation,ExternalFieldCommon,Tolerance where ExternalFieldCommon.RadiationSer=Radiation.RadiationSer and ExternalFieldCommon.ToleranceSer=Tolerance.ToleranceSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");
                if (toleranceIdTable.Rows.Count == 1 && toleranceIdTable.Rows[0][0] != DBNull.Value)
                {
                    s6_tolerances.Add((string)toleranceIdTable.Rows[0][0]);
                }
                else
                {
                    s6_tolerances.Add("Saknas");
                }
            }
            string[] uniqueTolerances = s6_tolerances.Distinct().ToArray();
            if (uniqueTolerances.Length == 1 && String.Equals(s6_tolerances[0], "Saknas", StringComparison.OrdinalIgnoreCase) == false)
            {
                s6_value = s6_tolerances[0];
            }
            else if (uniqueTolerances.Length == 1 && String.Equals(s6_tolerances[0], "Saknas", StringComparison.OrdinalIgnoreCase) == false)
            {
                s6_value  = s6_tolerances[0];
                s6_status = AutoCheckStatus.FAIL;
            }
            else
            {
                foreach (string tolerance in uniqueTolerances)
                {
                    s6_value += (s6_value.Length == 0 ? string.Empty : ", ") + tolerance;
                }
                s6_status = AutoCheckStatus.FAIL;
            }
            checklistItems.Add(new ChecklistItem("S6. Toleranstabell har valts korrekt", "Kontrollera att korrekt toleranstabell har använts, baserat på maskintyp (Elekta/Varian), strålkvalité (elektroner/fotoner), nätmask (H&N fix), annan fixation som sitter fast i britsen (fast fix) eller icke fast fixation (utan fix).", s6_value, s6_status));

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          s7_value               = string.Empty;
                string          s7_value_detailed      = string.Empty;
                AutoCheckStatus s7_status              = AutoCheckStatus.MANUAL;
                List <string>   s7_imageModalityBeam   = new List <string>();
                List <int>      s7_imageModalityBeamNr = new List <int>();
                List <string>   s7_beamId              = new List <string>();
                foreach (Beam beam in planSetup.Beams)
                {
                    if (beam.IsSetupField && !Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                    {
                        List <string> protocolIds = new List <string>();

                        s7_value_detailed += (s7_value_detailed.Length == 0 ? string.Empty : "\r\n\r\n") + beam.Id + ": ";
                        s7_value           = string.Empty;
                        DataTable dataTableImageSessions = AriaInterface.Query("select Session.SessionNum,SessionProcedure.SessionProcedureTemplateId from SessionProcedurePart,SessionProcedure,Session,Radiation where SessionProcedurePart.RadiationSer=Radiation.RadiationSer and SessionProcedure.SessionProcedureSer=SessionProcedurePart.SessionProcedureSer and Session.SessionSer=SessionProcedure.SessionSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "' order by SessionNum");
                        foreach (DataRow dataRow in dataTableImageSessions.Rows)
                        {
                            int    sessionNr           = (int)dataRow[0];
                            string procedureTemplateId = (dataRow[1] == DBNull.Value ? "-" : (string)dataRow[1]);
                            s7_value_detailed += "\r\n  Session " + sessionNr.ToString() + ": " + procedureTemplateId;
                            protocolIds.Add(procedureTemplateId);
                        }

                        s7_beamId.Add(beam.Id);
                        string[] uniqueprotocolIds = protocolIds.Distinct().ToArray();
                        if (uniqueprotocolIds.Length == 0)
                        {
                            s7_imageModalityBeam.Add("Ingen");
                            s7_status = AutoCheckStatus.FAIL;
                        }
                        else if (uniqueprotocolIds.Length == 1)
                        {
                            s7_imageModalityBeam.Add(uniqueprotocolIds[0]);
                        }
                        else
                        {
                            s7_imageModalityBeam.Add("Flera");
                            s7_status = AutoCheckStatus.FAIL;
                        }
                        if (fractionation != null && fractionation.NumberOfFractions != protocolIds.Count)
                        {
                            s7_status = AutoCheckStatus.FAIL;
                        }
                        s7_imageModalityBeamNr.Add(protocolIds.Count);
                    }
                }
                for (int beamNr = 0; beamNr < s7_imageModalityBeam.Count; beamNr++)
                {
                    s7_value += (s7_value.Length == 0 ? string.Empty : ", ") + s7_beamId[beamNr] + ": " + s7_imageModalityBeam[beamNr] + " (" + s7_imageModalityBeamNr[beamNr].ToString() + " fr)";
                }
                checklistItems.Add(new ChecklistItem("S7. Bildtagningsmodalitet är korrekt", "Kontrollera att bildtagning är korrekt\r\nVarian:\r\n  • Korrekt bildtagningsmodalitet är inlagd, samt att bildtagning är aktiverad för alla sessioner på setup-fälten\r\n  • Se bilaga 4 i dokumentet ”Verifikationsbilder”\r\nElekta:\r\n  • Inga setup-fält på tangentiella bröstbehandlingar\r\n  • Inga setup-fält på L09, L07 och L05 (XVI används i första hand för icke-laterala behandlingar)\r\n  • På L03 tas bilder med behandlingsfält om de finns i 0/180° och 90/270°, annars ska det finnas setup-fält", s7_value, s7_value_detailed, s7_status));
            }

            string          s8_value  = "Saknas";
            AutoCheckStatus s8_status = AutoCheckStatus.FAIL;

            foreach (Beam beam in planSetup.Beams)
            {
                if (beam.IsSetupField && Operators.LikeString(beam.Id.ToLower(), "Uppl*gg".ToLower(), CompareMethod.Text))
                {
                    s8_status = AutoCheckStatus.PASS;
                    s8_value  = "Existerar";
                    break;
                }
            }
            checklistItems.Add(new ChecklistItem("S8. Uppläggsfält existerar i planen", "Kontrollera att det finns ett fält med Id Upplägg i behandlingsplanen", s8_value, s8_status));

            checklistItems.Add(new ChecklistItem("S9. Uppläggningen är genomförbar", "Kontrollera att upplägget är genomförbart för den givna geometrin \r\n  • Exempelvis att behandlingar av extremt kaudala target inte är orienterade 'Head First'", "", AutoCheckStatus.MANUAL));
        }
Example #10
0
        public void C() //Conformal Arc
        {
            if (checklistType == ChecklistType.EclipseConformal)
            {
                checklistItems.Add(new ChecklistItem("C. Conformal Arc"));

                string c1_value = string.Empty;

                AutoCheckStatus c1_status           = AutoCheckStatus.FAIL;
                int             c1_numberOfWarnings = 0;
                int             c1_numberOfPass     = 0;
                List <double>   collAngles          = new List <double>();
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double collimatorAngle = beam.ControlPoints[0].CollimatorAngle;
                        collAngles.Add(collimatorAngle);
                        if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
                        {
                            if (collimatorAngle >= 0 && collimatorAngle <= 5)
                            {
                                c1_numberOfPass++;
                            }
                            else if (collimatorAngle > 5 && collimatorAngle < 355)
                            {
                                c1_numberOfWarnings++;
                            }
                        }


                        c1_value += (c1_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + collimatorAngle.ToString("0.0") + "°";
                    }
                }
                if (c1_numberOfPass == numberOfTreatmentBeams)
                {
                    c1_status = AutoCheckStatus.PASS;
                }
                else if (c1_numberOfPass + c1_numberOfWarnings == numberOfTreatmentBeams)
                {
                    c1_status = AutoCheckStatus.WARNING;
                }
                if (collAngles.Count > 1 && collAngles.Distinct().ToList().Count < 2)
                {
                    c1_status = AutoCheckStatus.FAIL;
                }

                checklistItems.Add(new ChecklistItem("C1. Kollimatorvinkeln är lämplig", "Kontrollera att kollimatorvinkeln är lämplig\r\n  • Varian Conformal Arc: vanligtvis 0° till 5°, men passar detta ej PTV är andra vinklar ok", c1_value, c1_status));

                string          c2_value        = string.Empty;
                AutoCheckStatus c2_status       = AutoCheckStatus.WARNING;
                int             c2_numberOfPass = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double jawLim = 2.5;
                        double X1     = 0.1 * beam.ControlPoints[0].JawPositions.X1;
                        double X2     = 0.1 * beam.ControlPoints[0].JawPositions.X2;
                        double Y1     = 0.1 * beam.ControlPoints[0].JawPositions.Y1;
                        double Y2     = 0.1 * beam.ControlPoints[0].JawPositions.Y2;
                        if ((Math.Abs(X1) <= jawLim && Math.Abs(X2) <= jawLim && Math.Abs(Y1) <= jawLim && Math.Abs(Y2) <= jawLim) && (beam.EnergyModeDisplayName == "6X-FFF" || beam.EnergyModeDisplayName == "10X-FFF"))
                        {
                            c2_numberOfPass++;
                        }
                        else if ((Math.Abs(X1) > jawLim || Math.Abs(X2) > jawLim || Math.Abs(Y1) > jawLim || Math.Abs(Y2) > jawLim) && (beam.EnergyModeDisplayName == "6X" || beam.EnergyModeDisplayName == "10X"))
                        {
                            c2_numberOfPass++;
                        }
                        c2_value += (c2_value.Length == 0 ? string.Empty : ", ") + beam.Id + " " + beam.EnergyModeDisplayName + ": X1: " + X1.ToString("0.0") + " cm, X2: " + X2.ToString("0.0") + " cm, Y1: " + Y1.ToString("0.0") + " cm, Y2: " + Y2.ToString("0.0") + " cm";
                    }
                }
                if (c2_numberOfPass == numberOfTreatmentBeams)
                {
                    c2_status = AutoCheckStatus.PASS;
                }
                checklistItems.Add(new ChecklistItem("C2. Fältbredden är rimlig ", "Kontrollera att fältet har en rimlig fältbredd och har korrekt behandlingsteknik FF eller FFF (riktvärde <= 5 cm, vid större fältbredd ska FF användas).", c2_value, c2_status));

                string c3_value = string.Empty;

                AutoCheckStatus c3_status = AutoCheckStatus.WARNING;

                string          c4_value  = string.Empty;
                AutoCheckStatus c4_status = AutoCheckStatus.MANUAL;
                //int c3_numberOfPass = 0;
                double totArcLength = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        //double arclength = beam.ControlPoints[0].GantryAngle - beam.ControlPoints[beam.ControlPoints.Count()].GantryAngle;
                        // Kombinerad summering av arcLength samt kontroll av korrekt MLC-inställning samt behandlingsteknik.
                        totArcLength += beam.ArcLength;


                        c3_value += (c3_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + beam.ArcLength.ToString("0.0") + "°";
                        if (beam.MLCPlanType.ToString().IndexOf("ArcDynamic") == -1 && beam.Technique.ToString().IndexOf("SRS ARC") == -1)
                        {
                            c4_value += "Behandlingsteknik är " + beam.Technique.ToString() + " och MLC-inställningar är " + beam.MLCPlanType.ToString() + ", korrigera till SRS ARC respektive Arc Dynamic. Tag bort och lägg till MLC igen och gör om Fit To Structure.";
                            c4_status = AutoCheckStatus.FAIL;
                        }
                        else if (beam.MLCPlanType.ToString().IndexOf("ArcDynamic") == -1 && beam.Technique.ToString().IndexOf("SRS ARC") > -1)
                        {
                            c4_value += "MLC-inställningar är " + beam.MLCPlanType.ToString() + ", korrigera till Arc Dynamic. Tag bort och lägg till MLC igen och gör om Fit To Structure.";
                            c4_status = AutoCheckStatus.FAIL;
                        }
                        else if (beam.Technique.ToString().IndexOf("SRS ARC") == -1 && beam.MLCPlanType.ToString().IndexOf("ArcDynamic") > -1)
                        {
                            c4_value += "Behandlingsteknik är " + beam.Technique.ToString() + ", korrigera till SRS ARC.";
                            c4_status = AutoCheckStatus.FAIL;
                        }
                    }
                }
                c3_value += ". Total längd: " + totArcLength.ToString("0.0");
                if (totArcLength > 180)
                {
                    c3_status = AutoCheckStatus.PASS;
                }


                checklistItems.Add(new ChecklistItem("C3. Arclängd är rimlig", "Kontrollera att totala längden på arcs är mer än 180°)", c3_value, c3_status));
                // No Jawtracking for Conformal arcs
                //var v5_values = CheckJawTracking(planSetup);
                // Values here is set in the loop for c3.

                checklistItems.Add(new ChecklistItem("C4. Leveransmönstret är rimligt", "Kontrollera visuellt att leveransmönstret är rimligt (att MLCn går längs Z_PTV-konturen)", c4_value, c4_status));
            }
        }
Example #11
0
        public void P()
        {
            checklistItems.Add(new ChecklistItem("P. Dosplan"));

            string          p1_value        = string.Empty;
            string          p1_value_detail = string.Empty;
            bool            reviewed        = false;
            AutoCheckStatus p1_status       = AutoCheckStatus.MANUAL; //CheckResult(planSetup.ApprovalStatus == PlanSetupApprovalStatus.PlanningApproved);
            //DataTable history = AriaInterface.Query("SELECT DISTINCT HistoricalStatus=Approval.Status, HistoricalStatusDate=Approval.StatusDate, HistoricalStatusUserId=Approval.StatusUserName, HistoricalStatusUserName=CONCAT((SELECT DISTINCT Staff.AliasName FROM Staff WHERE Staff.StaffId=Approval.StatusUserName), (SELECT DISTINCT Doctor.AliasName FROM Doctor WHERE Doctor.DoctorId=Approval.StatusUserName)) FROM Approval, PlanSetup, Staff WHERE PlanSetup.PlanSetupSer=Approval.TypeSer AND Approval.ApprovalType='PlanSetup' and PlanSetup.PlanSetupSer = '" + planSetupSer.ToString() + "' ORDER BY HistoricalStatusDate");
            DataTable history = AriaInterface.Query("SELECT DISTINCT HistoricalStatus=Approval.Status, HistoricalStatusDate=Approval.StatusDate, HistoricalStatusUserId=Approval.StatusUserName, HistoricalStatusUserName=CONCAT((SELECT DISTINCT Staff.AliasName FROM Staff WHERE Staff.StaffId=Approval.StatusUserName), (SELECT DISTINCT Doctor.AliasName FROM Doctor WHERE Doctor.DoctorId=Approval.StatusUserName)) FROM Approval, PlanSetup, Staff WHERE PlanSetup.PlanSetupSer=Approval.TypeSer AND Approval.ApprovalType='PlanSetup' and PlanSetup.PlanSetupSer = '" + planSetupSer.ToString() + "' UNION SELECT DISTINCT HistoricalStatus=PlanSetup.Status, HistoricalStatusDate=PlanSetup.StatusDate, HistoricalStatusUserId=PlanSetup.StatusUserName, HistoricalStatusUserName=CONCAT((SELECT DISTINCT Staff.AliasName FROM Staff WHERE Staff.StaffId=PlanSetup.StatusUserName), (SELECT DISTINCT Doctor.AliasName FROM Doctor WHERE Doctor.DoctorId=PlanSetup.StatusUserName)) FROM PlanSetup WHERE PlanSetup.PlanSetupSer= '" + planSetupSer.ToString() + "' ORDER BY HistoricalStatusDate");

            if (history.Rows.Count > 0)
            {
                p1_value_detail += "Historisk Status\tTid\t\t\tUserId\tUserName\r\n";
            }
            DataRow lastRow = history.Rows[history.Rows.Count - 1]; // except status from last row, since it will be added explicitly

            foreach (DataRow row in history.Rows)
            {
                if (String.Equals((string)row["HistoricalStatus"], "Reviewed"))
                {
                    reviewed = true;
                }
                if (row != lastRow)
                {
                    p1_value += (string)row["HistoricalStatus"] + ", ";
                }
                p1_value_detail += (string)row["HistoricalStatus"] + "\t" + row["HistoricalStatusDate"].ToString() + "\t" + (string)row["HistoricalStatusUserId"];
                if (row["HistoricalStatusUserName"] == DBNull.Value)
                {
                    p1_value_detail += "\r\n";
                }
                else
                {
                    p1_value_detail += "\t" + (string)row["HistoricalStatusUserName"] + "\r\n";
                }
            }
            p1_value += planSetup.ApprovalStatus.ToString();
            if (String.Equals(planSetup.ApprovalStatus.ToString(), "PlanningApproved") == false)
            {
                p1_status = AutoCheckStatus.FAIL;
                p1_value += ", planen har fel status";
            }
            else if (reviewed == false)
            {
                p1_status = AutoCheckStatus.FAIL;
                p1_value += ", planen är inte Reviewed";
            }
            else
            {
                if (history.Rows.Count == 3 && String.Equals((string)history.Rows[1]["HistoricalStatus"], "Reviewed"))
                {
                    p1_status = AutoCheckStatus.PASS;
                }
            }
            if (String.IsNullOrEmpty(p1_value_detail) == true)
            {
                checklistItems.Add(new ChecklistItem("P1. Planens status är korrekt", "Kontrollera att planen är Planning Approved i Aria samt att den tidigare haft status Reviewed", p1_value, p1_status));
            }
            else
            {
                checklistItems.Add(new ChecklistItem("P1. Planens status är korrekt", "Kontrollera att planen är Planning Approved i Aria samt att den tidigare haft status Reviewed", p1_value, p1_value_detail, p1_status));
            }

            string          p2_value  = string.Empty;
            AutoCheckStatus p2_status = AutoCheckStatus.FAIL;

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Multiple)
            {
                p2_status = AutoCheckStatus.WARNING;
            }
            int p2_numberOfPass = 0;

            foreach (Beam beam in planSetup.Beams)
            {
                bool fff = (beam.EnergyModeDisplayName.IndexOf("FFF") != -1);
                if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
                {
                    if (fff == false && beam.DoseRate == 600)
                    {
                        p2_numberOfPass++;
                    }
                    else if (fff == true && beam.EnergyModeDisplayName.IndexOf("6") == 0 && beam.DoseRate == 1400)
                    {
                        p2_numberOfPass++;
                    }
                    else if (fff == true && beam.EnergyModeDisplayName.IndexOf("10") == 0 && beam.DoseRate == 2400)
                    {
                        p2_numberOfPass++;
                    }
                }
                else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta)
                {
                    if (beam.EnergyModeDisplayName.IndexOf("4") == 0 && beam.DoseRate == 250)
                    {
                        p2_numberOfPass++;
                    }
                    else if (beam.EnergyModeDisplayName.IndexOf("6") == 0 && beam.DoseRate == 600)
                    {
                        p2_numberOfPass++;
                    }
                    else if (beam.EnergyModeDisplayName.IndexOf("10") == 0 && beam.DoseRate == 500)
                    {
                        p2_numberOfPass++;
                    }

                    /*{
                     *  if (beam.TreatmentUnit.Id.IndexOf("L05") == -1 && beam.DoseRate == 400)
                     *      p2_numberOfPass++;
                     *  else if (beam.TreatmentUnit.Id.IndexOf("L05") != -1 && beam.DoseRate == 500)
                     *      p2_numberOfPass++;
                     * }*/
                }
                p2_value += (p2_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + beam.DoseRate.ToString();
            }
            if (p2_numberOfPass == numberOfBeams)
            {
                p2_status = AutoCheckStatus.PASS;
            }
            p2_value = reorderBeamParam(p2_value, ",");
            checklistItems.Add(new ChecklistItem("P2. Dosraten är korrekt", "Kontrollera att dosraten (MU/min) är korrekt:\r\n  • Varian: 600 (ej FFF), 1400 (6 MV FFF), 2400 (10 MV FFF)\r\n  • Elekta: 250 (4 MV), 600 (6 MV), 500 (10 MV)", p2_value, p2_status));

            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
            {
                string          p3_value        = string.Empty;
                AutoCheckStatus p3_status       = AutoCheckStatus.FAIL;
                int             p3_numberOfPass = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double    treatmentTime      = double.NaN;
                        DataTable treatmentTimeTable = AriaInterface.Query("select TreatmentTime from Radiation,ExternalFieldCommon where ExternalFieldCommon.RadiationSer=Radiation.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString() + " and Radiation.RadiationId='" + beam.Id + "'");

                        if (treatmentTimeTable.Rows.Count == 1 && treatmentTimeTable.Rows[0][0] != DBNull.Value)
                        {
                            treatmentTime = (double)treatmentTimeTable.Rows[0][0];

                            double openMU;
                            double wedgedMU;
                            GetMU(beam, out openMU, out wedgedMU);

                            if (beam.EnergyModeDisplayName.IndexOf("FFF") != -1 && !(checklistType == ChecklistType.EclipseConformal) && !(checklistType == ChecklistType.EclipseVMAT))
                            {
                                if (openMU < 600 && treatmentTime == 0.5)
                                {
                                    p3_numberOfPass++;
                                }
                            }
                            else if ((checklistType == ChecklistType.EclipseVMAT || checklistType == ChecklistType.EclipseConformal) && beam.EnergyModeDisplayName.IndexOf("FFF") == -1)
                            {
                                // For VMAT use treatmentTime=2 if MU<=400, otherwise treatmentTime = min(5.0, max(3.0, ceil(MU/(DoseRate/N)))), where N=2

                                if (openMU <= 400 && treatmentTime == 2)
                                {
                                    p3_numberOfPass++;
                                }
                                if (openMU > 400 && openMU <= 900 && treatmentTime == 3)
                                {
                                    p3_numberOfPass++;
                                }
                                if (openMU > 900 && openMU <= 1200 && treatmentTime == 4)
                                {
                                    p3_numberOfPass++;
                                }
                                if (openMU > 1200 && openMU <= 2000 && treatmentTime == 5)
                                {
                                    p3_numberOfPass++;
                                }
                                if (openMU > 2000 && treatmentTime == 7)
                                {
                                    p3_numberOfPass++;
                                }

                                /*
                                 * New Old 2018-07-02 commented.
                                 * int doseRateFactor = 2;
                                 * if (openMU > 400 && treatmentTime == Math.Min(5.0, Math.Max(3.0, Math.Ceiling(openMU / ((double)beam.DoseRate / doseRateFactor)))))
                                 *  p3_numberOfPass++;
                                 *
                                 * Old
                                 * if (openMU <= 400 && treatmentTime == 2)
                                 *  p3_numberOfPass++;
                                 * else if (openMU > 400 && treatmentTime == 3)
                                 *  p3_numberOfPass++;
                                 */
                            }
                            else if (checklistType == ChecklistType.EclipseVMAT && beam.EnergyModeDisplayName.IndexOf("FFF") != -1) // Specific Check for Hypo and SRS-brain.
                            {
                                int    doseRateFactor = 2;
                                double estTime        = openMU / ((double)beam.DoseRate / doseRateFactor);

                                if (planSetup.UniqueFractionation.NumberOfFractions == 7 && planSetup.UniqueFractionation.PrescribedDosePerFraction.Dose > 6)
                                {
                                    if (planSetup.Beams.Where(v => v.IsSetupField == false).Count() == 1 && treatmentTime == 3)
                                    {
                                        p3_numberOfPass++;
                                    }
                                    else if (planSetup.Beams.Where(v => v.IsSetupField == false).Count() == 2 && treatmentTime == 1.5)
                                    {
                                        p3_numberOfPass++;
                                    }
                                }
                                if (planSetup.UniqueFractionation.NumberOfFractions == 3 && planSetup.UniqueFractionation.PrescribedDosePerFraction.Dose > 9)
                                {
                                    if (planSetup.Beams.Where(v => v.IsSetupField == false).Count() == 1 && treatmentTime == 3)
                                    {
                                        p3_numberOfPass++;
                                    }
                                    else if (planSetup.Beams.Where(v => v.IsSetupField == false).Count() == 2 && treatmentTime == 1.5)
                                    {
                                        p3_numberOfPass++;
                                    }
                                }
                            }
                            else if (checklistType == ChecklistType.EclipseGating || (checklistType == ChecklistType.EclipseConformal && beam.EnergyModeDisplayName.IndexOf("FFF") != -1))
                            {
                                if (treatmentTime == 5)
                                {
                                    p3_numberOfPass++;
                                }
                            }
                            else
                            {
                                if (openMU <= 500 && wedgedMU == 0 && treatmentTime == 1 || wedgedMU > 0 && wedgedMU <= 300 && treatmentTime == 1)
                                {
                                    p3_numberOfPass++;
                                }
                                else if (openMU > 500 && wedgedMU == 0 && treatmentTime == 2 || wedgedMU > 300 && treatmentTime == 2)
                                {
                                    p3_numberOfPass++;
                                }
                            }
                        }

                        p3_value += (p3_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + (double.IsNaN(treatmentTime) ? "-" : treatmentTime.ToString() + " min");
                    }
                }
                if (p3_numberOfPass == numberOfTreatmentBeams)
                {
                    p3_status = AutoCheckStatus.PASS;
                }
                p3_value = reorderBeamParam(p3_value, ",");

                checklistItems.Add(new ChecklistItem("P3. Beam on-tiderna är korrekta", "Kontrollera att fälten är tilldelade korrekta beam on-tider:\r\n  • 0.5 min för FFF fält med <600 MU\r\n  • 1 min för öppna fält med <=500 MU och kilfält med <=300 MU\r\n  • 2 min för öppna fält med >500 MU och kilfält med >300 MU  \r\n  • 5 min för gating\r\n  • 5 min för cArc FFF\r\n  • För RA/cArc gäller* \r\n\t MU \t\tBeam on (min)\r\n\t <= 400\t\t2\r\n\t 400<x<=900\t3\r\n\t 900<x<=1200\t4\r\n\t 1200<x<=2000\t5\r\n\t >2000\t\t7\r\n*Om dosraten är 600 MU/min. \r\n  • För Hypo/hjärna FFF gäller: \r\n\t Antal arcs \tBeam on (min)\r\n\t 1\t\t3\r\n\t 2\t\t1.5\r\n\t", p3_value, p3_status));
            }

            // Will now use information from Prescription rather than verifying against ChecklistType
            string          p4_value         = string.Empty;
            AutoCheckStatus p4_status        = AutoCheckStatus.FAIL;
            string          prescribedGating = string.Empty;


            DataTable dataTableUseGated = AriaInterface.Query("select distinct ExternalFieldCommon.MotionCompTechnique from Radiation,ExternalFieldCommon where Radiation.RadiationSer=ExternalFieldCommon.RadiationSer and Radiation.PlanSetupSer=" + planSetupSer.ToString());
            bool      gatingChecked;

            if (dataTableUseGated.Rows.Count == 1 && dataTableUseGated.Rows[0][0] != DBNull.Value && string.Compare((string)dataTableUseGated.Rows[0][0], "GATING") == 0)
            {
                gatingChecked = true;
                p4_value      = "Ikryssad";
            }
            else
            {
                gatingChecked = false;
                p4_value      = "Ej ikryssad";
            }

            if (prescSer > 0)
            {
                DataTable prescription = AriaInterface.Query("select Gating from Prescription, PlanSetup where PlanSetup.PrescriptionSer = Prescription.PrescriptionSer and PlanSetup.PlanSetupSer = '" + planSetupSer.ToString() + "'");
                if (prescription.Rows[0]["Gating"] != DBNull.Value)
                {
                    prescribedGating = (string)prescription.Rows[0]["Gating"];
                }
                p4_status = CheckResult(String.IsNullOrEmpty(prescribedGating) != gatingChecked);
            }
            else
            {
                p4_status = AutoCheckStatus.WARNING;
                p4_value  = "Ordination saknas - kontroll kan ej genomföras; " + p4_value;
            }

            /*
             * {
             *  if (String.IsNullOrEmpty(prescribedGating) == false)
             *      p4_status = AutoCheckStatus.PASS;
             *  else
             *      p4_status = AutoCheckStatus.FAIL;
             *  p4_value = "Ikryssad";
             * }
             * else
             * {
             *  if (String.IsNullOrEmpty(prescribedGating) == false)
             *      p4_status = AutoCheckStatus.FAIL;
             *  else
             *      p4_status = AutoCheckStatus.PASS;
             *  p4_value = "Ej ikryssad";
             * }
             */
            /*
             * if (dataTableUseGated.Rows.Count == 1 && dataTableUseGated.Rows[0][0] != DBNull.Value && string.Compare((string)dataTableUseGated.Rows[0][0], "GATING") == 0)
             * {
             *  if (checklistType == ChecklistType.EclipseGating)
             *      p4_status = AutoCheckStatus.PASS;
             *  else
             *      p4_status = AutoCheckStatus.FAIL;
             *  p4_value = "Ikryssad";
             * }
             * else
             * {
             *  if (checklistType == ChecklistType.EclipseGating)
             *      p4_status = AutoCheckStatus.FAIL;
             *  else
             *      p4_status = AutoCheckStatus.PASS;
             *  p4_value = "Ej ikryssad";
             * }
             */
            checklistItems.Add(new ChecklistItem("P4. Use Gated är korrekt", "Kontrollera att rutan Use Gated under Plan properties svarar mot ordination.", p4_value, p4_status));

            if (false)//checklistType == ChecklistType.EclipseGating)
            {
                string          p5_value  = string.Empty;
                AutoCheckStatus p5_status = AutoCheckStatus.FAIL;
                if (image != null && image.Comment.ToLower().IndexOf("bh") == -1)
                {
                    int p5_numberOfPass = 0;
                    foreach (Beam beam in planSetup.Beams)
                    {
                        if (!beam.IsSetupField)
                        {
                            double openMU;
                            double wedgedMU;
                            GetMU(beam, out openMU, out wedgedMU);
                            if (wedgedMU == 0)
                            {
                                p5_numberOfPass++;
                            }
                        }
                    }
                    if (p5_numberOfPass == numberOfTreatmentBeams)
                    {
                        p5_status = AutoCheckStatus.PASS;
                    }
                    p5_value = "EIG";
                }
                else
                {
                    p5_status = AutoCheckStatus.PASS;
                    p5_value  = "Breath hold";
                }
                checklistItems.Add(new ChecklistItem("P5. Kilade fält ej förekommande för EIG", "Kontrollera att det inte finns några kilade fält i EIG gating-plan.", p5_value, p5_status));
            }

            string          p6_value                   = string.Empty;
            string          p6_value_detailed          = string.Empty;
            AutoCheckStatus p6_status                  = AutoCheckStatus.UNKNOWN;
            DataTable       dataTableTreatmentSessions = AriaInterface.Query("select Session.SessionNum,SessionRTPlan.Status from Session,SessionRTPlan,RTPlan where Session.SessionSer=SessionRTPlan.SessionSer and RTPlan.RTPlanSer=SessionRTPlan.RTPlanSer and RTPlan.PlanSetupSer=" + planSetupSer.ToString() + " order by SessionNum");

            foreach (DataRow dataRow in dataTableTreatmentSessions.Rows)
            {
                int    sessionNr = (int)dataRow[0];
                string status    = (dataRow[1] == DBNull.Value ? "-" : (string)dataRow[1]);
                p6_value_detailed += (p6_value_detailed.Length == 0 ? string.Empty : "\r\n") + "Session " + sessionNr.ToString() + ": " + status;
            }
            p6_value = "# aktiva sessioner: " + dataTableTreatmentSessions.Rows.Count.ToString();
            if (fractionation != null && fractionation.NumberOfFractions > 0 && fractionation.NumberOfFractions == dataTableTreatmentSessions.Rows.Count)
            {
                p6_status = AutoCheckStatus.PASS;
            }
            else
            {
                p6_status = AutoCheckStatus.FAIL;
            }
            checklistItems.Add(new ChecklistItem("P6. Behandlingssessionerna är aktiva", "Kontrollera att alla behandlingssessioner är aktiva", p6_value, p6_value_detailed, p6_status));

            if (checklistType == ChecklistType.Eclipse || checklistType == ChecklistType.EclipseGating || checklistType == ChecklistType.MasterPlan)
            {
                string          p7_value        = string.Empty;
                AutoCheckStatus p7_status       = AutoCheckStatus.FAIL;
                int             p7_numberOfPass = 0;
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double diode_value = double.NaN;
                        if (beam.Comment.Length > 0)
                        {
                            NumberFormatInfo numberFormatInfo = new NumberFormatInfo()
                            {
                                NumberDecimalSeparator = ".", NumberGroupSeparator = string.Empty, NegativeInfinitySymbol = "Inf", PositiveInfinitySymbol = "Inf", NaNSymbol = "NaN", NumberDecimalDigits = 0
                            };
                            string[] splitString = beam.Comment.ToLower().Split(new string[] { " ", "gy" }, StringSplitOptions.RemoveEmptyEntries);
                            if (splitString.Length == 0)
                            {
                                double.TryParse(beam.Comment.Replace(',', '.'), NumberStyles.Number | NumberStyles.AllowExponent, numberFormatInfo, out diode_value);
                            }
                            else
                            {
                                double.TryParse(splitString[0].Replace(',', '.'), NumberStyles.Number | NumberStyles.AllowExponent, numberFormatInfo, out diode_value);
                            }
                        }
                        double openMU;
                        double wedgedMU;
                        GetMU(beam, out openMU, out wedgedMU);
                        if (double.IsNaN(diode_value) == false)
                        {
                            p7_numberOfPass++;
                        }
                        else
                        {
                            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian && openMU + wedgedMU < 25)
                            {
                                p7_numberOfPass++;
                            }
                            else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta && openMU < 25 && openMU + wedgedMU < 50)
                            {
                                p7_numberOfPass++;
                            }
                        }
                        p7_value += (p7_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + (double.IsNaN(diode_value) ? "-" : diode_value.ToString() + " Gy");
                    }
                }
                if (p7_numberOfPass == numberOfTreatmentBeams)
                {
                    p7_status = AutoCheckStatus.PASS;
                }
                p7_value = reorderBeamParam(p7_value, ",");
                checklistItems.Add(new ChecklistItem("P7. Diodvärden finns införda under Comments för fälten", "Kontrollera att diodvärden finns införda för fält med >=25 MU alternativt >=50 MU (öppet+kil) för Elekta.", p7_value, p7_status));
            }

            checklistItems.Add(new ChecklistItem("P8. Dosfördelningen är rimlig", "Kontrollera att dosfördelningen är rimlig med avseende på targettäckning och omkringliggande riskorgan. Kontroll skall göras av varje dosnivå", "", AutoCheckStatus.MANUAL));

            string          p9_value_detailed = string.Empty;
            string          p9_value          = String.Empty;
            bool            isSplit           = false;
            AutoCheckStatus p9_status         = AutoCheckStatus.UNKNOWN;

            if (checklistType == ChecklistType.EclipseVMAT)
            {
                isSplit = GetIsSplitVMAT(planSetup);
            }
            foreach (Beam beam in planSetup.Beams)
            {
                if (!beam.IsSetupField)
                {
                    double openMU;
                    double wedgedMU;
                    GetMU(beam, out openMU, out wedgedMU);

                    p9_value_detailed += beam.Id + ":\r\n";
                    if (checklistType == ChecklistType.EclipseVMAT)
                    {
                        p9_value_detailed += "  Open: " + openMU.ToString("0.0") + " MU\r\n  " + beam.MetersetPerGy.ToString("0.0") + " MU/Gy\r\n";
                        if (beam.MetersetPerGy > 300 && !isSplit)
                        {
                            p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För många MU/Gy";
                        }
                        else if (beam.MetersetPerGy > 550 && isSplit)
                        {
                            p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För många MU/Gy";
                        }
                    }
                    else
                    {
                        p9_value_detailed += "  Open: " + openMU.ToString("0.0") + ", Wedged: " + wedgedMU.ToString("0.0") + "\r\n";
                    }
                    p9_value_detailed += "  Energi: " + beam.EnergyModeDisplayName + "\r\n\r\n";

                    /*
                     * if (openMU < 10 && openMU != 0 || wedgedMU < 30 && wedgedMU != 0)
                     *  p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För få MU";
                     * if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta && openMU + wedgedMU > 999)
                     *  p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För många MU";
                     */
                    if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta)
                    {
                        if (openMU + wedgedMU > 999)
                        {
                            p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För många MU";
                        }
                        if (openMU < 10 && openMU != 0 || wedgedMU < 30 && wedgedMU != 0)
                        {
                            p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För få MU";
                        }
                    }
                    else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
                    {
                        if (openMU < 10 && wedgedMU == 0 || wedgedMU != 0 && openMU + wedgedMU < 20)
                        {
                            p9_value += (p9_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": För få MU";
                        }
                    }
                }
            }
            if (p9_value.Length > 0)
            {
                if (checklistType == ChecklistType.EclipseVMAT)
                {
                    p9_status = AutoCheckStatus.WARNING;
                }
                else
                {
                    p9_status = AutoCheckStatus.FAIL;
                }
                p9_value = reorderBeamParam(p9_value, ",");
            }

            p9_value_detailed = reorderBeamParam(p9_value_detailed, "\r\n\r\n");
            checklistItems.Add(new ChecklistItem("P9. Fälten ser rimliga ut vad gäller form, energi, MU och korrektion av artefakter", "Kontrollera att fälten ser rimliga ut vad gäller form, energi, MU och korrektion av artefakter\r\n  • Riktlinje för RapidArc är max 300 MU/Gy om bländarna är utanför target under hela varvet (sett ur BEV). Vid delvis skärmat target är denna gräns max 550 MU/Gy.\r\n  • Öppna fält ska ha ≥10 MU.\r\n  • Fält med dynamisk kil (Varian) ska ha minst 20 MU.\r\n  • Fält med fast kil (Elekta) ska ha ≥30 kilade MU.\r\n  •  För Elekta gäller dessutom att totala antalet MU per fält (öppet + kilat) ej får överstiga 999 MU.", p9_value, p9_value_detailed, p9_status));

            if (checklistType != ChecklistType.EclipseVMAT && checklistType != ChecklistType.EclipseConformal)
            {
                if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta)
                {
                    AutoCheckStatus p10_status = AutoCheckStatus.UNKNOWN;
                    string          p10_value  = ElektaMLCCheck(planSetup);
                    //p10_status = CheckResult(String.Compare(p10_value, "MLC positioner OK.", true) == 0);
                    if (String.Compare(p10_value, "Fält levererbara.", true) == 0)
                    {
                        p10_status = AutoCheckStatus.PASS;
                    }
                    if (p10_value.IndexOf("ej levererbara") > 0)
                    {
                        p10_status = AutoCheckStatus.FAIL;
                    }
                    else if (p10_value.IndexOf("ej optimala") > 0)
                    {
                        p10_status = AutoCheckStatus.WARNING;
                    }
                    if (p10_status == AutoCheckStatus.WARNING)
                    {
                        var p10_values = p10_value.Split('.').ToList();
                        p10_values[1] = reorderBeamParam(p10_values[1], ",");
                        p10_value     = String.Join <string>(". ", p10_values);
                    }

                    checklistItems.Add(new ChecklistItem("P10. MLC:n är indragen till X-bländare, och ett/två blad är öppna utanför Y-bländare", "Kontrollera att MLC:n är indragen till X-bländare eller innanför, och att ett helt bladpar är öppet utanför Y-bländare på resp. sida om Y1 resp. Y2 har decimal 0,7, 0,8 eller 0,9.", p10_value, p10_status));
                }
                else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
                {
                    AutoCheckStatus p10_status = AutoCheckStatus.UNKNOWN;
                    string          p10_value  = string.Empty;
                    foreach (Beam beam in planSetup.Beams)
                    {
                        string MLCcheck = VarianMLCCheck(beam);
                        if (MLCcheck.Length > 0)
                        {
                            p10_value += (p10_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + VarianMLCCheck(beam);
                        }
                    }
                    if (p10_value.Length > 0)
                    {
                        p10_status = AutoCheckStatus.WARNING;
                        p10_value  = reorderBeamParam(p10_value, ",");
                    }
                    else
                    {
                        p10_status = AutoCheckStatus.PASS;
                    }
                    checklistItems.Add(new ChecklistItem("P10. MLC:n är indragen till X-bländare", "Kontrollera att MLC:n är indragen till X-bländare eller innanför", p10_value, p10_status));
                }
            }

            string          p11_value  = "Metod: " + planSetup.PlanNormalizationMethod + ", target: " + planSetup.TargetVolumeID + ", prescribed percentage: " + (planSetup.PrescribedPercentage * 100.0).ToString("0.0") + ", värde: " + planSetup.PlanNormalizationValue.ToString("0.0");
            AutoCheckStatus p11_status = AutoCheckStatus.MANUAL;

            if (planSetup.PlanNormalizationMethod.Equals("No plan normalization", StringComparison.OrdinalIgnoreCase))
            {
                p11_status = AutoCheckStatus.FAIL;
            }
            double normLimitVMAT = 3.0;

            if (checklistType == ChecklistType.EclipseVMAT && Math.Abs(planSetup.PlanNormalizationValue - 100) > normLimitVMAT)
            {
                p11_status = AutoCheckStatus.FAIL;
            }
            if (planSetup.PlanNormalizationMethod.IndexOf("100% in Isocenter of") == -1 && checklistType == ChecklistType.EclipseConformal)
            {
                p11_status = AutoCheckStatus.FAIL;
            }
            checklistItems.Add(new ChecklistItem("P11. Normering är korrekt", "Kontrollera att planen är normerad på korrekt vis \r\n  • Icke-normerade planer accepteras ej. \r\n  • Normalt till targetvolymens mediandos (om särskilt skäl föreligger kan en punktnormering användas). \r\n  • För stereotaktiska lungor i Eclipse normeras dosen till isocenter och ordineras till 75%-isodosen.\r\n  • För stereotaktiska behandlingar av skelettmetastaser ska planen normeras så att 95% av PTV-volymen erhåller ordinerad dos (normal 30 Gy). \r\n  • För VMAT ska Plan Normalization Value skall normeringsvärdet vara i intervallet [0.970, 1.030].", p11_value, p11_status));

            string                p12_value               = string.Empty;
            string                p13_value               = string.Empty;
            string                p13_value_detailed      = string.Empty;
            AutoCheckStatus       p13_status              = AutoCheckStatus.WARNING;
            List <ReferencePoint> referencePoints         = new List <ReferencePoint>();
            List <double>         referencePointDose      = new List <double>();
            List <double>         referencePointTotalDose = new List <double>();
            List <int>            activeReferencePoints   = new List <int>();

            // Get dose to reference points in active course
            foreach (PlanSetup planSetupInCourse in course.PlanSetups)
            {
                if (planSetupInCourse.ApprovalStatus != PlanSetupApprovalStatus.UnApproved && planSetupInCourse.ApprovalStatus != PlanSetupApprovalStatus.Rejected)
                {
                    foreach (Beam beam in planSetupInCourse.Beams)
                    {
                        foreach (FieldReferencePoint fieldReferencePoint in beam.FieldReferencePoints)
                        {
                            int referencePointIndex = -1;
                            for (int refPointNr = 0; refPointNr < referencePoints.Count; refPointNr++)
                            {
                                if (string.Compare(fieldReferencePoint.ReferencePoint.Id, referencePoints[refPointNr].Id) == 0)
                                {
                                    referencePointIndex = refPointNr;
                                    break;
                                }
                            }
                            if (referencePointIndex == -1)
                            {
                                referencePointIndex = referencePoints.Count;
                                referencePoints.Add(fieldReferencePoint.ReferencePoint);
                                referencePointDose.Add(0.0);
                                referencePointTotalDose.Add(0.0);
                            }
                            referencePointTotalDose[referencePointIndex] += fieldReferencePoint.FieldDose.Dose * (planSetupInCourse.UniqueFractionation == null ? double.NaN : (double)planSetupInCourse.UniqueFractionation.NumberOfFractions);
                            if (planSetupInCourse == planSetup)
                            {
                                referencePointDose[referencePointIndex] += fieldReferencePoint.FieldDose.Dose;
                                if (activeReferencePoints.Contains(referencePointIndex) == false)
                                {
                                    activeReferencePoints.Add(referencePointIndex);
                                }
                            }
                        }
                    }
                }
            }
            int p13_numberOfPass = 0;

            for (int refPointNr = 0; refPointNr < referencePoints.Count; refPointNr++)
            {
                p13_value_detailed += (p13_value_detailed.Length == 0 ? string.Empty : "\r\n\r\n") + referencePoints[refPointNr].Id + ":\r\n";

                double totalDoseLimit   = double.NaN;
                double dailyDoseLimit   = double.NaN;
                double sessionDoseLimit = double.NaN;

                DataTable dataTableRefPointLimits = AriaInterface.Query("select distinct RefPoint.RefPointId,RefPoint.TotalDoseLimit,RefPoint.DailyDoseLimit,RefPoint.SessionDoseLimit from PlanSetup,Radiation,RadiationRefPoint,RefPoint where RadiationRefPoint.RefPointSer=RefPoint.RefPointSer and RadiationRefPoint.RadiationSer=Radiation.RadiationSer and PlanSetup.PlanSetupSer=Radiation.PlanSetupSer and PlanSetup.CourseSer=" + courseSer.ToString() + " and RefPoint.RefPointId='" + referencePoints[refPointNr].Id + "'");
                if (dataTableRefPointLimits.Rows.Count == 1)
                {
                    totalDoseLimit   = (dataTableRefPointLimits.Rows[0][1] == DBNull.Value ? totalDoseLimit = double.NaN : totalDoseLimit = (double)dataTableRefPointLimits.Rows[0][1]);
                    dailyDoseLimit   = (dataTableRefPointLimits.Rows[0][2] == DBNull.Value ? dailyDoseLimit = double.NaN : dailyDoseLimit = (double)dataTableRefPointLimits.Rows[0][2]);
                    sessionDoseLimit = (dataTableRefPointLimits.Rows[0][3] == DBNull.Value ? sessionDoseLimit = double.NaN : sessionDoseLimit = (double)dataTableRefPointLimits.Rows[0][3]);
                }
                p13_value_detailed += "  Dosbidrag från aktuell plan: " + (fractionation == null ? double.NaN : referencePointDose[refPointNr] * (double)fractionation.NumberOfFractions).ToString("0.000") + " Gy, " + referencePointDose[refPointNr].ToString("0.000") + " Gy/fr " + " (Total dose limit: " + totalDoseLimit.ToString("0.000") + " Gy, daily limit: " + dailyDoseLimit.ToString("0.000") + " Gy, session limit: " + sessionDoseLimit.ToString("0.000") + " Gy)\r\n";
                p13_value_detailed += "  Totalt dosbidrag från samtliga godkändaplaner: " + referencePointTotalDose[refPointNr].ToString("0.000") + " Gy " + " (Total limit: " + totalDoseLimit.ToString("0.000") + " Gy)";

                if (activeReferencePoints.Contains(refPointNr)) // Reference point is present in the active plan
                {
                    p12_value += (p12_value.Length == 0 ? string.Empty : ", ") + referencePoints[refPointNr].Id + ": " + referencePointDose[refPointNr].ToString("0.000") + " Gy";
                    p13_value += (p13_value.Length == 0 ? string.Empty : ", ") + referencePoints[refPointNr].Id + ": (T:" + totalDoseLimit.ToString("0.000") + "/D:" + dailyDoseLimit.ToString("0.000") + "/S:" + sessionDoseLimit.ToString("0.000") + " Gy)";

                    if (Math.Round(referencePointDose[refPointNr], 3) <= Math.Round(dailyDoseLimit, 3) &&
                        Math.Round(referencePointDose[refPointNr], 3) <= Math.Round(sessionDoseLimit, 3) &&
                        Math.Round(referencePointTotalDose[refPointNr], 3) == Math.Round(totalDoseLimit, 3))
                    {
                        p13_numberOfPass++;
                    }
                }
            }
            if (activeReferencePoints.Count > 0 && p13_numberOfPass == activeReferencePoints.Count)
            {
                p13_status = AutoCheckStatus.MANUAL;
            }
            checklistItems.Add(new ChecklistItem("P12. Referenspunkternas dosbidrag är korrekta", "Kontrollera att dosbidrag till referenspunkter (dos) är korrekta:\r\n  • Varje plan ska ha en punkt (primary reference point) som summerar upp till ordinerad dos för det största PTV som planen primärt behandlar.\r\n  • Om flera planer bidrar med dos till samma targetvolymer eller om en plan bidrar med dos till flera targetvolymer ska det finnas referenspunkter utan lokalisation i alla planer som summerar dosen till dessa volymer.\r\n  • Referenspunkterna ska inte ha dosbidrag från tidigare behandlingar.", p12_value, AutoCheckStatus.MANUAL));
            checklistItems.Add(new ChecklistItem("P13. Referenspunkternas gränser är korrekta", "Kontrollera att referenspunkternas gränser (dos) är korrekta", p13_value, p13_value_detailed, p13_status));

            if (checklistType == ChecklistType.Eclipse || checklistType == ChecklistType.EclipseGating)
            {
                checklistItems.Add(new ChecklistItem("P14. Skarven är flyttad korrekt för skarvplan", "Skarvplaner: Skarven är flyttad korrekt och fälten är i övrigt likadana\r\n  • Bröstbehandlingar med kollimator i 0° för både huvudfält i fossa- och tang.-fält flyttas endast om eventuellt PTV_66 ligger i skarven.", string.Empty, AutoCheckStatus.MANUAL));
            }


            AutoCheckStatus p15_status       = AutoCheckStatus.UNKNOWN;
            string          p15_value        = string.Empty;
            int             p15_numberOfPass = 0;
            List <string>   machineId        = new List <string>();

            foreach (Beam beam in planSetup.Beams)
            {
                machineId.Add(beam.TreatmentUnit.Id);
                if (String.Equals(beam.TreatmentUnit.ToString(), planSetup.Beams.First().TreatmentUnit.ToString()))
                {
                    p15_numberOfPass += 1;
                }
                p15_value += (p15_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + beam.TreatmentUnit.Id;
            }
            if (p15_numberOfPass == numberOfBeams)
            {
                p15_status = AutoCheckStatus.PASS;
            }
            else
            {
                p15_status = AutoCheckStatus.FAIL;
            }
            p15_value = reorderBeamParam(p15_value, ",");
            checklistItems.Add(new ChecklistItem("P15. Konsekvent maskinval", "Kontrollera att samtliga fält är planerade till en och samma behandlingsapparat.", p15_value, p15_status));

            AutoCheckStatus p16_status           = AutoCheckStatus.UNKNOWN;
            string          p16_value            = string.Empty;
            string          p16_value_detailed   = "Följande bokningar är aktiva:\r\n";
            string          treatMachineIdCommon = machineId.ToArray().GroupBy(v => v)
                                                   .OrderByDescending(g => g.Count())
                                                   .First()
                                                   .Key;

            p16_value = "Planerat: " + treatMachineIdCommon + (machineId.Distinct().Count() == 1 ? " (enhetligt)" : " (tvetydigt)");
            DateTime      date                  = DateTime.Now;
            List <string> bookedMachineId       = new List <string>();
            string        bookedMachineIdCommon = string.Empty;
            //DataTable bookings = AriaInterface.Query("select x.MachineId, x.ScheduledStartTime from (SELECT DISTINCT Patient.PatientSer, Patient.PatientId, ScheduledActivity.ActualEndDate,ScheduledActivity.ScheduledActivityCode, ScheduledActivity.ActivityInstanceSer,Machine.MachineId,ScheduledActivity.ScheduledStartTime, ScheduledActivity.ObjectStatus FROM ScheduledActivity,Attendee,Patient,Machine WHERE Patient.PatientId = " + patient.Id.ToString() + " AND ScheduledActivity.ObjectStatus='Active' AND ScheduledActivity.ScheduledActivityCode = 'Open' AND ScheduledActivity.PatientSer=Patient.PatientSer AND Attendee.ActivityInstanceSer=ScheduledActivity.ActivityInstanceSer AND Machine.ResourceSer=Attendee.ResourceSer and ScheduledActivity.ScheduledStartTime > '" + date.ToString("yyyy-MM-dd") + " 00:00:00') as x where PatientId = '" + patient.Id.ToString() + "' ORDER BY ScheduledStartTime");
            DataTable bookings = AriaInterface.Query("SELECT DISTINCT Patient.PatientSer, Patient.PatientId, ScheduledActivity.ActualEndDate,ScheduledActivity.ScheduledActivityCode, ScheduledActivity.ActivityInstanceSer,Machine.MachineId,ScheduledActivity.ScheduledStartTime, ScheduledActivity.ObjectStatus FROM ScheduledActivity,Attendee,Patient,Machine,ActivityInstance,Activity,ActivityCategory WHERE Patient.PatientId = '" + patient.Id.ToString() + "' AND ScheduledActivity.ObjectStatus='Active' AND ScheduledActivity.ScheduledActivityCode = 'Open' AND ScheduledActivity.PatientSer=Patient.PatientSer AND Attendee.ActivityInstanceSer=ScheduledActivity.ActivityInstanceSer AND Attendee.ObjectStatus='Active' AND Machine.MachineType = 'RadiationDevice' AND Machine.ResourceSer=Attendee.ResourceSer AND ActivityInstance.ActivityInstanceSer=ScheduledActivity.ActivityInstanceSer AND Activity.ActivitySer=ActivityInstance.ActivitySer AND ActivityCategory.ActivityCategorySer = Activity.ActivityCategorySer AND ActivityCategory.ActivityCategoryCode = 'Treatment' AND ScheduledActivity.ScheduledStartTime > '" + date.ToString("yyyy-MM-dd") + " 00:00:00' ORDER BY ScheduledStartTime");

            if (bookings.Rows.Count > 0)
            {
                foreach (DataRow row in bookings.Rows)
                {
                    bookedMachineId.Add((string)row["MachineId"]);
                    p16_value_detailed += (string)row["ScheduledStartTime"].ToString() + ": " + (string)row["MachineId"] + "\r\n";
                }
                bookedMachineIdCommon = bookedMachineId.ToArray().GroupBy(v => v)
                                        .OrderByDescending(g => g.Count())
                                        .First()
                                        .Key;
                p16_value += ", Bokat: " + bookedMachineIdCommon + (bookedMachineId.Distinct().Count() == 1 ? " (enhetligt)" : " (tvetydigt)");
                if (String.Equals(treatMachineIdCommon, bookedMachineIdCommon, StringComparison.OrdinalIgnoreCase) && bookedMachineId.Distinct().Count() == 1 && machineId.Distinct().Count() == 1)
                {
                    p16_status = AutoCheckStatus.PASS;
                }
                else if (String.Equals(treatMachineIdCommon, bookedMachineIdCommon, StringComparison.OrdinalIgnoreCase))
                {
                    p16_status = AutoCheckStatus.MANUAL;
                }
                else
                {
                    p16_status = AutoCheckStatus.FAIL;
                }
            }
            else
            {
                p16_value += ", Bokat: -";
                p16_status = AutoCheckStatus.WARNING;
            }

            checklistItems.Add(new ChecklistItem("P16. Konsekvens mellan planerad och bokad behandlingsapparat.", "Kontrollera att patienten är bokad till den behandlingsapparat som planen är planerad för.", p16_value, p16_value_detailed, p16_status));
        }
Example #12
0
        public void B()
        {
            checklistItems.Add(new ChecklistItem("B. Bolus"));

            string          b1_value  = string.Empty;
            AutoCheckStatus b1_status = AutoCheckStatus.UNKNOWN;

            if (planSetup.StructureSet != null)
            {
                bool tpsBolusExist         = false;
                bool tpsBolusLinkedToField = false;
                foreach (Structure structure in planSetup.StructureSet.Structures)
                {
                    if (string.Compare(structure.DicomType, "BOLUS") == 0)
                    {
                        tpsBolusExist = true;
                    }
                }
                foreach (Beam b in planSetup.Beams)
                {
                    if (b.Boluses.Count() > 0)
                    {
                        tpsBolusLinkedToField = true;
                    }
                }
                if (!tpsBolusExist)
                {
                    b1_value  = "Ej ansatt";
                    b1_status = AutoCheckStatus.PASS;
                }
                else if (tpsBolusExist && !tpsBolusLinkedToField)
                {
                    b1_value  = "Bolus har ansatts i TPS, men ej kopplats till minst ett fält. Verifera.";
                    b1_status = AutoCheckStatus.WARNING;
                }
                else if (tpsBolusExist && tpsBolusLinkedToField)
                {
                    b1_value = "Bolus har ansatts i TPS, och kopplats till minst ett fält. Verifiera.";
                }
            }
            else
            {
                b1_value = "StructureSet saknas";
            }
            checklistItems.Add(new ChecklistItem("B1. I dosplaneringssystemet ansatt bolus är med i beräkningen", "Kontrollera att bolus som ansatts i dosplaneringssystemet är med i beräkningen (kopplat till resp. fält)", b1_value, b1_status));

            AutoCheckStatus b2_status = AutoCheckStatus.MANUAL;
            string          b2_value  = string.Empty;

            // Check against prescription
            if (prescSer > 0)
            {
                DataTable bolus = AriaInterface.Query("select PlanSetupSer, PlanSetup.PrescriptionSer, Prescription.PrescriptionSer, BolusFrequency, BolusThickness from PlanSetup, Prescription where PlanSetup.PrescriptionSer = Prescription.PrescriptionSer and PlanSetup.PlanSetupSer = " + planSetupSer.ToString());
                if (bolus.Rows.Count > 0)
                {
                    b2_value += (bolus.Rows[0][3] == DBNull.Value ? string.Empty : (string)bolus.Rows[0][3]);
                    b2_value += (b2_value.Length == 0 ? string.Empty : ", ") + (bolus.Rows[0][4] == DBNull.Value ? string.Empty : (string)bolus.Rows[0][4]);
                }

                if (String.IsNullOrWhiteSpace(b2_value))
                {
                    b2_value = "Information saknas";
                }
            }
            else
            {
                b2_status = AutoCheckStatus.WARNING;
                b2_value  = "Ordination saknas, kontroll ej möjlig.";
            }
            checklistItems.Add(new ChecklistItem("B2. Ordinationen innehåller information om bolus", "Kontrollera att bolus finns angivet i ordinationen (aktuell tjocklek och bolustyp).", b2_value, b2_status));
        }
Example #13
0
        private void GetFieldSizeGridSize(PlanSetup planSetup, double lim, ChecklistType checklistType, out string outText, out AutoCheckStatus checkstatusOut) // Section for controlling field size in all types of plans Lim in mm!
        {
            //Note Lim is in mm!
            //This part checks the size of the fields.
            outText        = string.Empty;
            checkstatusOut = AutoCheckStatus.MANUAL;
            string calcSize;
            int    tol       = 25;
            bool   isOverTol = false;

            foreach (Beam beam in planSetup.Beams)
            {
                if (!beam.IsSetupField)
                {
                    var    xSz   = beam.ControlPoints.Select(i => Math.Abs(i.JawPositions.X2 - i.JawPositions.X1));
                    var    ySz   = beam.ControlPoints.Select(i => Math.Abs(i.JawPositions.Y2 - i.JawPositions.Y1));
                    double percX = 0;
                    double percY = 0;

                    if (xSz.Min() < lim)
                    {
                        percX = (double)xSz.Where(v => v <= lim).Count() / (double)xSz.Count() * 100;
                    }
                    if (ySz.Min() < lim)
                    {
                        percY = (double)ySz.Where(v => v <= lim).Count() / (double)ySz.Count() * 100;
                    }
                    if (percX > 0 || percY > 0)
                    {
                        if (checklistType == ChecklistType.Eclipse || checklistType == ChecklistType.EclipseGating)
                        {
                            outText += (String.IsNullOrEmpty(outText) ? "" : ", ") + beam.Id + ": " + (percX > 0 ? "X-kollimator < " + lim + " mm" : "") + (percY > 0 ? " Y-kollimator < " + lim + " mm" : "");
                        }
                        else
                        {
                            outText += (String.IsNullOrEmpty(outText) ? "" : ", ") + beam.Id + ": " + (percX > 0 ? "X-kollimator < " + lim + " mm i " + percX.ToString("0.0") + "% av segmenten" : "") + (percY > 0 ? " Y-kollimator < " + lim + " mm i " + percY.ToString("0.0") + "% av segmenten" : "");
                        }
                        if (percX > tol || percY > tol)
                        {
                            isOverTol = true;
                        }
                    }
                }
            }
            if (!planSetup.PhotonCalculationOptions.TryGetValue("CalculationGridSizeInCM", out calcSize))
            {
                outText        = "Ingen beräkningsupplösning " + outText;
                checkstatusOut = AutoCheckStatus.FAIL;
            }
            else
            {
                //Ger följande utfall
                if (calcSize == "0.1" && !String.IsNullOrEmpty(outText)) // outText är ej tom, dvs någon del av något fält < lim mm. Då skall Algoritmen
                {
                    checkstatusOut = AutoCheckStatus.PASS;
                }
                else if (calcSize == "0.25" && String.IsNullOrEmpty(outText))
                {
                    checkstatusOut = AutoCheckStatus.PASS;
                }
                else if (calcSize == "0.25" && !String.IsNullOrEmpty(outText))
                {
                    if (isOverTol) // if more than 25 % of the segments are less than the set value lim this will give a fail, else Warning.
                    {
                        checkstatusOut = AutoCheckStatus.FAIL;
                    }
                    else
                    {
                        checkstatusOut = AutoCheckStatus.WARNING;
                    }
                }

                else if (calcSize == "0.1" && String.IsNullOrEmpty(outText))
                {
                    checkstatusOut = AutoCheckStatus.WARNING;
                    outText        = ", Rekommenderat med 0.25 cm för fält > " + lim / 10 + " cm.";
                }
                outText = calcSize + " cm. " + outText;
            }
            //return new Tuple<string, AutoCheckStatus>(outText, checkstatusOut);
        }
Example #14
0
        public void U() // The name U is kept for historical reasons. Might change to R in future versions.
        {
            checklistItems.Add(new ChecklistItem("R. Remiss/Ordination"));

            string r1_imageid = string.Empty;

            if (planSetup.StructureSet != null && planSetup.StructureSet.Image != null)
            {
                r1_imageid = planSetup.StructureSet.Image.Id;
            }
            string    r1_value        = "Personnummer: " + patient.Id + ", Course: " + course.Id + ", Plan: " + planSetup.Id + ", CT: " + (image == null ? "-" : image.Id);
            string    r1_value_detail = string.Empty;
            DataTable remarks         = AriaInterface.Query("select Image.ImageNotes from Image, Series where Series.SeriesUID = '" + image.Series.UID.ToString() + "' and Image.SeriesSer = Series.SeriesSer and Image.ImageType = 'Image' and Image.ImageId = '" + image.Id.ToString() + "'");

            if (remarks.Rows.Count == 1 && remarks.Rows[0][0] != DBNull.Value)
            {
                r1_value_detail = (string)remarks.Rows[0][0];
                checklistItems.Add(new ChecklistItem("R1. Jämför id (course, plan, CT-set, patient) mellan remiss, protokoll och Aria", "Kontrollera att \r\n  • Patientens personnummer stämmer överens mellan remiss och Aria\r\n  • Course, plannamn och CT-set stämmer överens mellan protokoll och Aria.", r1_value, r1_value_detail, AutoCheckStatus.MANUAL));
            }
            else
            {
                checklistItems.Add(new ChecklistItem("R1. Jämför id (course, plan, CT-set, patient) mellan remiss, protokoll och Aria", "Kontrollera att \r\n  • Patientens personnummer stämmer överens mellan remiss och Aria\r\n  • Course, plannamn och CT-set stämmer överens mellan protokoll och Aria.", r1_value, AutoCheckStatus.MANUAL));
            }

            AutoCheckStatus r2_status                  = AutoCheckStatus.FAIL;
            string          r2_value                   = string.Empty;
            string          r2_value_detail            = string.Empty;
            string          prescriptionVolume         = string.Empty;
            long            prescriptionAnatomySer     = long.MinValue;
            bool            guessedVolume              = false;
            bool            multiplePrescriptionLevels = false;
            string          planningVolume             = string.Empty;

            DataTable planning = AriaInterface.Query("select distinct PlanSetupSer, PrimaryPTVSer, PatientVolumeSer, StructureId from PlanSetup, Structure where PlanSetup.PlanSetupSer = " + planSetupSer.ToString() + "  and PlanSetup.PrimaryPTVSer = Structure.PatientVolumeSer");

            if (planning.Rows.Count == 1 && planning.Rows[0][3] != DBNull.Value)
            {
                planningVolume = (string)planning.Rows[0][3];
            }
            DataTable prescription = AriaInterface.Query("select distinct PlanSetupSer, PlanSetup.PrescriptionSer, PrescriptionAnatomy.PrescriptionSer, PrescriptionAnatomy.PrescriptionAnatomySer, PrescriptionAnatomyItem.PrescriptionAnatomySer, ItemType, ItemValue, Prescription.Status, Prescription.PrescriptionSer, Prescription.PrescriptionName, Prescription.Notes from PlanSetup, Prescription, PrescriptionAnatomy, PrescriptionAnatomyItem where PlanSetup.PlanSetupSer = " + planSetupSer.ToString() + " and PlanSetup.PrescriptionSer = PrescriptionAnatomy.PrescriptionSer and PrescriptionAnatomy.PrescriptionAnatomySer = PrescriptionAnatomyItem.PrescriptionAnatomySer and PrescriptionAnatomyItem.ItemType = 'VOLUME ID' and PlanSetup.PrescriptionSer = Prescription.PrescriptionSer");

            if (prescription.Rows.Count > 0 && prescription.Rows[0][6] != DBNull.Value)
            {
                //string volumeName = string.Empty;
                string prescriptionStatus = (string)prescription.Rows[0][7];
                string prescriptionName   = (string)prescription.Rows[0][9];
                r2_value_detail = (string)prescription.Rows[0][10];

                if (prescription.Rows.Count == 1)
                {
                    prescriptionVolume     = (string)prescription.Rows[0][6];
                    prescriptionAnatomySer = (long)prescription.Rows[0][3];
                }

                /*
                 * else
                 * {
                 *  multiplePrescriptionLevels = true;
                 *  foreach (DataRow row in prescription.Rows)
                 *  {
                 *      string volumeName = (string)row[6];
                 *      if (volumeName.IndexOf(planningVolume) == 0 && planningVolume.Length > 1)
                 *      {
                 *          prescriptionVolume = (string)row[6];
                 *          prescriptionAnatomySer = (long)row[3];
                 *          guessedVolume = true;
                 *          break;
                 *      }
                 *  }
                 * }
                 */

                r2_status = CheckResult(string.Compare(prescriptionStatus, "Approved") == 0);
                r2_value  = prescriptionName + ": " + prescriptionStatus;
            }
            else if (prescription.Rows.Count == 0)
            {
                r2_value = "Ordination saknas";
            }
            checklistItems.Add(new ChecklistItem("R2. Status på kopplad ordination.", "Kontrollera att planen är kopplad till en ordination kopplad vars status 'Approved'.", r2_value, r2_value_detail, r2_status));

            if (r2_status == AutoCheckStatus.PASS)
            {
                string r3_value;

                /*
                 * AutoCheckStatus r3_status = AutoCheckStatus.MANUAL;
                 * if (multiplePrescriptionLevels == true && guessedVolume == false)
                 * {
                 *  r3_value = "Multipla ordinationsvolymer existerar. Ingen matchar den planerade volymen. ";
                 *  r3_status = AutoCheckStatus.MANUAL;
                 * }
                 * else if (multiplePrescriptionLevels == true && guessedVolume == true)
                 * {
                 *  r3_value = "Multipla ordinationsvolymer existerar. Följande matchar den planerade volymen: " + prescriptionVolume + ", ";
                 *  r3_status = AutoCheckStatus.MANUAL;
                 * }
                 * else
                 * {
                 *  r3_value = "Ordinerad volym: " + prescriptionVolume + ", ";
                 *  if (prescriptionVolume.IndexOf(planningVolume) == 0 && planningVolume.Length > 1) // maybe this is too nice. Perhaps it should be a String.Compare. Possibly with a string split for prescritonVolume (using :)
                 *      r3_status = AutoCheckStatus.PASS;
                 *  else
                 *      r3_status = AutoCheckStatus.WARNING;
                 * }
                 * r3_value += "Planerad volym: " + (planningVolume == string.Empty ? "-" : planningVolume);
                 * checklistItems.Add(new ChecklistItem("R3. Kontrollera att ordinerad volym stämmer överens med planerad volym.", "Kontrollera att volymen som planens primära referenspunkt tillhör motsvarar den volym som det är ordinerat till.", r3_value, r3_status));
                 */
                if (prescription.Rows.Count > 1)
                {
                    r3_value = "Ordinerade volymer: ";
                }
                else
                {
                    r3_value = "Ordinerad volym: ";
                }
                foreach (DataRow row in prescription.Rows)
                {
                    r3_value += (string)row[6] + ", ";
                }
                r3_value += "Planerad volym: " + (planningVolume == string.Empty ? "-" : planningVolume);
                r3_value.Replace(", Planerad volym", "; Planerad volym");
                checklistItems.Add(new ChecklistItem("R3. Ordinerad volym stämmer överens med planerad volym.", "Kontrollera att volymen som planens primära referenspunkt tillhör motsvarar den volym som det är ordinerat till.", r3_value, AutoCheckStatus.MANUAL));

                AutoCheckStatus r4_status         = AutoCheckStatus.UNKNOWN;
                string          r4_value          = string.Empty;
                string          r4_value_detailed = string.Empty;
                if (prescription.Rows.Count == 1)
                {
                    int       numberOfFractions = int.MinValue;
                    double    dosePerFraction   = double.NaN;
                    double    totalDose         = double.NaN;
                    DataTable prescriptionItem  = AriaInterface.Query("select NumberOfFractions, ItemType, ItemValue, PrescriptionAnatomyItem.PrescriptionAnatomySer, PrescriptionAnatomy.PrescriptionAnatomySer, PrescriptionAnatomy.PrescriptionSer, Prescription.PrescriptionSer  from Prescription, PrescriptionAnatomy, PrescriptionAnatomyItem where PrescriptionAnatomy.PrescriptionAnatomySer = " + prescriptionAnatomySer.ToString() + " and PrescriptionAnatomy.PrescriptionAnatomySer = PrescriptionAnatomyItem.PrescriptionAnatomySer and PrescriptionAnatomy.PrescriptionSer = Prescription.PrescriptionSer");
                    if (prescriptionItem.Rows.Count > 0)
                    {
                        numberOfFractions = (int)prescriptionItem.Rows[0]["NumberOfFractions"];
                        foreach (DataRow row in prescriptionItem.Rows)
                        {
                            if (String.Equals((string)row["ItemType"], "Total dose", StringComparison.OrdinalIgnoreCase))
                            {
                                double.TryParse((string)row["ItemValue"], out totalDose);
                            }
                            if (String.Equals((string)row["ItemType"], "Dose per fraction", StringComparison.OrdinalIgnoreCase))
                            {
                                double.TryParse((string)row["ItemValue"], out dosePerFraction);
                            }
                        }
                        r4_value          = "Ordination: " + dosePerFraction.ToString("0.000") + " Gy * " + numberOfFractions.ToString() + " = " + totalDose.ToString("0.000") + " Gy";
                        r4_value_detailed = "Ordination: \r\n  • Volym: " + prescriptionVolume + "\r\n  • Fraktionsdos: " + dosePerFraction.ToString("0.000") + " Gy \r\n  • Antal fraktioner: " + numberOfFractions.ToString() + "\r\n  • Totaldos: " + totalDose.ToString("0.000") + " Gy\r\n";
                    }
                    if (fractionation != null)
                    {
                        r4_value += (r4_value == null ? "Ordination: - , " : ", ") + "Planerat: " + fractionation.PrescribedDosePerFraction.ToString() + " * " + fractionation.NumberOfFractions.ToString() + " = " + planSetup.TotalPrescribedDose.ToString();
                        r4_status = CheckResult(numberOfFractions == fractionation.NumberOfFractions && dosePerFraction == fractionation.PrescribedDosePerFraction.Dose && totalDose == planSetup.TotalPrescribedDose.Dose);
                    }
                }
                else
                {
                    r4_status = AutoCheckStatus.MANUAL;
                    if (fractionation != null)
                    {
                        r4_value += (r4_value == string.Empty ? "Ordination: Tvetydigt, " : ", ") + "Planerat: " + fractionation.PrescribedDosePerFraction.ToString() + " * " + fractionation.NumberOfFractions.ToString() + " = " + planSetup.TotalPrescribedDose.ToString();
                    }
                    if (prescription.Rows.Count > 0)
                    {
                        foreach (DataRow row in prescription.Rows)
                        {
                            string    volumeName       = (string)row[6];
                            long      ser              = (long)row[3];
                            double    totalDose        = double.NaN;
                            double    dosePerFraction  = double.NaN;
                            int       nOfFractions     = 0;
                            DataTable prescriptionItem = AriaInterface.Query("select NumberOfFractions, ItemType, ItemValue, PrescriptionAnatomyItem.PrescriptionAnatomySer, PrescriptionAnatomy.PrescriptionAnatomySer, PrescriptionAnatomy.PrescriptionSer, Prescription.PrescriptionSer  from Prescription, PrescriptionAnatomy, PrescriptionAnatomyItem where PrescriptionAnatomy.PrescriptionAnatomySer = " + ser.ToString() + " and PrescriptionAnatomy.PrescriptionAnatomySer = PrescriptionAnatomyItem.PrescriptionAnatomySer and PrescriptionAnatomy.PrescriptionSer = Prescription.PrescriptionSer");
                            if (prescriptionItem.Rows.Count > 0)
                            {
                                nOfFractions = (int)prescriptionItem.Rows[0]["NumberOfFractions"];
                                foreach (DataRow itemRow in prescriptionItem.Rows)
                                {
                                    if (String.Equals((string)itemRow["ItemType"], "Total dose", StringComparison.OrdinalIgnoreCase))
                                    {
                                        double.TryParse((string)itemRow["ItemValue"], out totalDose);
                                    }
                                    if (String.Equals((string)itemRow["ItemType"], "Dose per fraction", StringComparison.OrdinalIgnoreCase))
                                    {
                                        double.TryParse((string)itemRow["ItemValue"], out dosePerFraction);
                                    }
                                }
                            }
                            r4_value_detailed += (r4_value_detailed == string.Empty ? "Ordination: \r\n" : "\r\n") + "  • Volym: " + volumeName + "\r\n  • Fraktionsdos: " + dosePerFraction.ToString("0.000") + " Gy \r\n  • Antal fraktioner: " + nOfFractions.ToString() + "\r\n  • Totaldos: " + totalDose.ToString("0.000") + " Gy\r\n";
                        }
                    }
                }
                if (fractionation == null)
                {
                    r4_status = AutoCheckStatus.FAIL;
                }
                else
                {
                    r4_value_detailed += (r4_value_detailed == string.Empty ? "" : "\r\n") + "Planerat: \r\n  • Volym: " + planningVolume + "\r\n  • Fraktionsdos: " + fractionation.PrescribedDosePerFraction.ToString() + "\r\n  • Antal fraktioner: " + fractionation.NumberOfFractions.ToString() + "\r\n  • Totaldos: " + planSetup.TotalPrescribedDose.ToString();
                }
                checklistItems.Add(new ChecklistItem("R4. Planen är konsekvent med vad som ordinerats.", "Kontrollera att planen är konsekvent med vad som ordinerats gällande: \r\n  • Fraktionsdos\r\n  • Antal fraktioner\r\n  • Totaldos", r4_value, r4_value_detailed, r4_status));
            }
        }
Example #15
0
 public static bool Passed(this AutoCheckStatus checkStatus)
 {
     return(checkStatus == AutoCheckStatus.PASS);
 }
Example #16
0
        public void D()
        {
            checklistItems.Add(new ChecklistItem("D. Dosberäkning"));

            string d1_value = planSetup.PhotonCalculationModel;

            if (d1_value.Length == 0)
            {
                d1_value = "-";
            }
            AutoCheckStatus d1_status = CheckResult(string.Compare(d1_value, "AAA_13.6.23") == 0);

            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                d1_status = AutoCheckStatus.UNKNOWN;
                checklistItems.Add(new ChecklistItem("D1. Beräkningsalgoritm är korrekt vald", "Kontrollera att korrekt beräkningsalgoritm (PB) har använts vid dosplaneringen.", d1_value, d1_status));
            }
            else
            {
                checklistItems.Add(new ChecklistItem("D1. Beräkningsalgoritm är korrekt vald", "Kontrollera att korrekt beräkningsalgoritm (AAA_13.6.26) har använts vid dosplaneringen.", d1_value, d1_status));
            }

            string d2_value;

            if (!planSetup.PhotonCalculationOptions.TryGetValue("CalculationGridSizeInCM", out d2_value))
            {
                d2_value = "-";
            }
            else
            {
                d2_value += " cm";
            }

            AutoCheckStatus d2_status = CheckResult(string.Compare(d2_value, "0.25 cm") == 0);

            GetFieldSizeGridSize(planSetup, 30, checklistType, out d2_value, out d2_status); //30 är beräsningen satt för kollimatorstorleken.

            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                d2_status = AutoCheckStatus.UNKNOWN;
                checklistItems.Add(new ChecklistItem("D2. Beräkningsupplösningen är korrekt", "Kontrollera att korrekt beräkningsupplösning (0.30 cm) har använts.", d2_value, d2_status));
            }
            else
            {
                checklistItems.Add(new ChecklistItem("D2. Beräkningsupplösningen är korrekt", "Kontrollera att korrekt beräkningsupplösning \r\n• 0.10 cm (fält < 3 cm i > 25% av segmenten) eller \r\n• 0.25 cm har använts.", d2_value, d2_status));
            }

            string d3_value;

            if (!planSetup.PhotonCalculationOptions.TryGetValue("HeterogeneityCorrection", out d3_value))
            {
                d3_value = "-";
            }
            AutoCheckStatus d3_status = CheckResult(string.Compare(d3_value, "ON") == 0);

            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                d3_status = AutoCheckStatus.UNKNOWN;
            }
            checklistItems.Add(new ChecklistItem("D3. Heterogenitetskorrektion har applicerats korrekt", "Kontrollera att heterogenitetskorrektion har använts om ej särskilda skäl föreligger", d3_value, d3_status));

            // VMATFluenceResolution removed from checklist

            /*
             * if (checklistType == ChecklistType.EclipseVMAT)
             * {
             *  string d4_value = string.Empty;
             *  if (!planSetup.PhotonCalculationOptions.TryGetValue("VMATFluenceResolution", out d4_value))
             *      d4_value = "-";
             *  AutoCheckStatus d4_status = CheckResult(string.Compare(d4_value, "High") == 0);
             *  checklistItems.Add(new ChecklistItem("D4. Fluensupplösningen är korrekt", "Kontrollera att korrekt fluensupplösning har använts", d4_value, d4_status));
             * }
             */

            string          d5_value        = string.Empty;
            AutoCheckStatus d5_status       = AutoCheckStatus.UNKNOWN;
            string          couchModel      = string.Empty;
            double          couchSurfaceHU  = double.NaN;
            double          couchInteriorHU = double.NaN;

            if (structureSet != null)
            {
                foreach (Structure structure in structureSet.Structures)
                {
                    double assignedHU;
                    structure.GetAssignedHU(out assignedHU);
                    if (string.Compare(structure.DicomType, "SUPPORT") == 0)
                    {
                        if (structure.Id.IndexOf("Surface") != -1)
                        {
                            structure.GetAssignedHU(out couchSurfaceHU);
                            couchModel = structure.Name;
                        }
                        if (structure.Id.IndexOf("Interior") != -1)
                        {
                            structure.GetAssignedHU(out couchInteriorHU);
                        }
                    }
                }
            }
            // If a patient have had a support structure connected in a previous course, the name of that structure will be maintained even though it is obsolete.
            // Specifically: The substring "Top" was part of the name in 13.0, but disappeared in 13.6. Returning patient treated during 13.0 will have that substring retained.
            // Solution. Replace(" Top".String.Empty)
            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian && string.Compare(couchModel.Replace(" Top", String.Empty), "Exact IGRT Couch, medium") == 0 && couchInteriorHU == -950 && couchSurfaceHU == -300)
            {
                d5_status = AutoCheckStatus.PASS;
            }
            else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta && string.Compare(couchModel.Replace(" Top", String.Empty), "BrainLAB/iBeam Couch") == 0 && couchInteriorHU == -950 && couchSurfaceHU == -300)
            {
                d5_status = AutoCheckStatus.PASS;
            }
            else if (couchModel.Length == 0)
            {
                d5_status  = AutoCheckStatus.WARNING;
                couchModel = "Saknas";
            }
            else
            {
                d5_status = AutoCheckStatus.FAIL;
            }
            // add on test if plan is non coplanar VMAT
            if (checklistType == ChecklistType.EclipseVMAT && GetVMATCoplanar(planSetup) == false)
            {
                d5_status = AutoCheckStatus.MANUAL;
            }
            if (string.Compare(couchModel, "Saknas") == 0)
            {
                d5_value = "Saknas (" + treatmentUnitManufacturer + ")";
            }

            else
            {
                d5_value = "Model: " + couchModel + ", Interior: " + couchInteriorHU.ToString() + " HU, Surface: " + couchSurfaceHU.ToString() + " HU (" + treatmentUnitManufacturer + ")";
            }
            checklistItems.Add(new ChecklistItem("D5. Britsprofil och HU har valts korrekt", "Kontrollera att korrekt britsprofil och korrekta HU valts under Structure Properties för britsstrukturerna och fliken General samt CT Value and Material.\r\n• Varian: Exact IGRT Couch, medium (CouchSurface: -300, CouchInterior: -950)\r\n• Elekta: BrainLAB/iBeam Couch (CouchSurface: -300, CouchInterior: -950)\r\n• Notera att brits inte ska inkluderas för icke coplanara VMAT behandlingar av intra- och extra-kraniella target kraniellt om C1.", d5_value, d5_status));

            // if synthetic CT, compute the distance between body and couch surface
            if (syntheticCT)
            {
                string          d6_value  = string.Empty;
                AutoCheckStatus d6_status = AutoCheckStatus.UNKNOWN;
                double          distance  = 15.0;
                double          threshold = 5.0;

                Structure body         = structureSet.Structures.Where(s => String.CompareOrdinal(s.Id, "BODY") == 0).ToList().FirstOrDefault();
                Structure couchSurface = structureSet.Structures.Where(s => String.CompareOrdinal(s.DicomType, "SUPPORT") == 0).Where(s => s.Id.IndexOf("Surface") != -1).ToList().FirstOrDefault();

                if (body == null)
                {
                    d6_status = AutoCheckStatus.FAIL;
                    d6_value  = "Body struktur saknas. ";
                }
                if (couchSurface == null)
                {
                    d6_status = AutoCheckStatus.FAIL;
                    d6_value += "Britsstruktur saknas. ";
                }
                if (d6_status != AutoCheckStatus.FAIL)
                {
                    // compute separation between structures and distance to threshold
                    double separation = 0;
                    if (image.ImagingOrientation.ToString().IndexOf("Prone") > 0)
                    {
                        separation = body.MeshGeometry.Bounds.Location.Y - (couchSurface.MeshGeometry.Bounds.Location.Y + couchSurface.MeshGeometry.Bounds.Size.Y);
                    }
                    else
                    {
                        separation = -1 * (body.MeshGeometry.Bounds.Location.Y + body.MeshGeometry.Bounds.Size.Y - couchSurface.MeshGeometry.Bounds.Location.Y);
                    }
                    if (Math.Round(distance - separation, 0) > threshold)
                    {
                        d6_status = AutoCheckStatus.WARNING;
                    }
                    else
                    {
                        d6_status = AutoCheckStatus.PASS;
                    }
                    d6_value = "Avstånd mellan Body och brits: " + separation.ToString("N0") + " mm";
                }
                checklistItems.Add(new ChecklistItem("D6. Kontrollera avstånd mellan Body och britsstruktur", "Kontrollera att avståndet mellan Body och britsstuktur är [10, 20] mm för syntetisk CT", d6_value, d6_status));
            }

            string          d7_value                  = string.Empty;
            string          d7_value_detailed         = string.Empty;
            AutoCheckStatus d7_status                 = AutoCheckStatus.UNKNOWN;
            bool            calculationErrorOrWarning = false;

            foreach (Beam beam in planSetup.Beams)
            {
                if (!beam.IsSetupField)
                {
                    d7_value_detailed += beam.Id + ":\r\n";
                    foreach (BeamCalculationLog beamCalculationLog in beam.CalculationLogs)
                    {
                        foreach (string messageLine in beamCalculationLog.MessageLines)
                        {
                            if (messageLine.IndexOf("Warning") == 0 || messageLine.IndexOf("Error") == 0)
                            {
                                d7_value_detailed        += "• " + messageLine + "\r\n";
                                calculationErrorOrWarning = true;
                            }
                        }
                    }
                    d7_value_detailed += "\r\n";
                }
            }
            if (calculationErrorOrWarning == false)
            {
                d7_status = AutoCheckStatus.PASS;
                d7_value  = "Inga error eller varningar";
            }
            else
            {
                d7_status = AutoCheckStatus.WARNING;
                d7_value  = "Error eller varningar";
            }
            d7_value_detailed = "Fält:\r\n" + reorderBeamParam(d7_value_detailed, "\r\n\r\n");
            checklistItems.Add(new ChecklistItem("D7. Eventuella felmeddelanden under Errors And Warnings är acceptabla", "Kontrollera att eventuella meddelanden under Errors And Warnings är acceptabla och bekräfta detta med signatur i protokollet.", d7_value, d7_value_detailed, d7_status));
        }
Example #17
0
        public void U() // The name U is kept for historical reasons. Might change to R in future versions.
        {
            checklistItems.Add(new ChecklistItem("R. Strålanmälan/Ordination"));

            string r1_imageid = string.Empty;

            if (planSetup.StructureSet != null && planSetup.StructureSet.Image != null)
            {
                r1_imageid = planSetup.StructureSet.Image.Id;
            }
            string    r1_value        = "Personnummer: " + patient.Id + ", Course: " + course.Id + ", Plan: " + planSetup.Id + ", CT: " + (image == null ? "-" : image.Id);
            string    r1_value_detail = string.Empty;
            DataTable remarks         = AriaInterface.Query("select Image.ImageNotes from Image, Series where Series.SeriesUID = '" + image.Series.UID.ToString() + "' and Image.SeriesSer = Series.SeriesSer and Image.ImageType = 'Image' and Image.ImageId = '" + image.Id.ToString() + "'");

            if (remarks.Rows.Count == 1 && remarks.Rows[0][0] != DBNull.Value)
            {
                r1_value_detail = (string)remarks.Rows[0][0];
                string remark = (string)remarks.Rows[0][0];
                int    count  = remark.Select((c, i) => remark.Substring(i)).Count(sub => sub.StartsWith("User"));
                if (count > 1)
                {
                    MessageBox.Show(remark, "Aktuella remarks");
                }
            }
            checklistItems.Add(new ChecklistItem("R1. Jämför id (course, plan, CT-set, patient) mellan strålanmälan, protokoll och Aria", "Kontrollera att \r\n  • Patientens personnummer stämmer överens mellan strålanmälan, protokoll och Aria\r\n  • Course, plannamn och CT-set stämmer överens mellan protokoll och Aria.", r1_value, AutoCheckStatus.MANUAL));

            AutoCheckStatus r2_status                  = AutoCheckStatus.FAIL;
            string          r2_value                   = string.Empty;
            string          r2_value_detail            = string.Empty;
            string          prescriptionVolume         = string.Empty;
            long            prescriptionAnatomySer     = long.MinValue;
            bool            guessedVolume              = false;
            bool            multiplePrescriptionLevels = false;
            string          planningVolume             = string.Empty;
            DataTable       prescription               = new DataTable();

            // If/else based on wether prescription exists or not
            if (prescSer > 0)  // prescription exists
            {
                DataTable planning = AriaInterface.Query("select distinct PlanSetupSer, PrimaryPTVSer, PatientVolumeSer, StructureId from PlanSetup, Structure where PlanSetup.PlanSetupSer = " + planSetupSer.ToString() + "  and PlanSetup.PrimaryPTVSer = Structure.PatientVolumeSer");
                if (planning.Rows.Count == 1 && planning.Rows[0][3] != DBNull.Value)
                {
                    planningVolume = (string)planning.Rows[0][3];
                }
                prescription = AriaInterface.Query("select distinct PlanSetupSer, PlanSetup.PrescriptionSer, PrescriptionAnatomy.PrescriptionSer, PrescriptionAnatomy.PrescriptionAnatomySer, PrescriptionAnatomyItem.PrescriptionAnatomySer, ItemType, ItemValue, Prescription.Status, Prescription.PrescriptionSer, Prescription.PrescriptionName, Prescription.Notes from PlanSetup, Prescription, PrescriptionAnatomy, PrescriptionAnatomyItem where PlanSetup.PlanSetupSer = " + planSetupSer.ToString() + " and PlanSetup.PrescriptionSer = PrescriptionAnatomy.PrescriptionSer and PrescriptionAnatomy.PrescriptionAnatomySer = PrescriptionAnatomyItem.PrescriptionAnatomySer and PrescriptionAnatomyItem.ItemType = 'VOLUME ID' and PlanSetup.PrescriptionSer = Prescription.PrescriptionSer");
                if (prescription.Rows.Count > 0 && prescription.Rows[0][6] != DBNull.Value)
                {
                    //string volumeName = string.Empty;
                    string prescriptionStatus = (string)prescription.Rows[0][7];
                    string prescriptionName   = (string)prescription.Rows[0][9];
                    if (prescription.Rows[0][10] != DBNull.Value)
                    {
                        r2_value_detail = (string)prescription.Rows[0][10];
                    }

                    if (prescription.Rows.Count == 1)
                    {
                        prescriptionVolume     = (string)prescription.Rows[0][6];
                        prescriptionAnatomySer = (long)prescription.Rows[0][3];
                    }

                    /*
                     * else
                     * {
                     *  multiplePrescriptionLevels = true;
                     *  foreach (DataRow row in prescription.Rows)
                     *  {
                     *      string volumeName = (string)row[6];
                     *      if (volumeName.IndexOf(planningVolume) == 0 && planningVolume.Length > 1)
                     *      {
                     *          prescriptionVolume = (string)row[6];
                     *          prescriptionAnatomySer = (long)row[3];
                     *          guessedVolume = true;
                     *          break;
                     *      }
                     *  }
                     * }
                     */

                    r2_status = CheckResult(string.Compare(prescriptionStatus, "Approved") == 0);
                    r2_value  = prescriptionName + ": " + prescriptionStatus;
                }
                else if (prescription.Rows.Count == 0)
                {
                    r2_value = "Ordination saknas";
                }
            }
            else  // prescription does not exist
            {
                r2_value = "Ordination saknas/är inte kopplad";
                //r2_value_detail = "Kontrollen kan ej utföras korrekt utan kopplad ordination.";
                r2_status = AutoCheckStatus.WARNING;
            }
            if (String.IsNullOrEmpty(r2_value_detail))
            {
                checklistItems.Add(new ChecklistItem("R2. Status på kopplad ordination.", "Kontrollera att planen är kopplad till en ordination med status 'Approved'.", r2_value, r2_status));
            }
            else
            {
                checklistItems.Add(new ChecklistItem("R2. Status på kopplad ordination.", "Kontrollera att planen är kopplad till en ordination med status 'Approved'.", r2_value, r2_value_detail, r2_status));
            }

            string r3_value = String.Empty;

            /*
             * AutoCheckStatus r3_status = AutoCheckStatus.MANUAL;
             * if (multiplePrescriptionLevels == true && guessedVolume == false)
             * {
             *  r3_value = "Multipla ordinationsvolymer existerar. Ingen matchar den planerade volymen. ";
             *  r3_status = AutoCheckStatus.MANUAL;
             * }
             * else if (multiplePrescriptionLevels == true && guessedVolume == true)
             * {
             *  r3_value = "Multipla ordinationsvolymer existerar. Följande matchar den planerade volymen: " + prescriptionVolume + ", ";
             *  r3_status = AutoCheckStatus.MANUAL;
             * }
             * else
             * {
             *  r3_value = "Ordinerad volym: " + prescriptionVolume + ", ";
             *  if (prescriptionVolume.IndexOf(planningVolume) == 0 && planningVolume.Length > 1) // maybe this is too nice. Perhaps it should be a String.Compare. Possibly with a string split for prescritonVolume (using :)
             *      r3_status = AutoCheckStatus.PASS;
             *  else
             *      r3_status = AutoCheckStatus.WARNING;
             * }
             * r3_value += "Planerad volym: " + (planningVolume == string.Empty ? "-" : planningVolume);
             * checklistItems.Add(new ChecklistItem("R3. Kontrollera att ordinerad volym stämmer överens med planerad volym.", "Kontrollera att volymen som planens primära referenspunkt tillhör motsvarar den volym som det är ordinerat till.", r3_value, r3_status));
             */
            switch (prescription.Rows.Count)
            {
            case 0:
                r3_value += "Ordination saknas. ";
                break;

            case 1:
                r3_value += "Ordinerad volym: ";
                break;

            default:
                r3_value += "Ordinerade volymer: ";
                break;
            }
            if (prescription.Rows.Count > 1)
            {
                r3_value = "Ordinerade volymer: ";
            }
            else
            {
                r3_value = "Ordinerad volym: ";
            }
            foreach (DataRow row in prescription.Rows)
            {
                r3_value += (string)row[6] + ", ";
            }
            r3_value += "Planerad volym: " + (planningVolume == string.Empty ? "-" : planningVolume);
            r3_value  = r3_value.Replace(", Planerad volym", "; Planerad volym");
            checklistItems.Add(new ChecklistItem("R3. Ordinerad volym stämmer överens med planerad volym.", "Kontrollera att volymen som planens primära referenspunkt tillhör motsvarar den volym som det är ordinerat till.", r3_value, AutoCheckStatus.MANUAL));

            AutoCheckStatus r4_status         = AutoCheckStatus.UNKNOWN;
            string          r4_value          = string.Empty;
            string          r4_value_detailed = string.Empty;

            List <int>    numberOfFractions = new List <int>();
            List <double> dosePerFraction   = new List <double>();
            List <double> totalDose         = new List <double>();

            switch (prescription.Rows.Count)
            {
            case 0:
                r4_status = AutoCheckStatus.WARNING;
                r4_value  = "Ordination: Saknas";
                break;

            default:
                foreach (DataRow row in prescription.Rows)
                {
                    string    volumeName = (string)row[6];
                    long      ser = (long)row[3];
                    DataTable prescriptionItem = AriaInterface.Query("select NumberOfFractions, ItemType, ItemValue, PrescriptionAnatomyItem.PrescriptionAnatomySer, PrescriptionAnatomy.PrescriptionAnatomySer, PrescriptionAnatomy.PrescriptionSer, Prescription.PrescriptionSer  from Prescription, PrescriptionAnatomy, PrescriptionAnatomyItem where PrescriptionAnatomy.PrescriptionAnatomySer = " + ser.ToString() + " and PrescriptionAnatomy.PrescriptionAnatomySer = PrescriptionAnatomyItem.PrescriptionAnatomySer and PrescriptionAnatomy.PrescriptionSer = Prescription.PrescriptionSer");
                    double    tdose = -1, dosepf = -1;
                    foreach (DataRow itemRow in prescriptionItem.Rows)
                    {
                        numberOfFractions.Add((int)prescriptionItem.Rows[0]["NumberOfFractions"]);
                        if (String.Equals((string)itemRow["ItemType"], "Total dose", StringComparison.OrdinalIgnoreCase))
                        {
                            double.TryParse((string)itemRow["ItemValue"], out tdose);
                            totalDose.Add(tdose);
                        }
                        if (String.Equals((string)itemRow["ItemType"], "Dose per fraction", StringComparison.OrdinalIgnoreCase))
                        {
                            double.TryParse((string)itemRow["ItemValue"], out dosepf);
                            dosePerFraction.Add(dosepf);
                        }
                    }
                    if (tdose > 0 && dosepf > 0)
                    {
                        r4_value_detailed += (r4_value_detailed == string.Empty ? "Ordination: \r\n" : "\r\n") + "  • Volym: " + volumeName + "\r\n  • Fraktionsdos: " + dosepf.ToString("0.000") + " Gy \r\n  • Antal fraktioner: " + numberOfFractions.LastOrDefault().ToString() + "\r\n  • Totaldos: " + tdose.ToString("0.000") + " Gy\r\n";
                    }
                }

                // Check if numberOfFractions, dosePerFraction are distinct
                if (numberOfFractions.Distinct().ToList().Count > 1)
                {
                    r4_status = AutoCheckStatus.FAIL;
                    r4_value  = "Ordination: Inkonsekvent antal fraktioner";
                }
                else
                {
                    if (dosePerFraction.Distinct().ToList().Count > 1)
                    {
                        r4_status = AutoCheckStatus.MANUAL;
                        r4_value  = "Ordination: SIB * " + numberOfFractions[0].ToString();
                    }
                    if (numberOfFractions.Distinct().ToList().Count == 1 && dosePerFraction.Distinct().ToList().Count == 1)
                    {
                        r4_value = "Ordination: " + dosePerFraction[0].ToString("0.000") + "Gy * " + numberOfFractions[0].ToString() + " = " + totalDose[0].ToString("0.000") + " Gy";
                    }
                }
                break;
            }

            if (fractionation == null)
            {
                r4_status = AutoCheckStatus.FAIL;
            }
            else
            {
                if (r4_status == AutoCheckStatus.UNKNOWN)
                {
                    r4_status = CheckResult(numberOfFractions[0] == fractionation.NumberOfFractions && Math.Round(dosePerFraction[0], 3) == Math.Round(fractionation.PrescribedDosePerFraction.Dose, 3) && Math.Round(totalDose[0], 3) == Math.Round(planSetup.TotalPrescribedDose.Dose, 3));
                }
                // Even for a SIB we need to check the number of fractions
                if (r4_status == AutoCheckStatus.MANUAL)
                {
                    if (numberOfFractions[0] != fractionation.NumberOfFractions)
                    {
                        r4_status = AutoCheckStatus.FAIL;
                    }
                }
                r4_value          += "; Planerat: " + fractionation.PrescribedDosePerFraction.ToString() + " * " + fractionation.NumberOfFractions.ToString() + " = " + planSetup.TotalPrescribedDose.ToString();
                r4_value_detailed += (r4_value_detailed == string.Empty ? "" : "\r\n") + "Planerat: \r\n  • Volym: " + planningVolume + "\r\n  • Fraktionsdos: " + fractionation.PrescribedDosePerFraction.ToString() + "\r\n  • Antal fraktioner: " + fractionation.NumberOfFractions.ToString() + "\r\n  • Totaldos: " + planSetup.TotalPrescribedDose.ToString();
            }
            checklistItems.Add(new ChecklistItem("R4. Planen är konsekvent med vad som ordinerats.", "Kontrollera att planen är konsekvent med vad som ordinerats gällande: \r\n  • Fraktionsdos\r\n  • Antal fraktioner\r\n  • Totaldos", r4_value, r4_value_detailed, r4_status));
        }
Example #18
0
        public void V()
        {
            if (checklistType == ChecklistType.EclipseVMAT || checklistType == ChecklistType.MasterPlanIMRT)
            {
                checklistItems.Add(new ChecklistItem("V. VMAT/IMRT"));

                string v1_value = string.Empty;

                AutoCheckStatus v1_status           = AutoCheckStatus.FAIL;
                int             v1_numberOfWarnings = 0;
                int             v1_numberOfPass     = 0;
                List <double>   collAngles          = new List <double>();
                foreach (Beam beam in planSetup.Beams)
                {
                    if (!beam.IsSetupField)
                    {
                        double collimatorAngle = beam.ControlPoints[0].CollimatorAngle;
                        collAngles.Add(collimatorAngle);
                        if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
                        {
                            if (collimatorAngle == 5 || collimatorAngle == 355)
                            {
                                v1_numberOfPass++;
                            }
                            else if (collimatorAngle > 5 && collimatorAngle < 355)
                            {
                                v1_numberOfWarnings++;
                            }
                        }
                        else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta)
                        {
                            if (collimatorAngle == 30 || collimatorAngle == 330)
                            {
                                v1_numberOfPass++;
                            }
                        }

                        v1_value += (v1_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + collimatorAngle.ToString("0.0") + "°";
                    }
                }
                if (v1_numberOfPass == numberOfTreatmentBeams)
                {
                    v1_status = AutoCheckStatus.PASS;
                }
                else if (v1_numberOfPass + v1_numberOfWarnings == numberOfTreatmentBeams)
                {
                    v1_status = AutoCheckStatus.WARNING;
                }
                if (collAngles.Count > 1 && collAngles.Distinct().ToList().Count < 2)
                {
                    v1_status = AutoCheckStatus.FAIL;
                }

                checklistItems.Add(new ChecklistItem("V1. Kollimatorvinkeln är lämplig", "Kontrollera att kollimatorvinkeln är lämplig\r\n  • Varian: vanligtvis 5° resp. 355°, men passar detta ej PTV är andra vinklar ok (dock ej vinklar mellan 355° och 5°)\r\n  • Elekta: 30° resp. 330°", v1_value, v1_status));

                if (checklistType == ChecklistType.EclipseVMAT)//JSR && treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian)
                {
                    string          v2_value        = string.Empty;
                    AutoCheckStatus v2_status       = AutoCheckStatus.WARNING;
                    int             v2_numberOfPass = 0;
                    foreach (Beam beam in planSetup.Beams)
                    {
                        if (!beam.IsSetupField)
                        {
                            double fieldWidth = 0.1 * (beam.ControlPoints[0].JawPositions.X2 - beam.ControlPoints[0].JawPositions.X1);
                            if (fieldWidth <= 15)
                            {
                                v2_numberOfPass++;
                            }
                            v2_value += (v2_value.Length == 0 ? string.Empty : ", ") + beam.Id + ": " + fieldWidth.ToString("0.0") + " cm";
                        }
                    }
                    if (v2_numberOfPass == numberOfTreatmentBeams)
                    {
                        v2_status = AutoCheckStatus.PASS;
                    }
                    checklistItems.Add(new ChecklistItem("V2. Fältbredden är rimlig ", "Kontrollera att VMAT-fält har en rimlig fältbredd (riktvärde 15 cm, vid större target ska två arcs och delade fält övervägas).", v2_value, v2_status));

                    string          v3_details = string.Empty;
                    string          v3_value   = string.Empty;
                    AutoCheckStatus v3_status  = AutoCheckStatus.MANUAL;

                    checklistItems.Add(new ChecklistItem("V3. Optimeringsbolus är korrekt använt", "Kontrollera att optimeringsbolus har använts korrekt för ytliga target:	\r\n  Eclipse H&N (VMAT):\r\n    • Optimeringsbolus har använts vid optimeringen i de fall då PTV ligger mindre än 4 mm innanför ytterkonturen.\r\n    • BODY ska inkludera eventuellt optimeringsbolus\r\n  Eclipse Ani, Recti (VMAT):\r\n    • BODY ska inkludera eventuellt optimeringsbolus\r\n  Optimeringsbolus i Eclipse (VMAT):\r\n    • HU för optimeringsbolus är satt till 0 HU\r\n    • Optimeringsbolus är skapat genom 5 mm (H&N) eller 6 mm (Ani, Recti) expansion från det PTV-struktur optimeringen skett på. Boluset ska ej gå innanför patientens hudyta.", v3_value, v3_details, v3_status));     //JSR

                    checklistItems.Add(new ChecklistItem("V4. Robusthet", "Kontrollera planens robusthet m.a.p. ISO-center-förskjutning m.h.a. Uncertainty-planer. Planerna skapas av dosplaneraren.\r\n    • Skillnaderna i maxdos för uncertainty-planerna (±0,4 cm i x, y, resp. z) är <5% relativt originalplanen.\r\n    • CTV täckning är acceptabel.", string.Empty, AutoCheckStatus.MANUAL));

                    // Check for jawtracking:
                    var v5_values = CheckJawTracking(planSetup);

                    string          v5_value  = v5_values.Item1;
                    AutoCheckStatus v5_status = v5_values.Item2;

                    checklistItems.Add(new ChecklistItem("V5. Leveransmönstret är rimligt", "Kontrollera att leveransmönstret är rimligt (att det inte är en stor andel extremt små öppningar, att riskorgan skärmas, att alla segment går på ett target samt jawtracking för kollimatorerna)", v5_value, v5_status));
                }
            }
        }
Example #19
0
        public void I()
        {
            checklistItems.Add(new ChecklistItem("I. Bildmaterial"));

            string          i1_value = string.Empty;
            AutoCheckStatus i1_status;

            if (image != null && image.Series != null)
            {
                if (string.Compare(image.Series.ImagingDeviceId, "CT_A") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_B") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_C") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "PET/CT 01") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "PET/CT 02") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "PET/CT 03") == 0)
                {
                    if (image.Comment.IndexOf("RT") == 0)
                    {
                        i1_status = AutoCheckStatus.PASS;
                    }
                    else
                    {
                        i1_status = AutoCheckStatus.FAIL;
                    }
                    i1_value = image.Series.ImagingDeviceId + ", " + image.Comment;
                }
                // Specific checks for synthetic CTs
                else if (string.Compare(image.Series.ImagingDeviceId, "sCT_MR_A") == 0)
                {
                    // set synthetic CT
                    syntheticCT = true;
                    string trigger = "MR acquisition: ";
                    i1_status = AutoCheckStatus.MANUAL;
                    //string MRparameterCheckFile = patient.LastName + "_" + image.Series.Study.CreationDateTime.Value.ToString("yyyyMMdd") + "_" + image.Series.Study.CreationDateTime.Value.ToString("HHmmss") + ".txt";
                    string MRparameterCheckFile   = patient.LastName + "_" + image.Comment.Substring(image.Comment.IndexOf(trigger) + trigger.Length).Trim() + ".txt";
                    string MRparameterCheckResult = ValidateMR(MRparameterCheckFile);
                    if (!String.Equals("MRI SYNTHETIC CT PARAMETERS OK", MRparameterCheckResult))
                    {
                        i1_status = AutoCheckStatus.FAIL;
                    }
                    i1_value = image.Series.ImagingDeviceId + ", " + MRparameterCheckResult + ", " + image.Comment;
                }

                else
                {
                    i1_status = AutoCheckStatus.FAIL;
                    i1_value  = image.Series.ImagingDeviceId + ", " + image.Comment;
                }
            }
            else
            {
                i1_status = AutoCheckStatus.FAIL;
                i1_value  = "-";
            }
            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                i1_status = AutoCheckStatus.UNKNOWN;
            }
            checklistItems.Add(new ChecklistItem("I1. CT-protokoll för radioterapi har använts", "Kontrollera att ett CT-protokoll för radioterapi har använts:\r\n• Eclipse: Se Image comment under Image properties (för serien) eller protokollet", i1_value, i1_status));

            if (syntheticCT == true)
            {
                string sCT_version = "v1.1.2";
                // The version is first in the ImageComment of each slice. Select the first slice in the Image (the first item is the volume, so skip that). Split the string on whitespace and take the first item
                string i2_value = image.Series.Images.Where(img => img.ZSize == 1).FirstOrDefault().Comment.ToString().Split(' ').FirstOrDefault().ToString();

                AutoCheckStatus i2_status = CheckResult(string.Compare(i2_value, sCT_version) == 0);
                checklistItems.Add(new ChecklistItem("I2. MRI-planner version", "Kontrollera att korrekt version av MRI-planner använts vid generering av sCT\r\n• " + sCT_version, i2_value, i2_status));
            }

            // Will now use information from Prescription rather than verifying against ChecklistType
            string          i3_value  = "CT-underlag: ";
            AutoCheckStatus i3_status = AutoCheckStatus.MANUAL;

            if (image != null)
            {
                i3_value += image.Id + "; Ordination: ";
            }
            else
            {
                i3_value += "-" + "; Ordination: ";
                i3_status = AutoCheckStatus.FAIL;
            }


            DataTable prescription = AriaInterface.Query("select Gating from Prescription, PlanSetup where PlanSetup.PrescriptionSer = Prescription.PrescriptionSer and PlanSetup.PlanSetupSer = '" + planSetupSer.ToString() + "'");

            switch (prescription.Rows.Count)
            {
            case 0:
                if (i3_status != AutoCheckStatus.FAIL)
                {
                    i3_status = AutoCheckStatus.WARNING;
                }
                i3_value = "Ordination saknas";
                break;

            case 1:
                if (prescription.Rows[0]["Gating"] != DBNull.Value)
                {
                    i3_value += (string)prescription.Rows[0]["Gating"];
                }
                else
                {
                    i3_value += "Friandning";
                }
                break;

            default:
                i3_value += "Obestämbart";
                break;
            }

            /*
             * if (image != null)
             * {
             *  if (checklistType == ChecklistType.EclipseGating)
             *  {
             *      if (image.Comment.ToLower().IndexOf("gating") != -1 && image.Id.ToLower().IndexOf("gating") != -1 || image.Comment.ToLower().IndexOf("bh") != -1 && image.Id.ToLower().IndexOf("bh") != -1)
             *          i3_status = AutoCheckStatus.PASS;
             *      else
             *          i3_status = AutoCheckStatus.FAIL;
             *  }
             *  else
             *  {
             *      if (image.Comment.ToLower().IndexOf("gating") != -1 || image.Id.ToLower().IndexOf("gating") != -1 || image.Comment.ToLower().IndexOf("bh") != -1 || image.Id.ToLower().IndexOf("bh") != -1)
             *          i3_status = AutoCheckStatus.FAIL;
             *      else
             *          i3_status = AutoCheckStatus.PASS;
             *  }
             *  i3_value = image.Comment + ", " + image.Id;
             * }
             * else
             * {
             *  i3_status = AutoCheckStatus.FAIL;
             *  i3_value = "-";
             * }
             * if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
             *  i3_status = AutoCheckStatus.UNKNOWN;
             */
            checklistItems.Add(new ChecklistItem("I3. CT-studie är korrekt m.a.p. gatingordination", "Kontrollera att den korrekta CT-studien med avseende på gatingordination har använts.", i3_value, i3_status));

            string          i4_value  = string.Empty;
            AutoCheckStatus i4_status = AutoCheckStatus.UNKNOWN;

            if (structureSet != null)
            {
                int firstImagePlane = int.MaxValue;
                int lastImagePlane  = int.MinValue;
                foreach (Structure structure in structureSet.Structures)
                {
                    if (string.Compare(structure.DicomType, "PTV") == 0)
                    {
                        for (int imagePlane = 0; imagePlane < image.ZSize; imagePlane++)
                        {
                            VVector[][] contour = structure.GetContoursOnImagePlane(imagePlane);
                            if (contour.Length > 0 && contour[0].Length > 0)
                            {
                                if (imagePlane < firstImagePlane)
                                {
                                    firstImagePlane = imagePlane;
                                }
                                if (imagePlane > lastImagePlane)
                                {
                                    lastImagePlane = imagePlane;
                                }
                            }
                        }
                    }
                }
                if (firstImagePlane != int.MaxValue && lastImagePlane != int.MinValue)
                {
                    double minusZ = 0.1 * firstImagePlane * image.ZRes;
                    double plusZ  = 0.1 * (image.ZSize - lastImagePlane - 1) * image.ZRes;
                    if (minusZ >= 4 && plusZ >= 4)
                    {
                        i4_status = AutoCheckStatus.PASS;
                    }
                    else
                    {
                        i4_status = AutoCheckStatus.WARNING;
                    }
                    // DICOM -> IEC61217: z -> y
                    i4_value = "-y: " + minusZ.ToString("0.0") + " cm, +y: " + plusZ.ToString("0.0") + " cm";
                }
            }
            checklistItems.Add(new ChecklistItem("I4. Axiell utökning av beräkningsvolym gjorts då det behövs", "Kontrollera att axiell utökning av beräkningsvolym gjorts då det behövs (<4 cm mellan target och första/sista snittet i 3D-volymen) och även att det inte gjorts då det är oberättigat (t.ex. superior för skalle).", i4_value, i4_status));

            string i5_value = (image == null ? "-" : image.ImagingOrientation.ToString());

            checklistItems.Add(new ChecklistItem("I5. Patientriktning har angivits korrekt vid CT-undersökningen", "Kontrollera att patientriktning har angivits korrekt vid CT-undersökningen genom att jämföra orienteringsfigur mot CT-data.", i5_value, AutoCheckStatus.MANUAL));

            AutoCheckStatus i6_status = AutoCheckStatus.MANUAL;
            string          i6_value  = ("Planorientering: " + planSetup.TreatmentOrientation.ToString());

            i6_value += "; CT-orientering: " + i5_value;
            if (!String.Equals(planSetup.TreatmentOrientation.ToString(), image.ImagingOrientation.ToString()))
            {
                i6_status = AutoCheckStatus.WARNING;
            }
            checklistItems.Add(new ChecklistItem("I6. Orientering är konsekvent mellan CT-undersökning och behandlingsplan.", "Kontrollera att samma orientering valts för CT-undersökning och behandlingsplanen om inte särskilda skäl föreligger.", i6_value, i6_status));

            string i7_value = (checklistType == ChecklistType.EclipseGating ? "Obs Gating! Referenspunkt sätts utifrån icke-gatad CT" : string.Empty);

            checklistItems.Add(new ChecklistItem("I7. Referenspunkten (anatomisk) är korrekt placerad", "Kontrollera att referenspunkten (anatomisk) är korrekt placerad (User Origin i Eclipse). Observera att på patienter som ska ha gating sätts User Origin utifrån det icke gatade CT-underlaget.", i7_value, AutoCheckStatus.MANUAL));
        }
Example #20
0
 public ChecklistItem(string shortInfo, string detailedInfo, string shortResult, string detailedResult, AutoCheckStatus autoCheckStatus)
 {
     this.shortInfo       = shortInfo;
     this.detailedInfo    = detailedInfo;
     this.shortResult     = shortResult;
     this.detailedResult  = detailedResult;
     this.autoCheckStatus = autoCheckStatus.ToString();
 }
Example #21
0
        public void I()
        {
            checklistItems.Add(new ChecklistItem("I. Bildmaterial"));

            string          i1_value = string.Empty;
            AutoCheckStatus i1_status;

            if (image != null && image.Series != null)
            {
                if (string.Compare(image.Series.ImagingDeviceId, "CT_A") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_B") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_C") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "PET/CT 01") == 0)
                {
                    if (image.Comment.IndexOf("RT") == 0)
                    {
                        i1_status = AutoCheckStatus.PASS;
                    }
                    else
                    {
                        i1_status = AutoCheckStatus.FAIL;
                    }
                }
                else
                {
                    i1_status = AutoCheckStatus.FAIL;
                }
                i1_value = image.Series.ImagingDeviceId + ", " + image.Comment;
            }
            else
            {
                i1_status = AutoCheckStatus.FAIL;
                i1_value  = "-";
            }
            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                i1_status = AutoCheckStatus.UNKNOWN;
            }
            checklistItems.Add(new ChecklistItem("I1. CT-protokoll för radioterapi har använts", "Kontrollera att ett CT-protokoll för radioterapi har använts:\r\n• Eclipse: Se Image comment under Image properties (för serien) eller protokollet", i1_value, i1_status));

            // consider using information from prescription if we can get prescriptions sorted
            string          i2_value = string.Empty;
            AutoCheckStatus i2_status;

            if (image != null)
            {
                if (checklistType == ChecklistType.EclipseGating)
                {
                    if (image.Comment.ToLower().IndexOf("gating") != -1 && image.Id.ToLower().IndexOf("gating") != -1 || image.Comment.ToLower().IndexOf("bh") != -1 && image.Id.ToLower().IndexOf("bh") != -1)
                    {
                        i2_status = AutoCheckStatus.PASS;
                    }
                    else
                    {
                        i2_status = AutoCheckStatus.FAIL;
                    }
                }
                else
                {
                    if (image.Comment.ToLower().IndexOf("gating") != -1 || image.Id.ToLower().IndexOf("gating") != -1 || image.Comment.ToLower().IndexOf("bh") != -1 || image.Id.ToLower().IndexOf("bh") != -1)
                    {
                        i2_status = AutoCheckStatus.FAIL;
                    }
                    else
                    {
                        i2_status = AutoCheckStatus.PASS;
                    }
                }
                i2_value = image.Comment + ", " + image.Id;
            }
            else
            {
                i2_status = AutoCheckStatus.FAIL;
                i2_value  = "-";
            }
            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                i2_status = AutoCheckStatus.UNKNOWN;
            }
            checklistItems.Add(new ChecklistItem("I2. CT-studie är korrekt m.a.p. gatingordination", "Kontrollera att den korrekta CT-studien med avseende på gatingordination har använts.", i2_value, i2_status));

            string          i3_value  = string.Empty;
            AutoCheckStatus i3_status = AutoCheckStatus.UNKNOWN;

            if (structureSet != null)
            {
                int firstImagePlane = int.MaxValue;
                int lastImagePlane  = int.MinValue;
                foreach (Structure structure in structureSet.Structures)
                {
                    if (string.Compare(structure.DicomType, "PTV") == 0)
                    {
                        for (int imagePlane = 0; imagePlane < image.ZSize; imagePlane++)
                        {
                            VVector[][] contour = structure.GetContoursOnImagePlane(imagePlane);
                            if (contour.Length > 0 && contour[0].Length > 0)
                            {
                                if (imagePlane < firstImagePlane)
                                {
                                    firstImagePlane = imagePlane;
                                }
                                if (imagePlane > lastImagePlane)
                                {
                                    lastImagePlane = imagePlane;
                                }
                            }
                        }
                    }
                }
                if (firstImagePlane != int.MaxValue && lastImagePlane != int.MinValue)
                {
                    double minusZ = 0.1 * firstImagePlane * image.ZRes;
                    double plusZ  = 0.1 * (image.ZSize - lastImagePlane - 1) * image.ZRes;
                    if (minusZ >= 4 && plusZ >= 4)
                    {
                        i3_status = AutoCheckStatus.PASS;
                    }
                    else
                    {
                        i3_status = AutoCheckStatus.WARNING;
                    }
                    // DICOM -> IEC61217: z -> y
                    i3_value = "-y: " + minusZ.ToString("0.0") + " cm, +y: " + plusZ.ToString("0.0") + " cm";
                }
            }
            checklistItems.Add(new ChecklistItem("I3. Axiell utökning av beräkningsvolym gjorts då det behövs", "Kontrollera att axiell utökning av beräkningsvolym gjorts då det behövs (<4 cm mellan target och första/sista snittet i 3D-volymen) och även att det inte gjorts då det är oberättigat (t.ex. superior för skalle).", i3_value, i3_status));

            string i4_value = (image == null ? "-" : image.ImagingOrientation.ToString());

            checklistItems.Add(new ChecklistItem("I4. Patientriktning har angivits korrekt vid CT-undersökningen", "Kontrollera att patientriktning har angivits korrekt vid CT-undersökningen genom att jämföra orienteringsfigur mot CT-data.", i4_value, AutoCheckStatus.MANUAL));

            AutoCheckStatus i5_status = AutoCheckStatus.MANUAL;
            string          i5_value  = ("Planorientering: " + planSetup.TreatmentOrientation.ToString());

            i5_value += "; CT-orientering: " + i4_value;
            if (!String.Equals(planSetup.TreatmentOrientation.ToString(), image.ImagingOrientation.ToString()))
            {
                i5_status = AutoCheckStatus.WARNING;
            }
            checklistItems.Add(new ChecklistItem("I5. Orientering är konsekvent mellan CT-undersökning och behandlingsplan.", "Kontrollera att samma orientering valts för CT-undersökning och behandlingsplanen om inte särskilda skäl föreligger.", i5_value, i5_status));

            string i6_value = (checklistType == ChecklistType.EclipseGating ? "Obs Gating! Referenspunkt sätts utifrån icke-gatad CT" : string.Empty);

            checklistItems.Add(new ChecklistItem("I6. Referenspunkten (anatomisk) är korrekt placerad", "Kontrollera att referenspunkten (anatomisk) är korrekt placerad (User Origin i Eclipse). Observera att på patienter som ska ha gating sätts User Origin utifrån det icke gatade CT-underlaget.", i6_value, AutoCheckStatus.MANUAL));
        }
Example #22
0
        public void X()
        {
            checklistItems.Add(new ChecklistItem("X. Slutförande"));

            //checklistItems.Add(new ChecklistItem("X1. Skriv in antal MU, diodvärden och följande eventuella diodkorrektioner i behandlingskortet", "Skriv in antal MU, diodvärden och följande eventuella diodkorrektioner i behandlingskortet (se ”In vivo-dosimetri”-dokumentet för detaljer):\r\n  • Kil (Mimatordioder på Elekta)\r\n  • Kort SSD (IBA-dioder)\r\n  • Långt SSD (Mimatordioder)", string.Empty, AutoCheckStatus.MANUAL));

            string          x2_value  = string.Empty;
            AutoCheckStatus x2_status = AutoCheckStatus.MANUAL;

            if (image != null && image.Series != null)
            {
                x2_value = image.Series.ImagingDeviceId;
                if (string.Compare(image.Series.ImagingDeviceId, "CT_A") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_B") == 0 ||
                    string.Compare(image.Series.ImagingDeviceId, "CT_C") == 0)
                {
                    if (planSetup.Beams.Count() > 0)
                    {
                        double userY = -image.UserOrigin.y * 0.1;
                        double isoY  = -(planSetup.Beams.First().IsocenterPosition.y - image.UserOrigin.y) * 0.1;
                        if (planSetup.TreatmentOrientation.ToString().IndexOf("Prone") != -1) // Change sign if Orientation is Prone.
                        {
                            isoY  *= -1;
                            userY *= -1;
                        }
                        double shiftY = 7.1;
                        double sumY   = -isoY - userY + shiftY;
                        x2_value += ", Beräknad britshöjd: " + (-userY).ToString("0.0") + (-isoY >= 0 ? "+" : string.Empty) + (-isoY).ToString("0.0") + "+" + shiftY.ToString("0.0") + " = " + sumY.ToString("0.0") + " cm";
                        if (sumY < -30)
                        {
                            x2_status = AutoCheckStatus.WARNING;
                        }
                    }
                }
                else if (string.Compare(image.Series.ImagingDeviceId, "PET/CT 01") == 0)
                {
                    x2_value += ", Mät position manuellt";
                }
            }
            checklistItems.Add(new ChecklistItem("X2. Förväntad britshöjd räknas ut och läggs in i Aria", "Räkna ut förväntad britshöjd och lägg in i Aria (på alla fält, inklusive setup-fält) i modulen Treatment Preparation i rutan för Couch Vrt:\r\n• Eclipse: -DICOM offset Z - isocenter Z + offset cm\r\n• Offset är 7,1 cm för CT_A, CT_B, CT_C och -17,5 för PET/CT 01 (kan dock variera beroende på britshöjd vid PET-undersökningen)\r\n• Observera att vid för prone byter DICOM-koordinaten tecken\r\n• Observera risk för kollision mellan gantry och bord vid Vrt < -30 cm\r\nVid SSD-teknik:\r\n  • Ska tjockleken på eventuell vacuumpåse bestämmas genom mätning i CT-bilderna och antecknas under Setup note\r\n  • Räkna ut förflyttning från fältet närmast 0° till övriga fält (Isocenterkoordinat för ursprungsfältet minus övriga fälts isocenterkoordinater) och anteckna detta på sida 2 i behandlingsprotokollet. Exempel: Relativ förflyttning från fält 1 till fält 2: ∆Vrt=25,0 cm.\r\n  • Skriv följande under Setup note: ”FHA-beh. Ring fysiker vid start.”", x2_value, x2_status));
            //checklistItems.Add(new ChecklistItem("X2. Förväntad britshöjd räknas ut och läggs in i Aria", "Räkna ut förväntad britshöjd och lägg in i Aria (på alla fält, inklusive setup-fält) i modulen Treatment Preparation i rutan för Couch Vrt:\r\n• Eclipse: -DICOM offset Z - isocenter Z + offset cm\r\nMasterPlan: -TPRP coordinate Z - isocenter Z + offset cm\r\n• Offset är 7,1 cm för CT_A, CT_B, CT_C och -17,5 för PET/CT 01 (kan dock variera beroende på britshöjd vid PET-undersökningen)\r\n• Observera risk för kollision mellan gantry och bord vid Vrt < -30 cm\r\nVid SSD-teknik:\r\n  • Ska tjockleken på eventuell vacuumpåse bestämmas genom mätning i CT-bilderna och antecknas under Setup note\r\n  • Räkna ut förflyttning från fältet närmast 0° till övriga fält (Isocenterkoordinat för ursprungsfältet minus övriga fälts isocenterkoordinater) och anteckna detta på sida 2 i behandlingsprotokollet. Exempel: Relativ förflyttning från fält 1 till fält 2: ∆Vrt=25,0 cm.\r\n  • Skriv följande under Setup note: ”FHA-beh. Ring fysiker vid start.”", x2_value, x2_status));
            // Add elinores corda computation here

            if (checklistType == ChecklistType.EclipseVMAT && GetVMATCoplanar(planSetup) == false)
            {
                checklistItems.Add(new ChecklistItem("X3. Notera icke coplanar VMAT under Setup note", "Planen i fråga är en icke coplanar VMAT behandling. Säkerställ att en notering om detta finns under planens Setup note", string.Empty, AutoCheckStatus.MANUAL));
            }

            if (checklistType == ChecklistType.Eclipse || checklistType == ChecklistType.EclipseGating)
            {
                checklistItems.Add(new ChecklistItem("X4. Genomför oberoende MU-kontroll", "Genomför obeorende MU-kontroll via RVP", "", AutoCheckStatus.MANUAL));
            }

            if (checklistType == ChecklistType.EclipseVMAT)
            {
                checklistItems.Add(new ChecklistItem("X5. QC Course sätts till Completed.", "Sätt status på QC coursen till Completed.", "", AutoCheckStatus.MANUAL));
            }

            checklistItems.Add(new ChecklistItem("X6. Treatment Approved", "Gör planen Treatment Approved. Planen får endast göras Treatment Approved efter att ovanstående kontroller är utförda och Oberoende MU-kontroll eller QC-mätning är godkänd.", string.Empty, AutoCheckStatus.MANUAL));

            checklistItems.Add(new ChecklistItem("X7. Task sätts till Done", "Tryck Done när alla kontroller är klara\r\n  • Ändra Qty till det antal planer som har kontrollerats\r\n  • Om planen har kontrollmätts tycker man Done först när planen både är kontrollerad och kontrollmätt", string.Empty, AutoCheckStatus.MANUAL));

            //checklistItems.Add(new ChecklistItem("X5. Signera i rutan Fysiker kontroll", "Genomgången checklista med accepterat resultat bekräftas med signatur i behandlingskortet i rutan Fysiker kontroll.", string.Empty, AutoCheckStatus.MANUAL));
        }
Example #23
0
        public void D()
        {
            checklistItems.Add(new ChecklistItem("D. Dosberäkning"));

            string d1_value = planSetup.PhotonCalculationModel;

            if (d1_value.Length == 0)
            {
                d1_value = "-";
            }
            AutoCheckStatus d1_status = CheckResult(string.Compare(d1_value, "AAA_13.6.23") == 0);

            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                d1_status = AutoCheckStatus.UNKNOWN;
                checklistItems.Add(new ChecklistItem("D1. Beräkningsalgoritm är korrekt vald", "Kontrollera att korrekt beräkningsalgoritm (PB) har använts vid dosplaneringen.", d1_value, d1_status));
            }
            else
            {
                checklistItems.Add(new ChecklistItem("D1. Beräkningsalgoritm är korrekt vald", "Kontrollera att korrekt beräkningsalgoritm (AAA_13.0.26) har använts vid dosplaneringen.", d1_value, d1_status));
            }

            string d2_value;

            if (!planSetup.PhotonCalculationOptions.TryGetValue("CalculationGridSizeInCM", out d2_value))
            {
                d2_value = "-";
            }
            else
            {
                d2_value += " cm";
            }
            AutoCheckStatus d2_status = CheckResult(string.Compare(d2_value, "0.25 cm") == 0);

            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                d2_status = AutoCheckStatus.UNKNOWN;
                checklistItems.Add(new ChecklistItem("D2. Beräkningsupplösningen är korrekt", "Kontrollera att korrekt beräkningsupplösning (0.30 cm) har använts.", d2_value, d2_status));
            }
            else
            {
                checklistItems.Add(new ChecklistItem("D2. Beräkningsupplösningen är korrekt", "Kontrollera att korrekt beräkningsupplösning (0.25 cm) har använts.", d2_value, d2_status));
            }

            string d3_value;

            if (!planSetup.PhotonCalculationOptions.TryGetValue("HeterogeneityCorrection", out d3_value))
            {
                d3_value = "-";
            }
            AutoCheckStatus d3_status = CheckResult(string.Compare(d3_value, "ON") == 0);

            if (checklistType == ChecklistType.MasterPlan || checklistType == ChecklistType.MasterPlanIMRT)
            {
                d3_status = AutoCheckStatus.UNKNOWN;
            }
            checklistItems.Add(new ChecklistItem("D3. Heterogenitetskorrektion har applicerats korrekt", "Kontrollera att heterogenitetskorrektionen har använts om ej särskilda skäl föreligger", d3_value, d3_status));

            // VMATFluenceResolution removed from checklist

            /*
             * if (checklistType == ChecklistType.EclipseVMAT)
             * {
             *  string d4_value = string.Empty;
             *  if (!planSetup.PhotonCalculationOptions.TryGetValue("VMATFluenceResolution", out d4_value))
             *      d4_value = "-";
             *  AutoCheckStatus d4_status = CheckResult(string.Compare(d4_value, "High") == 0);
             *  checklistItems.Add(new ChecklistItem("D4. Fluensupplösningen är korrekt", "Kontrollera att korrekt fluensupplösning har använts", d4_value, d4_status));
             * }
             */

            string          d5_value        = string.Empty;
            AutoCheckStatus d5_status       = AutoCheckStatus.UNKNOWN;
            string          couchModel      = string.Empty;
            double          couchSurfaceHU  = double.NaN;
            double          couchInteriorHU = double.NaN;

            if (structureSet != null)
            {
                foreach (Structure structure in structureSet.Structures)
                {
                    double assignedHU;
                    structure.GetAssignedHU(out assignedHU);
                    if (string.Compare(structure.DicomType, "SUPPORT") == 0)
                    {
                        if (structure.Id.IndexOf("Surface") != -1)
                        {
                            structure.GetAssignedHU(out couchSurfaceHU);
                            couchModel = structure.Name;
                        }
                        if (structure.Id.IndexOf("Interior") != -1)
                        {
                            structure.GetAssignedHU(out couchInteriorHU);
                        }
                    }
                }
            }
            if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Varian && string.Compare(couchModel, "Exact IGRT Couch, medium") == 0 && couchInteriorHU == -950 && couchSurfaceHU == -300)
            {
                d5_status = AutoCheckStatus.PASS;
            }
            else if (treatmentUnitManufacturer == TreatmentUnitManufacturer.Elekta && string.Compare(couchModel, "BrainLAB/iBeam Couch") == 0 && couchInteriorHU == -950 && couchSurfaceHU == -300)
            {
                d5_status = AutoCheckStatus.PASS;
            }
            else if (couchModel.Length == 0)
            {
                d5_status  = AutoCheckStatus.WARNING;
                couchModel = "Saknas";
            }
            else
            {
                d5_status = AutoCheckStatus.FAIL;
            }
            // add on test if plan is non coplanar VMAT
            if (checklistType == ChecklistType.EclipseVMAT && GetVMATCoplanar(planSetup) == false)
            {
                d5_status = CheckResult(string.Compare(couchModel, "Saknas") == 0);
            }
            if (string.Compare(couchModel, "Saknas") == 0)
            {
                d5_value = "Saknas (" + treatmentUnitManufacturer + ")";
            }

            else
            {
                d5_value = "Model: " + couchModel + ", Interior: " + couchInteriorHU.ToString() + " HU, Surface: " + couchSurfaceHU.ToString() + " HU (" + treatmentUnitManufacturer + ")";
            }
            checklistItems.Add(new ChecklistItem("D5. Britsprofil och HU har valts korrekt", "Kontrollera att korrekt britsprofil och korrekta HU valts under Structure Properties för britsstrukturerna och fliken General samt CT Value and Material.\r\n• Varian: Exact IGRT Couch, medium (CouchSurface: -300, CouchInterior: -950)\r\n• Elekta: BrainLAB/iBeam Couch (CouchSurface: -300, CouchInterior: -950)\r\n• Notera att brits inte ska inkluderas för icke coplanara VMAT behandlingar", d5_value, d5_status));

            string          d6_value                  = string.Empty;
            string          d6_value_detailed         = string.Empty;
            AutoCheckStatus d6_status                 = AutoCheckStatus.UNKNOWN;
            bool            calculationErrorOrWarning = false;

            foreach (Beam beam in planSetup.Beams)
            {
                if (!beam.IsSetupField)
                {
                    d6_value_detailed += beam.Id + ":\r\n";
                    foreach (BeamCalculationLog beamCalculationLog in beam.CalculationLogs)
                    {
                        foreach (string messageLine in beamCalculationLog.MessageLines)
                        {
                            if (messageLine.IndexOf("Warning") == 0 || messageLine.IndexOf("Error") == 0)
                            {
                                d6_value_detailed        += "• " + messageLine + "\r\n";
                                calculationErrorOrWarning = true;
                            }
                        }
                    }
                    d6_value_detailed += "\r\n";
                }
            }
            if (calculationErrorOrWarning == false)
            {
                d6_status = AutoCheckStatus.PASS;
                d6_value  = "Inga error eller varningar";
            }
            else
            {
                d6_status = AutoCheckStatus.WARNING;
                d6_value  = "Error eller varningar";
            }
            d6_value_detailed = "Fält:\r\n" + reorderBeamParam(d6_value_detailed, "\r\n\r\n");
            checklistItems.Add(new ChecklistItem("D6. Eventuella felmeddelanden under Errors And Warnings är acceptabla", "Kontrollera att eventuella meddelanden under Errors And Warnings är acceptabla och bekräfta detta med signatur i protokollet.", d6_value, d6_value_detailed, d6_status));
        }