dasli fix
This commit is contained in:
@@ -71,7 +71,7 @@ NEG_BUY_CHARGE_SHORTFALL_PENALTY_CZK_KWH = 100.0
|
||||
PRE_NEG_CHARGE_PENALTY_CZK_KWH = 400.0
|
||||
PRE_NEG_BATT_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||
PRE_NEG_BATT_EXPORT_MIN_SELL_CZK_KWH = 1.0
|
||||
PLANNER_BUILD_TAG = "2026-06-06-home01-late-replan-infeasible-v2"
|
||||
PLANNER_BUILD_TAG = "2026-06-06-home01-degraded-night-guard-v3"
|
||||
SOLVER_RELAX_STEPS: tuple[str, ...] = (
|
||||
"strict",
|
||||
"relaxed_expensive_import",
|
||||
@@ -1940,6 +1940,24 @@ def _evening_push_segment_candidates(
|
||||
return out
|
||||
|
||||
|
||||
def _degraded_relaxed_night_self_consume_indices(
|
||||
slots: list[PlanningSlot],
|
||||
) -> set[int]:
|
||||
"""
|
||||
relaxed_solver_masks: celé noční okno — dům z baterie (až min_soc), ne import za spot buy.
|
||||
"""
|
||||
out: set[int] = set()
|
||||
for t, s in enumerate(slots):
|
||||
if not _in_night_battery_export_window(s):
|
||||
continue
|
||||
if float(s.load_baseline_w) <= 0:
|
||||
continue
|
||||
if float(s.buy_price) < 0.0:
|
||||
continue
|
||||
out.add(t)
|
||||
return out
|
||||
|
||||
|
||||
def _post_evening_push_night_self_consume_indices(
|
||||
slots: list[PlanningSlot],
|
||||
evening_push_ts: set[int],
|
||||
@@ -3027,6 +3045,7 @@ def solve_dispatch(
|
||||
evening_early_export_penalty_ts: set[int] = set()
|
||||
night_self_consume_discourage_ts: set[int] = set()
|
||||
post_evening_push_night_ts: set[int] = set()
|
||||
degraded_relaxed_night_ts: set[int] = set()
|
||||
evening_push_hysteresis_retained = False
|
||||
push_override_raw: Optional[set[int]] = None
|
||||
push_override_eff: Optional[set[int]] = None
|
||||
@@ -3195,6 +3214,9 @@ def solve_dispatch(
|
||||
evening_early_export_penalty_ts = set()
|
||||
battery_export_defer_pv_ts = set()
|
||||
evening_push_hard_suppressed = True
|
||||
degraded_relaxed_night_ts = _degraded_relaxed_night_self_consume_indices(slots)
|
||||
night_self_consume_discourage_ts |= degraded_relaxed_night_ts
|
||||
post_evening_push_night_ts |= degraded_relaxed_night_ts
|
||||
pre_neg_buy_soc_ceiling_wh = _pre_neg_buy_soc_ceiling_wh(
|
||||
slots,
|
||||
first_neg_buy_idx=first_neg_buy_idx,
|
||||
@@ -3307,6 +3329,8 @@ def solve_dispatch(
|
||||
block_export_neg_sell = bool(getattr(grid, "block_export_on_negative_sell", False))
|
||||
if om == "AUTO":
|
||||
for t in range(T):
|
||||
if relaxed_solver_masks and not purchase_fixed_pre:
|
||||
continue
|
||||
if t not in discharge_export_slots:
|
||||
continue
|
||||
if t in evening_push_ts:
|
||||
@@ -3854,6 +3878,13 @@ def solve_dispatch(
|
||||
continue
|
||||
prob += ge_bat[t_pv] == 0
|
||||
prob += z_export[t_pv] == 0
|
||||
# Nouzový relax: spot v noci neexportovat baterii za ~2,5 Kč (žádný tvrdý evening dump).
|
||||
if relaxed_solver_masks and not purchase_fixed_pre:
|
||||
for t_blk in range(T):
|
||||
if not _in_night_battery_export_window(slots[t_blk]):
|
||||
continue
|
||||
prob += ge_bat[t_blk] == 0
|
||||
prob += z_export[t_blk] == 0
|
||||
# Ostatní profitable sloty: měkká shortfall penalizace (ne večerní push).
|
||||
if (
|
||||
last_pos_sell_pre_neg_buy is not None
|
||||
@@ -4195,6 +4226,7 @@ def solve_dispatch(
|
||||
else:
|
||||
export_soc_floor_t = float(arb_base_wh)
|
||||
# Večerní exportní slot: podlaha jen min_soc (ne safety ramp), aby šlo vybít při z_export=1.
|
||||
# Nouzový relaxed_solver_masks: export nikdy pod reserve_soc (ekonomická podlaha).
|
||||
if (
|
||||
om == "AUTO"
|
||||
and t in discharge_export_slots
|
||||
@@ -4202,8 +4234,14 @@ def solve_dispatch(
|
||||
t in evening_peak_export_ts
|
||||
or t in neg_evening_push_ts
|
||||
)
|
||||
and not relaxed_solver_masks
|
||||
):
|
||||
export_soc_floor_t = float(min_soc_wh)
|
||||
elif relaxed_solver_masks and om == "AUTO":
|
||||
export_soc_floor_t = max(
|
||||
export_soc_floor_t,
|
||||
float(getattr(battery, "reserve_soc_wh", arb_base_wh)),
|
||||
)
|
||||
# Safety export floor: v běžných (ne high-sell) slotech nevybít exportem energii potřebnou pro
|
||||
# robustnost/noční baseload. Použije se pouze pokud je safety target v SQL vyplněný.
|
||||
tgt_s = slots[t].safety_soc_target_wh if daytime_en else None
|
||||
@@ -5149,6 +5187,10 @@ def solve_dispatch(
|
||||
slots[i].interval_start.isoformat()
|
||||
for i in sorted(night_self_consume_discourage_ts)
|
||||
],
|
||||
"degraded_relaxed_night_ts": [
|
||||
slots[i].interval_start.isoformat()
|
||||
for i in sorted(degraded_relaxed_night_ts)
|
||||
],
|
||||
},
|
||||
"masks": masks_snap,
|
||||
"soc_bounds": soc_bounds_snap,
|
||||
|
||||
Reference in New Issue
Block a user