chore: prepare for update of genetic algorithm (#1190)
Bump Version / Bump Version Workflow (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled

Andreas will update the genetic algorithm for 15-minutes optimization
intervals.

Copy the current GENETIC optimization algorithm to GENETIC0 to enable
to keep the algorithm with the current functionality. Also copy resources
like the load interpolator to the GENETIC0 algorithm to keep them despite
possible later changes to the interpolator.

Make the deprecated legacy /optimize endpoint use the GENETIC0 optimization
algorithm to in-fact behave the same way even if there will later be changes
to the GENETIC algorithm by Andreas. Add a new REST endpoint to provide
the unprocessed optimisation results of the GENETIC and GENETIC0 algorithm
in case one wants to use them as done with the deprecated /optimize endpoint.

Adapt the optimization configuration to have distinct configurations for the
GENETIC and the GENETIC0 algorithm.

Create a copy of the current tests for the GENETIC algorithm to be used
for the GENETIC0 algorithm. This avoids the tests for the GENETIC0
algorithm to be influenced by later changes by Andreas.

Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
Bobby Noelte
2026-07-29 12:56:08 +02:00
committed by GitHub
parent 7e5aa2f218
commit e23bb7b497
51 changed files with 13086 additions and 955 deletions
+1 -70
View File
@@ -110,38 +110,6 @@ class TestElecPriceFixed:
provider.config.reset_settings()
assert not provider.enabled()
@pytest.mark.asyncio
async def test_update_data_hourly_intervals(self, provider, config_eos):
"""Test updating data with hourly intervals (3600s)."""
# Set start datetime
ems_eos = get_ems()
start_dt = to_datetime("2024-01-01 00:00:00", in_timezone="Europe/Berlin")
ems_eos.set_start_datetime(start_dt)
# Configure hourly intervals
config_eos.optimization.interval = 3600
config_eos.prediction.hours = 24
# Update data
await provider.update_data(force_enable=True, force_update=True)
# Verify data was generated
assert len(provider) == 24 # 24 hours * 1 interval per hour
# Check prices
records = provider.records
# First 8 hours should be night rate (0.288 kWh = 0.000288 Wh)
for i in range(8):
assert abs(records[i].elecprice_marketprice_wh - 0.000288) < 1e-6
# Verify timestamps are on hour boundaries
assert records[i].date_time.minute == 0
assert records[i].date_time.second == 0
# Next 16 hours should be day rate (0.34 kWh = 0.00034 Wh)
for i in range(8, 24):
assert abs(records[i].elecprice_marketprice_wh - 0.00034) < 1e-6
@pytest.mark.asyncio
async def test_update_data_15min_intervals(self, provider, config_eos):
"""Test updating data with 15-minute intervals (900s)."""
@@ -149,7 +117,6 @@ class TestElecPriceFixed:
start_dt = to_datetime("2024-01-01 00:00:00", in_timezone="Europe/Berlin")
ems_eos.set_start_datetime(start_dt)
config_eos.optimization.interval = 900
config_eos.prediction.hours = 10 # spans both windows: 00:0010:00 = 40 intervals
await provider.update_data(force_enable=True, force_update=True)
@@ -176,40 +143,6 @@ class TestElecPriceFixed:
f"Expected day rate at interval {i}, got {records[i].elecprice_marketprice_wh}"
)
@pytest.mark.asyncio
async def test_update_data_30min_intervals(self, provider, config_eos):
"""Test updating data with 30-minute intervals (1800s)."""
ems_eos = get_ems()
start_dt = to_datetime("2024-01-01 00:00:00", in_timezone="Europe/Berlin")
ems_eos.set_start_datetime(start_dt)
config_eos.optimization.interval = 1800
config_eos.prediction.hours = 10 # spans both windows: 00:0010:00 = 20 intervals
await provider.update_data(force_enable=True, force_update=True)
# 10 hours * 2 intervals per hour = 20 intervals
assert len(provider) == 20
records = provider.records
# Check timestamps are on 30-minute boundaries
for record in records:
assert record.date_time.minute in (0, 30)
assert record.date_time.second == 0
# First 16 intervals: 00:0008:00, night rate (8h * 2 = 16)
for i in range(16):
assert abs(records[i].elecprice_marketprice_wh - 0.000288) < 1e-6, (
f"Expected night rate at interval {i}, got {records[i].elecprice_marketprice_wh}"
)
# Remaining 4 intervals: 08:0010:00, day rate (2h * 2 = 4)
for i in range(16, 20):
assert abs(records[i].elecprice_marketprice_wh - 0.00034) < 1e-6, (
f"Expected day rate at interval {i}, got {records[i].elecprice_marketprice_wh}"
)
@pytest.mark.asyncio
async def test_update_data_without_config(self, provider, config_eos):
"""Test update_data fails without configuration."""
@@ -232,12 +165,11 @@ class TestElecPriceFixed:
@pytest.mark.asyncio
async def test_key_to_array_resampling(self, provider, config_eos):
"""Test that key_to_array can resample to different intervals."""
# Setup provider with hourly data
# Provider provides 15-minutes data
ems_eos = get_ems()
start_dt = to_datetime("2024-01-01 00:00:00", in_timezone="Europe/Berlin")
ems_eos.set_start_datetime(start_dt)
config_eos.optimization.interval = 3600
config_eos.prediction.hours = 24
await provider.update_data(force_enable=True, force_update=True)
@@ -315,7 +247,6 @@ class TestElecPriceFixedIntegration:
config_eos.elecprice.elecpricefixed = ElecPriceFixedCommonSettings(time_windows=time_windows)
config_eos.prediction.hours = 168 # 7 days
config_eos.optimization.interval = 900 # 15 minutes
# Update data
await provider.update_data(force_enable=True, force_update=True)