public static NeurologyForm LoadNeurologyFormFrom(XDocument xmlDocument) { var formXml = xmlDocument.Root.Element("NeurologyForm"); var neurologyForm = new NeurologyForm() { AnalContraction = GetBinaryObservationFrom(formXml.Element("AnalContraction")), AnalSensation = GetBinaryObservationFrom(formXml.Element("AnalSensation")) }; neurologyForm.SetRightLowestNonKeyMuscleWithMotorFunction(formXml.Element("RightLowestNonKeyMuscleWithMotorFunction").Value); neurologyForm.SetLeftLowestNonKeyMuscleWithMotorFunction(formXml.Element("LeftLowestNonKeyMuscleWithMotorFunction").Value); foreach (var dermatomeElement in formXml.Descendants("Dermatome")) AddValuesFromDermatomeToForm(dermatomeElement, neurologyForm); return neurologyForm; }
public NeurologyFormTotalsSummary Post(NeurologyFormModel formModel) { var neurologyForm = new NeurologyForm(); formModel.BindTo(neurologyForm); return Algorithm.GetTotalsSummaryFor(neurologyForm); }
public void BindTo(NeurologyForm neurologyForm) { neurologyForm.AnalContraction = AnalContraction; neurologyForm.AnalSensation = AnalSensation; if (!string.IsNullOrEmpty(RightLowestNonKeyMuscleWithMotorFunction)) neurologyForm.SetRightLowestNonKeyMuscleWithMotorFunction(RightLowestNonKeyMuscleWithMotorFunction); if (!string.IsNullOrEmpty(LeftLowestNonKeyMuscleWithMotorFunction)) neurologyForm.SetLeftLowestNonKeyMuscleWithMotorFunction(LeftLowestNonKeyMuscleWithMotorFunction); neurologyForm.UpdateLevelAt("C2", C2RightTouch, C2LeftTouch, C2RightPrick, C2LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("C3", C3RightTouch, C3LeftTouch, C3RightPrick, C3LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("C4", C4RightTouch, C4LeftTouch, C4RightPrick, C4LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("C5", C5RightTouch, C5LeftTouch, C5RightPrick, C5LeftPrick, C5RightMotor, C5LeftMotor); neurologyForm.UpdateLevelAt("C6", C6RightTouch, C6LeftTouch, C6RightPrick, C6LeftPrick, C6RightMotor, C6LeftMotor); neurologyForm.UpdateLevelAt("C7", C7RightTouch, C7LeftTouch, C7RightPrick, C7LeftPrick, C7RightMotor, C7LeftMotor); neurologyForm.UpdateLevelAt("C8", C8RightTouch, C8LeftTouch, C8RightPrick, C8LeftPrick, C8RightMotor, C8LeftMotor); neurologyForm.UpdateLevelAt("T1", T1RightTouch, T1LeftTouch, T1RightPrick, T1LeftPrick, T1RightMotor, T1LeftMotor); neurologyForm.UpdateLevelAt("T2", T2RightTouch, T2LeftTouch, T2RightPrick, T2LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T3", T3RightTouch, T3LeftTouch, T3RightPrick, T3LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T4", T4RightTouch, T4LeftTouch, T4RightPrick, T4LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T5", T5RightTouch, T5LeftTouch, T5RightPrick, T5LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T6", T6RightTouch, T6LeftTouch, T6RightPrick, T6LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T7", T7RightTouch, T7LeftTouch, T7RightPrick, T7LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T8", T8RightTouch, T8LeftTouch, T8RightPrick, T8LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T9", T9RightTouch, T9LeftTouch, T9RightPrick, T9LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T10", T10RightTouch, T10LeftTouch, T10RightPrick, T10LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T11", T11RightTouch, T11LeftTouch, T11RightPrick, T11LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("T12", T12RightTouch, T12LeftTouch, T12RightPrick, T12LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("L1", L1RightTouch, L1LeftTouch, L1RightPrick, L1LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("L2", L2RightTouch, L2LeftTouch, L2RightPrick, L2LeftPrick, L2RightMotor, L2LeftMotor); neurologyForm.UpdateLevelAt("L3", L3RightTouch, L3LeftTouch, L3RightPrick, L3LeftPrick, L3RightMotor, L3LeftMotor); neurologyForm.UpdateLevelAt("L4", L4RightTouch, L4LeftTouch, L4RightPrick, L4LeftPrick, L4RightMotor, L4LeftMotor); neurologyForm.UpdateLevelAt("L5", L5RightTouch, L5LeftTouch, L5RightPrick, L5LeftPrick, L5RightMotor, L5LeftMotor); neurologyForm.UpdateLevelAt("S1", S1RightTouch, S1LeftTouch, S1RightPrick, S1LeftPrick, S1RightMotor, S1LeftMotor); neurologyForm.UpdateLevelAt("S2", S2RightTouch, S2LeftTouch, S2RightPrick, S2LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("S3", S3RightTouch, S3LeftTouch, S3RightPrick, S3LeftPrick, "0", "0"); neurologyForm.UpdateLevelAt("S4_5", S4_5RightTouch, S4_5LeftTouch, S4_5RightPrick, S4_5LeftPrick, "0", "0"); }
public void GetTotalsForNeurologyForm() { // Arrange var neurologyForm = new NeurologyForm() { AnalContraction = BinaryObservation.No, AnalSensation = BinaryObservation.Yes }; neurologyForm.UpdateLevelAt("C2", "2", "2", "2", "2", "0", "0"); neurologyForm.UpdateLevelAt("C3", "2", "2", "2", "2", "0", "0"); neurologyForm.UpdateLevelAt("C4", "2", "2", "2", "2", "0", "0"); neurologyForm.UpdateLevelAt("C5", "2", "2", "2", "2", "5", "5"); neurologyForm.UpdateLevelAt("C6", "1", "1", "1", "0", "1", "1"); neurologyForm.UpdateLevelAt("C7", "1", "0", "1", "0", "0", "0"); neurologyForm.UpdateLevelAt("C8", "1", "0", "1", "0", "0", "0"); neurologyForm.UpdateLevelAt("T1", "1", "0", "1", "0", "0", "0"); neurologyForm.UpdateLevelAt("T2", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T3", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T4", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T5", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T6", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T7", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T8", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T9", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T10", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T11", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("T12", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("L1", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("L2", "NT", "NT", "NT", "NT", "NT", "NT"); neurologyForm.UpdateLevelAt("L3", "NT", "NT", "NT", "NT", "NT", "NT"); neurologyForm.UpdateLevelAt("L4", "NT", "NT", "NT", "NT", "NT", "NT"); neurologyForm.UpdateLevelAt("L5", "NT", "NT", "NT", "NT", "NT", "NT"); neurologyForm.UpdateLevelAt("S1", "NT", "NT", "NT", "NT", "NT", "NT"); neurologyForm.UpdateLevelAt("S2", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("S3", "NT", "NT", "NT", "NT", "0", "0"); neurologyForm.UpdateLevelAt("S4_5", "NT", "NT", "NT", "NT", "0", "0"); // Act var summary = Algorithm.GetTotalsSummaryFor(neurologyForm); // Assert Assert.AreEqual("B,C,D", summary.AsiaImpairmentScale); Assert.AreEqual("I", summary.Completeness); Assert.AreEqual("UTD", summary.LeftLowerMotorTotal); Assert.AreEqual("C5", summary.LeftMotor); Assert.AreEqual("UTD", summary.LeftMotorTotal); Assert.AreEqual("NA", summary.LeftMotorZpp); Assert.AreEqual("UTD", summary.LeftPrickTotal); Assert.AreEqual("C5", summary.LeftSensory); Assert.AreEqual("NA", summary.LeftSensoryZpp); Assert.AreEqual("UTD", summary.LeftTouchTotal); Assert.AreEqual("6", summary.LeftUpperMotorTotal); Assert.AreEqual("UTD", summary.LowerMotorTotal); Assert.AreEqual("C5", summary.NeurologicalLevelOfInjury); Assert.AreEqual("UTD", summary.PrickTotal); Assert.AreEqual("UTD", summary.RightLowerMotorTotal); Assert.AreEqual("C5", summary.RightMotor); Assert.AreEqual("UTD", summary.RightMotorTotal); Assert.AreEqual("NA", summary.RightMotorZpp); Assert.AreEqual("UTD", summary.RightPrickTotal); Assert.AreEqual("C5", summary.RightSensory); Assert.AreEqual("NA", summary.RightSensoryZpp); Assert.AreEqual("UTD", summary.RightTouchTotal); Assert.AreEqual("6", summary.RightUpperMotorTotal); Assert.AreEqual("UTD", summary.TouchTotal); Assert.AreEqual("12", summary.UpperMotorTotal); }
private static void AddValuesFromDermatomeToForm(XElement dermatomeElement, NeurologyForm neurologyForm) { // Right Touch var rightTouchName = dermatomeElement.Element("RightTouch").Value; var rightPrickName = dermatomeElement.Element("RightPrick").Value; var leftTouchName = dermatomeElement.Element("LeftTouch").Value; var leftPrickName = dermatomeElement.Element("LeftPrick").Value; var rightMotorElement = dermatomeElement.Element("RightMotor"); var rightMotorName = rightMotorElement == null ? "0" : rightMotorElement.Value; var leftMotorElement = dermatomeElement.Element("LeftMotor"); var leftMotorName = leftMotorElement == null ? "0" : leftMotorElement.Value; neurologyForm.UpdateLevelAt(dermatomeElement.Attribute("name").Value, rightTouchName, leftTouchName, rightPrickName, leftPrickName, rightMotorName, leftMotorName); }
/// <summary> /// Returns the results produced by the ISNCSCI Algorithm ir a raw values format. /// </summary> /// <param name="neurologyForm">Neurology form that has been populated with the values to be used in the algorithm calculations.</param> /// <returns> /// Totals in raw values format. The results contain lists with every prossible value for each field. /// You can use the resulting object to obtained a summarized version, which uses ranges, by passing the result to the method GetTotalsSummaryFor /// </returns> public static NeurologyFormTotals GetTotalsFor(NeurologyForm neurologyForm) { var totals = new NeurologyFormTotals(); UpdateTotalsWithLevelAt(neurologyForm, totals, neurologyForm.GetLevelWithName("C2"), false, false); totals.UpperMotorTotal = totals.RightUpperMotorTotal + totals.LeftUpperMotorTotal; totals.LowerMotorTotal = totals.RightLowerMotorTotal + totals.LeftLowerMotorTotal; totals.TouchTotal = totals.RightTouchTotal + totals.LeftTouchTotal; totals.PrickTotal = totals.RightPrickTotal + totals.LeftPrickTotal; var s4_5 = neurologyForm.GetLevelWithName("S4_5"); var c1 = neurologyForm.GetLevelWithName("C2").Previous; if (totals.RightSensoryZppHasOnlySoftValues) totals.AddRightSensoryZppValue(c1); if (totals.LeftSensoryZppHasOnlySoftValues) totals.AddLeftSensoryZppValue(c1); if (totals.RightMotorZppHasOnlySoftValues) totals.AddRightMotorZppValue(c1); if (totals.LeftMotorZppHasOnlySoftValues) totals.AddLeftMotorZppValue(c1); if (totals.MostRostralRightLevelWithMotorFunction == null) totals.MostRostralRightLevelWithMotorFunction = c1; if (totals.MostRostralLeftLevelWithMotorFunction == null) totals.MostRostralLeftLevelWithMotorFunction = c1; if (totals.MostCaudalRightLevelWithMotorFunction == null) totals.MostCaudalRightLevelWithMotorFunction = c1; if (totals.MostCaudalLeftLevelWithMotorFunction == null) totals.MostCaudalLeftLevelWithMotorFunction = c1; // [ASIA learning center 2012-11-14] Sensory incomplete: Sacral sparing of sensory function var isSensoryIncomplete = neurologyForm.AnalSensation == BinaryObservation.Yes || neurologyForm.AnalSensation == BinaryObservation.NT || !"0".Equals(s4_5.RightTouchName) || !"0".Equals(s4_5.LeftTouchName) || !"0".Equals(s4_5.RightPrickName) || !"0".Equals(s4_5.LeftPrickName); var couldNotHaveMotorFunctionMoreThan3LevelsBelowMotorLevel = CouldNotHaveMotorFunctionMoreThan3LevelsBelowMotorLevel(neurologyForm, totals); var couldNotBeMotorIncomplete = (neurologyForm.AnalContraction == BinaryObservation.No || neurologyForm.AnalContraction == BinaryObservation.NT) && isSensoryIncomplete && couldNotHaveMotorFunctionMoreThan3LevelsBelowMotorLevel; if ((neurologyForm.AnalContraction == BinaryObservation.No || neurologyForm.AnalContraction == BinaryObservation.NT) && (neurologyForm.AnalSensation == BinaryObservation.No || neurologyForm.AnalSensation == BinaryObservation.NT) && s4_5.RightTouchValue == 0 && !s4_5.RightTouchImpairmentNotDueToSci && s4_5.RightPrickValue == 0 && !s4_5.RightPrickImpairmentNotDueToSci && s4_5.LeftTouchValue == 0 && !s4_5.LeftTouchImpairmentNotDueToSci && s4_5.LeftPrickValue == 0 && !s4_5.LeftPrickImpairmentNotDueToSci) totals.AddAsiaImpairmentScaleValue("A"); if (couldNotBeMotorIncomplete && totals.MostRostralNeurologicalLevelOfInjury.Name != "S4_5") totals.AddAsiaImpairmentScaleValue("B"); //// Not an ASIA E only //// AND not an ASIA A only if (totals.MostRostralNeurologicalLevelOfInjury.Name != "S4_5" && (isSensoryIncomplete || neurologyForm.AnalContraction == BinaryObservation.Yes || neurologyForm.AnalContraction == BinaryObservation.NT)) { bool couldBeAsiaC; bool couldBeAsiaD; CouldBeAsiaCorD(neurologyForm, totals, out couldBeAsiaC, out couldBeAsiaD); if (couldBeAsiaC) totals.AddAsiaImpairmentScaleValue("C"); if (couldBeAsiaD) totals.AddAsiaImpairmentScaleValue("D"); } if (totals.RightSensoryContains("S4_5") && totals.LeftSensoryContains("S4_5") && totals.RightMotorContains("S4_5") && totals.LeftMotorContains("S4_5")) totals.AddAsiaImpairmentScaleValue("E"); return totals; }
/// <summary> /// Recursive method which iterates through the values in a nuerology form while it updates the totals generating the results produced by the algorithm. /// </summary> /// <param name="neurologyForm">Form being evaluated.</param> /// <param name="totals">Brand new totals object where the results are to be stored.</param> /// <param name="level">Current neurology level being evaluated</param> /// <param name="nextNonKeyMuscleShouldBeRightMotor">Flag used to evaluate the Kathy Collins condition on the right motor results.</param> /// <param name="nextNonKeyMuscleShouldBeLeftMotor">Flag used to evaluate the Kathy Collins condition on the left motor results.</param> private static void UpdateTotalsWithLevelAt(NeurologyForm neurologyForm, NeurologyFormTotals totals, NeurologyFormLevel level, bool nextNonKeyMuscleShouldBeRightMotor, bool nextNonKeyMuscleShouldBeLeftMotor) { totals.RightTouchTotal += level.RightTouchValue; totals.LeftTouchTotal += level.LeftTouchValue; totals.RightPrickTotal += level.RightPrickValue; totals.LeftPrickTotal += level.LeftPrickValue; if (level.IsKeyMuscle) { if (level.IsLowerMuscle) { if (level.RightMotorImpairmentNotDueToSci && !totals.RightLowerMotorTotalHasImpairmentNotDueToSci) totals.RightLowerMotorTotalHasImpairmentNotDueToSci = true; if (level.LeftMotorImpairmentNotDueToSci && !totals.LeftLowerMotorTotalHasImpairmentNotDueToSci) totals.LeftLowerMotorTotalHasImpairmentNotDueToSci = true; if (NtRegex.IsMatch(level.RightMotorName) && !level.RightMotorImpairmentNotDueToSci) totals.RightLowerMotorContainsNt = true; if (NtRegex.IsMatch(level.LeftMotorName) && !level.LeftMotorImpairmentNotDueToSci) totals.LeftLowerMotorContainsNt = true; } else { if (level.RightMotorImpairmentNotDueToSci && !totals.RightUpperMotorTotalHasImpairmentNotDueToSci) totals.RightUpperMotorTotalHasImpairmentNotDueToSci = true; if (level.LeftMotorImpairmentNotDueToSci && !totals.LeftUpperMotorTotalHasImpairmentNotDueToSci) totals.LeftUpperMotorTotalHasImpairmentNotDueToSci = true; if (NtRegex.IsMatch(level.RightMotorName) && !level.RightMotorImpairmentNotDueToSci) totals.RightUpperMotorContainsNt = true; if (NtRegex.IsMatch(level.LeftMotorName) && !level.LeftMotorImpairmentNotDueToSci) totals.LeftUpperMotorContainsNt = true; } } else { if (nextNonKeyMuscleShouldBeRightMotor) { nextNonKeyMuscleShouldBeRightMotor = false; totals.AddRightMotorValue(level.Previous); if (!totals.RightSensoryHasOnlySoftValues) totals.RightMotorHasOnlySoftValues = false; } if (nextNonKeyMuscleShouldBeLeftMotor) { nextNonKeyMuscleShouldBeLeftMotor = false; totals.AddLeftMotorValue(level.Previous); if (!totals.LeftSensoryHasOnlySoftValues) totals.LeftMotorHasOnlySoftValues = false; } } if (level.RightTouchImpairmentNotDueToSci && !totals.RightTouchTotalHasImpairmentNotDueToSci) totals.RightTouchTotalHasImpairmentNotDueToSci = true; if (level.LeftTouchImpairmentNotDueToSci && !totals.LeftTouchTotalHasImpairmentNotDueToSci) totals.LeftTouchTotalHasImpairmentNotDueToSci = true; if (level.RightPrickImpairmentNotDueToSci && !totals.RightPrickTotalHasImpairmentNotDueToSci) totals.RightPrickTotalHasImpairmentNotDueToSci = true; if (level.LeftPrickImpairmentNotDueToSci && !totals.LeftPrickTotalHasImpairmentNotDueToSci) totals.LeftPrickTotalHasImpairmentNotDueToSci = true; // Check if a column contains any NT value so we can properly format the total presented to the user if (NtRegex.IsMatch(level.RightTouchName) && !level.RightTouchImpairmentNotDueToSci && !totals.RightTouchContainsNt) totals.RightTouchContainsNt = true; if (NtRegex.IsMatch(level.LeftTouchName) && !level.LeftTouchImpairmentNotDueToSci && !totals.LeftTouchContainsNt) totals.LeftTouchContainsNt = true; if (NtRegex.IsMatch(level.RightPrickName) && !level.RightPrickImpairmentNotDueToSci && !totals.RightPrickContainsNt) totals.RightPrickContainsNt = true; if (NtRegex.IsMatch(level.LeftPrickName) && !level.LeftPrickImpairmentNotDueToSci && !totals.LeftPrickContainsNt) totals.LeftPrickContainsNt = true; if (totals.RightSensoryHasOnlySoftValues && ((level.RightTouchValue != 2 && !level.RightTouchImpairmentNotDueToSci) || (level.RightPrickValue != 2 && !level.RightPrickImpairmentNotDueToSci))) { totals.AddRightSensoryValue(level.Previous); if ("S4_5".Equals(level.Name) && (level.RightTouchValue == 2 || NtRegex.IsMatch(level.RightTouchName)) && (level.RightPrickValue == 2 || NtRegex.IsMatch(level.RightPrickName))) { totals.AddRightSensoryValue(level); if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues) totals.AddNeurologicalLevelOfInjury(level); } if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues) totals.AddNeurologicalLevelOfInjury(level.Previous); if ((level.RightTouchValue != 2 && !NtRegex.IsMatch(level.RightTouchName)) || (level.RightPrickValue != 2 && !NtRegex.IsMatch(level.RightPrickName))) { totals.RightSensoryHasOnlySoftValues = false; totals.NeurologicalLevelOfInjuryHasOnlySoftValues = false; } if (level.IsKeyMuscle) { nextNonKeyMuscleShouldBeRightMotor = true; totals.HasRightCollins = true; } } if (totals.LeftSensoryHasOnlySoftValues && ((level.LeftTouchValue != 2 && !level.LeftTouchImpairmentNotDueToSci) || (level.LeftPrickValue != 2 && !level.LeftPrickImpairmentNotDueToSci))) { totals.AddLeftSensoryValue(level.Previous); if ("S4_5".Equals(level.Name) && (level.LeftTouchValue == 2 || NtRegex.IsMatch(level.LeftTouchName)) && (level.LeftPrickValue == 2 || NtRegex.IsMatch(level.LeftPrickName))) { totals.AddLeftSensoryValue(level); if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues) totals.AddNeurologicalLevelOfInjury(level); } if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues) totals.AddNeurologicalLevelOfInjury(level.Previous); if ((level.LeftTouchValue != 2 && !NtRegex.IsMatch(level.LeftTouchName)) || (level.LeftPrickValue != 2 && !NtRegex.IsMatch(level.LeftPrickName))) { totals.LeftSensoryHasOnlySoftValues = false; totals.NeurologicalLevelOfInjuryHasOnlySoftValues = false; } if (level.IsKeyMuscle) { nextNonKeyMuscleShouldBeLeftMotor = true; totals.HasLeftCollins = true; } } if (totals.RightMotorHasOnlySoftValues && level.RightMotorValue != 5 && !level.RightMotorImpairmentNotDueToSci) { if (level.IsKeyMuscle && (level.RightMotorValue >= 3 || NtRegex.IsMatch(level.RightMotorName))) { totals.AddRightMotorValue(level); // Check if left won't make the NLI have to be the previous level. // Let the logic for left motor handle the SNL instead if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues && (level.LeftMotorValue > 2 || level.LeftMotorImpairmentNotDueToSci || NtRegex.IsMatch(level.LeftMotorName))) { totals.AddNeurologicalLevelOfInjury(level); if (!NtRegex.IsMatch(level.RightMotorName)) totals.NeurologicalLevelOfInjuryHasOnlySoftValues = false; } } if (level.RightMotorValue < 3 || NtRegex.IsMatch(level.RightMotorName)) { totals.AddRightMotorValue(level.Previous); if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues) { totals.AddNeurologicalLevelOfInjury(level.Previous); if (!NtRegex.IsMatch(level.RightMotorName)) totals.NeurologicalLevelOfInjuryHasOnlySoftValues = false; } } if (!NtRegex.IsMatch(level.RightMotorName)) totals.RightMotorHasOnlySoftValues = false; } if (totals.LeftMotorHasOnlySoftValues && level.LeftMotorValue != 5 && !level.LeftMotorImpairmentNotDueToSci) { if (level.IsKeyMuscle && (level.LeftMotorValue >= 3 || NtRegex.IsMatch(level.LeftMotorName))) { totals.AddLeftMotorValue(level); if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues) totals.AddNeurologicalLevelOfInjury(level); } if (level.LeftMotorValue < 3 || NtRegex.IsMatch(level.LeftMotorName)) { totals.AddLeftMotorValue(level.Previous); if (totals.NeurologicalLevelOfInjuryHasOnlySoftValues) totals.AddNeurologicalLevelOfInjury(level.Previous); } if (!NtRegex.IsMatch(level.LeftMotorName)) { totals.LeftMotorHasOnlySoftValues = false; totals.NeurologicalLevelOfInjuryHasOnlySoftValues = false; } } /* -- RECURSIVE CALL --------------- */ if (level.Next != null) UpdateTotalsWithLevelAt(neurologyForm, totals, level.Next, nextNonKeyMuscleShouldBeRightMotor && totals.RightMotorHasOnlySoftValues, nextNonKeyMuscleShouldBeLeftMotor && totals.LeftMotorHasOnlySoftValues); #region This happens when there are INTACT values ------------------------------------------- if ("S4_5".Equals(level.Name)) { if (totals.RightSensoryHasOnlySoftValues && totals.LeftSensoryHasOnlySoftValues && totals.RightMotorHasOnlySoftValues && totals.LeftMotorHasOnlySoftValues) totals.AddNeurologicalLevelOfInjury(level); if (totals.RightSensoryHasOnlySoftValues) { totals.AddRightSensoryValue(level); totals.RightSensoryHasOnlySoftValues = false; } if (totals.LeftSensoryHasOnlySoftValues) { totals.AddLeftSensoryValue(level); totals.LeftSensoryHasOnlySoftValues = false; } if (totals.RightMotorHasOnlySoftValues) { totals.AddRightMotorValue(level); totals.RightMotorHasOnlySoftValues = false; } if (totals.LeftMotorHasOnlySoftValues) { totals.AddLeftMotorValue(level); totals.LeftMotorHasOnlySoftValues = false; } } #endregion if (totals.RightSensoryZppHasOnlySoftValues && (!"0".Equals(level.RightTouchName) || !"0".Equals(level.RightPrickName))) { if ((level.RightTouchValue > 0 || level.RightTouchImpairmentNotDueToSci) || (level.RightPrickValue > 0 || level.RightPrickImpairmentNotDueToSci)) totals.RightSensoryZppHasOnlySoftValues = false; totals.AddRightSensoryZppValue(level); } if (totals.LeftSensoryZppHasOnlySoftValues && (!"0".Equals(level.LeftTouchName) || !"0".Equals(level.LeftPrickName))) { if ((level.LeftTouchValue > 0 || level.LeftTouchImpairmentNotDueToSci) || (level.LeftPrickValue > 0 || level.LeftPrickImpairmentNotDueToSci)) totals.LeftSensoryZppHasOnlySoftValues = false; totals.AddLeftSensoryZppValue(level); } if (totals.RightMotorZppHasOnlySoftValues && (level.HasOtherRightMotorFunction || (!"0".Equals(level.RightMotorName) && (level.IsKeyMuscle || totals.RightMotorContains(level.Name))))) { if ((level.RightMotorImpairmentNotDueToSci || level.HasOtherRightMotorFunction || !NtRegex.IsMatch(level.RightMotorName)) && (level.IsKeyMuscle || level.Ordinal < 4 || (level.Ordinal > 25 && !totals.RightUpperMotorContainsNt && !totals.RightLowerMotorContainsNt && !totals.HasRightCollins) || (level.Ordinal > 8 && level.Ordinal < 21 && !totals.RightUpperMotorContainsNt))) totals.RightMotorZppHasOnlySoftValues = false; totals.AddRightMotorZppValue(level); } if (totals.LeftMotorZppHasOnlySoftValues && (level.HasOtherLeftMotorFunction || (!"0".Equals(level.LeftMotorName) && (level.IsKeyMuscle || totals.LeftMotorContains(level.Name))))) { if ((level.LeftMotorImpairmentNotDueToSci || level.HasOtherLeftMotorFunction || !NtRegex.IsMatch(level.LeftMotorName)) && (level.IsKeyMuscle || level.Ordinal < 4 || (level.Ordinal > 25 && !totals.LeftUpperMotorContainsNt && !totals.LeftLowerMotorContainsNt && !totals.HasLeftCollins) || (level.Ordinal > 8 && level.Ordinal < 21 && !totals.LeftUpperMotorContainsNt))) totals.LeftMotorZppHasOnlySoftValues = false; totals.AddLeftMotorZppValue(level); } // Update most Rostral levels with motor function if ((level.IsKeyMuscle || level.HasOtherRightMotorFunction) && totals.MostRostralRightLevelWithMotorFunction == null && (level.RightMotorImpairmentNotDueToSci || level.HasOtherRightMotorFunction || (level.RightMotorValue != 0 && level.IsKeyMuscle))) totals.MostRostralRightLevelWithMotorFunction = level; if ((level.IsKeyMuscle || level.HasOtherLeftMotorFunction) && totals.MostRostralLeftLevelWithMotorFunction == null && (level.LeftMotorImpairmentNotDueToSci || level.HasOtherLeftMotorFunction || (level.LeftMotorValue != 0 && level.IsKeyMuscle))) totals.MostRostralLeftLevelWithMotorFunction = level; // Update most Caudal levels with motor function if ((level.IsKeyMuscle || level.HasOtherRightMotorFunction) && totals.MostCaudalRightLevelWithMotorFunction == null && (!"0".Equals(level.RightMotorName) || level.HasOtherRightMotorFunction)) totals.MostCaudalRightLevelWithMotorFunction = level; if ((level.IsKeyMuscle || level.HasOtherLeftMotorFunction) && totals.MostCaudalLeftLevelWithMotorFunction == null && (!"0".Equals(level.LeftMotorName) || level.HasOtherLeftMotorFunction)) totals.MostCaudalLeftLevelWithMotorFunction = level; if (!level.IsKeyMuscle) return; if (level.IsLowerMuscle) { totals.RightLowerMotorTotal += level.RightMotorValue; totals.LeftLowerMotorTotal += level.LeftMotorValue; } else { totals.RightUpperMotorTotal += level.RightMotorValue; totals.LeftUpperMotorTotal += level.LeftMotorValue; } }
/// <summary> /// Evaluates the specified form and totals to determine if any of the different /// return conditions could produce a case where there could be motor function more /// than 3 levels below the injury level. /// </summary> /// <param name="neurologyForm">Form that was used to produce the totals.</param> /// <param name="totals">Totals retunred by the algorithm.</param> /// <returns>Flag indicating if any combination in the totals could have a case with motor function more than 3 levels below the injury level.</returns> private static bool CouldNotHaveMotorFunctionMoreThan3LevelsBelowMotorLevel(NeurologyForm neurologyForm, NeurologyFormTotals totals) { NeurologyFormLevel mostRostralRightLevelWithMotor = null; NeurologyFormLevel mostRostralLeftLevelWithMotor = null; var currentLevel = neurologyForm.GetLevelWithName("S1"); while ((mostRostralRightLevelWithMotor == null || mostRostralLeftLevelWithMotor == null) && currentLevel != null // Could happen if SNL is C1 && currentLevel.Ordinal >= totals.MostCaudalNeurologicalLevelOfInjury.Ordinal) { if (mostRostralRightLevelWithMotor == null && (currentLevel.RightMotorImpairmentNotDueToSci || currentLevel.HasOtherRightMotorFunction || (currentLevel.RightMotorValue != 0 && currentLevel.IsKeyMuscle))) mostRostralRightLevelWithMotor = currentLevel; if (mostRostralLeftLevelWithMotor == null && (currentLevel.LeftMotorImpairmentNotDueToSci || currentLevel.HasOtherLeftMotorFunction || (currentLevel.LeftMotorValue != 0 && currentLevel.IsKeyMuscle))) mostRostralLeftLevelWithMotor = currentLevel; currentLevel = currentLevel.Previous; } return (mostRostralRightLevelWithMotor == null || mostRostralRightLevelWithMotor.Ordinal - totals.MostCaudalRightMotor.Ordinal <= 3) && (mostRostralLeftLevelWithMotor == null || mostRostralLeftLevelWithMotor.Ordinal - totals.MostCaudalLeftMotor.Ordinal <= 3); }
/// <summary> /// Evaluates the specified form and totals to determine if any of the different /// return conditions could produce a case where the Asia Impairment Scale is C o D. /// </summary> /// <param name="neurologyForm">Form that was used to produce the totals.</param> /// <param name="totals">Totals retunred by the algorithm.</param> /// <param name="couldBeAsiaC">out variable use as flag indicating if this case is a possible ASIA C.</param> /// <param name="couldBeAsiaD">out variable use as flag indicating if this case is a possible ASIA D.</param> private static void CouldBeAsiaCorD(NeurologyForm neurologyForm, NeurologyFormTotals totals, out bool couldBeAsiaC, out bool couldBeAsiaD) { couldBeAsiaC = false; couldBeAsiaD = false; NeurologyFormLevel rightMotor = null; NeurologyFormLevel leftMotor = null; // Check if the patient could be motor incoplete via sphincter contraction // Otherwise we need to check for motor function more than 3 levels below motor level. var couldHaveAnalContraction = neurologyForm.AnalContraction == BinaryObservation.Yes || neurologyForm.AnalContraction == BinaryObservation.NT; //var couldNotHaveAnalContraction = neurologyForm.AnalContraction == BinaryObservation.No || neurologyForm.AnalContraction == BinaryObservation.NT; var nliEnum = totals.GetNeurologicalLevelsOfInjury().GetEnumerator(); while (nliEnum.MoveNext() && (!couldBeAsiaC || !couldBeAsiaD)) { //var otherMotorIsMoreThanThreeLevelsBelowNli = (neurologyForm.) // RIGHT MOTOR // If not motor incomplete already, find the right motor level that correspond to this particular neurological level if (!couldHaveAnalContraction && (rightMotor == null || rightMotor.Ordinal < nliEnum.Current.Ordinal)) { var rightMotorValues = totals.GetRightMotorValues().GetEnumerator(); rightMotor = null; while (rightMotor == null && rightMotorValues.MoveNext()) { if (rightMotorValues.Current.Ordinal >= nliEnum.Current.Ordinal) rightMotor = rightMotorValues.Current; } rightMotorValues.Dispose(); } // LEFT MOTOR // If not motor incomplete already, find the left motor level that correspond to this particular neurological level if (!couldHaveAnalContraction && (leftMotor == null || leftMotor.Ordinal < nliEnum.Current.Ordinal)) { var leftMotorValues = totals.GetLeftMotorValues().GetEnumerator(); leftMotor = null; while (leftMotor == null && leftMotorValues.MoveNext()) { if (leftMotorValues.Current.Ordinal >= nliEnum.Current.Ordinal) leftMotor = leftMotorValues.Current; } leftMotorValues.Dispose(); } //if (couldNotHaveAnalContraction // && (rightMotor == null || totals.MostCaudalRightLevelWithMotorFunction.Ordinal - rightMotor.Ordinal <= 3) // && (leftMotor == null || totals.MostCaudalLeftLevelWithMotorFunction.Ordinal - leftMotor.Ordinal <= 3)) // couldBeAsiaB = true; // If the test is not motor incomplete at this level, do not continue to count motor levels, move to the next nli available. if (!couldHaveAnalContraction && totals.MostCaudalRightLevelWithMotorFunction.Ordinal - rightMotor.Ordinal <= 3 && totals.MostCaudalLeftLevelWithMotorFunction.Ordinal - leftMotor.Ordinal <= 3) continue; // When motor incomplete and the nli is S1 or more caudal, it is automatically D since there are no myotomes to count from. // We can break the loop. if (nliEnum.Current.Ordinal > 24) // Greater than L5 (24) { couldBeAsiaD = true; break; } // If motor incomplete, count the motor levels with muscle grade greater than two var levelsWithMuscleGradeGreaterThanTwo = 0; var levelsWithMuscleGradeLessThanThree = 0; var eligibleLevelCount = 0; var currentLevel = nliEnum.Current.Next; while (currentLevel != null) { if (currentLevel.IsKeyMuscle) { eligibleLevelCount += 2; if (currentLevel.RightMotorValue > 2 || currentLevel.RightMotorImpairmentNotDueToSci || NtRegex.IsMatch(currentLevel.RightMotorName)) levelsWithMuscleGradeGreaterThanTwo++; if ((currentLevel.RightMotorValue < 3 || NtRegex.IsMatch(currentLevel.RightMotorName)) && !currentLevel.RightMotorImpairmentNotDueToSci) levelsWithMuscleGradeLessThanThree++; if (currentLevel.LeftMotorValue > 2 || currentLevel.LeftMotorImpairmentNotDueToSci || NtRegex.IsMatch(currentLevel.LeftMotorName)) levelsWithMuscleGradeGreaterThanTwo++; if ((currentLevel.LeftMotorValue < 3 || NtRegex.IsMatch(currentLevel.LeftMotorName)) && !currentLevel.LeftMotorImpairmentNotDueToSci) levelsWithMuscleGradeLessThanThree++; } currentLevel = currentLevel.Next; } // If not more than half the myotomes contain values less to 3, this is an Asia C if (levelsWithMuscleGradeLessThanThree > eligibleLevelCount / 2) couldBeAsiaC = true; // If at least half the myotomes below the current NLI containing values greater or equal to 3, hooray! it is ASIA D. if (levelsWithMuscleGradeGreaterThanTwo >= eligibleLevelCount / 2) couldBeAsiaD = true; } nliEnum.Dispose(); }
/// <summary> /// Produces a summarized version of a NeurologyFormTotals object which can be used to be displayed in an interface or be stored in a database. /// The values in the summary return will have ranges instead of lists of values. /// </summary> /// <param name="neurologyForm">Neurology form that has been populated with the values to be used in the algorithm calculations.</param> /// <returns> /// Summarized version of the totals which presents the results as ranges, rather than lists containing every possible value for every field. /// </returns> public static NeurologyFormTotalsSummary GetTotalsSummaryFor(NeurologyForm neurologyForm) { return GetTotalsSummaryFor(GetTotalsFor(neurologyForm)); }