From db76c1968464c47b31222b998b4142437ad0fe24 Mon Sep 17 00:00:00 2001 From: Thibault Lestang Date: Fri, 28 Jul 2023 15:50:13 +0100 Subject: [PATCH] Dont assume start time falls withing first data interval --- cats/forecast.py | 22 +++++++++++++++++----- tests/test_windowed_forecast.py | 11 +++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/cats/forecast.py b/cats/forecast.py index af40e59..70bd80e 100644 --- a/cats/forecast.py +++ b/cats/forecast.py @@ -42,16 +42,28 @@ def __init__( duration: int, # in minutes start: datetime, ): - self.data = data self.data_stepsize = data[1].datetime - data[0].datetime self.start = start # TODO: Expect duration as a timedelta directly self.end = start + timedelta(minutes=duration) + # Restrict data points so that start time falls within the + # first data interval. In other we don't need any data prior + # the closest data preceding (on the left of) the job start + # time. + def bisect_right(data, t): + for i, d in enumerate(data): + if d.datetime > t: + return i - 1 + # bisect_right(data, start) returns the index of the first + # data point with datetime value immediately preceding the job + # start time + self.data = data[bisect_right(data, start):] + # Find number of data points in a window, by finding the index - # of the first data point past the job end time. Could be done - # with the bisect module in the stdlib for python 3.10+ ('key' - # parameter was introduced in 3.10). + # of the closest data point past the job end time. Could be + # done with the bisect module in the stdlib for python 3.10+ + # ('key' parameter was introduced in 3.10). # # bisect_left(data, self.end, key=lambda x: x.datetime) # @@ -59,7 +71,7 @@ def bisect_left(data, t): for i, d in enumerate(data): if d.datetime >= t: return i - self.ndata = bisect_left(data, self.end) + 1 + self.ndata = bisect_left(self.data, self.end) + 1 def __getitem__(self, index: int) -> CarbonIntensityAverageEstimate: """Return the average of timeseries data from index over the diff --git a/tests/test_windowed_forecast.py b/tests/test_windowed_forecast.py index 28210c6..d5d787c 100644 --- a/tests/test_windowed_forecast.py +++ b/tests/test_windowed_forecast.py @@ -144,6 +144,17 @@ def test_average_intensity_with_offset(): ) assert result == expected + # Test that the WindowedForecast is able to work with a job start + # beyond the first data interval. Not technically required when + # working with carbonintensity.org.uk, but useful generalisation + # nontheless. + + # When start at 09:15 the WindowedForecast's 'data' attribute + # should discard the first data point at 08:30. + job_start = datetime.fromisoformat("2023-01-01T09:15") + result = WindowedForecast(CI_forecast, duration, start=job_start)[0] + assert result == expected + def test_average_intensity_with_offset_long_job(): # Case where job start and end time are not colocated with data # carbon intensity data points. In this case cats interpolate the