/// <summary> /// <see cref="IsEvenlySpaced(BO.Energiemenge, TimeRange, Wertermittlungsverfahren, string, Mengeneinheit, bool)"/> /// </summary> /// <param name="em">Energiemenge</param> /// <param name="allowGaps"></param> /// <returns></returns> public static bool IsEvenlySpaced(this BO4E.BO.Energiemenge em, bool allowGaps = false) { if (!em.IsPure()) { // Find all combinations of Wertermittlungsverfahren, obis and Mengeneinheit. // The Energiemenge is evenly spaced if each of the combinations is evenly spaced itself. using (MiniProfiler.Current.Step("Check all Werte/Einheit/OBIS combinations")) { ISet <Tuple <Wertermittlungsverfahren, string, Mengeneinheit> > combinations = GetWevObisMeCombinations(em); foreach (Tuple <Wertermittlungsverfahren, string, Mengeneinheit> combo in combinations) { if (!em.IsEvenlySpaced(em.GetTimeRange(), combo.Item1, combo.Item2, combo.Item3, allowGaps)) { return(false); } } } return(true); } else { Verbrauch v = em.Energieverbrauch.FirstOrDefault(); return(em.IsEvenlySpaced(em.GetTimeRange(), v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit, allowGaps)); } }
/// <summary> /// <see cref="GetCompletenessReport(BO.Energiemenge, ITimeRange, Wertermittlungsverfahren, string, Mengeneinheit)"/> /// for pure Energiemengen within their own time range. /// </summary> /// <param name="em">Energiemenge</param> /// <returns><see cref="GetCompletenessReport(BO.Energiemenge, ITimeRange, Wertermittlungsverfahren, string, Mengeneinheit)"/></returns> public static CompletenessReport GetCompletenessReport(this BO4E.BO.Energiemenge em) { if (!em.IsPure()) { throw new ArgumentException("The provided Energiemenge is not pure. Please use overloaded method GetCompletenessReport(... , wertermittlungsverfahren, obiskennzahl, mengeneinheit)."); } Verbrauch v; try { v = em.Energieverbrauch.First <Verbrauch>(); } catch (InvalidOperationException) { return(new CompletenessReport() { Coverage = null, LokationsId = em.LokationsId, ErrorMessage = "energieverbrauch is empty" }); } return(em.GetCompletenessReport(em.GetTimeRange(), v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit)); }
/// <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 BO4E.BO.Energiemenge emReference, BO4E.BO.Energiemenge emOther, ITimeRange timeframe = null, bool ignoreLocation = false) { using (MiniProfiler.Current.Step(nameof(GetPlausibilityReport))) { TimeRange trReference = emReference.GetTimeRange(); TimeRange trOther = emOther.GetTimeRange(); if (timeframe == null) { ITimeRange 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; } decimal absoluteDeviation = consumptionOther.Item1 - consumptionReference.Item1; decimal?relativeDeviation; try { relativeDeviation = absoluteDeviation / consumptionReference.Item1; } catch (DivideByZeroException) { relativeDeviation = null; } Verbrauch vReference = emReference.Energieverbrauch.FirstOrDefault(); // copies obiskennzahl, wertermittlungsverfahren... vReference.Wert = consumptionReference.Item1; vReference.Einheit = consumptionReference.Item2; vReference.Startdatum = timeframe.Start; vReference.Enddatum = timeframe.End; Verbrauch 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 BO4E.COM.Zeitraum() { Startdatum = timeframe.Start, Enddatum = 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); } }
/// <summary> /// Get percentage of full time range of energiemenge which is covered with values. /// </summary> /// <param name="em">Energiemenge</param> /// <returns>value between 0 (only coverage for 1 point in time) and 1.0 (100% coverage)</returns> public static decimal GetCoverage(this BO4E.BO.Energiemenge em) { return(em.GetCoverage(em.GetTimeRange())); }
/// <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 BO4E.BO.Energiemenge em) { return(em.GetMissingTimeRanges(em.GetTimeRange())); }
/// <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)); }