Skip to content

Commit 8bc6d5e

Browse files
authored
Merge pull request #82 from staadecker/multi-fuel
Small optimizations
2 parents 916b8ac + 87756cf commit 8bc6d5e

File tree

2 files changed

+55
-9
lines changed

2 files changed

+55
-9
lines changed

switch_model/energy_sources/fuel_costs/markets.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ def define_components(mod):
204204
become non-linear.
205205
206206
"""
207+
# When this variable is True we only allow positive fuel costs
208+
# This simplifies the model since we can set some of our constraints
209+
# as greater than instead of equals.
210+
ONLY_POSITIVE_RFM_COSTS = False
207211

208212
mod.REGIONAL_FUEL_MARKETS = Set(dimen=1)
209213
mod.rfm_fuel = Param(mod.REGIONAL_FUEL_MARKETS, within=mod.FUELS)
@@ -234,7 +238,8 @@ def zone_rfm_init(m, load_zone, fuel):
234238
dimen=3, validate=lambda m, r, p, st: (
235239
r in m.REGIONAL_FUEL_MARKETS and p in m.PERIODS))
236240
mod.rfm_supply_tier_cost = Param(
237-
mod.RFM_SUPPLY_TIERS, within=Reals)
241+
mod.RFM_SUPPLY_TIERS,
242+
within=PositiveReals if ONLY_POSITIVE_RFM_COSTS else Reals)
238243
mod.rfm_supply_tier_limit = Param(
239244
mod.RFM_SUPPLY_TIERS, within=NonNegativeReals, default=float('inf'))
240245
mod.min_data_check(
@@ -333,12 +338,16 @@ def GENS_FOR_RFM_PERIOD_rule(m, rfm, p):
333338
enforce_fuel_consumption_scaling_factor = 1e-2
334339

335340
def Enforce_Fuel_Consumption_rule(m, rfm, p):
336-
return m.FuelConsumptionInMarket[rfm, p] * enforce_fuel_consumption_scaling_factor \
337-
== enforce_fuel_consumption_scaling_factor * sum(
338-
m.GenFuelUseRate[g, t, m.rfm_fuel[rfm]] * m.tp_weight_in_year[t]
339-
for g in m.GENS_FOR_RFM_PERIOD[rfm, p]
340-
for t in m.TPS_IN_PERIOD[p]
341-
)
341+
lhs = m.FuelConsumptionInMarket[rfm, p] * enforce_fuel_consumption_scaling_factor
342+
rhs = enforce_fuel_consumption_scaling_factor * sum(
343+
m.GenFuelUseRate[g, t, m.rfm_fuel[rfm]] * m.tp_weight_in_year[t] for g in m.GENS_FOR_RFM_PERIOD[rfm, p] for
344+
t in m.TPS_IN_PERIOD[p])
345+
# If we have only positive costs, FuelConsumptionInMarket will automatically
346+
# try to be minimized in which case we can use a one-sided constraint
347+
if ONLY_POSITIVE_RFM_COSTS:
348+
return lhs >= rhs
349+
else:
350+
return lhs == rhs
342351
mod.Enforce_Fuel_Consumption = Constraint(
343352
mod.REGIONAL_FUEL_MARKETS, mod.PERIODS,
344353
rule=Enforce_Fuel_Consumption_rule)

switch_model/generators/core/dispatch.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,47 @@ def init(m, gen, period):
235235
mod.DispatchGen = Var(
236236
mod.GEN_TPS,
237237
within=NonNegativeReals)
238-
mod.DispatchGenByFuel = Var(mod.GEN_TP_FUELS, within=NonNegativeReals)
238+
239+
##########################################
240+
# Define DispatchGenByFuel
241+
#
242+
# Previously DispatchGenByFuel was simply a Variable for all the projects and a constraint ensured
243+
# that the sum of DispatchGenByFuel across all fuels was equal the total dispatch for that project.
244+
# However this approach creates extra variables in our model for projects that have only one fuel.
245+
# Although these extra variables likely get removed during Gurobi pre-solve, we've nonetheless
246+
# simplified the model here to reduce time in presolve and ensure the model is always
247+
# simplified regardless of the solving method.
248+
#
249+
# To do this we redefine DispatchGenByFuel to be an
250+
# expression that is equal to DispatchGenByFuelVar when we have multiple fuels but
251+
# equal to DispatchGen when we have only one fuel.
252+
253+
# Define a set that is used to define DispatchGenByFuelVar
254+
mod.GEN_TP_FUELS_FOR_MULTIFUELS = Set(
255+
dimen=3,
256+
initialize=mod.GEN_TP_FUELS,
257+
filter=lambda m, g, t, f: g in m.MULTIFUEL_GENS,
258+
doc="Same as GEN_TP_FUELS but only includes multi-fuel projects"
259+
)
260+
# DispatchGenByFuelVar is a variable that exists only for multi-fuel projects.
261+
mod.DispatchGenByFuelVar = Var(mod.GEN_TP_FUELS_FOR_MULTIFUELS, within=NonNegativeReals)
262+
# DispatchGenByFuel_Constraint ensures that the sum of all the fuels is DispatchGen
239263
mod.DispatchGenByFuel_Constraint = Constraint(
240264
mod.FUEL_BASED_GEN_TPS,
241-
rule=lambda m, g, t: sum(m.DispatchGenByFuel[g, t, f] for f in m.FUELS_FOR_GEN[g]) == m.DispatchGen[g, t])
265+
rule=lambda m, g, t:
266+
(Constraint.Skip if g not in m.MULTIFUEL_GENS
267+
else sum(m.DispatchGenByFuelVar[g, t, f] for f in m.FUELS_FOR_MULTIFUEL_GEN[g]) == m.DispatchGen[g, t])
268+
)
269+
270+
# Define DispatchGenByFuel to equal the matching variable if we have many fuels but to equal
271+
# the total dispatch if we have only one fuel.
272+
mod.DispatchGenByFuel = Expression(
273+
mod.GEN_TP_FUELS,
274+
rule=lambda m, g, t, f: m.DispatchGenByFuelVar[g, t, f] if g in m.MULTIFUEL_GENS else m.DispatchGen[g, t]
275+
)
276+
277+
# End Defining DispatchGenByFuel
278+
##########################################
242279

243280
# Only used to improve the performance of calculating ZoneTotalCentralDispatch and ZoneTotalDistributedDispatch
244281
mod.GENS_FOR_ZONE_TPS = Set(

0 commit comments

Comments
 (0)