void EvaluateMetrics(StructureSet ss, PlanningItem plan) { //start with a general regex that pulls out the metric type and the @ (evalunit) part. string pattern = @"^(?<type>[^\[\]]+)(\[(?<evalunit>[^\[\]]+)\])$"; string minmaxmean_Pattern = @"^(M(in|ax|ean)|Volume)$"; //check for Max or Min or Mean or Volume string d_at_v_pattern = @"^D(?<evalpt>\d+\p{P}\d+|\d+)(?<unit>(%|cc))$"; // matches D95%, D2cc string dc_at_v_pattern = @"^DC(?<evalpt>\d+)(?<unit>(%|cc))$"; // matches DC95%, DC700cc string v_at_d_pattern = @"^V(?<evalpt>\d+\p{P}\d+|\d+)(?<unit>(%|Gy|cGy))$"; // matches V98%, V40Gy string cv_at_d_pattern = @"^CV(?<evalpt>\d+)(?<unit>(%|Gy|cGy))$"; // matches CV98%, CV40Gy // Max[Gy] D95%[%] V98%[%] CV98%[%] D2cc[Gy] V40Gy[%] foreach (var objective in m_objectives) { // first find the structure for this objective Structure evalStructure = FindStructureFromAlias(ss, objective.ID, objective.Aliases); if (evalStructure == null) { objective.Achieved = "Structure not found."; objective.FoundStructureID = ""; continue; } objective.FoundStructureID = evalStructure.Id; //start with a general regex that pulls out the metric type and the [evalunit] part. var matches = Regex.Matches(objective.DVHObjective, pattern); if (matches.Count != 1) { objective.Achieved = string.Format("DVH Objective expression \"{0}\" is not a recognized expression type.", objective.DVHObjective); break; } Match m = matches[0]; Group type = m.Groups["type"]; Group evalunit = m.Groups["evalunit"]; Console.WriteLine("expression {0} => type = {1}, unit = {2}", objective.DVHObjective, type.Value, evalunit.Value); //MessageBox.Show(type.Value+" " + minmaxmean_Pattern); // further decompose <type> var testMatch = Regex.Matches(type.Value, minmaxmean_Pattern); if (testMatch.Count != 1) { testMatch = Regex.Matches(type.Value, v_at_d_pattern); if (testMatch.Count != 1) { testMatch = Regex.Matches(type.Value, d_at_v_pattern); if (testMatch.Count != 1) { testMatch = Regex.Matches(type.Value, cv_at_d_pattern); if (testMatch.Count != 1) { testMatch = Regex.Matches(type.Value, dc_at_v_pattern); if (testMatch.Count != 1) { objective.Achieved = string.Format("DVH Objective expression \"{0}\" is not a recognized expression type.", objective.DVHObjective); // MessageBox.Show(objective.Achieved); } else { // we have Covered Dose at Volume pattern System.Console.WriteLine("Covered Dose at Volume"); objective.Achieved = "Not supported"; } } else { // we have Covered Volume at Dose pattern System.Console.WriteLine("Covered Volume at Dose"); objective.Achieved = "Not supported"; } } else { // we have Dose at Volume pattern // MessageBox.Show("Dose at Volume"); /* * string d_at_v_pattern = @"^D(?<evalpt>\d+)(?<unit>(%|cc))$"; // matches D95%, D2cc */ Group eval = testMatch[0].Groups["evalpt"]; Group unit = testMatch[0].Groups["unit"]; DoseValue.DoseUnit du = (unit.Value.CompareTo("%") == 0) ? DoseValue.DoseUnit.Percent : (unit.Value.CompareTo("Gy") == 0) ? DoseValue.DoseUnit.Gy : DoseValue.DoseUnit.Unknown; VolumePresentation vp = (unit.Value.CompareTo("%") == 0) ? VolumePresentation.Relative : VolumePresentation.AbsoluteCm3; DoseValue dv = new DoseValue(double.Parse(eval.Value), du); double volume = double.Parse(eval.Value); VolumePresentation vpFinal = (evalunit.Value.CompareTo("%") == 0) ? VolumePresentation.Relative : VolumePresentation.AbsoluteCm3; DoseValuePresentation dvpFinal = (evalunit.Value.CompareTo("%") == 0) ? DoseValuePresentation.Relative : DoseValuePresentation.Absolute; DoseValue dvAchieved = plan.GetDoseAtVolume(evalStructure, volume, vp, dvpFinal); //checking dose output unit and adapting to template if (dvAchieved.UnitAsString.CompareTo(evalunit.Value.ToString()) != 0) { if ((evalunit.Value.CompareTo("Gy") == 0) && (dvAchieved.Unit.CompareTo(DoseValue.DoseUnit.cGy) == 0)) { dvAchieved = new DoseValue(dvAchieved.Dose / 100, DoseValue.DoseUnit.Gy); } else { throw new ApplicationException("internal error"); } } objective.Achieved = dvAchieved.ToString(); } } else { // we have Volume at Dose pattern // MessageBox.Show("Volume at Dose"); /* * string v_at_d_pattern = @"^V(?<evalpt>\d+)(?<unit>(%|Gy|cGy))$"; // matches V98%, V40Gy, V4000cGy */ Group eval = testMatch[0].Groups["evalpt"]; Group unit = testMatch[0].Groups["unit"]; DoseValue.DoseUnit du = (unit.Value.CompareTo("%") == 0) ? DoseValue.DoseUnit.Percent : (unit.Value.CompareTo("Gy") == 0) ? DoseValue.DoseUnit.Gy : DoseValue.DoseUnit.Unknown; VolumePresentation vp = (unit.Value.CompareTo("%") == 0) ? VolumePresentation.Relative : VolumePresentation.AbsoluteCm3; DoseValue dv = new DoseValue(double.Parse(eval.Value), du); double volume = double.Parse(eval.Value); VolumePresentation vpFinal = (evalunit.Value.CompareTo("%") == 0) ? VolumePresentation.Relative : VolumePresentation.AbsoluteCm3; DoseValuePresentation dvpFinal = (evalunit.Value.CompareTo("%") == 0) ? DoseValuePresentation.Relative : DoseValuePresentation.Absolute; double volumeAchieved = plan.GetVolumeAtDose(evalStructure, dv, vpFinal); objective.Achieved = string.Format("{0:0.00} {1}", volumeAchieved, evalunit.Value); // todo: better formatting based on VolumePresentation #if false string message = string.Format("{0} - Dose unit = {1}, Volume Presentation = {2}, vpFinal = {3}, dvpFinal ={4}", objective.DVHObjective, du.ToString(), vp.ToString(), vpFinal.ToString(), dvpFinal.ToString()); MessageBox.Show(message); #endif } } else { // we have Min, Max, Mean, or Volume if (type.Value.CompareTo("Volume") == 0) { objective.Achieved = string.Format("{0:0.00} {1}", evalStructure.Volume, evalunit.Value); } else { DoseValuePresentation dvp = (evalunit.Value.CompareTo("%") == 0) ? DoseValuePresentation.Relative : DoseValuePresentation.Absolute; DVHData dvh = plan.GetDVHCumulativeData(evalStructure, dvp, VolumePresentation.Relative, 0.1); if (type.Value.CompareTo("Max") == 0) { //checking dose output unit and adapting to template //Gy to cGy if ((evalunit.Value.CompareTo("Gy") == 0) && (dvh.MaxDose.Unit.CompareTo(DoseValue.DoseUnit.cGy) == 0)) { objective.Achieved = new DoseValue(dvh.MaxDose.Dose / 100, DoseValue.DoseUnit.Gy).ToString(); } //Gy to Gy or % to % else { objective.Achieved = dvh.MaxDose.ToString(); } } else if (type.Value.CompareTo("Min") == 0) { //checking dose output unit and adapting to template //Gy to cGy if ((evalunit.Value.CompareTo("Gy") == 0) && (dvh.MinDose.Unit.CompareTo(DoseValue.DoseUnit.cGy) == 0)) { objective.Achieved = new DoseValue(dvh.MinDose.Dose / 100, DoseValue.DoseUnit.Gy).ToString(); } //Gy to Gy or % to % else { objective.Achieved = dvh.MinDose.ToString(); } } else { //checking dose output unit and adapting to template //Gy to cGy if ((evalunit.Value.CompareTo("Gy") == 0) && (dvh.MeanDose.Unit.CompareTo(DoseValue.DoseUnit.cGy) == 0)) { objective.Achieved = new DoseValue(dvh.MeanDose.Dose / 100, DoseValue.DoseUnit.Gy).ToString(); } //Gy to Gy or % to % else { objective.Achieved = dvh.MeanDose.ToString(); } } } } } // further decompose <ateval> //look at the evaluator and compare to goal or variation foreach (var objective in m_objectives) { string evalpattern = @"^(?<type><|<=|=|>=|>)(?<goal>\d+\p{P}\d+|\d+)$"; if (!String.IsNullOrEmpty(objective.Evaluator)) { var matches = Regex.Matches(objective.Evaluator, evalpattern); if (matches.Count != 1) { MessageBox.Show("Eval pattern not recognized"); objective.Met = string.Format("Evaluator expression \"{0}\" is not a recognized expression type.", objective.Evaluator); } Match m = matches[0]; Group goal = m.Groups["goal"]; Group evaltype = m.Groups["type"]; if (String.IsNullOrEmpty(Regex.Match(objective.Achieved, @"\d+\p{P}\d+|\d+").Value)) { objective.Met = "Not evaluated"; } else { double evalvalue = Double.Parse(Regex.Match(objective.Achieved, @"\d+\p{P}\d+|\d+").Value); if (evaltype.Value.CompareTo("<") == 0) { if ((evalvalue - Double.Parse(goal.ToString())) < 0) { objective.Met = "Goal"; } else { if (String.IsNullOrEmpty(objective.Variation)) { objective.Met = "Not met"; } else { if ((evalvalue - Double.Parse(objective.Variation)) < 0) { objective.Met = "Variation"; } else { objective.Met = "Not met"; } } } } else if (evaltype.Value.CompareTo("<=") == 0) { //MessageBox.Show("evaluating <= " + evaltype.ToString()); if ((evalvalue - Double.Parse(goal.ToString())) <= 0) { objective.Met = "Goal"; } else { //MessageBox.Show("Evaluating variation"); if (String.IsNullOrEmpty(objective.Variation)) { //MessageBox.Show(String.Format("Empty variation condition Achieved: {0} Variation: {1}", objective.Achieved.ToString(), objective.Variation.ToString())); objective.Met = "Not met"; } else { //MessageBox.Show(String.Format("Non Empty variation condition Achieved: {0} Variation: {1}", objective.Achieved.ToString(), objective.Variation.ToString())); if ((evalvalue - Double.Parse(objective.Variation)) <= 0) { objective.Met = "Variation"; } else { objective.Met = "Not met"; } } } } else if (evaltype.Value.CompareTo("=") == 0) { if ((evalvalue - Double.Parse(goal.ToString())) == 0) { objective.Met = "Goal"; } else { if (String.IsNullOrEmpty(objective.Variation)) { objective.Met = "Not met"; } else { if ((evalvalue - Double.Parse(objective.Variation)) == 0) { objective.Met = "Variation"; } else { objective.Met = "Not met"; } } } } else if (evaltype.Value.CompareTo(">=") == 0) { if ((evalvalue - Double.Parse(goal.ToString())) >= 0) { objective.Met = "Goal"; } else { if (String.IsNullOrEmpty(objective.Variation)) { objective.Met = "Not met"; } else { if ((evalvalue - Double.Parse(objective.Variation)) >= 0) { objective.Met = "Variation"; } else { objective.Met = "Not met"; } } } } else if (evaltype.Value.CompareTo(">") == 0) { if ((evalvalue - Double.Parse(goal.ToString())) > 0) { objective.Met = "Goal"; } else { if (String.IsNullOrEmpty(objective.Variation)) { objective.Met = "Not met"; } else { if ((evalvalue - Double.Parse(objective.Variation)) > 0) { objective.Met = "Variation"; } else { objective.Met = "Not met"; } } } } } } } }
public void addPQMInfo(PlanningItem plan, Structure organ, XmlWriter writer) { writer.WriteStartElement("PQM"); writer.WriteAttributeString("type", "DoseAtVolume"); writer.WriteAttributeString("name", name); DoseValue dv = plan.GetDoseAtVolume(organ, volume, vp, dvp); writer.WriteStartElement("DoseValue"); writer.WriteAttributeString("units", dv.UnitAsString); writer.WriteAttributeString("calculated", true.ToString()); writer.WriteString(dv.ValueAsString); writer.WriteEndElement(); // </DoseValue> writer.WriteStartElement("Volume"); writer.WriteAttributeString("units", vp.ToString()); writer.WriteAttributeString("calculated", false.ToString()); writer.WriteString(volume.ToString("0.000")); writer.WriteEndElement(); // </Volume> string limType = lt.ToString(), tolType; if (lt == PQMUtilities.LimitType.upper) { tolType = "leq"; } else { tolType = "geq"; } writer.WriteStartElement("Evaluate"); writer.WriteStartElement("Limit"); writer.WriteAttributeString("type", limType); writer.WriteString(doseConstraint.ValueAsString); writer.WriteEndElement(); // </Limit> writer.WriteStartElement("Tolerance"); writer.WriteAttributeString("type", tolType); writer.WriteString(upperLimit.ToString("0.000")); writer.WriteEndElement(); // </Tolerance> writer.WriteStartElement("Result"); double limitMax = (doseConstraint.Dose * upperLimit); writer.WriteElementString("MaxLimit", limitMax.ToString("0.000")); string pfw = "PASS"; if (lt == PQMUtilities.LimitType.upper) { if (dv.Dose > doseConstraint.Dose && dv.Dose <= limitMax) { pfw = "WARN"; } else if (dv.Dose > limitMax) { pfw = "FAIL"; } } else { if (dv.Dose < doseConstraint.Dose && dv.Dose >= limitMax) { pfw = "WARN"; } else if (dv.Dose < limitMax) { pfw = "FAIL"; } } writer.WriteElementString("PFW", pfw); writer.WriteEndElement(); // </Result> writer.WriteEndElement(); // </Evaluate> writer.WriteEndElement(); // </PQM> }