コード例 #1
0
 /// <summary>
 ///     Get list of those time ranges within the energiemenge where there are gaps.
 /// </summary>
 /// <param name="em">Energiemenge</param>
 /// <returns></returns>
 public static IList <TimeRange> GetMissingTimeRanges(this BO.Energiemenge em)
 {
     return(em.GetMissingTimeRanges(em.GetTimeRange()));
 }
コード例 #2
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 time frame</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 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(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.");
                }
                var periodicity = GetTimeSpans(em, wev, obis, me).Min();
                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.
                var duration = filteredVerbrauch.Values.Min(v => v.Enddatum) -
                               filteredVerbrauch.Values.Min(v => v.Startdatum);
                var result = new List <TimeRange>();
                using (MiniProfiler.Current.Step("Populating list with time slices in UTC"))
                {
                    for (var 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);
            }
        }
コード例 #3
0
 /// <summary>
 ///     Same as <see cref="GetAverage(BO4E.BO.Energiemenge)" /> 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 BO.Energiemenge em,
                                  Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit me)
 {
     return(em.GetAverage(em.GetTimeRange(), wev, obiskennzahl, me));
 }
コード例 #4
0
 /// <summary>
 ///     Same as
 ///     <see
 ///         cref="GetTotalConsumption(BO4E.BO.Energiemenge,BO4E.ENUM.Wertermittlungsverfahren,string,BO4E.ENUM.Mengeneinheit)" />
 ///     but without auto-detected parameters.
 ///     By default a the full length of the Energiemenge is taken into account.
 /// </summary>
 /// <param name="em">Energiemenge</param>
 /// <returns>Tuple of consumption value and unit of measurement</returns>
 public static Tuple <decimal, Mengeneinheit> GetTotalConsumption(this BO.Energiemenge em)
 {
     return(GetConsumption(em, new TimeRange(em.GetMinDate().UtcDateTime, em.GetMaxDate().UtcDateTime)));
 }
コード例 #5
0
        /// <summary>
        ///     Returns a <see cref="PlausibilityReport" /> that compares <paramref name="emReference" /> with
        ///     <paramref name="emOther" />.
        ///     within the interval defined in <paramref name="timeframe" />.
        /// </summary>
        /// <param name="emReference">reference Energiemenge (reference = used for normalisation)</param>
        /// <param name="emOther">other Energiemenge</param>
        /// <param name="timeframe">
        ///     time frame to be analysed. If null, the overlap of <paramref name="emReference" /> and
        ///     <paramref name="emOther" /> is used.
        /// </param>
        /// <param name="ignoreLocation">
        ///     By default (false) an ArgumentException is thrown if the
        ///     <see cref="BO4E.BO.Energiemenge.LokationsId" /> do not match. Setting this flag suppresses the error.
        /// </param>
        /// <returns>a <see cref="PlausibilityReport" /></returns>
        public static PlausibilityReport GetPlausibilityReport(this BO.Energiemenge emReference,
                                                               BO.Energiemenge emOther, ITimeRange timeframe = null, bool ignoreLocation = false)
        {
            using (MiniProfiler.Current.Step(nameof(GetPlausibilityReport)))
            {
                var trReference = emReference.GetTimeRange();
                var trOther     = emOther.GetTimeRange();
                if (timeframe == null)
                {
                    var overlap = trReference.GetIntersection(trOther);
                    if (!ignoreLocation)
                    {
                        if (!(emReference.LokationsId == emOther.LokationsId &&
                              emReference.LokationsTyp == emOther.LokationsTyp))
                        {
                            throw new ArgumentException(
                                      $"locations do not match! '{emReference.LokationsId}' ({emReference.LokationsTyp}) != '{emOther.LokationsId}' ({emOther.LokationsTyp})");
                        }
                    }
                    timeframe = overlap;
                }

                Tuple <decimal, Mengeneinheit> consumptionReference;
                Tuple <decimal, Mengeneinheit> consumptionOtherRaw;
                using (MiniProfiler.Current.Step("Get Consumptions for overlap:"))
                {
                    consumptionReference = emReference.GetConsumption(timeframe);
                    consumptionOtherRaw  = emOther.GetConsumption(timeframe);
                }

                Tuple <decimal, Mengeneinheit> consumptionOther;
                if (consumptionReference.Item2 != consumptionOtherRaw.Item2)
                {
                    // unit mismatch
                    if (consumptionReference.Item2.IsConvertibleTo(consumptionOtherRaw.Item2))
                    {
                        consumptionOther = new Tuple <decimal, Mengeneinheit>(
                            consumptionOtherRaw.Item1 *
                            consumptionOtherRaw.Item2.GetConversionFactor(consumptionReference.Item2),
                            consumptionReference.Item2);
                    }
                    else
                    {
                        throw new ArgumentException(
                                  $"The unit {consumptionOtherRaw.Item2} is not comparable to {consumptionReference.Item2}!");
                    }
                }
                else
                {
                    consumptionOther = consumptionOtherRaw;
                }

                var     absoluteDeviation = consumptionOther.Item1 - consumptionReference.Item1;
                decimal?relativeDeviation;
                try
                {
                    relativeDeviation = absoluteDeviation / consumptionReference.Item1;
                }
                catch (DivideByZeroException)
                {
                    relativeDeviation = null;
                }

                var vReference =
                    emReference.Energieverbrauch.FirstOrDefault(); // copies obiskennzahl, wertermittlungsverfahren...
                vReference.Wert       = consumptionReference.Item1;
                vReference.Einheit    = consumptionReference.Item2;
                vReference.Startdatum = timeframe.Start;
                vReference.Enddatum   = timeframe.End;

                var vOther =
                    emOther.Energieverbrauch.FirstOrDefault(); // copies obiskennzahl, wertermittlungsverfahren...
                vOther.Wert       = consumptionOther.Item1;
                vOther.Einheit    = consumptionOther.Item2;
                vOther.Startdatum = timeframe.Start;
                vOther.Enddatum   = timeframe.End;

                var pr = new PlausibilityReport
                {
                    LokationsId        = emReference.LokationsId,
                    ReferenceTimeFrame = new Zeitraum
                    {
                        Startdatum = new DateTimeOffset(timeframe.Start),
                        Enddatum   = new DateTimeOffset(timeframe.End)
                    },
                    VerbrauchReference       = vReference,
                    VerbrauchOther           = vOther,
                    AbsoluteDeviation        = Math.Abs(absoluteDeviation),
                    AbsoluteDeviationEinheit = consumptionReference.Item2
                };
                if (relativeDeviation.HasValue)
                {
                    pr.RelativeDeviation = Math.Round(relativeDeviation.Value, 4);
                }
                else
                {
                    pr.RelativeDeviation = null;
                }
                return(pr);
            }
        }
コード例 #6
0
        /// <summary>
        ///     Get Monthly Completeness Reports for overall time range defined in <paramref name="config" />.
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="config">
        ///     configuration that contains the overall time range in
        ///     <see cref="PlausibilityReport.PlausibilityReportConfiguration.Timeframe" />
        /// </param>
        /// <returns></returns>
        public static IDictionary <ITimeRange, PlausibilityReport> GetMonthlyPlausibilityReports(this BO.Energiemenge em,
                                                                                                 PlausibilityReportConfiguration config)
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }
            if (config.Timeframe == null)
            {
                throw new ArgumentNullException(nameof(config.Timeframe));
            }
            var slices = GetLocalMonthlySlices(new TimeRange
            {
                Start = config.Timeframe.Startdatum.Value.UtcDateTime,
                End   = config.Timeframe.Enddatum.Value.UtcDateTime
            });

            return(em.GetSlicedPlausibilityReports(config, slices));
        }
コード例 #7
0
        /// <summary>
        ///     creates a dictionary of completeness reports for a given list of reference time ranges.
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="config">container containing the relevant data</param>
        /// <param name="ranges">list of ranges for which the completeness reports are generated</param>
        /// <returns></returns>
        public static IDictionary <ITimeRange, PlausibilityReport> GetSlicedPlausibilityReports(this BO.Energiemenge em,
                                                                                                PlausibilityReportConfiguration config, IEnumerable <ITimeRange> ranges)
        {
            if (ranges == null)
            {
                throw new ArgumentNullException(nameof(ranges), "list of time ranges must not be null");
            }
            var result = new Dictionary <ITimeRange, PlausibilityReport>();

            foreach (var range in ranges)
            {
                var localConfig =
                    JsonConvert.DeserializeObject <PlausibilityReportConfiguration>(JsonConvert.SerializeObject(config));
                localConfig.Timeframe = new Zeitraum
                {
                    Startdatum = range.Start,
                    Enddatum   = range.End
                };
                var subResult = GetPlausibilityReport(em, localConfig);
                result.Add(range, subResult);
            }

            return(result);
        }