コード例 #1
0
        /// <summary>
        /// Get average of Mengeneinheit for given time interval
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="reference">reference time frame</param>
        /// <param name="wev">Wertermittlungsverfahren</param>
        /// <param name="obiskennzahl">OBIS</param>
        /// <param name="me">an extensive or intensive unit</param>
        /// <returns>the average value or null if no Verbrauch overlapped with the specified time interval</returns>
        public static decimal?GetAverage(this BO4E.BO.Energiemenge em, TimeRange reference,
                                         Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit me)
        {
            decimal?result             = null;
            decimal overallDenominator = 0.0M;

            foreach (Verbrauch v in em.Energieverbrauch.Where(v => v.Einheit == me))
            {
                decimal overlapFactor = GetOverlapFactor(new TimeRange(v.Startdatum, v.Enddatum), reference, true);
                if (result.HasValue)
                {
                    result += overlapFactor * v.Wert;
                }
                else
                {
                    result = v.Wert;
                }
                overallDenominator += overlapFactor;
            }
            if (result.HasValue)
            {
                return(result / overallDenominator);
            }
            else
            {
                return(result);
            }
        }
コード例 #2
0
 /// <summary>
 /// Returns the consumption of a given kind of Mengeneinheit within the specified reference time range.
 /// </summary>
 /// <param name="em">Energiemenge</param>
 /// <param name="reference">reference time frame</param>
 /// <param name="wev">Wertermittlungsverfahren</param>
 /// <param name="obiskennzahl">OBIS number</param>
 /// <param name="me">an extensive unit (e.g. "kWh")</param>
 /// <returns>the consumption within the give time slice <paramref name="reference"/> in the unit passed as <paramref name="me"/></returns>
 public static decimal GetConsumption(this BO4E.BO.Energiemenge em, ITimeRange reference,
                                      Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit me)
 {
     if (!me.IsExtensive())
     {
         throw new ArgumentException($"The Mengeneinheit {me} isn't extensive. Calculating a consumption doesn't make sense.");
     }
     return(em.Energieverbrauch
            .Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obiskennzahl && v.Einheit == me)
            //.AsParallel<Verbrauch>()
            .Sum(v => GetOverlapFactor(new TimeRange(v.Startdatum, v.Enddatum), reference, false) * v.Wert));
 }
コード例 #3
0
        /// <summary>
        /// Get ratio of overlap between given Energiemenge and a reference.
        /// Method is basically just another name for <see cref="GetOverlapFactor(TimeRange, TimeRange, bool)"/>
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="reference">reference time range</param>
        /// <param name="obisKz">OBIS</param>
        /// <param name="mengeneinheit">unit of measurement</param>
        /// <param name="wev">type of measurement</param>
        /// <param name="decimalRounding">post decimals</param>
        /// <returns>value between 0 (no overlap) and 1.0 (100% overlap)</returns>
        public static decimal GetCoverage(this BO4E.BO.Energiemenge em, ITimeRange reference,
                                          Wertermittlungsverfahren wev, string obisKz, Mengeneinheit mengeneinheit, int decimalRounding = 10)
        {
            decimal exactResult;

            using (MiniProfiler.Current.Step($"calculating coverage for list with {em.Energieverbrauch.Count} entries."))
            {
                exactResult = em.Energieverbrauch
                              //.AsParallel<Verbrauch>()
                              .Where <Verbrauch>(v => v.Einheit == mengeneinheit && v.Obiskennzahl == obisKz && v.Wertermittlungsverfahren == wev)
                              .Sum(v => GetOverlapFactor(new TimeRange(v.Startdatum, v.Enddatum), reference, true));
            }
            return(Math.Round(exactResult, decimalRounding));
        }
コード例 #4
0
        private static HashSet <TimeSpan> GetTimeSpans(this BO4E.BO.Energiemenge em, Wertermittlungsverfahren wev, string obis, Mengeneinheit me)
        {
            HashSet <TimeSpan> result = new HashSet <TimeSpan>();
            List <Verbrauch>   vlist  = new List <Verbrauch>(em.Energieverbrauch);

            vlist.Sort(new VerbrauchDateTimeComparer());
            vlist = vlist.Where <Verbrauch>(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obis && v.Einheit == me).ToList <Verbrauch>();
            for (int i = 1; i < vlist.Count; i++)
            {
                result.Add(vlist[i].Startdatum - vlist[i - 1].Startdatum);
                result.Add(vlist[i].Enddatum - vlist[i - 1].Enddatum);
            }
            return(result);
        }
コード例 #5
0
        /// <summary>
        /// Generate a <see cref="CompletenessReport"/> for the given parameters.
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="reference">reference time frame</param>
        /// <param name="wev">Wertermittlungsverfahren</param>
        /// <param name="obiskennzahl">OBIS Kennzahl</param>
        /// <param name="einheit">Mengeneinheit</param>
        /// <returns>the completeness report</returns>
        public static CompletenessReport GetCompletenessReport(this BO4E.BO.Energiemenge em, ITimeRange reference, Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit einheit)
        {
            CompletenessReport result;

            using (MiniProfiler.Current.Step("create completeness report skeleton + find the coverage"))
            {
                result = new CompletenessReport
                {
                    LokationsId = em.LokationsId,
                    Einheit     = einheit,
                    Coverage    = GetCoverage(em, reference, wev, obiskennzahl, einheit),
                    wertermittlungsverfahren = wev,
                    Obiskennzahl             = obiskennzahl,
                    ReferenceTimeFrame       = new Zeitraum
                    {
                        Startdatum = DateTime.SpecifyKind(reference.Start, DateTimeKind.Utc),
                        Enddatum   = DateTime.SpecifyKind(reference.End, DateTimeKind.Utc)
                    },
                };
            }
            if (em.Energieverbrauch != null && em.Energieverbrauch.Count > 0)
            {
                /*using (MiniProfiler.Current.Step("populating time slices of/with missing/null values"))
                 * {
                 *  result.values = em.GetMissingTimeRanges(reference, wev, obis, einheit)
                 *      .Select(mtr => new CompletenessReport.BasicVerbrauch
                 *      {
                 *          startdatum = DateTime.SpecifyKind(mtr.Start, DateTimeKind.Utc),
                 *          enddatum = DateTime.SpecifyKind(mtr.End, DateTimeKind.Utc),
                 *          wert = null
                 *      }).ToList<CompletenessReport.BasicVerbrauch>();
                 * }
                 * using (MiniProfiler.Current.Step("populating time slices existing values"))
                 * {
                 *  result.values.AddRange(
                 *  em.energieverbrauch
                 *  //.AsParallel<Verbrauch>()
                 *  .Where(v => v.obiskennzahl == obis && v.einheit == einheit && v.wertermittlungsverfahren == wev)
                 *  .Select(v => new CompletenessReport.BasicVerbrauch
                 *  {
                 *      startdatum = DateTime.SpecifyKind(v.startdatum, DateTimeKind.Utc),
                 *      enddatum = DateTime.SpecifyKind(v.enddatum, DateTimeKind.Utc),
                 *      wert = v.wert
                 *  })
                 *  .ToList<CompletenessReport.BasicVerbrauch>());
                 * }*/
                using (MiniProfiler.Current.Step("Setting aggregated gaps"))
                {
                    var        nonNullValues = new TimePeriodCollection(em.Energieverbrauch.Select(v => new TimeRange(v.Startdatum, v.Enddatum)));
                    ITimeRange limits;
                    if (result.ReferenceTimeFrame != null && result.ReferenceTimeFrame.Startdatum.HasValue && result.ReferenceTimeFrame.Enddatum.HasValue)
                    {
                        limits = new TimeRange(result.ReferenceTimeFrame.Startdatum.Value, result.ReferenceTimeFrame.Enddatum.Value);
                    }
                    else
                    {
                        limits = null;
                    }
                    var gaps = (new TimeGapCalculator <TimeRange>()).GetGaps(nonNullValues, limits: limits);
                    result.Gaps = gaps.Select(gap => new CompletenessReport.BasicVerbrauch()
                    {
                        Startdatum = gap.Start,
                        Enddatum   = gap.End,
                        Wert       = null
                    }).ToList();
                }

                /*using (MiniProfiler.Current.Step("sorting result"))
                 * {
                 *  result.values.Sort(new BasicVerbrauchDateTimeComparer());
                 * }*/
                if (em.IsPure(checkUserProperties: true))
                {
                    try
                    {
                        foreach (var kvp in em.Energieverbrauch.Where(v => v.UserProperties != null).SelectMany(v => v.UserProperties))
                        {
                            if (result.UserProperties == null)
                            {
                                result.UserProperties = new Dictionary <string, JToken>();
                            }
                            if (!result.UserProperties.ContainsKey(kvp.Key))
                            {
                                result.UserProperties.Add(kvp.Key, kvp.Value);
                            }
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        // ok, there's no Verbrauch with user properties.
                    }
                }
            }

            /*else
             * {
             *  result.coverage = null;
             *  result._errorMessage = "energieverbrauch is empty";
             * }*/
            return(result);
        }
コード例 #6
0
        /// <summary>
        /// Test, if the single entries/intervals of the energieverbrauch array share the same duration and spacing in time.
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="reference">reference time frame</param>
        /// <param name="wev">Wertermittlungsverfahren</param>
        /// <param name="obis">OBIS-Kennzahl</param>
        /// <param name="me">Mengeneinheit</param>
        /// <param name="allowGaps">set true to allow gaps</param>
        /// <returns>True, if all energieverbrauch entries have the same length and their start and enddatum are evenly spaced.
        /// Also true, if there less than 2 entries in the energieverbrauch array.</returns>
        public static bool IsEvenlySpaced(this BO4E.BO.Energiemenge em, ITimeRange reference, Wertermittlungsverfahren wev, string obis, Mengeneinheit me, bool allowGaps = false)
        {
            HashSet <TimeSpan> startEndDatumPeriods;

            using (MiniProfiler.Current.Step("finding time spans"))
            {
                startEndDatumPeriods = GetTimeSpans(em, wev, obis, me);
            }
            if (startEndDatumPeriods.Count < 2)
            {
                return(true);
            }
            if (allowGaps)
            {
                // each time difference must be a multiple of the smallest difference.
                using (MiniProfiler.Current.Step("Iterating over all time spans"))
                {
                    double minDiff = startEndDatumPeriods.Min <TimeSpan>().TotalSeconds;
                    foreach (TimeSpan ts in startEndDatumPeriods)
                    {
                        if (Math.Abs(ts.TotalSeconds % minDiff) != 0)
                        {
                            // use profiler as logger:
                            using (MiniProfiler.Current.Step($"Found TimeSpan {ts} with a duration of {ts.TotalSeconds}. This is no multiple of {minDiff} => not evenly spaced."))
                            {
                                return(false);
                            }
                        }
                    }
                }
                return(true);
            }
            else
            {
                // there must be only 1 time difference between all the elements
                return(startEndDatumPeriods.Count <= 1);
            }
        }
コード例 #7
0
        /// <summary>
        /// Get a list of those time ranges within a reference, where no energieverbrauch entries are defined.
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="reference">reference timeframe</param>
        /// <param name="wev">Wertermittlungsverfahren</param>
        /// <param name="obis">OBIS-Kennzahl</param>
        /// <param name="me">Mengeneinheit</param>
        /// <returns></returns>
        public static List <TimeRange> GetMissingTimeRanges(this BO4E.BO.Energiemenge em, ITimeRange reference, Wertermittlungsverfahren wev, string obis, Mengeneinheit me)
        {
            using (MiniProfiler.Current.Step(nameof(GetMissingTimeRanges)))
            {
                IDictionary <Tuple <DateTime, DateTime>, Verbrauch> filteredVerbrauch;
                using (MiniProfiler.Current.Step($"Filtering energieverbrauch on OBIS={obis}, WEV={wev}, Mengeneinheit={me}"))
                {
                    filteredVerbrauch = em.Energieverbrauch
                                        .Where <Verbrauch>(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obis && v.Einheit == me)
                                        .ToDictionary(v => new Tuple <DateTime, DateTime>(v.Startdatum, v.Enddatum), v => v);
                }
                if (filteredVerbrauch.Count < 2)
                {
                    throw new ArgumentException("Not enough entries in energieverbrauch to determine periodicity.");
                }
                if (!IsEvenlySpaced(em, reference, wev, obis, me, true))
                {
                    throw new ArgumentException("The provided Energiemenge is not evenly spaced although gaps are allowed.");
                }
                TimeSpan periodicity = GetTimeSpans(em, wev, obis, me).Min <TimeSpan>();
                if (Math.Abs((reference.Start - em.GetMinDate()).TotalMilliseconds % periodicity.TotalMilliseconds) != 0)
                {
                    throw new ArgumentException($"The absolute difference between reference.start ({reference.Start}) and the minimal date time in the Energiemenge ({em.GetMinDate()}) has to be an integer multiple of the periodicity {periodicity.TotalMilliseconds} but was {(reference.Start - em.GetMinDate()).TotalMilliseconds}.");
                }
                // since it's assured, that the energieverbrauch entries are evenly spaced it doesn't matter which entry we use to determine the duration.
                TimeSpan         duration = filteredVerbrauch.Values.Min(v => v.Enddatum) - filteredVerbrauch.Values.Min(v => v.Startdatum);
                List <TimeRange> result   = new List <TimeRange>();
                using (MiniProfiler.Current.Step("Populating list with time slices in UTC"))
                {
                    for (DateTime dt = reference.Start; dt < reference.End; dt += periodicity)
                    {
                        // use a strict '==' instead of overlap. This is justified because all the other cases are considered beforehand
                        switch (dt.Kind)
                        {
                        case DateTimeKind.Local:
                            throw new ArgumentException("Local DateTime not supported!");

                        case DateTimeKind.Unspecified:
                            dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
                            break;

                        case DateTimeKind.Utc:
                            break;
                        }
                        //using (MiniProfiler.Current.Step("linq where on filtered verbrauch"))
                        //{
                        if (!filteredVerbrauch.ContainsKey(new Tuple <DateTime, DateTime>(dt, dt + duration)))//   Where<Verbrauch>(v => v.startdatum == dt && v.enddatum == dt + duration).Any())
                        {
                            result.Add(new TimeRange(dt, dt + duration));
                        }
                        //}
                    }
                }
                return(result);
            }
        }
コード例 #8
0
 /// <summary>
 /// Same as <see cref="GetAverage(Mengeneinheit, DateTime, DateTime)"/> but without specifying a time slice.
 /// </summary>
 /// <param name="em">Energiemenge</param>
 /// <param name="wev">type of measurement</param>
 /// <param name="obiskennzahl">OBIS</param>
 /// <param name="me">an intensive or extensive unit</param>
 /// <returns>The average for the given Mengeneinheit for the Energiemenge object or null if there was no Verbrauch for the given Mengeneinheit.</returns>
 public static decimal?GetAverage(this BO4E.BO.Energiemenge em,
                                  Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit me)
 {
     return(em.GetAverage(em.GetTimeRange(), wev, obiskennzahl, me));
 }
コード例 #9
0
 /// <summary>
 ///     Get total consumption for given parameters
 /// </summary>
 /// <param name="em">Energiemenge</param>
 /// <param name="wev">type of measurement</param>
 /// <param name="obiskennzahl">OBIS</param>
 /// <param name="me">unit of measurement</param>
 /// <returns>consumption value</returns>
 public static decimal GetTotalConsumption(this BO.Energiemenge em,
                                           Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit me)
 {
     return(em.GetConsumption(em.GetTimeRange(), wev, obiskennzahl, me));
 }