Example #1
0
        /// <summary>
        /// Calculate stored data
        /// </summary>
        /// <param name="data">Internal data storage</param>
        /// <param name="calcType">Calculate average data by each doctor or by each doctor's pacient</param>
        /// <param name="calcTimeType">Calculate results by any part of year (year/month/week/day)</param>
        /// <param name="excludeDoctorsWithoutPacients">Excludes from result doctors with no one pacient</param>
        /// <param name="excludePacientsWithoutMeasurements">Excludes from result pacients with one or no one measuremtns</param>
        /// <returns>Calculation result</returns>
        public IEnumerable<AnalysisModule.SimpleCalculationResult> Calculate(
            InternalData data,
            CalculationType calcType = CalculationType.ByDoctor,
            CalculationTimeType calcTimeType = CalculationTimeType.PerWeek,
            bool excludeDoctorsWithoutPacients = false,
            bool excludePacientsWithoutMeasurements = false)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            if (data.Doctors == null)
                throw new ArgumentNullException("data.Doctors", "Feel 'Doctors' array before calling Calculation");
            if (data.Pacients == null)
                throw new ArgumentNullException("data.Pacients", "Feel 'Pacients' array before calling Calculation");
            if (data.Timestamps == null)
                throw new ArgumentNullException("data.Timestamps", "Feel 'Timestamps' array before calling Calculation");
            if (data.Measurements == null)
                throw new ArgumentNullException("data.Measurements", "Feel 'Measurements' array before calling Calculation");
            if (data.HeighComponent == null)
                throw new ArgumentNullException("data.HeighComponent", "Feel 'HeighComponent' array before calling Calculation");
            if (!data.Doctors.Any())
                throw new ArgumentException("You must feel doctors array before calling Calculation", "data.Doctors");

            var res = new List<AnalysisModule.SimpleCalculationResult>();

            var bigTableData =
                data.Doctors
                .LeftOuterJoin(data.Pacients, d => d.DoctorId, p => p.DoctorId, (d, p) => new { DoctorId = d.DoctorId, PacientId = p == null ? (long?)null : p.PacientId })
                .LeftOuterJoin(data.Measurements, i => i.PacientId, m => m.PacientId, (i, m) => new { i.DoctorId, i.PacientId, MeasurementId = m == null ? (long?)null : m.MeasurementId })
                .LeftOuterJoin(data.Timestamps, i => i.MeasurementId, t => t.MeasurementId, (i, t) => new { i.DoctorId, i.PacientId, i.MeasurementId, Timestamp = t == null ? (DateTime?)null : t.Timestamp })
                .LeftOuterJoin(data.HeighComponent
                    .Where(h => h.Height > 0
                        && !double.IsInfinity(h.Height)
                        && !double.IsNegativeInfinity(h.Height)
                        && !double.IsPositiveInfinity(h.Height)
                        && !double.IsNaN(h.Height)
                        ),
                    i => i.MeasurementId, hc => hc.MeasurementId, (i, hc) => new { i.DoctorId, i.PacientId, i.MeasurementId, i.Timestamp, Height = hc == null ? (double?)null : hc.Height })
                .ToArray();

            //Table generated. Group data by Doctor, Pacient and Measurement
            var doctors = bigTableData
                .GroupBy(i => i.DoctorId)
                .Select(g => new
                {
                    g.FirstOrDefault().DoctorId,
                    //Group data by pacient
                    Pacients = g.Where(p => p != null)
                        .GroupBy(g2 => g2.PacientId)
                        .Select(g2 => new
                        {
                            g2.FirstOrDefault().PacientId,
                            Measurements = g2
                                .Where(i => i.Height != null && i.Timestamp != null)
                                .OrderBy(m => m.Timestamp)
                                .ToArray()
                        })
                        .Select(g2 => new
                        {
                            g2.PacientId,
                            MeasurementsExists = g2.Measurements.Count() > 1,
                            Measurements = g2.Measurements.Count() > 1
                                ? Enumerable.Range(0, g2.Measurements.Count() - 1)
                                    .Select(i => new //Get measurement pairs for pacient
                                    {
                                        Start = g2.Measurements.ElementAt(i),
                                        End = g2.Measurements.ElementAt(i + 1)
                                    })
                                    .Select(i => new //Calc start and end measure data
                                    {
                                        HeightStart = i.Start.Height.Value,
                                        HeightEnd = i.End.Height.Value,
                                        TimestampStart = i.Start.Timestamp.Value,
                                        TimestampEnd = i.End.Timestamp.Value,
                                    })
                                    .Select(i => new //get height change by part of time
                                    {
                                        HeightChange = i.HeightEnd - i.HeightStart,
                                        TimeParts = GetTimePart((i.TimestampEnd - i.TimestampStart).TotalDays, calcTimeType),
                                    })
                                    .Select(i => i.HeightChange / i.TimeParts) //calc growth per week
                                    .ToArray()
                                : Enumerable.Empty<double>().ToArray() //return empty array if no one or one only measurement
                        })
                        .Select(g2 => new
                            {
                                g2.PacientId,
                                g2.MeasurementsExists,
                                //g2.Measurements //!!! enable to debug
                                MeanRateGrowhPerTimePart = g2.MeasurementsExists ? g2.Measurements.Average() : 0
                            })
                })
                //Exclude from data pacients with one or less measurements (is setted)
                .Select(i => new
                    {
                        i.DoctorId,
                        Pacients = i.Pacients
                            .Where(p => p.PacientId != null)
                            .Where(n => !excludePacientsWithoutMeasurements || n.MeasurementsExists)
                            .ToArray()
                    })
                //Exclude from data doctors without pacients (is setted)
                .Where(i => !excludeDoctorsWithoutPacients || i.Pacients.Any())
                .ToArray()
                ;

            //Get enum description attribute
            var perName = calcTimeType.ToString();
            var memInfo = calcTimeType.GetType().GetMember(perName).FirstOrDefault();
            if (memInfo != null)
            {
                var descrAttr = memInfo.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute;
                if (descrAttr != null)
                    perName = "per " + descrAttr.Description;
            }

            //generate result from data
            foreach (var doc in doctors)
            {
                switch (calcType)
                {
                    case CalculationType.ByPacient:
                        res.AddRange(
                            doc.Pacients.Select(i => new AnalysisModule.SimpleCalculationResult()
                            {
                                Result = i.MeanRateGrowhPerTimePart,
                                AnalysisName = string.Format("{0} {3} for pacient (id:{1}) of doctor (id:{2})", CalcTaskName, i.PacientId, doc.DoctorId, perName)
                            }));
                        break;

                    case CalculationType.ByDoctor:
                        res.Add(new AnalysisModule.SimpleCalculationResult()
                        {
                            Result = doc.Pacients.Any() ? doc.Pacients.Average(p => p.MeanRateGrowhPerTimePart) : 0,
                            AnalysisName = string.Format("{0} {2} for doctor (id:{1})", CalcTaskName, doc.DoctorId, perName)
                        });
                        break;
                }
            }
            return res;
        }
Example #2
0
 /// <summary>
 /// Return time part for totalDays with selected calculation time type
 /// </summary>
 /// <param name="totalDays">Total days</param>
 /// <param name="calcTime">Calculation time type</param>
 /// <returns>Double value in selected time part</returns>
 private static double GetTimePart(double totalDays, CalculationTimeType calcTime)
 {
     double dec = 1d;
     switch (calcTime)
     {
         case CalculationTimeType.PerYear:
             dec = 365.25d;
             break;
         case CalculationTimeType.PerMonth:
             dec = ((365.25d / 12d));
             break;
         case CalculationTimeType.PerWeek:
             dec = 7d;
             break;
         case CalculationTimeType.PerDay:
             dec = 1d;
             break;
     }
     return totalDays / dec;
 }