Skip to content

Commit ffb02c1

Browse files
lucas-vivierclaude
andcommitted
Fix generic defaults enrichment for single-country runs
When running single-country simulations, the *Default tables (pGenDataInputDefault, pAvailabilityDefault) could become empty after zone filtering, causing the generic enrichment to be skipped entirely. Now handles the empty case by creating defaults from scratch using generic data, similar to how pCapexTrajectoriesDefault already worked. For pAvailabilityDefault, seasons are taken from pHours instead of hardcoded values. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 5bce7a9 commit ffb02c1

1 file changed

Lines changed: 47 additions & 14 deletions

File tree

epm/input_treatment.py

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,50 +2146,83 @@ def _enrich_defaults_with_generic(db: gt.Container):
21462146
# GAMS-loaded generic data is already in long format: (tech, f, pGenDataInputHeader, value)
21472147
if "gendata" in generic and "pGenDataInputDefault" in db:
21482148
gendata_default = db["pGenDataInputDefault"].records
2149-
if gendata_default is not None and not gendata_default.empty:
2149+
generic_gendata = generic["gendata"] # Already has (tech, f, pGenDataInputHeader, value)
2150+
2151+
if gendata_default is None or gendata_default.empty:
2152+
# pGenDataInputDefault is empty - create it entirely from generic data
2153+
to_add = required.merge(generic_gendata, on=["tech", "f"], how="inner")
2154+
if not to_add.empty:
2155+
db.data["pGenDataInputDefault"].setRecords(to_add)
2156+
_write_back(db, "pGenDataInputDefault")
2157+
n_combos = to_add[["z", "tech", "f"]].drop_duplicates().shape[0]
2158+
gams.printLog(f"[input_treatment][generic] Created pGenDataInputDefault with {n_combos} (zone, tech, fuel) combination(s) from generic.")
2159+
else:
2160+
# pGenDataInputDefault has data - only add missing combinations
21502161
gendata_keys = gendata_default[["z", "tech", "f"]].drop_duplicates()
21512162
merged = required.merge(gendata_keys, on=["z", "tech", "f"], how="left", indicator=True)
21522163
missing = merged[merged["_merge"] == "left_only"][["z", "tech", "f"]]
2153-
2164+
21542165
if not missing.empty:
2155-
generic_gendata = generic["gendata"] # Already has (tech, f, pGenDataInputHeader, value)
21562166
# Join missing combinations with generic values
21572167
to_add = missing.merge(generic_gendata, on=["tech", "f"], how="inner")
21582168
if not to_add.empty:
21592169
updated = pd.concat([gendata_default, to_add], ignore_index=True)
21602170
db.data["pGenDataInputDefault"].setRecords(updated)
21612171
_write_back(db, "pGenDataInputDefault")
21622172
n_combos = to_add[["z", "tech", "f"]].drop_duplicates().shape[0]
2163-
gams.printLog(f"[input_treatment][generic] Enriched pGenDataInputDefault with {n_combos} tech-fuel combination(s) from generic.")
2173+
gams.printLog(f"[input_treatment][generic] Enriched pGenDataInputDefault with {n_combos} (zone, tech, fuel) combination(s) from generic.")
21642174

21652175
# Enrich pAvailabilityDefault
21662176
# GAMS-loaded generic data is (tech, f, value) - single annual value
2167-
if "availability" in generic and "pAvailabilityDefault" in db:
2177+
# Get seasons from pHours
2178+
seasons_from_hours = []
2179+
if "pHours" in db:
2180+
phours_records = db["pHours"].records
2181+
if phours_records is not None and not phours_records.empty:
2182+
q_col = "q" if "q" in phours_records.columns else phours_records.columns[0]
2183+
seasons_from_hours = phours_records[q_col].unique().tolist()
2184+
2185+
if "availability" in generic and "pAvailabilityDefault" in db and seasons_from_hours:
21682186
avail_default = db["pAvailabilityDefault"].records
2169-
if avail_default is not None and not avail_default.empty:
2187+
generic_avail = generic["availability"] # (tech, f, value)
2188+
2189+
if avail_default is None or avail_default.empty:
2190+
# pAvailabilityDefault is empty - create it entirely from generic data
2191+
to_add = required.merge(generic_avail, on=["tech", "f"], how="inner")
2192+
if not to_add.empty:
2193+
new_records = []
2194+
for _, row in to_add.iterrows():
2195+
for q in seasons_from_hours:
2196+
new_records.append({"z": row["z"], "tech": row["tech"], "f": row["f"],
2197+
"q": q, "value": row["value"]})
2198+
if new_records:
2199+
new_df = pd.DataFrame(new_records)
2200+
db.data["pAvailabilityDefault"].setRecords(new_df)
2201+
_write_back(db, "pAvailabilityDefault")
2202+
n_combos = to_add[["z", "tech", "f"]].drop_duplicates().shape[0]
2203+
gams.printLog(f"[input_treatment][generic] Created pAvailabilityDefault with {n_combos} (zone, tech, fuel) combination(s) from generic.")
2204+
else:
2205+
# pAvailabilityDefault has data - only add missing combinations
21702206
avail_keys = avail_default[["z", "tech", "f"]].drop_duplicates()
21712207
merged = required.merge(avail_keys, on=["z", "tech", "f"], how="left", indicator=True)
21722208
missing = merged[merged["_merge"] == "left_only"][["z", "tech", "f"]]
2173-
2209+
21742210
if not missing.empty:
2175-
generic_avail = generic["availability"] # (tech, f, value)
2176-
# Get seasons from existing default (q column in long format)
2177-
seasons = avail_default["q"].unique().tolist() if "q" in avail_default.columns else ["Q1"]
2178-
21792211
# Join missing combinations with generic values, expand to all seasons
21802212
to_add = missing.merge(generic_avail, on=["tech", "f"], how="inner")
21812213
if not to_add.empty:
21822214
new_records = []
21832215
for _, row in to_add.iterrows():
2184-
for q in seasons:
2185-
new_records.append({"z": row["z"], "tech": row["tech"], "f": row["f"],
2216+
for q in seasons_from_hours:
2217+
new_records.append({"z": row["z"], "tech": row["tech"], "f": row["f"],
21862218
"q": q, "value": row["value"]})
21872219
if new_records:
21882220
new_df = pd.DataFrame(new_records)
21892221
updated = pd.concat([avail_default, new_df], ignore_index=True)
21902222
db.data["pAvailabilityDefault"].setRecords(updated)
21912223
_write_back(db, "pAvailabilityDefault")
2192-
gams.printLog(f"[input_treatment][generic] Enriched pAvailabilityDefault with {len(to_add)} tech-fuel combination(s) from generic.")
2224+
n_combos = to_add[["z", "tech", "f"]].drop_duplicates().shape[0]
2225+
gams.printLog(f"[input_treatment][generic] Enriched pAvailabilityDefault with {n_combos} (zone, tech, fuel) combination(s) from generic.")
21932226

21942227
# Enrich pCapexTrajectoriesDefault
21952228
# GAMS-loaded generic data is already in long format: (tech, f, y, value)

0 commit comments

Comments
 (0)