Skip to content

Commit aff8f2c

Browse files
PatyHidalgostaadecker
authored andcommitted
Merge pull request #82 from staadecker/multi-fuel
Small optimizations
2 parents 2a12d8d + ab7d01d commit aff8f2c

File tree

2 files changed

+64
-9
lines changed

2 files changed

+64
-9
lines changed

switch_model/energy_sources/fuel_costs/markets.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ def define_components(mod):
209209
become non-linear.
210210
211211
"""
212+
# When this variable is True we only allow positive fuel costs
213+
# This simplifies the model since we can set some of our constraints
214+
# as greater than instead of equals.
215+
ONLY_POSITIVE_RFM_COSTS = False
212216

213217
mod.REGIONAL_FUEL_MARKETS = Set(dimen=1)
214218
mod.rfm_fuel = Param(mod.REGIONAL_FUEL_MARKETS, within=mod.FUELS)
@@ -244,7 +248,9 @@ def zone_rfm_init(m, load_zone, fuel):
244248
dimen=3,
245249
validate=lambda m, r, p, st: (r in m.REGIONAL_FUEL_MARKETS and p in m.PERIODS),
246250
)
247-
mod.rfm_supply_tier_cost = Param(mod.RFM_SUPPLY_TIERS, within=Reals)
251+
mod.rfm_supply_tier_cost = Param(
252+
mod.RFM_SUPPLY_TIERS, within=PositiveReals if ONLY_POSITIVE_RFM_COSTS else Reals
253+
)
248254
mod.rfm_supply_tier_limit = Param(
249255
mod.RFM_SUPPLY_TIERS, within=NonNegativeReals, default=float("inf")
250256
)
@@ -365,13 +371,20 @@ def GENS_FOR_RFM_PERIOD_rule(m, rfm, p):
365371
enforce_fuel_consumption_scaling_factor = 1e-2
366372

367373
def Enforce_Fuel_Consumption_rule(m, rfm, p):
368-
return m.FuelConsumptionInMarket[
369-
rfm, p
370-
] * enforce_fuel_consumption_scaling_factor == enforce_fuel_consumption_scaling_factor * sum(
374+
lhs = (
375+
m.FuelConsumptionInMarket[rfm, p] * enforce_fuel_consumption_scaling_factor
376+
)
377+
rhs = enforce_fuel_consumption_scaling_factor * sum(
371378
m.GenFuelUseRate[g, t, m.rfm_fuel[rfm]] * m.tp_weight_in_year[t]
372379
for g in m.GENS_FOR_RFM_PERIOD[rfm, p]
373380
for t in m.TPS_IN_PERIOD[p]
374381
)
382+
# If we have only positive costs, FuelConsumptionInMarket will automatically
383+
# try to be minimized in which case we can use a one-sided constraint
384+
if ONLY_POSITIVE_RFM_COSTS:
385+
return lhs >= rhs
386+
else:
387+
return lhs == rhs
375388

376389
mod.Enforce_Fuel_Consumption = Constraint(
377390
mod.REGIONAL_FUEL_MARKETS, mod.PERIODS, rule=Enforce_Fuel_Consumption_rule

switch_model/generators/core/dispatch.py

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,57 @@ def init(m, gen, period):
246246
mod.GEN_TPS, rule=lambda m, g, t: m.GenCapacity[g, m.tp_period[t]]
247247
)
248248
mod.DispatchGen = Var(mod.GEN_TPS, within=NonNegativeReals)
249-
mod.DispatchGenByFuel = Var(mod.GEN_TP_FUELS, within=NonNegativeReals)
249+
250+
##########################################
251+
# Define DispatchGenByFuel
252+
#
253+
# Previously DispatchGenByFuel was simply a Variable for all the projects and a constraint ensured
254+
# that the sum of DispatchGenByFuel across all fuels was equal the total dispatch for that project.
255+
# However this approach creates extra variables in our model for projects that have only one fuel.
256+
# Although these extra variables likely get removed during Gurobi pre-solve, we've nonetheless
257+
# simplified the model here to reduce time in presolve and ensure the model is always
258+
# simplified regardless of the solving method.
259+
#
260+
# To do this we redefine DispatchGenByFuel to be an
261+
# expression that is equal to DispatchGenByFuelVar when we have multiple fuels but
262+
# equal to DispatchGen when we have only one fuel.
263+
264+
# Define a set that is used to define DispatchGenByFuelVar
265+
mod.GEN_TP_FUELS_FOR_MULTIFUELS = Set(
266+
dimen=3,
267+
initialize=mod.GEN_TP_FUELS,
268+
filter=lambda m, g, t, f: g in m.MULTIFUEL_GENS,
269+
doc="Same as GEN_TP_FUELS but only includes multi-fuel projects",
270+
)
271+
# DispatchGenByFuelVar is a variable that exists only for multi-fuel projects.
272+
mod.DispatchGenByFuelVar = Var(
273+
mod.GEN_TP_FUELS_FOR_MULTIFUELS, within=NonNegativeReals
274+
)
275+
# DispatchGenByFuel_Constraint ensures that the sum of all the fuels is DispatchGen
250276
mod.DispatchGenByFuel_Constraint = Constraint(
251277
mod.FUEL_BASED_GEN_TPS,
252-
rule=lambda m, g, t: sum(
253-
m.DispatchGenByFuel[g, t, f] for f in m.FUELS_FOR_GEN[g]
254-
)
255-
== m.DispatchGen[g, t],
278+
rule=lambda m, g, t: (
279+
Constraint.Skip
280+
if g not in m.MULTIFUEL_GENS
281+
else sum(
282+
m.DispatchGenByFuelVar[g, t, f] for f in m.FUELS_FOR_MULTIFUEL_GEN[g]
283+
)
284+
== m.DispatchGen[g, t]
285+
),
256286
)
257287

288+
# Define DispatchGenByFuel to equal the matching variable if we have many fuels but to equal
289+
# the total dispatch if we have only one fuel.
290+
mod.DispatchGenByFuel = Expression(
291+
mod.GEN_TP_FUELS,
292+
rule=lambda m, g, t, f: m.DispatchGenByFuelVar[g, t, f]
293+
if g in m.MULTIFUEL_GENS
294+
else m.DispatchGen[g, t],
295+
)
296+
297+
# End Defining DispatchGenByFuel
298+
##########################################
299+
258300
# Only used to improve the performance of calculating ZoneTotalCentralDispatch and ZoneTotalDistributedDispatch
259301
mod.GENS_FOR_ZONE_TPS = Set(
260302
mod.LOAD_ZONES,

0 commit comments

Comments
 (0)