Skip to content

Commit d2bbc81

Browse files
committed
manual adjustment HP
1 parent f755b15 commit d2bbc81

1 file changed

Lines changed: 64 additions & 1 deletion

File tree

examples/loma-14a.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from datetime import datetime
44

55
import geopandas as gpd
6+
import numpy as np
67
import pandas as pd
78

89
from edisgo import EDisGo
@@ -350,6 +351,66 @@ def prepare_edisgo_for_14a(edisgo, *, shapefile_path, output_dir, cache_dir=None
350351
edisgo.set_time_series_reactive_power_control()
351352

352353

354+
def fix_hp_peak_loads(edisgo, seed=None):
355+
"""
356+
Enforce minimum HP p_set constraints and ensure adequate representation
357+
in higher power bands. Timeseries are scaled proportionally when p_set changes.
358+
359+
Rules:
360+
1. p_set >= 0.003 MW for every heat pump.
361+
2. At least 5 % of HPs have p_set in [0.01, 0.02] MW.
362+
3. At least 5 % of HPs have p_set in [0.02, 0.03] MW.
363+
4. At least 5 % of HPs have p_set in [0.04, 0.05] MW.
364+
"""
365+
rng = np.random.default_rng(seed)
366+
loads_df = edisgo.topology.loads_df
367+
hp_idx = loads_df[loads_df["type"] == "heat_pump"].index.tolist()
368+
n_hp = len(hp_idx)
369+
if n_hp == 0:
370+
return
371+
372+
lap = edisgo.timeseries.loads_active_power
373+
374+
def _rescale(hp, new_p):
375+
old_p = loads_df.at[hp, "p_set"]
376+
if old_p > 0 and hp in lap.columns:
377+
lap[hp] = lap[hp] * (new_p / old_p)
378+
loads_df.at[hp, "p_set"] = new_p
379+
380+
# Rule 1: floor all HPs at 0.003 MW
381+
for hp in hp_idx:
382+
if loads_df.at[hp, "p_set"] < 0.003:
383+
_rescale(hp, 0.003)
384+
385+
# Rules 2–4: ensure at least 5 % of HPs fall in each target band
386+
target_bands = [(0.01, 0.02), (0.02, 0.03), (0.04, 0.05)]
387+
min_count = max(1, int(np.ceil(n_hp * 0.05)))
388+
389+
assigned = set()
390+
for lo, hi in target_bands:
391+
already = [hp for hp in hp_idx if lo <= loads_df.at[hp, "p_set"] <= hi]
392+
assigned |= set(already)
393+
need = min_count - len(already)
394+
if need <= 0:
395+
continue
396+
# prefer HPs not yet assigned to any target band; fall back to all others
397+
candidates = [hp for hp in hp_idx if hp not in assigned]
398+
if len(candidates) < need:
399+
candidates = [hp for hp in hp_idx if hp not in set(already)]
400+
chosen = rng.choice(candidates, size=min(need, len(candidates)), replace=False).tolist()
401+
for hp in chosen:
402+
_rescale(hp, float(rng.uniform(lo, hi)))
403+
assigned.add(hp)
404+
405+
# Keep heat_demand_df consistent with updated timeseries
406+
hp_in_lap = [h for h in hp_idx if h in lap.columns]
407+
if not edisgo.heat_pump.cop_df.empty and hp_in_lap:
408+
edisgo.heat_pump.heat_demand_df = (
409+
lap[hp_in_lap] * edisgo.heat_pump.cop_df[hp_in_lap]
410+
)
411+
print(f"[fix_hp_peak_loads] Adjusted {n_hp} heat pumps.")
412+
413+
353414
def get_monthly_snapshot_ranges(year=2025, test=False):
354415
"""Return list of (month_label, start_idx, end_idx) for each month of year.
355416
@@ -400,8 +461,10 @@ def main(output_dir, snapshot_range, seed=42):
400461
seed=seed,
401462
)
402463

464+
fix_hp_peak_loads(edisgo, seed=seed)
465+
403466
edisgo = run_optimization_14a(edisgo)
404-
edisgo.analyze()
467+
#edisgo.analyze()
405468

406469
# ────────────────────────── Slack diagnosis ──────────────────────────────
407470
slacks = edisgo.opf_results.grid_slacks_t

0 commit comments

Comments
 (0)