revert a nove upravy
This commit is contained in:
@@ -64,7 +64,7 @@ NEG_SELL_PV_B_VENT_PENALTY_CZK_KWH = 4.0
|
||||
# Výboj baterie při sell<0 jen těsně před extrémně záporným buy (round-trip arbitráž).
|
||||
EXTREME_BUY_DUMP_PREWINDOW_SLOTS = 12
|
||||
NEG_SELL_BAT_DUMP_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||
PLANNER_BUILD_TAG = "2026-05-27-neg-sell-soc-reservation-v13"
|
||||
PLANNER_BUILD_TAG = "2026-05-27-simple-buy-neg-window-v16"
|
||||
CORRECTION_WINDOW_H = 1 # hodina zpět pro výpočet korekčního faktoru
|
||||
CORRECTION_MIN_CLAMP = 0.5 # spodní limit korekčního faktoru
|
||||
CORRECTION_MAX_CLAMP = 1.5 # horní limit korekčního faktoru
|
||||
@@ -1200,6 +1200,28 @@ def solve_dispatch(
|
||||
discharge_export_slots = {
|
||||
t for t, s in enumerate(slots) if s.allow_discharge_export
|
||||
}
|
||||
# Vybití baterie před `buy<0` oknem: pokud je v horizontu buy<0, můžeme baterii
|
||||
# vybít teď za `sell` a v buy<0 okně ji nabít za záporný buy (= příjem).
|
||||
# Ekonomicky výhodné dokud: sell_t > avg_buy_neg + degradation
|
||||
# (vybíjet ztratíme ~discharge_eff loss, nabíjení v buy<0 nás platí; marže ~ sell − buy_neg − degrad).
|
||||
# Cílem je obejít to, že R__063 v noci dává allow_discharge_export=false a LP
|
||||
# by jinak nemohl baterku vyklidit přes ge_bat.
|
||||
_neg_buy_for_disch = next(
|
||||
(t for t, s in enumerate(slots) if float(s.buy_price) < 0), None
|
||||
)
|
||||
if _neg_buy_for_disch is not None and _neg_buy_for_disch > 0:
|
||||
_neg_buy_prices = [
|
||||
float(slots[t].buy_price)
|
||||
for t in range(_neg_buy_for_disch, T)
|
||||
if float(slots[t].buy_price) < 0
|
||||
]
|
||||
_avg_neg_buy = sum(_neg_buy_prices) / len(_neg_buy_prices) if _neg_buy_prices else 0.0
|
||||
# Práh = avg buy<0 + degradation cycle overhead; default fallback 0.1 Kč/kWh
|
||||
# když z nějakého důvodu neumíme spočítat (ochrana proti vybití do mínusu).
|
||||
_disch_sell_thr = max(_avg_neg_buy + float(degradation_cost_effective), 0.1)
|
||||
for t in range(_neg_buy_for_disch):
|
||||
if float(slots[t].sell_price) >= _disch_sell_thr:
|
||||
discharge_export_slots.add(t)
|
||||
# SELF_SUSTAIN dřív vynucoval ge[t] == 0, což umí udělat MILP infeasible v okamžiku, kdy:
|
||||
# - baterie je na max SoC (nelze nabíjet),
|
||||
# - PV pole B není curtailable,
|
||||
@@ -1913,6 +1935,16 @@ def solve_dispatch(
|
||||
prob += bd[t] == 0
|
||||
|
||||
# Slot pre-selection (z DB fn_load_planning_slots_full → allow_*)
|
||||
# PŘED prvním buy<0 slotem v horizontu (= rezervační okno):
|
||||
# - sell ≥ 0 → bc_pv = 0 (PV poteče do gridu / curtail, baterka se nenabíjí z PV
|
||||
# protože v buy<0 okně bude akvizice levnější — záporná).
|
||||
# - sell < 0 → slot je v charge_slots (R__063), bc_pv ≤ pv_surplus (= nemůžeme
|
||||
# pole A vyhodit do mínusu, raději nabít baterii).
|
||||
# JINDY (po buy<0 okně, nebo žádné buy<0 v horizontu): původní permissive
|
||||
# bc_pv ≤ pv_surplus aby nedošlo k regresi normálních dnů.
|
||||
_neg_buy_idx_main = next(
|
||||
(t for t, s in enumerate(slots) if float(s.buy_price) < 0), None
|
||||
)
|
||||
if om == "AUTO":
|
||||
for t in range(T):
|
||||
if t not in charge_slots:
|
||||
@@ -1923,11 +1955,17 @@ def solve_dispatch(
|
||||
+ int(s.pv_b_forecast_w)
|
||||
- int(s.load_baseline_w),
|
||||
)
|
||||
# Mimo grid-charge masku: jen PV přebytek; výjimka záporný buy (spot arbitráž).
|
||||
if float(s.buy_price) >= 0.0:
|
||||
prob += bc_gi[t] == 0
|
||||
in_pre_neg_buy_window = (
|
||||
_neg_buy_idx_main is not None and t < _neg_buy_idx_main
|
||||
)
|
||||
if pv_surplus_w <= 0:
|
||||
prob += bc_pv[t] == 0
|
||||
elif in_pre_neg_buy_window:
|
||||
# Strukturální preference: PV jde do gridu (sell≥0) nebo curtail,
|
||||
# ne do baterie — kapacitu si šetříme na buy<0 okno.
|
||||
prob += bc_pv[t] == 0
|
||||
else:
|
||||
prob += bc_pv[t] <= float(pv_surplus_w)
|
||||
if t not in discharge_export_slots and t not in neg_sell_bat_dump_slots:
|
||||
|
||||
Reference in New Issue
Block a user