From c52946a4ce7763997d96aeb48ab8ae1751f87407 Mon Sep 17 00:00:00 2001 From: Dusan Vojacek Date: Mon, 27 Apr 2026 19:24:37 +0200 Subject: [PATCH] fix BA81 nevybijeni do site --- backend/services/planning_engine.py | 6 ++---- backend/tests/test_planning_dispatch_milp.py | 2 ++ ...9__asset_battery_terminal_soc_factor_not_null.sql | 12 ++++++++++++ db/routines/R__039_fn_planning_site_context.sql | 10 ++-------- 4 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 db/migration/V069__asset_battery_terminal_soc_factor_not_null.sql diff --git a/backend/services/planning_engine.py b/backend/services/planning_engine.py index c5cd108..19e42d8 100644 --- a/backend/services/planning_engine.py +++ b/backend/services/planning_engine.py @@ -29,7 +29,6 @@ logger = logging.getLogger(__name__) # Když DB vrátí NULL (skoro žádná OTE data), denní plán použije krátký fallback (soulad s min hodinami ve fn_planning_horizon_end). _DAILY_FALLBACK_HORIZON_HOURS = 1.0 # Shadow cena zbytkové energie na konci horizontu: - (avg_buy * FACTOR / 1000) * soc[T-1] (Kč; soc v Wh). -TERMINAL_SOC_VALUE_FACTOR = 0.9 INTERVAL_H = 0.25 # 15 minut v hodinách CURTAILMENT_PENALTY = 0.001 # Kč/Wh – malá penalizace za omezení FVE pole A SOLVER_TIME_LIMIT = 10 # sekund @@ -577,9 +576,7 @@ def solve_dispatch( if horizon_slots_h24 > 0 else 4.0 ) - terminal_factor = float( - getattr(battery, "planner_terminal_soc_value_factor", TERMINAL_SOC_VALUE_FACTOR) - ) + terminal_factor = float(battery.planner_terminal_soc_value_factor) # Kč/Wh: ocenění energie ponechané v baterii na konci horizontu (receding horizon kotva). terminal_soc_kcz_per_wh = ( avg_buy_terminal * terminal_factor / 1000.0 @@ -1135,6 +1132,7 @@ async def _load_site_context(site_id: int, db): planner_discharge_relax_prewindow_slots=int(relax_prewin) if relax_prewin is not None else DEFAULT_PLANNER_DISCHARGE_RELAX_PREWINDOW_SLOTS, + planner_terminal_soc_value_factor=float(b["planner_terminal_soc_value_factor"]), ) hpj = ctx["heat_pump"] diff --git a/backend/tests/test_planning_dispatch_milp.py b/backend/tests/test_planning_dispatch_milp.py index 10440a3..b069272 100644 --- a/backend/tests/test_planning_dispatch_milp.py +++ b/backend/tests/test_planning_dispatch_milp.py @@ -44,6 +44,7 @@ def _battery( min_pct: float = 10.0, arb_pct: float = 20.0, max_pct: float = 95.0, + terminal_soc_value_factor: float = 0.9, ) -> SimpleNamespace: uc = uc_wh min_wh = min_pct / 100.0 * uc @@ -59,6 +60,7 @@ def _battery( degradation_cost_czk_kwh=0.15, max_charge_power_w=10_000, max_discharge_power_w=10_000, + planner_terminal_soc_value_factor=terminal_soc_value_factor, ) diff --git a/db/migration/V069__asset_battery_terminal_soc_factor_not_null.sql b/db/migration/V069__asset_battery_terminal_soc_factor_not_null.sql new file mode 100644 index 0000000..3a68db0 --- /dev/null +++ b/db/migration/V069__asset_battery_terminal_soc_factor_not_null.sql @@ -0,0 +1,12 @@ +-- planner_terminal_soc_value_factor: LP terminal SoC shadow price (planning_engine). +-- V062 přidal sloupec NOT NULL default 0.9; tato migrace je idempotentní upevnění pro starší / ručně upravené DB. + +update ems.asset_battery + set planner_terminal_soc_value_factor = 0.9 + where planner_terminal_soc_value_factor is null; + +alter table ems.asset_battery + alter column planner_terminal_soc_value_factor set default 0.9; + +alter table ems.asset_battery + alter column planner_terminal_soc_value_factor set not null; diff --git a/db/routines/R__039_fn_planning_site_context.sql b/db/routines/R__039_fn_planning_site_context.sql index 3cb85f0..69e7cf6 100644 --- a/db/routines/R__039_fn_planning_site_context.sql +++ b/db/routines/R__039_fn_planning_site_context.sql @@ -66,7 +66,8 @@ begin ) )::int, 'charge_slot_buffer', ab.charge_slot_buffer, - 'discharge_slot_buffer', ab.discharge_slot_buffer + 'discharge_slot_buffer', ab.discharge_slot_buffer, + 'planner_terminal_soc_value_factor', ab.planner_terminal_soc_value_factor ) into v_b from ems.asset_battery ab @@ -130,13 +131,6 @@ begin raise exception 'No site_grid_connection for site_id=%', p_site_id; end if; - -- LP tuning (battery-level): terminal SoC shadow price factor - v_b := jsonb_set( - v_b, - '{planner_terminal_soc_value_factor}', - to_jsonb(coalesce((v_b->>'planner_terminal_soc_value_factor')::numeric, 0.9)) - ); - select coalesce( jsonb_agg( jsonb_build_object(