Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
12422dd
Subclass model data into thermal and renewable.
xiangao1 May 17, 2022
359863c
Treat thermal and renewable static params differently in coordiantor.
xiangao1 May 17, 2022
3839e2b
Generate different bids in selfscheduler for thermal and renewable ge…
xiangao1 May 17, 2022
59a97a2
Fix a bug.
xiangao1 May 17, 2022
7e97e8b
Update iterator capabilities.
xiangao1 May 17, 2022
0926ac3
Update the tests.
xiangao1 May 17, 2022
dd7919f
Fix conflicts.
xiangao1 May 17, 2022
b507c3f
Include initial status in the thermal model data.
xiangao1 May 18, 2022
7b1b40d
Deactivate DA power UB when DA signal is realized.
xiangao1 May 18, 2022
b4ab0b3
Use nearest historical prices first.
xiangao1 May 18, 2022
47fa831
Ignore default bids.
xiangao1 May 18, 2022
4a9cb75
Add doc strings and comments in Backcaster.
xiangao1 May 19, 2022
005c91b
2.0.0a2
lbianchi-lbl May 20, 2022
f50087b
Merge branch 'handle-renewable-gen' into 2.0.0.dev0
dguittet Jul 1, 2022
84b0b64
update ver to 2.0.0.a3
dguittet Jul 3, 2022
62e7fbc
fix some typos
dguittet Jul 5, 2022
aba0b7b
Merge branch 'main' into 2.0.0.dev4
dguittet Jul 5, 2022
2904490
Update ver.py
dguittet Jul 11, 2022
b2cbd7d
Merge branch 'main' into update_grid_integration
dguittet Oct 10, 2022
3327400
ver.py
dguittet Oct 10, 2022
e1579a8
black format
dguittet Oct 10, 2022
d96cc07
fix thermal_generator.py
dguittet Oct 11, 2022
9ca3f51
merge in latest from Xian's handle-renewable-gen
dguittet Oct 12, 2022
b6fa9c3
Squashed commit of the following:
dguittet Oct 12, 2022
ab3ff33
Merge branch 'update_grid_integration' into 2.0.0.a4
dguittet Oct 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 57 additions & 22 deletions idaes/apps/grid_integration/bidder.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ def __init__(
n_scenario,
solver,
forecaster,
real_time_underbid_penalty,
):

"""
Expand Down Expand Up @@ -284,6 +285,7 @@ def __init__(
self.n_scenario = n_scenario
self.solver = solver
self.forecaster = forecaster
self.real_time_underbid_penalty = real_time_underbid_penalty

self._check_inputs()

Expand Down Expand Up @@ -337,6 +339,10 @@ def formulate_DA_bidding_problem(self):
model = self._set_up_bidding_problem(self.day_ahead_horizon)
self._add_DA_bidding_constraints(model)

# do not relax the DA offering UB
for i in model.SCENARIOS:
model.fs[i].real_time_underbid_power.fix(0)

return model

def formulate_RT_bidding_problem(self):
Expand All @@ -352,6 +358,10 @@ def formulate_RT_bidding_problem(self):
model = self._set_up_bidding_problem(self.real_time_horizon)
self._add_RT_bidding_constraints(model)

# relax the DA offering UB
for i in model.SCENARIOS:
model.fs[i].real_time_underbid_power.unfix()

return model

def _save_power_outputs(self, model):
Expand Down Expand Up @@ -396,6 +406,9 @@ def _add_bidding_params(self, model):
model.fs[i].real_time_energy_price = pyo.Param(
time_index, initialize=0, mutable=True
)
model.fs[i].real_time_underbid_penalty = pyo.Param(
initialize=self.real_time_underbid_penalty, mutable=True
)

return

Expand All @@ -411,17 +424,24 @@ def _add_bidding_vars(self, model):
None
"""

def day_ahead_power_ub_rule(fs, t):
return fs.power_output_ref[t] >= fs.day_ahead_power[t]
def relaxed_day_ahead_power_ub_rule(fs, t):
return (
fs.power_output_ref[t] + fs.real_time_underbid_power[t]
>= fs.day_ahead_power[t]
)

for i in model.SCENARIOS:
time_index = model.fs[i].power_output_ref.index_set()
model.fs[i].day_ahead_power = pyo.Var(
time_index, initialize=0, within=pyo.NonNegativeReals
)

model.fs[i].real_time_underbid_power = pyo.Var(
time_index, initialize=0, within=pyo.NonNegativeReals
)

model.fs[i].day_ahead_power_ub = pyo.Constraint(
time_index, rule=day_ahead_power_ub_rule
time_index, rule=relaxed_day_ahead_power_ub_rule
)

return
Expand Down Expand Up @@ -459,6 +479,8 @@ def _add_bidding_objective(self, model):
+ model.fs[k].real_time_energy_price[t]
* (model.fs[k].power_output_ref[t] - model.fs[k].day_ahead_power[t])
- weight * cost[t]
- model.fs[k].real_time_underbid_penalty
* model.fs[k].real_time_underbid_power[t]
)

return
Expand Down Expand Up @@ -654,8 +676,12 @@ def _pass_realized_day_ahead_dispatches(self, realized_day_ahead_dispatches, hou
dispatch = realized_day_ahead_dispatches[t + hour]
except IndexError as ex:
self.real_time_model.fs[s].day_ahead_power[t].unfix()
# unrelax the DA offering UB
self.real_time_model.fs[s].real_time_underbid_power[t].fix(0)
else:
self.real_time_model.fs[s].day_ahead_power[t].fix(dispatch)
# relax the DA offering UB
self.real_time_model.fs[s].real_time_underbid_power[t].unfix()

def update_day_ahead_model(self, **kwargs):

Expand Down Expand Up @@ -808,6 +834,7 @@ def __init__(
n_scenario,
solver,
forecaster,
real_time_underbid_penalty=10000,
fixed_to_schedule=False,
):
"""
Expand Down Expand Up @@ -839,6 +866,7 @@ def __init__(
n_scenario,
solver,
forecaster,
real_time_underbid_penalty,
)
self.fixed_to_schedule = fixed_to_schedule

Expand Down Expand Up @@ -922,6 +950,7 @@ def _assemble_bids(self, model, power_var_name, energy_price_param_name, hour):
"""

bids = {}
is_thermal = self.bidding_model_object.model_data.generator_type == "thermal"

power_output_var = getattr(model.fs[0], power_var_name)
time_index = power_output_var.index_set()
Expand All @@ -939,29 +968,34 @@ def _assemble_bids(self, model, power_var_name, energy_price_param_name, hour):

if self.fixed_to_schedule:
bids[t][self.generator]["p_min"] = bids[t][self.generator]["p_max"]
bids[t][self.generator]["min_up_time"] = 0
bids[t][self.generator]["min_down_time"] = 0
bids[t][self.generator]["fixed_commitment"] = (
1 if bids[t][self.generator]["p_min"] > 0 else 0
)
bids[t][self.generator]["startup_fuel"] = [
(bids[t][self.generator]["min_down_time"], 0)
]
bids[t][self.generator]["startup_cost"] = [
(bids[t][self.generator]["min_down_time"], 0)
]

bids[t][self.generator]["p_cost"] = [
(bids[t][self.generator]["p_min"], 0),
(bids[t][self.generator]["p_max"], 0),
]
if is_thermal:
bids[t][self.generator]["min_up_time"] = 0
bids[t][self.generator]["min_down_time"] = 0

bids[t][self.generator]["startup_fuel"] = [
(bids[t][self.generator]["min_down_time"], 0)
]
bids[t][self.generator]["startup_cost"] = [
(bids[t][self.generator]["min_down_time"], 0)
]

if is_thermal:

bids[t][self.generator]["startup_capacity"] = bids[t][self.generator][
"p_min"
]
bids[t][self.generator]["shutdown_capacity"] = bids[t][self.generator][
"p_min"
]
bids[t][self.generator]["p_cost"] = [
(bids[t][self.generator]["p_min"], 0),
(bids[t][self.generator]["p_max"], 0),
]

bids[t][self.generator]["startup_capacity"] = bids[t][self.generator][
"p_min"
]
bids[t][self.generator]["shutdown_capacity"] = bids[t][self.generator][
"p_min"
]

return bids

Expand Down Expand Up @@ -1023,6 +1057,7 @@ def __init__(
n_scenario,
solver,
forecaster,
real_time_underbid_penalty=10000,
):

"""
Expand Down Expand Up @@ -1052,6 +1087,7 @@ def __init__(
n_scenario,
solver,
forecaster,
real_time_underbid_penalty,
)

def _add_DA_bidding_constraints(self, model):
Expand Down Expand Up @@ -1234,7 +1270,6 @@ def _assemble_bids(self, model, power_var_name, energy_price_param_name, hour):
full_bids[t][gen]["p_cost"] = bids[t_idx][gen]
full_bids[t][gen]["p_min"] = min([p[0] for p in bids[t_idx][gen]])
full_bids[t][gen]["p_max"] = max([p[0] for p in bids[t_idx][gen]])

full_bids[t][gen]["startup_capacity"] = full_bids[t][gen]["p_min"]
full_bids[t][gen]["shutdown_capacity"] = full_bids[t][gen]["p_min"]

Expand Down
34 changes: 24 additions & 10 deletions idaes/apps/grid_integration/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ def __init__(self, bidder, tracker, projection_tracker):
Arguments:
bidder: an initialized bidder object

tracker: an initialized bidder object
tracker: an initialized tracker object

projection_tracker: an initialized bidder object, this object is
mimicking the behaviro of the projection SCED in
projection_tracker: an initialized tracker object, this object is
mimicking the behaviror of the projection SCED in
Prescient and to projecting the system states
and updating bidder model.

Expand Down Expand Up @@ -285,7 +285,7 @@ def assemble_project_tracking_signal(self, options, simulator, hour):

"""
This function assembles the signals for the tracking model to estimate the
state of the bidding model at the begining of next RUC.
state of the bidding model at the beginning of next RUC.

Arguments:
options: Prescient options from prescient.simulator.config.
Expand Down Expand Up @@ -398,18 +398,32 @@ def _update_static_params(self, gen_dict):
None
"""

is_thermal = (
self.bidder.bidding_model_object.model_data.generator_type == "thermal"
)
is_renewable = (
self.bidder.bidding_model_object.model_data.generator_type == "renewable"
)

for param, value in self.bidder.bidding_model_object.model_data:
if param == "gen_name" or value is None:
continue
elif param == "p_cost":
curve_value = convert_marginal_costs_to_actual_costs(value)
gen_dict[param] = {
"data_type": "cost_curve",
"cost_curve_type": "piecewise",
"values": curve_value,
}
if is_thermal:
curve_value = convert_marginal_costs_to_actual_costs(value)
gen_dict[param] = {
"data_type": "cost_curve",
"cost_curve_type": "piecewise",
"values": curve_value,
}
elif is_renewable:
gen_dict[param] = value

if "p_fuel" in gen_dict:
gen_dict.pop("p_fuel")
elif param == "initial_status" or param == "initial_p_output":
if param not in gen_dict:
gen_dict[param] = value
else:
gen_dict[param] = value

Expand Down
9 changes: 5 additions & 4 deletions idaes/apps/grid_integration/examples/thermal_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from idaes.apps.grid_integration import Tracker
from idaes.apps.grid_integration import Bidder
from idaes.apps.grid_integration import PlaceHolderForecaster
from idaes.apps.grid_integration.model_data import GeneratorModelData
from idaes.apps.grid_integration.model_data import ThermalGeneratorModelData

from pyomo.common.dependencies import attempt_import

Expand Down Expand Up @@ -138,10 +138,9 @@ def assemble_model_data(self, generator_name, gen_params):
model_data["Power Segments"][l]
] = model_data["Marginal Costs"][l]

self._model_data = GeneratorModelData(
self._model_data = ThermalGeneratorModelData(
gen_name=generator_name,
bus=model_data["Bus Name"],
generator_type="thermal",
p_min=model_data["PMin MW"],
p_max=model_data["PMax MW"],
min_down_time=model_data["Min Down Time Hr"],
Expand All @@ -150,6 +149,9 @@ def assemble_model_data(self, generator_name, gen_params):
ramp_down_60min=model_data["RD"],
shutdown_capacity=model_data["SD"],
startup_capacity=model_data["SU"],
initial_status=-1,
initial_p_output=0,
fixed_commitment=None,
production_cost_bid_pairs=[
(
model_data["PMin MW"],
Expand All @@ -163,7 +165,6 @@ def assemble_model_data(self, generator_name, gen_params):
startup_cost_pairs=[
(model_data["Min Down Time Hr"], model_data["SU Cost"])
],
fixed_commitment=None,
)

return model_data
Expand Down
5 changes: 1 addition & 4 deletions idaes/apps/grid_integration/forecaster.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,7 @@ def fetch_day_ahead_stats_from_prescient(self, uc_date, uc_hour, day_ahead_resul
None
"""

forecasts_arr = np.random.normal(
loc=corresponding_means, scale=corresponding_stds, size=(n_samples, horizon)
)
forecasts_arr[forecasts_arr < 0] = 0
return


class Backcaster(AbstractPrescientPriceForecaster):
Expand Down
Loading