/// <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="totals">The form totals object to be used to generate the summary.</param> /// <returns> /// Summarized version of the totals where the enumerations get replaced by ranges. /// </returns> public static NeurologyFormTotalsSummary GetTotalsSummaryFor(NeurologyFormTotals totals) { var ais = totals.GetAsiaImpairmentScaleValues(); var isAsiaA = ais.Contains("A"); var couldBeOtherThanAsiaA = !isAsiaA || ais.Length > 1; var summary = new NeurologyFormTotalsSummary { AsiaImpairmentScale = ais, Completeness = isAsiaA ? (couldBeOtherThanAsiaA ? "C,I" : "C") : "I", LeftLowerMotorTotal = GetSummaryStringFor(totals.LeftLowerMotorTotal, totals.LeftLowerMotorTotalHasImpairmentNotDueToSci, totals.LeftLowerMotorContainsNt), LeftMotor = GetLevelsRange(totals.GetLeftMotorValues(), false), LeftMotorZpp = isAsiaA ? GetLevelsRange(totals.GetLeftMotorZppValues(), couldBeOtherThanAsiaA) : NotApplicable, LeftMotorTotal = GetSummaryStringFor(totals.LeftUpperMotorTotal + totals.LeftLowerMotorTotal, totals.LeftUpperMotorTotalHasImpairmentNotDueToSci || totals.LeftLowerMotorTotalHasImpairmentNotDueToSci, totals.LeftUpperMotorContainsNt || totals.LeftLowerMotorContainsNt), LeftPrickTotal = GetSummaryStringFor(totals.LeftPrickTotal, totals.LeftPrickTotalHasImpairmentNotDueToSci, totals.LeftPrickContainsNt), LeftSensory = GetLevelsRange(totals.GetLeftSensoryValues(), false), LeftSensoryZpp = isAsiaA ? GetLevelsRange(totals.GetLeftSensoryZppValues(), couldBeOtherThanAsiaA) : NotApplicable, LeftTouchTotal = GetSummaryStringFor(totals.LeftTouchTotal, totals.LeftTouchTotalHasImpairmentNotDueToSci, totals.LeftTouchContainsNt), LeftUpperMotorTotal = GetSummaryStringFor(totals.LeftUpperMotorTotal, totals.LeftUpperMotorTotalHasImpairmentNotDueToSci, totals.LeftUpperMotorContainsNt), LowerMotorTotal = GetSummaryStringFor(totals.LowerMotorTotal, totals.RightLowerMotorTotalHasImpairmentNotDueToSci || totals.LeftLowerMotorTotalHasImpairmentNotDueToSci, totals.RightLowerMotorContainsNt || totals.LeftLowerMotorContainsNt), NeurologicalLevelOfInjury = GetLevelsRange(totals.GetNeurologicalLevelsOfInjury(), false), PrickTotal = GetSummaryStringFor(totals.RightPrickTotal + totals.LeftPrickTotal, totals.RightPrickTotalHasImpairmentNotDueToSci || totals.LeftPrickTotalHasImpairmentNotDueToSci, totals.RightPrickContainsNt || totals.LeftPrickContainsNt), RightLowerMotorTotal = GetSummaryStringFor(totals.RightLowerMotorTotal, totals.RightLowerMotorTotalHasImpairmentNotDueToSci, totals.RightLowerMotorContainsNt), RightMotor = GetLevelsRange(totals.GetRightMotorValues(), false), RightMotorZpp = isAsiaA ? GetLevelsRange(totals.GetRightMotorZppValues(), couldBeOtherThanAsiaA) : NotApplicable, RightMotorTotal = GetSummaryStringFor(totals.RightUpperMotorTotal + totals.RightLowerMotorTotal, totals.RightUpperMotorTotalHasImpairmentNotDueToSci || totals.RightLowerMotorTotalHasImpairmentNotDueToSci, totals.RightUpperMotorContainsNt || totals.RightLowerMotorContainsNt), RightPrickTotal = GetSummaryStringFor(totals.RightPrickTotal, totals.RightPrickTotalHasImpairmentNotDueToSci, totals.RightPrickContainsNt), RightSensory = GetLevelsRange(totals.GetRightSensoryValues(), false), RightSensoryZpp = isAsiaA ? GetLevelsRange(totals.GetRightSensoryZppValues(), couldBeOtherThanAsiaA) : NotApplicable, RightTouchTotal = GetSummaryStringFor(totals.RightTouchTotal, totals.RightTouchTotalHasImpairmentNotDueToSci, totals.RightTouchContainsNt), RightUpperMotorTotal = GetSummaryStringFor(totals.RightUpperMotorTotal, totals.RightUpperMotorTotalHasImpairmentNotDueToSci, totals.RightUpperMotorContainsNt), TouchTotal = GetSummaryStringFor(totals.RightTouchTotal + totals.LeftTouchTotal, totals.RightTouchTotalHasImpairmentNotDueToSci || totals.LeftTouchTotalHasImpairmentNotDueToSci, totals.RightTouchContainsNt || totals.LeftTouchContainsNt), UpperMotorTotal = GetSummaryStringFor(totals.UpperMotorTotal, totals.RightUpperMotorTotalHasImpairmentNotDueToSci || totals.LeftUpperMotorTotalHasImpairmentNotDueToSci, totals.RightUpperMotorContainsNt || totals.LeftUpperMotorContainsNt) }; return summary; }