Skip to content

Commit

Permalink
Merge pull request #44 from SutubraResearch/v3.0.0-dev
Browse files Browse the repository at this point in the history
Optimize Code for Faster Performance
  • Loading branch information
SutubraResearch authored Aug 19, 2023
2 parents b424dda + c588312 commit a63f02f
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 20 deletions.
12 changes: 2 additions & 10 deletions temoa_model/temoa_initialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -1046,21 +1046,13 @@ def DemandActivityConstraintIndices ( M ):
yield (r,p,s,d,t,v,dem,s0,d0)

def DemandConstraintIndices ( M ):
used_dems = set((r,dem) for r, p, dem in M.Demand.sparse_iterkeys())
DSD_keys = M.DemandSpecificDistribution.sparse_keys()
dem_slices = { (r,dem) : set(
(s, d)
for s in M.time_season
for d in M.time_of_day
if (r, s, d, dem) in DSD_keys )
for (r,dem) in used_dems
}

indices = set(
(r, p, s, d, dem)

for r, p, dem in M.Demand.sparse_iterkeys()
for s, d in dem_slices[ (r,dem) ]
for s in M.time_season
for d in M.time_of_day
)

return indices
Expand Down
6 changes: 5 additions & 1 deletion temoa_model/temoa_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def temoa_create_model(name="Temoa"):
# Define demand- and resource-related parameters
M.DemandDefaultDistribution = Param(M.time_season, M.time_of_day, mutable=True)
M.DemandSpecificDistribution = Param(
M.regions, M.time_season, M.time_of_day, M.commodity_demand, mutable=True
M.regions, M.time_season, M.time_of_day, M.commodity_demand, mutable=True, default=0
)

M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand)
Expand Down Expand Up @@ -379,6 +379,10 @@ def temoa_create_model(name="Temoa"):
M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint
)

# We make use of this following set in some of the storage constraints.
# Pre-computing it is considerably faster.
M.SegFracPerSeason = Param(M.time_season, initialize=SegFracPerSeason_rule)

M.StorageEnergyUpperBoundConstraint = Constraint(
M.StorageConstraints_rpsdtv, rule=StorageEnergyUpperBound_Constraint
)
Expand Down
13 changes: 5 additions & 8 deletions temoa_model/temoa_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,6 @@ def Demand_Constraint(M, r, p, s, d, dem):
could satisfy both an end-use and internal system demand, then the output from
:math:`\textbf{FO}` and :math:`\textbf{FOA}` would be double counted.
"""
if (r,s,d,dem) not in M.DemandSpecificDistribution.sparse_keys():
return Constraint.Skip

supply = sum(
M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem]
Expand All @@ -443,6 +441,7 @@ def Demand_Constraint(M, r, p, s, d, dem):
DemandConstraintErrorCheck(supply + supply_annual, r, p, s, d, dem)

expr = supply + supply_annual == M.Demand[r, p, dem] * M.DemandSpecificDistribution[r, s, d, dem]

return expr

def DemandActivity_Constraint(M, r, p, s, d, t, v, dem, s_0, d_0):
Expand Down Expand Up @@ -474,9 +473,6 @@ def DemandActivity_Constraint(M, r, p, s, d, t, v, dem, s_0, d_0):
variations, and therefore the equation above only includes :math:`\textbf{FO}`
and not :math:`\textbf{FOA}`
"""
if (r,s,d,dem) not in M.DemandSpecificDistribution.sparse_keys():
return Constraint.Skip
DSD = M.DemandSpecificDistribution # lazy programmer

act_a = sum(
M.V_FlowOut[r, p, s_0, d_0, S_i, t, v, dem]
Expand All @@ -487,7 +483,7 @@ def DemandActivity_Constraint(M, r, p, s, d, t, v, dem, s_0, d_0):
for S_i in M.ProcessInputsByOutput[r, p, t, v, dem]
)

expr = act_a * DSD[r, s, d, dem] == act_b * DSD[r, s_0, d_0, dem]
expr = act_a * M.DemandSpecificDistribution[r, s, d, dem] == act_b * M.DemandSpecificDistribution[r, s_0, d_0, dem]
return expr


Expand Down Expand Up @@ -989,7 +985,7 @@ def StorageEnergyUpperBound_Constraint(M, r, p, s, d, t, v):
M.V_Capacity[r, t, v]
* M.CapacityToActivity[r, t]
* (M.StorageDuration[r, t] / 8760)
* sum(M.SegFrac[s,S_d] for S_d in M.time_of_day) * 365
* M.SegFracPerSeason[s] * 365
* value(M.ProcessLifeFrac[r, p, t, v])
)
expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity
Expand Down Expand Up @@ -2600,7 +2596,8 @@ def ParamLoanAnnualize_rule(M, r, t, v):

return annualized_rate


def SegFracPerSeason_rule(M, s):
return sum(M.SegFrac[s, S_d] for S_d in M.time_of_day)

def LinkedEmissionsTech_Constraint(M, r, p, s, d, t, v, e):
r"""
Expand Down
18 changes: 17 additions & 1 deletion temoa_model/temoa_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,23 @@ def solve_temoa_instance (self):
if self.options.neos:
self.result = self.optimizer.solve(self.instance, opt=self.options.solver)
else:
self.result = self.optimizer.solve( self.instance, suffixes=['dual'],# 'rc', 'slack'],
if self.options.solver == 'cbc':
# Solver options. Reference: https://genxproject.github.io/GenX/dev/solver_configuration/
self.optimizer.options["dualTolerance"] = 1e-6
self.optimizer.options["primalTolerance"] = 1e-6
self.optimizer.options["zeroTolerance"] = 1e-12
self.optimizer.options["crossover"] = 'off'

elif self.options.solver == 'cplex':
# Note: these parameter values are taken to be the same as those in PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html)
self.optimizer.options["lpmethod"] = 4 # barrier
self.optimizer.options["solutiontype"] = 2 # non basic solution, ie no crossover
self.optimizer.options["barrier convergetol"] = 1.e-5
self.optimizer.options["feasopt tolerance"] = 1.e-6

# Note: still need to add gurobi parameters.

self.result = self.optimizer.solve( self.instance, suffixes=['dual'],# 'rc', 'slack'],
keepfiles=self.options.keepPyomoLP,
symbolic_solver_labels=self.options.keepPyomoLP )
yield '\t\t\t\t\t\t[%8.2f]\n' % duration()
Expand Down

0 comments on commit a63f02f

Please sign in to comment.