Skip to content

Commit 9d8d30e

Browse files
committed
Correcting storage assignment
1 parent ec768f2 commit 9d8d30e

10 files changed

Lines changed: 992 additions & 31 deletions

File tree

.claude/commands/diagnose-model.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# EPM Model Diagnostic
2+
3+
Interactive diagnostic for EPM optimization results. Helps identify why model results don't look right - even when there's no explicit error.
4+
5+
## Environment Setup
6+
7+
**IMPORTANT**: Always use the `esmap_env` conda environment when running Python commands:
8+
```bash
9+
conda run -n esmap_env python <script>
10+
```
11+
12+
Or activate it first:
13+
```bash
14+
conda activate esmap_env
15+
```
16+
17+
## Instructions
18+
19+
You are an expert at debugging GAMS optimization models for electricity planning. This is an **interactive, conversational diagnostic**. The user often has an intuition that something is wrong but may not know exactly what.
20+
21+
**IMPORTANT**: Perform the full diagnostic automatically without asking for permission at each step. Go through all steps and provide comprehensive findings.
22+
23+
### Step 1: Ask for the scenario folder
24+
25+
Use AskUserQuestion to ask:
26+
- "Which scenario folder should I analyze? (Path to folder containing PA.gdx)"
27+
28+
Provide common options like:
29+
- `epm/output/simulations_test/baseline`
30+
- Let user type custom path
31+
32+
### Step 2: Gather context from the user
33+
34+
Before diving into data, **ask the user what they observed**. Use AskUserQuestion:
35+
36+
**Question**: "What made you think something might be wrong? Select any that apply or describe in 'Other':"
37+
- "A variable is always zero when it shouldn't be"
38+
- "Prices seem too high or too low"
39+
- "Storage/renewables not being used as expected"
40+
- "Costs don't look right"
41+
- Other (free text)
42+
43+
**Follow-up question**: "Do you have a specific variable, equation, or generator in mind?"
44+
- Let user specify (e.g., "vStorage for BESS_Angola", "eSOCUpperBound marginal is negative")
45+
- Or "No, please do a general check"
46+
47+
### Step 3: Targeted investigation based on user input
48+
49+
Based on user's answers, prioritize your investigation:
50+
51+
**If storage issue suspected:**
52+
1. Check `vStorage`, `vCapStor`, `vStorInj`, `vPwrOut` levels
53+
2. Check `eSOCUpperBound`, `eStorageHourTransition` marginals
54+
3. Verify storage is in `st(g)` set
55+
4. Check initialization logic in main.gms:810-832
56+
57+
**If price issue suspected:**
58+
1. Check `pPrice` distribution by zone
59+
2. Look for VOLL events (unmet demand)
60+
3. Check binding transmission constraints
61+
62+
**If capacity/dispatch issue:**
63+
1. Check `vCap` vs `vPwrOut` utilization
64+
2. Look for curtailment
65+
3. Check reserve constraints
66+
67+
### Step 4: Read the GDX file
68+
69+
Use Python with gams.transfer to extract specific data:
70+
71+
```python
72+
import gams.transfer as gt
73+
import pandas as pd
74+
75+
container = gt.Container("<path>/PA.gdx")
76+
77+
# Get variable with levels and marginals
78+
var = container.data["<variable_name>"]
79+
df = var.records
80+
print(df)
81+
```
82+
83+
Key columns in GDX records:
84+
- `level`: The solution value
85+
- `marginal`: Shadow price (dual value)
86+
- `lower`, `upper`: Variable bounds
87+
88+
### Step 5: Cross-reference with GAMS source
89+
90+
Read `epm/base.gms` to understand equation definitions. Pay attention to:
91+
- The `$()` conditional domain - this controls when the equation is active
92+
- Related sets like `st(g)`, `FD(q,d,t)`, `fEnableStorage`
93+
94+
### Step 6: Check input data if needed
95+
96+
Look at CSV files in `epm/input/<data_folder>/supply/`:
97+
- `pGenDataInput.csv` - Generator parameters
98+
- `pStorageDataInput.csv` - Storage parameters
99+
- Check `Status`, `StYr`, `RetrYr` fields
100+
101+
### Step 7: Present findings conversationally
102+
103+
Don't just dump data. Explain what you found in plain language:
104+
105+
**Good**: "I found that vStorage is zero for BESS_Angola even though vCapStor shows 200 MWh of capacity. Looking at the equations, this happens because..."
106+
107+
**Bad**: "Here are 50 rows of data..."
108+
109+
### Output Format
110+
111+
```
112+
## What I Found
113+
114+
[Plain language explanation of the issue]
115+
116+
## Why This Happens
117+
118+
[Technical explanation with references to specific equations/code]
119+
120+
## The Fix
121+
122+
[Concrete steps to resolve - be specific about file, line, value changes]
123+
124+
## Want Me To...
125+
126+
[Offer next steps: "Should I check the input data?", "Want me to look at related constraints?"]
127+
```
128+
129+
## Key Diagnostic Patterns
130+
131+
### Storage capacity exists but not used (vCapStor > 0, vStorage = 0)
132+
- Check if `st(g)` set includes the unit (requires tech="Storage" or "STOPV")
133+
- Check `fEnableStorage` flag
134+
- Check initialization: if `StYr = sStartYear`, line 811 condition fails
135+
- Check `RetrYr`: if missing, line 814 condition fails
136+
137+
### Negative marginal on inequality constraint
138+
- Normal! Means constraint is binding
139+
- Large negative value = high shadow price = relaxing this constraint would help a lot
140+
141+
### Variable at zero with non-zero marginal
142+
- Constraint is preventing the variable from being positive
143+
- The marginal tells you "cost" of that constraint
144+
145+
## Arguments
146+
147+
$ARGUMENTS - Optional: path to the scenario folder (if not provided, will ask interactively)

epm/base.gms

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,7 @@ eCSPStorageInitialBalance(cs,q,d,sFirstHour(t),y)$((fEnableCSP) and FD(q,d,t))..
10741074
* Tracks storage energy capacity builds/retirements.
10751075
* ------------------------------
10761076

1077+
* TODO: Why is it defined for all generators (g) rather than just storage (st)?
10771078
* Limits total installed storage capacity to predefined technical data from pStorageData and CSP-related capacity from pCSPData. Only applies if storage is included (fEnableStorage).
10781079
eCapacityStorLimit(g,y)$fEnableStorage..
10791080
vCapStor(g,y) =l= pStorageData(g,"CapacityMWh") + pCSPData(g,"Storage","CapacityMWh");

epm/epm.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,28 @@ def launch_epm(scenario,
437437
rslt = subprocess.run(command, cwd=cwd)
438438

439439
if rslt.returncode != 0:
440-
raise RuntimeError('GAMS Error: check GAMS logs file ')
440+
logfile_path = Path(cwd) / logfile
441+
error_msg = f"GAMS Error (return code {rslt.returncode}) for scenario '{scenario_name}'\n"
442+
error_msg += f"Log file: {logfile_path}\n"
443+
444+
# Try to extract the last lines from the log file to show the actual error
445+
if logfile_path.exists():
446+
try:
447+
with open(logfile_path, 'r', encoding='utf-8', errors='ignore') as f:
448+
lines = f.readlines()
449+
# Get last 30 lines or all if fewer
450+
tail_lines = lines[-30:] if len(lines) > 30 else lines
451+
# Look for error indicators in the log
452+
error_lines = [l for l in lines if '****' in l or 'Error' in l or 'error' in l]
453+
if error_lines:
454+
error_msg += "\nErrors found in log:\n" + "".join(error_lines[-10:])
455+
error_msg += "\nLast lines of log:\n" + "".join(tail_lines[-15:])
456+
except Exception as e:
457+
error_msg += f"\n(Could not read log file: {e})"
458+
else:
459+
error_msg += "\n(Log file not found - GAMS may have failed before creating it)"
460+
461+
raise RuntimeError(error_msg)
441462

442463
metrics = _log_solver_metrics_for_scenario(Path(cwd) / logfile, scenario_name) or {}
443464

epm/input/data_test/supply/pGenDataInput.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Akanyaru Peat,Rwanda,ST,Coal,2,2032,,,0,,50,,,,,,,,,,,,,,,,,,,,
66
Akieni,Gabon,ROR,Water,3,2030,,,120.75,,0,,,,,,,,,,,,,,,,,,,,
77
Akoga,EquatorialGuinea,OCGT,Gas,3,2030,,,38,,38,,,,,,,,,,,,,,,,,,,,
88
Inga 2,DRC,ReservoirHydro,Water,1,1982,2051,,800,,,,,,,,,,,,,,,,,,,,,,
9-
Soyo,Angola,CCGT,Gas,1,2017,2051,,750,,,,,,,,,,,,,,,,,,,,,,
9+
Soyo,Angola,CCGT,Gas,1,2017,2051,,750,,,,,,0,0,,,,,,,,,,,,,,,
1010
Capanda,Angola,ReservoirHydro,Water,1,2004,,,520,,,,,,,,,,,,,,,,,,,,,,
1111
AM Timan 1,Chad,PV,Solar,2,2023,,,5,,5,,,,,,,,,,,,,,,,,,,,
1212
AM Timan 2,Chad,PV,Solar,3,2028,,,5,,5,,,,,,,,,,,,,,,,,,,,
@@ -454,4 +454,4 @@ Zina,Burundi,PV,Solar,3,2030,,,60,,10,,,,,,,,,,,,,,,,,,,,
454454
Mukungwa,Rwanda,OCGT,Diesel,1,2010,2051,,0,,,,,,,,,,,,,,,,,,,,,,
455455
Mwadingusha,DRC_South,ReservoirHydro,Water,1,1954,2060,,0,,,,,,,,,,,,,,,,,,,,,,
456456
Zoukomanbalé,Cameroon,ROR,Water,,2051,,,30,,30,,,,,,,,,,,,,,,,,,,,
457-
Zoulabot,Cameroon,ROR,Water,,2051,,,71,,71,,,,,,,,,,,,,,,,,,,,
457+
Zoulabot,Cameroon,ROR,Water,,2051,,,71,,71,,,,,,,,,,,,,,,,,,,,
Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
g,z,tech,f,Linked plant,Status,StYr,RetrYr,Life,Capacity,UnitSize,BuildLimitperYear,CapacityMWh,DescreteCap,Efficiency,Capex,FOMperMW,VOM,ReserveCost,CapexMWh,FixedOMMWh,VOMMWh,MinGenShareAllHours,HeatRate,RampUpRate,RampDnRate,OverLoadFactor,ResLimShare,HoursOn,HoursOff,minUT,minDT,StUpCost,InitialOn,MinGenCommitment
2-
Generic_BESS_Angola,Angola,Storage,Battery,,3,2035,,,200000,,100,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
3-
Generic_BESS_Burundi,Burundi,Storage,Battery,,3,2035,,,3000,,6,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
4-
Generic_BESS_CAF,CAR,Storage,Battery,,3,2035,,,1000,,4,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
5-
Generic_BESS_Cameroon,Cameroon,Storage,Battery,,3,2035,,,70000,,170,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
6-
Generic_BESS_Chad,Chad,Storage,Battery,,3,2035,,,40000,,7,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
7-
Generic_BESS_Congo,Congo,Storage,Battery,,3,2035,,,50000,,45,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
8-
Generic_BESS_DRC,DRC,Storage,Battery,,3,2030,,,400000,,100,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
9-
Generic_BESS_DRCEast,DRC_East,Storage,Battery,,3,2035,,,400000,,10,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
10-
Generic_BESS_DRCSouth,DRC_South,Storage,Battery,,3,2035,,,400000,,74,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
11-
Generic_BESS_EquatorialGuinea,EquatorialGuinea,Storage,Battery,,3,2030,,,4000,,17,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
12-
Generic_BESS_Gabon,Gabon,Storage,Battery,,3,2035,,,40000,,45,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
13-
Generic_BESS_Rwanda,Rwanda,Storage,Battery,,3,2035,,,40000,,40,10000000,,0.9,0.1,,,,180,0,0,,,,,,,,,,,,,
2+
BESS_Angola,Angola,Storage,Battery,,1,2024,,,50,,,200,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
3+
Generic_BESS_Angola,Angola,Storage,Battery,,3,2035,,,200000,,100,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
4+
Generic_BESS_Burundi,Burundi,Storage,Battery,,3,2035,,,3000,,6,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
5+
Generic_BESS_CAF,CAR,Storage,Battery,,3,2035,,,1000,,4,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
6+
Generic_BESS_Cameroon,Cameroon,Storage,Battery,,3,2035,,,70000,,170,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
7+
Generic_BESS_Chad,Chad,Storage,Battery,,3,2035,,,40000,,7,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
8+
Generic_BESS_Congo,Congo,Storage,Battery,,3,2035,,,50000,,45,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
9+
Generic_BESS_DRC,DRC,Storage,Battery,,3,2030,,,400000,,100,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
10+
Generic_BESS_DRCEast,DRC_East,Storage,Battery,,3,2035,,,400000,,10,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
11+
Generic_BESS_DRCSouth,DRC_South,Storage,Battery,,3,2035,,,400000,,74,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
12+
Generic_BESS_EquatorialGuinea,EquatorialGuinea,Storage,Battery,,3,2030,,,4000,,17,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
13+
Generic_BESS_Gabon,Gabon,Storage,Battery,,3,2035,,,40000,,45,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
14+
Generic_BESS_Rwanda,Rwanda,Storage,Battery,,3,2035,,,40000,,40,10000000,,0.9,0.1,0,,,180,0,0,,,,,,,,,,,,,
1415
PumpedStorage Rwanda,Rwanda,Storage,Water,,3,2040,,,48,,48,3000,,0.8,2.9,50000,,,150,0,0,,,,,,,,,,,,,

epm/input/data_test/supply/sensitivity/pGenDataInput_linear.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Akanyaru Peat,Rwanda,ST,Coal,2.0,2032.0,,,0.0,,50.0,,,,,,,,,,,,,,,,,,,,,0
66
Akieni,Gabon,ROR,Water,3.0,2030.0,,,120.75,,0.0,,,,,,,,,,,,,,,,,,,,,0
77
Akoga,EquatorialGuinea,OCGT,Gas,3.0,2030.0,,,38.0,,38.0,,,,,,,,,,,,,,,,,,,,,0
88
Inga 2,DRC,ReservoirHydro,Water,1.0,1982.0,2051.0,,800.0,,,,,,,,,,,,,,,,,,,,,,,0
9-
Soyo,Angola,CCGT,Gas,1.0,2017.0,2051.0,,750.0,,,,,,,,,,,,,,,,,,,,,,,0
9+
Soyo,Angola,CCGT,Gas,1.0,2017.0,2051.0,,750.0,,,,,,0.0,0.0,,,,,,,,,,,,,,,,0
1010
Capanda,Angola,ReservoirHydro,Water,1.0,2004.0,,,520.0,,,,,,,,,,,,,,,,,,,,,,,0
1111
AM Timan 1,Chad,PV,Solar,2.0,2023.0,,,5.0,,5.0,,,,,,,,,,,,,,,,,,,,,0
1212
AM Timan 2,Chad,PV,Solar,3.0,2028.0,,,5.0,,5.0,,,,,,,,,,,,,,,,,,,,,0

epm/input_readers.gms

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,10 @@ $onEmbeddedCode Connect:
280280
file: %pGenDataInput%
281281
name: pGenDataInput
282282
indexColumns: [1,2,3,4]
283+
valueSubstitutions: {0: EPS}
283284
header: [1]
284285
type: par
285286

286-
287287
- CSVReader:
288288
trace: %TRACE%
289289
file: %pGenDataInputDefault%
@@ -413,7 +413,7 @@ $onEmbeddedCode Connect:
413413
file: %pStorageDataInput%
414414
name: pStorageDataInput
415415
indexSubstitutions: {.nan: ""}
416-
valueSubstitutions: {0: .nan}
416+
valueSubstitutions: {0: EPS}
417417
indexColumns: [1,2,3,4]
418418
header: [1]
419419
type: par

0 commit comments

Comments
 (0)