From e89e09e4206f4631264cdb1e54d2e895ab98ec87 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Fri, 26 Jul 2024 11:17:31 +0100 Subject: [PATCH 01/18] Update batches.py to include time features --- ocf_datapipes/batch/batches.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ocf_datapipes/batch/batches.py b/ocf_datapipes/batch/batches.py index cdb8f8833..4489fc580 100644 --- a/ocf_datapipes/batch/batches.py +++ b/ocf_datapipes/batch/batches.py @@ -118,6 +118,15 @@ class BatchKey(Enum): gsp_x_osgb_fourier = auto() gsp_time_utc_fourier = auto() # (batch_size, time, n_fourier_features) + # -------------- TIME ------------------------------------------- + # Sine and cosine of date of year and time of day at every timestep. + # shape = (batch_size, n_timesteps) + # This is calculated for wind only inside datapipes. + wind_date_sin = auto() + wind_date_cos = auto() + wind_time_sin = auto() + wind_time_cos = auto() + # -------------- SUN -------------------------------------------- # Solar position at every timestep. shape = (batch_size, n_timesteps) # The solar position data comes from two alternative sources: either the Sun pre-prepared From e5ffc8cb8e909d15fb230ce68efd43f212fa9d8c Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Fri, 26 Jul 2024 11:27:16 +0100 Subject: [PATCH 02/18] add time features windnet.py --- ocf_datapipes/training/windnet.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ocf_datapipes/training/windnet.py b/ocf_datapipes/training/windnet.py index 6bc944160..82aa4880f 100644 --- a/ocf_datapipes/training/windnet.py +++ b/ocf_datapipes/training/windnet.py @@ -213,11 +213,15 @@ def __iter__(self): numpy_modalities.append(datapipes_dict["wind"].convert_wind_to_numpy_batch()) logger.debug("Combine all the data sources") - combined_datapipe = MergeNumpyModalities(numpy_modalities).add_sun_position( + logger.debug("Adding trigonometric date and time") + combined_datapipe = MergeNumpyModalities(numpy_modalities).add_trigonometric_date_time( modality_name="wind" ) + # combined_datapipe = MergeNumpyModalities(numpy_modalities).add_sun_position( + # modality_name="wind" + #) - logger.info("Filtering out samples with no data") + # logger.info("Filtering out samples with no data") # if self.check_satellite_no_zeros: # in production we don't want any nans in the satellite data # combined_datapipe = combined_datapipe.map(check_nans_in_satellite_data) From 68d33d1f81534d31f8a22f35b2b110425b101647 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:27:55 +0000 Subject: [PATCH 03/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ocf_datapipes/training/windnet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ocf_datapipes/training/windnet.py b/ocf_datapipes/training/windnet.py index 82aa4880f..5de9707cd 100644 --- a/ocf_datapipes/training/windnet.py +++ b/ocf_datapipes/training/windnet.py @@ -219,7 +219,7 @@ def __iter__(self): ) # combined_datapipe = MergeNumpyModalities(numpy_modalities).add_sun_position( # modality_name="wind" - #) + # ) # logger.info("Filtering out samples with no data") # if self.check_satellite_no_zeros: From 080877f3e6d218d41f81ca90a85f5adff1beb6d4 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Fri, 26 Jul 2024 11:30:12 +0100 Subject: [PATCH 04/18] Create datetime_features.py --- .../numpy_batch/datetime_features.py | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 ocf_datapipes/transform/numpy_batch/datetime_features.py diff --git a/ocf_datapipes/transform/numpy_batch/datetime_features.py b/ocf_datapipes/transform/numpy_batch/datetime_features.py new file mode 100644 index 000000000..73b33a71b --- /dev/null +++ b/ocf_datapipes/transform/numpy_batch/datetime_features.py @@ -0,0 +1,70 @@ +"""Datapipes to add Sun position to NumpyBatch""" + +import numpy as np +from torch.utils.data import IterDataPipe, functional_datapipe + +from ocf_datapipes.batch import BatchKey + + +def _get_date_time_in_pi(dt): + day_of_year = (dt - dt.astype('datetime64[Y]')).astype(int) + minute_of_day = (dt - dt.astype('datetime64[D]')).astype(int) + + # converting into positions on sin-cos circle + time_in_pi = (2*np.pi) * (minute_of_day / (24*3600)) + date_in_pi = (2*np.pi) * (day_of_year / (365*24*3600)) + + return date_in_pi, time_in_pi + + +@functional_datapipe("add_trigonometric_date_time") +class AddTrigonometricDateTimeIterDataPipe(IterDataPipe): + """Adds the trigonometric encodings of date of year, time of day to the NumpyBatch""" + + def __init__(self, source_datapipe: IterDataPipe, modality_name: str): + """ + Adds the sine and cosine of time to the NumpyBatch + + Args: + source_datapipe: Datapipe of NumpyBatch + modality_name: Modality to add the time for + """ + self.source_datapipe = source_datapipe + self.modality_name = modality_name + assert self.modality_name in [ + "wind", + ], f"Trigonometric time not implemented for {self.modality_name}" + + def __iter__(self): + for np_batch in self.source_datapipe: + time_utc = np_batch[BatchKey.wind_time_utc] + + # Check if the input is batched + # time_utc could have shape (batch_size, n_times) or (n_times,) + assert len(time_utc.shape) in [1, 2] + is_batched = len(time_utc.shape) == 2 + + times = time_utc.astype("datetime64[s]") + + if is_batched: + time_in_pi = np.full_like(time_utc, fill_value=np.nan).astype(np.float32) + date_in_pi = np.full_like(time_utc, fill_value=np.nan).astype(np.float32) + + # Loop round each example to get converted time values + for example_idx, dt in enumerate(times): + date_in_pi[example_idx], time_in_pi[example_idx] = _get_date_time_in_pi(dt) + else: + date_in_pi, time_in_pi = _get_date_time_in_pi(times) + + # Store + date_sin_batch_key = BatchKey[self.modality_name + "_date_sin"] + date_cos_batch_key = BatchKey[self.modality_name + "_date_cos"] + time_sin_batch_key = BatchKey[self.modality_name + "_time_sin"] + time_cos_batch_key = BatchKey[self.modality_name + "_time_cos"] + + np_batch[date_sin_batch_key] = np.sin(date_in_pi) + np_batch[date_cos_batch_key] = np.cos(date_in_pi) + np_batch[time_sin_batch_key] = np.sin(time_in_pi) + np_batch[time_cos_batch_key] = np.cos(time_in_pi) + + yield np_batch From 95a719d5d3bb691456d0b5dddfffd4c6eb219087 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Fri, 26 Jul 2024 11:31:09 +0100 Subject: [PATCH 05/18] Update __init__.py to include time features --- ocf_datapipes/transform/numpy_batch/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ocf_datapipes/transform/numpy_batch/__init__.py b/ocf_datapipes/transform/numpy_batch/__init__.py index 49d455cad..51afa1deb 100644 --- a/ocf_datapipes/transform/numpy_batch/__init__.py +++ b/ocf_datapipes/transform/numpy_batch/__init__.py @@ -3,3 +3,4 @@ from .add_fourier_space_time import AddFourierSpaceTimeIterDataPipe as AddFourierSpaceTime from .add_topographic_data import AddTopographicDataIterDataPipe as AddTopographicData from .sun_position import AddSunPositionIterDataPipe as AddSunPosition +from .datetime_features import AddTrigonometricDateTimeIterDataPipe as AddTrigonometricDateTime From 412422472bec2bafe789817ea57d29e051de8d42 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:31:50 +0000 Subject: [PATCH 06/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ocf_datapipes/transform/numpy_batch/__init__.py | 2 +- ocf_datapipes/transform/numpy_batch/datetime_features.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ocf_datapipes/transform/numpy_batch/__init__.py b/ocf_datapipes/transform/numpy_batch/__init__.py index 51afa1deb..c43e9943a 100644 --- a/ocf_datapipes/transform/numpy_batch/__init__.py +++ b/ocf_datapipes/transform/numpy_batch/__init__.py @@ -2,5 +2,5 @@ from .add_fourier_space_time import AddFourierSpaceTimeIterDataPipe as AddFourierSpaceTime from .add_topographic_data import AddTopographicDataIterDataPipe as AddTopographicData -from .sun_position import AddSunPositionIterDataPipe as AddSunPosition from .datetime_features import AddTrigonometricDateTimeIterDataPipe as AddTrigonometricDateTime +from .sun_position import AddSunPositionIterDataPipe as AddSunPosition diff --git a/ocf_datapipes/transform/numpy_batch/datetime_features.py b/ocf_datapipes/transform/numpy_batch/datetime_features.py index 73b33a71b..ea3ef5c1b 100644 --- a/ocf_datapipes/transform/numpy_batch/datetime_features.py +++ b/ocf_datapipes/transform/numpy_batch/datetime_features.py @@ -7,12 +7,12 @@ def _get_date_time_in_pi(dt): - day_of_year = (dt - dt.astype('datetime64[Y]')).astype(int) - minute_of_day = (dt - dt.astype('datetime64[D]')).astype(int) + day_of_year = (dt - dt.astype("datetime64[Y]")).astype(int) + minute_of_day = (dt - dt.astype("datetime64[D]")).astype(int) # converting into positions on sin-cos circle - time_in_pi = (2*np.pi) * (minute_of_day / (24*3600)) - date_in_pi = (2*np.pi) * (day_of_year / (365*24*3600)) + time_in_pi = (2 * np.pi) * (minute_of_day / (24 * 3600)) + date_in_pi = (2 * np.pi) * (day_of_year / (365 * 24 * 3600)) return date_in_pi, time_in_pi From 53d4fcf98e5e4ed591f464340e3133852876fa09 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:17:53 +0100 Subject: [PATCH 07/18] add type hints datetime_features.py --- ocf_datapipes/transform/numpy_batch/datetime_features.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ocf_datapipes/transform/numpy_batch/datetime_features.py b/ocf_datapipes/transform/numpy_batch/datetime_features.py index ea3ef5c1b..ceebf18fa 100644 --- a/ocf_datapipes/transform/numpy_batch/datetime_features.py +++ b/ocf_datapipes/transform/numpy_batch/datetime_features.py @@ -1,12 +1,13 @@ """Datapipes to add Sun position to NumpyBatch""" import numpy as np +from numpy.typing import NDArray from torch.utils.data import IterDataPipe, functional_datapipe from ocf_datapipes.batch import BatchKey -def _get_date_time_in_pi(dt): +def _get_date_time_in_pi(dt: NDArray[np.datetime64])) -> tuple[NDArray[np.float64], NDArray[np.float64]]: day_of_year = (dt - dt.astype("datetime64[Y]")).astype(int) minute_of_day = (dt - dt.astype("datetime64[D]")).astype(int) From e6d24a5d22000c074466f6618193486749711f25 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:21:56 +0100 Subject: [PATCH 08/18] fix typo datetime_features.py --- ocf_datapipes/transform/numpy_batch/datetime_features.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ocf_datapipes/transform/numpy_batch/datetime_features.py b/ocf_datapipes/transform/numpy_batch/datetime_features.py index ceebf18fa..0adb479a3 100644 --- a/ocf_datapipes/transform/numpy_batch/datetime_features.py +++ b/ocf_datapipes/transform/numpy_batch/datetime_features.py @@ -7,7 +7,7 @@ from ocf_datapipes.batch import BatchKey -def _get_date_time_in_pi(dt: NDArray[np.datetime64])) -> tuple[NDArray[np.float64], NDArray[np.float64]]: +def _get_date_time_in_pi(dt: NDArray[np.datetime64]) -> tuple[NDArray[np.float64], NDArray[np.float64]]: day_of_year = (dt - dt.astype("datetime64[Y]")).astype(int) minute_of_day = (dt - dt.astype("datetime64[D]")).astype(int) From fd27e3414454a8c5aa18343e8e7690e88f35dff6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:22:26 +0000 Subject: [PATCH 09/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ocf_datapipes/transform/numpy_batch/datetime_features.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ocf_datapipes/transform/numpy_batch/datetime_features.py b/ocf_datapipes/transform/numpy_batch/datetime_features.py index 0adb479a3..2120e1d0a 100644 --- a/ocf_datapipes/transform/numpy_batch/datetime_features.py +++ b/ocf_datapipes/transform/numpy_batch/datetime_features.py @@ -7,7 +7,9 @@ from ocf_datapipes.batch import BatchKey -def _get_date_time_in_pi(dt: NDArray[np.datetime64]) -> tuple[NDArray[np.float64], NDArray[np.float64]]: +def _get_date_time_in_pi( + dt: NDArray[np.datetime64], +) -> tuple[NDArray[np.float64], NDArray[np.float64]]: day_of_year = (dt - dt.astype("datetime64[Y]")).astype(int) minute_of_day = (dt - dt.astype("datetime64[D]")).astype(int) From 423152e6a981e94e556a583471d245aa0e6459bb Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:25:30 +0100 Subject: [PATCH 10/18] remove batched check in datetime_features.py --- .../numpy_batch/datetime_features.py | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/ocf_datapipes/transform/numpy_batch/datetime_features.py b/ocf_datapipes/transform/numpy_batch/datetime_features.py index 2120e1d0a..b350f4ad0 100644 --- a/ocf_datapipes/transform/numpy_batch/datetime_features.py +++ b/ocf_datapipes/transform/numpy_batch/datetime_features.py @@ -42,22 +42,9 @@ def __iter__(self): for np_batch in self.source_datapipe: time_utc = np_batch[BatchKey.wind_time_utc] - # Check if the input is batched - # time_utc could have shape (batch_size, n_times) or (n_times,) - assert len(time_utc.shape) in [1, 2] - is_batched = len(time_utc.shape) == 2 - - times = time_utc.astype("datetime64[s]") - - if is_batched: - time_in_pi = np.full_like(time_utc, fill_value=np.nan).astype(np.float32) - date_in_pi = np.full_like(time_utc, fill_value=np.nan).astype(np.float32) - - # Loop round each example to get converted time values - for example_idx, dt in enumerate(times): - date_in_pi[example_idx], time_in_pi[example_idx] = _get_date_time_in_pi(dt) - else: - date_in_pi, time_in_pi = _get_date_time_in_pi(times) + times: NDArray[np.datetime64] = time_utc.astype("datetime64[s]") + + date_in_pi, time_in_pi = _get_date_time_in_pi(times) # Store date_sin_batch_key = BatchKey[self.modality_name + "_date_sin"] From 62dc505fad843d35c67f18ba690335152948b748 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:30:05 +0100 Subject: [PATCH 11/18] Update description in datetime_features.py --- ocf_datapipes/transform/numpy_batch/datetime_features.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ocf_datapipes/transform/numpy_batch/datetime_features.py b/ocf_datapipes/transform/numpy_batch/datetime_features.py index b350f4ad0..ded62427a 100644 --- a/ocf_datapipes/transform/numpy_batch/datetime_features.py +++ b/ocf_datapipes/transform/numpy_batch/datetime_features.py @@ -1,4 +1,4 @@ -"""Datapipes to add Sun position to NumpyBatch""" +"""Datapipes to trigonometric date and time to NumpyBatch""" import numpy as np from numpy.typing import NDArray From 22295dc3da762561ac76d579e9effca65cd82a62 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:53:39 +0100 Subject: [PATCH 12/18] Create test_datetime_features.py --- .../numpy_batch/test_datetime_features.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/transform/numpy_batch/test_datetime_features.py diff --git a/tests/transform/numpy_batch/test_datetime_features.py b/tests/transform/numpy_batch/test_datetime_features.py new file mode 100644 index 000000000..862ad33de --- /dev/null +++ b/tests/transform/numpy_batch/test_datetime_features.py @@ -0,0 +1,34 @@ +import numpy as np +from datetime import datetime + +from ocf_datapipes.transform.numpy_batch import AddTrigonometricDateTime + +from ocf_datapipes.transform.numpy_batch.datetime_features import _get_date_time_in_pi + + +def test_get_date_time_in_pi(): + times = [ + "2020-01-01T00:00:01", "2020-04-01T06:00:00", + "2020-07-01T12:00:00", "2020-09-30T18:00:00", + "2020-12-31T23:59:59", + "2021-01-01T00:00:01", "2021-04-02T06:00:00", + "2021-07-02T12:00:00", "2021-10-01T18:00:00", + "2021-12-31T23:59:59" + ] + + expected_times_in_pi = [0, 0.5*np.pi, np.pi, 1.5*np.pi, 2*np.pi]*2 + + times = np.array([datetime.fromisoformat(time) for time in times], dtype="datetime64[s]") + + date_in_pi, time_in_pi = _get_date_time_in_pi(times) + + assert np.isclose(np.cos(time_in_pi), np.cos(expected_times_in_pi), atol=1e-04).all() + assert np.isclose(np.sin(time_in_pi), np.sin(expected_times_in_pi), atol=1e-04).all() + assert np.isclose(np.cos(date_in_pi), np.cos(expected_times_in_pi), atol=0.01).all() + assert np.isclose(np.sin(date_in_pi), np.sin(expected_times_in_pi), atol=0.02).all() + + +def test_add_trigonometric_datetime(combined_datapipe): + combined_datapipe = AddTrigonometricDateTime(combined_datapipe, modality_name="wind") + data = next(iter(combined_datapipe)) + assert data is not None From 2d68b5a06a308d26eeda4a8bfdf1fd21193d8d42 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:54:06 +0000 Subject: [PATCH 13/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../numpy_batch/test_datetime_features.py | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/transform/numpy_batch/test_datetime_features.py b/tests/transform/numpy_batch/test_datetime_features.py index 862ad33de..7b7480e48 100644 --- a/tests/transform/numpy_batch/test_datetime_features.py +++ b/tests/transform/numpy_batch/test_datetime_features.py @@ -8,15 +8,19 @@ def test_get_date_time_in_pi(): times = [ - "2020-01-01T00:00:01", "2020-04-01T06:00:00", - "2020-07-01T12:00:00", "2020-09-30T18:00:00", - "2020-12-31T23:59:59", - "2021-01-01T00:00:01", "2021-04-02T06:00:00", - "2021-07-02T12:00:00", "2021-10-01T18:00:00", - "2021-12-31T23:59:59" - ] - - expected_times_in_pi = [0, 0.5*np.pi, np.pi, 1.5*np.pi, 2*np.pi]*2 + "2020-01-01T00:00:01", + "2020-04-01T06:00:00", + "2020-07-01T12:00:00", + "2020-09-30T18:00:00", + "2020-12-31T23:59:59", + "2021-01-01T00:00:01", + "2021-04-02T06:00:00", + "2021-07-02T12:00:00", + "2021-10-01T18:00:00", + "2021-12-31T23:59:59", + ] + + expected_times_in_pi = [0, 0.5 * np.pi, np.pi, 1.5 * np.pi, 2 * np.pi] * 2 times = np.array([datetime.fromisoformat(time) for time in times], dtype="datetime64[s]") From 3a4af19a4f1ac03e37e3a036850a0952b4e5aa7c Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:04:21 +0100 Subject: [PATCH 14/18] Update test_datetime_features.py --- tests/transform/numpy_batch/test_datetime_features.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/transform/numpy_batch/test_datetime_features.py b/tests/transform/numpy_batch/test_datetime_features.py index 7b7480e48..cbdce16da 100644 --- a/tests/transform/numpy_batch/test_datetime_features.py +++ b/tests/transform/numpy_batch/test_datetime_features.py @@ -30,9 +30,3 @@ def test_get_date_time_in_pi(): assert np.isclose(np.sin(time_in_pi), np.sin(expected_times_in_pi), atol=1e-04).all() assert np.isclose(np.cos(date_in_pi), np.cos(expected_times_in_pi), atol=0.01).all() assert np.isclose(np.sin(date_in_pi), np.sin(expected_times_in_pi), atol=0.02).all() - - -def test_add_trigonometric_datetime(combined_datapipe): - combined_datapipe = AddTrigonometricDateTime(combined_datapipe, modality_name="wind") - data = next(iter(combined_datapipe)) - assert data is not None From 52e11892665091b0f28c76acb56e9c7f63f09814 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:30:29 +0100 Subject: [PATCH 15/18] Change tolerance of test in test_datetime_features.py --- .../numpy_batch/test_datetime_features.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/transform/numpy_batch/test_datetime_features.py b/tests/transform/numpy_batch/test_datetime_features.py index cbdce16da..47a9e3fae 100644 --- a/tests/transform/numpy_batch/test_datetime_features.py +++ b/tests/transform/numpy_batch/test_datetime_features.py @@ -25,8 +25,12 @@ def test_get_date_time_in_pi(): times = np.array([datetime.fromisoformat(time) for time in times], dtype="datetime64[s]") date_in_pi, time_in_pi = _get_date_time_in_pi(times) - - assert np.isclose(np.cos(time_in_pi), np.cos(expected_times_in_pi), atol=1e-04).all() - assert np.isclose(np.sin(time_in_pi), np.sin(expected_times_in_pi), atol=1e-04).all() - assert np.isclose(np.cos(date_in_pi), np.cos(expected_times_in_pi), atol=0.01).all() - assert np.isclose(np.sin(date_in_pi), np.sin(expected_times_in_pi), atol=0.02).all() + + # Note on precision: times are compared with tolerance equivalent to 1 second, + # dates are compared with tolerance equivalent to 5 minutes + # None of the data we use has a higher time resolution, so this is a good test of + # whether not accounting for leap years breaks things + assert np.isclose(np.cos(time_in_pi), np.cos(expected_times_in_pi), atol=7.3e-05).all() + assert np.isclose(np.sin(time_in_pi), np.sin(expected_times_in_pi), atol=7.3e-05).all() + assert np.isclose(np.cos(date_in_pi), np.cos(expected_times_in_pi), atol=0.02182).all() + assert np.isclose(np.sin(date_in_pi), np.sin(expected_times_in_pi), atol=0.02182).all() From dfefee09f860289b0a72d28fd5c107560b9e8a39 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:31:03 +0000 Subject: [PATCH 16/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/transform/numpy_batch/test_datetime_features.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/transform/numpy_batch/test_datetime_features.py b/tests/transform/numpy_batch/test_datetime_features.py index 47a9e3fae..54df6b5c5 100644 --- a/tests/transform/numpy_batch/test_datetime_features.py +++ b/tests/transform/numpy_batch/test_datetime_features.py @@ -25,7 +25,7 @@ def test_get_date_time_in_pi(): times = np.array([datetime.fromisoformat(time) for time in times], dtype="datetime64[s]") date_in_pi, time_in_pi = _get_date_time_in_pi(times) - + # Note on precision: times are compared with tolerance equivalent to 1 second, # dates are compared with tolerance equivalent to 5 minutes # None of the data we use has a higher time resolution, so this is a good test of From e10f984f9caa2cad735b5e019717b54bd63b6798 Mon Sep 17 00:00:00 2001 From: Alexandra Udaltsova <43303448+AUdaltsova@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:43:07 +0100 Subject: [PATCH 17/18] Add 2D array test test_datetime_features.py --- .../numpy_batch/test_datetime_features.py | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/transform/numpy_batch/test_datetime_features.py b/tests/transform/numpy_batch/test_datetime_features.py index 54df6b5c5..c487a25c2 100644 --- a/tests/transform/numpy_batch/test_datetime_features.py +++ b/tests/transform/numpy_batch/test_datetime_features.py @@ -1,28 +1,21 @@ import numpy as np -from datetime import datetime - -from ocf_datapipes.transform.numpy_batch import AddTrigonometricDateTime from ocf_datapipes.transform.numpy_batch.datetime_features import _get_date_time_in_pi def test_get_date_time_in_pi(): - times = [ - "2020-01-01T00:00:01", - "2020-04-01T06:00:00", - "2020-07-01T12:00:00", - "2020-09-30T18:00:00", - "2020-12-31T23:59:59", - "2021-01-01T00:00:01", - "2021-04-02T06:00:00", - "2021-07-02T12:00:00", - "2021-10-01T18:00:00", - "2021-12-31T23:59:59", - ] - - expected_times_in_pi = [0, 0.5 * np.pi, np.pi, 1.5 * np.pi, 2 * np.pi] * 2 - - times = np.array([datetime.fromisoformat(time) for time in times], dtype="datetime64[s]") + times = np.array([ + "2020-01-01T00:00:00", "2020-04-01T06:00:00", + "2020-07-01T12:00:00", "2020-09-30T18:00:00", + "2020-12-31T23:59:59", + "2021-01-01T00:00:00", "2021-04-02T06:00:00", + "2021-07-02T12:00:00", "2021-10-01T18:00:00", + "2021-12-31T23:59:59" + ]).reshape((2, 5)) + + expected_times_in_pi = np.array([0, 0.5*np.pi, np.pi, 1.5*np.pi, 2*np.pi] * 2).reshape((2,5)) + + times = times.astype("datetime64[s]") date_in_pi, time_in_pi = _get_date_time_in_pi(times) @@ -34,3 +27,9 @@ def test_get_date_time_in_pi(): assert np.isclose(np.sin(time_in_pi), np.sin(expected_times_in_pi), atol=7.3e-05).all() assert np.isclose(np.cos(date_in_pi), np.cos(expected_times_in_pi), atol=0.02182).all() assert np.isclose(np.sin(date_in_pi), np.sin(expected_times_in_pi), atol=0.02182).all() + + # 1D array test + assert np.isclose(np.cos(time_in_pi[0]), np.cos(expected_times_in_pi[0]), atol=7.3e-05).all() + assert np.isclose(np.sin(time_in_pi[0]), np.sin(expected_times_in_pi[0]), atol=7.3e-05).all() + assert np.isclose(np.cos(date_in_pi[0]), np.cos(expected_times_in_pi[0]), atol=0.02182).all() + assert np.isclose(np.sin(date_in_pi[0]), np.sin(expected_times_in_pi[0]), atol=0.02182).all() From 77035903837fcbb2a5ff511bc02db84c50dc6f68 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:44:12 +0000 Subject: [PATCH 18/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../numpy_batch/test_datetime_features.py | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/transform/numpy_batch/test_datetime_features.py b/tests/transform/numpy_batch/test_datetime_features.py index c487a25c2..c626ec2cf 100644 --- a/tests/transform/numpy_batch/test_datetime_features.py +++ b/tests/transform/numpy_batch/test_datetime_features.py @@ -4,16 +4,24 @@ def test_get_date_time_in_pi(): - times = np.array([ - "2020-01-01T00:00:00", "2020-04-01T06:00:00", - "2020-07-01T12:00:00", "2020-09-30T18:00:00", - "2020-12-31T23:59:59", - "2021-01-01T00:00:00", "2021-04-02T06:00:00", - "2021-07-02T12:00:00", "2021-10-01T18:00:00", - "2021-12-31T23:59:59" - ]).reshape((2, 5)) - - expected_times_in_pi = np.array([0, 0.5*np.pi, np.pi, 1.5*np.pi, 2*np.pi] * 2).reshape((2,5)) + times = np.array( + [ + "2020-01-01T00:00:00", + "2020-04-01T06:00:00", + "2020-07-01T12:00:00", + "2020-09-30T18:00:00", + "2020-12-31T23:59:59", + "2021-01-01T00:00:00", + "2021-04-02T06:00:00", + "2021-07-02T12:00:00", + "2021-10-01T18:00:00", + "2021-12-31T23:59:59", + ] + ).reshape((2, 5)) + + expected_times_in_pi = np.array([0, 0.5 * np.pi, np.pi, 1.5 * np.pi, 2 * np.pi] * 2).reshape( + (2, 5) + ) times = times.astype("datetime64[s]")