public Timeseries Apply(IUnaryAggregateOperator op, Timeseries ts) { if (ts == null || ! ts.Any()) return new Timeseries(); var result = new Timeseries(); // Default to monthly var t = ts.First().Time; do { var t0 = new DateTime(t.Year, t.Month, 1, 0, 0, 0); var t1 = new DateTime(t.Year, t.Month, DateTime.DaysInMonth(t.Year, t.Month), 23, 59, 59); result.Add(op.Apply(t0, t1, ts)); t = t0.AddMonths(1); } while (t <= ts.Last().Time); return result; }
public Timeseries Apply(IUnaryAggregateOperator op, Timeseries ts) { if (ts == null || !ts.Any()) { return(new Timeseries()); } var result = new Timeseries(); // Default to monthly var t = ts.First().Time; do { var t0 = new DateTime(t.Year, t.Month, 1, 0, 0, 0); var t1 = new DateTime(t.Year, t.Month, DateTime.DaysInMonth(t.Year, t.Month), 23, 59, 59); result.Add(op.Apply(t0, t1, ts)); t = t0.AddMonths(1); } while (t <= ts.Last().Time); return(result); }
/// <summary> /// Periodizes a time series with relative consumption /// </summary> /// <param name="op"></param> /// <param name="ts">A time series with relative consumption, without roll over or meter change</param> /// <param name="interval"></param> /// <returns></returns> private Timeseries Periodize(IUnaryAggregateOperator op, Timeseries ts, Interval interval) { var result = new Timeseries(); using (var enumerator = ts.GetEnumerator()) { DateTime?intervalStart = null; DateTime nextIntervalStart = DateTime.MinValue; var areMoreValues = enumerator.MoveNext(); Tvq currentTvq = null; Tvq previousTvq; Tvq nextTvq = enumerator.Current; var doNeedToMove = true; double sumForPeriod = 0; while (areMoreValues) { // Setup previous, current and next if we need to enumerator.MoveNext(); previousTvq = currentTvq; currentTvq = nextTvq; nextTvq = enumerator.Current; Debug.Assert(currentTvq != null); // Initialize interval if (!intervalStart.HasValue) { intervalStart = FirstSecond(currentTvq.Time, interval); nextIntervalStart = FirstSecondOfNextInterval(intervalStart.Value, interval); sumForPeriod = 0; } Debug.Assert(currentTvq.Time >= intervalStart); Debug.Assert(currentTvq.Time <= nextIntervalStart); do // next value may be many periods ahead { if (nextTvq == null) { if (previousTvq != null) // Prevent input with only one value from entering { sumForPeriod += currentTvq.V / (currentTvq.Time - previousTvq.Time).TotalDays * (nextIntervalStart - previousTvq.Time).TotalDays; // Extrapolate consumption to end of interval } result.Add(new Tvq(intervalStart.Value, sumForPeriod, Quality.Interpolated)); sumForPeriod = 0; } else if (nextIntervalStart <= nextTvq.Time) { doNeedToMove = false; sumForPeriod += currentTvq.V; var remainingConsumptionBelongingToThisPeriod = nextTvq.V * (nextIntervalStart - currentTvq.Time).TotalDays / (nextTvq.Time - currentTvq.Time).TotalDays; var consumptionInPeriod = sumForPeriod + remainingConsumptionBelongingToThisPeriod; result.Add(new Tvq(intervalStart.Value, consumptionInPeriod, Quality.Interpolated)); sumForPeriod = -remainingConsumptionBelongingToThisPeriod - currentTvq.V; // This is how much of nextTvq.V that we already have added. intervalStart = nextIntervalStart; nextIntervalStart = FirstSecondOfNextInterval(intervalStart.Value, interval); } else { sumForPeriod += currentTvq.V; doNeedToMove = true; } } while (!doNeedToMove); areMoreValues = nextTvq != null; } } return(result); }