dasli fix
This commit is contained in:
@@ -3698,6 +3698,90 @@ class ChargeAcquisitionArbitrageTests(unittest.TestCase):
|
||||
self.assertLess(results[0].grid_setpoint_w, -500)
|
||||
self.assertLess(results[0].battery_soc_target, 70.0)
|
||||
|
||||
def test_degraded_relaxed_solver_no_night_dump_and_self_consume(self) -> None:
|
||||
"""relaxed_solver_masks: žádný večerní dump za ~2,5 Kč; noc dům z baterie, ne import ~4 Kč."""
|
||||
prague = ZoneInfo("Europe/Prague")
|
||||
base = datetime(2026, 6, 6, 21, 30, tzinfo=prague).astimezone(timezone.utc)
|
||||
rows: list[tuple[float, float, int]] = [
|
||||
(4.66, 2.85, 780),
|
||||
(4.48, 2.72, 780),
|
||||
(4.76, 2.92, 450),
|
||||
(4.35, 2.61, 450),
|
||||
(4.06, 2.40, 440),
|
||||
(3.80, 2.20, 440),
|
||||
(3.76, 2.17, 440),
|
||||
(3.48, 1.96, 440),
|
||||
(3.76, 2.17, 460),
|
||||
(3.48, 1.96, 460),
|
||||
(3.34, 1.85, 460),
|
||||
(3.03, 1.61, 460),
|
||||
]
|
||||
slots: list[PlanningSlot] = []
|
||||
for i in range(48):
|
||||
local = (base + timedelta(minutes=15 * i)).astimezone(prague)
|
||||
if i < len(rows):
|
||||
buy, sell, load = rows[i]
|
||||
pv_a, pv_b = 0, 0
|
||||
elif local.hour >= 5 and local.hour < 12:
|
||||
buy, sell, load, pv_a, pv_b = 0.5, -0.3, 800, 2000, 2500
|
||||
else:
|
||||
buy, sell, load, pv_a, pv_b = 3.0, 2.0, 500, 0, 0
|
||||
slots.append(
|
||||
PlanningSlot(
|
||||
interval_start=base + timedelta(minutes=15 * i),
|
||||
buy_price=buy,
|
||||
sell_price=sell,
|
||||
pv_a_forecast_w=pv_a,
|
||||
pv_b_forecast_w=pv_b,
|
||||
load_baseline_w=load,
|
||||
ev1_connected=False,
|
||||
ev2_connected=False,
|
||||
allow_charge=True,
|
||||
allow_discharge_export=sell >= 0,
|
||||
)
|
||||
)
|
||||
bat = _battery(uc_wh=64_000.0, arb_pct=20.0, terminal_soc_value_factor=0.9)
|
||||
bat.planner_neg_sell_prep_soc_percent = 100.0
|
||||
hp = SimpleNamespace(rated_heating_power_w=0, tuv_min_temp_c=45.0, tuv_target_temp_c=55.0)
|
||||
grid = SimpleNamespace(
|
||||
max_import_power_w=17_000,
|
||||
max_export_power_w=13_500,
|
||||
block_export_on_negative_sell=False,
|
||||
purchase_pricing_mode="spot",
|
||||
)
|
||||
vehicles = [
|
||||
SimpleNamespace(max_charge_power_w=0, battery_capacity_kwh=1.0, default_target_soc_pct=80.0),
|
||||
SimpleNamespace(max_charge_power_w=0, battery_capacity_kwh=1.0, default_target_soc_pct=80.0),
|
||||
]
|
||||
soc = 0.71 * bat.soc_max_wh
|
||||
results, _ms, snap = solve_dispatch(
|
||||
slots,
|
||||
bat,
|
||||
hp,
|
||||
grid,
|
||||
[None, None],
|
||||
vehicles,
|
||||
soc,
|
||||
50.0,
|
||||
operating_mode="AUTO",
|
||||
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,
|
||||
relaxed_solver_masks=True,
|
||||
)
|
||||
inp = snap.get("inputs") or {}
|
||||
self.assertTrue(inp.get("relaxed_solver_masks"))
|
||||
self.assertGreater(len(inp.get("degraded_relaxed_night_ts") or []), 0)
|
||||
for i, r in enumerate(results[:12]):
|
||||
self.assertGreaterEqual(r.battery_soc_target, 10.0)
|
||||
if i < 4:
|
||||
self.assertGreater(r.grid_setpoint_w, -500, msg=f"slot {i} evening dump")
|
||||
if 8 <= i <= 11 and rows[i][0] > 3.0:
|
||||
self.assertLessEqual(r.grid_setpoint_w, rows[i][2] + 50, msg=f"slot {i} grid import")
|
||||
|
||||
def test_kv1_evening_push_profitable_vs_morning_zone_peak(self) -> None:
|
||||
"""v52: KV1 večer ≥ ranní max (5–11) − degrad; pod prahem ne."""
|
||||
prague = ZoneInfo("Europe/Prague")
|
||||
|
||||
Reference in New Issue
Block a user