dalsi 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-ba81-gen-cutoff-exec-v1"
|
||||
PLANNER_BUILD_TAG = "2026-06-06-home01-late-replan-infeasible-v1"
|
||||
SOLVER_RELAX_STEPS: tuple[str, ...] = (
|
||||
"strict",
|
||||
"relaxed_expensive_import",
|
||||
@@ -79,6 +79,7 @@ SOLVER_RELAX_STEPS: tuple[str, ...] = (
|
||||
"relaxed_neg_prep_hold_only",
|
||||
"relaxed_neg_prep_window",
|
||||
"neg_sell_phases_fallback",
|
||||
"relaxed_pos_sell_ge_block",
|
||||
)
|
||||
# Ranní slabá FVE: neaplikovat pv_store ge_pv=0 (jinak curtail při sell < večerní peak).
|
||||
DAWN_LOW_PV_NO_CURTAIL_W = 1500
|
||||
@@ -149,6 +150,7 @@ def _solver_relax_chain(
|
||||
relaxed_neg_prep_hold_only: bool = False,
|
||||
relaxed_neg_prep_window: bool = False,
|
||||
neg_sell_phases_fallback: bool = False,
|
||||
relaxed_pos_sell_ge_block: bool = False,
|
||||
) -> list[str]:
|
||||
flags = {
|
||||
"relaxed_expensive_import": relaxed_expensive_import,
|
||||
@@ -156,6 +158,7 @@ def _solver_relax_chain(
|
||||
"relaxed_neg_prep_hold_only": relaxed_neg_prep_hold_only,
|
||||
"relaxed_neg_prep_window": relaxed_neg_prep_window,
|
||||
"neg_sell_phases_fallback": neg_sell_phases_fallback,
|
||||
"relaxed_pos_sell_ge_block": relaxed_pos_sell_ge_block,
|
||||
}
|
||||
chain = [SOLVER_RELAX_STEPS[0]]
|
||||
for step in SOLVER_RELAX_STEPS[1:]:
|
||||
@@ -2525,6 +2528,7 @@ def solve_dispatch(
|
||||
relaxed_neg_prep_hold_only: bool = False,
|
||||
relaxed_neg_prep_window: bool = False,
|
||||
neg_sell_phases_fallback: bool = False,
|
||||
relaxed_pos_sell_ge_block: bool = False,
|
||||
evening_push_ts_override: Optional[set[int]] = None,
|
||||
) -> tuple[list[DispatchResult], int, dict[str, Any]]:
|
||||
"""
|
||||
@@ -2534,6 +2538,7 @@ def solve_dispatch(
|
||||
relaxed_neg_buy_charge: druhý nouzový retry bez neg_buy charge shortfall.
|
||||
relaxed_neg_prep_hold_only: třetí retry — bez prep_soc_shortfall a prep hold binárek (evening push zůstává).
|
||||
relaxed_neg_prep_window: čtvrtý retry — vypne strict pre-neg bundle; future_neg_buy večerní export zůstává.
|
||||
relaxed_pos_sell_ge_block: poslední retry — neaplikovat ge=0 v pos_sell před buy<0 (zbylá Infeasible).
|
||||
"""
|
||||
T = len(slots)
|
||||
if T < 1:
|
||||
@@ -2543,6 +2548,7 @@ def solve_dispatch(
|
||||
or relaxed_neg_buy_charge
|
||||
or relaxed_neg_prep_window
|
||||
or neg_sell_phases_fallback
|
||||
or relaxed_pos_sell_ge_block
|
||||
)
|
||||
prep_hold_relaxed = relaxed_neg_prep_hold_only or relaxed_neg_prep_window
|
||||
EV = len(vehicles) # počet EV (typicky 2)
|
||||
@@ -3085,6 +3091,36 @@ def solve_dispatch(
|
||||
battery_export_defer_pv_ts = {
|
||||
t for t in range(T) if _battery_export_push_defer_to_pv(slots[t])
|
||||
}
|
||||
# Pozdní replan večer: SQL allow_charge může být false (drahý buy), ale večerní vývoz
|
||||
# k reserve před neg dnem vyžaduje souběžně grid import pro load (ne jen bd).
|
||||
if neg_evening_discharge_active or evening_push_ts:
|
||||
replan_day = _prague_calendar_date(slots[0])
|
||||
for t in range(T):
|
||||
if _prague_calendar_date(slots[t]) != replan_day:
|
||||
continue
|
||||
if float(slots[t].sell_price) < 0.0:
|
||||
continue
|
||||
if (
|
||||
t in evening_push_ts
|
||||
or t in neg_evening_push_ts
|
||||
or (
|
||||
_in_evening_push_hour_window(slots[t])
|
||||
and t in discharge_export_slots
|
||||
)
|
||||
):
|
||||
charge_slots.add(t)
|
||||
if neg_evening_discharge_active:
|
||||
for t in discharge_export_slots:
|
||||
if _prague_calendar_date(slots[t]) == replan_day:
|
||||
charge_slots.add(t)
|
||||
if relaxed_pos_sell_ge_block:
|
||||
# Poslední retry: SQL allow_charge / drahý import nesmí zablokovat fyzicky dosažitelný plán.
|
||||
charge_slots = set(range(T))
|
||||
discharge_export_slots = {
|
||||
t
|
||||
for t, s in enumerate(slots)
|
||||
if s.allow_discharge_export or float(s.sell_price) >= 0.0
|
||||
}
|
||||
else:
|
||||
battery_export_defer_pv_ts = set()
|
||||
pre_neg_buy_soc_ceiling_wh = _pre_neg_buy_soc_ceiling_wh(
|
||||
@@ -4174,6 +4210,7 @@ def solve_dispatch(
|
||||
and first_neg_buy_idx > 0
|
||||
and t in pos_sell_pre_neg_buy_ts
|
||||
and t not in pos_sell_pre_neg_buy_ge_exempt_ts
|
||||
and not relaxed_pos_sell_ge_block
|
||||
):
|
||||
prob += ge[t] == 0
|
||||
prob += ge_pv[t] == 0
|
||||
@@ -4551,6 +4588,38 @@ def solve_dispatch(
|
||||
neg_sell_phases_fallback=True,
|
||||
evening_push_ts_override=evening_push_ts_override,
|
||||
)
|
||||
if not relaxed_pos_sell_ge_block:
|
||||
logger.warning(
|
||||
"solve_dispatch still Infeasible, retry with relaxed_pos_sell_ge_block "
|
||||
"(no ge=0 on pos_sell before buy<0)"
|
||||
)
|
||||
battery_no_phases = SimpleNamespace(
|
||||
**{
|
||||
**vars(battery),
|
||||
"planner_neg_sell_prep_soc_percent": 100.0,
|
||||
}
|
||||
)
|
||||
return solve_dispatch(
|
||||
slots,
|
||||
battery_no_phases,
|
||||
heat_pump,
|
||||
grid,
|
||||
ev_sessions,
|
||||
vehicles,
|
||||
current_soc_wh,
|
||||
current_tuv_temp_c,
|
||||
tuv_delta_stats=tuv_delta_stats,
|
||||
operating_mode=operating_mode,
|
||||
charge_commitment_prev_w=charge_commitment_prev_w,
|
||||
planner_version=planner_version,
|
||||
relaxed_expensive_import=True,
|
||||
relaxed_neg_buy_charge=True,
|
||||
relaxed_neg_prep_hold_only=True,
|
||||
relaxed_neg_prep_window=True,
|
||||
neg_sell_phases_fallback=True,
|
||||
relaxed_pos_sell_ge_block=True,
|
||||
evening_push_ts_override=evening_push_ts_override,
|
||||
)
|
||||
raise PlannerSolverError(
|
||||
pulp.LpStatus[status],
|
||||
relax_chain=_solver_relax_chain(
|
||||
@@ -4559,6 +4628,7 @@ def solve_dispatch(
|
||||
relaxed_neg_prep_hold_only=relaxed_neg_prep_hold_only,
|
||||
relaxed_neg_prep_window=relaxed_neg_prep_window,
|
||||
neg_sell_phases_fallback=neg_sell_phases_fallback,
|
||||
relaxed_pos_sell_ge_block=relaxed_pos_sell_ge_block,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -4910,12 +4980,14 @@ def solve_dispatch(
|
||||
"relaxed_neg_prep_hold_only": relaxed_neg_prep_hold_only,
|
||||
"relaxed_neg_prep_window": relaxed_neg_prep_window,
|
||||
"neg_sell_phases_fallback": neg_sell_phases_fallback,
|
||||
"relaxed_pos_sell_ge_block": relaxed_pos_sell_ge_block,
|
||||
"relax_chain": _solver_relax_chain(
|
||||
relaxed_expensive_import=relaxed_expensive_import,
|
||||
relaxed_neg_buy_charge=relaxed_neg_buy_charge,
|
||||
relaxed_neg_prep_hold_only=relaxed_neg_prep_hold_only,
|
||||
relaxed_neg_prep_window=relaxed_neg_prep_window,
|
||||
neg_sell_phases_fallback=neg_sell_phases_fallback,
|
||||
relaxed_pos_sell_ge_block=relaxed_pos_sell_ge_block,
|
||||
),
|
||||
"charge_acquisition_buy_czk_kwh": charge_acquisition_czk_kwh,
|
||||
"charge_acquisition_cutoff_at": (
|
||||
|
||||
Reference in New Issue
Block a user