Skip to content

Commit 23bc024

Browse files
committed
add new bess notebook
1 parent 197d470 commit 23bc024

18 files changed

+2081
-7
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ The first two notebook cells are modified to ensure that requirements are instal
6565
|AMPL Model Colaboratory Template|[![colab.ipynb](https://img.shields.io/badge/github-%23121011.svg?logo=github)](https://github.com/ampl/colab.ampl.com/blob/master/template/colab.ipynb)|[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/template/colab.ipynb)|[![Open In Deepnote](https://deepnote.com/buttons/launch-in-deepnote-small.svg)](https://deepnote.com/launch?url=https://github.com/ampl/colab.ampl.com/blob/master/template/colab.ipynb)|[![Open In Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/ampl/colab.ampl.com/blob/master/template/colab.ipynb)|[![Open In Gradient](https://assets.paperspace.io/img/gradient-badge.svg)](https://console.paperspace.com/github/ampl/colab.ampl.com/blob/master/template/colab.ipynb)|[![Open In SageMaker Studio Lab](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/ampl/colab.ampl.com/blob/master/template/colab.ipynb)|
6666
|Aircrew trainee scheduling with seniority constraints|[![tip8_aircrew_trainees_seniority.ipynb](https://img.shields.io/badge/github-%23121011.svg?logo=github)](https://github.com/ampl/colab.ampl.com/blob/master/authors/glebbelov/modeling-tips/tip8_aircrew_trainees_seniority.ipynb)|[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/authors/glebbelov/modeling-tips/tip8_aircrew_trainees_seniority.ipynb)|[![Open In Deepnote](https://deepnote.com/buttons/launch-in-deepnote-small.svg)](https://deepnote.com/launch?url=https://github.com/ampl/colab.ampl.com/blob/master/authors/glebbelov/modeling-tips/tip8_aircrew_trainees_seniority.ipynb)|[![Open In Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/ampl/colab.ampl.com/blob/master/authors/glebbelov/modeling-tips/tip8_aircrew_trainees_seniority.ipynb)|[![Open In Gradient](https://assets.paperspace.io/img/gradient-badge.svg)](https://console.paperspace.com/github/ampl/colab.ampl.com/blob/master/authors/glebbelov/modeling-tips/tip8_aircrew_trainees_seniority.ipynb)|[![Open In SageMaker Studio Lab](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/ampl/colab.ampl.com/blob/master/authors/glebbelov/modeling-tips/tip8_aircrew_trainees_seniority.ipynb)|
6767
|Balanced Task Assignment with Inverse Cost Scaling|[![Inverse_cost.ipynb](https://img.shields.io/badge/github-%23121011.svg?logo=github)](https://github.com/ampl/colab.ampl.com/blob/master/authors/mikhail/Inverse_cost/Inverse_cost.ipynb)|[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/authors/mikhail/Inverse_cost/Inverse_cost.ipynb)|[![Open In Deepnote](https://deepnote.com/buttons/launch-in-deepnote-small.svg)](https://deepnote.com/launch?url=https://github.com/ampl/colab.ampl.com/blob/master/authors/mikhail/Inverse_cost/Inverse_cost.ipynb)|[![Open In Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/ampl/colab.ampl.com/blob/master/authors/mikhail/Inverse_cost/Inverse_cost.ipynb)|[![Open In Gradient](https://assets.paperspace.io/img/gradient-badge.svg)](https://console.paperspace.com/github/ampl/colab.ampl.com/blob/master/authors/mikhail/Inverse_cost/Inverse_cost.ipynb)|[![Open In SageMaker Studio Lab](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/ampl/colab.ampl.com/blob/master/authors/mikhail/Inverse_cost/Inverse_cost.ipynb)|
68+
|Battery Energy Storage System (BESS) Evaluation Model|[![bess.ipynb](https://img.shields.io/badge/github-%23121011.svg?logo=github)](https://github.com/ampl/colab.ampl.com/blob/master/authors/jpbohorquez/bess/bess.ipynb)|[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/authors/jpbohorquez/bess/bess.ipynb)|[![Open In Deepnote](https://deepnote.com/buttons/launch-in-deepnote-small.svg)](https://deepnote.com/launch?url=https://github.com/ampl/colab.ampl.com/blob/master/authors/jpbohorquez/bess/bess.ipynb)|[![Open In Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/ampl/colab.ampl.com/blob/master/authors/jpbohorquez/bess/bess.ipynb)|[![Open In Gradient](https://assets.paperspace.io/img/gradient-badge.svg)](https://console.paperspace.com/github/ampl/colab.ampl.com/blob/master/authors/jpbohorquez/bess/bess.ipynb)|[![Open In SageMaker Studio Lab](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/ampl/colab.ampl.com/blob/master/authors/jpbohorquez/bess/bess.ipynb)|
6869
|Bilevel Markets|[![bilevel_markets.ipynb](https://img.shields.io/badge/github-%23121011.svg?logo=github)](https://github.com/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_markets.ipynb)|[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_markets.ipynb)|[![Open In Deepnote](https://deepnote.com/buttons/launch-in-deepnote-small.svg)](https://deepnote.com/launch?url=https://github.com/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_markets.ipynb)|[![Open In Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_markets.ipynb)|[![Open In Gradient](https://assets.paperspace.io/img/gradient-badge.svg)](https://console.paperspace.com/github/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_markets.ipynb)|[![Open In SageMaker Studio Lab](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_markets.ipynb)|
6970
|Bilevel Optimization Introduction|[![bilevel_introduction.ipynb](https://img.shields.io/badge/github-%23121011.svg?logo=github)](https://github.com/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_introduction.ipynb)|[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_introduction.ipynb)|[![Open In Deepnote](https://deepnote.com/buttons/launch-in-deepnote-small.svg)](https://deepnote.com/launch?url=https://github.com/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_introduction.ipynb)|[![Open In Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_introduction.ipynb)|[![Open In Gradient](https://assets.paperspace.io/img/gradient-badge.svg)](https://console.paperspace.com/github/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_introduction.ipynb)|[![Open In SageMaker Studio Lab](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/ampl/colab.ampl.com/blob/master/authors/eduardosalaz/bilevel/bilevel_introduction.ipynb)|
7071
|Book Example: Economic equilibria|[![economic_eq_lecture.ipynb](https://img.shields.io/badge/github-%23121011.svg?logo=github)](https://github.com/ampl/colab.ampl.com/blob/master/ampl-lecture/economic_eq_lecture.ipynb)|[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/ampl-lecture/economic_eq_lecture.ipynb)|[![Open In Deepnote](https://deepnote.com/buttons/launch-in-deepnote-small.svg)](https://deepnote.com/launch?url=https://github.com/ampl/colab.ampl.com/blob/master/ampl-lecture/economic_eq_lecture.ipynb)|[![Open In Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/ampl/colab.ampl.com/blob/master/ampl-lecture/economic_eq_lecture.ipynb)|[![Open In Gradient](https://assets.paperspace.io/img/gradient-badge.svg)](https://console.paperspace.com/github/ampl/colab.ampl.com/blob/master/ampl-lecture/economic_eq_lecture.ipynb)|[![Open In SageMaker Studio Lab](https://studiolab.sagemaker.aws/studiolab.svg)](https://studiolab.sagemaker.aws/import/github/ampl/colab.ampl.com/blob/master/ampl-lecture/economic_eq_lecture.ipynb)|

authors/jpbohorquez/bess/BESS.mod

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
2+
set TIME ordered; # Set of hours in the simulation (1..8760)
3+
set MONTHS; # Set of months
4+
5+
# ----------------------------------------------------------------------------
6+
# PARAMETERS
7+
# ----------------------------------------------------------------------------
8+
9+
# Mapping parameter to link time steps to rate periods
10+
param time_month_map {TIME} within MONTHS;
11+
12+
# Load and Rates
13+
param site_electric_load {TIME} >= 0; # Baseline facility load (kW) [Symbol: L]
14+
param energy_rate {MONTHS} >= 0; # Retail energy rate ($/kWh) [Symbol: RE]
15+
param demand_rate {MONTHS} >= 0; # Retail demand rate ($/kW) [Symbol: RD]
16+
17+
# Market Prices and Signals
18+
param tso_energy_price {TIME}; # Electricity market price ($/MWh) [Symbol: ME]
19+
param tso_flex_up_price {TIME} >= 0; # Freq regulation market price ($/MWh) [Symbol: MR]
20+
param tso_flex_down_price {TIME} >= 0; # Freq regulation market price for regulation down ($/MWh) [Symbol: MR_DN]
21+
param reg_d_up {TIME}; # Freq reg signal for increased supply (%) [Symbol: RS_U]
22+
param reg_d_down {TIME}; # Freq reg signal for decreased supply (%) [Symbol: RS_D]
23+
param tso_load {TIME} >= 0; # Aggregate demand for TSO (MW) [Symbol: TL]
24+
param dso_load {TIME} >= 0; # Aggregate demand for DSO (MW) [Symbol: DL]
25+
param cp_tso_rate_kw >= 0; # Coincident peak capacity rate ($/kW) [Symbol: RC]
26+
param cp_dso_rate_kw >= 0; # Coincident peak capacity rate for DSO (if applicable) ($/kW) [Symbol: RC_DSO]
27+
28+
# Battery Technical Specs
29+
param battery_power >= 0; # Inverter capacity/Max rate (kW) [Symbol: Gbattery]
30+
param battery_energy >= 0; # Storage capacity (kWh) [Symbol: Sbattery]
31+
param efficiency >= 0, <= 1; # Battery efficiency (%) [Symbol: E]
32+
param battery_fixed_om >= 0; # Battery O&M costs ($/kWh-year) [Symbol: OMbattery]
33+
param initial_soc_pct >= 0, <= 1, default 0.5; # Initial state of charge (kWh) [Symbol: Soc0]
34+
param min_soc_pct >= 0, <= 1, default 0.1; # Minimum state of charge as % of capacity (kWh) [Symbol: MinSoc]
35+
param max_soc_pct >= 0, <= 1, default 0.9;
36+
37+
# Solar Technical Specs
38+
param solar_capacity >= 0; # Solar generation capacity (kW) [Symbol: Gsolar]
39+
param solar_production_profile {TIME} >= 0; # Solar production per unit capacity (%) [Symbol: U]
40+
param solar_fixed_om >= 0; # Solar O&M costs ($/kW-year) [Symbol: OMsolar]
41+
42+
# Coincident Peak Identification
43+
# Find the max TSO load to identify t*
44+
param max_tso_val = max {t in TIME} tso_load[t];
45+
param max_tso_time = max {t in TIME: tso_load[t] = max_tso_val} t; # Only count 1 hour for the coincident peak, not every hour where max demand happens
46+
47+
param max_dso_val = max {t in TIME} dso_load[t];
48+
param max_dso_time = max {t in TIME: dso_load[t] = max_dso_val} t; # Only count 1 hour for the coincident peak, not every hour where max demand happens
49+
50+
# Baseline peak parameter for each month
51+
param baseline_peak {m in MONTHS} = max {t in TIME: time_month_map[t] = m} site_electric_load[t];
52+
53+
# Operating and Maintenance Costs
54+
# OM1 = Fixed costs (Battery + Solar)
55+
param OM1 = (battery_fixed_om * battery_energy) + (solar_fixed_om * solar_capacity);
56+
57+
# ----------------------------------------------------------------------------
58+
# DECISION VARIABLES
59+
# ----------------------------------------------------------------------------
60+
61+
var SolarProduction {TIME} >= 0; # Solar electricity production (kW) [Symbol: P]
62+
var BatteryCharge {TIME} >= 0; # BESS electric charge (kW) [Symbol: C]
63+
var BatteryDischarge {TIME} >= 0; # BESS electric discharge (kW) [Symbol: D]
64+
var Soc {TIME} >= min_soc_pct * battery_energy, <= max_soc_pct * battery_energy; # BESS state of charge (kWh) [Symbol: Soc]
65+
var NetLoad {TIME} >= 0; # Net facility load after BESS/Solar (kW) [Symbol: N]
66+
var ExportToGrid {TIME} >= 0; # Surplus solar production exported (kW) [Symbol: X]
67+
var FlexUpBattery {TIME} >= 0, <= battery_power; # BESS capacity participating in Freq Reg (kW) [Symbol: FR]
68+
var FlexDownBattery {TIME} >= 0, <= battery_power; # BESS capacity participating in Freq Reg for regulation down (kW) [Symbol: FR_DN]
69+
70+
# Auxiliary variables for peak tracking (Required for Demand Charge Savings)
71+
var PeakNetLoad {MONTHS} >= 0; # Max net load per month
72+
73+
var BatteryCharging {TIME} binary; # Binary variable to indicate if battery is charging (1) or discharging (0) at time t
74+
var BatteryDischarging {TIME} binary; # Binary variable to indicate if battery is discharging (1) or charging (0) at time t
75+
76+
# -----
77+
# Other variables (savings and revenues) for objective function
78+
# -----
79+
80+
# Energy Charge Savings
81+
# E1 = Sum((Lt - Nt) * RE)
82+
var EnergyChargesSavings = sum {t in TIME} (site_electric_load[t] - NetLoad[t]) * (tso_energy_price[t]/1000 + energy_rate[time_month_map[t]]);
83+
84+
# Demand Charge Savings
85+
# D1 = Sum((Max(L) - Max(N)) * RD)
86+
var DemandChargesSavings = sum {m in MONTHS} (baseline_peak[m] - PeakNetLoad[m]) * demand_rate[m];
87+
88+
# Coincident Peak Charge Savings
89+
# CP1 = RC * (Lt* - Nt*)
90+
var CP_TSO_DemandChargesSavings =
91+
sum {t in TIME: t = max_tso_time} 12*(cp_tso_rate_kw * (site_electric_load[t] - NetLoad[t]));
92+
93+
# Coincident Peak Charge Savings for DSO
94+
# CP2 = RC_DSO * (Dt* - Nt*)
95+
var CP_DSO_DemandChargesSavings =
96+
sum {t in TIME: t = max_dso_time} 12*(cp_dso_rate_kw * (site_electric_load[t] - NetLoad[t]));
97+
98+
# Wholesale Energy Market Revenues
99+
# M1 = Sum(Xt * MEt)
100+
var ExportPowerValue = sum {t in TIME} (ExportToGrid[t] * tso_energy_price[t])/1000;
101+
102+
# Frequency Regulation Market Revenues
103+
# FR1 = Sum(FRt * MRt)
104+
var FlexUpRevenue = sum {t in TIME} (FlexUpBattery[t] * tso_flex_up_price[t])/1000;
105+
# FR2 = Sum(FR_DNt * MR_DNt)
106+
var FlexDownRevenue = sum {t in TIME} (FlexDownBattery[t] * tso_flex_down_price[t])/1000;
107+
108+
109+
# ----------------------------------------------------------------------------
110+
# OBJECTIVE FUNCTION
111+
# ----------------------------------------------------------------------------
112+
113+
# V1 = E1 + D1 + CP1 + M1 + FR1 - OM1
114+
maximize NetValue:
115+
EnergyChargesSavings +
116+
DemandChargesSavings +
117+
CP_TSO_DemandChargesSavings +
118+
CP_DSO_DemandChargesSavings +
119+
ExportPowerValue +
120+
FlexUpRevenue +
121+
FlexDownRevenue -
122+
OM1;
123+
124+
# ----------------------------------------------------------------------------
125+
# OPERATING CONSTRAINTS
126+
# ----------------------------------------------------------------------------
127+
128+
subject to Exclusive_State {t in TIME}:
129+
BatteryCharging[t] + BatteryDischarging[t] <= 1;
130+
131+
# Solar Production
132+
subject to SolarGenDef {t in TIME}:
133+
SolarProduction[t] = solar_production_profile[t] * solar_capacity;
134+
135+
# Battery Power Capacity
136+
subject to ChargeLimit {t in TIME}:
137+
BatteryCharge[t] <= battery_power * BatteryCharging[t];
138+
139+
subject to DischargeLimit {t in TIME}:
140+
BatteryDischarge[t] <= battery_power * BatteryDischarging[t];
141+
142+
subject to FlexUpLimit {t in TIME}:
143+
FlexUpBattery[t] <= ((if ord(t) > 1 then Soc[t-1] else initial_soc_pct * battery_energy) - min_soc_pct * battery_energy) / (efficiency^0.5);
144+
145+
subject to FlexDownLimit {t in TIME}:
146+
FlexDownBattery[t] <= (max_soc_pct * battery_energy - (if ord(t) > 1 then Soc[t-1] else initial_soc_pct * battery_energy)) * (efficiency^0.5);
147+
148+
# Battery State of Charge limits
149+
subject to SocCapacity {t in TIME}:
150+
Soc[t] <= battery_energy;
151+
152+
# Battery Continuity Balance
153+
subject to SocBalance {t in TIME}:
154+
Soc[t] = (if ord(t) > 1 then Soc[t-1] else initial_soc_pct * battery_energy)
155+
+ ((efficiency^0.5)* BatteryCharge[t])
156+
- (BatteryDischarge[t] / (efficiency^0.5));
157+
158+
# Net Electric Load
159+
# Nt = Lt - Pt - Dt + Ct + Xt
160+
subject to NetLoadDef {t in TIME}:
161+
NetLoad[t] = site_electric_load[t]
162+
- SolarProduction[t]
163+
- BatteryDischarge[t]
164+
+ BatteryCharge[t]
165+
+ ExportToGrid[t];
166+
167+
# Frequency Regulation Participation
168+
# Discharge must meet Up signal * Committed Capacity
169+
subject to RegUpConstraint {t in TIME}:
170+
BatteryDischarge[t] >= reg_d_up[t] * FlexUpBattery[t];
171+
172+
# Charge must meet Down signal * Committed Capacity
173+
subject to RegDownConstraint {t in TIME}:
174+
BatteryCharge[t] >= -reg_d_down[t] * FlexDownBattery[t];
175+
176+
# Define Peak Tracking for Demand Charges
177+
# PeakNetLoad must be at least the NetLoad in that month
178+
subject to PeakTracking {m in MONTHS, t in TIME: time_month_map[t] = m}:
179+
PeakNetLoad[m] >= NetLoad[t];
180+
181+
# Limit exports to onsite generation (Solar + Battery Discharge)
182+
subject to ExportLimit {t in TIME}:
183+
ExportToGrid[t] <= SolarProduction[t];#+ BatteryDischarge[t];

0 commit comments

Comments
 (0)