Exemplo n.º 1
0
        /// <summary>
        /// Builds a dictionary key using a provided sex and measurement value.
        /// </summary>
        /// <param name="measurement">The measurement in metric units</param>
        /// <param name="sex">Whether the child is male or female</param>
        /// <returns>int; represents the integer dictionary key for the given sex and measurement values</returns>
        internal int BuildKey(Sex sex, double measurement)
        {
            if (StatisticsHelper.IsWholeNumber(measurement))
            {
                int sexKeyPart         = sex == Sex.Male ? 1 : 2;
                int measurementKeyPart = (int)(measurement * 100) + sexKeyPart;
                return(measurementKeyPart);
            }

            return(-1);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Calculates a z-score for a given indicator, pair of measurements (measurement1-for-measurement2, as
        /// in "BMI-for-Age"), and gender.
        /// </summary>
        /// <param name="indicator">The indicator to use for computing the z-score (e.g. BMI, Height-for-Age, Weight-for-Age, etc.)</param>
        /// <param name="measurement1">
        /// The first measurement value. Must be in metric units and must be greater than or equal to zero. For
        /// example, if the indicator is 'Height-for-Age', then measurement1 represents the child's height in
        /// centimeters. Note that subscapular skinfold and triceps skinfold require measurement1 be provided
        /// in millimeters.
        /// </param>
        /// <param name="measurement2">
        /// The second measurement. Typically age of the child in days. For example, if the indicator is
        /// 'Height-for-Age', then measurement2 represents the child's age. If the indicator is instead
        /// 'Weight-for-Length' or 'Weight-for-Height' then measurement2 represents the child's length or
        /// height (respectively) and must be a non-zero value provided in centimeters. Automatically
        /// rounded to 5 decimal values if measuring height or length and automatically rounded to a whole
        /// number if measuring age in days.
        /// </param>
        /// <param name="sex">Whether the child is male or female</param>
        /// <returns>double; the z-score for the given inputs</return>
        internal double CalculateZScore(Indicator indicator, double measurement1, double measurement2, Sex sex)
        {
            if (measurement1 < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(measurement1));
            }
            if (!IsValidMeasurement(indicator, measurement2))
            {
                throw new ArgumentOutOfRangeException(nameof(measurement2));
            }

            measurement2 = Math.Round(measurement2, 5);

            Dictionary <int, Lookup> reference = null;
            bool shouldRound = true;

            switch (indicator)
            {
            case Indicator.BodyMassIndexForAge:
                reference = WHO2006_BMI;
                break;

            case Indicator.WeightForLength:
                reference   = WHO2006_WeightForLength;
                shouldRound = false;
                break;

            case Indicator.WeightForHeight:
                reference   = WHO2006_WeightForHeight;
                shouldRound = false;
                break;

            case Indicator.WeightForAge:
                reference = WHO2006_WeightForAge;
                break;

            case Indicator.ArmCircumferenceForAge:
                reference = WHO2006_ArmCircumference;
                break;

            case Indicator.HeadCircumferenceForAge:
                reference = WHO2006_HeadCircumference;
                break;

            case Indicator.HeightForAge:
            case Indicator.LengthForAge:
                reference = WHO2006_LengthHeightForAge;
                break;

            case Indicator.SubscapularSkinfoldForAge:
                reference = WHO2006_SubscapularSkinfoldForAge;
                break;

            case Indicator.TricepsSkinfoldForAge:
                reference = WHO2006_TricepsSkinfoldForAge;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(indicator));
            }

            if (shouldRound && !StatisticsHelper.IsWholeNumber(measurement2))
            {
                measurement2 = Math.Round(measurement2, 0);
            }

            int    key    = BuildKey(sex, measurement2);
            Lookup lookup = null;
            bool   found  = reference.TryGetValue(key, out lookup);

            if (found)
            {
                return(StatisticsHelper.CalculateZScore(measurement1, lookup.L, lookup.M, lookup.S, true));
            }
            else if (indicator == Indicator.WeightForLength || indicator == Indicator.WeightForHeight)
            {
                var interpolatedLMS = InterpolateLMS(sex, measurement2, reference);
                return(StatisticsHelper.CalculateZScore(measurement1, interpolatedLMS.Item1, interpolatedLMS.Item2, interpolatedLMS.Item3, true));
            }
            else
            {
                throw new InvalidOperationException($"Could not find a lookup match for value {Math.Round(measurement2, 2).ToString("N2")}");
            }
        }